-- Leo's gemini proxy

-- Connecting to gmi.karl.berlin:1965...

-- Connected

-- Sending request

-- Meta line: 20 text/gemini

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 2023-09-18.

-- Response ended

-- Page fetched on Thu May 2 06:54:22 2024