git:以编程方式了解分支领先/落后远程分支多少

发布于 2024-09-04 11:56:25 字数 350 浏览 8 评论 0 原文

我想提取 git status 之后打印的信息,如下所示:

# On branch master
# Your branch is ahead of 'origin/master' by 2 commits.

当然我可以解析 git status 的输出,但不建议这样做,因为这人类可读的输出很容易改变。

这里有两个问题:

  1. 如何知道远程跟踪的分支?它通常是起源/分支,但不一定是。
  2. 如何获取数字?如何知道是否领先/落后?通过多少次提交?那么分歧分支的情况又如何呢?

I would like to extract the information that is printed after a git status, which looks like:

# On branch master
# Your branch is ahead of 'origin/master' by 2 commits.

Of course I can parse the output of git status but this is not recommended since this human readable output is liable to change.

There are two problems:

  1. How to know the remote tracked branch? It is often origin/branch but need not be.
  2. How to get the numbers? How to know whether it is ahead/behind? By how many commits? And what about the diverged branch case?

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

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

发布评论

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

评论(10

何以畏孤独 2024-09-11 11:56:25

git rev-list origin..HEAD 将显示当前分支中的提交,但不显示 origin 的提交——即,您是否领先于 origin 以及哪些提交。

git rev-list HEAD..origin 将显示相反的情况。

如果两个命令都显示提交,则说明您有分歧的分支。

git rev-list origin..HEAD will show the commits that are in your current branch, but not origin -- i.e., whether you're ahead of origin and by which commits.

git rev-list HEAD..origin will show the opposite.

If both commands show commits, then you have diverged branches.

风蛊 2024-09-11 11:56:25

更新

正如 amalloy 所指出的,最新版本的 git 支持通过给出“branchname@{upstream}”(或“branchname@{u}”或“@”来查找给定分支的匹配跟踪分支) {u}”用于 HEAD 的跟踪分支)。这有效地取代了下面的脚本。你可以这样做:

git rev-list @{u}..
git rev-list --left-right --boundary @{u}...
gitk @{u}...

等等。例如,我将 git q 别名为 git log --pretty='...' @{u}.. 来向我展示“已排队”提交准备好推送。

原始答案

一般情况下,似乎没有一种简单的方法可以找到跟踪分支,而无需解析比一些 shell 命令中实用的更多的 git 配置。但对于许多情况,这将大有帮助:

# work out the current branch name
currentbranch=$(expr $(git symbolic-ref HEAD) : 'refs/heads/\(.*\)')
[ -n "$currentbranch" ] || die "You don't seem to be on a branch"
# look up this branch in the configuration
remote=$(git config branch.$currentbranch.remote)
remote_ref=$(git config branch.$currentbranch.merge)
# convert the remote ref into the tracking ref... this is a hack
remote_branch=$(expr $remote_ref : 'refs/heads/\(.*\)')
tracking_branch=refs/remotes/$remote/$remote_branch
# now $tracking_branch should be the local ref tracking HEAD
git rev-list $tracking_branch..HEAD

另一种更暴力的方法:

git rev-list HEAD --not --remotes

jamessan 的答案解释了如何使用 git rev-list 找到 $tracking_branch 和 HEAD 之间的相对差异。您可以做一件有趣的事情:(

git rev-list --left-right $tracking_branch...HEAD

注意 $tracking_branch 和 HEAD 之间的三个点)。这将显示两个“手臂”上的提交,并在前面有一个区分标记:“<”对于 $tracking_branch 上的提交,以及“>”用于 HEAD 上的提交。

update

As pointed out by amalloy, recent versions of git support finding the matching tracking branch for a given branch by giving "branchname@{upstream}" (or "branchname@{u}", or "@{u}" for the tracking branch of HEAD). This effectively supercedes the script below. You can do:

git rev-list @{u}..
git rev-list --left-right --boundary @{u}...
gitk @{u}...

etc. For example, I have git q aliased to git log --pretty='...' @{u}.. to show me "queued" commits ready for pushing.

original answer

There doesn't seem to be an easy way to find the tracking branch in general, without parsing lots more git config than is practical in a few shell commands. But for many cases this will go a long way:

# work out the current branch name
currentbranch=$(expr $(git symbolic-ref HEAD) : 'refs/heads/\(.*\)')
[ -n "$currentbranch" ] || die "You don't seem to be on a branch"
# look up this branch in the configuration
remote=$(git config branch.$currentbranch.remote)
remote_ref=$(git config branch.$currentbranch.merge)
# convert the remote ref into the tracking ref... this is a hack
remote_branch=$(expr $remote_ref : 'refs/heads/\(.*\)')
tracking_branch=refs/remotes/$remote/$remote_branch
# now $tracking_branch should be the local ref tracking HEAD
git rev-list $tracking_branch..HEAD

Another, more brute-force, approach:

git rev-list HEAD --not --remotes

jamessan's answer explains how to find the relative differences between $tracking_branch and HEAD using git rev-list. One fun thing you can do:

git rev-list --left-right $tracking_branch...HEAD

(note three dots between $tracking_branch and HEAD). This will show commits on both "arms" with a distinguishing mark at the front: "<" for commits on $tracking_branch, and ">" for commits on HEAD.

醉殇 2024-09-11 11:56:25

您可以尝试gitbranch -v -v。使用 -v 标志给出两次,它会输出上游分支的名称。示例输出:

* devel  7a5ff2c [origin/devel: ahead 1] smaller file status overlay icons
  master 37ca389 [origin/master] initial project check-in.

我认为这种格式比 git status 输出更稳定。

You can try git branch -v -v. With -v flag given twice, it outputs names of upstream branches. Sample output:

* devel  7a5ff2c [origin/devel: ahead 1] smaller file status overlay icons
  master 37ca389 [origin/master] initial project check-in.

I think this format is more stable than git status output.

围归者 2024-09-11 11:56:25

在现代版本的 git 中,@{u} 指向当前分支的上游(如果已设置)。

因此,要计算您在远程跟踪分支后面的提交次数:

git rev-list --count HEAD..@{u}

并查看您领先远程分支的距离,只需切换顺序:

git rev-list --count @{u}..HEAD

为了获得更易读的摘要,您可以要求提供日志:

git log --pretty=oneline @{u}..HEAD

对于我自己的出于目的,我正在编写一个脚本,如果尚未设置上游,该脚本将用适当的猜测替换 @{u} 。不幸的是,目前没有 @{d} 来代表下游(您将推送到的位置)。

In modern versions of git, @{u} points to the upstream of the current branch, if one is set.

So to count how many commits you are behind the remote tracking branch:

git rev-list --count HEAD..@{u}

And to see how far you are ahead of the remote, just switch the order:

git rev-list --count @{u}..HEAD

For a more human-readable summary, you could ask for a log instead:

git log --pretty=oneline @{u}..HEAD

For my own purposes, I am working on a script that will replace @{u} with an appropriate guess, if no upstream is yet set. Unfortunately there is at this time no @{d} to represent the downstream (where you would push to).

我不在是我 2024-09-11 11:56:25

编辑:
我原来的答案实际上不是很好,因为它依赖于用户拥有一个名为“origin”的遥控器。如果当前分支除了 origin-head 之外还有跟踪分支,它也会失败。这些缺陷基本上使其毫无用处。然而,@araqnid 的答案并不是最有效的方法,而且他到达 $tracking_branch 的方式也不是直线前进。我发现获得相同功能的最有效(最快)的方法如下:

# get the tracking-branch name
tracking_branch=$(git for-each-ref --format='%(upstream:short)' $(git symbolic-ref -q HEAD))
# creates global variables $1 and $2 based on left vs. right tracking
# inspired by @adam_spiers
set -- $(git rev-list --left-right --count $tracking_branch...HEAD)
behind=$1
ahead=$2

原始答案:(较差,但为了清楚起见而给出)

也许是我能找到的最简单的方法(受到@insidepower的启发)

# count the number of logs
behind=$(git log --oneline HEAD..origin | wc -l)
ahead=$( git log --oneline origin..HEAD | wc -l)

我以前一直在使用该方法@araqnid,但现在我想我会将一些脚本移至此方法,因为它要简单得多。这应该适用于任何 UNIX 系统。

Edit:
My original answer was actually not very good because it relied on the user to have a remote called "origin". It also failed if the current branch was had a tracking branch besides origin-head. These flaws essentially made it useless. However, the answer by @araqnid is not the most efficient method and the way he arrives at $tracking_branch is less than strait forward. The most efficient (fastest) method I have found to get the same functionality is the following:

# get the tracking-branch name
tracking_branch=$(git for-each-ref --format='%(upstream:short)' $(git symbolic-ref -q HEAD))
# creates global variables $1 and $2 based on left vs. right tracking
# inspired by @adam_spiers
set -- $(git rev-list --left-right --count $tracking_branch...HEAD)
behind=$1
ahead=$2

original answer: (inferior, but given for clarity)

Perhaps the simplest method I could find (inspired by @insidepower)

# count the number of logs
behind=$(git log --oneline HEAD..origin | wc -l)
ahead=$( git log --oneline origin..HEAD | wc -l)

I had previously been using the method of @araqnid, but now I think I'll move some of my scripts to this method since it is much simpler. This should work on any unix system.

赏烟花じ飞满天 2024-09-11 11:56:25

git status 有一个 --porcelain 选项,用于通过脚本进行解析。它基于 --short 输出 - 它们在撰写本文时几乎相同(请参阅 git status 手册页 了解详细信息)。主要区别在于 --short 具有颜色输出。

默认情况下,不显示分支信息,但如果添加 --branch 选项,您将得到如下输出:

git status --short --branch
## master...origin/master [ahead 1]
?? untrackedfile.txt
...

如果您是最新的(在获取之后),则分支行将是:

## master

如果你领先:

## master...origin/master [ahead 1]

如果你落后:

## master...origin/master [behind 58]

