Sprawdź czy pull jest potrzebny w Git

Jak sprawdzić, czy zdalne repozytorium się zmieniło i muszę je pobrać?

Teraz używam tego prostego skryptu:

git pull --dry-run | grep -q -v 'Already up-to-date.' && changed=1
Ale jest raczej ciężki. Czy jest lepszy sposób? Idealnym rozwiązaniem byłoby sprawdzenie wszystkich zdalnych gałęzi i zwrócenie nazw zmienionych gałęzi oraz liczby nowych commitów w każdej z nich.
 523
Author: Peter Mortensen, 2010-07-15

22 answers

Pierwsze użycie git remote update, aby Twoje zdalne refy były aktualne. Następnie możesz zrobić jedną z kilku rzeczy, takich jak:

  1. git status -uno powie Ci, czy gałąź, którą śledzisz, jest z przodu, z tyłu lub się rozeszła. Jeśli nic nie mówi, lokalne i zdalne są takie same.

  2. git show-branch *master wyświetli commity we wszystkich gałęziach, których nazwy kończą się na 'master' (np. master I origin / master ).

Jeśli używasz -v z git remote update (git remote -v update) możesz zobaczyć, które gałęzie zostały zaktualizowane, więc tak naprawdę nie potrzebujesz żadnych dalszych poleceń.

Jednak wygląda na to, że chcesz to zrobić w skrypcie lub programie i skończysz z wartością true / false. Jeśli tak, istnieją sposoby, aby sprawdzić związek pomiędzy Twoim obecnym HEAD commit a szefem gałęzi, którą śledzisz, chociaż ponieważ są cztery możliwe wyniki, nie możesz zredukować tego do odpowiedzi tak/nie. Jeśli jednak jesteś gotowy na pull --rebase, to może traktować "local is behind" I "local has diverged "jako" need to pull", a pozostałe dwa jako " don 't need to pull".

Możesz uzyskać identyfikator commitu dowolnego ref używając git rev-parse <ref>, więc możesz to zrobić dla master I origin/master i porównać je. Jeśli są równe, gałęzie są takie same. Jeśli są nierówne, chcesz wiedzieć, który jest przed drugim. Użycie git merge-base master origin/master powie Ci wspólnego przodka obu gałęzi, a jeśli się nie rozeszły, będzie to takie samo jak jedno albo drugie. Jeśli dostaniesz trzy różne identyfikatory, gałęzie się rozeszły.

Aby zrobić to poprawnie, np. w skrypcie, musisz być w stanie odwołać się do bieżącej gałęzi, oraz do gałęzi zdalnej, którą śledzi. Funkcja Bash prompt-setting w /etc/bash_completion.d ma kilka przydatnych kodów do pobierania nazw gałęzi. Jednak prawdopodobnie nie musisz zdobywać nazwisk. Git posiada kilka zgrabnych skrótów odnoszących się do gałęzi i commitów (jak zostało to udokumentowane w git rev-parse --help). W szczególności możesz użyć @ dla bieżąca gałąź (zakładając, że nie jesteś w stanie odłączonej głowicy) i @{u} dla jej gałęzi nadrzędnej (np origin/master). Tak więc git merge-base @ @{u} zwróci (hash) commita, w którym bieżąca gałąź i jej źródło się różnią, a git rev-parse @ i git rev-parse @{u} podadzą ci skróty dwóch podpowiedzi. Można to podsumować w następującym skrypcie:

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

Uwaga: starsze wersje Gita nie zezwalały na @ samodzielnie, więc być może będziesz musiał użyć @{0}.

Linia UPSTREAM=${1:-'@{u}'} pozwala na opcjonalnie jawnie przekazać gałąź upstream, na wypadek, gdybyś chciał sprawdzić inną zdalną gałąź niż ta skonfigurowana dla bieżącej gałęzi. Zazwyczaj ma to postać remotename/branchname. Jeśli nie podano żadnego parametru, wartość domyślna to @{u}.

Skrypt zakłada, że najpierw wykonałeś git fetch lub git remote update, aby uaktualnić gałęzie śledzące. Nie wbudowałem tego w skrypt, ponieważ jest bardziej elastyczny, aby móc wykonywać pobieranie i porównywanie jako oddzielne operacje, na przykład, jeśli chcesz porównać bez pobierania, ponieważ pobrano już niedawno.

 699
Author: Neil Mayhew,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-08-17 20:32:08

Jeśli masz gałąź upstream

git fetch <remote>
git status

Jeśli nie masz gałęzi upstream

Porównaj dwie gałęzie:

git fetch <remote>
git log <local_branch_name>..<remote_branch_name> --oneline

Na przykład:

git fetch origin

# See if there are any incoming changes
git log HEAD..origin/master --oneline

