检查Git中是否需要拉

tak*_*hin 600 git bash shell

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

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

git pull --dry-run | grep -q -v 'Already up-to-date.' && changed=1
Run Code Online (Sandbox Code Playgroud)

但它相当沉重.

有没有更好的办法?理想的解决方案是检查所有远程分支,并返回已更改分支的名称和每个分支的新提交数.

Nei*_*hew 818

首次使用git remote update,让您的遥控器更新.然后你可以做以下几件事之一,例如:

  1. git status -uno会告诉你你正在跟踪的分支是在前面,后面还是分歧.如果没有说什么,本地和远程都是一样的.

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

如果使用-vwith git remote update(git remote -v update),您可以看到哪些分支已更新,因此您不需要任何其他命令.

但是,看起来您希望在脚本或程序中执行此操作,并最终得到true/false值.如果是这样,有一些方法可以检查当前HEAD提交与您正在跟踪的分支的负责人之间的关系,尽管由于有四种可能的结果,您无法将其减少为是/否答案.但是,如果你准备做一个,pull --rebase那么你可以将"本地落后"和"本地分歧"视为"需要拉动",另外两个则称为"不需要拉动".

您可以获取任何ref使用的提交ID git rev-parse <ref>,因此您可以为masterorigin/master执行此操作并进行比较.如果它们相等,则分支是相同的.如果他们不平等,你想知道哪一个先于另一个.使用git merge-base master origin/master将告诉你两个分支的共同祖先,如果它们没有分歧,这将是一个或另一个相同.如果你得到三个不同的ID,那么分支就会分歧.

要正确执行此操作(例如,在脚本中),您需要能够引用当前分支以及它正在跟踪的远程分支.bash提示设置函数/etc/bash_completion.d包含一些用于获取分支名称的有用代码.但是,您可能实际上并不需要获取名称.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
Run Code Online (Sandbox Code Playgroud)

注意:旧版本的git本身不允许@,因此您可能需要使用它@{0}.

该行UPSTREAM=${1:-'@{u}'}允许您可选地显式传递上游分支,以防您要检查与为当前分支配置的远程分支不同的远程分支.这通常是remotename/branchname的形式.如果未给出参数,则值默认为@{u}.

该脚本假设您已完成git fetchgit remote update首先执行,以使跟踪分支更新.我没有将它构建到脚本中,因为它能够更灵活地进行提取和比较作为单独的操作,例如,如果你想比较而不提取,因为你最近已经提取了.

  • @takeshin我猜你可以将@brool建议的git ls-remote origin -h refs/heads/master与git rev-list --max-count = 1 origin/master结合起来.如果它们返回相同的哈希值,则自上次更新远程引用后,远程分支没有更改(使用pull,fetch,remote update等).这样做的好处是您不必删除内容所有的提交马上,但可以留下更方便的时间.但是,由于远程更新是非破坏性的,您无论如何都可以这样做. (3认同)
  • 您还可以尝试`git status -s -u no`,它的输出比`git status -u no`短。 (2认同)
  • @mhulse,`git remote -v update`.查看`git remote --help`的输出以获得更全面的解释. (2认同)

Pla*_*mer 129

如果你有一个上游分支

git fetch <remote>
git status
Run Code Online (Sandbox Code Playgroud)

如果您没有上游分支

比较两个分支:

git fetch <remote>
git log <local_branch_name>..<remote_branch_name> --oneline
Run Code Online (Sandbox Code Playgroud)

例如:

git fetch origin

# See if there are any incoming changes
git log HEAD..origin/master --oneline
Run Code Online (Sandbox Code Playgroud)

(我假设origin/master你是远程跟踪分支)

如果上面的输出中列出了任何提交,那么您有传入的更改 - 您需要合并.如果没有列出提交,git log则没有任何内容可以合并.

请注意,即使您位于功能分支上(即没有跟踪远程),这也会起作用,因为如果显式引用origin/master而不是隐式使用Git记住的上游分支.

  • `git rev-list HEAD ... origin/master --count`将为你提供两者之间"不同"提交的总数. (49认同)
  • 即使是较短的符号`git fetch; git log HEAD .. --oneline`如果有本地的默认远程分支,则可以使用. (2认同)

Ste*_*man 61

如果是脚本,您可以使用:

git fetch
$(git rev-parse HEAD) == $(git rev-parse @{u})
Run Code Online (Sandbox Code Playgroud)

(注意:这与以前的答案相比,你不需要单独的命令来获取当前的分支名称."HEAD"和"@ {u}"(当前分支的上游)负责处理它. "git rev-parse --help"了解更多详情.)

  • 我添加了 git fetch,因为确实有必要回答原来的问题。顺便说一句,“@”是“HEAD”的缩写。 (4认同)
  • 这是票!不过,您的逻辑使用的是“ ==”,意思是“如果上游没有变化”。我使用`!=`来检查我的应用程序的“上游是否有更改”。不要忘了先`git fetch`! (3认同)

bro*_*ool 36

命令

git ls-remote origin -h refs/heads/master
Run Code Online (Sandbox Code Playgroud)

