如何检查远程仓库是否已更改,需要进行拉取操作?
目前我使用以下简单脚本:
git pull --dry-run | grep -q -v 'Already up-to-date.' && changed=1
但它相当沉重。
有没有更好的方法?理想的解决方案应该检查所有远程分支,并返回每个已更改分支的名称和新提交数量。
首先使用git remote update
命令,将您的远程引用更新到最新状态。然后您可以执行以下几个操作之一:
git status -uno
告诉您正在跟踪的分支是前进、落后还是已分叉。如果没有输出,本地和远程相同。
git show-branch *master
显示所有名称以“master”结尾的分支(例如 master 和 origin/master)中的提交。
如果您在 git remote update
中使用 -v
选项(git remote -v update
),则可以查看哪些分支已更新,因此您不需要任何其他命令。
但是,看起来您想在脚本或程序中执行此操作,并最终得到一个真/假值。如果是这样,有方法可以检查当前 HEAD 提交与正在跟踪的分支的 HEAD 之间的关系,尽管由于存在四种可能的结果,您无法将其简化为是/否答案。但是,如果您准备执行 pull --rebase
,那么您可以将“本地落后”和“本地已分叉”视为“需要拉取”,而将另外两个(“本地领先”和“相同”)视为“不需要拉取”。
git rev-parse <ref>
获取任何引用的提交ID,因此您可以针对master和origin/master执行此操作并进行比较。如果它们相等,则分支相同。如果它们不相等,则需要知道哪个领先于另一个。使用git merge-base master origin/master
将告诉您两个分支的公共祖先,如果它们没有分歧,则这将与其中一个相同。如果您获得三个不同的ID,则分支已经分叉。/etc/bash_completion.d
中的bash提示符设置函数具有一些有用的代码可用于获取分支名称。但是,您可能实际上不需要获取名称。 Git有一些简洁的方式来引用分支和提交(如git rev-parse --help
中所述)。特别地,您可以使用@
表示当前分支(假设您不处于分离头状态),@{u}
表示其上游分支(例如origin/master
)。因此,git merge-base @ @{u}
将返回当前分支和其上游分支分叉的(哈希值的)提交,git rev-parse @
和git rev-parse @{u}
将为您提供两个提示的哈希值。这可以在以下脚本中总结:#!/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}
。
行UPSTREAM=${1:-'@{u}'}
允许您显式传递上游分支,以防您想要针对与当前分支配置的不同远程分支进行检查。这通常采用remotename/branchname的形式。如果未给出参数,则该值默认为@{u}
。
脚本假定您已经先执行了git fetch
或git remote update
,以使跟踪分支保持最新状态。我没有将其构建到脚本中,因为将获取和比较作为单独操作更加灵活,例如,如果您想在不获取的情况下进行比较,因为您已经最近获取了。
git status -s -u no
,它比git status -u no
的输出更短。 - Phillip Cloudgit remote -v update
。查看git remote --help
的输出以获得更详细的说明。 - Neil Mayhewgit rev-parse --help
表示 @
是 HEAD
的快捷方式。我正在使用 git 版本 2.1.1
。 - Neil Mayhewgit 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
未列出任何提交记录,则没有需要合并的内容。
请注意,即使您在功能分支上--没有跟踪远程分支,这也可以正常工作,因为它明确地引用origin/master
而不是隐式使用Git记住的上游分支。
git fetch; git log HEAD.. --oneline
。 - phil pirozhkovgit rev-list HEAD...origin/master --count
会给你两者之间所有 "不同" 提交记录的总数。 - Jake Bergergit fetch
以接收远程最新更改。 - José Manuel Blasco如果这是为了脚本,你可以使用:
git fetch
$(git rev-parse HEAD) == $(git rev-parse @{u})
(注意:与之前的答案相比,这种方法的好处在于您不需要单独使用命令来获取当前分支名称。" HEAD "和" @{u} "(当前分支的上游)会处理它。有关更多详细信息,请参见" git rev-parse --help "。)
git rev-parse @{u}
会在没有进行git fetch
的情况下显示最新的提交吗? - Kyle Strand==
,意思是“如果与上游没有变化”。而我用!=
来检查“如果与上游有变化”,以供我的应用程序使用。别忘了先运行git fetch
命令! - ChrisPrime@
代表HEAD
。 - user1338062@{u}
周围加上单引号,例如git rev-parse '@{u}'
。 - spuder这里是一个Bash单行命令,比较当前分支的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 command-substitution 语法,将命令分组并嵌套。git rev-parse --abbrev-ref @{u}
返回一个简写的上游引用(例如 origin/master
),然后利用管道字符 sed
命令将其转换为以空格分隔的字段,例如 origin master
。git ls-remote
命令,该命令返回远程分支的头提交。此命令将与远程存储库通信。管道字符 cut
命令提取第一个字段(提交哈希),删除制表符分隔的引用字符串。git rev-parse HEAD
返回本地提交哈希。[ a = b ] && x || y
完成了这个一行命令:这是一个 Bash string-comparison =
在测试结构 [ test ]
中,接着是 and-list 和 or-list 结构 && true || false
。该命令
git ls-remote origin -h refs/heads/master
会列出远程仓库的当前 HEAD -- 你可以将其与先前的值进行比较,或查看你的本地仓库是否有该 SHA。
git rev-list HEAD...origin/master --count
可以给出两者之间“不同”的提交总数。 - Jake Bergergit fetch
或git remote update
命令的情况下才能正常工作。另外,git status
也会显示提交次数。 - Dennis以下脚本完美运行。
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
我建议您查看脚本https://github.com/badele/gitcheck。我编写了这个脚本以便一次性检查所有的Git仓库,并且它可以显示谁没有提交过代码,谁没有推送/拉取代码。
以下是一个示例结果:
我只是想将这个作为实际帖子发布,因为在评论中很容易错过。
这个问题的正确和最佳答案由 @Jake Berger 给出,非常感谢你,大家都需要这个答案,而且每个人都会在评论中错过它。所以,为了所有挣扎的人,这里是正确的答案,只需使用此命令的输出即可知道是否需要进行 git pull 操作。如果输出为 0,则显然无需更新任何内容。
@stackoverflow,请给这个家伙敲响铃铛。感谢 @Jake Berger。
# will give you the total number of "different" commits between the two
# Jake Berger Feb 5 '13 at 19:23
git rev-list HEAD...origin/master --count
fetch
才能按预期工作,还是对origin/master
的引用意味着git将在不获取本地任何内容的情况下查询远程? - Nick Chammasfetch
之后和 pull/merge/reset
之前非常有用。 - Akom我认为最好的方法是:
git diff remotes/origin/HEAD
假设您已经注册了此 refspec。 如果您已克隆存储库,则应该可以使用它; 否则(即如果是在本地新建并推送到远程存储库),您需要显式添加 refspec。
我基于@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
...
似乎是您解决方案的有效部分。 - Jake Berger
git fetch -v --dry-run
命令来完成这个任务。 - Claudio Floreani