对于两者:

## master...origin/master [ahead 1, behind 58]

请注意, git status --porcelain --branch 仅在 1.7.10.3 或更高版本(尽管 git status --short --branch 已可用自 1.7.2 开始。

git status has a --porcelain option that is intended for parsing by scripts. It is based on the --short output - they are almost identical at the time of writing (see the "Porcelain Format" section of the git status man page for details). The main difference is that --short has colour output.

By default no branch information is shown, but if you add the --branch option you will get output like:

git status --short --branch
## master...origin/master [ahead 1]
?? untrackedfile.txt
...

If you are up to date (after a fetch), the branch line will just be:

## master

If you are ahead:

## master...origin/master [ahead 1]

If you are behind:

## master...origin/master [behind 58]

And for both:

## master...origin/master [ahead 1, behind 58]

Note that git status --porcelain --branch is only available in 1.7.10.3 or later (though git status --short --branch has been available since 1.7.2 ).

鲜肉鲜肉永远不皱 2024-09-11 11:56:25

为什么这不起作用:

#!/bin/sh
git diff origin/master..HEAD --quiet --exit-code
RETVAL=$?
if [ $RETVAL -gt 0 ]; then
    echo "You need to git push!"
else
    echo "No git push necessary!"
fi 

Why wouldn't this work:

#!/bin/sh
git diff origin/master..HEAD --quiet --exit-code
RETVAL=$?
if [ $RETVAL -gt 0 ]; then
    echo "You need to git push!"
else
    echo "No git push necessary!"
fi 
空城仅有旧梦在 2024-09-11 11:56:25

araqnid 的答案中最上面的代码块对我来说不起作用,所以也许 git 中的某些内容自 18 个月前编写以来已经发生了变化。如果我更改为:

tracking_branch=refs/remotes/$remote/$remote_branch

但是

tracking_branch=$remote/$remote_branch

跟踪本地分支时仍然存在问题,在这种情况下,您必须修剪远程部分(变成“。”):

tracking_branch=${tracking_branch#./}

然后您可以以编程方式获取前后的修订数量,如下所示如下:

set -- `git rev-list --left-right --count $tracking_branch...HEAD`
behind="$1"
ahead="$2"

我已经编写了脚本来完成所有这些操作(以及更多 - 例如,他们还可以尝试在 git-svn 桥的另一侧发现遥控器),并将它们发布在 git-svn">)。 com/aspiers/git-config#readme" rel="nofollow">我在 github 上的 git-config 存储库。例如,这是我的 git-compare-upstream。有关安装说明和其他方便的相关脚本,请参阅自述文件

The top chunk of code in araqnid's answer doesn't work for me, so maybe something in git has changed since it was written 18 months ago. It works if I change:

tracking_branch=refs/remotes/$remote/$remote_branch

to

tracking_branch=$remote/$remote_branch

However there is still an issue when tracking a local branch, in which case you have to trim the remote part (which becomes '.'):

tracking_branch=${tracking_branch#./}

Then you can programmatically obtain the number of revisions behind and ahead as follows:

set -- `git rev-list --left-right --count $tracking_branch...HEAD`
behind="$1"
ahead="$2"

I've written scripts to do all that (and more - e.g. they can also attempt to spot remotes on the other side of a git-svn bridge), and published them in my git-config repository on github. For example, here's my git-compare-upstream. See the README for installation instructions and other handy related scripts.

满天都是小星星 2024-09-11 11:56:25

如何知道远程跟踪的分支?它通常是起源/分支,但不一定是。

Git 2.5+ 引入了一个新的快捷方式,它引用您要推送到的分支。 @{push}:这将是这里感兴趣的远程跟踪分支。

这意味着您有另一个选项可以查看配置为推送到分支的所有分支的前方/后方。

git for-each-ref --format="%(push:track)" refs/heads

请参阅“查看未推送的 Git 提交”了解更多信息

How to know the remote tracked branch? It is often origin/branch but need not be.

Git 2.5+ introduces a new shortcut which references the branch you are pushing to. @{push}: that would be the remote tracking branch which is of interest here.

That means you have another option to see ahead/behind for all branches which are configured to push to a branch.

git for-each-ref --format="%(push:track)" refs/heads

See more at "Viewing Unpushed Git Commits"

裸钻 2024-09-11 11:56:25

对于最新版本的 git,您应该使用

git status --porcelain --branch

并检查前方/后方:

## master...origin/master [behind 1]

--瓷器[=版本]

以易于解析的脚本格式提供输出。这与短输出类似,但在不同的 Git 版本中都保持稳定,无论
用户配置。详情请参阅下文。

-b,--分支

即使以短格式显示分支和跟踪信息。

With recent versions of git you should use

git status --porcelain --branch

and check for ahead/behind:

## master...origin/master [behind 1]

--porcelain[=version]

Give the output in an easy-to-parse format for scripts. This is similar to the short output, but will remain stable across Git versions and regardless of
user configuration. See below for details.

-b, --branch

Show the branch and tracking info even in short-format.

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