185

My team alternates between usage of dev and master as default branch for several repos and I would like to write a script that checks for the default branch when entering a directory.

When pull requests are opened in some of these repos, they either default to 'dev' or 'master' as the merge target.

I understand how to set this information but not retrieve it: https://help.github.com/articles/setting-the-default-branch/

Is there a git command available to determine default branch for remote repository?

Rubens Mariuzzo
  • 28,358
  • 27
  • 121
  • 148
random-forest-cat
  • 33,652
  • 11
  • 120
  • 99
  • 20
    The default branch is a github thing, not a git thing. – Ismail Badawi Feb 23 '15 at 03:10
  • You can use the GitHub API, as in this question: http://stackoverflow.com/questions/16500461/how-do-i-find-the-default-branch-for-a-repository-using-the-github-v3-api – Ismail Badawi Feb 23 '15 at 03:15
  • 31
    @IsmailBadawi Really? When creating a local bare repo and performing a clone on that there must still be some logic that determines which branch is checked out by default, right? – bluenote10 Jul 16 '19 at 07:33
  • None of the below solution does work reliably for me: if I'm in branch `feature`, forked from `develop`, it will return me `develop` and not `master` (or `main`, from which `develop` is a fork)... Any help? – user3341592 Jan 12 '21 at 16:02
  • Question asked in https://stackoverflow.com/questions/65703168/how-to-get-the-default-for-the-master-branch-in-git – user3341592 Jan 13 '21 at 13:42
  • The change from `master` to `main` was made by people who had absolutely no clue how many things they would break. – nyet Oct 25 '22 at 17:28
  • The question title is misleading now after Git 2.28 and `init.defaultBranch`. It should be changed to emphasize remotes and GitHub. – Guildenstern Apr 01 '23 at 07:46
  • @IsmailBadawi How so? `git init` has a `--initial-branch` parameter which sets `HEAD`, and `git remote show` display the branch used for `HEAD`. Now that's a convention that mainly apply to bare repos, if your remote is an actual checkout the behavior will be quite different, but GH's behavior is consistent with any other bare repo remotes. – Thomas Guyot-Sionnest Jul 26 '23 at 21:11

17 Answers17

160

I found a way to detect the default-branch if it is not master.

git remote show [your_remote] | sed -n '/HEAD branch/s/.*: //p'

I tested it with multiple repo from gitlab, and it worked fine. (for the most situations [your_remote] will be origin, run git remote to check the name of your remote)

