diff --git a/Documents/bin/git-namespace-backup b/Documents/bin/git-namespace-backup
new file mode 100755
index 0000000000000000000000000000000000000000..0653a980330e809c34157b2ac0109aec15aee6da
--- /dev/null
+++ b/Documents/bin/git-namespace-backup
@@ -0,0 +1,143 @@
+#!/usr/bin/env python3
+# pylint: disable=invalid-name
+"""Backup a Git repositories namespace to my GitLab instace.
+
+Which means creating a namespace in GitLab, creating a project for every
+repository in the namespace, adding a remote to the repository and pushing
+everything to that project.
+
+In this context, a namespace is a directory under ~/Repositories.
+"""
+
+import argparse
+import pathlib
+import sys
+import os
+import os.path
+import re
+import gitlab  # pylint: disable=import-error
+import sh  # pylint: disable=import-error
+from sh.contrib import git  # pylint: disable=import-error
+
+
+def namespace_path(namespace):
+    """Returns the full path to the namespace.
+
+    Raises an exception if the path doesn't exits or isn't a directory.
+    """
+    path = pathlib.Path(os.path.expanduser("~/Repositories/" + namespace))
+    if not path.exists():
+        raise argparse.ArgumentTypeError("Path {} does not exit.".format(path))
+    if not path.is_dir():
+        raise argparse.ArgumentTypeError(
+            "Path {} is not a directory.".format(path)
+        )
+    return path
+
+
+def name_to_path(name):
+    """Converts a name to valid path in GitLab."""
+    return re.sub("[^a-zA-Z0-9_-]", "-", name).lower()
+
+
+def get_group(lab, name):
+    """Returns a GitLab group object.
+
+    If a group with that name already exists, return that. Otherwise create a
+    new group and return that instead.
+    """
+    for i in lab.groups.list():
+        if i.name == name:
+            print(
+                "Using existing group id: {}, name: {}, path: {}.".format(
+                    i.id, i.name, i.path
+                ),
+                file=sys.stderr,
+            )
+            return i
+    new_group = lab.groups.create(
+        {
+            "name": name,
+            "path": name_to_path(name),
+            "visivility": "internal",
+        }
+    )
+    print(
+        "Created new group id: {}, name: {}, path: {}.".format(
+            new_group.id, new_group.name, new_group.path
+        ),
+        file=sys.stderr,
+    )
+    return group
+
+
+def get_project(group, name):  # pylint: disable=redefined-outer-name
+    """Returns a GitLab project.
+
+    If a project with that name already exists, return that. Otherwise create a
+    new project and return that instead.
+    """
+    for i in group.projects.list():
+        if i.name == name:
+            print(
+                "Using existing project id: {}, name: {}, path: {}.".format(
+                    i.id, i.name, i.path
+                ),
+                file=sys.stderr,
+            )
+            return i
+    new_project = group.projects.gitlab.projects.create(
+        {"name": name, "namespace_id": group.id}
+    )
+    print(
+        "Created new project id: {}, name: {}, path: {}.".format(
+            new_project.id, new_project.name, new_project.path
+        ),
+        file=sys.stderr,
+    )
+    return project
+
+
+def is_git_repo(path):
+    """Returns a boolean if the path is a Git repo."""
+    return path.is_dir() and pathlib.Path(path, ".git").is_dir()
+
+
+def list_repositories(namespace):
+    """Returns a list of paths under the namespace that are Git
+    repositories."""
+    return [x for x in namespace.iterdir() if is_git_repo(x)]
+
+
+TOKEN = os.environ["GITLAB_PRIVATE_TOKEN"]
+URL = os.environ["GITLAB_BASE_URL"].removesuffix("api/v4")
+
+if __name__ == "__main__":
+    parser = argparse.ArgumentParser(description=__doc__)
+    parser.add_argument("namespace", type=namespace_path)
+    args = parser.parse_args()
+
+    with gitlab.Gitlab(url=URL, private_token=TOKEN) as Lab:
+        group = get_group(Lab, args.namespace.name)
+        for repo in list_repositories(args.namespace):
+            project = get_project(group, repo.name)
+            with sh.pushd(repo):
+                if "shore.co.il" in git.remote().splitlines():
+                    print(
+                        "Setting the remote URL in {}.".format(repo.name),
+                        file=sys.stderr,
+                    )
+                    git.remote(
+                        "set-url", "shore.co.il", project.ssh_url_to_repo
+                    )
+                else:
+                    print(
+                        "Adding remote in {}.".format(repo.name),
+                        file=sys.stderr,
+                    )
+                    git.remote("add", "shore.co.il", project.ssh_url_to_repo)
+                print(
+                    "Pushing to {}.".format(project.ssh_url_to_repo),
+                    file=sys.stderr,
+                )
+                git.push("--all", "shore.co.il")