Überprüfen Sie, ob in Git ein Pull erforderlich ist

622

Wie überprüfe ich, ob sich das Remote-Repository geändert hat und ich ziehen muss?

Jetzt benutze ich dieses einfache Skript:

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

Aber es ist ziemlich schwer.

Gibt es einen besseren Weg? Die ideale Lösung würde alle Remote-Zweige überprüfen und die Namen der geänderten Zweige und die Anzahl der neuen Commits in jedem zurückgeben.

Takeshin
quelle
14
Bitte beachten Sie: "git pull --dry-run" funktioniert nicht wie erwartet. Es scheint, dass Git Pull unbekannte Optionen direkt an Git Fetch übergibt. Das Ergebnis ist das eines normalen Git Pull.
27
"Pull" ist nur ein kurzer Weg, um "Fetch" und "Merge" gleichzeitig auszuführen. Wenn Sie den Remote-Repo-Status überprüfen müssen, simulieren Sie wirklich einen "Fetch". Also git fetch -v --dry-runist was du brauchst.
Claudio Floreani

Antworten:

858

Verwenden git remote updateSie diese Option zuerst , um Ihre Remote-Refs auf den neuesten Stand zu bringen. Dann können Sie eines von mehreren Dingen tun, wie zum Beispiel:

  1. git status -unowird Ihnen sagen, ob der Zweig, den Sie verfolgen, vor, hinter oder divergiert. Wenn nichts gesagt wird, sind lokal und remote identisch.

  2. git show-branch *masterzeigt Ihnen die Commits in allen Zweigen, deren Namen auf 'master' enden (z. B. master und origin / master ).

Wenn Sie -vmit git remote update( git remote -v update) verwenden, können Sie sehen, welche Zweige aktualisiert wurden, sodass Sie keine weiteren Befehle benötigen.

Es sieht jedoch so aus, als ob Sie dies in einem Skript oder Programm tun möchten und am Ende einen True / False-Wert erhalten möchten. In diesem Fall gibt es Möglichkeiten, die Beziehung zwischen Ihrem aktuellen HEAD- Commit und dem Leiter des von Ihnen verfolgten Zweigs zu überprüfen. Da es jedoch vier mögliche Ergebnisse gibt, können Sie diese nicht auf eine Ja / Nein-Antwort reduzieren. Wenn Sie jedoch bereit sind, eine pull --rebaseAktion auszuführen, können Sie "lokal ist hinterher" und "lokal ist divergiert" als "ziehen müssen" und die anderen beiden als "nicht ziehen" behandeln.

Sie können die Commit-ID jeder Referenz mit abrufen git rev-parse <ref>, also können Sie dies für Master und Origin / Master tun und diese vergleichen. Wenn sie gleich sind, sind die Zweige gleich. Wenn sie ungleich sind, möchten Sie wissen, welche vor den anderen liegt. Mit git merge-base master origin/masterwird Ihnen der gemeinsame Vorfahr beider Zweige angezeigt. Wenn diese nicht voneinander abweichen, ist dies derselbe wie der eine oder andere. Wenn Sie drei verschiedene IDs erhalten, sind die Zweige auseinander gegangen.

Um dies richtig zu tun, z. B. in einem Skript, müssen Sie in der Lage sein, auf den aktuellen Zweig und den Remote-Zweig zu verweisen, den er verfolgt. Die Funktion zum Einstellen der Bash-Eingabeaufforderung in /etc/bash_completion.denthält nützlichen Code zum Abrufen von Zweigstellennamen. Allerdings müssen Sie die Namen wahrscheinlich nicht wirklich erhalten. Git hat einige nette Abkürzungen für den Verweis auf Zweige und Commits (wie in dokumentiert git rev-parse --help). Insbesondere können Sie @für den aktuellen Zweig (vorausgesetzt, Sie befinden sich nicht in einem Zustand mit getrenntem Kopf) und @{u}für den vorgelagerten Zweig (z origin/master. B. ) verwenden. So git merge-base @ @{u}kehrt die (Hash - Wert des) begehen , an dem die Stromzweig und seine Upstream - divergieren und git rev-parse @und git rev-parse @{u}sehen Sie die Hashes der beiden Tipps geben. Dies kann im folgenden Skript zusammengefasst werden:

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

Hinweis: Ältere Versionen von git waren für sich genommen nicht zulässig @, daher müssen Sie möglicherweise @{0}stattdessen verwenden.

