diff --git a/Gemfile b/Gemfile
index 324e1ce2c1b389a086dadf9500f899465de5aa73..a532a7dcfe2221bb3dfa7efe982ff9d98572fd29 100644
--- a/Gemfile
+++ b/Gemfile
@@ -99,6 +99,13 @@ gem "colored"
 # GitLab settings
 gem 'settingslogic'
 
+# Wiki 
+# - Use latest master to resolve Gem dependency with Pygemnts
+# github-linquist needs pygments 0.4.2 but Gollum 2.4.11
+# requires pygments 0.3.2. The latest master Gollum has been updated
+# to use pygments 0.4.2. Change this after next Gollum release.
+gem "gollum", "~> 2.4.0", git: "git://github.com/github/gollum.git"
+
 # Misc
 gem "foreman"
 gem "git"
diff --git a/Gemfile.lock b/Gemfile.lock
index 36447188359728d7a8c3815abef24bd57011a432..0e35997ae9a2ce8dfcea95dfa29bf17ecadf7a73 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -1,3 +1,19 @@
+GIT
+  remote: git://github.com/github/gollum.git
+  revision: 544d499ab170c9d9b355b7a0160afc74139ee2a4
+  specs:
+    gollum (2.4.11)
+      github-markdown (~> 0.5.3)
+      github-markup (>= 0.7.5, < 1.0.0)
+      grit (~> 2.5.0)
+      mustache (>= 0.99.4, < 1.0.0)
+      nokogiri (~> 1.5.6)
+      pygments.rb (~> 0.4.2)
+      sanitize (~> 2.0.3)
+      sinatra (~> 1.3.5)
+      stringex (~> 1.5.1)
+      useragent (~> 0.4.16)
+
 GIT
   remote: https://github.com/ctran/annotate_models.git
   revision: be4e26825b521f0b2d86b181e2dff89901aa9b1e
@@ -139,6 +155,7 @@ GEM
       escape_utils (~> 0.2.3)
       mime-types (~> 1.19)
       pygments.rb (>= 0.2.13)
+    github-markdown (0.5.3)
     github-markup (0.7.5)
     gitlab-grack (1.0.0)
       rack (~> 1.4.1)
@@ -170,6 +187,10 @@ GEM
     grape-entity (0.2.0)
       activesupport
       multi_json (>= 1.3.2)
+    grit (2.5.0)
+      diff-lcs (~> 1.1)
+      mime-types (~> 1.15)
+      posix-spawn (~> 0.3.6)
     grit_ext (0.6.2)
       charlock_holmes (~> 0.6.9)
     growl (1.0.3)
@@ -231,7 +252,8 @@ GEM
       sprockets (~> 2.0)
     multi_json (1.6.1)
     multi_xml (0.5.3)
-    multipart-post (1.2.0)
+    multipart-post (1.1.5)
+    mustache (0.99.4)
     mysql2 (0.3.11)
     net-ldap (0.2.2)
     nokogiri (1.5.6)
@@ -365,6 +387,8 @@ GEM
       rspec-mocks (~> 2.12.0)
     rubyntlm (0.1.1)
     rubyzip (0.9.9)
+    sanitize (2.0.3)
+      nokogiri (>= 1.4.4, < 1.6)
     sass (3.2.5)
     sass-rails (3.2.5)
       railties (~> 3.2.0)
@@ -418,6 +442,7 @@ GEM
       tilt (~> 1.1, != 1.3.0)
     stamp (0.5.0)
     state_machine (1.1.2)
+    stringex (1.5.1)
     temple (0.5.5)
     test_after_commit (0.0.1)
     therubyracer (0.10.2)
@@ -440,6 +465,7 @@ GEM
       kgio (~> 2.6)
       rack
       raindrops (~> 0.7)
+    useragent (0.4.16)
     virtus (0.5.4)
       backports (~> 2.6.1)
       descendants_tracker (~> 0.0.1)
@@ -487,6 +513,7 @@ DEPENDENCIES
   gitlab_meta (= 5.0)
   gitlab_omniauth-ldap (= 1.0.2)
   gitlab_yaml_db (= 1.0.0)
+  gollum (~> 2.4.0)!
   gon
   grape (~> 0.3.1)
   grape-entity (~> 0.2.0)
diff --git a/app/assets/stylesheets/application.scss b/app/assets/stylesheets/application.scss
index 6b500b88823a7be2a3f2e11a48509467fbcd1faf..d6f2fa9632ecb04caeab5d462ffe1aa3b947dc60 100644
--- a/app/assets/stylesheets/application.scss
+++ b/app/assets/stylesheets/application.scss
@@ -33,6 +33,7 @@
 @import "sections/login.scss";
 @import "sections/editor.scss";
 @import "sections/admin.scss";
+@import "sections/wiki.scss";
 
 @import "highlight/white.scss";
 @import "highlight/dark.scss";
