检查 Git 中是不是需要拉取

Posted

技术标签:

【中文标题】检查 Git 中是不是需要拉取【英文标题】:Check if pull needed in Git检查 Git 中是否需要拉取 【发布时间】:2011-03-16 13:17:27 【问题描述】:

如何查看远程仓库是否发生变化需要拉取?

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

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

但是比较重。

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

【问题讨论】:

请注意:“git pull --dry-run”可能无法按预期工作。似乎 git pull 直接将未知选项传递给 git fetch。结果是正常的 git pull。 "pull" 只是一次执行“fetch”和“merge”的一种简短方法,如果您需要检查远程 repo 状态,您实际上是在模拟“fetch”。所以git fetch -v --dry-run 是你所需要的。 我尝试了 OP 提出的解决方案,但它确实没有返回任何内容。可能不是最好的方法? 【参考方案1】:

首先使用git remote update,更新您的远程参考。然后你可以做几件事之一,例如:

    git status -uno 会告诉你你正在跟踪的分支是领先、落后还是已经偏离。如果它什么也没说,本地和远程是一样的。

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

如果您将-vgit remote update (git remote -v update) 一起使用,您可以看到哪些分支已更新,因此您实际上不需要任何其他命令。

但是,您似乎想在脚本或程序中执行此操作,并最终得到一个真/假值。如果是这样,有一些方法可以检查您当前的 HEAD 提交与您正在跟踪的分支的负责人之间的关系,尽管由于有四种可能的结果,您不能将其减少到是/没有答案。但是,如果您准备做pull --rebase,那么您可以将“本地落后”和“本地已经分歧”视为“需要拉动”,而其他两个(“本地领先”和“相同”)作为“不需要拉”。

您可以使用git rev-parse <ref> 获取任何 ref 的提交 ID,因此您可以对 masterorigin/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 fetchgit remote update,以使跟踪分支保持最新。我没有将它构建到脚本中,因为它能够将获取和比较作为单独的操作进行更灵活,例如,如果您想在不获取的情况下进行比较,因为您最近已经获取了。

【讨论】:

@takeshin 我猜你可以按照@brool 的建议将 git ls-remote origin -h refs/heads/master 与 git rev-list --max-count=1 origin/master 结合使用。如果它们返回相同的哈希,则远程分支自您上次更新远程引用(使用拉取、获取、远程更新等)以来没有更改。这将具有您不必下拉内容的优势立即提交所有提交,但可以将其留到更方便的时间。但是,由于远程更新是非破坏性的,因此您也可以这样做。 你也可以试试git status -s -u no,它的输出比git status -u no短。 @mhulse,git remote -v update。查看git remote --help 的输出以获得更完整的解释。 @ChrisMaes 好点。旧版本的 git 需要更明确的语法。我尝试了我拥有的各种系统,发现 @u 可以与 git 1.8.3.2 一起使用,但 @ 不能。但是@1.8.5.4 一起使用。故事的寓意:git 不断改进,值得拥有最新版本。 @现在需要一个说明符。您可以使用 @0 代替 @。【参考方案2】:

如果你有上游分支

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 没有列出任何提交,则没有可合并的内容。

请注意,即使您在功能分支上也可以使用 - 没有跟踪远程,因为 if 显式引用 origin/master 而不是隐式使用 upstream 分支 记住吉特。

【讨论】:

如果本地分支有默认的远程分支,甚至可以使用更短的符号git fetch; git log HEAD.. --oneline @philpirozhkov 如果你有一个默认的远程分支,我认为应该做一个简单的“git status”。我的答案是任何两个分支的通用答案,其中一个可能会或可能不会跟踪另一个。 git rev-list HEAD...origin/master --count 将为您提供两者之间“不同”提交的总数。 简短而简单。我最喜欢的只显示新提交的解决方案(点赞两次) 附注@JakeBerger 评论,您首先必须git fetch 远程接收最新更改。【参考方案3】:

如果这是一个脚本,你可以使用:

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

(注意:与以前的答案相比,此答案的好处是您不需要单独的命令来获取当前分支名称。“HEAD”和“@u”(当前分支的上游)负责它。有关详细信息,请参阅“git rev-parse --help”。)

【讨论】:

我独立发现了@u,并在看到你的答案之前更新了我的答案。 git rev-parse @u 会在没有git fetch 的情况下实际显示最新提交吗? 这是票!虽然,您的逻辑使用==,这意味着“如果上游没有更改”。我使用!= 为我的应用程序检查“是否有来自上游的更改”。别忘了先git fetch 我添加了 git fetch,因为确实有必要回答原始问题。 @HEAD btw 的缩写。 Windows 用户需要在@u 周围加上单引号,例如git rev-parse '@u'【参考方案4】:

命令

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

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

【讨论】:

有没有比较这些值的示例脚本? git rev-list HEAD...origin/master --count 将为您提供两者之间“不同”提交的总数。 @jberger 澄清一下,这只会显示您落后的提交数量(而不是领先和落后),并且只有在您首先 git fetchgit remote update 时才有效。 git status 也显示计数,顺便说一句。 @Dennis 我认为.. 是“在 origin/master 中的提交,减去 HEAD”(即后面的提交数)。而... 是symmetric difference(即前面和后面) 优秀。据我所知,这是唯一真正检查更新来源但不隐式执行fetch 的解决方案。【参考方案5】:

这是一个 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

以下是这条有点密集的线的分解方式:

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

【讨论】:

如果您在分支名称中使用斜杠,我将在 sed 上使用 /g。那只是“sed 's/\// /”。 @wjordan 当远程存储库无法访问(或正在维护)时,您的解决方案将失败,并将触发“最新”【参考方案6】:

我建议你去看看脚本https://github.com/badele/gitcheck。我已经编写了这个脚本,以便一次性签入你的所有 Git 存储库,它会显示谁没有提交以及谁没有推送/拉取。

这里是一个示例结果:

【讨论】:

整洁,考虑用纯shell重写 现在,您还可以直接从 docker 容器中使用 gitcheck(文件在您的主机中)。更多信息请参见 gitcheck github 项目 bash git-multi-repo-tooling 中的类似工具。 git mrepo -c 这将显示所有待处理的提交。【参考方案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

【讨论】:

【参考方案8】:

我认为最好的方法是:

git diff remotes/origin/HEAD

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

【讨论】:

【参考方案9】:

我的这个解决方案基于@jberger 的 cmets。

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

【讨论】:

参考你之前的comment,目前我无法给你一个明确的答案。在我制作这些 cmets 的时候,我正在深入 git 的深处,尤其是遥控器和差异。从那时起已经有几个月了,很多知识都埋藏在我的大脑中。 ;) 如果您正在寻找两者之间“不同”提交的数量,那么 ... 似乎是您解决方案的有效部分。 谢谢。这很干净。【参考方案10】:

我只想将其作为实际帖子发布,因为在 cmets 中很容易错过。

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

@***,给这个家伙一个铃铛。 谢谢@杰克伯杰

# 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

【讨论】:

谢谢你把它变成漂亮的 Arnaud :) 这是否需要fetch 才能按预期工作,或者对origin/master 的引用是否意味着git 将查询远程而不在本地获取任何内容? @NickChammas 这个命令是本地的,所以 after fetchbefore pull/merge/reset 很有用【参考方案11】:

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

# 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

【讨论】:

原始答案缺少'!'在如果。当没有变化时,来自 git diff 的返回值为零。 IMO 最好的解决方案,尽管我需要用“origin/master”或其他版本替换“remotes/origin/HEAD”【参考方案12】:

我会按照 brool 建议的方式进行。以下单行脚本采用您上次提交版本的 SHA1 并将其与远程来源的一个进行比较,并且仅当它们不同时才拉取更改。 而且它比基于git pullgit fetch 的解决方案更加轻量。

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

【讨论】:

