Consistent Handling of Git Repositories With Different Default Branches
Why Do I Care About Default Branches?
Typically, I develop on a feature branch, and when the feature is ready, there is an obvious branch into which I want to merge the branch. This branch is often called
master', main' or `develop'. During development, I will occasionally rebase my feature branch on top of this branch, to reduce future merge conflicts, and to avoid falling behind on changes merged by other developers. I will call this branch the default branch from here on.
To make common operations consistent across repositories, I want to use a `git default-branch' command that returns the name of the default branch, so that I can use commands like
# Rebase on latest version of the default branch git fetch origin $(git default-branch) && git rebase origin/$(git default-branch) # Switch to the default branch and bring it up to date git switch $(git default-branch) && pull # Absorb staged changes into the respective commits since branching off of the default branch git absorb --base (git merge-base HEAD $(git default-branch))
How to Determine the Default Branch
What I consider the default branch in the examples above is the HEAD of the remote repository (usually on GitHub). I use the remote name
origin for the remote containing the latest version of the default branch. If your naming is different, adapt the commands accordingly.
remote show origin provides all relevant information about the remote, including the HEAD branch which can be filtered out with
git remote show origin | sed -n '/HEAD branch/s/.*: //p'. The downside of this approach is that it queries the remote, so it will take quite a long time due to network latency, and will only work if you are online.
Fortunately there is a local representation of this information available via
git symbolic-ref refs/remotes/origin/HEAD, but it may be out of date or unavailable (in which case you will see the error
fatal: ref refs/remotes/origin/HEAD is not a symbolic ref). To update it, run
git remote set-head origin --auto.
Since I want to neither memorize nor type out these commands all the time, I package them up in two git aliases in my
[alias] default-branch = "!git symbolic-ref refs/remotes/origin/HEAD --short | sed 's|origin/||'" update-default-branch = remote set-head origin --auto
Now you can update the information with
git update-default-branch and then use the
git default-branch as shown in examples at the top or however else you like.
If you prefer the slow, always up-to-date version with online requirement, use the following alias instead:
[alias] default-branch = "!git remote show origin | sed -n '/HEAD branch/s/.*: //p'"
The remote names differ across my repositories, so I can't put the alias with an
originremote into my gitconfig?
If you want the same alias to work across all repos, you will have to set up consistent branch names.
origin always points to your personal github repo, but for some repos your default branch lives in you repo while in other cases, your repo is a fork and your default branch lives in the
upstream remote. In that case I suggest to add an
upstream remote to all repos (even if it will be identical to
origin when your repo contains the default branch). This allows you to use
upstream in the alias and have your alias work across all repos again.
Why don't you create a local branch called
defaultthat points to the default branch on the remote?
This would also be a valid solution, but I am easily confused when local branch names don't match remote branch names.Written on 2023-09-17. Last updated on 2023-09-18.