(zakładam, że origin/master to twoja zdalna gałąź śledzenia)

Jeśli któraś z rewizji znajduje się na liście powyżej, to masz nadchodzące zmiany -- musisz scalić. Jeśli nie ma commitów na liście git log, to nie ma nic do scalenia.

Zauważ, że to zadziała nawet jeśli jesteś na gałęzi feature-that nie posiada pilota do śledzenia, ponieważ if jawnie odwołuje się do origin/master zamiast do niejawnego używania gałęzi upstream zapamiętanej przez Git.

 117
Author: PlagueHammer,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-10-29 15:22:57

Jeśli jest to skrypt, możesz użyć:

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

(Uwaga: zaletą tej I poprzednich odpowiedzi jest to, że nie potrzebujesz osobnego polecenia, aby uzyskać bieżącą nazwę gałęzi. "HEAD" i "@{u} " (bieżąca gałąź jest pod prąd) dbają o to. Zobacz "git rev-parse --help" po więcej szczegółów.)

 49
Author: Stephen Haberman,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-10-16 18:34:53

Komenda

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

Wyświetli bieżącą głowicę na zdalnym -- możesz porównać ją z poprzednią wartością lub sprawdzić, czy masz SHA w lokalnym repo.

 34
Author: brool,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-07-15 17:37:21

Oto Jednolinijkowy Bash, który porównuje hash aktualnej gałęzi HEAD commit z odległą gałęzią upstream, bez konieczności wykonywania ciężkich operacji git fetch lub git 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

Oto jak ta nieco gęsta linia jest podzielona:

  • polecenia są grupowane i zagnieżdżane przy użyciu składni $(x) Bash command-substitution .
  • git rev-parse --abbrev-ref @{u} zwraca skrócony ref (np. origin/master), który jest następnie konwertowany na pola oddzielone spacjami za pomocą polecenia piped sed , np. origin master.
  • ten łańcuch jest wprowadzany do git ls-remote, który zwraca commit head zdalnej gałęzi. To polecenie będzie komunikować się ze zdalnym repozytorium. Polecenie piped cut wydobywa tylko pierwsze pole (Skrót zatwierdzania), usuwając oddzielony tabulatorami łańcuch odniesienia.
  • git rev-parse HEAD zwraca lokalny hash zatwierdzania.
  • Składnia Bash [ a = b ] && x || y uzupełnia one-liner: this is a Bash string-comparison = w konstrukcji testowej [ test ], po której następuje and-list and or-list constructs && true || false.
 26
Author: wjordan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-08-03 21:07:57

Proponuję zapoznać się ze skryptem https://github.com/badele/gitcheck . zakodowałem ten skrypt, aby sprawdzić w jednym przejściu wszystkie repozytoria Git, i pokazuje, kto nie popełnił, a kto nie pchnął / pociągnął.

Oto przykładowy wynik:

Tutaj wpisz opis obrazka

 17
Author: Bruno Adelé,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-11-29 23:04:44

Oparłem To rozwiązanie na komentarzach @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
 9
Author: ma11hew28,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-06-19 13:10:23

Myślę, że najlepszym sposobem na to będzie:

git diff remotes/origin/HEAD

Zakładając, że masz zarejestrowany ten refspec. Powinieneś, jeśli sklonowałeś repozytorium, w przeciwnym razie (np. jeśli repo zostało utworzone de novo lokalnie i przesunięte do zdalnego), musisz wyraźnie dodać refspec.

 8
Author: Jeet,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-07-16 01:18:01

Istnieje już wiele bardzo bogatych i pomysłowych odpowiedzi. Aby zapewnić kontrast, mógłbym zrobić bardzo prostą linię.

# 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
 8
Author: thuovila,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-03-03 08:59:50

Zrobiłbym to, co zasugerował brool. Poniższy skrypt jednowierszowy pobiera SHA1 ostatniej zatwierdzonej wersji i porównuje ją do zdalnej wersji origin i pobiera zmiany tylko wtedy, gdy różnią się one. I to jeszcze bardziej lekkie rozwiązania oparte na git pull lub git fetch.

[ `git log --pretty=%H ...refs/heads/master^` != `git ls-remote origin
-h refs/heads/master |cut -f1` ] && git pull
 6
Author: Claudio Floreani,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-03-10 17:42:20

Poniższy skrypt działa doskonale.

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
 5
Author: Harikrishna,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-12-20 23:33:44

Jeśli uruchomisz ten skrypt, sprawdzi, czy bieżąca gałąź potrzebuje 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
}

Jest bardzo wygodne, aby umieścić go jako Git hook pre-commit, aby uniknąć

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

Kiedy ty commit przed pulling.

