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

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

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

但它相当重。

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


当前回答

我会按照布罗尔的建议去做。下面的一行脚本使用您最后提交的版本的SHA1,并将其与远程原始版本的SHA1进行比较,仅在它们不同时才进行更改。 基于git pull或git fetch的解决方案更加轻量级。

[ `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

在阅读了许多答案和多个帖子,并花了半天时间尝试各种排列之后,这就是我想出的。

如果你在Windows上,你可以使用Git for Windows提供的Git Bash在Windows中运行这个脚本(安装或移植)。

这个脚本需要参数

- local path e.g. /d/source/project1
- Git URL e.g. https://username@bitbucket.org/username/project1.git
- password

if a password should not be entered on the command line in plain text,
then modify the script to check if GITPASS is empty; do not
replace and let Git prompt for a password

脚本将会

- 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 to 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

命令

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

将列出远程上的当前头—您可以将其与以前的值进行比较,或者查看您的本地回购中是否有SHA。

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

由brol给出的是检查遥控器中是否发生了变化的最简单的方法。

从局部头部开始:

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

我看到我拉的原点在那个标签处是最新的。Git状态也是这么说的。但这只是最新的本地数据,取数据后的(快进)合并。

检查远程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的摘要表顶部的信息大致相同:

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

只有ls-remote收集的信息更少-但只有我知道我是9e1ff…即v5.15-rc4。

除了命名引用(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代替“origin”。


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

如果你这么问,就拔。

我如何检查远程存储库是否最终完成了一些事情,我想要拉?

然后取回,检查,合并。


使用单个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说年龄:46分钟。关于最后一次在master上提交。

git取回后:

$ 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显示HASH或git diff HASH工作。

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

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

那我怎么知道什么时候拉呢?只要这两个散列是/将是不同的:更新9e1ff307c779..60 a9483534ed快进。它们不可能是一样的,那就是“没什么可更新的”。

最新的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不会首先查询远程头;取而代之的是使用缓存信息。

因为尼尔的回答对我帮助很大,这里是一个没有依赖关系的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__))

hth