Check if local git repo is ahead/behind remote

I'm developing a git plug-in, and I need to know when a local repo is changed (can commit changes), ahead (can push to remote) or behind (can pull from remote) using the command line.

This is what I am doing so far:

  • Can commit?

    If git diff-index --name-only --ignore-submodules HEAD -- returns something, then yes, there are changes to commit.

  • Can push?

    If git status -sb contains the word ahead in it's output, then yes, there are commits to push.

  • Can pull?

    Nothing implemented yet.

  • The can commit? part seems to work properly. Can push? only works for the master branch, and this is a huge problem.

    How can I safely check if, on every branch, a git repo has changes to commit, commits to push, or needs a git pull ?


    You can do this with a combination of git merge-base and git rev-parse . If git merge-base <branch> <remote branch> returns the same as git rev-parse <remote branch> , then your local branch is ahead. If it returns the same as git rev-parse <branch> , then your local branch is behind. If merge-base returns a different answer than either rev-parse , then the branches have diverged and you'll need to do a merge.

    It would be best to do a git fetch before checking the branches, though, otherwise your determination of whether or not you need to pull will be out of date. You'll also want to verify that each branch you check has a remote tracking branch. You can use git for-each-ref --format='%(upstream:short)' refs/heads/<branch> to do that. That command will return the remote tracking branch of <branch> or the empty string if it doesn't have one. Somewhere on SO there's a different version which will return an error if the branch doesn't haven't a remote tracking branch, which may be more useful for your purpose.


    In the end, I implemented this in my C++11 git-ws plugin.

    string currentBranch = run("git rev-parse --abbrev-ref HEAD"); 
    bool canCommit = run("git diff-index --name-only --ignore-submodules HEAD --").empty();
    bool canPush = stoi(run("git rev-list HEAD...origin/" + currentBranch + " --ignore-submodules --count")[0]) > 0;
    

    Seems to work so far. canPull still needs to be tested and implemented.

    Explanation:

  • currentBranch gets the console output, which is a string of the current branch name
  • canCommit gets whether the console outputs something (difference between current changes and HEAD, ignoring submodules)
  • canPush gets the count of changes between origin/ currentBranch and the local repo - if > 0 , the local repo can be pushed

  • 感谢@Trebor我只是为了这个目的扔了一个简单的鱼类功能:

    #! /usr/bin/fish
    #
    # Echos (to stdout) whether your branch is up-to-date, behind, ahead or diverged from another branch.
    # Don't forget to fetch before calling.
    #
    # @param branch
    # @param otherbranch
    #
    # @echo string up-to-date/behind/ahead/diverged
    #
    # @example
    #
    #   # if master is ahead of origin/master you can find out like this:
    #   #
    #   if test ( branch-status master origin/master ) = ahead
    #
    #      echo "We should push"
    #
    #   end
    #
    function branch-status
    
        set -l a $argv[ 1 ]
        set -l b $argv[ 2 ]
    
        set -l base ( git merge-base $a $b )
        set -l aref ( git rev-parse  $a    )
        set -l bref ( git rev-parse  $b    )
    
             if [ $aref = $bref ]; echo up-to-date
    
        else if [ $aref = $base ]; echo behind
        else if [ $bref = $base ]; echo ahead
    
        else                     ; echo diverged
        end
    
    end
    
    链接地址: http://www.djcxy.com/p/31762.html

    上一篇: 为什么使用'eval'是一种不好的做法?

    下一篇: 检查本地git仓库是否在远程前/后