Sprawdź, czy konieczne jest ściąganie w Git

622

Jak sprawdzić, czy zdalne repozytorium uległo zmianie i czy 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? Idealne rozwiązanie sprawdzi wszystkie odległe gałęzie i zwróci nazwy zmienionych gałęzi oraz liczbę nowych zatwierdzeń w każdej z nich.

zabiera
źródło
14
Uwaga: „git pull --dry-run” nie działa zgodnie z oczekiwaniami. Wygląda na to, że git pull przekazuje nieznane opcje bezpośrednio do git fetch. Rezultatem jest normalne ściąganie gitów.
27
„pull” to tylko krótki sposób na jednoczesne „pobranie” i „scalenie”, jeśli chcesz sprawdzić status zdalnego repo, naprawdę symulujesz „pobieranie”. Właśnie git fetch -v --dry-runtego potrzebujesz.
Claudio Floreani,

Odpowiedzi:

858

Pierwsze użycie git remote update, aby zaktualizować swoje zdalne referencje. Następnie możesz zrobić jedną z kilku rzeczy, takich jak:

  1. git status -unopoinformuje Cię, czy gałąź, którą śledzisz, znajduje się przed, za czy może się rozdzieliła. Jeśli nic nie mówi, lokalne i zdalne są takie same.

  2. git show-branch *masterpokaże zatwierdzenia we wszystkich gałęziach, których nazwy kończą się na „master” (np. master i origin / master ).

Jeśli używasz -vz 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ń.

Wygląda jednak na to, że chcesz to zrobić w skrypcie lub programie i uzyskać wartość prawda / fałsz. Jeśli tak, istnieją sposoby na sprawdzenie związku między twoim bieżącym zatwierdzeniem HEAD a szefem śledzonego oddziału, chociaż ponieważ są cztery możliwe wyniki, nie możesz zredukować go do odpowiedzi tak / nie. Jeśli jednak jesteś gotowy, aby to zrobićpull --rebase tego, możesz traktować „lokalny jest za”, a „lokalny jest rozbieżny” jako „trzeba ciągnąć”, a pozostałe dwa jako „nie trzeba ciągnąć”.

Możesz uzyskać identyfikator zatwierdzenia dowolnego używanego ref 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ć, co jest przed sobą. Użycie git merge-base master origin/masterpowie ci wspólnego przodka obu gałęzi, a jeśli się nie rozejdą, będzie to to samo, co jedno lub drugie. Jeśli otrzymasz trzy różne identyfikatory, gałęzie się rozeszły.

Aby to zrobić poprawnie, np. W skrypcie, musisz mieć możliwość odniesienia do bieżącej gałęzi, a gałąź zdalna śledzi ją. Funkcja ustawiania znaku zachęty w bash /etc/bash_completion.dzawiera użyteczny kod do pobierania nazw oddziałów. Jednak prawdopodobnie nie potrzebujesz nazwisk. Git ma kilka schludnych skrótów do odwoływania się do gałęzi i zatwierdzeń (jak udokumentowano w git rev-parse --help). W szczególności możesz użyć @dla bieżącej gałęzi (zakładając, że nie jesteś w stanie odłączonym) i @{u}dla jej gałęzi upstream (np origin/master.). Zwróci więc git merge-base @ @{u}(mieszanie) zatwierdzenie, w którym rozbieżność obecnego odgałęzienia i jego górnego biegu, git rev-parse @i git rev-parse @{u}da ci skróty dwóch wskazówek. Można to streścić 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 git nie pozwalały @same, więc może być konieczne użycie @{0}zamiast tego.

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

Skrypt zakłada, że ​​zrobiłeś pierwszy git fetchlub git remote updatepierwszy, aby zaktualizować gałęzie śledzące. Nie wbudowałem tego w skrypt, ponieważ jest bardziej elastyczne, aby móc pobierać i porównywać jako osobne operacje, na przykład jeśli chcesz porównać bez pobierania, ponieważ ostatnio został pobrany.

