如何获得默认的 Git 分支?

我的团队在使用 dev 和 master 作为默认分支的几个回购协议中交替使用,我想编写一个脚本,在进入目录时检查默认分支。

当在这些回购协议中打开拉请求时,它们或者默认为“ dev”,或者默认为“ master”作为合并目标。

我知道如何设置这些信息,但不检索它们: Https://help.github.com/articles/setting-the-default-branch/

是否有 git 命令可用于确定远程存储库的默认分支?

67029 次浏览

是否有 git 命令可用于确定远程存储库的默认分支?

下面列出了默认的 本地存储库分支:

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

GitHub API可以使用它的 CLI gh:

gh api /repos/{owner}/{repo} --jq '.default_branch'

这对我来说适用于 Git 2.1.10,使用从 GitHub 克隆的存储库:

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

这种方法的一个主要问题是它列出了指向 HEAD 的 每个远程分支; 然而,输出包含一个提示:

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

所以你可以用 grep或者类似的方法对输出进行后期处理,找到带箭头的那个:

git branch -r --points-at refs/remotes/origin/HEAD | grep '\->' | cut -d' ' -f5 | cut -d/ -f2

这似乎是一个变通的解决方案,但这似乎是有效的:

$ cat .git/refs/remotes/origin/HEAD
ref: refs/remotes/origin/master

用 git2.9.4(但可能适用于其他版本)在从 Github 克隆的回购中进行了测试:

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

输出样本:

master

Git 符号参考有一个 选项,所以我的首选命令是:

$ basename $(git symbolic-ref --short refs/remotes/origin/HEAD)
master

我找到了一种方法来检测默认分支(如果它不是 master 的话)。

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

我用 Gitlab 的多重回购测试过,效果很好。 (在大多数情况下,[your_remote]将是 origin,运行 git remote检查您的远程名称)

到目前为止,似乎没有一个答案是不需要克隆的

这需要 git2.8.0或更高版本

$ git ls-remote --symref git@github.com:pre-commit/pre-commit.github.io HEAD
ref: refs/heads/real_master HEAD
e100a6a3c72b4e54f0d176f791dfd2dbd7eb5fa7    HEAD

这个问题有点老了,但是如果最近有人碰到这个问题..。

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

这也将只显示分支名称,而不包括任何空格或其他无意义的内容。

我喜欢使用一些 git 别名来保存它(我有很多这样的有用别名) :

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

我使用“上游”和“原点”作为我的远程几乎100% 的时间(“上游”当我去与 叉子和拉工作流... 这是经常)。您的用例可能不需要 upstream-name别名,我只是觉得它很有用。

git rev-parse --abbrev-ref origin/HEAD将打印 origin/<default-branch-name>git symbolic-ref的答案做同样的事情,但需要一个更长的参数。

如果 origin存储库更改其默认分支名称,那么 git remote set-head origin -a将检索新的默认分支名称。

如果你想得到一个 GitHub默认分支,而不是其他的 git 服务器:

你可以使用 /repos GitHub API得到默认的分支,它是响应的 default_branch字段:

$ curl -s https://api.github.com/repos/darthwalsh/bootstrappingCIL | \
jq --raw-output .default_branch
master

我只是想要一个 shell 脚本来知道这个分支是“ master”还是“ main”。

就此而言,这似乎已经足够好了:

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

如果你知道它总是从回购的根目录调用,它可以简化为

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

我在我的 Git 别名中使用它,比如: https://github.com/henrik/dotfiles/commit/6815bd95770afab2936fb6202b1ee5e82cb9662b

所有其他的答案都做了太多的假设,这是唯一对我有效的方法。无论您当前在哪个分支上,这都是可行的,不假定 origin/HEAD ref 在本地存在,并且即使当前的默认分支已经更改,它也将始终反映该分支。

唯一的缺点是它改变了本地的 origin/HEAD参考,但是这通常不会是一个问题。

允许 git 设置 origin/HEAD,决定自动使用哪个分支:

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

然后,获取一个包含默认分支名称的字符串:

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

或者,对于单行解决方案:

$ git remote set-head origin --auto >/dev/null 2>&1 && git rev-parse --abbrev-ref origin/HEAD
origin/main

下面的命令将列出 HEAD 分支,无论您如何命名您的远程:

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

可以从中提取默认分支,如下所示:

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

(使用 git branch参数的简短变体)。

如果您的 shell 没有 rev命令,您可以改用 awk:

git branch -rl '*/HEAD' | awk -F/ '{print $NF}'

使用 gh cli 工具(经过测试的 v2.0.0)可以做到这一点

gh repo view --json defaultBranchRef --jq .defaultBranchRef.name

正如其他回答者所指出的那样,默认分支的概念是 GitHub 的东西,这对 Git 来说(从崇高的意义上来说)没有什么意义(这里有一个相当不错的评论(如果没有得到足够的重视) : https://stackoverflow.com/a/65710958/2521092) ,但是在实践中,我们都知道这意味着什么。

自从最初提出这个问题以来,Git 2.28添加了 init.defaultBranch,允许与 master不同的初始分支,现在很多项目都在使用 main。很好。这里的大多数答案依赖于检查一个远程,但是这实际上依赖于那里的 生存一个远程,并且存在一个可靠和一致的命名方案到这些远程。这些可能(越来越多?)合理的假设,但这并不是一个保证,我不认为这里的任何一个主要答案都能很好地失败。

此外,我的主要用例是为各种 git 别名(例如 lm = log main..HEAD)使用默认分支的名称。我希望使用相同的别名,而不会想太多,不管是使用 master的外部回购,还是使用 main的本地回购,没有远程控制。Git 及其配置无法真正“存储”信息,因此无法提前设置当前存储库的主分支是什么。因此,任何想要在主分支和 HEAD 之间显示提交的别名都不能假定 git log master..HEADgit log main..HEAD可以工作。

因此,我在 Git 中定义了一个 default-branch别名,它指出缺省分支,然后将其提供给其他别名。这是一个痛苦,因为一个简单的 lm = log main..HEAD不得不变成 lm = "!git log $(git default-branch)..HEAD",但我们在这里:

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

这只是获取分支名称,然后在已定义的列表中找到第一个分支。如果有一个 main,使用它; 如果没有,并且有一个 master,使用它。我也有 dev在那里作为一个三选项,一些人使用。

这有点类似于@henrik-n 在 https://stackoverflow.com/a/66622363/2521092中的功能,但是我是在 Git 本身而不是 shell 中完成的,我认为它有一些更多的可选性。

我会在其他答案的基础上再加一个答案。我不喜欢任何其他的答案,因为查询一个远程缓慢,但我也不想要一个“本地唯一”的解决方案。

我使用这个(长)别名:

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"

以上基本上是这样做的:

  • 如果存在名为 main的本地分支,请使用该分支
  • 如果存在名为 master的本地分支,请使用该分支
  • 否则,就回到检查远程控制器上(远程控制器的速度要慢得多)

这适用于99% 的用例(以及我所有的用例) ,包括:

  • 一个“常规的”克隆仓库
  • 一个全新的存储库,它甚至可能还没有一个远程控制器。

您仍然可以通过创建一个名为 mainmaster(或两者兼有)的本地分支轻松地“破坏”它,即使它实际上不是默认分支。如果您没有远程控制器,并且您的默认分支名称既不是 main也不是 master,那么这也会失败。但在这些情况下,你最有可能 努力打破它。;-)

我首先检查 main,因为如果你同时拥有 main还有,你很可能正在从 master切换到 main的过程中。

来自 git 2.28.0及以上版本:

$ git config --get init.defaultBranch || echo master