将列出遥控器上的当前头部 - 您可以将其与之前的值进行比较,或者查看您的本地仓库中是否有SHA.

  • `git rev-list HEAD ... origin/master --count`将为你提供两者之间"不同"提交的总数. (16认同)
  • @jberger澄清一下,这只会显示你落后的提交数量(不是前后),只有你首先使用`git fetch`或`git remote update`才能生效.`git status`也显示了一个计数,顺便说一句. (3认同)
  • 优秀.据我所知,这是实际检查更新源的唯一解决方案,但不隐式执行`fetch`. (3认同)

wjo*_*dan 33

这是一个Bash单行程序,它将当前分支的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
Run Code Online (Sandbox Code Playgroud)

这是一个有点密集的线被分解的方式:

  • 使用$(x)Bash 命令替换语法对命令进行分组和嵌套.
  • git rev-parse --abbrev-ref @{u}返回缩写的上游ref(例如origin/master),然后通过管道sed命令将其转换为空格分隔的字段,例如origin master.
  • 该字符串被送入git ls-remote其中,返回远程分支的头部提交.此命令将与远程存储库通信.piped cut命令仅提取第一个字段(提交哈希),删除以制表符分隔的引用字符串.
  • git rev-parse HEAD 返回本地提交哈希.
  • Bash语法[ a = b ] && x || y完成了单行:这是测试构造中的Bash 字符串比较 ,后跟and-list和or-list构造.=[ test ]&& true || false

  • 如果分支名称中使用斜杠,我将*不*在sed上使用/ g。那只是“ sed's / \ // /”。 (2认同)

Bru*_*elé 20

我建议你去看看脚本https://github.com/badele/gitcheck.我已经编写了这个脚本,以便一次性检查所有Git存储库,并显示谁没有提交,谁没有推/拉.

这是一个示例结果:

在此输入图像描述

  • 整洁,考虑用纯壳重写它 (6认同)

ma1*_*w28 10

我的解决方案基于@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
Run Code Online (Sandbox Code Playgroud)


Jee*_*eet 9

我认为最好的方法是:

git diff remotes/origin/HEAD
Run Code Online (Sandbox Code Playgroud)

假设您已注册此refspec.您应该克隆存储库,否则(即,如果repo是在本地创建并推送到远程),则需要显式添加refspec.


thu*_*ila 9

已经有许多功能丰富且巧妙的答案.为了提供一些对比,我可以用一个非常简单的线来做.

# 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
Run Code Online (Sandbox Code Playgroud)

  • 原来的答案是缺乏'!' 在if.当没有变化时,git diff的返回值为零. (2认同)

Har*_*hna 7

以下脚本完美无缺.

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
Run Code Online (Sandbox Code Playgroud)


Cla*_*ani 6

我会按照布鲁尔建议的方式行事.以下单行脚本获取上次提交的版本的SHA1,并将其与远程源的SHA1进行比较,并仅在它们不同时才进行更改.它的重量甚至更轻,基于git pullgit fetch.

[ `git log --pretty=%H ...refs/heads/master^` != `git ls-remote origin
-h refs/heads/master |cut -f1` ] && git pull
Run Code Online (Sandbox Code Playgroud)


Gil*_*not 6

如果您运行此脚本,它将测试当前分支是否需要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
}
Run Code Online (Sandbox Code Playgroud)

将它作为Git钩子预先提交以避免它是非常方便的

Merge branch 'foobar' of url:/path/to/git/foobar into foobar
Run Code Online (Sandbox Code Playgroud)

当你commit之前pulling.

要将此代码用作挂钩,只需复制/粘贴脚本即可

.git/hooks/pre-commit
Run Code Online (Sandbox Code Playgroud)

chmod +x .git/hooks/pre-commit
Run Code Online (Sandbox Code Playgroud)


Dig*_*man 6

所有这些复杂的建议,而解决方案是如此简短和简单:

#!/bin/bash

BRANCH="<your branch name>"
LAST_UPDATE=`git show --no-notes --format=format:"%H" $BRANCH | head -n 1`
LAST_COMMIT=`git show --no-notes --format=format:"%H" origin/$BRANCH | head -n 1`

git remote update
if [ $LAST_COMMIT != $LAST_UPDATE ]; then
        echo "Updating your branch $BRANCH"
        git pull --no-edit
else
        echo "No updates available"
fi
Run Code Online (Sandbox Code Playgroud)


che*_*che 5

运行git fetch (remote)以更新您的远程引用,它会向您显示新内容。然后,当您结帐本地分支时,它会显示它是否落后于上游。


die*_*_SA 5

我只想将其发布为实际发布,因为很容易在评论中错过它。

@Jake Berger给出了这个问题的正确和最佳答案,非常感谢,伙计,每个人都需要这个,每个人都在评论中错过了。因此,对于每个在此方面苦苦挣扎的人来说,这都是正确的答案,只需使用此命令的输出即可知道是否需要执行git pull。如果输出为0,则显然没有任何更新。

@stackoverflow,给这个家伙一个钟声。谢谢@杰克·伯格

git rev-list HEAD...origin/master --count will give you the total number of "different" commits between the two. – Jake Berger Feb 5 '13 at 19:23
Run Code Online (Sandbox Code Playgroud)