Neil Mayhew
źródło
4
@takeshin Chyba możesz połączyć git ls-remote origin -h refs / heads / master, jak sugeruje @brool z git rev-list - max-count = 1 origin / master. Jeśli zwrócą ten sam skrót, gałąź zdalna nie zmieniła się od czasu ostatniej aktualizacji zdalnych referencji (z ściąganiem, pobieraniem, zdalną aktualizacją itp.). Zaletą tego byłoby to, że nie musiałbyś ściągać zawartości wszystkie zobowiązania są od razu, ale mogą pozostawić to na wygodniejszy czas. Ponieważ jednak zdalna aktualizacja nie jest niszcząca, równie dobrze możesz to zrobić.
Neil Mayhew
2
Możesz także spróbować git status -s -u no, co daje krótszy wynik niż git status -u no.
Phillip Cloud,
2
@mhulse, git remote -v update. Spójrz na wynik git remote --helppełnego wyjaśnienia.
Neil Mayhew
1
@ChrisMaes Dobra uwaga. Bardziej wyraźna składnia jest potrzebna w starszych wersjach git. Eksperymentowałem z różnymi systemami, które miałem i okazało się, że @{u}działa z git 1.8.3.2, ale @nie działa. Jednak @współpracuje z 1.8.5.4. Morał tej historii: git ciągle się poprawia i warto mieć najnowszą wersję, jaką możesz.
Neil Mayhew
1
Specyfikator jest teraz wymagany dla @. Możesz użyć @ {0} zamiast @.
Ben Davis
132

Jeśli masz oddział upstream

git fetch <remote>
git status

Jeśli nie masz oddziału 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/masterjest to Twój oddział zdalnego śledzenia)

Jeśli jakieś zatwierdzenia są wymienione w wynikach powyżej, oznacza to, że masz nadchodzące zmiany - musisz je scalić. Jeśli do tej git logpory nie wymieniono żadnych zatwierdzeń, nie ma nic do scalenia.

Zauważ, że to zadziała, nawet jeśli jesteś na gałęzi funkcji - która nie ma zdalnego śledzenia, ponieważ jeśli jest to jawne odniesienie origin/masterzamiast domyślnego użycia odgałęzienia zapamiętanego przez Git.

PlagueHammer
źródło
2
Nawet krótszej notacji git fetch; git log HEAD.. --onelinemożna użyć, jeśli istnieje domyślna gałąź zdalna dla gałęzi lokalnej.
phil pirozhkov
@philpirozhkov Jeśli masz domyślną zdalną gałąź, myślę, że powinien zrobić prosty „status git”. Moja odpowiedź była ogólna dla dwóch dowolnych gałęzi, gdzie jedna może, ale nie musi, śledzić drugą.
PlagueHammer
55
git rev-list HEAD...origin/master --countda ci całkowitą liczbę „różnych” zatwierdzeń między nimi.
Jake Berger
1
krótki i prosty. Moje ulubione rozwiązanie, które pokazuje tylko nowe zmiany (kciuk w górę dwa razy)
spankmaster79
Jak mogę użyć tego w pliku wsadowym (Ubuntu), aby móc uruchamiać inne polecenia na wypadek, gdyby polecenie to wymagało ściągnięcia?
Ulysses Alves
69

Jeśli dotyczy to skryptu, 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ć nazwę bieżącej gałęzi. Zajmij się nią „HEAD” i „@ {u}” (poprzednia gałąź obecnego). Zobacz „git rev-parse --help”, aby uzyskać więcej informacji.)

Stephen Haberman
źródło
Odkryłem @ {u} niezależnie i zaktualizowałem moją odpowiedź, zanim zobaczyłem twoją.
Neil Mayhew
1
Czy git rev-parse @{u}faktycznie pokaże ostatnie zatwierdzenie bez git fetch?
Kyle Strand
3
To był bilet! Chociaż twoja logika używa, ==co oznacza „jeśli nie ma żadnych zmian w stosunku do wcześniejszego”. Kiedyś !=sprawdzałem, czy w mojej aplikacji nie ma „zmian w górę”. Nie zapomnij git fetchnajpierw!
ChrisPrime
1
Dodałem git fetch, ponieważ naprawdę trzeba odpowiedzieć na pierwotne pytanie. @jest skrótem od HEADbtw.
user1338062,
Użytkownicy systemu Windows będą potrzebować pojedynczych cudzysłowów na @{u}przykład np.git rev-parse '@{u}'
spuder
36

Komenda

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

wyświetli aktualną pozycję na pilocie - możesz porównać ją z poprzednią wartością lub sprawdzić, czy masz SHA w lokalnym repozytorium.

