DEV Community

Wen Ping
Wen Ping

Posted on Edited on Originally published at anguskit.com

A self-hosted Git server versus a bare repository: you need pull requests

This article explains how a Git server built with git init --bare differs from AngusGit, and how to move a bare repository you already have. After reading it, you can tell that a bare repository can only push and pull, with no website, no pull requests, and no review; when someone else has to look at a change before it lands on main, you open a pull request on AngusGit and push the bare repository into a new empty repository.

Sign in to AngusGit first. If the repository is still empty, or you do not have a key yet, do this before you push. If you have no ~/.ssh/id_ed25519.pub, run ssh-keygen -t ed25519 -C "you@example.com", press Enter for the path, and register the line from cat ~/.ssh/id_ed25519.pub that starts with ssh-ed25519 under Settings → Profile, on the SSH Keys tab. When you open Repositories → New repository in the sidebar, leave Add a README file, Add .gitignore, and Choose a license unchecked. The push address is ssh://git@host:2222/owner/repo.git, and the username is git. For HTTPS, an access token is a secret string you generate and use in place of a password. Open the Access Tokens tab and generate a git:write token with repository permission WRITE. The username is your login name, and the password is the token.

The conversation page is compared with the still-open xlliu/test-pr-example #9. When you move a bare repository, put your own empty repository in the target of the commands. Do not push to anguskit/AngusKit, which already has history.

1. How a bare repository works

Creating a bare repository on a server is short:

sudo adduser git
sudo -u git git init --bare /srv/git/AngusKit.git
Enter fullscreen mode Exit fullscreen mode

A bare repository stores only Git data. It has no working files you can edit. Each person who needs access gives an SSH public key to an administrator. The administrator appends it to ~/.ssh/authorized_keys for the git user on the server. After that, clone and push work:

git clone git@your-server:/srv/git/AngusKit.git
Enter fullscreen mode Exit fullscreen mode

In this setup, the server only checks "can this person sign in as git". A public key in authorized_keys can read and write every repository and every branch on the server, and can force-push or delete a branch. Limiting that means writing your own server-side hook scripts.

The left side is only push and pull. The right side also has pull requests and permissions on the web

2. What a bare repository and AngusGit can each do

What you want to do Bare repository AngusGit
Push and pull code Yes, over SSH Yes, over SSH or HTTPS
Read code and commit history without cloning No Browse files, commits, and branches on the code page
Open a pull request so someone looks before you merge No. You agree in person or by email Open it under Pull Requests. The diff and the check results are visible before merge
Comment on one line of code No Write a line comment under Review, then submit an approval or a request for changes
Block a direct push to main, and block force-push and deletion Write a hook script yourself Turn the switches on under repository Settings → Branch Protection
Let someone look and not push Hard. A server account is all or nothing Five repository permissions: Read, Triage, Write, Maintain, and Admin
Record bugs and requirements, and tie them to a code change No Record them under Issues. A pull request that contains Closes #<number> links and closes the issue
Bring a new teammate in An administrator signs in to the server and appends a public key The new person registers a public key under Settings → Profile, on the SSH Keys tab. An administrator only adds them to the team or the repository

A bare repository has a place it fits: one or two people, one extra copy of the code on the intranet, and no need for review or separate permissions. It is simpler than any platform. As soon as you need "someone looks at a change before it lands on main", switch to a platform that can open pull requests.

A pull request is a request to merge one branch into another after someone reviews the change.

3. Open the first pull request on AngusGit

AngusGit calls a merge request a Pull Request. It is the same thing as a GitLab merge request and a GitHub pull request. Starting from a repository that already has code, the shortest path is four steps. The still-open xlliu/test-pr-example #9 is the example. It already exists, so you can look at the page before merge. You do not need to create another one or merge this one.

  1. Change code on a new branch and push Do not edit main directly. Create a new branch locally (git switch -c <branch-name>), commit, and push with git push -u origin <branch-name>. The example branch is feature/link-empty-cart.
  2. Open a pull request Open the repository in a browser, go to the Branches tab, and on the new branch's row click Compare with default branch. Then click Create Pull Request. Title says what changed. Description says why. This one's title is "docs: 说明空购物车不计算折扣", and the description contains Closes #4.
  3. Ask a teammate to review The teammate opens the request under Review in the sidebar, reads the diff, and submits Approve, or writes down what should change. On this one, Angus and admin are both still Pending.
  4. Merge After the review is approved and there are no conflicts, go back to the pull request's Conversation tab, click Merge pull request, choose the merge method, and click Confirm merge. The change lands on main after you see Pull request merged successfully. This one cannot be merged yet.

