diff --git a/files/gitlab-config-template/gitlab.rb.template b/files/gitlab-config-template/gitlab.rb.template
index de01e768b91a4893b8e4fa8214e5d173287e6619_ZmlsZXMvZ2l0bGFiLWNvbmZpZy10ZW1wbGF0ZS9naXRsYWIucmIudGVtcGxhdGU=..2894e127b28159b0cd1d1a2215601851f71337a2_ZmlsZXMvZ2l0bGFiLWNvbmZpZy10ZW1wbGF0ZS9naXRsYWIucmIudGVtcGxhdGU= 100644
--- a/files/gitlab-config-template/gitlab.rb.template
+++ b/files/gitlab-config-template/gitlab.rb.template
@@ -1621,6 +1621,10 @@
 ##! internal git
 ################################################################################
 
+##! The format of the Omnibus gitconfig is:
+##! { "section" => ["subsection = value"] }
+##! For example:
+##! { "pack" => ["threads = 1"] }
 ##! For multiple options under one header use array of comma separated values,
 ##! eg.:
 ##! { "receive" => ["fsckObjects = true"], "alias" => ["st = status", "co = checkout"] }
@@ -1624,18 +1628,7 @@
 ##! For multiple options under one header use array of comma separated values,
 ##! eg.:
 ##! { "receive" => ["fsckObjects = true"], "alias" => ["st = status", "co = checkout"] }
-
-# omnibus_gitconfig['system'] = {
-#  "pack" => ["threads = 1"],
-#  "receive" => ["fsckObjects = true", "advertisePushOptions = true"],
-#  "repack" => ["writeBitmaps = true"],
-#  "transfer" => ["hideRefs=^refs/tmp/", "hideRefs=^refs/keep-around/", "hideRefs=^refs/remotes/"],
-#  "core" => [
-#    'alternateRefsCommand="exit 0 #"',
-#    "fsyncObjectFiles = true"
-#  ],
-#  "fetch" => ["writeCommitGraph = true"]
-# }
+# omnibus_gitconfig['system'] = {}
 
 ################################################################################
 ## GitLab Pages
diff --git a/files/gitlab-cookbooks/gitaly/libraries/gitaly.rb b/files/gitlab-cookbooks/gitaly/libraries/gitaly.rb
index de01e768b91a4893b8e4fa8214e5d173287e6619_ZmlsZXMvZ2l0bGFiLWNvb2tib29rcy9naXRhbHkvbGlicmFyaWVzL2dpdGFseS5yYg==..2894e127b28159b0cd1d1a2215601851f71337a2_ZmlsZXMvZ2l0bGFiLWNvb2tib29rcy9naXRhbHkvbGlicmFyaWVzL2dpdGFseS5yYg== 100644
--- a/files/gitlab-cookbooks/gitaly/libraries/gitaly.rb
+++ b/files/gitlab-cookbooks/gitaly/libraries/gitaly.rb
@@ -97,17 +97,23 @@
         end
       end
 
-      # ... but remove any of its values that are part of the default
-      # configuration. We do not want to inject our old default values into
-      # Gitaly anymore given that it is setting its own defaults nowadays.
-      # Furthermore, we must not inject the `core.fsyncObjectFiles` config
-      # entry, which has been deprecated in Git.
-      omnibus_gitconfig -= Gitlab['node']['gitlab']['omnibus-gitconfig']['system'].flat_map do |section, entries|
-        entries.map do |entry|
-          key, value = entry.split('=', 2)
-          "#{section}.#{key.rstrip}=#{value.lstrip}"
-        end
-      end
+      # ... but remove any of its values that had been part of the default
+      # configuration when introducing the Gitaly gitconfig. We do not want to
+      # inject our old default values into Gitaly anymore given that it is
+      # setting its own defaults nowadays. Furthermore, we must not inject the
+      # `core.fsyncObjectFiles` config entry, which has been deprecated in Git.
+      omnibus_gitconfig -= [
+        'pack.threads=1',
+        'receive.advertisePushOptions=true',
+        'receive.fsckObjects=true',
+        'repack.writeBitmaps=true',
+        'transfer.hideRefs=^refs/tmp/',
+        'transfer.hideRefs=^refs/keep-around/',
+        'transfer.hideRefs=^refs/remotes/',
+        'core.alternateRefsCommand="exit 0 #"',
+        'core.fsyncObjectFiles=true',
+        'fetch.writeCommitGraph=true'
+      ]
 
       # The configuration format has changed. Previously, we had a map of
       # top-level config entry keys to their sublevel entry keys which also
