5

How to get main branch name from command-line/terminal?

I know that the main branch is called master by default, however one can rename it to anything they want.

PS—It would be nice to get the name of the local and remote main branch.

Edit: What I call main branch others might call default branch or stable branch. It’s the one into which you (should) merge everything (stable/working) into.

tukusejssirs
  • 564
  • 1
  • 7
  • 29
  • 2
    I don't think there's such a thing as a "main branch" because for git all branches are just the same... pointers to revisions, and they can be called anything. – eftshift0 Mar 20 '19 at 17:40
  • 1
    eftshift0 is correct. [There's no such thing as a "main branch"](https://stackoverflow.com/q/25446978/354577). – ChrisGPT was on strike Mar 20 '19 at 19:34
  • **See Also**: [How to get default branch name?](https://stackoverflow.com/q/28666357/1366033) – KyleMit Jan 02 '22 at 14:16

4 Answers4

6

I have no deep knowledge of git, however, in git, there is usually {remote}/HEAD, e.g. origin/HEAD. Here’s an excerpt from the man page of git remote:

 set-head

    Sets or deletes the default branch (i.e. the target of the
    symbolic-ref refs/remotes/<name>/HEAD) for the named remote.
    Having a default branch for a remote is not required, but allows
    the name of the remote to be specified in lieu of a specific
    branch. For example, if the default branch for origin is set to
    master, then origin may be specified wherever you would normally
    specify origin/master.

From this I understand that the {remote}/HEAD is the main/default branch of the {remote}. One could get the name of the branch using this (does anyone know a better/plumbing command?):

git branch -r | grep -Po 'HEAD -> \K.*$'
origin/master

When one wants to get the local main/default branch, there usually is no HEAD branch, however usually there’s one and only branch that tracks the {remote}/HEAD, which name we can get using (again, there surely is a better command):

git branch -vv | grep -Po "^[\s\*]*\K[^\s]*(?=.*$(git branch -rl '*/HEAD' | grep -o '[^ ]\+$'))"
master

Of course, one need to set-head if it is not already set, in order to have a ‘HEAD/master/main branch’ in the output of git remote -r. Therefore, we need to run the following command once prior to using the above commands (thanks for pointing this out @pixelbrackets).

git remote set-head origin -a

Update:

Recently, I wanted to get some more information (some commands I’ve got from here):

# Get currently checked out local branch name
git rev-parse --abbrev-ref HEAD
# Output: branch

# Get remote branch name that is tracked by currently checked out local branch
git for-each-ref --format='%(upstream:short)' "$(git symbolic-ref -q HEAD)"
# Output: origin/branch

# Get local main branch name
git branch -vv | grep -Po \
  "^[\s\*]*\K[^\s]*(?=.*$(git branch -rl '*/HEAD' | grep -o '[^ ]\+$'))"
# Output: master

# Get remote branch name that is tracked by local main branch (AKA the remote HEAD branch)
git branch -r | grep -Po 'HEAD -> \K.*$'
# Output: origin/master
tukusejssirs
  • 564
  • 1
  • 7
  • 29
  • 1
    This answer only works if the origin shows a `HEAD`. This might not be the case. To set it up run `git remote set-head origin -a` (source stackoverflow.com/a/52062124/3894752). Then the given command `git branch -r | grep -Po "HEAD -> \K.*$"` will work just fine. – pixelbrackets Jul 28 '20 at 07:56
5

If you assume that the main branch will either be called master or main, here is what I do to quickly detect the main branch name in a local repository:

git_main_branch () {
    git branch | cut -c 3- | grep -E '^master$|^main$'
}

Then other commands I have that need to know the main branch name can use it. For example I have gc-m which stands for "git checkout main branch":

alias gc='git checkout '
alias gc-m='gc $(git_main_branch)'
David Foster
  • 6,931
  • 4
  • 41
  • 42
3

you can also use something like this:

alias gc-m='git checkout `git branch -rl "*/HEAD" | rev | cut -d/ -f1 | rev`'
Luis Davim
  • 91
  • 5
  • Thanks, @LuisDavim! (1) I could shorten your command to `alias gc-m='git checkout "$(git branch -rl '*/HEAD' | grep -o '[^/]\+$')"'`. – tukusejssirs Jun 24 '21 at 14:27
  • (2) I currently use `git checkout "$(git branch -vv | grep -Po "^[\s\*]*\K[^\s]*(?=.*$(git branch -r | grep -Po 'HEAD -> \K.*$').*)")"` for the same purpose (certainly, it could be shortened and potentially optimalised), but there is one big difference between your command and my command: first I get the remote main branch (e.g. `origin/master`) and then check which local branch is tracking that remote. Although it usually is not the case, a user _might_ change the local branch name (or set a different branch to track the remote main branch) and then your command wouldn’t work. – tukusejssirs Jun 24 '21 at 14:27
  • (3) I tried to update my command with the yours (shortened by me) and it is longer by a single character: `git checkout "$(git branch -vv | grep -Po "^[\s\*]*\K[^\s]+(?=.*$(git branch -rl '*/HEAD' | grep -o '[^ ]\+$'))")"`. – tukusejssirs Jun 24 '21 at 14:28
2

you probably want to use this command git branch -r, -r is for list remote branches only, if you want to list both uses -a. Normally the master branch point to origin/HEAD something like this origin/HEAD -> origin/master

spiider
  • 21
  • 1
  • I think this answer shows me a _way_ to deal with this. It’s the `HEAD` ref, which I believe to be only one in a repo. Am I wrong? – tukusejssirs Mar 20 '19 at 19:56
  • I was wrong: there are as many `HEAD`s, as many branches. (cf https://stackoverflow.com/questions/26049827/how-are-the-terms-head-head-and-tip-different) – tukusejssirs Mar 20 '19 at 20:17
  • If `git branch -rv` does not list a HEAD on origin, then it may be set up using `git remote set-head origin -a` (source https://stackoverflow.com/a/52062124/3894752). – pixelbrackets Jul 28 '20 at 07:53