Check if pull needed in Git

How do I check whether the remote repository has changed and I need to pull?

Now I use this simple script:

  • Is it possible to accept user input as part of a remote git post-receive hook?
  • Python 3 Wont run from the Git Bash command line
  • Is it OK to automate Git commands?
  • Dynamic elements in bash PS1
  • Why did my local git tag go from “hello” to “hello-1-48281”
  • I need some guidance with my Git hook for pre-commit using Bash
  • git pull --dry-run | grep -q -v 'Already up-to-date.' && changed=1
    

    But it is rather heavy.

    Is there a better way? The ideal solution would check all the remote branches, and return names of the changed branches and the number of new commits in each one.

  • Pull SVN trunk to a git branch
  • PyCharm: multiple projects in same window, independent version control
  • EGit Push: How to store the remote repository info
  • Git: want to iterate through all commits on branch, and list files in each commit
  • Merging develop branch into master
  • Preview changes on bare repo doesn't work correctly
  • 19 Solutions collect form web for “Check if pull needed in Git”

    First use git remote update, to bring your remote refs up to date. Then you can do one of several things, such as:

    1. git status -uno will tell you whether the branch you are tracking is ahead, behind or has diverged. If it says nothing, the local and remote are the same.

    2. git show-branch *master will show you the commits in all of the branches whose names end in ‘master’ (eg master and origin/master).

    If you use -v with git remote update (git remote -v update) you can see which branches got updated, so you don’t really need any further commands.

    However, it looks like you want to do this in a script or program and end up with a true/false value. If so, there are ways to check the relationship between your current HEAD commit and the head of the branch you’re tracking, although since there are four possible outcomes you can’t reduce it to a yes/no answer. However, if you’re prepared to do a pull --rebase then you can treat “local is behind” and “local has diverged” as “need to pull”, and the other two as “don’t need to pull”.

    You can get the commit id of any ref using git rev-parse <ref>, so you can do this for master and origin/master and compare them. If they’re equal, the branches are the same. If they’re unequal, you want to know which is ahead of the other. Using git merge-base master origin/master will tell you the common ancestor of both branches, and if they haven’t diverged this will be the same as one or the other. If you get three different ids, the branches have diverged.

    To do this properly, eg in a script, you need to be able to refer to the current branch, and the remote branch it’s tracking. The bash prompt-setting function in /etc/bash_completion.d has some useful code for getting branch names. However, you probably don’t actually need to get the names. Git has some neat shorthands for referring to branches and commits (as documented in git rev-parse --help). In particular, you can use @ for the current branch (assuming you’re not in a detached-head state) and @{u} for its upstream branch (eg origin/master). So git merge-base @ @{u} will return the (hash of) the commit at which the current branch and its upstream diverge and git rev-parse @ and git rev-parse @{u} will give you the hashes of the two tips. This can be summarized in the following script:

    #!/bin/sh
    
    UPSTREAM=${1:-'@{u}'}
    LOCAL=$(git rev-parse @)
    REMOTE=$(git rev-parse "$UPSTREAM")
    BASE=$(git merge-base @ "$UPSTREAM")
    
    if [ $LOCAL = $REMOTE ]; then
        echo "Up-to-date"
    elif [ $LOCAL = $BASE ]; then
        echo "Need to pull"
    elif [ $REMOTE = $BASE ]; then
        echo "Need to push"
    else
        echo "Diverged"
    fi
    

    Note: older versions of git didn’t allow @ on its own, so you may have to use @{0} instead.

    The line UPSTREAM=${1:-'@{u}'} allows you optionally to pass an upstream branch explicitly, in case you want to check against a different remote branch than the one configured for the current branch. This would typically be of the form remotename/branchname. If no parameter is given, the value defaults to @{u}.

    The script assumes that you’ve done a git fetch or git remote update first, to bring the tracking branches up to date. I didn’t build this into the script because it’s more flexible to be able to do the fetching and the comparing as separate operations, for example if you want to compare without fetching because you already fetched recently.

    If you have an upstream branch

    git fetch <remote>
    git status
    

    If you don’t have an upstream branch

    Compare the two branches:

    git fetch <remote>
    git log <local_branch_name>..<remote_branch_name> --oneline
    

    For example:

    git fetch origin
    
    # See if there are any incoming changes
    git log HEAD..origin/master --oneline
    

    (I’m assuming origin/master is your remote tracking branch)

    If any commits are listed in the output above, then you have incoming changes — you need to merge. If no commits are listed by git log then there is nothing to merge.

    Note that this will work even if you are on a feature branch — that does not have a tracking remote, since if explicitly refers to origin/master instead of implicitly using the upstream branch remembered by Git.

    If this is for a script, you can use:

    git fetch
    $(git rev-parse HEAD) == $(git rev-parse @{u})
    

    (Note: the benefit of this vs. previous answers is that you don’t need a separate command to get the current branch name. “HEAD” and “@{u}” (the current branch’s upstream) take care of it. See “git rev-parse –help” for more details.)

    The command

    git ls-remote origin -h refs/heads/master
    

    will list the current head on the remote — you can compare it to a previous value or see if you have the SHA in your local repo.

    Here’s a Bash one-liner that compares the current branch’s HEAD commit hash against its remote upstream branch, no heavy git fetch or git pull --dry-run operations required:

    [ $(git rev-parse HEAD) = $(git ls-remote $(git rev-parse --abbrev-ref @{u} | \
    sed 's/\// /g') | cut -f1) ] && echo up to date || echo not up to date
    

    Here’s how this somewhat dense line is broken down:

    • Commands are grouped and nested using $(x) Bash command-substitution syntax.
    • git rev-parse --abbrev-ref @{u} returns an abbreviated upstream ref (e.g. origin/master), which is then converted into space-separated fields by the piped sed command, e.g. origin master.
    • This string is fed into git ls-remote which returns the head commit of the remote branch. This command will communicate with the remote repository. The piped cut command extracts just the first field (the commit hash), removing the tab-separated reference string.
    • git rev-parse HEAD returns the local commit hash.
    • The Bash syntax [ a = b ] && x || y completes the one-liner: this is a Bash string-comparison = within a test construct [ test ], followed by and-list and or-list constructs && true || false.

    I suggest you go see the script https://github.com/badele/gitcheck, i have coded this script for check in one pass all your git repositories, and it show who has not commited and who has not pushed/pulled.

    Here a sample result enter image description here

    I think the best way to do this would be:

    git diff remotes/origin/HEAD
    

    Assuming that you have the this refspec registered. You should if you have cloned the repository, otherwise (i.e., if the repo was created de novo locally, and pushed to the remote), you need to add the refspec explicitly.

    I based this solution on the comments of @jberger.

    if git checkout master &&
        git fetch origin master &&
        [ `git rev-list HEAD...origin/master --count` != 0 ] &&
        git merge origin/master
    then
        echo 'Updated!'
    else
        echo 'Not updated.'
    fi
    

    I would do the way suggested by brool. The following one-line script takes the SHA1 of your last commited version and compares it to the one of the remote origin, and pull changes only if they differ.
    And it’s even more light-weight of the solutions based on git pull or git fetch.

    [ `git log --pretty=%H ...refs/heads/master^` != `git ls-remote origin
    -h refs/heads/master |cut -f1` ] && git pull
    

    There are many very feature rich and ingenious answers already. To provide some contrast, I could make do with a very simple line.

    # Check return value to see if there are incoming updates.
    if ! git diff --quiet remotes/origin/HEAD; then
     # pull or whatever you want to do
    fi
    

    If you run this script, it will test if the current branch need a git pull:

    #!/bin/bash
    
    git fetch -v --dry-run 2>&1 |
        grep -qE "\[up\s+to\s+date\]\s+$(
            git branch 2>/dev/null |
               sed -n '/^\*/s/^\* //p' |
                    sed -r 's:(\+|\*|\$):\\\1:g'
        )\s+" || {
            echo >&2 "Current branch need a 'git pull' before commit"
            exit 1
    }
    

    It’s very convenient to put it as a Git hook pre-commit to avoid

    Merge branch 'foobar' of url:/path/to/git/foobar into foobar
    

    when you commit before pulling.

    To use this code as a hook, simply copy/paste the script in

    .git/hooks/pre-commit
    

    and

    chmod +x .git/hooks/pre-commit
    

    Run git fetch (remote) to update your remote refs, it’s show you what’s new. Then, when you checkout your local branch, it will show you whether it’s behind upstream.

    git ls-remote | cut -f1 | git cat-file --batch-check >&-
    

    will list everything referenced in any remote that isn’t in your repo. To catch remote ref changes to things you already had (e.g. resets to previous commits) takes a little more:

    git pack-refs --all
    mine=`mktemp`
    sed '/^#/d;/^^/{G;s/.\(.*\)\n.* \(.*\)/\1 \2^{}/;};h' .git/packed-refs | sort -k2 >$mine
    for r in `git remote`; do 
        echo Checking $r ...
        git ls-remote $r | sort -k2 | diff -b - $mine | grep ^\<
    done
    

    Here’s my version of a bash script that checks all repos in a predefined folder:

    https://gist.github.com/henryiii/5841984

    It can differentiate between common situations, like pull needed and push needed, and it is multithreaded, so the fetch happens all at once. It has several commands, like pull and status.

    Put a symlink (or the script) in a folder in your path, then it works as git all status (etc). It only supports origin/master, but it can be edited or combined with another method.

    I use a version of script based on Stephen Haberman’s answer:

    if [ -n "$1" ]; then
        gitbin="git -C $1"
    else
        gitbin="git"
    fi
    
    # Fetches from all the remotes, although --all can be replaced with origin
    $gitbin fetch --all
    if [ $($gitbin rev-parse HEAD) != $($gitbin rev-parse @{u}) ]; then
        $gitbin rebase @{u} --preserve-merges
    fi
    

    Assuming this script is called git-fetch-and-rebase, it can be invoked with an optional argument directory name of the local git repository to perform operation on. If the script is called with no arguments, it assumes the current directory to be part of the git repository.

    Examples:

    # Operates on /abc/def/my-git-repo-dir
    git-fetch-and-rebase /abc/def/my-git-repo-dir
    
    # Operates on the git repository which the current working directory is part of
    git-fetch-and-rebase
    

    It is available here as well.

    After reading many answers and multiple posts, and spending half a day trying various permutations, this is what I have come up with.

    If you are on Windows, you may run this script in Windows using gitbash provided by Git for Windows (installation or portable).

    This script requires arguments

    - local path e.g. /d/source/project1
    - Git URL e.g. https://username@bitbucket.org/username/project1.git
    - password 
    
    if password should not be entered on command line in plain text, 
    then modify script to check if GITPASS is empty, do not 
    replace and let git prompt for password
    

    The script will

    - find current branch
    - get the SHA1 of the remote on that branch
    - get the SHA1 of the local on that branch
    - compare them. 
    

    If there is a change as printed by the script, then you may proceed to fetch or pull. The script may not be efficient, but it gets the job done for me.

    Update – 2015-10-30 : stderr to dev null to prevent printing url with password to console.

    #!/bin/bash
    
    # shell script to check if a git pull is required.
    
    LOCALPATH=$1
    GITURL=$2
    GITPASS=$3
    
    cd $LOCALPATH
    BRANCH="$(git rev-parse --abbrev-ref HEAD)"
    
    echo 
    echo git url = $GITURL
    echo branch = $BRANCH
    
    # bash replace - replace @ with :password@ in the GIT URL
    GITURL2="${GITURL/@/:$GITPASS@}"
    FOO="$(git ls-remote $GITURL2 -h $BRANCH 2> /dev/null)"
    if [ "$?" != "0" ]; then
      echo cannot get remote status
      exit 2
    fi
    FOO_ARRAY=($FOO)
    BAR=${FOO_ARRAY[0]}
    echo [$BAR]
    
    LOCALBAR="$(git rev-parse HEAD)"
    echo [$LOCALBAR]
    echo
    
    if [ "$BAR" == "$LOCALBAR" ]; then
      #read -t10 -n1 -r -p 'Press any key in the next ten seconds...' key
      echo No changes
      exit 0
    else
      #read -t10 -n1 -r -p 'Press any key in the next ten seconds...' key
      #echo pressed $key
      echo There are changes between local and remote repositories.
      exit 1
    fi
    

    Maybe this, if you want to add task as crontab:

    #!/bin/bash
    dir="/path/to/root"
    lock=/tmp/update.lock
    msglog="/var/log/update.log"
    
    log()
    {
            echo "$(date) ${1:-missing}" >> $msglog
    }
    
    if [ -f $lock ]; then
            log "Already run, exiting..."
    else
            > $lock
            git -C ~/$dir remote update &> /dev/null
            checkgit=`git -C ~/$dir status`
            if [[ ! "$checkgit" =~ "Your branch is up-to-date" ]]; then
                    log "-------------- Update ---------------"
                    git -C ~/$dir pull &>> $msglog
                    log "-------------------------------------"
            fi
            rm $lock
    
    fi
    exit 0
    

    Below script works perfectly

    changed=0
    git remote update && git status -uno | grep -q 'Your branch is behind' && changed=1
    if [ $changed = 1 ]; then
        git pull
        echo "Updated successfully";
    else
        echo "Up-to-date"
    fi
    

    You can also find a Phing script who does that now.

    I needed a solution to update my production environments automatically and we’re very happy thanks to this script that I’m sharing.

    The script is written in XML and needs Phing.

    Git Baby is a git and github fan, let's start git clone.