diff --git a/app/assets/stylesheets/sections/wiki.scss b/app/assets/stylesheets/sections/wiki.scss
new file mode 100644
index 0000000000000000000000000000000000000000..175911d731202e188b37e5ed83eb402a7ba19e21
--- /dev/null
+++ b/app/assets/stylesheets/sections/wiki.scss
@@ -0,0 +1,6 @@
+h3.page_title .edit-wiki-header {
+  width: 780px;
+  margin-left: auto;
+  margin-right: auto;
+  padding-right: 7px;
+}
diff --git a/app/controllers/wikis_controller.rb b/app/controllers/wikis_controller.rb
index 6928029100304b99e5a281b2982bbe7c6a569532..940b1e9734051b433c597432170d145a56688091 100644
--- a/app/controllers/wikis_controller.rb
+++ b/app/controllers/wikis_controller.rb
@@ -2,58 +2,94 @@ class WikisController < ProjectResourceController
   before_filter :authorize_read_wiki!
   before_filter :authorize_write_wiki!, only: [:edit, :create, :history]
   before_filter :authorize_admin_wiki!, only: :destroy
+  before_filter :load_gollum_wiki
 
   def pages
-    @wiki_pages = @project.wikis.group(:slug).ordered
+    @wiki_pages = @gollum_wiki.pages
   end
 
   def show
-    @most_recent_wiki = @project.wikis.where(slug: params[:id]).ordered.first
-    if params[:version_id]
-      @wiki = @project.wikis.find(params[:version_id])
-    else
-      @wiki = @most_recent_wiki
-    end
+    @wiki = @gollum_wiki.find_page(params[:id], params[:version_id])
 
     if @wiki
       render 'show'
     else
-      if can?(current_user, :write_wiki, @project)
-        @wiki = @project.wikis.new(slug: params[:id])
-        render 'edit'
-      else
-        render 'empty'
-      end
+      return render('empty') unless can?(current_user, :write_wiki, @project)
+      @wiki = WikiPage.new(@gollum_wiki)
+      @wiki.title = params[:id]
+
+      render 'edit'
     end
   end
 
   def edit
-    @wiki = @project.wikis.where(slug: params[:id]).ordered.first
-    @wiki = Wiki.regenerate_from @wiki
+    @wiki = @gollum_wiki.find_page(params[:id])
+  end
+
+  def update
+    @wiki = @gollum_wiki.find_page(params[:id])
+
+    return render('empty') unless can?(current_user, :write_wiki, @project)
+
+    if @wiki.update(content, format, message)
+      redirect_to [@project, @wiki], notice: 'Wiki was successfully updated.'
+    else
+      render 'edit'
+    end
   end
 
   def create
-    @wiki = @project.wikis.new(params[:wiki])
-    @wiki.user = current_user
-
-    respond_to do |format|
-      if @wiki.save
-        format.html { redirect_to [@project, @wiki], notice: 'Wiki was successfully updated.' }
-      else
-        format.html { render action: "edit" }
-      end
+    @wiki = WikiPage.new(@gollum_wiki)
+
+    if @wiki.create(wiki_params)
+      redirect_to project_wiki_path(@project, @wiki), notice: 'Wiki was successfully updated.'
+    else
+      render action: "edit"
     end
   end
 
   def history
-    @wiki_pages = @project.wikis.where(slug: params[:id]).ordered
+    unless @wiki = @gollum_wiki.find_page(params[:id])
+      redirect_to project_wiki_path(@project, :home), notice: "Page not found"
+    end
   end
 
   def destroy
-    @wikis = @project.wikis.where(slug: params[:id]).delete_all
+    @wiki = @gollum_wiki.find_page(params[:id])
+    @wiki.delete if @wiki
+    redirect_to project_wiki_path(@project, :home), notice: "Page was successfully deleted"
+  end
 
-    respond_to do |format|
-      format.html { redirect_to project_wiki_path(@project, :index), notice: "Page was successfully deleted" }
-    end
+  def git_access
   end
+
+  private
+
+  def load_gollum_wiki
+    @gollum_wiki = GollumWiki.new(@project, current_user)
+
+    # Call #wiki to make sure the Wiki Repo is initialized
+    @gollum_wiki.wiki
+  rescue GollumWiki::CouldNotCreateWikiError => ex
+    flash[:notice] = "Could not create Wiki Repository at this time. Please try again later."
+    redirect_to @project
+    return false
+  end
+
+  def wiki_params
+    params[:wiki].slice(:title, :content, :format, :message)
+  end
+
+  def content
+    params[:wiki][:content]
+  end
+
+  def format
+    params[:wiki][:format]
+  end
+
+  def message
+    params[:wiki][:message]
+  end
+
 end