broszka
źródło
1
Każdy przykładowy skrypt do porównania tych wartości?
bierze
18
git rev-list HEAD...origin/master --countda ci całkowitą liczbę „różnych” zatwierdzeń między nimi.
Jake Berger
3
@jberger, aby wyjaśnić, że pokaże tylko liczbę zatwierdzeń, które jesteś w tyle (nie w przód i w tył) i działa tylko, jeśli ty git fetchlub git remote updatepierwszy. git statuspokazuje również liczbę, btw.
Dennis
1
@Dennis Myślałem, że ..to „ commits in origin / master, odejmując HEAD” (tzn. Liczba commits za). Natomiast ...jest symetryczna różnica (tj. Przód i tył)
Jake Berger
3
Świetny. O ile wiem, jest to jedyne rozwiązanie, które faktycznie sprawdza pochodzenie aktualizacji, ale nie robi tego pośrednio fetch.
Kyle Strand
35

Oto linijka Bash, która porównuje hash zatwierdzenia HEAD z bieżącej gałęzi z jego zdalnym odgałęzieniem, nie wymaga ciężkich operacji git fetchani git pull --dry-runoperacji:

[ $(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 rozkłada się ta nieco gęsta linia:

  • Polecenia są pogrupowane i zagnieżdżone przy użyciu składni $(x)Bash -podstawiania poleceń .
  • git rev-parse --abbrev-ref @{u}zwraca skrócone odwołanie zwrotne (np. origin/master), które jest następnie konwertowane na pola rozdzielone spacjami za pomocą sedpolecenia potokowego , np origin master.
  • Ten ciąg znaków jest wprowadzany do, git ls-remotektóry zwraca zatwierdzenie głowy zdalnej gałęzi. To polecenie komunikuje się ze zdalnym repozytorium. Polecenie potokowe cutwyodrębnia tylko pierwsze pole (skrót zatwierdzenia), usuwając ciąg odwołania oddzielony tabulatorami.
  • git rev-parse HEAD zwraca lokalny skrót zatwierdzenia.
  • Składnia Bash [ a = b ] && x || yuzupełnia jednowierszową: jest to porównanie = ciągu Bash w konstrukcie testowym [ test ], a następnie konstrukcje and-list i or-list && true || false.
Wjordan
źródło
2
Chciałbym nie jeśli używać ukośników w nazwach branży używać / g na sed. To jest tylko „sed” / \ // / ”.
Martyn Davis,
@wjordan Twoje rozwiązanie zawiedzie, gdy zdalne repozytorium jest nieosiągalne (lub jest w trakcie konserwacji) i uruchomi „aktualne”
ramka
20

Radzę zobaczyć skrypt https://github.com/badele/gitcheck . Zakodowałem ten skrypt do sprawdzenia w jednym przejściu wszystkich repozytoriów Git i pokazuje, kto nie popełnił, a kto nie wypchnął / nie wyciągnął.

Oto przykładowy wynik:

Wpisz opis zdjęcia tutaj

Bruno Adelé
źródło
6
schludny, myśląc o przepisaniu go w czystej powłoce
Olivier Refalo
1
Teraz możesz także używać gitcheck bezpośrednio z kontenera dokowanego (z plikami w hoście) Aby uzyskać więcej informacji, zobacz projekt gitubck gitcheck
Bruno Adelé
Podobne narzędzie w bash git-multi-repo-tooling . git mrepo -cspowoduje to wyświetlenie wszystkich oczekujących zmian.
Greg
11

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
ma11hew28
źródło
odnosząc się do twojego poprzedniego komentarza , w tej chwili nie mogę udzielić ci jednoznacznej odpowiedzi. W czasie, gdy robiłem te komentarze, nurkowałem w głębinach git, a zwłaszcza pilotów i diffów. Od tego czasu minęło kilka miesięcy, a duża część tej wiedzy jest zakopana w moim mózgu. ;) Jeśli szukasz liczby „różnych” zatwierdzeń między nimi, to ...wydaje się być prawidłową częścią twojego rozwiązania.
Jake Berger
1
Dzięki. To było czyste.
Shobhit Puri
10

Istnieje już wiele bardzo bogatych w funkcje i genialnych odpowiedzi. Aby zapewnić pewien kontrast, mógłbym zadowolić się 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
Thuovila
źródło
2
W pierwotnej odpowiedzi brakowało „!” w if. Zwracana wartość z git diff wynosi zero, gdy nie ma żadnych zmian.
thuovila
IMO najlepsze rozwiązanie, chociaż muszę zastąpić „piloty / pochodzenie / HEAD” słowem „pochodzenie / mistrz” lub inną wersję
Matthias Michael Engh
9

Myślę, że najlepszym sposobem na to byłoby:

git diff remotes/origin/HEAD

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

Jeet
źródło
9

Poniższy skrypt działa idealnie.

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
Harikrishna
źródło
6

Zrobiłbym sposób sugerowany przez Bro. Poniższy skrypt jednowierszowy pobiera SHA1 ostatniej zatwierdzonej wersji i porównuje go ze zdalnym źródłem i pobiera zmiany tylko wtedy, gdy się różnią. I to jeszcze bardziej lekkie rozwiązania oparte na git pulllub git fetch.

[ `git log --pretty=%H ...refs/heads/master^` != `git ls-remote origin
-h refs/heads/master |cut -f1` ] && git pull
Claudio Floreani
źródło
To polecenie kończy się niepowodzeniem, jeśli repozytorium git zostało sklonowane z opcją „--depth 1” (w celu ograniczenia rozmiaru pobierania). Czy wiesz, czy można to naprawić?
Adam Ryczkowski
Dziennik git zwraca to wiele wierszy i wyświetla komunikat o błędzie „bash: [: zbyt wiele argumentów” Przełączam nagit rev-parse --verify HEAD
Drew Pierce
1
Jest to proste porównanie napisów wykonane przez bash. Jeśli coś zawiedzie, sugeruję sprawdzenie składni (tzn. Wpisujesz ją źle). Najpierw uruchom, git log --pretty=%H ...refs/heads/master^ aby uzyskać SHA1 ostatniej zatwierdzonej wersji, a następnie uruchom, git ls-remote origin -h refs/heads/master |cut -f1 aby uzyskać SHA1 zdalnego pochodzenia. Te dwa są poleceniami git i nie mają nic wspólnego z bash. Bash wewnątrz nawiasów kwadratowych polega na porównaniu danych wyjściowych z pierwszego polecenia z drugim, a jeśli są równe, zwraca wartość true i uruchamia się git pull.
Claudio Floreani,
msgstr "a jeśli są równe, zwraca true i działa git pull". Wiem, że jestem podejrzany, ale żeby uratować kogoś od zamieszania, powinno to być „a jeśli nie równe”. Ponadto, z jakiegokolwiek powodu, pierwsze polecenie git nie działa dla mnie. (Jestem na git 2.4.1.) Więc używam git log --pretty=%H master | head -n1zamiast tego. Ale nie jestem pewien, czy to dokładnie to samo.
xd1le
6

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 to bardzo wygodne, aby umieścić go jako wstępny zatwierdzenie haka Git, aby uniknąć

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

kiedy ty commitwcześniej pulling.

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

.git/hooks/pre-commit

i

chmod +x .git/hooks/pre-commit
Gilles Quenot
źródło
6

Chcę tylko opublikować ten post jako rzeczywisty, ponieważ łatwo go przeoczyć w komentarzach.

Prawidłowa i najlepsza odpowiedź na to pytanie została udzielona przez @Jake Berger, Dziękuję bardzo, wszyscy tego potrzebują i wszyscy tęsknią w komentarzach. Więc dla wszystkich, którzy zmagają się z tym, tutaj jest poprawna odpowiedź, wystarczy użyć danych wyjściowych tego polecenia, aby wiedzieć, czy musisz wykonać polecenie git pull. jeśli wyjście ma wartość 0, to oczywiście nie ma nic do zaktualizowania.

@stackoverflow, daj temu facetowi dzwonki. 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
diegeelvis_SA
źródło
4

Uruchom, git fetch (remote)aby zaktualizować swoje zdalne referencje, pokaże ci, co nowego. Następnie, gdy kasujesz swój lokalny oddział, pokaże ci, czy jest on z tyłu.

che
źródło
Myślę, że ma już sprawdzony lokalny oddział, więc potrzebuje czegoś innego, aby pokazać, czy jest za nim itp. Może to zrobić ze statusem git.
Neil Mayhew
To prawda, że ​​po pobraniu pilotów również git statusto pokaże.
che
1
To coś w nastroju git pull --dry-run, ale myślę, że jest to zbyt trudne do uruchomienia skryptu cron co minutę.
bierze
@takeshin: Nie można sprawdzać zdalnych repozytoriów bez połączenia z siecią. Jeśli nie ma nic nowego fetch, nie zrobisz nic poza sprawdzeniem statusu. Jeśli potrzebujesz bardzo szybkiej i lekkiej reakcji na zdalne aktualizacje, możesz zajrzeć do przechwytywania pewnego rodzaju powiadomień do zdalnego repozytorium.
che
@takeshin: jeśli chcesz sprawdzać zdalne repozytorium co minutę, myślę, że przegapiłeś punkt DVCS. Cały pomysł polega na tym, aby móc przez pewien czas rozwijać się niezależnie, a następnie płynnie wszystko połączyć. To nie jest jak cvs, svn, p4 itp., Gdzie zawsze musisz pracować nad tym, co jest najnowsze w repozytorium. Jeśli naprawdę potrzebujesz czegoś, nad czym pracuje ktoś inny, powinieneś użyć innego mechanizmu komunikacji, takiego jak e-mail, aby poinformować Cię, kiedy będzie gotowy.
Neil Mayhew
4

Wszystkie takie złożone sugestie, podczas gdy rozwiązanie jest tak krótkie i łatwe:

#!/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
Digital Human
źródło
LAST_COMMIT i LAST_UPDATE są zawsze równe, nawet jeśli są zmiany
canbax
To rozwiązanie jest dobre i proste, należy wprowadzić polecenie git remote updatewykonania przed kodem, aby uzyskać najnowsze informacje o zatwierdzeniu pochodzenia
ak93
git remote updateNie powinien dołączać przed git showpoleceniami?
Setop
2

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 potrzeba ściągania i potrzeba push, i jest wielowątkowy, więc pobieranie odbywa się od razu. Ma kilka poleceń, takich jak pull i status.

Umieść dowiązanie symboliczne (lub skrypt) w folderze na swojej ścieżce, a następnie działa jako git all status(itp.). Obsługuje tylko origin / master, ale można go edytować lub łączyć z inną metodą.

Henry Schreiner
źródło
1
git ls-remote | cut -f1 | git cat-file --batch-check >&-

wyświetli listę wszystkich odnośników w dowolnym pilocie, którego nie ma w repozytorium. Aby przechwycić zmiany zdalnych zmian w rzeczach, które już miałeś (np. Resetuje poprzednie zatwierdzenia), potrzebujesz 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
jthill
źródło
1

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
Altzone
źródło
1

Za pomocą prostego wyrażenia regularnego:

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
Tomas Kukis
źródło
To nie zadziała. Status git jest tylko czekiem lokalnym, więc powiedziałby ci tylko, czy twój oddział jest w tyle, jeśli już zaktualizowałeś zdalne def.
minhaz1
0

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 ten skrypt jest wywoływany git-fetch-and-rebase, można go wywołać z opcjonalnym argumentemdirectory name lokalnego repozytorium Git w celu 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 również dostępny tutaj .

Tuxdude
źródło
0

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

Jeśli korzystasz z systemu Windows, możesz uruchomić ten skrypt w systemie Windows przy użyciu Git Bash dostarczonego przez Git dla Windows (instalacyjny lub przenośny).

Ten skrypt wymaga argumentów

- ścieżka lokalna np. / d / source / project1
- Git URL, np. Https: //[email protected]/username/project1.git
- hasło

jeśli hasło nie powinno być wprowadzane w wierszu poleceń zwykłym tekstem,
następnie zmodyfikuj skrypt, aby sprawdzić, czy GITPASS jest pusty; nie rób
zamień i pozwól Gitowi poprosić o hasło

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 pojawi się zmiana wydrukowana przez skrypt, możesz przystąpić do pobierania lub pobierania. Skrypt może nie być wydajny, ale wykonuje zadanie za mnie.

Aktualizacja - 30.10.2015: stderr na dev null, aby zapobiec drukowaniu 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
RuntimeException
źródło
0

Dla użytkowników systemu Windows, którzy szukają tego pytania, zmodyfikowałem część odpowiedzi w skrypcie PowerShell. Dostosuj w razie potrzeby, zapisz do .ps1pliku 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')
}
Andrew Grothe
źródło
0

Ponieważ odpowiedź Neilsa bardzo mi pomogła, oto tłumaczenie Pythona bez żadnych zależności:

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

franki
źródło
-5

Możesz także znaleźć skrypt Phing, który teraz to robi.

Potrzebowałem rozwiązania do automatycznej aktualizacji środowisk produkcyjnych i jesteśmy bardzo zadowoleni z tego skryptu, który udostępniam.

Skrypt jest napisany w formacie XML i wymaga phing .

Pol Dellaiera
źródło
Może nie jest dobrym pomysłem skopiowanie tutaj wklejania skryptu, wciąż go aktualizuję ...
Pol Dellaiera