Conversation on #9: feature/link-empty-cart into main, not ready to merge

The pull request title is "docs: 说明空购物车不计算折扣". The source branch is feature/link-empty-cart. The target is main. The merge card says "This pull request is not ready to merge": there are No status checks, and "Reviews are still pending and must be approved before merge". The Merge pull request button is there. The review is not finished, so leave it unclicked. #9 is the page to compare with. You do not need to look for fix-install-path.

Prepare the key and the token as at the start of this article. Create the empty repository as at the start, then push the bare repository as in section 4. To make "every change goes through a pull request" a hard rule, turn on branch protection for main. During review, open the request under Review in the sidebar, read the diff under Files changed, comment on a line, then click Submit review and choose Approve, Request changes, or Comment.

4. Move an existing bare repository to AngusGit in full

History, branches, and tags in a bare repository can move as they are. Clone it in full, then push to an empty repository on AngusGit.

  1. Create an empty repository on AngusGit In the sidebar, click Repositories, then New repository. Leave Add a README file, Add .gitignore, and Choose a license unchecked. Otherwise the push is rejected because the histories do not match. Use a repository name that does not exist yet. anguskit/AngusKit already has commits, so it cannot be this empty repository.
  2. Clone the old repository in full On any computer that can reach the old server, run git clone --bare and download every branch and tag.
  3. Push to AngusGit The first command uses --all to push every branch. The second uses --tags to push every tag.
  4. Have everyone switch to the new URL Each person runs git remote set-url origin in their local repository, points it at AngusGit, then runs git fetch origin. The history was copied as it is, so the local repository does not need a fresh clone.

The commands for the move, and for switching the remote, are:

git clone --bare git@your-server:/srv/git/notes.git
cd notes.git
git push ssh://git@git.anguskit.com:2222/<your-team>/notes.git --all
git push ssh://git@git.anguskit.com:2222/<your-team>/notes.git --tags

# Each teammate runs this in their own local working directory:
git remote set-url origin ssh://git@git.anguskit.com:2222/<your-team>/notes.git
git fetch origin
Enter fullscreen mode Exit fullscreen mode

The target of those commands is the empty repository you create. The example name <your-team>/notes has to exist first. When the old repository's main branch is master, run git branch -m master main inside notes.git before the push, so it matches the default branch main on the new AngusGit repository. Other people's local repositories then rename the main branch too, or they clone again.

After the move, open the Branches tab and the commit history. Compare the branch count and the latest commit with the old repository. Stop the old server after they match.

Common questions

Can AngusGit still push and pull over SSH, the way a bare repository does?

Yes. Register a public key under Settings → Profile, on the SSH Keys tab, then push and pull with the SSH URL shown on the page. The page title is My Profile. AngusGit's default SSH port is 2222. The URL already includes it. The username is always git.

Can Community do what this article describes?

Yes. Repository hosting, pull requests, human review, and issue tracking are in Community. Community is open source under GPL-3.0, and you can use it freely.

What about hook scripts on the old server?

Server-side hooks do not travel with git push. A hook that blocked pushes to main becomes branch protection on AngusGit. A hook that started a build becomes a repository webhook that notifies the build system. A webhook is a notice sent to another system when something in the repository changes.

Can the bare repository and AngusGit both be used for a while?

Yes, with one agreement: push to only one side. If people push to both, the histories diverge, and joining them later is messy. Pick the cutover time. Before it, push only to the old server. After it, push only to AngusGit.

Summary

What git init --bare creates is a directory of Git data. It handles push and pull. Permission is the server account, all or nothing. When the team needs "someone looks at a change before it lands on main", you need a platform that can open pull requests. On top of the same Git push and pull, AngusGit adds browsing on the web, pull requests, line-level review, branch protection, issues, and five permission levels on each repository. An existing bare repository moves in full with git clone --bare plus git push --all and --tags. Change origin on the local repository and keep working.

Conclusion: A bare repository only offers Git push and pull through a system account. When you need pull requests, line-level review, branch protection, and five repository permission levels, git clone --bare plus git push --all and --tags moves the bare repository into AngusGit with its history intact.

Further reading

Top comments (0)