diff --git a/app/models/gollum_wiki.rb b/app/models/gollum_wiki.rb
new file mode 100644
index 0000000000000000000000000000000000000000..91641ff18730ad24c60ca0bc3e50e8f462af3d90
--- /dev/null
+++ b/app/models/gollum_wiki.rb
@@ -0,0 +1,125 @@
+class GollumWiki
+
+  MARKUPS = {
+    "Markdown"         => :markdown,
+    "Textile"          => :textile,
+    "RDoc"             => :rdoc,
+    "Org-mode"         => :org,
+    "Creole"           => :creole,
+    "reStructuredText" => :rest,
+    "AsciiDoc"         => :asciidoc,
+    "MediaWiki"        => :mediawiki,
+    "Pod"              => :post
+  }
+
+  class CouldNotCreateWikiError < StandardError; end
+
+  # Returns a string describing what went wrong after
+  # an operation fails.
+  attr_reader :error_message
+
+  def initialize(project, user = nil)
+    @project = project
+    @user = user
+  end
+
+  def path_with_namespace
+    @project.path_with_namespace + ".wiki"
+  end
+
+  def url_to_repo
+    gitlab_shell.url_to_repo(path_with_namespace)
+  end
+
+  def ssh_url_to_repo
+    url_to_repo
+  end
+
+  def http_url_to_repo
+    http_url = [Gitlab.config.gitlab.url, "/", path_with_namespace, ".git"].join('')
+  end
+
+  # Returns the Gollum::Wiki object.
+  def wiki
+    @wiki ||= begin
+      Gollum::Wiki.new(path_to_repo)
+    rescue Grit::NoSuchPathError
+      create_repo!
+    end
+  end
+
+  # Returns an Array of Gitlab WikiPage instances or an
+  # empty Array if this Wiki has no pages.
+  def pages
+    wiki.pages.map { |page| WikiPage.new(self, page, true) }
+  end
+
+  # Returns the last 30 Commit objects accross the entire
+  # repository.
+  def recent_history
+    Commit.fresh_commits(wiki.repo, 30)
+  end
+
+  # Finds a page within the repository based on a tile
+  # or slug.
+  #
+  # title - The human readable or parameterized title of
+  #         the page.
+  #
+  # Returns an initialized WikiPage instance or nil
+  def find_page(title, version = nil)
+    if page = wiki.page(title, version)
+      WikiPage.new(self, page, true)
+    else
+      nil
+    end
+  end
+
+  def create_page(title, content, format = :markdown, message = nil)
+    commit = commit_details(:created, message, title)
+
+    wiki.write_page(title, format, content, commit)
+  rescue Gollum::DuplicatePageError => e
+    @error_message = "Duplicate page: #{e.message}"
+    return false
+  end
+
+  def update_page(page, content, format = :markdown, message = nil)
+    commit = commit_details(:updated, message, page.title)
+
+    wiki.update_page(page, page.name, format, content, commit)
+  end
+
+  def delete_page(page, message = nil)
+    wiki.delete_page(page, commit_details(:deleted, message, page.title))
+  end
+
+  private
+
+  def create_repo!
+    if gitlab_shell.add_repository(path_with_namespace)
+      Gollum::Wiki.new(path_to_repo)
+    else
+      raise CouldNotCreateWikiError
+    end
+  end
+
+  def commit_details(action, message = nil, title = nil)
+    commit_message = message || default_message(action, title)
+
+    {email: @user.email, name: @user.name, message: commit_message}
+  end
+
+  def default_message(action, title)
+    "#{@user.username} #{action} page: #{title}"
+  end
+
+  def gitlab_shell
+    @gitlab_shell ||= Gitlab::Shell.new
+  end
+
+  def path_to_repo
+    @path_to_repo ||= File.join(Gitlab.config.gitlab_shell.repos_path, "#{path_with_namespace}.git")
+  end
+
+end
diff --git a/app/models/wiki_page.rb b/app/models/wiki_page.rb
new file mode 100644
index 0000000000000000000000000000000000000000..adc77b22231eb49b316f91022bae362d2c21f230
--- /dev/null
+++ b/app/models/wiki_page.rb
@@ -0,0 +1,181 @@
+class WikiPage
+  include ActiveModel::Validations
+  include ActiveModel::Conversion
+  include StaticModel
+  extend ActiveModel::Naming
+
+  def self.primary_key
+    'slug'
+  end
+
+  def self.model_name
+    ActiveModel::Name.new(self, nil, 'wiki')
+  end
+
+  def to_key
+    [:slug]
+  end
+
+  validates :title, presence: true
+  validates :content, presence: true
+
+  # The Gitlab GollumWiki instance.
+  attr_reader :wiki
+
+  # The raw Gollum::Page instance.
+  attr_reader :page
+
+  # The attributes Hash used for storing and validating
+  # new Page values before writing to the Gollum repository.
+  attr_accessor :attributes
+
+  def initialize(wiki, page = nil, persisted = false)
+    @wiki       = wiki
+    @page       = page
+    @persisted  = persisted
+    @attributes = {}.with_indifferent_access
+
+    set_attributes if persisted?
+  end
+
+  # The escaped URL path of this page.
+  def slug
+    @attributes[:slug]
+  end
+
+  alias :to_param :slug
+
+  # The formatted title of this page.
+  def title
+    @attributes[:title] || ""
+  end
+
+  # Sets the title of this page.
+  def title=(new_title)
+    @attributes[:title] = new_title
+  end
+
+  # The raw content of this page.
+  def content
+    @attributes[:content]
+  end
+
+  # The processed/formatted content of this page.
+  def formatted_content
+    @attributes[:formatted_content]
+  end
+
+  # The markup format for the page.
+  def format
+    @attributes[:format] || :markdown
+  end
+
+  # The commit message for this page version.
+  def message
+    version.try(:message)
+  end
+
+  # The Gitlab Commit instance for this page.
+  def version
+    return nil unless persisted?
+
+    @version ||= Commit.new(@page.version)
+  end
+
+  # Returns an array of Gitlab Commit instances.
+  def versions
+    return [] unless persisted?
+
+    @page.versions.map { |v| Commit.new(v) }
+  end
+
+  # Returns the Date that this latest version was
+  # created on.
+  def created_at
+    @page.version.date
+  end
+
+  # Returns boolean True or False if this instance
+  # is an old version of the page.
+  def historical?
+    @page.historical?
+  end
+
+  # Returns boolean True or False if this instance
+  # has been fully saved to disk or not.
+  def persisted?
+    @persisted == true
+  end
+
+  # Creates a new Wiki Page.
+  #
+  # attr - Hash of attributes to set on the new page.
+  #       :title   - The title for the new page.
+  #       :content - The raw markup content.
+  #       :format  - Optional symbol representing the
+  #                  content format. Can be any type
+  #                  listed in the GollumWiki::MARKUPS
+  #                  Hash.
+  #       :message - Optional commit message to set on
+  #                  the new page.
+  #
+  # Returns the String SHA1 of the newly created page
+  # or False if the save was unsuccessful.
+  def create(attr = {})
+    @attributes.merge!(attr)
+
+    save :create_page, title, content, format, message
+  end
+
+  # Updates an existing Wiki Page, creating a new version.
+  #
+  # new_content - The raw markup content to replace the existing.
+  # format      - Optional symbol representing the content format.
+  #               See GollumWiki::MARKUPS Hash for available formats.
+  # message     - Optional commit message to set on the new version.
+  #
+  # Returns the String SHA1 of the newly created page
+  # or False if the save was unsuccessful.
+  def update(new_content = "", format = :markdown, message = nil)
+    @attributes[:content] = new_content
+    @attributes[:format] = format
+
+    save :update_page, @page, content, format, message
+  end
+
+  # Destroys the WIki Page.
+  #
+  # Returns boolean True or False.
+  def delete
+    if wiki.delete_page(@page)
+      true
+    else
+      false
+    end
+  end
+
+  private
+
+  def set_attributes
+    attributes[:slug] = @page.escaped_url_path
+    attributes[:title] = @page.title
+    attributes[:content] = @page.raw_data
+    attributes[:formatted_content] = @page.formatted_data
+    attributes[:format] = @page.format
+  end
+
+  def save(method, *args)
+    if valid? && wiki.send(method, *args)
+      @page = wiki.wiki.paged(title)
+
+      set_attributes
+
+      @persisted = true
+    else
+      errors.add(:base, wiki.error_message) if wiki.error_message
+      @persisted = false
+    end
+    @persisted
+  end
+
+end
diff --git a/app/observers/project_observer.rb b/app/observers/project_observer.rb
index 4b1f8295dc2189a208a7df6bbe3356c5a0198aa7..89dc97ac14025c8c76be4d4ee6f14e0858669d51 100644
--- a/app/observers/project_observer.rb
+++ b/app/observers/project_observer.rb
@@ -18,6 +18,11 @@ def after_destroy(project)
       project.path_with_namespace
     )
 
