如何在分离头状态下找到当前的git分支

69

我可以通过以下任一方法找到当前的git分支名称:

git branch | awk '/^\*/ { print $2 }'
git describe --contains --all HEAD

但是,当处于游离HEAD状态时,例如在Jenkins maven构建的后构建阶段(或在Travis git fetch中),这些命令无法起作用。

我的当前解决方案是:

git show-ref | grep $(git log --pretty=%h -1) | sed 's|.*/\(.*\)|\1|' | sort -u | grep -v HEAD

它显示任何具有其HEAD尖端上最后提交的分支名称。 这很好用,但我觉得有更强大的git-fu的人可能会有更漂亮的解决方案?

10
“当前 Git 分支 […] 位于分离的 HEAD” - 分离的 HEAD 意味着没有当前分支,那你正在尝试查找哪个分支呢? - poke
8
@poke:OP的例子已经很清楚地说明了他在寻找什么。 - Cascabel
@Jefromi:我知道,但是要求某些东西并通过一个已经工作的解决方案来定义它并不是一个好主意。并不是每个人都能够阅读并理解结果是什么样子的。 - poke
3
@poke:我不仅仅是要求一个可行的解决方案,我还要求找到匹配分支名称的最简单方法(或者说是“git方式”?)。 - neu242
8个回答

61

更优雅的方式:

git log -n 1 --pretty=%d HEAD

# or equivalently:
git show -s --pretty=%d HEAD

引用将以 (HEAD, master) 的格式列出 - 如果您打算在脚本中使用而不是仅供人类消费,则需要进行一些解析。

您还可以更清晰地自己实现:

git for-each-ref --format='%(objectname) %(refname:short)' refs/heads | awk "/^$(git rev-parse HEAD)/ {print \$2}"

使用此方法可以获得候选参考资料,并使它们分别显示在不带额外字符的单独行上。


10
您可以使用--pretty=%D选项获取带有分支名称但不包含括号的HEAD。这在git v2.11.0上测试过。 - thom_nic
请确保您查看 Jenkins 上的原始参考,而不是 @epeli 指出的本地参考。 - Jilles van Gurp
3
git show -s --pretty=%D HEAD | tr -s ', ' '\n' | grep -v HEAD | head -n1 - jpbochi
更新:git show -s --pretty=%D HEAD | tr -s ',' '\n' | sed 's/^ //' | grep -v -e HEAD -e '^origin/' | head -n1 不幸的是,只有在分离状态下才能使用。 - jpbochi
1
另一个选项是无论HEAD是否分离,都可以使用git show -s --pretty=%D HEAD | cut -f2 -d ',' | xargs。末尾的| xargs可以修剪空格。 - Daniel
显示剩余2条评论

44

对于Jenkins,我需要一个稍微不同的解决方案,因为它没有分支的本地副本。因此,当前提交必须与远程分支匹配:

git ls-remote --heads origin | grep $(git rev-parse HEAD) | cut -d / -f 3

或者没有网络:

git branch --remote --verbose --no-abbrev --contains | sed -rne 's/^[^\/]*\/([^\ ]+).*$/\1/p'

值得注意的是,当您在同一提交中拥有多个分支头时,此操作可能会返回多个分支名称。

更新:

我刚刚注意到 Jenkins 设置了 GIT_BRANCH 环境变量,其中包含类似于 origin/master 的值。这也可以用于在 Jenkins 中获取 git 分支:

echo $GIT_BRANCH | cut -d / -f 2

1
我认为--format=%(refname:lstrip=-2)能够帮你省去sed的步骤。 - Adrian Baker
我和楼主一样在使用GitLab Runner时遇到了同样的问题,而“无网络”解决方案是目前为止最好的!谢谢! - YCN-
1
@YCN- 在GitLab上,你可以直接使用$CI_COMMIT_BRANCH - undefined

18
git branch --contains HEAD

显然是丢弃(no branch)。当然,你可能会得到任意数量的分支来描述当前的HEAD(包括当然取决于你如何进入无分支),这些分支可能已经快进合并到本地分支中(这是为什么您应该始终使用 git merge --no-ff 的诸多好理由之一)。


@neu242:另一个答案中的哪个命令返回一个有用的分支(例如不是HEAD),而这个命令不会返回(如果它是远程分支,则添加-a)?在测试期间,git checkout @{0}可以正常工作。 - Seth Robertson
1
@Jefromi的所有答案,再加上我的“当前工作解决方案”,可以返回一个处于分离HEAD状态的有用分支。 - neu242
与被接受的答案不同,如果HEAD被标记,这将显示分支名称而不是标记名称。但是我只是假设它可以报告多个分支名称。这是真的吗? - grenix
哦,我真蠢,你已经提到了多个分支名称的事情,只是用其他的措辞表达了。 - grenix

5
一个 sed 解决方案:
git log -1 --pretty=%D HEAD | sed 's/.*origin\///g;s/, .*//g'

使用 log 检查最后一个项目在分支中是否存在。然后,sed 找到以 origin/ 开头的分支,并删除该短语及其之前的所有内容。接着,sed 再次删除任何可能附加的列出的分支(逗号和其后的所有内容)。上一个 log 的原因是用来确保这个分离的 HEAD 不是已知分支 HEAD 上面的提交,从而作为一个合理性检查。

如果这是空的,则可以实现故障安全逻辑来标记该分支为“detached”(或“undefined”?),或确保它处于最新状态或回滚到已知 HEAD 的末端。


1
非常好,谢谢!:-)在sed表达式中使用替代分隔符不需要转义/,并且可能更容易阅读,例如... sed 's|.*origin/||g;s|, .*||g' - ssc

3

我更喜欢使用这个:

git branch --remote --contains | sed "s|[[:space:]]*origin/||"

如果分支的头部已经检查出来,或者当前的检查是一个分离的HEAD,并且不需要网络访问,那么它可以正常工作。


请记住,“origin”只是一个标准约定,而不是Git关键字。可能有一些仓库根本不使用“origin”。无论如何,在我的仓库中它起作用了。 - grenix

2
这里是git nthlastcheckout,它从reflog中获取您第n次最后一次检出时使用的确切字符串:
git config --global alias.nthlastcheckout '!nthlastcheckout'"() {
        git reflog |
        awk '\$3==\"checkout:\" {++n}
             n=='\${1-1}' {print \$NF; exit}
             END {exit n!='\${1-1}'}'
}; nthlastcheckout \"\$@\""

示例:

$ git nthlastcheckout
master
$ git nthlastcheckout 2
v1.3.0^2

这只为我显示了一个提交哈希,但感谢您使用reflog的想法。也许reflog不够基础以便被解析? - grenix

2

我在Bitbucket Pipelines上工作时,最短的代码如下:

git show -s --pretty=%D HEAD | awk '{gsub("origin/", ""); print $2}'

0

这是我在一个项目中使用的:

const { execSync } = require('child_process');

const getBranchName = () => {
  let branch = execSync('git rev-parse --abbrev-ref HEAD').toString().trim();
  if (branch === 'HEAD') branch = execSync(`git branch -a --contains HEAD | sed -n 2p | awk '{ printf $1 }'`).toString().trim();
  return branch;
}

对于像我这样的新手,您可以提及这是哪种编程语言。无论如何:为什么不总是使用“git branch -a --contains HEAD”方法? - grenix
@ grenix 抱歉,我是在“自动模式”下编写的。这是在 NodeJS 环境中使用 JavaScript 编写的。如果您有更多问题,请告诉我。 - Raphael Setin

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接