检查是否需要在Git中拉

如何检查远程存储库是否已经更改,我需要拉?

现在我使用这个简单的脚本:

git pull --dry-run | grep -q -v 'Already up-to-date.' && changed=1 

但是它相当重。

有没有更好的办法? 理想的解决scheme将检查所有远程分支,并返回更改分支的名称和每个提交的新数量。

首先使用git remote update ,使您的远程refs最新。 然后你可以做几件事情之一,比如:

  1. git status -uno会告诉你你正在追踪的分支是前进还是后退。 如果什么都不说,本地和远程都是一样的。

  2. git show-branch *master将显示所有名称以“master”结尾的分支(例如masterorigin / master )的提交。

如果你使用-vgit remote updategit remote -v update ),你可以看到哪个分支得到了更新,所以你不需要任何进一步的命令。

但是,它看起来像你想要在脚本或程序中做到这一点,结束了一个真/假的价值。 如果是这样,有办法检查您当前的HEAD提交和您正在跟踪的分支的头部之间的关系,但由于有四个可能的结果,您不能将其减less到是/否的答案。 然而,如果你准备做一个pull --rebase那么你可以把“本地落后”和“本地分化”看作“需要拉动”,而另外两个就是“不需要拉动”。

你可以使用git rev-parse <ref>获得任何ref的提交ID,所以你可以对masterorigin / 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 fetchgit 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 fetchgit 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 ),然后通过piped sed命令(例如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 pullgit 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 。