+    GitlabShellWorker.perform_async(
+      :remove_repository,
+      project.path_with_namespace + ".wiki"
+    )
+
     project.satellite.destroy
 
     log_info("Project \"#{project.name}\" was removed")
diff --git a/app/views/layouts/project_resource.html.haml b/app/views/layouts/project_resource.html.haml
index 37d0f16fa20c7027d9e36ed7a2d140d13ea17096..3c53c0f2b46f77722a1a46824094a999dbfab3f5 100644
--- a/app/views/layouts/project_resource.html.haml
+++ b/app/views/layouts/project_resource.html.haml
@@ -41,6 +41,6 @@
 
         - if @project.wiki_enabled
           = nav_link(controller: :wikis) do
-            = link_to 'Wiki', project_wiki_path(@project, :index)
+            = link_to 'Wiki', project_wiki_path(@project, :home)
 
       .content= yield
diff --git a/app/views/wikis/_form.html.haml b/app/views/wikis/_form.html.haml
index 7758b129b07aec99ac6a9b88e11f1ae487adb360..6fa41db4f7a9e07d494b31328a8a5d988ba317ca 100644
--- a/app/views/wikis/_form.html.haml
+++ b/app/views/wikis/_form.html.haml
@@ -8,9 +8,12 @@
 
   .ui-box.ui-box-show
     .ui-box-head
-      = f.label :title
-      .input= f.text_field :title, class: 'span8'
-      = f.hidden_field :slug
+      %h3.page_title
+        .edit-wiki-header
+          = @wiki.title.titleize
+          = f.hidden_field :title, value: @wiki.title
+          = f.select :format, options_for_select(GollumWiki::MARKUPS, {selected: @wiki.format}), {}, class: "pull-right input-medium"
+          = f.label :format, class: "pull-right", style: "padding-right: 20px;"
     .ui-box-body
       .input
         %span.cgray
@@ -22,6 +25,9 @@
     .ui-box-bottom
       = f.label :content
       .input= f.text_area :content, class: 'span8 js-gfm-input'
+    .ui-box-bottom
+      = f.label :commit_message
+      .input= f.text_field :message, class: 'span8'
   .actions
     = f.submit 'Save', class: "btn-save btn"
     = link_to "Cancel", project_wiki_path(@project, :index), class: "btn btn-cancel"