Über die Leitung UPSTREAM=${1:-'@{u}'}können Sie optional einen Upstream-Zweig explizit übergeben, falls Sie einen anderen Remote-Zweig als den für den aktuellen Zweig konfigurierten vergleichen möchten. Dies hat normalerweise die Form Remotename / Branchname . Wenn kein Parameter angegeben wird, wird standardmäßig der Wert verwendet @{u}.

Das Skript setzt voraus, dass Sie eine git fetchoder die git remote updateerste Option ausgeführt haben , um die Tracking-Zweige auf den neuesten Stand zu bringen. Ich habe dies nicht in das Skript integriert, da es flexibler ist, das Abrufen und Vergleichen als separate Operationen durchzuführen, z. B. wenn Sie vergleichen möchten, ohne abzurufen, da Sie bereits kürzlich abgerufen haben.

Neil Mayhew
quelle
4
@takeshin Ich denke, Sie könnten git ls-remote origin -h refs / Heads / Master wie von @brool vorgeschlagen mit git rev-list --max-count = 1 origin / master kombinieren. Wenn sie denselben Hash zurückgeben, hat sich der Remote-Zweig seit der letzten Aktualisierung Ihrer Remote-Refs nicht geändert (mit Pull, Fetch, Remote-Update usw.). Dies hätte den Vorteil, dass Sie den Inhalt von nicht abrufen müssten alle Commits sofort, aber könnte das für eine bequemere Zeit verlassen. Da das Remote-Update jedoch nicht destruktiv ist, können Sie es trotzdem tun.
Neil Mayhew
2
Sie können auch versuchen git status -s -u no, was eine kürzere Ausgabe als ergibt git status -u no.
Phillip Cloud
2
@mhulse , git remote -v update. Schauen Sie sich die Ausgabe von an, git remote --helpum eine ausführlichere Erklärung zu erhalten.
Neil Mayhew
1
@ ChrisMaes Guter Punkt. Die explizitere Syntax wird bei älteren Versionen von git benötigt. Ich habe mit den verschiedenen Systemen experimentiert und festgestellt, dass dies @{u}mit Git 1.8.3.2 funktioniert, @aber nicht. Funktioniert jedoch @mit 1.8.5.4. Moral der Geschichte: Git verbessert sich ständig und es lohnt sich, die neueste Version zu haben, die Sie können.
Neil Mayhew
1
Für @ ist jetzt ein Bezeichner erforderlich. Sie können @ {0} anstelle von @ verwenden.
Ben Davis
132

Wenn Sie eine vorgelagerte Niederlassung haben

git fetch <remote>
git status

Wenn Sie keine vorgelagerte Niederlassung haben

Vergleichen Sie die beiden Zweige:

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

Zum Beispiel:

git fetch origin

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

(Ich gehe davon aus, dass origin/masteres sich um Ihren Remote-Tracking-Zweig handelt.)

Wenn in der obigen Ausgabe Commits aufgeführt sind, haben Sie eingehende Änderungen - Sie müssen zusammenführen. Wenn bis dahin keine Commits aufgeführt git logsind, muss nichts zusammengeführt werden.

Beachten Sie, dass dies auch dann funktioniert, wenn Sie sich in einem Feature-Zweig befinden - der keine Tracking-Fernbedienung hat, da explizit auf origin/masterden von Git gespeicherten Upstream-Zweig verwiesen wird , anstatt ihn implizit zu verwenden .

PlagueHammer
quelle
2
Sogar eine kürzere Notation git fetch; git log HEAD.. --onelinekann verwendet werden, wenn es einen Standard-Remote-Zweig für den lokalen gibt.
Phil Pirozhkov
@philpirozhkov Wenn Sie einen Standard-Remote-Zweig haben, sollte ein einfacher "Git-Status" meiner Meinung nach funktionieren. Meine Antwort war eine generische für zwei beliebige Zweige, in denen einer den anderen verfolgen kann oder nicht.
PlagueHammer
55
git rev-list HEAD...origin/master --countgibt Ihnen die Gesamtzahl der "unterschiedlichen" Commits zwischen den beiden.
Jake Berger
1
kurz und einfach. Meine Lieblingslösung, die nur die neuen Commits anzeigt (Daumen hoch)
spankmaster79
Wie kann ich dies in einer (Ubuntu) Batch-Datei verwenden, damit ich andere Befehle ausführen kann, nur für den Fall, dass dieser Befehl zeigt, dass ein Pull erforderlich ist?
Ulysses Alves
69

