如何找到当前处于分离HEAD状态的git分支

发布于 2024-11-07 22:56:22 字数 498 浏览 6 评论 0原文

我可以通过执行以下任一操作找到当前的 git 分支名称:

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

但是当处于分离的 HEAD 状态时,例如在 Jenkins maven build(或在 Travis git fetch 中),这些命令不起作用。

我当前的工作解决方案是这样的:

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

它显示其 HEAD 尖端上有最后一次提交的任何分支名称。这工作正常,但我觉得具有更强 git-fu 的人可能有更漂亮的解决方案?

I can find the current git branch name by doing either of these:

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

But when in a detached HEAD state, such as in the post build phase in a Jenkins maven build (or in a Travis git fetch), these commands doesn't work.

My current working solution is this:

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

It displays any branch name that has the last commit on its HEAD tip. This works fine, but I feel that someone with stronger git-fu might have a prettier solution?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(9

書生途 2024-11-14 22:56:23
git branch --contains HEAD

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

git branch --contains HEAD

Obviously discarding (no branch). Of course, you may get an arbitrary number of branches which could describe the current HEAD (including of course none depending on how you got onto no-branch) which might have be fast-forward merged into the local branch (one of many good reasons why you should always use git merge --no-ff).

浸婚纱 2024-11-14 22:56:23

sed 解决方案:

git log -1 --pretty=%D HEAD | sed 's/.*origin\///g;s/, .*//g'

它使用 log 检查最后一项是否存在于分支上。然后,sed 找到以 origin/ 开头的分支,并删除该短语及其之前的所有内容。然后 sed 再次删除任何可能的附加列出的分支(逗号及其后面的所有内容)。最后一个 log 被用作健全性检查,以确保此分离的 HEAD 不是已知分支 HEAD 之上的提交。

如果这是空的,则可以实现故障安全逻辑来将分支标记为“分离”(或“未定义”?)或确保它是最新的或回滚到已知 HEAD 的尖端。

A sed solution:

git log -1 --pretty=%D HEAD | sed 's/.*origin\///g;s/, .*//g'

This uses log to check the last item for its presence on a branch. Then sed finds the branch preceded by origin/ and removes the phrase and everything before it. Then sed does another removal of any possible additional listed branches (comma and everything after it). The reason last log was used as a sanity check to ensure this detached HEAD is not a commit above known branch HEADs.

If this is empty, failsafe logic can be implemented to label the branch "detached" (or "undefined"?) or to ensure it's up-to-date or rolled back to the tip of a known HEAD.

从﹋此江山别 2024-11-14 22:56:23

我更喜欢使用这个:

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

如果签出分支的头部以及当前签出是分离的头部并且不需要网络访问,则它可以正常工作。

I prefer to use this one:

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

It works fine if the head of a branch is checked out as well as when the current checkout is a detached head and it requires no network access.

未蓝澄海的烟 2024-11-14 22:56:23

这是 git nthlastcheckout ,它从引用日志中获取您用于第 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

Here's git nthlastcheckout, it gets the exact string you used for your nth last checkout from the reflog:

git config --global alias.nthlastcheckout '!nthlastcheckout'"() {
        git reflog |
        awk '\$3==\"checkout:\" {++n}
             n=='\${1-1}' {print \$NF; exit}
             END {exit n!='\${1-1}'}'
}; nthlastcheckout \"\$@\""

Examples:

$ git nthlastcheckout
master
$ git nthlastcheckout 2
v1.3.0^2
ζ澈沫 2024-11-14 22:56:23

我在 bitbucket 管道上工作的最短:

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

The shortest I got working on bitbucket pipelines:

git show -s --pretty=%D HEAD | awk '{gsub("origin/", ""); print $2}'
但可醉心 2024-11-14 22:56:23

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

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;
}

This is what I am using in one of my projects:

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;
}
迷离° 2024-11-14 22:56:23

对于任何尝试从 Gradle 中执行此操作的人(例如,通过您自己的自定义任务、插件等),您可以使用 Grgit 插件,提供 Gradle-Git 桥梁。事实上,如果你正在使用 Nebula Release 插件,那么 Grgit 已经是存在于您的构建中。

因此,使用 Grgit,解析指向当前分离的 HEAD 的远程分支如下所示:

project.getPlugins().apply(GrgitServicePlugin.class);

final var git = project.getExtensions()
    .getByType(GrgitServiceExtension.class)
    .getService()
    .get()
    .getGrgit();

final var rev = git.head().getId();

final var branch = git.lsremote(Map.of("heads", true))
    .entrySet()
    .stream()
    .filter(remote -> remote.getValue().equals(rev))
    .map(remote -> remote.getKey().getName())
    .findFirst()
    .orElseGet(() -> git.getBranch().current().getName());

// do something interesting with branch

For anyone attempting to do this from within Gradle (say, via your own custom task, plugin, etc..) you can use the Grgit Plugin, which provides a Gradle-Git bridge. In fact, if you are using the Nebula Release plugin, then Grgit is already present in your build.

And so with Grgit, resolving the remote branch that points to your current detached HEAD looks like this:

project.getPlugins().apply(GrgitServicePlugin.class);

final var git = project.getExtensions()
    .getByType(GrgitServiceExtension.class)
    .getService()
    .get()
    .getGrgit();

final var rev = git.head().getId();

final var branch = git.lsremote(Map.of("heads", true))
    .entrySet()
    .stream()
    .filter(remote -> remote.getValue().equals(rev))
    .map(remote -> remote.getKey().getName())
    .findFirst()
    .orElseGet(() -> git.getBranch().current().getName());

// do something interesting with branch
謌踐踏愛綪 2024-11-14 22:56:22

更简洁的方式:

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}"

好处是将候选引用放在单独的行上,没有额外的字符。

A more porcelain way:

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

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

The refs will be listed in the format (HEAD, master) - you'll have to parse it a little bit if you intend to use this in scripts rather than for human consumption.

You could also implement it yourself a little more cleanly:

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

with the benefit of getting the candidate refs on separate lines, with no extra characters.

鸵鸟症 2024-11-14 22:56:22

我需要为 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 这样的值。这也可以用来在 Jenksin 中获取 git 分支:

echo $GIT_BRANCH | cut -d / -f 2

I needed a bit different solution for Jenkins because it does not have local copies of the branches. So the current commit must be matched against the remote branches:

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

or without network:

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

It's also worth noting that this might return multiple branch names when you have multiple branch heads at the same commit.

UPDATE:

I just noticed that Jenkins sets GIT_BRANCH environment variable which contains a value like origin/master. This can be used to get git branch in Jenksin too:

echo $GIT_BRANCH | cut -d / -f 2
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文