diff --git a/files/gitlab-cookbooks/gitlab/attributes/default.rb b/files/gitlab-cookbooks/gitlab/attributes/default.rb
index de01e768b91a4893b8e4fa8214e5d173287e6619_ZmlsZXMvZ2l0bGFiLWNvb2tib29rcy9naXRsYWIvYXR0cmlidXRlcy9kZWZhdWx0LnJi..2894e127b28159b0cd1d1a2215601851f71337a2_ZmlsZXMvZ2l0bGFiLWNvb2tib29rcy9naXRsYWIvYXR0cmlidXRlcy9kZWZhdWx0LnJi 100644
--- a/files/gitlab-cookbooks/gitlab/attributes/default.rb
+++ b/files/gitlab-cookbooks/gitlab/attributes/default.rb
@@ -20,17 +20,6 @@
 # omnibus options
 ####
 default['gitlab']['bootstrap']['enable'] = true
-default['gitlab']['omnibus-gitconfig']['system'] = {
-  "pack" => ["threads = 1"],
-  "receive" => ["fsckObjects = true", "advertisePushOptions = true"],
-  "repack" => ["writeBitmaps = true"],
-  "transfer" => ["hideRefs=^refs/tmp/", "hideRefs=^refs/keep-around/", "hideRefs=^refs/remotes/"],
-  "core" => [
-    'alternateRefsCommand="exit 0 #"',
-    "fsyncObjectFiles = true"
-  ],
-  "fetch" => ["writeCommitGraph = true"]
-}
 # Create users and groups needed for the package
 default['gitlab']['manage-accounts']['enable'] = true
 
diff --git a/files/gitlab-cookbooks/gitlab/recipes/default.rb b/files/gitlab-cookbooks/gitlab/recipes/default.rb
index de01e768b91a4893b8e4fa8214e5d173287e6619_ZmlsZXMvZ2l0bGFiLWNvb2tib29rcy9naXRsYWIvcmVjaXBlcy9kZWZhdWx0LnJi..2894e127b28159b0cd1d1a2215601851f71337a2_ZmlsZXMvZ2l0bGFiLWNvb2tib29rcy9naXRsYWIvcmVjaXBlcy9kZWZhdWx0LnJi 100644
--- a/files/gitlab-cookbooks/gitlab/recipes/default.rb
+++ b/files/gitlab-cookbooks/gitlab/recipes/default.rb
@@ -70,7 +70,7 @@
 template "#{install_dir}/embedded/etc/gitconfig" do
   source "gitconfig-system.erb"
   mode 0755
-  variables gitconfig: node['gitlab']['omnibus-gitconfig']['system']
+  variables gitconfig: node.dig('gitlab', 'omnibus-gitconfig', 'system') || {}
 end
 
 # This recipe needs to run before gitlab-rails
diff --git a/files/gitlab-cookbooks/gitlab/recipes/users.rb b/files/gitlab-cookbooks/gitlab/recipes/users.rb
index de01e768b91a4893b8e4fa8214e5d173287e6619_ZmlsZXMvZ2l0bGFiLWNvb2tib29rcy9naXRsYWIvcmVjaXBlcy91c2Vycy5yYg==..2894e127b28159b0cd1d1a2215601851f71337a2_ZmlsZXMvZ2l0bGFiLWNvb2tib29rcy9naXRsYWIvcmVjaXBlcy91c2Vycy5yYg== 100644
--- a/files/gitlab-cookbooks/gitlab/recipes/users.rb
+++ b/files/gitlab-cookbooks/gitlab/recipes/users.rb
@@ -43,7 +43,7 @@
   group gitlab_group
   mode "0644"
   variables(user_options: node['gitlab']['user'],
-            system_core_options: node['gitlab']['omnibus-gitconfig']['system']['core'])
+            system_core_options: node.dig('gitlab', 'omnibus-gitconfig', 'system', 'core') || [])
 end
 
 # The directory will remain empty in Omnibus GitLab use-case.