Aby użyć tego kodu jako Hooka, po prostu skopiuj / wklej skrypt w

.git/hooks/pre-commit

I

chmod +x .git/hooks/pre-commit
 4
Author: Gilles Quenot,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-11-10 16:10:12

Uruchom git fetch (remote) aby zaktualizować swoje zdalne refy, pokaże ci, co nowego. Następnie, gdy kasujesz lokalny oddział, pokaże Ci, czy jest on za prądem.

 4
Author: che,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-09-23 20:10:56

Chcę po prostu opublikować to jako rzeczywisty post, ponieważ łatwo jest to przegapić w komentarzach.

Prawidłową i najlepszą odpowiedź na to pytanie dał @Jake Berger, dziękuję bardzo stary, każdy tego potrzebuje i każdy tęskni za tym w komentarzach. Więc dla wszystkich, którzy zmagają się z tym tutaj jest poprawna odpowiedź, po prostu użyj wyjścia tego polecenia, aby wiedzieć, czy musisz zrobić git pull. jeśli na wyjściu jest 0, to oczywiście nie ma co aktualizować.

@stackoverflow, daj ten facet to dzwonek. Dzięki @ 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
 2
Author: diegeelvis_SA,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-06-07 08:56:07
git ls-remote | cut -f1 | git cat-file --batch-check >&-

Wyświetli wszystkie odniesienia w każdym zdalnym, który nie jest w repo. Aby złapać zdalne zmiany ref do rzeczy, które już posiadałeś (np. reset do poprzednich commitów), potrzeba trochę więcej:

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
 1
Author: jthill,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-03-11 00:40:14

Oto moja wersja skryptu Bash, który sprawdza wszystkie repozytoria w predefiniowanym folderze:

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

Może rozróżniać typowe sytuacje, takie jak pociągnięcie potrzebne i pchnięcie potrzebne, i jest wielowątkowy, więc pobieranie dzieje się wszystko na raz. Posiada kilka poleceń, takich jak pull i status.

Umieść dowiązanie symboliczne (lub skrypt) w folderze w ścieżce, a następnie działa jako git all status (, itd.). Obsługuje tylko origin / master, ale może być edytowane lub łączone z inną metodą.

 1
Author: Henry Schreiner,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-12-20 23:07:28

Using simple regexp:

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
 1
Author: Tomas Kukis,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-03-07 14:50:28

Może to, jeśli chcesz dodać zadanie jako 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
 0
Author: Altzone,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-06-22 11:49:31

Używam wersji skryptu opartej na odpowiedzi Stephena Habermana:

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

Zakładając, że skrypt zostanie wywołany git-fetch-and-rebase, może być wywołany opcjonalnym argumentem directory name lokalnego repozytorium Git do wykonania operacji. Jeśli skrypt jest wywoływany bez argumentów, zakłada, że bieżący katalog jest częścią repozytorium Git.

Przykłady:

# 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

Jest on dostępny tutaj również.

 0
Author: Tuxdude,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-12-20 23:09:21

Po przeczytaniu wielu odpowiedzi i wielu postów, i spędzeniu pół dnia na próbowaniu różnych permutacji, to jest to, co wymyśliłem.

Jeśli korzystasz z systemu Windows, możesz uruchomić ten skrypt w systemie Windows używając Git Bash dostarczonego przez Git for Windows (installation lub portable).

Ten skrypt wymaga argumentów

- local path e.g. /d/source/project1
- Git URL e.g. https://[email protected]/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

Skrypt będzie

- Find the current branch
- Get the SHA1 of the remote on that branch
- Get the SHA1 of the local on that branch
- Compare them.

Jeśli nastąpiła zmiana wydrukowana przez skrypt, możesz przystąpić do pobierania lub pobierania. Skrypt może nie jest wydajny, ale to robi to za mnie.

Update-2015-10-30: stderr do dev null, aby zapobiec wydrukowaniu adresu URL z hasłem do konsoli.

#!/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
 0
Author: RuntimeException,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-12-20 23:33:11

Dla użytkowników windows, którzy kończą na tym pytaniu szukając tego, zmodyfikowałem część odpowiedzi na skrypt powershell. Dostosuj w razie potrzeby, Zapisz do pliku .ps1 i uruchom na żądanie lub zaplanuj, jeśli chcesz.

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')
}
 0
Author: Andrew Grothe,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-03-24 12:49:58

Możesz również znaleźć skrypt Phing Kto to teraz robi.

Potrzebowałem rozwiązania do automatycznej aktualizacji środowiska produkcyjnego i jesteśmy bardzo zadowoleni dzięki temu skryptowi, który udostępniam.

Skrypt jest napisany w XML i wymaga Phing .

 -1
Author: Pol Dellaiera,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-06-03 13:37:25