diff --git a/app/views/wikis/_main_links.html.haml b/app/views/wikis/_main_links.html.haml
new file mode 100644
index 0000000000000000000000000000000000000000..262ed74681c5c519e1ffa01127936e519858e153
--- /dev/null
+++ b/app/views/wikis/_main_links.html.haml
@@ -0,0 +1,16 @@
+%span.pull-right
+  = link_to project_wiki_path(@project, :home), class: "btn btn-small grouped" do
+    Home
+  = link_to pages_project_wikis_path(@project), class: "btn btn-small grouped" do
+    Pages
+  - if (@wiki && @wiki.persisted?)
+    = link_to history_project_wiki_path(@project, @wiki), class: "btn btn-small grouped" do
+      History
+  - if can?(current_user, :write_wiki, @project)
+    - if @wiki && @wiki.persisted?
+      = link_to edit_project_wiki_path(@project, @wiki), class: "btn btn-small grouped" do
+        %i.icon-edit
+        Edit
+    = link_to git_access_project_wikis_path(@project), class: "btn btn-small grouped" do
+      %i.icon-download-alt
+      Git Access
diff --git a/app/views/wikis/edit.html.haml b/app/views/wikis/edit.html.haml
index 9e221aba47dfcbb24c1ce8e2f8160c7126221cbe..1e78d16e53baa8dae29603bc25b6e5a5a95b2bce 100644
--- a/app/views/wikis/edit.html.haml
+++ b/app/views/wikis/edit.html.haml
@@ -1,8 +1,10 @@
-%h3.page_title Editing page
+%h3.page_title
+  Editing page
+  = render partial: 'main_links'
 %hr
 = render 'form'
 
 .pull-right
   - if can? current_user, :admin_wiki, @project
-    = link_to project_wiki_path(@project, @wiki), confirm: "Are you sure you want to delete this page?", method: :delete, class: "btn btn-small btn-remove" do
-      Delete this page
\ No newline at end of file
+    = link_to project_wikis_path(@project, @wiki), confirm: "Are you sure you want to delete this page?", method: :delete, class: "btn btn-small btn-remove" do
+      Delete this page
diff --git a/app/views/wikis/git_access.html.haml b/app/views/wikis/git_access.html.haml
new file mode 100644
index 0000000000000000000000000000000000000000..353d86f2d4d3a3259e772abb59fb69eefdfed610
--- /dev/null
+++ b/app/views/wikis/git_access.html.haml
@@ -0,0 +1,36 @@
+%h3.page_title
+  Git Access
+  %strong= @gollum_wiki.path_with_namespace
+  = render partial: 'main_links'
+
+%br
+.content
+  .project_clone_panel
+    .row
+      .span7
+        .form-horizontal
+          .input-prepend.project_clone_holder
+            %button{class: "btn active", :"data-clone" => @gollum_wiki.ssh_url_to_repo} SSH
+            %button{class: "btn", :"data-clone" => @gollum_wiki.http_url_to_repo}= Gitlab.config.gitlab.protocol.upcase
+            = text_field_tag :project_clone, @gollum_wiki.url_to_repo, class: "one_click_select input-xxlarge", readonly: true
+  .git-empty
+    %fieldset
+      %legend Install Gollum:
+      %pre.dark
+        :preserve
+          gem install gollum
+
+      %legend Clone Your Wiki:
+      %pre.dark
+        :preserve
+          git clone #{@gollum_wiki.path_with_namespace}.git
+          cd #{@gollum_wiki.path_with_namespace}
+
+      %legend Start Gollum And Edit Locally:
+      %pre.dark
+        :preserve
+          gollum
+          == Sinatra/1.3.5 has taken the stage on 4567 for development with backup from Thin
+          >> Thin web server (v1.5.0 codename Knife)
+          >> Maximum connections set to 1024
+          >> Listening on 0.0.0.0:4567, CTRL+C to stop
diff --git a/app/views/wikis/history.html.haml b/app/views/wikis/history.html.haml
index 18df8e1d71b6d766a2484a557da978abbf91cfe6..609207106aba554502367fb1e7384be9e8467852 100644
--- a/app/views/wikis/history.html.haml
+++ b/app/views/wikis/history.html.haml
@@ -1,23 +1,29 @@
 %h3.page_title
   %span.cgray History for
-  = @wiki_pages.first.title
+  = @wiki.title.titleize
+  = render partial: 'main_links'
 %br
 %table
   %thead
     %tr
       %th Page version
+      %th Author
+      %th Commit Message
       %th Last updated
-      %th Updated by
+      %th Format
   %tbody
-    - @wiki_pages.each_with_index do |wiki_page, i|
+    - @wiki.versions.each do |version|
+      - commit = CommitDecorator.new(version)
       %tr
         %td
-          %strong
-            = link_to project_wiki_path(@project, wiki_page, version_id: wiki_page.id) do
-              Version
-              = @wiki_pages.count - i
+          = link_to project_wiki_path(@project, @wiki, version_id: commit.id) do
+            = commit.short_id
+        %td= commit.author_link avatar: true, size: 24
+        %td
+          = commit.title
         %td