diff --git a/spec/chef/cookbooks/gitlab/recipes/default_spec.rb b/spec/chef/cookbooks/gitlab/recipes/default_spec.rb
index de01e768b91a4893b8e4fa8214e5d173287e6619_c3BlYy9jaGVmL2Nvb2tib29rcy9naXRsYWIvcmVjaXBlcy9kZWZhdWx0X3NwZWMucmI=..2894e127b28159b0cd1d1a2215601851f71337a2_c3BlYy9jaGVmL2Nvb2tib29rcy9naXRsYWIvcmVjaXBlcy9kZWZhdWx0X3NwZWMucmI= 100644
--- a/spec/chef/cookbooks/gitlab/recipes/default_spec.rb
+++ b/spec/chef/cookbooks/gitlab/recipes/default_spec.rb
@@ -22,21 +22,5 @@
       group: 'root',
       mode: '0755'
     )
-
-    gitconfig_hash = {
-      "receive" => ["fsckObjects = true", "advertisePushOptions = true"],
-      "pack" => ["threads = 1"],
-      "repack" => ["writeBitmaps = true"],
-      "transfer" => ["hideRefs=^refs/tmp/", "hideRefs=^refs/keep-around/", "hideRefs=^refs/remotes/"],
-      "core" => [
-        'alternateRefsCommand="exit 0 #"',
-        "fsyncObjectFiles = true"
-      ],
-      "fetch" => ["writeCommitGraph = true"]
-    }
-
-    expect(chef_run).to create_template('/opt/gitlab/embedded/etc/gitconfig').with(
-      variables: { gitconfig: gitconfig_hash }
-    )
   end
 
@@ -41,5 +25,26 @@
   end
 
-  it 'creates the system gitconfig directory and file' do
-    stub_gitlab_rb(omnibus_gitconfig: { system: { receive: ["fsckObjects = true", "advertisePushOptions = true"], pack: ["threads = 2"] } })
+  context 'with gitconfig' do
+    shared_examples 'a rendered system-level gitconfig' do
+      before do
+        stub_gitlab_rb(gitlab_config)
+      end
+
+      it 'creates the system gitconfig directory' do
+        expect(chef_run).to create_directory('/opt/gitlab/embedded/etc').with(
+          user: 'root',
+          group: 'root',
+          mode: '0755'
+        )
+      end
+
+      it 'creates the gitconfig file' do
+        expect(chef_run).to create_template('/opt/gitlab/embedded/etc/gitconfig').with(
+          source: 'gitconfig-system.erb',
+          variables: {
+            gitconfig: expected_params
+          },
+          mode: 0755
+        )
+      end
 
@@ -45,7 +50,35 @@
 
-    expect(chef_run).to create_directory('/opt/gitlab/embedded/etc').with(
-      user: 'root',
-      group: 'root',
-      mode: '0755'
-    )
+      it 'renders the gitconfig file' do
+        expect(chef_run).to render_file('/opt/gitlab/embedded/etc/gitconfig').with_content { |content|
+          expect(content).to match(expected_content)
+        }
+      end
+    end
+
+    context 'with default gitconfig' do
+      let(:gitlab_config) { {} }
+      let(:expected_params) { {} }
+      let(:expected_content) { '' }
+
+      it_behaves_like 'a rendered system-level gitconfig'
+    end
+
+    context 'with omnibus_gitconfig' do
+      let(:gitlab_config) do
+        {
+          omnibus_gitconfig: {
+            system: {
+              receive: ["fsckObjects = true", "advertisePushOptions = true"],
+              pack: ["threads = 2"]
+            }
+          }
+        }
+      end
+
+      let(:expected_params) do
+        {
+          "receive" => ["fsckObjects = true", "advertisePushOptions = true"],
+          "pack" => ["threads = 2"]
+        }
+      end
 