Wenn dies für ein Skript ist, können Sie Folgendes verwenden:

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

(Hinweis: Dies hat gegenüber früheren Antworten den Vorteil, dass Sie keinen separaten Befehl benötigen, um den aktuellen Filialnamen abzurufen. "HEAD" und "@ {u}" (der Upstream des aktuellen Zweigs) kümmern sich darum. Siehe "git rev-parse --help" für weitere Details.)

Stephen Haberman
quelle
Ich habe @ {u} unabhängig entdeckt und meine Antwort aktualisiert, bevor ich Ihre sah.
Neil Mayhew
1
Wird git rev-parse @{u}tatsächlich das neueste Commit ohne ein git fetchangezeigt?
Kyle Strand
3
Das war das Ticket! Ihre Logik verwendet jedoch, ==was bedeutet "wenn es KEINE Änderungen von Upstream gibt". Ich habe !=für meine Anwendung immer nach "ob es Änderungen gegenüber dem Upstream gibt" gesucht. Vergiss nicht git fetchzuerst!
ChrisPrime
1
Ich habe git fetch hinzugefügt, weil es wirklich notwendig ist, die ursprüngliche Frage zu beantworten. @ist HEADübrigens kurz für .
user1338062
Windows-Benutzer benötigen einfache Anführungszeichen um den @{u}zBgit rev-parse '@{u}'
spuder
36

Der Befehl

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

listet den aktuellen Kopf auf der Fernbedienung auf - Sie können ihn mit einem vorherigen Wert vergleichen oder sehen, ob Sie den SHA in Ihrem lokalen Repo haben.

brool
quelle
1
Gibt es ein Beispielskript zum Vergleichen dieser Werte?
Takeshin
18
git rev-list HEAD...origin/master --countgibt Ihnen die Gesamtzahl der "unterschiedlichen" Commits zwischen den beiden.
Jake Berger
3
@jberger zur Verdeutlichung, das zeigt nur die Anzahl der Commits an, hinter denen Sie stehen (nicht vor und hinter) und es funktioniert nur, wenn Sie git fetchoder git remote updatezuerst. git statuszeigt übrigens auch eine Zählung.
Dennis
1
@ Tennis Ich dachte, es ..ist "Commits in Origin / Master, HEAD subtrahieren" (dh Anzahl der Commits dahinter). Während ...ist der symmetrische Unterschied (dh vor und hinter)
Jake Berger
3
Ausgezeichnet. Soweit ich das beurteilen kann, ist dies die einzige Lösung, die den Ursprung tatsächlich auf Aktualisierungen überprüft, jedoch nicht implizit eine fetch.
Kyle Strand
35

Hier ist ein Bash-Einzeiler, der den HEAD-Commit-Hash des aktuellen Zweigs mit dem Remote-Upstream-Zweig vergleicht, ohne dass schwere git fetchoder git pull --dry-runOperationen erforderlich sind:

[ $(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

So wird diese etwas dichte Linie aufgeschlüsselt:

  • Befehle werden mithilfe der $(x)Bash- Befehlssubstitutionssyntax gruppiert und verschachtelt .
  • git rev-parse --abbrev-ref @{u}Gibt eine abgekürzte Upstream-Referenz (z. B. origin/master) zurück, die dann durch den sedBefehl piped in durch Leerzeichen getrennte Felder umgewandelt wird , z origin master.
  • Diese Zeichenfolge wird eingespeist, git ls-remotedie das Head-Commit des Remote-Zweigs zurückgibt. Dieser Befehl kommuniziert mit dem Remote-Repository. Der cutBefehl piped extrahiert nur das erste Feld (den Commit-Hash) und entfernt die durch Tabulatoren getrennte Referenzzeichenfolge.
  • git rev-parse HEAD Gibt den lokalen Commit-Hash zurück.
  • Die Bash-Syntax [ a = b ] && x || yvervollständigt den Einzeiler: Dies ist ein Bash- String-Vergleich = innerhalb eines Testkonstrukts [ test ], gefolgt von and-list- und or-list-Konstrukten && true || false.
wjordan
quelle
2
Ich würde nicht verwenden / g auf der sed , wenn Sie Schrägstriche in den Zweignamen verwenden. Das ist nur "sed's / \ // /".
Martyn Davis
@wjordan Ihre Lösung schlägt fehl, wenn das Remote-Repository nicht erreichbar ist (oder gerade gewartet wird) und "aktuell" auslöst
Frame
20

Ich schlage vor, Sie sehen sich das Skript https://github.com/badele/gitcheck an . Ich habe dieses Skript zum Einchecken aller Git-Repositorys in einem Durchgang codiert und es zeigt, wer nicht festgeschrieben und wer nicht gedrückt / gezogen hat.

Hier ein Beispielergebnis:

Geben Sie hier die Bildbeschreibung ein

Bruno Adelé
quelle
6
ordentlich, darüber nachdenken, es in reiner Hülle
umzuschreiben
1
Jetzt können Sie Gitcheck auch direkt aus einem Docker-Container verwenden (mit Ihren Dateien in Ihrem Host). Weitere Informationen finden Sie im Gitcheck-Github-Projekt
Bruno Adelé,
Ein ähnliches Tool in Bash Git-Multi-Repo-Tooling . git mrepo -cDadurch werden alle ausstehenden Commits angezeigt.
Greg
11

Ich habe diese Lösung auf den Kommentaren von @jberger basiert.

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
quelle
Unter Bezugnahme auf Ihren vorherigen Kommentar kann ich Ihnen zum jetzigen Zeitpunkt keine endgültige Antwort geben. Zu der Zeit, als ich diese Kommentare machte, tauchte ich in die Tiefen von Git und insbesondere in Fernbedienungen und Unterschiede ein. Seitdem sind einige Monate vergangen und ein Großteil dieses Wissens steckt in meinem Gehirn. ;) Wenn Sie nach der Anzahl der "unterschiedlichen" Commits zwischen den beiden suchen, ...scheint dies ein gültiger Teil Ihrer Lösung zu sein.
Jake Berger
1
Vielen Dank. Das war sauber.
Shobhit Puri
10

Es gibt bereits viele sehr funktionsreiche und geniale Antworten. Um einen gewissen Kontrast zu schaffen, könnte ich mit einer sehr einfachen Linie auskommen.

# 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
quelle
2
Die ursprüngliche Antwort fehlte '!' im wenn. Der Rückgabewert von git diff ist Null, wenn keine Änderungen vorliegen.
Thuovila
IMO beste Lösung da draußen, obwohl ich "Fernbedienungen / Ursprung / KOPF" durch "Ursprung / Master" oder eine andere Revision ersetzen muss
Matthias Michael Engh
9

Ich denke, der beste Weg, dies zu tun, wäre:

git diff remotes/origin/HEAD

Angenommen, Sie haben diese Referenz registriert. Wenn Sie das Repository geklont haben, andernfalls (dh wenn das Repo de novo lokal erstellt und auf die Fernbedienung übertragen wurde), müssen Sie die Referenzspezifikation explizit hinzufügen.

Jeet
quelle
9

Das folgende Skript funktioniert perfekt.

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
quelle
6

Ich würde den von Brool vorgeschlagenen Weg tun. Das folgende einzeilige Skript verwendet den SHA1 Ihrer letzten festgeschriebenen Version und vergleicht ihn mit dem des Remote-Ursprungs. Änderungen werden nur abgerufen, wenn sie sich unterscheiden. Und es ist noch leichter von den Lösungen, die auf git pulloder basieren git fetch.

[ `git log --pretty=%H ...refs/heads/master^` != `git ls-remote origin
-h refs/heads/master |cut -f1` ] && git pull
Claudio Floreani
quelle
Dieser Befehl schlägt fehl, wenn das Git-Repository mit "--depth 1" geklont wird (um die Downloadgröße zu begrenzen). Wissen Sie, ob es eine Möglichkeit gibt, das Problem zu beheben?
Adam Ryczkowski
Das Git-Protokoll gibt viele Zeilen zurück und gibt den Fehler "bash: [: zu viele Argumente" aus, zu dem ich wechseln würdegit rev-parse --verify HEAD
Drew Pierce
1
Dies ist ein einfacher String-Vergleich, der von bash durchgeführt wird. Wenn etwas fehlschlägt, würde ich Ihnen empfehlen, Ihre Syntax zu überprüfen (dh Sie geben sie falsch ein). Führen git log --pretty=%H ...refs/heads/master^ Sie zuerst den SHA1 Ihrer letzten festgeschriebenen Version aus und anschließend git ls-remote origin -h refs/heads/master |cut -f1 den SHA1 des Remote-Ursprungs aus. Diese beiden sind Git-Befehle und haben nichts mit Bash zu tun. Bash in den eckigen Klammern vergleicht die Ausgabe des ersten Befehls mit der des zweiten Befehls. Wenn sie gleich sind, wird true zurückgegeben und ausgeführt git pull.
Claudio Floreani
"und wenn sie gleich sind, gibt es true zurück und läuft git pull". Ich weiß, dass ich pingelig bin, aber nur um jemandem Verwirrung zu ersparen, sollte das "und wenn sie nicht gleich sind" sein. Aus irgendeinem Grund funktioniert der erste git-Befehl bei mir nicht. (Ich bin auf Git 2.4.1.) Also benutze ich git log --pretty=%H master | head -n1stattdessen nur. Aber ich bin mir nicht sicher, ob das genau das gleiche ist.
xd1le
6

Wenn Sie dieses Skript ausführen, wird getestet, ob der aktuelle Zweig Folgendes benötigt 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
}