Radon8472
  • 4,285
  • 1
  • 33
  • 41
  • 21
    This worked well for me, except that the cut command leaves a space before the actual branch name, which can cause problems when using this from scripts. I ended up using `git remote show upstream | grep "HEAD branch" | sed 's/.*: //'` – JHH Oct 09 '18 at 12:01
  • 6
    Best method so far. I don't even have refs/remotes/origin/HEAD for some reasons. – Loïc Faure-Lacroix Oct 11 '18 at 16:08
  • It depends how you names your remote, or if you have added a remote. Try to run `git remote` and see what it shows – Radon8472 Oct 15 '18 at 14:18
  • @JHH You can also execute 'xargs' to get rid of spaces. That is: `git remote show [your_remote] | grep "HEAD branch" | cut -d ":" -f 2 | xargs` – balaganAtomi Aug 27 '19 at 12:54
  • 7
    I updated it to be like this to remove the space `git remote show origin | grep 'HEAD branch' | cut -d' ' -f5` – Andrew Sep 20 '19 at 16:56
  • 2
    Be aware that this might not work for some (older) versions of git, provided you have ambiguous HEAD. See e.g. [this post](https://stackoverflow.com/questions/2832269/git-remote-head-is-ambiguous) – David Střelák Sep 27 '19 at 09:53
  • It also doesn't work with localized (translated) Git. For example, in mine the output of `git remote show upstream` has `branch HEAD:`. – flod Oct 10 '20 at 05:26
  • Does not work reliably for me: if I'm in branch `feature`, forked from `develop`, it will return me `develop` and not `master` (whose `develop` is a fork)... Any help? – user3341592 Jan 11 '21 at 17:59
  • Other options to strip out the space; * sed-based: `git remote show origin | sed -e '/HEAD branch: /!d' -e '/HEAD branch: /s/.*: //'` * perl-based: `git remote show origin | perl -ne 'if (/HEAD branch:\s*(.*)/) { print "$1"} '` – bernard paulus Jun 11 '21 at 15:49
  • Using regex (js in my case), this pattern may be used: `result.match(/(?<=HEAD branch:).+/)?.[0].trim()` – Henrique Bruno Jul 25 '21 at 17:59
  • Doesn't work for me, it says "Connection timed out". I guess that's because the command accesses the network instead of using the locally available info, I think it's worth mentioning in the post. – Hi-Angel Aug 08 '21 at 14:30
  • This works with Azure DevOps also. I found awk simpler for the filtering, ie. `git remote show origin | awk -F': ' '/HEAD branch/ { print $2 }'` – Ed Randall Dec 03 '21 at 10:46
  • 7
    This won't work if git is running under an non-English locale. For example with a German locale `HEAD branch` is spelled `Hauptbranch`. To fix this use: `LC_ALL=C git remote show origin | sed -n '/HEAD branch/s/.*: //p'` – Slaven Rezic Mar 23 '22 at 16:15
  • @Slaven I AM running git under multiple german, and I never hat such issues, but thx for adding more informations to the command. Which git version are you using that show this different translated name? – Radon8472 Mar 24 '22 at 22:49
  • 1
    @Radon8472 CentOS 7 has git version 1.8.3.1 and the wording is "Hauptzweig". Debian 9 has 2.11.0 and the wording here is "Hauptbranch". Later Debians and Ubuntu also have "Hauptbranch". However Ubuntu 18.04 with git 2.17.1 has "HEAD branch". So maybe it does not seem to depend on the git version. (All of these tried with `LC_ALL=de_DE.utf8 git remote show origin`) – Slaven Rezic Mar 27 '22 at 11:00
  • 1
    This is similar but seems to be much faster (a few ms vs a few seconds): `git branch -a | sed -n '/HEAD ->/s/.*\///p'`. You also don't need to know the name of the remote this way. Though it might not work if you have multiple remotes set up – redbmk May 18 '22 at 17:36
  • For anyone looking for a **super fast** command, that looks in local references instead of going to the remote server, use this one: https://stackoverflow.com/a/49384283/4561887. Put `time` in front and you'll see it runs in **0.003 sec** instead of the **0.621 sec** which the cmd above takes. – Gabriel Staples Sep 19 '22 at 07:13
  • Similar but a bit cleaner way to get the default branch: ```git remote set-head origin -a && default_branch=$(git rev-parse --abbrev-ref origin/HEAD | sed 's|^origin/||') && echo "$default_branch"```. Do not use `symbolic-ref` as it will produce a wrong result if the head is not set. In contrast `rev-parse` would just fail in this case. – Stanislav German-Evtushenko Dec 23 '22 at 04:48
  • 1
    Also do not use `basename` as it'll give a wrong result if your default branch name has slash, e.g. `env/dev` – Stanislav German-Evtushenko Dec 23 '22 at 05:03
  • `cut` supports whitespace separation, so `git remote show origin | grep 'HEAD branch' | cut -wf4` has less cognitive overhead. – wteuber Jun 13 '23 at 08:50
147

Tested with git 2.9.4 (but possibly works in other versions) in a repo cloned from Github:

git symbolic-ref refs/remotes/origin/HEAD | sed 's@^refs/remotes/origin/@@'

Sample output:

master

Or:

git symbolic-ref refs/remotes/origin/HEAD --short

Sample output:

origin/master
weston
  • 54,145
  • 21
  • 145
  • 203
danielkza
  • 2,517
  • 1
  • 22
  • 20
  • 7
    if i change the default branch on the server side (github) this still gets the old default in an old but otherwise current clone (but fresh clones are fine). How does one force an update here? – nhed Apr 05 '18 at 15:20
  • 3
    This works fine for origin, but when I tried getting the default branch for another remote, such as upstream in a forked github setup, I get "not a symbolic ref". I'm not git-savvy enough to understand why, but apparently ref/remotes/upstream won't exist at all. Radon8472's solution based on git remote worked for me though. – JHH Oct 09 '18 at 11:49
  • 23
    Maybe I'm doing something wrong, but when I run this I get: `fatal: ref refs/remotes/origin/HEAD is not a symbolic ref` with Git 2.19.1. – christianbundy Nov 02 '18 at 17:03
  • 19
    This method can fail or return incorrect results. The ref may be a hash that cannot be resolved to a branch rather than a symbolic reference. This can be solved by looking at HEAD as well. Still, in 6528 repositories I checked the two `git symbolic-ref` methods return wrong results (e.g. `master` rather than `develop` for `Alfresco/chef-alfresco`) in 172 cases. The `git remote show` method proposed by @Radon8472 is more reliable and seems to return the correct result in a few of the 172 diverging cases I verified by hand. – Diomidis Spinellis Jan 25 '19 at 15:20
  • 16
    You can also use **basename** instead of sed `basename $(git symbolic-ref refs/remotes/origin/HEAD)` – OzzyCzech Mar 26 '19 at 11:20
  • 1
    @lfender6445 the command from this answer returns incorrect results for my repos. The other one with git remote show ... returns the correct branch. – Side S. Fresh Sep 20 '19 at 07:08
  • 20
    To sync this symbolic ref from upstream, `git remote set-head origin --auto`. This updates both what is seen in `git remote show` and the symbolic ref referenced here. – Edward Anderson Jan 14 '20 at 14:46
  • I've just cloned [AlfrescoLabs/chef-alfresco](https://github.com/AlfrescoLabs/chef-alfresco), run this command, and correctly received `develop` as the master branch name. – vault Nov 25 '21 at 12:24
  • This can fail if you don't have any remotes. If you're running it on the primary git repo, you have no remotes (you are the remote). In this case, just use "HEAD" – macetw Mar 25 '22 at 17:59
  • This was working nicely for me locally, but in a github action, produces: `fatal: ref refs/remotes/origin/HEAD is not a symbolic ref`. – rainabba Oct 20 '22 at 17:31
  • may want to shorten the sed command: `git branch -rl '*/HEAD' | sed 's@.*/@@'` – kbrock Jul 25 '23 at 16:24
67

git rev-parse --abbrev-ref origin/HEAD will print origin/<default-branch-name>. The git symbolic-ref answers are doing the same thing but need a longer argument.

If the origin repository changes its default branch name, then

git remote set-head origin -a

will retrieve the new default branch name.

Flow
  • 23,572
  • 15
  • 99
  • 156
Jeffrey Yasskin
  • 5,171
  • 2
  • 27
  • 39
  • 5
    This runs a lot faster than `git remote show`, because it uses local information without polling the remote. You can trim off the first 7 characters (i.e. "origin/") and get just the branch name with `git rev-parse --abbrev-ref origin/HEAD | cut -c8-`. – scottclowe Jun 15 '21 at 00:20
  • Isn't this actually the canonical answer, since it uses a plumbing command and doesn't require any utilities outside of git itself? – Andrew Spencer Jun 18 '21 at 11:47
  • 5
    Answering myself - this is NOT the canonical answer since it only works in a repo created by cloning from the remote - not from a repo that you created and then added the remote by `git remote add` and pushed to it. – Andrew Spencer Jun 18 '21 at 11:52
  • 1
    (still upvoting since it's the best answer in the likely use case of a script where you know that you've cloned the repo from a remote) – Andrew Spencer Jun 18 '21 at 11:54
  • 5
    Doesn't work for me: when executed as in the answer, the only stdout I get is `origin/HEAD`, and there are also errors `warning: ignoring dangling symref refs/remotes/origin/HEAD`, `fatal: ambiguous argument 'origin/HEAD': unknown revision or path not in the working tree.`. If I append to the command a `-- .`, it says `warning: ignoring dangling symref refs/remotes/origin/HEAD`, `fatal: bad revision 'origin/HEAD'`. However, the `git symbolic-ref` answer this answer refers to works for me. – Hi-Angel Aug 08 '21 at 14:42
  • Hello, I recently created an alias based on this: https://stackoverflow.com/a/69950967/10095231 – kelvin Nov 15 '21 at 21:30
  • `basename \`git rev-parse --abbrev-ref origin/HEAD\`` – Juliy V. Chirkov Sep 30 '22 at 13:45
  • This answer helped me learn the role of `origin/HEAD`; specifying `origin/HEAD` explicitly worked perfectly for my needs. Thanks! – Chris Long Jan 08 '23 at 02:04
34

There doesn't seem to be an answer that doesn't require cloning so far

This requires git 2.8.0 or newer

$ git ls-remote --symref git@github.com:pre-commit/pre-commit.github.io HEAD
ref: refs/heads/real_master HEAD
e100a6a3c72b4e54f0d176f791dfd2dbd7eb5fa7    HEAD
anthony sottile
  • 61,815
  • 15
  • 148
  • 207
  • 1
    Thanks for a nice answer. I added awk to take the branch name: `git ls-remote --symref https://github.com/hnakamur/ltsvlog HEAD | awk '/^ref:/ {sub(/refs\/heads\//, "", $2); print $2}'` – hnakamur Jul 27 '20 at 09:02
  • Thats a nice answer, but it does only give you the current HEAD of the remote, and it gives no information which one is the default-branch. – Radon8472 Sep 21 '22 at 08:00
  • 1
    `real_master` here is the default branch – anthony sottile Sep 21 '22 at 12:41
  • @Radon8472 On GitHub, isn't the HEAD on a remote repo the default branch? – Martin Braun Mar 16 '23 at 17:39
  • It would be handy if there were an option to show _only_ the 'symref'. Also, note that the URL can be replaced by a named remote such as `origin` or `.`. – Brent Bradburn Mar 26 '23 at 19:05
  • 1
    @MartinBraun no its not. Many bare remotes don`t have a head. And when you e.g. use a remote for deploy, the head can be whatever the user wanted. So Head has nothing to do with default branch, HEAD tells you what point of history you currently have checked out. You can even have a detached head, what is not even linked to any branch. – Radon8472 May 09 '23 at 14:22
29

This question is a bit old but in case anyone comes across this more recently...

git remote show <remote_name> | awk '/HEAD branch/ {print $NF}'

That will also only display the branch name, not including any of the whitespace or other nonsense.

I like to save this using a couple git aliases (I have a bunch of useful aliases like this):

upstream-name = !git remote | egrep -o '(upstream|origin)' | tail -1
head-branch = !git remote show $(git upstream-name) | awk '/HEAD branch/ {print $NF}'

I use "upstream" and "origin" as my remotes almost 100% of the time ("upstream" when I go with a Fork & Pull workflow... which is often). Your use case may not need the upstream-name alias, I just find it useful.

JoeLinux
  • 4,198
  • 1
  • 29
  • 31
  • 1
    A possible PowerShell solution: `(git remote show origin | Select-String "HEAD branch: " -Raw).Split(' ', [System.StringSplitOptions]::RemoveEmptyEntries)[2]` – kapsiR May 05 '21 at 07:04
  • git remote show is slow because it queries the server. Using the -n option it's faster but only gives back the list of branches already known. That might not be the best solution but one could write the following: `git remote show origin -n | grep -c main &> /dev/null && echo main || echo master` – fredericrous Jul 07 '21 at 21:57
  • Doesn't work for me, it says "Connection timed out". I guess that's because the command accesses the network instead of using the locally available info, I think it's worth mentioning in the post. – Hi-Angel Aug 08 '21 at 14:35
  • This will fail if git is localized. See also https://stackoverflow.com/questions/28666357/git-how-to-get-default-branch#comment126528129_50056710 – Slaven Rezic Jul 01 '22 at 10:32
  • This works great with git 2.37.1! – djthoms Aug 09 '22 at 20:50
  • Its similar to my solution, and I like the "upstream-name" command, but unforunelly it will not work if your upstream is named differently than "upstream" or "origin" – Radon8472 Sep 21 '22 at 07:56
  • This could have been added as a comment to Radon8472's answer, using awk is nicer but it's essentially doing the same thing. There are better answers too. – Thomas Guyot-Sionnest Jul 26 '23 at 21:04
19

There is a --short option to git symbolic-ref. So my preferred command:

$ basename $(git symbolic-ref --short refs/remotes/origin/HEAD) 
master
lsl
  • 4,371
  • 3
  • 39
  • 54
Christian Hesse
  • 377
  • 2
  • 3
  • 12
    For remote it would still be `git symbolic-ref --short refs/remotes/origin/HEAD | sed 's@^origin/@@'` – maxm Oct 04 '18 at 22:28
  • 5
    It's a path, so in most POSIX-y shells you can also just use basename to get the last component. :D `basename $(git symbolic-ref --short refs/remotes/origin/HEAD)` – dannysauer Jul 29 '20 at 21:09
  • 4
    basename does not work for all branch names as they can contain slashes – anthony sottile Jan 23 '22 at 17:18
  • it does not work ```$ git symbolic-ref --short refs/remotes/origin/HEAD fatal: ref refs/remotes/origin/HEAD is not a symbolic ref ;$ git --version git version 2.36.1 ``` – Andrei.Danciuc Sep 01 '22 at 07:46
  • I like this command because compared to many of the others it is **super fast**! I left a comment about that here: https://stackoverflow.com/questions/28666357/git-how-to-get-default-branch/49384283#comment130262457_50056710 – Gabriel Staples Sep 19 '22 at 07:11
  • Gives only `fatal: ref refs/remotes/origin/HEAD is not a symbolic ref` for me – Radon8472 Sep 21 '22 at 07:38
  • This fails in GitHub actions despite working locally for me. – rainabba Oct 20 '22 at 18:11
17

Requirements

You need refs/remotes/origin/HEAD and it is only set when cloning. Otherwise you need to set it yourself with

git remote set-head origin -a

More info

Command

The following command will list the HEAD branch, no matter how you have named your remotes:

git branch --remotes --list '*/HEAD'

From that you can extract the default branch like this:

git branch -rl '*/HEAD' | rev | cut -d/ -f1 | rev

(using short variants of the git branch arguments).

If your shell does not have the rev command, you can use awk instead:

git branch -rl '*/HEAD' | awk -F/ '{print $NF}'
rofrol
  • 14,438
  • 7
  • 79
  • 77
Henry
  • 529
  • 5
  • 16
  • I am working somewhere that `stage` is used as trunk for development, and `master` is used for deployment. This gives me `stage`, which is what I wanted – thanks! – rattray May 27 '21 at 18:39
  • Gives for me `bash: rev: command not found` and `fatal: -a and -r options to 'git branch' do not make sense with a branch name ` – Radon8472 Sep 21 '22 at 07:51
  • 1
    @Radon8472 If your shell does not have the `rev` command, you can use `awk` instead: `git branch -rl '*/HEAD' | awk -F/ '{print $NF}'` – Henry Sep 22 '22 at 12:15
  • @Henry this gives `fatal: -a and -r options to 'git branch' do not make sense with a branch name ` – Radon8472 Sep 24 '22 at 06:31
  • @Radon8472 Where does the `-a` option come from? What do you get when you run just the first command: `git branch -rl '*/HEAD'` ? – Henry Sep 25 '22 at 23:02
15

As noted by other answerers, the concept of a default branch is a GitHub thing doesn't really make sense (in the lofty sense) of Git (there's a reasonably good (if under-appreciated) comment here gets into it a bit: https://stackoverflow.com/a/65710958/2521092) but in practice, we all know what that means.

Since the original asking of this question, Git 2.28 added init.defaultBranch, allowing a different initial branch than master, and a lot of projects are now using main. That's good. Most of the answers here rely on checking a remote, but that relies on there actually being a remote, and that there exists a reliable and consistent naming scheme to those remotes. Those are probably (increasingly?) reasonable assumptions, but it's not a guarantee, and I don't find that any of the major answers here fail nicely.

Moreover, my main use case is using the name of the default branch for various git aliases (e.g. lm = log main..HEAD). I'd like to use the same aliases without thinking about it too much, regardless of an external repo using master or a local using main with no remote. Git and its config can't really "store" information, so there's no way to set ahead of time what the current repository's main branch is. As such, any alias that wants to, say, show commits between the main branch and HEAD can't assume git log master..HEAD or git log main..HEAD will work.

Thus, I define a default-branch alias in Git that figures out the default branch and then supply that to other aliases. This is a pain since a simple lm = log main..HEAD has to instead become lm = "!git log $(git default-branch)..HEAD" but here we are:

default-branch = "!git branch --sort=-refname | grep -o -m1 '\\b\\(main\\|master\\|dev\\)\\b'"

This simply gets the branch names then finds the first one in a defined list. If there's a main, use that; if not and there's a master, use that. I also have dev in there as a tertiary option some folks use.

This is sort of similar to what @henrik-n does in https://stackoverflow.com/a/66622363/2521092, but I do it in Git itself rather than the shell, and I think it has some more optionality.

Amory
  • 758
  • 2
  • 19
  • 31
  • But your way does not realy check what is assignes as default-branch in remote. What if the defaultbrauch is called e.g. `my-default` or anytrhing other? – Radon8472 Sep 21 '22 at 07:44
  • 1
    In my second paragraph, I detail one of the main reasons I find this useful: repositories *without* a remote. – Amory Sep 21 '22 at 13:47
  • Yes, I was reading this, but the question above asked how to get it from remote repo. So you answer is informativ, but it is no answer to the question that was asked here – Radon8472 Sep 21 '22 at 16:05
  • The whole "main" change was made by people who had no idea how much it would break. – nyet Oct 25 '22 at 17:24
  • “That's good. Most of the answers here rely on checking a remote, but that relies on there actually being a remote,[…]”—That’s what OP asked for. “Is there a git command available to determine default branch for remote repository?” – Guildenstern Apr 01 '23 at 07:46
13

This is possible to get with the gh cli tool (tested v2.0.0)

gh repo view --json defaultBranchRef --jq .defaultBranchRef.name
KyleMit
  • 30,350
  • 66
  • 462
  • 664
pfesenmeier
  • 131
  • 1
  • 2
8

All other answers made too many assumptions, this is the only way that worked for me. This works regardless of what branch you're currently on, doesn't assume the origin/HEAD ref exists locally, and will always reflect the current default branch even if it's been changed.

The only drawback is that it alters the local origin/HEAD ref, but that shouldn't generally be a problem.

Allow git to set your origin/HEAD, determining what branch to use automatically:

$ git remote set-head origin --auto
origin/HEAD set to main

Then, get a string containing the name of the default branch:

$ git rev-parse --abbrev-ref origin/HEAD
origin/main

Alternatively, for a one-line solution:

$ git remote set-head origin --auto >/dev/null 2>&1 && git rev-parse --abbrev-ref origin/HEAD
origin/main
Makusu2
  • 81
  • 1
  • 2
  • What are the potential drawbacks of altering the local `origin/HEAD` ref? – Chris Long Jan 06 '23 at 23:46
  • 1
    @ChrisLong Basically none, but it could confuse scripts or someone could have a specific reason to want to keep their origin/HEAD at some outdated value. – Makusu2 Jan 08 '23 at 00:08
6

I just wanted a shell script to know whether the branch is "master" or "main".

For that purpose, this seems good enough:

[ -f "$(git rev-parse --show-toplevel)/.git/refs/heads/master" ] && echo master || echo main

If you know it will always be called from the root directory of the repo, it can be simplified to

[ -f .git/refs/heads/master ] && echo master || echo main

I'm using this in my Git aliases like so: https://github.com/henrik/dotfiles/commit/6815bd95770afab2936fb6202b1ee5e82cb9662b

Henrik N
  • 15,786
  • 5
  • 82
  • 131
5

If like this question you are trying to get a GitHub default branch--not some other git server:

You can get the default branch using the /repos GitHub API. It's the default_branch field of the response:

$ curl -s https://api.github.com/repos/darthwalsh/bootstrappingCIL | \
      jq --raw-output .default_branch
master
Carl Walsh
  • 6,100
  • 2
  • 46
  • 50
4

This works for me with Git 2.1.10, using a repository cloned from GitHub:

git branch -r --points-at refs/remotes/origin/HEAD

A major problem with this approach is that it lists every remote branch pointing to HEAD; however, the output includes a hint:

  origin/HEAD -> origin/master
  origin/master
  origin/test123

So you can post-process the output with grep or similar to find the one with the arrow:

git branch -r --points-at refs/remotes/origin/HEAD | grep '\->' | cut -d' ' -f5 | cut -d/ -f2
  • 2
    It's worth pointing out `.git/refs/remotes/origin/HEAD` will not exist only if you've cloned the repo not if you've created/authored it. `git symbolic-ref refs/remotes/origin/HEAD refs/remotes/origin/master` can be used to link refs ( but that defeats the point of this question :) ) – shalomb Apr 10 '19 at 10:28
4

From git 2.28.0 and above:

$ git config --get init.defaultBranch || echo master
mfandrade
  • 67
  • 1
  • 4
2

Is there a git command available to determine default branch for remote repository?

This list the default local repository branch:

git rev-parse --abbrev-ref origin/HEAD

The GitHub API can show the default branch with using its CLI gh:

gh api /repos/{owner}/{repo} --jq '.default_branch'
VonC
  • 1,262,500
  • 529
  • 4,410
  • 5,250
1

I'll add yet another answer, based on the other answers. I didn't like any of the other answers because querying a remote is slow, but I also didn't want a "local-only" solution.

I use this (long) alias:

head-branch = "!f() { gitHeadsDir=\"$(git rev-parse --show-toplevel)/.git/refs/heads\"; if [ -f \"$gitHeadsDir/main\" ]; then echo 'main'; elif [ -f \"$gitHeadsDir/master\" ]; then echo 'master'; else git remote show origin | grep 'HEAD branch' | cut -d' ' -f5; fi; }; f"

The above basically does this:

  • if a local branch named main exists, use that
  • if a local branch named master exists, use that
  • otherwise, fall back to checking the remote (which is much slower)

This works for 99 % of use cases (and all of my use cases), including:

  • a "regular" cloned repository
  • a brand new repository, which might not even have a remote (yet).

You can still easily "break" this by creating a local branch named main or master (or both), even if that's not actually the default branch. This will also fail if you don't have a remote, and your default branch name is neither main or master. But in those cases you're most likely trying to break it. ;-)

I'm checking for main first, since if you have both main and master, you're likely in the process of switching from master to main.

Kankaristo
  • 2,515
  • 2
  • 20
  • 16
0

Seems like a bit of a workaround solution but this seems to work:

$ cat .git/refs/remotes/origin/HEAD 
ref: refs/remotes/origin/master
anorm
  • 2,255
  • 1
  • 19
  • 38