@@ -51,13 +84,31 @@
 
-    gitconfig_hash = {
-      "receive" => ["fsckObjects = true", "advertisePushOptions = true"],
-      "pack" => ["threads = 2"],
-      "repack" => ["writeBitmaps = true"],
-      "transfer" => ["hideRefs=^refs/tmp/", "hideRefs=^refs/keep-around/", "hideRefs=^refs/remotes/"],
-      "core" => [
-        'alternateRefsCommand="exit 0 #"',
-        "fsyncObjectFiles = true"
-      ],
-      "fetch" => ["writeCommitGraph = true"]
-    }
+      let(:expected_content) do
+        <<-EOF
+[receive]
+  fsckObjects = true
+advertisePushOptions = true
+[pack]
+  threads = 2
+        EOF
+      end
+
+      it_behaves_like 'a rendered system-level gitconfig'
+    end
+
+    context 'with empty section' do
+      let(:gitlab_config) do
+        {
+          omnibus_gitconfig: {
+            system: {
+              transfer: [],
+            }
+          }
+        }
+      end
+
+      let(:expected_params) do
+        {
+          "transfer" => [],
+        }
+      end
 
@@ -63,9 +114,46 @@
 
-    expect(chef_run).to create_template('/opt/gitlab/embedded/etc/gitconfig').with(
-      source: 'gitconfig-system.erb',
-      variables: { gitconfig: gitconfig_hash },
-      mode: 0755
-    )
+      let(:expected_content) do
+        # rubocop:disable Layout/TrailingWhitespace
+        <<-EOF
+[transfer]
+  
+        EOF
+        # rubocop:enable Layout/TrailingWhitespace
+      end
+
+      it_behaves_like 'a rendered system-level gitconfig'
+    end
+
+    context 'with subsections' do
+      let(:gitlab_config) do
+        {
+          omnibus_gitconfig: {
+            system: {
+              'http "http://example.com"' => [
+                "proxy = http://proxy.example.com"
+              ]
+            }
+          }
+        }
+      end
+
+      let(:expected_params) do
+        {
+          'http "http://example.com"' => [
+            "proxy = http://proxy.example.com",
+          ]
+        }
+      end
+
+      let(:expected_content) do
+        <<-EOF
+[http "http://example.com"]
+  proxy = http://proxy.example.com
+        EOF
+      end
+
+      it_behaves_like 'a rendered system-level gitconfig'
+    end
   end
 
   context 'with logrotate' do
diff --git a/spec/chef/cookbooks/gitlab/recipes/users_spec.rb b/spec/chef/cookbooks/gitlab/recipes/users_spec.rb
index de01e768b91a4893b8e4fa8214e5d173287e6619_c3BlYy9jaGVmL2Nvb2tib29rcy9naXRsYWIvcmVjaXBlcy91c2Vyc19zcGVjLnJi..2894e127b28159b0cd1d1a2215601851f71337a2_c3BlYy9jaGVmL2Nvb2tib29rcy9naXRsYWIvcmVjaXBlcy91c2Vyc19zcGVjLnJi 100644
--- a/spec/chef/cookbooks/gitlab/recipes/users_spec.rb
+++ b/spec/chef/cookbooks/gitlab/recipes/users_spec.rb
@@ -1,7 +1,7 @@
 require 'chef_helper'
 
 RSpec.describe 'gitlab::users' do
-  let(:chef_run) { ChefSpec::SoloRunner.new.converge('gitlab::users') }
+  let(:chef_run) { ChefSpec::SoloRunner.new.converge('gitlab::default') }
 
   before do
     allow(Gitlab).to receive(:[]).and_call_original
@@ -20,21 +20,6 @@
       expect(chef_run).to create_account('GitLab user and group').with(account_params)
     end
 