-          = wiki_page.created_at.to_s(:short)
-          (#{time_ago_in_words(wiki_page.created_at)}
-          ago)
-        %td= link_to_member(@project, wiki_page.user)
+          = time_ago_in_words(version.date)
+          ago
+        %td
+          %strong
+            = @wiki.page.wiki.page(@wiki.page.name, commit.id).try(:format)
diff --git a/app/views/wikis/pages.html.haml b/app/views/wikis/pages.html.haml
index 2e0f091ce72cf358c17ec857fadd61490551952d..fe35a2ede6bf5f66dabd872e4f78c31098a4338b 100644
--- a/app/views/wikis/pages.html.haml
+++ b/app/views/wikis/pages.html.haml
@@ -1,20 +1,24 @@
-%h3.page_title All Pages
+%h3.page_title
+  All Pages
+  = render partial: 'main_links'
 %br
 %table
   %thead
     %tr
       %th Title
-      %th Slug
+      %th Format
       %th Last updated
       %th Updated by
   %tbody
     - @wiki_pages.each do |wiki_page|
       %tr
         %td
-          %strong= link_to wiki_page.title, project_wiki_path(@project, wiki_page)
-        %td= wiki_page.slug
+          %strong= link_to wiki_page.title.titleize, project_wiki_path(@project, wiki_page)
+        %td
+          %strong= wiki_page.format
         %td
           = wiki_page.created_at.to_s(:short) do
             (#{time_ago_in_words(wiki_page.created_at)}
             ago)
-        %td= link_to_member(@project, wiki_page.user)
+        - commit = CommitDecorator.decorate(wiki_page.version)
+        %td= commit.author_link avatar: true, size: 24
diff --git a/app/views/wikis/show.html.haml b/app/views/wikis/show.html.haml
index 7ff8b5cc01ec9e94faaee58d9f74bec4db998542..54d2a7285049eaff94ed14585534f3b219eb11d0 100644
--- a/app/views/wikis/show.html.haml
+++ b/app/views/wikis/show.html.haml
@@ -1,16 +1,8 @@
 %h3.page_title
-  = @wiki.title
-  %span.pull-right
-    = link_to pages_project_wikis_path(@project), class: "btn btn-small grouped" do
-      Pages
-    - if can? current_user, :write_wiki, @project
-      = link_to history_project_wiki_path(@project, @wiki), class: "btn btn-small grouped" do
-        History
-      = link_to edit_project_wiki_path(@project, @wiki), class: "btn btn-small grouped" do
-        %i.icon-edit
-        Edit
+  = @wiki.title.titleize
+  = render partial: 'main_links'
 %br
-- if @wiki != @most_recent_wiki
+- if @wiki.historical?
   .warning_message
     This is an old version of this page.
     You can view the #{link_to "most recent version", project_wiki_path(@project, @wiki)} or browse the #{link_to "history", history_project_wiki_path(@project, @wiki)}.
@@ -18,6 +10,7 @@
 .file_holder
   .file_content.wiki
     = preserve do
-      = markdown @wiki.content
+      = @wiki.formatted_content.html_safe
 
-%p.time Last edited by #{link_to_member @project, @wiki.user}, #{time_ago_in_words @wiki.created_at} ago
+- commit = CommitDecorator.new(@wiki.version)
+%p.time Last edited by #{commit.author_link(avatar: true, size: 16)} #{time_ago_in_words @wiki.created_at} ago
diff --git a/config/routes.rb b/config/routes.rb
index b06fda8f85da6087b41bae6b8ded69e8ee0a76cc..2c9f0fd97e56efbac7a6e37df71c348774b9d23b 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -185,6 +185,8 @@
     resources :wikis, only: [:show, :edit, :destroy, :create] do
       collection do
         get :pages
+        put ':id' => 'wikis#update'
+        get :git_access
       end
 
       member do
diff --git a/lib/api/internal.rb b/lib/api/internal.rb
index c85c01f87bb17ecfb302d8f6c70f360b46a191e3..654dbe8c4cba7580429d768a1ea9bb89465d291b 100644
--- a/lib/api/internal.rb
+++ b/lib/api/internal.rb
@@ -12,10 +12,18 @@ class Internal < Grape::API
       #   ref - branch name
       #
       get "/allowed" do
+        # Check for *.wiki repositories.
+        # Strip out the .wiki from the pathname before finding the
+        # project. This applies the correct project permissions to
+        # the wiki repository as well.
+        project_path = params[:project]
+        project_path.gsub!(/\.wiki/,'') if project_path =~ /\.wiki/
+
         key = Key.find(params[:key_id])
-        project = Project.find_with_namespace(params[:project])
+        project = Project.find_with_namespace(project_path)
         git_cmd = params[:action]
 
+
         if key.is_deploy_key
           project == key.project && git_cmd == 'git-upload-pack'
         else
diff --git a/spec/features/gitlab_flavored_markdown_spec.rb b/spec/features/gitlab_flavored_markdown_spec.rb
index 769fcd688b40e64af8e937d7552b93396d0bf48d..05cef191cfc09cec71a85cc474e5818dc8d5f31d 100644
--- a/spec/features/gitlab_flavored_markdown_spec.rb
+++ b/spec/features/gitlab_flavored_markdown_spec.rb
@@ -208,24 +208,4 @@
     end
   end
 
