检查是否需要在Git中拉
如何检查远程存储库是否已经更改,我需要拉?
现在我使用这个简单的脚本:
git pull --dry-run | grep -q -v 'Already up-to-date.' && changed=1 但是它相当重。
有没有更好的办法? 理想的解决scheme将检查所有远程分支,并返回更改分支的名称和每个提交的新数量。
 首先使用git remote update ,使您的远程refs最新。 然后你可以做几件事情之一,比如: 
- 
git status -uno会告诉你你正在追踪的分支是前进还是后退。 如果什么都不说,本地和远程都是一样的。
- 
git show-branch *master将显示所有名称以“master”结尾的分支(例如master和origin / master )的提交。
 如果你使用-v和git remote update ( git remote -v update ),你可以看到哪个分支得到了更新,所以你不需要任何进一步的命令。 
 但是,它看起来像你想要在脚本或程序中做到这一点,结束了一个真/假的价值。 如果是这样,有办法检查您当前的HEAD提交和您正在跟踪的分支的头部之间的关系,但由于有四个可能的结果,您不能将其减less到是/否的答案。 然而,如果你准备做一个pull --rebase那么你可以把“本地落后”和“本地分化”看作“需要拉动”,而另外两个就是“不需要拉动”。 
 你可以使用git rev-parse <ref>获得任何ref的提交ID,所以你可以对master和origin / master进行比较。 如果他们是平等的,分支是一样的。 如果他们不平等,你想知道哪个领先于另一个。 使用git merge-base master origin/master会告诉你两个分支的共同祖先,如果他们没有分歧,这将是相同的一个或另一个。 如果你得到三个不同的ID,分支已经分歧。 
 要做到这一点,例如在脚本中,您需要能够引用当前分支以及它正在跟踪的远程分支。  /etc/bash_completion.d的bash提示设置function有一些有用的代码来获取分支名称。 但是,您可能实际上并不需要获取名称。  Git有一些简洁的指向分支和提交的简写(如git rev-parse --help )。 特别是,您可以使用@作为当前分支(假设您不处于分离头状态),使用@{u}作为其上游分支(例如origin/master )。 所以git merge-base @ @{u}会返回当前分支和它的上游分支和git rev-parse @和git rev-parse @{u}的提交(hash)将会给你的哈希两个提示。 这可以概括为以下脚本: 
 #!/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 
  注意:旧版本的git自己不允许@ ,所以你可能不得不使用@{0} 。 
 如果您想要针对与为当前分支configuration的远程分支不同的远程分支进行检查,则可以select显式传递上游分支, UPSTREAM=${1:-'@{u}'} 。 这通常是remotename / branchname的forms。 如果没有给出参数,则该值默认为@{u} 。 
 该脚本假定您已经完成了git fetch或git remote update ,以使跟踪分支更新。 我没有将它构build到脚本中,因为它能够以单独的操作执行抓取和比较更加灵活,例如,如果因为您最近已经抓取而无需抓取进行比较。 
如果你有一个上游分支
 git fetch <remote> git status 
如果你没有上游分支
比较两个分支:
 git fetch <remote> git log <local_branch_name>..<remote_branch_name> --oneline 
例如:
 git fetch origin # See if there are any incoming changes git log HEAD..origin/master --oneline 
  (我假设origin/master是你的远程追踪分支) 
 如果在上面的输出中列出了任何提交,那么您有传入更改 – 您需要合并。 如果没有提交通过git log列出,那么没有什么可以合并。 
 请注意,即使你在一个function分支上,这个function也可以工作,因为如果明确地指的是origin/master而不是隐式地使用Git记住的上游分支 , 
如果这是一个脚本,你可以使用:
 git fetch $(git rev-parse HEAD) == $(git rev-parse @{u}) 
(注意:这个与以前的答案相比,好处是你不需要单独的命令来获取当前的分支名称,“HEAD”和“@ {u}”(当前分支的上游)负责处理它。 “git rev-parse –help”了解更多详情。)
命令
 git ls-remote origin -h refs/heads/master 