-    it 'creates .gitconfig' do
-      template_params = {
-        owner: 'git',
-        group: 'git',
-        mode: '0644'
-      }
-
-      expect(chef_run).to create_template('/var/opt/gitlab/.gitconfig').with(template_params)
-      expect(chef_run).to render_file('/var/opt/gitlab/.gitconfig').with_content { |content|
-        expect(content).to match(/name = GitLab/)
-        expect(content).to match(/email = gitlab@fauxhai.local/)
-        expect(content).to match(/fsyncObjectFiles = true/)
-      }
-    end
-
     it 'creates .bundle directory' do
       directory_params = {
         owner: 'git',
@@ -44,4 +29,131 @@
       expect(chef_run).to create_directory('/var/opt/gitlab/.bundle').with(directory_params)
     end
   end
+
+  context 'user gitconfig' do
+    let(:gitconfig_header) do
+      <<-EOF
+# This file is managed by gitlab-ctl. Manual changes will be
+# erased! To change the contents below, edit /etc/gitlab/gitlab.rb
+# and run `sudo gitlab-ctl reconfigure`.
+      EOF
+    end
+
+    shared_examples 'a rendered .gitconfig' do
+      it 'creates the template' do
+        template_params = {
+          owner: 'git',
+          group: 'git',
+          mode: '0644',
+          variables: {
+            user_options: {
+              "gid" => nil,
+              "git_user_email" => "gitlab@fauxhai.local",
+              "git_user_name" => "GitLab",
+              "group" => "git",
+              "home" => "/var/opt/gitlab",
+              "shell" => "/bin/sh",
+              "uid" => nil,
+              "username" => "git"
+            },
+            system_core_options: expected_options,
+          }
+        }
+
+        expect(chef_run).to create_template('/var/opt/gitlab/.gitconfig').with(template_params)
+      end
+
+      it 'renders the gitconfig' do
+        expect(chef_run).to render_file('/var/opt/gitlab/.gitconfig').with_content { |content|
+          expect(content).to match(expected_content)
+        }
+      end
+    end
+
+    context 'with default attributes' do
+      let(:expected_options) { [] }
+      let(:expected_content) do
+        # rubocop:disable Layout/TrailingWhitespace
+        <<-EOF
+#{gitconfig_header}
+[user]
+        name = GitLab
+        email = gitlab@fauxhai.local
+[core]
+        autocrlf = input
+        
+[gc]
+        auto = 0
+        EOF
+        # rubocop:enable Layout/TrailingWhitespace
+      end
+
+      it_behaves_like 'a rendered .gitconfig'
+    end
+
+    context 'with non-core gitconfig' do
+      let(:expected_options) { [] }
+      let(:expected_content) do
+        # rubocop:disable Layout/TrailingWhitespace
+        <<-EOF
+#{gitconfig_header}
+[user]
+        name = GitLab
+        email = gitlab@fauxhai.local
+[core]
+        autocrlf = input
+        
+[gc]
+        auto = 0
+        EOF
+        # rubocop:enable Layout/TrailingWhitespace
+      end
+
+      before do
+        stub_gitlab_rb(
+          omnibus_gitconfig: {
+            system: {
+              pack: ["threads=1"],
+            }
+          }
+        )
+      end
+
+      it_behaves_like 'a rendered .gitconfig'
+    end
+
+    context 'with core gitconfig' do
+      let(:expected_options) do
+        [
+          'example = value'
+        ]
+      end
+
+      let(:expected_content) do
+        <<-EOF
+#{gitconfig_header}
+[user]
+        name = GitLab
+        email = gitlab@fauxhai.local
+[core]
+        autocrlf = input
+        example = value
+[gc]
+        auto = 0
+        EOF
+      end
+
+      before do
+        stub_gitlab_rb(
+          omnibus_gitconfig: {
+            system: {
+              core: ["example = value"],
+            }
+          }
+        )
+      end
+
+      it_behaves_like 'a rendered .gitconfig'
+    end
+  end
 end