Es ist sehr praktisch, es als Git-Hook-Pre-Commit zu verwenden, um dies zu vermeiden

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

wenn du commitvorherpulling .

Um diesen Code als Hook zu verwenden, kopieren Sie einfach das Skript und fügen Sie es ein

.git/hooks/pre-commit

und

chmod +x .git/hooks/pre-commit
Gilles Quenot
quelle
6

Ich möchte dies nur als tatsächlichen Beitrag veröffentlichen, da es leicht ist, dies in den Kommentaren zu übersehen.

Die richtige und beste Antwort auf diese Frage gab @Jake Berger. Vielen Dank, Alter, jeder braucht das und jeder vermisst dies in den Kommentaren. Für alle, die damit zu kämpfen haben, ist hier die richtige Antwort. Verwenden Sie einfach die Ausgabe dieses Befehls, um zu wissen, ob Sie einen Git-Pull ausführen müssen. Wenn die Ausgabe 0 ist, gibt es offensichtlich nichts zu aktualisieren.

@stackoverflow, gib diesem Kerl eine Glocke. Danke @ 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
quelle
4

Führen Sie es aus git fetch (remote), um Ihre Remote-Refs zu aktualisieren. Es zeigt Ihnen, was neu ist. Wenn Sie dann Ihre lokale Niederlassung auschecken, wird angezeigt, ob sie sich hinter dem Upstream befindet.

che
quelle
Ich denke, er hat bereits die lokale Niederlassung ausgecheckt, also braucht er etwas anderes, um zu zeigen, ob es dahinter steckt usw. Er kann dies mit dem Git-Status tun.
Neil Mayhew
Richtig, nachdem Sie Fernbedienungen abgerufen haben, git statuswird dies auch angezeigt .
Che
1
Das ist etwas in der Stimmung git pull --dry-run, aber ich denke, es ist zu schwer für ein Cron-Skript, das jede Minute ausgeführt wird.
Takeshin
@takeshin: Sie können Remote-Repositorys nicht überprüfen, ohne ins Netzwerk zu gehen. Wenn es nichts Neues gibt, wird es nicht fetchviel weiter tun, als den Status zu überprüfen. Wenn Sie eine sehr schnelle und einfache Reaktion auf Remote-Updates benötigen, sollten Sie eine Art von Benachrichtigungen an das Remote-Repository anschließen.
Che
@takeshin: Wenn Sie das Remote-Repo jede Minute überprüfen möchten, haben Sie den Punkt von DVCS verpasst. Die ganze Idee ist, sich für eine Weile selbständig entwickeln zu können und später alles reibungslos zusammenzufügen. Es ist nicht wie bei cvs, svn, p4 usw., bei denen Sie immer auf dem neuesten Stand im Repository arbeiten müssen. Wenn Sie wirklich etwas benötigen, an dem jemand anderes arbeitet, sollten Sie einen anderen Kommunikationsmechanismus verwenden, z. B. E-Mail, um Ihnen mitzuteilen, wann es zum Abrufen bereit ist.
Neil Mayhew
4

All diese komplexen Vorschläge, während die Lösung so kurz und einfach ist:

#!/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
Digitaler Mensch
quelle
LAST_COMMIT und LAST_UPDATE sind immer gleich, auch wenn es Änderungen gibt
canbax
Diese Lösung ist gut und einfach. Sie muss git remote updatevor Ihrem Code ausgeführt werden, um die neuesten Informationen zum Commit des Ursprungs zu erhalten
ak93
Sollte git remote updatenicht vor git showBefehlen angehängt werden?
Setop
2

