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))
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.
The command `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 `.gitconfig`:
[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 `origin` remote into my gitconfig?
If you want the same alias to work across all repos, you will have to set up consistent branch names.
Let's assume `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 `default` that 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.