diff --git a/roles/redirects/defaults/main.yml b/roles/redirects/defaults/main.yml
index 84e8d2161969a34d19192cba3107ccb84e33be23..2df1f5917a8c64b370667ea68b8eb6c55703d6c6 100644
--- a/roles/redirects/defaults/main.yml
+++ b/roles/redirects/defaults/main.yml
@@ -2,6 +2,7 @@
 #   - domain: the domain to listen on
 #   - to: the redirect target as defined by the nginx return statement
 #   - type: HTTP status code to use (302 = temporary redirect, 301 = permanent redirect)
+#   - map: the mapping file
 redirects:
   - mailman:
     domain: mailman.archlinux.org
@@ -15,3 +16,8 @@ redirects:
     domain: coc.archlinux.org
     to: https://gitlab.archlinux.org/archlinux/service-agreements/-/blob/master/code-of-conduct.md
     type: 302
+  - cgit:
+    domain: git.archlinux.org
+    to: https://gitlab.archlinux.org
+    type: 301
+    map: maps/cgit-migrated-repos.map
diff --git a/roles/redirects/files/maps/cgit-migrated-repos.map b/roles/redirects/files/maps/cgit-migrated-repos.map
new file mode 100644
index 0000000000000000000000000000000000000000..90a26c337cf198c17acfea2100cca1ef24bf49ed
--- /dev/null
+++ b/roles/redirects/files/maps/cgit-migrated-repos.map
@@ -0,0 +1,5 @@
+/pacman.git https://gitlab.archlinux.org/pacman/pacman;
+/pacman-contrib.git https://gitlab.archlinux.org/pacman/pacman-contrib;
+
+/netctl.git https://gitlab.archlinux.org/archlinux/netctl;
+/mkinitcpio.git https://github.com/archlinux/mkinitcpio;
diff --git a/roles/redirects/tasks/main.yml b/roles/redirects/tasks/main.yml
index 9efb268c6ab8e94aa5a7c45756542524d724b91b..aa0bc60e2a812df59bb4a30cc4978fa6e1ed036d 100644
--- a/roles/redirects/tasks/main.yml
+++ b/roles/redirects/tasks/main.yml
@@ -14,3 +14,6 @@
   template: src=nginx.d.conf.j2 dest="/etc/nginx/nginx.d/redirects.conf" owner=root group=root mode=644
   notify: reload nginx
   tags: ['nginx']
+
+- name: copy nginx map files
+  copy: src=maps dest=/etc/nginx/ owner=root group=root mode=0600
diff --git a/roles/redirects/templates/nginx.d.conf.j2 b/roles/redirects/templates/nginx.d.conf.j2
index 28f391a385d234468d65271eef0707a57e0a598b..dca0cf059b5f4bf360311f4b0ad84f5392e36664 100644
--- a/roles/redirects/templates/nginx.d.conf.j2
+++ b/roles/redirects/templates/nginx.d.conf.j2
@@ -1,4 +1,11 @@
 {% for redirect in redirects %}
+{% if redirect.map is defined %}
+map $uri ${{ redirect.map | hash('md5') }} {
+    default "";
+    include {{ redirect.map }};
+}
+
+{% endif %}
 server {
     listen       80;
     listen       [::]:80;
@@ -17,7 +24,12 @@ server {
     include snippets/letsencrypt.conf;
 
     location / {
-    	return {{ redirect.type }} {{ redirect.to }};
+        {% if redirect.map is defined %}
+        if (${{ redirect.map | hash('md5') }} != "") {
+             return {{ redirect.type }} ${{ redirect.map | hash('md5') }};
+        }
+        {% endif %}
+        return {{ redirect.type }} {{ redirect.to }};
     }
 }
 {% endfor %}
diff --git a/tf-stage1/archlinux.tf b/tf-stage1/archlinux.tf
index e492af1ce66b23331525fcbe59c9cc6843ee969b..08274ee930a7934278670add5aba94651418fbc1 100644
--- a/tf-stage1/archlinux.tf
+++ b/tf-stage1/archlinux.tf
@@ -288,6 +288,7 @@ locals {
     status        = { value = "stats.uptimerobot.com." }
     svn           = { value = "gemini" }
     coc           = { value = "redirect" }
+    git           = { value = "redirect" }
 
     # MTA-STS
     mta-sts               = { value = "mail" }