💾 Archived View for gmi.karl.berlin › git-default-branch.gmi captured on 2024-08-31 at 11:40:13. Gemini links have been rewritten to link to archived content

View Raw

More Information

⬅️ Previous capture (2024-02-05)

🚧 View Differences

-=-=-=-=-=-=-

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.

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`.

Implementing the `default-branch` Command

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'"

Q&A

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 2024-01-18.