Hier ist meine Version eines Bash-Skripts, das alle Repositorys in einem vordefinierten Ordner überprüft:

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

Es kann zwischen gängigen Situationen unterscheiden, z. B. Ziehen erforderlich und Drücken erforderlich, und es ist multithreaded, sodass der Abruf auf einmal erfolgt. Es hat mehrere Befehle, wie Pull und Status.

Fügen Sie einen Symlink (oder das Skript) in einen Ordner in Ihrem Pfad ein, dann funktioniert er als git all status(usw.). Es unterstützt nur origin / master, kann aber bearbeitet oder mit einer anderen Methode kombiniert werden.

Henry Schreiner
quelle
1
git ls-remote | cut -f1 | git cat-file --batch-check >&-

listet alles auf, auf das in einer Fernbedienung verwiesen wird, die nicht in Ihrem Repo enthalten ist. Das Abfangen von Änderungen an entfernten Refs an Dingen, die Sie bereits hatten (z. B. Zurücksetzen auf vorherige Commits), erfordert etwas mehr:

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
quelle
1

Vielleicht das, wenn Sie eine Aufgabe als crontab hinzufügen möchten:

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

Mit einfachem regulären Ausdruck:

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
quelle
Dies wird nicht funktionieren. Der Git-Status ist nur eine lokale Überprüfung und zeigt Ihnen daher nur an, ob Ihr Zweig im Rückstand ist, wenn Sie Ihre Remote-Defs bereits aktualisiert haben.
Minhaz1
0

Ich verwende eine Version eines Skripts, die auf Stephen Habermans Antwort basiert:

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

Angenommen, dieses Skript wird aufgerufen git-fetch-and-rebase, kann es mit einem optionalen Argument aufgerufen werdendirectory name des lokalen Git-Repositorys , um die Operation auszuführen. Wenn das Skript ohne Argumente aufgerufen wird, wird davon ausgegangen, dass das aktuelle Verzeichnis Teil des Git-Repositorys ist.

Beispiele:

# 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

Es ist auch hier erhältlich .

Tuxdude
quelle
0

Nachdem ich viele Antworten und mehrere Beiträge gelesen und einen halben Tag damit verbracht habe, verschiedene Permutationen auszuprobieren, habe ich mir das ausgedacht.

Wenn Sie unter Windows arbeiten, können Sie dieses Skript unter Windows mit Git Bash ausführen, das von Git für Windows bereitgestellt wird (Installation oder portabel).

Dieses Skript erfordert Argumente

- lokaler Pfad zB / d / source / project1
- Git URL zB https: //[email protected]/username/project1.git
- Passwort

Wenn in der Befehlszeile kein Kennwort im Klartext eingegeben werden soll,
Ändern Sie dann das Skript, um zu überprüfen, ob GITPASS leer ist. unterlassen Sie
Ersetzen Sie und lassen Sie Git nach einem Passwort fragen

Das Skript wird

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

Wenn es eine vom Skript gedruckte Änderung gibt, können Sie mit dem Abrufen oder Abrufen fortfahren. Das Skript ist zwar nicht effizient, erledigt aber die Arbeit für mich.

Update - 30.10.2015: stderr to dev null, um zu verhindern, dass die URL mit dem Kennwort an die Konsole gedruckt wird.

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

Für die Windows-Benutzer, die auf diese Frage stoßen und danach suchen, habe ich einen Teil der Antwort in ein Powershell-Skript geändert. Passen Sie die Einstellungen nach Bedarf an, speichern Sie sie in einer .ps1Datei und führen Sie sie bei Bedarf aus oder planen Sie sie, wenn Sie möchten .

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
quelle
0

Weil mir Neils Antwort so sehr geholfen hat, gibt es hier eine Python-Übersetzung ohne Abhängigkeiten:

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

frans
quelle
-5

Sie können auch ein Phing-Skript finden , das das jetzt tut.

Ich brauchte eine Lösung, um meine Produktionsumgebungen automatisch zu aktualisieren, und wir freuen uns sehr über dieses Skript, das ich teile.

Das Skript ist in XML geschrieben und benötigt Phing .

Pol Dellaiera
quelle
Vielleicht ist es keine gute Idee, das Skript hier zu kopieren und
einzufügen