원격 저장소가 변경되었는지 확인하고 풀해야합니까?
이제이 간단한 스크립트를 사용합니다.
git pull --dry-run | grep -q -v 'Already up-to-date.' && changed=1
그러나 다소 무겁습니다.
더 좋은 방법이 있습니까? 이상적인 솔루션은 모든 원격 분기를 확인하고 변경된 분기의 이름과 각 분기의 새 커밋 수를 반환합니다.
git fetch -v --dry-run
당신이 필요로하는 것입니다.
원격 저장소가 변경되었는지 확인하고 풀해야합니까?
이제이 간단한 스크립트를 사용합니다.
git pull --dry-run | grep -q -v 'Already up-to-date.' && changed=1
그러나 다소 무겁습니다.
더 좋은 방법이 있습니까? 이상적인 솔루션은 모든 원격 분기를 확인하고 변경된 분기의 이름과 각 분기의 새 커밋 수를 반환합니다.
git fetch -v --dry-run
당신이 필요로하는 것입니다.
답변:
먼저을 사용 git remote update
하여 원격 심판을 최신 상태로 만드십시오. 그러면 다음과 같은 여러 가지 작업 중 하나를 수행 할 수 있습니다.
git status -uno
추적중인 지점이 앞, 뒤 또는 분기되었는지 여부를 알려줍니다. 아무 것도 말하지 않으면 로컬과 원격이 동일합니다.
git show-branch *master
이름이 'master'(예 : master 및 origin / master )로 끝나는 모든 브랜치에서 커밋을 표시합니다 .
당신이 사용하는 경우 -v
에 git remote update
( git remote -v update
당신이 정말로 더 이상 명령을 필요가 없습니다) 당신은 가지가 업데이트되었다 확인할 수 있습니다.
그러나 스크립트 또는 프로그램 에서이 작업을 수행하고 true / false 값으로 끝나는 것처럼 보입니다. 그렇다면 현재 HEAD 커밋과 추적중인 지점의 헤드 사이의 관계를 확인할 수있는 방법이 있지만 네 가지 가능한 결과가 있기 때문에 예 / 아니오로 줄일 수는 없습니다. 그러나, 준비가 되었다면 pull --rebase
"local is behind"와 "local has diverted"을 "need to need"로 취급하고 다른 두 개는 "tull을 가져올 필요가 없다"고 취급 할 수 있습니다.
를 사용하여 심판의 커밋 ID를 얻을 수 git rev-parse <ref>
있으므로 master 및 origin / 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
참고 : 이전 버전의 git은 @
자체적으로 허용하지 않으므로 @{0}
대신 사용해야 합니다.
현재 UPSTREAM=${1:-'@{u}'}
분기에 대해 구성된 것과 다른 원격 분기를 검사하려는 경우 선을 통해 선택적으로 업스트림 분기를 명시 적으로 전달할 수 있습니다. 일반적으로 remotename / branchname 형식 입니다. 매개 변수를 지정하지 않으면 기본값은 @{u}
입니다.
스크립트는 추적 분기를 최신 상태로 유지하기 위해 git fetch
또는 git remote update
먼저 수행 한 것으로 가정합니다 . 필자는 최근에 이미 페치했기 때문에 페치하지 않고 비교하려는 경우와 같이 가져 오기 및 비교를 별도의 작업으로 수행 할 수 있기 때문에 스크립트에 작성하지 않았습니다.
git status -s -u no
보다 더 짧은 출력을 제공하는을 시도 할 수도 있습니다 git status -u no
.
git remote -v update
. git remote --help
자세한 설명 은 출력을 참조하십시오 .
@{u}
했지만 git 1.8.3.2에서는 작동하지만 @
그렇지는 않다는 것을 알았습니다 . 그러나 @
와 작동합니다 1.8.5.4
. 이야기의 교훈 : git은 계속 개선되고 있으며 가능한 최신 버전을 보유 할 가치가 있습니다.
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
병합 할 것이 없습니다.
Git에서 기억 origin/master
하는 업스트림 분기 를 암시 적으로 사용하는 대신 명시 적으로 참조하는 경우 추적 리모트가없는 기능 분기에 있어도 작동 합니다.
git fetch; git log HEAD.. --oneline
로컬에 대한 기본 원격 브랜치가있는 경우 더 짧은 표기법도 사용할 수 있습니다.
git rev-list HEAD...origin/master --count
둘 사이에 "다른"커밋의 총 수를 제공합니다.
스크립트 용인 경우 다음을 사용할 수 있습니다.
git fetch
$(git rev-parse HEAD) == $(git rev-parse @{u})
(참고 :이 답변과 이전 답변의 이점은 현재 분기 이름을 얻기 위해 별도의 명령이 필요하지 않다는 것입니다. "HEAD"및 "@ {u}"(현재 분기의 업스트림)가이를 처리합니다. 자세한 내용은 "git rev-parse --help"를 참조하십시오.)
git rev-parse @{u}
실제로 최신이없이 커밋 보여 git fetch
?
==
"상류에서 변경 사항이없는 경우"를 사용하고 있습니다. 내가 사용 !=
확인하기 위해 내 응용 프로그램에 대한 "상류의 변경이있는 경우". git fetch
먼저 잊지 마십시오 !
@
줄임말입니다 HEAD
.
@{u}
예를 들어 작은 따옴표가 필요합니다.git rev-parse '@{u}'
명령
git ls-remote origin -h refs/heads/master
리모컨의 현재 헤드를 나열합니다. 이전 값과 비교하거나 로컬 리포지토리에 SHA가 있는지 확인할 수 있습니다.
git rev-list HEAD...origin/master --count
둘 사이에 "다른"커밋의 총 수를 제공합니다.
git fetch
이나 git remote update
첫 번째 경우에만 작동합니다 . git status
또한 카운트, btw를 보여줍니다.
fetch
.
다음은 현재 브랜치의 HEAD 커밋 해시를 원격 업스트림 브랜치와 비교 git fetch
하거나 무거운 git pull --dry-run
작업이 필요 없는 Bash one-liner입니다 .
[ $(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 명령 대체 구문을 사용하여 그룹화되고 중첩됩니다 .git rev-parse --abbrev-ref @{u}
축약 된 업스트림 참조 (예 :)를 반환 한 origin/master
다음 파이프 sed
명령에 의해 공백으로 구분 된 필드로 변환됩니다 (예 :) origin master
.git ls-remote
원격 브랜치의 헤드 커밋을 반환합니다. 이 명령은 원격 저장소와 통신합니다. piped cut
명령은 첫 번째 필드 (커밋 해시) 만 추출하여 탭으로 구분 된 참조 문자열을 제거합니다.git rev-parse HEAD
로컬 커밋 해시를 반환합니다.[ a = b ] && x || y
은 one-liner를 완성합니다. 이것은 테스트 구문 내의 Bash 문자열 비교 와 and-list 및 or-list 구문 입니다.=
[ test ]
&& true || false
https://github.com/badele/gitcheck 스크립트를 참조하십시오 . 나는 당신의 모든 Git 저장소를 한 번에 체크인하기 위해이 스크립트를 코딩했으며, 누가 커밋하지 않았는지, 누가 밀거나 당기지 않았는지 보여줍니다.
샘플 결과는 다음과 같습니다.
git mrepo -c
보류중인 모든 커밋이 표시됩니다.
나는이 솔루션을 @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
...
솔루션의 유효한 부분 인 것 같습니다.
이미 풍부하고 독창적 인 답변이 많이 있습니다. 약간의 대비를 제공하기 위해 매우 간단한 라인으로 할 수 있습니다.
# 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
나는 brool이 제안한 방법을 할 것입니다. 다음의 한 줄 스크립트는 마지막 커밋 된 버전의 SHA1을 가져 와서 원격 원점 중 하나와 비교하고 변경 사항이 다른 경우에만 변경 사항을 가져옵니다. 그리고 그것은 기반으로 솔루션을 더욱 경량의 git pull
나 git fetch
.
[ `git log --pretty=%H ...refs/heads/master^` != `git ls-remote origin
-h refs/heads/master |cut -f1` ] && git pull
git rev-parse --verify HEAD
git log --pretty=%H ...refs/heads/master^
마지막으로 커밋 된 버전 git ls-remote origin -h refs/heads/master |cut -f1
의 SHA1을 가져 오기 위해 실행 한 다음 실행 하여 원격 원본의 SHA1을 가져옵니다. 이 두 가지는 git 명령이며 bash와 관련이 없습니다. 대괄호 안에서 bash가하는 일은 첫 번째 명령의 출력을 두 번째 명령의 출력과 비교하는 것이며, 같으면 true를 반환하고 실행 git pull
합니다.
git pull
"를 실행 합니다. 나는 이질적인 것을 알고 있지만, 누군가 혼란을 막기 위해 "그리고 그들이 같지 않으면 "되어야합니다 . 또한 어떤 이유로 든 첫 번째 git 명령이 작동하지 않습니다. (git에 2.4.1
있습니다.) 그래서 git log --pretty=%H master | head -n1
대신에 사용 하고 있습니다. 그러나 그것이 정확히 같은지 확실하지 않습니다.
이 스크립트를 실행하면 현재 분기에 다음이 필요한지 테스트합니다 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
코멘트에서 이것을 놓치기 쉽기 때문에 이것을 실제 게시물로 게시하고 싶습니다.
이 질문에 대한 정답과 최상의 답변은 @Jake Berger에 의해 주어졌습니다. 대단히 감사합니다. 모든 사람이 이것을 필요로하며 모든 사람들이 의견에서 이것을 놓칩니다. 따라서 여기에 어려움을 겪고있는 모든 사람들이 정답입니다.이 명령의 출력을 사용하여 git pull을 수행 해야하는지 확인하십시오. 출력이 0이면 업데이트 할 것이 없습니다.
@ stackoverflow,이 사람에게 종을 줘. 감사합니다 @ Jake Berger
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
git fetch (remote)
원격 심판을 업데이트하기 위해 실행 하면 새로운 기능이 표시됩니다. 그런 다음 로컬 지점을 체크 아웃하면 업스트림 뒤에 있는지 여부가 표시됩니다.
git status
마찬가지입니다.
git pull --dry-run
에 있지만, 매분마다 cron 스크립트를 실행하는 것이 무겁다 고 생각합니다.
fetch
상태를 확인하는 것 이상을 할 수 없습니다. 원격 업데이트에 대해 매우 빠르고 가벼운 반응이 필요한 경우 일종의 알림을 원격 리포지토리에 연결하는 것이 좋습니다.
솔루션이 너무 짧고 쉬운 동안 모든 복잡한 sugestions :
#!/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
git remote update
합니다. 최신 오리진 커밋 정보를 얻으려면 코드 전에 실행해야합니다
git remote update
앞에 git show
명령을 추가 해서는 안 됩니까?
미리 정의 된 폴더의 모든 리포지토리를 확인하는 내 Bash 스크립트 버전은 다음과 같습니다.
https://gist.github.com/henryiii/5841984
풀 필요 및 푸시 필요와 같은 일반적인 상황을 구별 할 수 있으며 멀티 스레드이므로 페치가 한 번에 발생합니다. 끌어 오기 및 상태와 같은 몇 가지 명령이 있습니다.
경로의 폴더에 심볼릭 링크 (또는 스크립트)를 넣은 다음 git all status
(등) 으로 작동합니다 . 원산지 / 마스터 만 지원하지만 다른 방법으로 편집하거나 결합 할 수 있습니다.
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
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
간단한 정규 표현식 사용 :
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
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 리포지토리 git-fetch-and-rebase
의 선택적 인수로 호출 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
많은 답변과 여러 게시물을 읽은 후 반나절을 다양한 순열을 시도한 후에 이것이 내가 생각해 낸 것입니다.
Windows를 사용하는 경우 Windows 용 Git (설치 또는 휴대용)에서 제공하는 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 : 암호가 포함 된 URL을 콘솔에 인쇄하지 못하도록 stderr을 null로 설정했습니다.
#!/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
이 질문을 끝내는 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')
}
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__))
hth
또한 지금이를 수행 하는 Phing 스크립트 를 찾을 수 있습니다 .
프로덕션 환경을 자동으로 업데이트 할 수있는 솔루션이 필요했으며이 스크립트 덕분에 매우 기쁩니다.