git - 如何获得默认分支?

git - how to get default branch?

我的团队交替使用 dev 和 master 作为多个存储库的默认分支,我想编写一个脚本来在进入目录时检查默认分支。

当在其中一些存储库中打开拉取请求时,它们默认为 'dev' 或 'master' 作为合并目标。

我了解如何设置此信息但无法检索它: https://help.github.com/articles/setting-the-default-branch/

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

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

没有,好像没有:

git ls-remote -h https://github.com/<user>/<repo>

这会列出所有分支,但不会列出 HEAD(这是指定默认分支的 symref)

同样,GitHub Reference API 可以列出头部,但不会包括 HEAD。

这适用于 Git 2.1.10,使用从 GitHub:

克隆的存储库
git branch -r --points-at refs/remotes/origin/HEAD

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

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

因此您可以 post-使用 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

在从 Github:

克隆的回购中使用 git 2.9.4(但可能适用于其他版本)进行测试
$ git symbolic-ref refs/remotes/origin/HEAD | sed 's@^refs/remotes/origin/@@'
master

--short 选项 git symbolic-ref。所以我的首选命令:

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

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

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

我用 gitlab 的多个 repo 测试了它,它运行良好。 (在大多数情况下 [your_remote] 将是 origin、运行 git remote 来检查您的遥控器的名称)

目前似乎没有不需要克隆的答案

这需要 git 2.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" 和 "origin" 作为我的遥控器("upstream" 当我使用 Fork & Pull 工作流程时......这通常是).您的用例可能不需要 upstream-name 别名,我只是觉得它很有用。

<a href="https://git-scm.com/docs/git-rev-parse#Documentation/git-rev-parse.txt---abbrev-refstrictloose" rel="noreferrer">git rev-parse --abbrev-ref</a> origin/HEAD will print origin/<default-branch-name>. The git symbolic-ref 答案是做同样的事情,但需要更长的参数。

如果 origin 存储库更改了其默认分支名称,则 <a href="https://git-scm.com/docs/git-remote#Documentation/git-remote.txt-emset-headem" rel="noreferrer">git remote set-head</a> 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

如果知道总是从repo的根目录调用,可以简化为

[ -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 参数的简短变体)。

这可以通过 gh cli 工具获得(已测试 v2.0.0)

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

正如其他回答者所指出的,默认分支的概念是 GitHub 的东西并没有真正意义(在崇高的意义上)Git(有一个相当好的(如果被低估了)这里的评论有点深入:)但在实践中,我们都知道这意味着什么。

自从最初提出这个问题后,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 在 中所做的,但我是在 Git 本身而不是 shell 中做的,我认为它有一些更多可选性。

我将根据其他答案添加另一个答案。我不喜欢任何其他答案,因为查询遥控器很慢,但我也不想要“local-only”解决方案。

我使用这个(长)别名:

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,您很可能在从 master 切换到 main 的过程。