关于git status:git:以编程方式知道分支在远程分支前后的位置

git: programmatically know by how much the branch is ahead/behind a remote branch

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

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

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

有两个问题:

  • 如何知道远程跟踪分支?它通常是origin/branch,但不必是。
  • 如何获取数字?如何知道它是在前面还是在后面?通过多少承诺?那分歧的分支案例呢?

  • git rev-list origin..HEAD将显示您当前分支中的承诺,但不显示来源,即您是否领先于来源,以及通过哪个承诺。

    git rev-list HEAD..origin将显示相反的结果。

    如果两个命令都显示提交,那么您就有了不同的分支。


    更新

    正如Amalloy所指出的,Git的最新版本支持通过给"branchname@upstream"(或"branchname@u",或"@u"(用于head的跟踪分支)查找给定分支的匹配跟踪分支。这实际上取代了下面的脚本。你可以做到:

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

    例如,我将git q别名为git log --pretty='...' @{u}..,以显示"排队"提交准备推送。

    原始答案

    一般来说,要找到跟踪分支似乎不是一个简单的方法,不需要解析比几个shell命令实际更多的git-config。但在许多情况下,这将有很长的路要走:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    # 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

    另一种更野蛮的方法:

    1
    git rev-list HEAD --not --remotes

    Jamessan的回答解释了如何使用git rev-list找到$tracking_分支和head之间的相对差异。你可以做一件有趣的事:

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

    (注意$tracking_branch和head之间有三个点)。这将显示两个"手臂"上的承诺,前面有一个区别标记:"<"表示在$tracking_分支上的承诺,">"表示在头部的承诺。


    你可以试试git branch -v -v。当-v标志给出两次时,它输出上游分支的名称。样品输出:

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

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


    编辑:我的原始答案实际上不是很好,因为它依赖于用户有一个称为"来源"的远程设备。如果当前分支除了原点之外还有一个跟踪分支,那么它也会失败。这些缺陷基本上使它无用。然而,@araqnid的回答并不是最有效的方法,他到达$tracking_branch的方式也比海峡前进的方式要少。我发现获得相同功能的最有效(最快)方法如下:

    1
    2
    3
    4
    5
    6
    7
    # 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)

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

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


    在Git的现代版本中,如果设置了一个分支,那么@{u}指向当前分支的上游。

    因此,要计算远程跟踪分支后面有多少提交:

    1
    git rev-list HEAD..@{u} | wc -l

    要查看遥控器的领先程度,只需切换顺序:

    1
    git rev-list @{u}..HEAD | wc -l

    要获得更易于阅读的摘要,您可以要求输入日志:

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

    为了我自己的目的,我正在编写一个脚本,如果没有设置上游,它将用适当的猜测来替换@{u}。不幸的是,此时没有@{d}代表下游(您将推动到哪里)。


    git status有一个--porcelain选项,用于脚本解析。它基于--short输出—它们在编写时几乎相同(有关详细信息,请参阅git状态手册页的"陶瓷格式"部分)。主要区别在于--short具有颜色输出。

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

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

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

    1
    ## master

    如果你在前面:

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

    如果你落后了:

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

    两者兼而有之:

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

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


    为什么这样不行:

    1
    2
    3
    4
    5
    6
    7
    8
    #!/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


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

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

    这意味着对于配置为推送到分支的所有分支,您还有另一个选项来查看前面/后面。

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

    在"查看未提交的git提交"中查看更多信息


    Araqnid的答案中最重要的部分代码对我来说不起作用,所以也许自18个月前Git编写以来,它的某些内容已经发生了变化。如果我改变了,它就会工作:

    1
    tracking_branch=refs/remotes/$remote/$remote_branch

    1
    tracking_branch=$remote/$remote_branch

    但是,在跟踪本地分支时仍然存在一个问题,在这种情况下,您必须修剪远程部分(它变为"."):

    1
    tracking_branch=${tracking_branch#./}

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

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

    我已经编写了一些脚本来完成所有这些工作(而且更多,例如,他们还可以尝试在Git SVN网桥的另一侧发现远程设备),并将它们发布到GitHub上的Git配置存储库中。例如,这里是我的Git比较上游。有关安装说明和其他方便的相关脚本,请参阅自述文件。