5

I'm working on a Bash script that does some Git repository maintenance. Some of repositories use 'master' as the main branch while others use 'main'. What Git command can I use to return the first branch of these which exists?

P.S. I want to check local branches of a repo, since there will always be a local 'master' or 'main' branch.

planetp
  • 12,388
  • 16
  • 74
  • 140
  • You'd have to define "the first which exists". If you meant the first which has been created, git doesn't keep that kind of branch metadata. But you might want to check `git config --get init.defaultbranch` on recent enough git repos. – Romain Valeri Jun 22 '21 at 15:07
  • 1
    @RomainValeri that would only tell you which would be the default branch when initializing a new repo, not of the current one – Marcus Müller Jun 22 '21 at 15:09
  • Not the first which has been created, just the first from the list which exists. I assume there will be one of these. BTW, `git config --get init.defaultbranch` doesn't return anything for me. – planetp Jun 22 '21 at 15:10
  • 1
    what do you do if both exist? – Marcus Müller Jun 22 '21 at 15:12
  • @MarcusMüller As I said, there will always be just one of them. Why would you need to have both? – planetp Jun 22 '21 at 15:29
  • @planetp for example, a medium-sized FOSS project I work closely with migrated to `main`. But they couldn't just waltz in and immediately delete `master`, because there's people (and projects) whose automation depends on the name of branches, so `master` and `main` both exist, but `master` simply sees no further updates. – Marcus Müller Jun 22 '21 at 15:30

4 Answers4

7

To find out which of the two local branches exists, you can use git branch with the -l/--list argument:

git branch -l master main  # outputs 'master' or 'main', provided only one exists

Git also marks the current branch with an asterisk, so you could use sed to strip it:

git branch -l master main | sed 's/^* //'
Eugene Yarmash
  • 131,677
  • 37
  • 301
  • 358
2

To find out what some other Git repository's HEAD is, use git ls-remote:

$ git ls-remote --symref origin HEAD
ref: refs/heads/master  HEAD
670b81a890388c60b7032a4f5b879f2ece8c4558    HEAD

This assumes both your Git, and the remote's Git, are not so old that they do not support --symref (it must be supported on both sides). Note that this command can be run outside any repository by using a URL directly, instead of a remote name like origin.

To find out what branch names exist in some other Git repository, either clone it and inspect the resulting remote-tracking names, or use git ls-remote. Note that you can specify just refs/heads to limit the output to branch names only, or omit it entirely to get everything (all branch and tag names and any other names they choose to expose).

torek
  • 389,216
  • 48
  • 524
  • 664
1

Well, "default branch" has no meaning locally; it only makes sense if your repo is a remote to someone else, or in terms of a remote that someone else hosts. (Also, in terms of "what branch do I pull by default when I pull from this local branch, but if you knew that, you wouldn't be asking this.)

git fetch
git branch -r --list 'origin/HEAD' | grep '>'
Marcus Müller
  • 31,250
  • 4
  • 47
  • 86
1

What Git command can I use to return the first branch of these which exists?

git branch -r returns a list of remotes.
grep origin/ma will match main and master.
If you need to be pickier, use grep -E 'origin/(main|master)'

Assigning the list returned to an array should work, but be wary of filenames with spaces &c because the array elements are delimited by whitespace and the whole thing can blow up.

b=( $(git branch -r | grep origin/ma ) ) # all matches
git checkout "${b[0]##*/}"               # first hit

If you want to be a little more careful,

for n in main master; do 
  b="$(git branch -r -l "origin/$n")"
  if [[ -n "$b" ]]; then
    git checkout "${b[0]##*/}"
    break # keep the first success
  fi 
done 
   
Paul Hodges
  • 10,927
  • 1
  • 16
  • 30