检查是否需要拉Git中检查是否需要拉Git中(Check if pull needed in Git

2019-05-10 15:36发布

如何检查远程仓库是否有变化,我需要去拉?

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

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

但它是相当沉重的。

有没有更好的办法? 理想的解决方案会检查所有远程分支机构,并返回改变分支的名称和在每一个新的提交数量。

Answer 1:

首先使用git remote update ,带给你的远程裁判是最新的。 然后,你可以做的几件事情,如一个:

  1. git status -uno会告诉你,你所跟踪的分支是否领先,落后或已发散。 如果什么都不说,本地和远程是相同的。

  2. git show-branch *master会显示在所有后缀名为“主”(如 产地/主 )分支的提交。

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

然而,它看起来像你想这样做的脚本或程序,并用真/假值结束。 如果是这样,有很多方法可以检查您当前HEAD提交和您所跟踪的分支的头之间的关系,虽然因为有四种可能的结果,你不能把它降低到是/否的答案。 但是,如果你准备做一个pull --rebase那么你可以把“本地的背后”和“地方已发散”为“需要拉”,另两个为“不需要拉”。

你可以使用任何裁判的提交ID git rev-parse <ref>这样你就可以对 产地/主做到这一点并加以比较。 如果他们是平等的,树枝是相同的。 如果他们是不平等的,你要知道哪个是领先于其他的。 使用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

注:旧版本的Git不允许@自身的,所以你可能需要使用@{0}来代替。

线UPSTREAM=${1:-'@{u}'}允许你任选明确地传送的上游分支,如果要检查针对除所述一个构造成用于当前分支不同的远程分支。 这通常是形式的远程名称/ BRANCHNAME的。 如果没有指定参数,则默认值为@{u}

脚本假设你已经做了一个git fetchgit remote update首先带来的跟踪分支是最新的。 因为,如果你想不取,因为你已经最近取出的比较更灵活,能够做的抓取和比较作为单独的操作,例如我没有建立到脚本这一点。



Answer 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那么就没有什么合并。

请注意,这会工作,即使你是一个特性分支-即不具有远程跟踪,因为如果明确是指origin/master ,而不是隐式使用的Git想起上游分支的。



Answer 3:

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

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

(注意:这与以前的答案的好处是,你并不需要一个单独的命令来获得当前分支名“HEAD”和“@ {蓝}”(当前分支的上游)照顾它见“混帐REV-解析--help”的更多细节。)



Answer 4:

命令

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

将列出遥控器上的现任掌门人 - 你可以把它比作一个以前的值或者看看你是否有SHA在您的本地回购。



Answer 5:

这里的一个击单行,用于比较当前分支的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)击命令取代语法。
  • git rev-parse --abbrev-ref @{u}返回一个缩写上游REF(例如origin/master ),其随后由管道转换成空间分隔的字段sed命令,例如origin master
  • 此字符串被送入git ls-remote它返回头提交所述远程分支。 此命令将与远程存储库进行通信。 的管道cut命令提取只是第一场(提交散列),除去所述制表符分隔的引用字符串。
  • git rev-parse HEAD返回本地提交哈希值。
  • Bash的语法[ a = b ] && x || y [ a = b ] && x || y完成单行:这是一个bash 字符串比较 =测试构建体中[ test ] ,接着与列表和或列表构建&& true || false && true || false


Answer 6:

我建议你去看看剧本https://github.com/badele/gitcheck 。 我已经编写此脚本检查一次走你所有的Git仓库,它显示谁没有犯,谁没有推/拉。

这里的样本结果:



Answer 7:

我基于@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


Answer 8:

有很多非常丰富的特性和巧妙的回答了。 为了提供一些对比,我能凑合着用一个非常简单的线条。

# 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


Answer 9:

我想这样做,这将是最好的方法:

git diff remotes/origin/HEAD

假设你有这样的Refspec注册。 你应该如果你克隆的资源库,否则(即,如果回购创建从头本地,并推到远程),则需要明确添加的Refspec。



Answer 10:

我会做的brool建议的方式。 下面的一行脚本需要你的最后COMMITED版本的SHA1,并将其与远程起源的一个,拉的变化,只有当他们是不同的。 而且它是一个基于解决方案的更轻质git pullgit fetch

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


Answer 11:

下面的脚本完美的作品。

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


Answer 12:

如果您运行此脚本,它将测试,如果当前分支需要一个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

当你commitpulling

要使用此代码作为一个钩子,简单的复制/粘贴脚本

.git/hooks/pre-commit

chmod +x .git/hooks/pre-commit


Answer 13:

我只是想张贴此作为一个实际的职位,因为它很容易在评论错过本作。

对于这个问题的正确和最好的答案被@Jake伯格给出,非常感谢你的家伙,每个人都需要这个,每个人都错过本中的注释。 所以大家有这个挣扎在这里是正确的答案,只是使用此命令的输出知道,如果你需要做一个git的拉动。 如果输出为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


Answer 14:

运行git fetch (remote)来更新您的远程裁判,它会告诉你什么是新的。 然后,当你检出你的本地分支,它会告诉你它是否是背后的上游。



Answer 15:

这里是我的一个bash脚本,将检查预定义的文件夹中的所有存储库的版本:

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

它可以与常见的情况区分,像拉推所需的必要,它是多线程的,所以取一切发生一次。 它有几个命令,如拉和状态。

将一个文件夹中的一个符号链接(或脚本)在您的路径,那么它可以作为git all status (等)。 它只支持原点/主,但它可以被编辑或与另一种方法相结合。



Answer 16:

git ls-remote | cut -f1 | git cat-file --batch-check >&-

将列出任何远程,是不是在你的回购引用的一切。 为了赶上远程裁判改变你已有的东西(如重置为以前提交)需要多一点:

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


Answer 17:

使用简单的正则表达式:

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


Answer 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


Answer 19:

我用一个版本的基础上斯蒂芬·哈伯曼的回答脚本:

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 ,它可以用一个可选的参数来调用directory name本地Git仓库来执行操作。 如果调用脚本时不带任何参数,它假定当前目录是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

它可以在这里为好。



Answer 20:

读很多答案和多个职位,并且花费了半天时间尝试不同的排列组合后,这是我想出了。

如果您使用的是Windows,你可以运行使用的Git的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.

如果是打印由脚本的变化,那么你可以继续获取或拉。 该脚本可能不是有效的,但是它会为我做这项工作。

更新 - 二零一五年十月三十零日:标准错误到dev空防止印刷与密码到控制台的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


Answer 21:

对于谁在这个问题上寻找这个最终的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')
}


Answer 22:

您还可以找到一个Phing脚本现在谁做到这一点。

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

该脚本是用XML,需要Phing 。



文章来源: Check if pull needed in Git
标签: git bash shell