如果使用“--depth 1”克隆 git 存储库(以限制下载大小),此命令将失败。你知道,如果有办法解决它? git 日志返回很多行,并给出错误“bash: [: too many arguments” 我会切换到git rev-parse --verify HEAD 这是一个由 bash 完成的简单字符串比较。如果出现问题,我建议您检查您的语法(即您输入错误)。首先运行git log --pretty=%H ...refs/heads/master^ 以获取您上次提交版本的SHA1,然后运行git ls-remote origin -h refs/heads/master |cut -f1 以获取远程源的SHA1。这两个是 git 命令,与 bash 无关。 bash 在方括号内的作用是将第一个命令的输出与第二个命令的输出进行比较,如果它们相等,则返回 true 并运行 git pull "如果它们相等,则返回 true 并运行 git pull"。我知道我很挑剔,但为了避免混淆,那应该是“如果他们相等”。此外,无论出于何种原因,第一个 git 命令对我不起作用。 (我在 git 2.4.1 上。)所以我只是使用 git log --pretty=%H master | head -n1 代替。但我不确定这是否完全相同。【参考方案13】:

如果你运行这个脚本,它会测试当前分支是否需要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 hook pre-commit来避免

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

当你在commit 之前pulling

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

.git/hooks/pre-commit

chmod +x .git/hooks/pre-commit

【讨论】:

【参考方案14】:

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

#!/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

【讨论】:

LAST_COMMIT 和 LAST_UPDATE 总是相等的,即使有变化 这个解决方案又好又简单,需要在你的代码之前执行git remote update,以获得最新的源提交信息 不应该在git remote update 之前追加git show 命令吗?【参考方案15】:

运行git fetch (remote) 来更新你的远程参考,它会告诉你什么是新的。然后,当您检查本地分支时,它会显示它是否落后于上游。

【讨论】:

我认为他已经检查了本地分支,所以他需要其他东西来显示它是否落后等。他可以使用 git status 来做到这一点。 没错,在您获取遥控器后,git status 也会显示这一点。 git pull --dry-run 的心情确实如此,但我认为每分钟运行一个 cron 脚本太重了。 @takeshin:不上网就无法检查远程存储库。如果没有任何新的fetch,除了检查状态之外不会做太多事情。如果您需要对远程更新做出非常快速和轻量级的反应,您可能需要考虑将某种通知挂钩到远程存储库。 @takeshin:如果你想每分钟检查一次远程仓库,我认为你错过了 DVCS 的重点。整个想法是能够独立开发一段时间,然后将它们顺利组合在一起。它不像 cvs、svn、p4 等,您总是必须在存储库中的最新内容之上工作。如果您确实需要其他人正在处理的东西,那么您应该使用不同的通信机制(例如电子邮件)来告诉您何时可以拉取。【参考方案16】:

这是我的 Bash 脚本版本,用于检查预定义文件夹中的所有存储库:

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

它可以区分常见情况,例如需要拉取和需要推送,并且它是多线程的,因此获取一次发生。它有几个命令,比如 pull 和 status。

将符号链接(或脚本)放在路径中的文件夹中,然后它会像git all status(等)一样工作。它只支持origin/master,但可以编辑或与其他方法组合。

【讨论】:

【参考方案17】:
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

【讨论】:

【参考方案18】:

如果你想将任务添加为 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

【讨论】:

【参考方案19】:

这个单线在 zsh 中为我工作(来自@Stephen Haberman 的回答)

git fetch; [ $(git rev-parse HEAD) = $(git rev-parse @u) ] \
    && echo "Up to date" || echo "Not up to date"

【讨论】:

【参考方案20】:
git ls-remote origin -h refs/heads/master

brool 提供的方法是最简单的方法,可以检查遥控器中是否有任何变化。

从本地头开始:

$ git log -1 --oneline @
9e1ff307c779 (HEAD -> master, tag: v5.15-rc4, origin/master, origin/HEAD) Linux 5.15-rc4

我看到我提取的原点在该标签上是最新的。 git status 也这么说。但这只是本地最新的,获取后的(快进)合并。

检查远程 HEAD 是否去了某个地方,还有 master,也许还有一些新标签:

$ git ls-remote origin HEAD master --tags 'v5.1[56]-rc[345]*'

84b3e42564accd94c2680e3ba42717c32c8b5fc4        HEAD
84b3e42564accd94c2680e3ba42717c32c8b5fc4        refs/heads/master
71a6dc2a869beafceef1ce46a9ebefd52288f1d7        refs/tags/v5.15-rc3
5816b3e6577eaa676ceb00a848f0fd65fe2adc29        refs/tags/v5.15-rc3^
f3cee05630e772378957a74a209aad059714cbd2        refs/tags/v5.15-rc4
9e1ff307c779ce1f0f810c7ecce3d95bbae40896        refs/tags/v5.15-rc4^

HEAD 仍然在同一个分支上,但不再是同一个提交。该本地 @ 提交保留在 v5.15-rc4 标记中。这与 kernel.org git 上的 summary 表顶部的信息大致相同:

Branch: master <commit message> <author> age: 2 hours

只有 ls-remote 收集的信息较少 - 但只有我知道我在 9e1ff... aka v5.15-rc4。

除了命名 refs(HEAD、master)或标签,还可以从任何 repo 中获取头或分支的列表:

$ git ls-remote --heads git://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git 

af06aff2a0007976513134dfe993d55992dd866a        refs/heads/akpm
20bcee8e95f783c11a7bea1b6a40c70a37873e0a        refs/heads/akpm-base
a25006a77348ba06c7bc96520d331cd9dd370715        refs/heads/master
4d5a088c93cea1c821d02a2217c592391d9682e2        refs/heads/pending-fixes
4de593fb965fc2bd11a0b767e0c65ff43540a6e4        refs/heads/stable

这里用一个 URL 代替“原点”。


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

如果你这样问,就拉吧。

如何检查远程仓库是否终于做了某事并且我想拉取?

然后你获取并检查并合并。


使用单个 git 命令:

$ git rev-list -1  master
9e1ff307c779ce1f0f810c7ecce3d95bbae40896
$ git rev-list -1  @
9e1ff307c779ce1f0f810c7ecce3d95bbae40896

这本身并没有多说,但假设我知道我没有犯任何事情,那么:

$ git ls-remote origin HEAD master
60a9483534ed0d99090a2ee1d4bb0b8179195f51        HEAD
60a9483534ed0d99090a2ee1d4bb0b8179195f51        refs/heads/master

会告诉我遥控器已更改。自上次编辑以来,它确实有。 kernel.org 说 Age: 46 min. 关于 master 上的最后一次提交。

git fetch之后:

$ git rev-list -1 master     
9e1ff307c779ce1f0f810c7ecce3d95bbae40896

$ git rev-list -1 FETCH_HEAD
60a9483534ed0d99090a2ee1d4bb0b8179195f51

$ git log --oneline ..FETCH_HEAD        
60a9483534ed (origin/master, origin/HEAD) Merge tag 'warning-fixes-20211005' of git://git.kernel.org/pub/scm/linux/kernel/git/dhowells/linux-fs
f6274b06e326 Merge tag 'linux-kselftest-fixes-5.15-rc5' of git://git.kernel.org/pub/scm/linux/kernel/git/shuah/linux-kselftest
ef31499a87cf fscache: Remove an unused static variable
d9e3f82279bf fscache: Fix some kerneldoc warnings shown up by W=1
bc868036569e 9p: Fix a bunch of kerneldoc warnings shown up by W=1
dcb442b13364 afs: Fix kerneldoc warning shown up by W=1
c0b27c486970 nfs: Fix kerneldoc warning shown up by W=1
84b3e42564ac Merge tag 'media/v5.15-3' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media
b60be028fc1a Merge tag 'ovl-fixes-5.15-rc5' of git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/vfs
df5c18838ea8 Merge tag 'mips-fixes_5.15_1' of git://git.kernel.org/pub/scm/linux/kernel/git/mips/linux
206704a1fe0b media: atomisp: restore missing 'return' statement
740da9d7ca4e MIPS: Revert "add support for buggy MT7621S core detection"
1dc1eed46f9f ovl: fix IOCB_DIRECT if underlying fs doesn't support direct IO
2f9602870886 selftests: drivers/dma-buf: Fix implicit declaration warns
a295aef603e1 ovl: fix missing negative dentry check in ovl_rename()

现在我在本地拥有所有信息,但还没有合并(还)。我还下载了所有对象。 git show HASHgit diff HASH 工作。

在这种情况下,合并几乎是无操作的:快进到最后一次提交,没有额外的(真正的)合并,更不用说冲突了。这可以通过 --ff-only 来确定:

$ git merge --ff-only FETCH_HEAD
Updating 9e1ff307c779..60a9483534ed
Fast-forward
...
... 

那么我怎么知道什么时候拉呢?一旦这两个哈希值/将有所不同:Updating 9e1ff307c779..60a9483534ed Fast-forward。它们不能相同,那将是“没有什么可更新的”。

最新的 reflog 提交也是这样说的:

$ git log -10 --oneline -g
60a9483534ed (HEAD -> master, origin/master, origin/HEAD) HEAD@0: merge 60a9483534ed0d99090a2ee1d4bb0b8179195f51: Fast-forward
9e1ff307c779 (tag: v5.15-rc4) HEAD@1: pull: Fast-forward

这样看来,出现一个新的标签可能是最好的触发点,也是这种情况下的目标;回到git ls-remote origin --tags PATTERN


...别告诉我git remote show另一种方法:

show 提供有关遥控器的一些信息。

使用 -n 选项,远程头不会首先使用 git ls-remote 进行查询;而是使用缓存的信息。

【讨论】:

【参考方案21】:

我使用基于 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

here 也可以使用。

【讨论】:

【参考方案22】:

看了很多答案和很多帖子,花了半天时间尝试各种排列,这就是我想出的。

如果您使用的是 Windows,则可以使用 Git for Windows 提供的 Git Bash 在 Windows 中运行此脚本(安装或便携)。

此脚本需要参数

- 本地路径,例如/d/source/project1 - Git URL 例如https://username@bitbucket.org/username/project1.git - 密码 如果不应在命令行中以纯文本形式输入密码, 然后修改脚本检查 GITPASS 是否为空;不要 替换并让 Git 提示输入密码

脚本将

- Find the 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 为 dev 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

【讨论】:

【参考方案23】:

使用简单的正则表达式:

str=$(git status) 
if [[ $str =~ .*Your\ branch\ is\ behind.*by.*commits,\ and\ can\ be\ fast-forwarded ]]; then
    echo `date "+%Y-%m-%d %H:%M:%S"` "Needs pull"
else
    echo "Code is up to date"
fi

【讨论】:

这行不通。 git status 只是一个本地检查,所以它只会告诉你如果你已经更新了你的远程定义,你的分支是否落后。【参考方案24】:

对于最终在此问题上寻找此问题的 Windows 用户,我已将部分答案修改为 powershell 脚本。根据需要进行调整,保存到 .ps1 文件并按需运行或按计划运行。

cd C:\<path to repo>
git remote update                           #update remote
$msg = git remote show origin               #capture status
$update = $msg -like '*local out of date*'
if($update.length -gt 0)                   #if local needs update
    Write-Host ('needs update')
    git pull
    git reset --hard origin/master
    Write-Host ('local updated')
 else 
    Write-Host ('no update needed')

【讨论】:

【参考方案25】:

因为 Neils 的回答对我帮助很大,所以这里是一个没有依赖关系的 Python 翻译:

import os
import logging
import subprocess

def check_for_updates(directory:str) -> None:
    """Check git repo state in respect to remote"""
    git_cmd = lambda cmd: subprocess.run(
        ["git"] + cmd,
        cwd=directory,
        stdout=subprocess.PIPE,
        check=True,
        universal_newlines=True).stdout.rstrip("\n")

    origin = git_cmd(["config", "--get", "remote.origin.url"])
    logging.debug("Git repo origin: %r", origin)
    for line in git_cmd(["fetch"]):
        logging.debug(line)
    local_sha = git_cmd(["rev-parse", "@"])
    remote_sha = git_cmd(["rev-parse", "@u"])
    base_sha = git_cmd(["merge-base", "@", "@u"])
    if local_sha == remote_sha:
        logging.info("Repo is up to date")
    elif local_sha == base_sha:
        logging.info("You need to pull")
    elif remote_sha == base_sha:
        logging.info("You need to push")
    else:
        logging.info("Diverged")

check_for_updates(os.path.dirname(__file__))

【讨论】:

【参考方案26】:

在所需分支上自动化git pull: 像这样使用:./pull.sh "origin/main"

#!/bin/bash

UPSTREAM=$1:-'@u'
DIFFCOMM=$(git fetch origin --quiet; git rev-list HEAD..."$UPSTREAM" --count)
if [ "$DIFFCOMM" -gt 0 ]; then
  echo "Pulling $UPSTREAM";
  git pull;
else
  echo "Up-to-date";
fi

【讨论】:

【参考方案27】:

您还可以找到a Phing script 现在谁在做这件事。

我需要一个解决方案来自动更新我的生产环境,感谢我分享的这个脚本,我们非常高兴。

脚本是用XML编写的,需要Phing。

【讨论】:

以上是关于检查 Git 中是不是需要拉取的主要内容,如果未能解决你的问题,请参考以下文章

有没有办法检查远程 git repo 是不是有更改,而无需实际获取更改?

SonarQube 检查代码然后传递给 git/repo

idea拉完代码发现代码和本地不一致

自动检查 git pull 请求以进行文件更改

git 服务器搭建及提交代码检查

为 GitHub 拉取请求添加验证检查