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

后端 未结 10 511
南方客
南方客 2021-01-30 10:29

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/         


        
相关标签:
10条回答
  • 2021-01-30 11:02

    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.

    0 讨论(0)
  • 2021-01-30 11:03

    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.

    0 讨论(0)
  • 2021-01-30 11:08

    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 HEAD..@{u} | wc -l
    

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

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

    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).

    0 讨论(0)
  • 2021-01-30 11:08

    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 ).

    0 讨论(0)
  • 2021-01-30 11:09

    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.

    0 讨论(0)
  • 2021-01-30 11:11

    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"

    0 讨论(0)
提交回复
热议问题