将列出远程的当前头 – 你可以将它与以前的值比较,或者看你在本地回购中是否有SHA。
 这是一个Bash git pull --dry-run比较当前分支的HEAD提交散列与远程上游分支,没有沉重的git fetch或git pull --dry-run所需的操作: 
 [ $(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 
下面是这条密集的线条如何分解:
-  命令使用$(x)Bash 命令replace语法进行分组和嵌套。
-   git rev-parse --abbrev-ref @{u}返回一个缩写的上游引用(例如origin/master),然后通过pipedsed命令(例如origin/master)将其转换为空格分隔的字段。
-  这个string被送入git ls-remote,它返回远程分支的头部提交。 该命令将与远程存储库进行通信。 pipe道cut命令只提取第一个字段(提交散列),删除制表符分隔的引用string。
-   git rev-parse HEAD返回本地提交散列。
-   Bash语法[ a = b ] && x || y[ a = b ] && x || y完成了一行:这是一个Bash string比较=在一个testing构造[ test ],其次是和列表和or列表结构&& true || false&& true || false。
我build议你去看脚本https://github.com/badele/gitcheck ,我已经编写了这个脚本检查一次通过所有的git仓库,它显示谁没有提交,谁没有推/拉。
 这里是一个示例结果 
我认为最好的办法是:
 git diff remotes/origin/HEAD 
假设你已经注册了这个refspec。 你应该如果你已经克隆了仓库,否则(例如,如果仓库在本地创build,并推送到远程),你需要明确添加refspec。
我基于@jberger的评论基于这个解决scheme。
 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 
 我会按照brool的build议。 以下单行脚本将取出最后一个提交版本的SHA1,并将其与远程原点的SHA1进行比较,并且只在两者不同时才进行更改。 基于git pull或git fetch的解决scheme更为轻量化。 
 [ `git log --pretty=%H ...refs/heads/master^` != `git ls-remote origin -h refs/heads/master |cut -f1` ] && git pull 
已经有许多非常丰富和巧妙的答案。 为了提供一些对比,我可以做一个非常简单的线。
 # 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 
 如果你运行这个脚本,它将testing当前分支是否需要一个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 } 
把它作为一个Git钩子预先提交来避免是非常方便的
 Merge branch 'foobar' of url:/path/to/git/foobar into foobar 
 当你commit之前commit 。 
要将此代码用作钩子,只需复制/粘贴脚本
 .git/hooks/pre-commit 
和
 chmod +x .git/hooks/pre-commit 
 运行git fetch (remote)来更新你的远程参考,它会告诉你什么是新的。 然后,当你结账你的本地分行,它会告诉你是否在上游。 
 git ls-remote | cut -f1 | git cat-file --batch-check >&- 
将列出任何不在您的回购中的远程引用的所有内容。 为了将远程ref修改为你已经拥有的东西(例如重置到之前的提交)需要多一点:
 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 
这里是我的一个bash脚本的版本,它检查预定义文件夹中的所有回购:
https://gist.github.com/henryiii/5841984
它可以区分常见的情况,比如需要拉取和推送,而且是multithreading的,所以抓取一次完成。 它有几个命令,如拉和状态。
 把一个符号链接(或脚本)放在你的path中的一个文件夹,然后它作为git all status (等)。 它仅支持origin / master,但可以编辑或与其他方法组合。 
我使用基于Stephen Haberman的答案的脚本版本:
 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 
 假设这个脚本叫做git-fetch-and-rebase ,可以用本地git仓库的一个可选的参数directory name来调用它,以执行操作。 如果脚本没有参数调用,它假定当前目录是git仓库的一部分。 
例子:
 # 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 
它也可以在这里使用 。
在阅读了许多答案和多个post后,花了半天的时间尝试各种排列,这就是我所想到的。
如果你在Windows上,你可以使用Git for Windows提供的gitbash(安装或便携)在Windows上运行这个脚本。
这个脚本需要参数
- 本地patheg / d / source / project1 - Git URL例如https://username@bitbucket.org/username/project1.git - 密码 如果密码不能以明文formsinput到命令行, 然后修改脚本来检查GITPASS是否为空,不 replace,让git提示input密码
该脚本将
 - find current branch - get the SHA1 of the remote on that branch - get the SHA1 of the local on that branch - compare them. 
如果脚本打印出来有变化,则可以继续取或拉。 脚本可能效率不高,但它为我完成了工作。
更新 – 2015-10-30:stderr开发null以防止用密码打印URL到控制台。
 #!/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 
也许这个,如果你想添加任务为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 
下面的脚本完美地运作
 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 
你现在也可以find一个Phing脚本 。
我需要一个解决scheme来自动更新我的生产环境,感谢我分享的这个脚本,我们非常高兴。
该脚本是用XML编写的,需要Phing 。