检查Git中是否需要拉动
如何检查远程存储库是否已更改,是否需要拉取 现在我使用这个简单的脚本:检查Git中是否需要拉动,git,bash,shell,Git,Bash,Shell,如何检查远程存储库是否已更改,是否需要拉取 现在我使用这个简单的脚本: git pull --dry-run | grep -q -v 'Already up-to-date.' && changed=1 但是它相当重 有更好的办法吗?理想的解决方案是检查所有远程分支,并返回已更改分支的名称以及每个分支中新提交的数量。命令 git ls-remote origin -h refs/heads/master 将在遥控器上列出当前头部——您可以将其与以前的值进行比较,或者查看您的
git pull --dry-run | grep -q -v 'Already up-to-date.' && changed=1
但是它相当重
有更好的办法吗?理想的解决方案是检查所有远程分支,并返回已更改分支的名称以及每个分支中新提交的数量。命令
git ls-remote origin -h refs/heads/master
将在遥控器上列出当前头部——您可以将其与以前的值进行比较,或者查看您的本地回购中是否有SHA。我认为最好的方法是:
git diff remotes/origin/HEAD
假设已注册此参照规范。如果您已经克隆了存储库,则应该这样做,否则(即,如果repo是在本地从头创建的,并推送到远程),则需要显式添加refspec。首先使用,以使远程ref更新。然后您可以执行以下几项操作之一,例如:
git status-uno
将告诉您正在跟踪的分支是在前面、后面还是已经分支。如果它什么也没说,本地和远程是一样的git show branch*master
将显示名称以“master”(例如master和origin/master)结尾的所有分支中的提交-v
与git remote update
(git remote-v update
)一起使用,您可以看到哪些分支得到了更新,因此实际上不需要任何进一步的命令
但是,看起来您希望在脚本或程序中执行此操作,并以真/假值结束。如果是这样的话,有很多方法可以检查您当前的负责人提交和您正在跟踪的分支机构负责人之间的关系,尽管有四种可能的结果,您不能将其归结为是/否。但是,如果您准备做一个pull--rebase
,那么您可以将“local is behind”和“local has divered”视为“need to pull”,将另外两个视为“not need to pull”
您可以使用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}
(例如原点/主节点
)。因此,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获取
或git远程更新
,以更新跟踪分支。我没有将其构建到脚本中,因为它更灵活,可以将获取和比较作为单独的操作来执行,例如,如果您想在不获取的情况下进行比较,因为您最近已经获取了数据。Rungit fetch(remote)
要更新远程引用,它将向您显示新内容。然后,当您签出本地分支机构时,它将显示它是否位于上游分支机构之后。如果您有上游分支机构
(我假设origin/master
是您的远程跟踪分支)
如果上面的输出中列出了任何提交,那么您就有了传入的更改——您需要合并。如果git log未列出任何提交,则没有要合并的内容
请注意,即使您在功能分支上,这也会起作用——该分支没有跟踪遥控器,因为if显式地引用
origin/master
,而不是隐式地使用Git记住的上游分支。我会按照brool建议的方式执行。下面的一行脚本获取您上一个提交版本的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
将列出任何远程中引用的、不在您的repo中的所有内容。要捕获对已有内容的远程引用更改(例如,重置为以前的提交),需要花费更多的时间:
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
git包引用--全部
我的=`mktemp`
sed'/^#/d/^^/{G;s/\(.*)\n.\(.*)/\1\2^{}/;};h'.git/包装参考|排序-k2>$mine
对于'git remote'中的r;做
回音检查$r。。。
git ls remote$r | sort-k2 | diff-b-$mine | grep^\<
完成
我建议你去看剧本。我已经编写了这个脚本,用于一次性签入所有Git存储库,它显示了谁没有提交,谁没有推/拉
下面是一个示例结果:
我基于@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
下面是我的Bash脚本版本,它检查所有reposit
[ `git log --pretty=%H ...refs/heads/master^` != `git ls-remote origin
-h refs/heads/master |cut -f1` ] && git pull
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
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
git fetch
$(git rev-parse HEAD) == $(git rev-parse @{u})
#!/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
}
Merge branch 'foobar' of url:/path/to/git/foobar into foobar
.git/hooks/pre-commit
chmod +x .git/hooks/pre-commit
[ $(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
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
# 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
# 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
- 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.
#!/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
#!/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
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
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
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')
}
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
#!/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
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__))
git fetch; [ $(git rev-parse HEAD) = $(git rev-parse @{u}) ] \
&& echo "Up to date" || echo "Not up to date"