-
-  describe "for wikis" do
-    before do
-      visit project_wiki_path(project, :index)
-      fill_in "Title", with: "Circumvent ##{issue.id}"
-      fill_in "Content", with: "# Other pages\n\n* [Foo](foo)\n* [Bar](bar)\n\nAlso look at ##{issue.id} :-)"
-      click_on "Save"
-    end
-
-    it "should NOT render title in wikis#show" do
-      within(".content h3") do # page title
-        page.should have_content("Circumvent ##{issue.id}")
-        page.should_not have_link("##{issue.id}")
-      end
-    end
-
-    it "should render content in wikis#show" do
-      page.should have_link("##{issue.id}")
-    end
-  end
 end
diff --git a/spec/models/gollum_wiki_spec.rb b/spec/models/gollum_wiki_spec.rb
new file mode 100644
index 0000000000000000000000000000000000000000..87601683275163ec8f858b193f540b35abacd923
--- /dev/null
+++ b/spec/models/gollum_wiki_spec.rb
@@ -0,0 +1,196 @@
+require "spec_helper"
+
+describe GollumWiki do
+
+  def create_temp_repo(path)
+    FileUtils.mkdir_p path
+    command = "git init --quiet #{path};"
+    system(command)
+  end
+
+  def remove_temp_repo(path)
+    FileUtils.rm_rf path
+  end
+
+  def commit_details
+    commit = {name: user.name, email: user.email, message: "test commit"}
+  end
+
+  def create_page(name, content)
+    subject.wiki.write_page(name, :markdown, content, commit_details)
+  end
+
+  def destroy_page(page)
+    subject.wiki.delete_page(page, commit_details)
+  end
+
+  let(:project) { create(:project) }
+  let(:repository) { project.repository }
+  let(:user) { project.owner }
+  let(:gitlab_shell) { Gitlab::Shell.new }
+
+  subject { GollumWiki.new(project, user) }
+
+  before do
+    create_temp_repo(subject.send(:path_to_repo))
+  end
+
+  describe "#path_with_namespace" do
+    it "returns the project path with namespace with the .wiki extension" do
+      subject.path_with_namespace.should == project.path_with_namespace + ".wiki"
+    end
+  end
+
+  describe "#url_to_repo" do
+    it "returns the correct ssh url to the repo" do
+      subject.url_to_repo.should == gitlab_shell.url_to_repo(subject.path_with_namespace)
+    end
+  end
+
+  describe "#ssh_url_to_repo" do
+    it "equals #url_to_repo" do
+      subject.ssh_url_to_repo.should == subject.url_to_repo
+    end
+  end
+
+  describe "#http_url_to_repo" do
+    it "provides the full http url to the repo" do
+      gitlab_url = Gitlab.config.gitlab.url
+      repo_http_url = "#{gitlab_url}/#{subject.path_with_namespace}.git"
+      subject.http_url_to_repo.should == repo_http_url
+    end
+  end
+
+  describe "#wiki" do
+    it "contains a Gollum::Wiki instance" do
+      subject.wiki.should be_a Gollum::Wiki
+    end
+
+    before do
+      Gitlab::Shell.any_instance.stub(:add_repository) do
+        create_temp_repo("#{Rails.root}/tmp/test-git-base-path/non-existant.wiki.git")
+      end
+      project.stub(:path_with_namespace).and_return("non-existant")
+    end
+
+    it "creates a new wiki repo if one does not yet exist" do
+      wiki = GollumWiki.new(project, user)
+      wiki.create_page("index", "test content").should_not == false
+
+      FileUtils.rm_rf wiki.send(:path_to_repo)
+    end
+
+    it "raises CouldNotCreateWikiError if it can't create the wiki repository" do
+      Gitlab::Shell.any_instance.stub(:add_repository).and_return(false)
+      expect { GollumWiki.new(project, user).wiki }.to raise_exception(GollumWiki::CouldNotCreateWikiError)
+    end
+  end
+
+  describe "#pages" do
+    before do
+      create_page("index", "This is an awesome new Gollum Wiki")
+      @pages = subject.pages
+    end
+
+    after do
+      destroy_page(@pages.first.page)
+    end
+
+    it "returns an array of WikiPage instances" do
+      @pages.first.should be_a WikiPage
+    end
+
+    it "returns the correct number of pages" do
+      @pages.count.should == 1
+    end
+  end
+
+  describe "#find_page" do
+    before do
+      create_page("index page", "This is an awesome Gollum Wiki")
+    end
+
+    after do
+      destroy_page(subject.pages.first.page)
+    end
+
+    it "returns the latest version of the page if it exists" do
+      page = subject.find_page("index page")
+      page.title.should == "index page"
+    end
+
+    it "returns nil if the page does not exist" do
+      subject.find_page("non-existant").should == nil
+    end
+
+    it "can find a page by slug" do
+      page = subject.find_page("index-page")
+      page.title.should == "index page"
+    end
+
+    it "returns a WikiPage instance" do
+      page = subject.find_page("index page")
+      page.should be_a WikiPage
+    end
+  end
+
+  describe "#create_page" do
+    after do
+      destroy_page(subject.pages.first.page)
+    end
+
+    it "creates a new wiki page" do
+      subject.create_page("test page", "this is content").should_not == false
+      subject.pages.count.should == 1
+    end
+
+    it "returns false when a duplicate page exists" do
+      subject.create_page("test page", "content")
+      subject.create_page("test page", "content").should == false
+    end
+
+    it "stores an error message when a duplicate page exists" do
+      2.times { subject.create_page("test page", "content") }
+      subject.error_message.should =~ /Duplicate page:/
+    end
+
+    it "sets the correct commit message" do
+      subject.create_page("test page", "some content", :markdown, "commit message")
+      subject.pages.first.page.version.message.should == "commit message"
+    end
+  end
+
+  describe "#update_page" do
+    before do
+      create_page("update-page", "some content")
+      @gollum_page = subject.wiki.paged("update-page")
+      subject.update_page(@gollum_page, "some other content", :markdown, "updated page")
+      @page = subject.pages.first.page
+    end
+
+    after do
+      destroy_page(@page)
+    end
+
+    it "updates the content of the page" do
+      @page.raw_data.should == "some other content"
+    end
+
+    it "sets the correct commit message" do
+      @page.version.message.should == "updated page"
+    end
+  end
+
+  describe "#delete_page" do
+    before do
+      create_page("index", "some content")
+      @page = subject.wiki.paged("index")
+    end
+
+    it "deletes the page" do
+      subject.delete_page(@page)
+      subject.pages.count.should == 0
+    end
+  end
+
+end
diff --git a/spec/models/wiki_page_spec.rb b/spec/models/wiki_page_spec.rb
new file mode 100644
index 0000000000000000000000000000000000000000..67f2a6da42d913cf240d9f25ded42e8353a12fb0
--- /dev/null
+++ b/spec/models/wiki_page_spec.rb
@@ -0,0 +1,164 @@
+require "spec_helper"
+
+describe WikiPage do
+
+  def create_temp_repo(path)
+    FileUtils.mkdir_p path
+    command = "git init --quiet #{path};"
+    system(command)
+  end
+
+  def remove_temp_repo(path)
+    FileUtils.rm_rf path
+  end
+
+  def commit_details
+    commit = {name: user.name, email: user.email, message: "test commit"}
+  end
+
+  def create_page(name, content)
+    wiki.wiki.write_page(name, :markdown, content, commit_details)
+  end
+
+  def destroy_page(title)
+    page = wiki.wiki.paged(title)
+    wiki.wiki.delete_page(page, commit_details)
+  end
+
+  let(:project) { create(:project) }
+  let(:repository) { project.repository }
+  let(:user) { project.owner }
+  let(:wiki) { GollumWiki.new(project, user) }
+
+  subject { WikiPage.new(wiki) }
+
+  before do
+    create_temp_repo(wiki.send(:path_to_repo))
+  end
+
+  describe "#initialize" do
+    context "when initialized with an existing gollum page" do
+      before do
+        create_page("test page", "test content")
+        @page = wiki.wiki.paged("test page")
+        @wiki_page = WikiPage.new(wiki, @page, true)
+      end
+
+      it "sets the slug attribute" do
+        @wiki_page.slug.should == "test-page"
+      end
+
+      it "sets the title attribute" do
+        @wiki_page.title.should == "test page"
+      end
+
+      it "sets the formatted content attribute" do
+        @wiki_page.content.should == "test content"
+      end
+
+      it "sets the format attribute" do
+        @wiki_page.format.should == :markdown
+      end
+
+      it "sets the message attribute" do
+        @wiki_page.message.should == "test commit"
+      end
+
+      it "sets the version attribute" do
+        @wiki_page.version.should be_a Commit
+      end
+    end
+  end
+
+  describe "validations" do
+    before do
+      subject.attributes = {title: 'title', content: 'content'}
+    end
+
+    it "validates presence of title" do
+      subject.attributes.delete(:title)
+      subject.valid?.should be_false
+    end
+
+    it "validates presence of content" do
+      subject.attributes.delete(:content)
+      subject.valid?.should be_false
+    end
+  end
+
+  before do
+    @wiki_attr = {title: "Index", content: "Home Page", format: "markdown"}
+  end
+
+  describe "#create" do
+    after do
+      destroy_page("Index")
+    end
+
+    context "with valid attributes" do
+      it "saves the wiki page" do
+        subject.create(@wiki_attr)
+        wiki.find_page("Index").should_not be_nil
+      end
+
+      it "returns true" do
+        subject.create(@wiki_attr).should == true
+      end
+    end
+  end
+
+  describe "#update" do
+    before do
+      create_page("Update", "content")
+      @page = wiki.find_page("Update")
+    end
+
+    after do
+      destroy_page("Update")
+    end
+
+    context "with valid attributes" do
+      it "updates the content of the page" do
+        @page.update("new content")
+        @page = wiki.find_page("Update")
+      end
+
+      it "returns true" do
+        @page.update("more content").should be_true
+      end
+    end
+  end
+
+  describe "#destroy" do
+    before do
+      create_page("Delete Page", "content")
+      @page = wiki.find_page("Delete Page")
+    end
+
+    it "should delete the page" do
+      @page.delete
+      wiki.pages.should be_empty
+    end
+
+    it "should return true" do
+      @page.delete.should == true
+    end
+  end
+
+  describe "#versions" do
+    before do
+      create_page("Update", "content")
+      @page = wiki.find_page("Update")
+    end
+
+    after do
+      destroy_page("Update")
+    end
+
+    it "returns an array of all commits for the page" do
+      3.times { |i| @page.update("content #{i}") }
+      @page.versions.count.should == 4
+    end
+  end
+
+end