Warum sagt Git, dass mein Hauptzweig "bereits auf dem neuesten Stand" ist, obwohl dies nicht der Fall ist?


116

Grundproblem

Ich habe gerade den gesamten Code aus einer Datei in meinem Projekt gelöscht und die Änderung (absichtlich) an meinem lokalen Git übergeben. Ich tat

git pull upstream master

vom Upstream abrufen und zusammenführen (theoretisch sollte der gelöschte Code zurück sein).

Git sagt mir, dass alles auf dem neuesten Stand ist.

Alles ist definitiv NICHT auf dem neuesten Stand - der gesamte gelöschte Code wird immer noch gelöscht.

Sonstige relevante Informationen

Ich habe nur einen Zweig namens "Master".

Ich habe kürzlich "master" eingerichtet, um Upstream wie folgt zu verfolgen:

Zweigstellenmaster eingerichtet, um den Remote-Zweigstellenmaster vom Upstream zu verfolgen.

Der Befehl git branch -vvergibt:

* master 7cfcb29 [upstream/master: ahead 9] deletion test

Warum warum warum passiert das? Ich bin kurz davor, meinem Projektmanager alle Änderungen, die ich an unserem Code vornehme, per E-Mail zu senden.

Aktualisieren

Ich dachte, es wäre offensichtlich, aber das ist trotzdem mein Ziel:

Holen Sie sich den neuesten Code auf meinem System.

Entschuldigen Sie meine Wut hier, aber warum muss eine so einfache Aufgabe so schwer sein?


1
Es ist offensichtlich, dass wenn Sie Ihre Quelle löschen, versuchen Sie, mit einem einfachen "Pull" zu ziehen, dass Git Ihre lokalen Änderungen (in diesem Fall Ihre Löschungen) nicht überschreibt, ohne sicherzustellen, dass Sie Ihre lokalen Änderungen wirklich überschreiben möchten. Die erste Antwort scheint genau zu erklären, wie Sie vorgehen können.
CashCow

Antworten:


208

Ich denke, Ihr grundlegendes Problem hier ist, dass Sie falsch interpretieren und / oder falsch verstehen, was Git macht und warum es es tut.

Wenn Sie ein anderes Repository klonen, erstellt git eine Kopie dessen, was "dort drüben" ist. Es nimmt auch "ihre" Verzweigungsbezeichnungen, wie z. B. master, und erstellt eine Kopie dieser Bezeichnung, deren "vollständiger Name" in Ihrem Git-Baum (normalerweise) lautet remotes/origin/master(aber in Ihrem Fall remotes/upstream/master). Meistens können Sie das remotes/Teil auch weglassen , sodass Sie auf diese Originalkopie als verweisen können upstream/master.

Wenn Sie jetzt Änderungen an Dateien vornehmen und festschreiben, sind Sie der einzige mit diesen Änderungen. In der Zwischenzeit können andere Personen das ursprüngliche Repository (aus dem Sie Ihren Klon erstellt haben) verwenden, um andere Klone zu erstellen und diese Klone zu ändern. Sie sind natürlich die einzigen mit ihren Veränderungen. Möglicherweise hat jemand Änderungen, die er an den ursprünglichen Eigentümer zurücksendet (über "Push" oder Patches oder was auch immer).

Der git pullBefehl ist meistens nur eine Abkürzung für git fetchgefolgt von git merge. Dies ist wichtig, da Sie verstehen müssen, was diese beiden Vorgänge tatsächlich tun.

Der git fetchBefehl besagt, dass Sie dorthin zurückkehren sollen, wo Sie geklont haben (oder sich anderweitig als Abrufort eingerichtet haben) und "neue Inhalte suchen, die von einer anderen Person hinzugefügt, geändert oder entfernt wurden". Diese Änderungen werden kopiert und auf Ihre Kopie dessen angewendet , was Sie zuvor von ihnen erhalten haben . Sie werden nicht auf Ihre eigene Arbeit angewendet, sondern nur auf ihre.

Der git mergeBefehl ist komplizierter und genau dort, wo Sie schief gehen. Was es ein wenig vereinfacht macht, ist, "was Sie in Ihrer Kopie geändert haben" mit "Änderungen zu vergleichen, die Sie von jemand anderem abgerufen und somit zu Ihrer Kopie der Arbeit eines anderen hinzugefügt haben". Wenn Ihre Änderungen und ihre Änderungen nicht in Konflikt zu geraten scheinen, werden sie durch die mergeOperation zusammengeführt und erhalten ein "Merge Commit", das Ihre Entwicklung und ihre Entwicklung miteinander verbindet (obwohl es einen sehr häufigen "einfachen" Fall gibt, in dem Sie keine haben ändert sich und Sie erhalten einen "schnellen Vorlauf").

Die Situation, der Sie jetzt begegnen, ist eine, in der Sie Änderungen vorgenommen und diese festgeschrieben haben - neun Mal, daher die "Voraus 9" - und sie haben keine Änderungen vorgenommen. Also fetchholt pflichtbewusst nichts ab, mergenimmt dann ihren Mangel an Veränderungen und tut auch nichts.

Was Sie wollen, ist, sich "ihre" Version des Codes anzusehen oder vielleicht sogar "zurückzusetzen".

Wenn Sie es sich nur ansehen möchten, können Sie sich einfach diese Version ansehen:

git checkout upstream/master

Das sagt git, dass Sie das aktuelle Verzeichnis in den Zweig verschieben möchten, dessen vollständiger Name tatsächlich lautet remotes/upstream/master. Sie sehen ihren Code ab dem letzten Mal, als Sie ausgeführt haben git fetchund den neuesten Code erhalten haben.

Wenn Sie alle Ihre eigenen Änderungen aufgeben möchten, müssen Sie die Idee von git ändern, welche Revision Ihr Label masterbenennen soll. Derzeit wird Ihr letztes Commit benannt. Wenn Sie zu diesem Zweig zurückkehren:

git checkout master

dann können Sie mit dem git resetBefehl sozusagen "das Etikett verschieben". Das einzige verbleibende Problem (vorausgesetzt, Sie sind wirklich bereit, alles aufzugeben, was Sie nicht tun) besteht darin, herauszufinden, wohin das Etikett zeigen soll.

git logSie können die numerischen Namen finden - solche Dinge wie 7cfcb29-, die permanente (sich nie ändernde) Namen sind, und es gibt eine lächerliche Anzahl anderer Möglichkeiten, sie zu benennen, aber in diesem Fall möchten Sie nur den Namen upstream/master.

Um das Etikett zu verschieben, löschen Sie Ihre eigenen Änderungen (alle Änderungen, die Sie vorgenommen haben, können tatsächlich für eine Weile wiederhergestellt werden, aber danach ist es viel schwieriger. Seien Sie also sehr sicher):

git reset --hard upstream/master

Der --hardgit git soll löschen, was Sie getan haben, die aktuelle Verzweigungsbezeichnung verschieben und dann das angegebene Commit überprüfen.

Es ist nicht üblich, wirklichgit reset --hard eine Menge Arbeit zu wollen und auszulöschen. Eine sicherere Methode (die es viel einfacher macht, diese Arbeit wiederherzustellen, wenn Sie der Meinung sind, dass sich ein Teil davon gelohnt hat) besteht darin, Ihren vorhandenen Zweig umzubenennen:

git branch -m master bunchofhacks

und dann mache einen neuen lokalen Zweig mit dem Namen master"Tracks" (ich mag diesen Begriff nicht wirklich, da ich denke, dass er die Leute verwirrt, aber das ist der Git-Begriff :-)) der Ursprungs- (oder Upstream-) Master:

git branch -t master upstream/master

womit Sie sich dann beschäftigen können:

git checkout master

Die letzten drei Befehle (es gibt Verknüpfungen, mit denen nur zwei Befehle erstellt werden können) ändern den Namen, der auf dem vorhandenen Etikett eingefügt ist, erstellen dann ein neues Etikett und wechseln zu diesem:

bevor Sie etwas tun:

C0 -    "remotes/upstream/master"
    \
     \- C1 --- C2 --- C3 --- C4 --- C5 --- C6 --- C7 --- C8 --- C9    "master"

nachher git branch -m:

C0 -    "remotes/upstream/master"
    \
     \- C1 --- C2 --- C3 --- C4 --- C5 --- C6 --- C7 --- C8 --- C9    "bunchofhacks"

nachher git branch -t master upstream/master:

C0 -    "remotes/upstream/master", "master"
    \
     \- C1 --- C2 --- C3 --- C4 --- C5 --- C6 --- C7 --- C8 --- C9    "bunchofhacks"

Hier C0ist das letzte Commit (ein vollständiger Quellbaum), das Sie erhalten haben, als Sie das erste Mal Ihr Commit ausgeführt haben git clone. C1 bis C9 sind Ihre Commits.

Beachten Sie , dass dies das letzte Bild ändern würde , wenn Sie es git checkout bunchofhacksdann git reset --hard HEAD^^tun würden:

C0 -    "remotes/upstream/master", "master"
    \
     \- C1 --- C2 --- C3 --- C4 --- C5 --- C6 --- C7 -    "bunchofhacks"
                                                      \
                                                       \- C8 --- C9

Der Grund dafür ist, dass HEAD^^die Revision zwei vom Kopf des aktuellen Zweigs (kurz vor dem Zurücksetzen bunchofhacks) nach oben benannt und reset --harddann die Beschriftung verschoben wird. Die Commits C8 und C9 sind jetzt größtenteils unsichtbar (Sie können Dinge wie das Reflog verwenden und git fscksie finden, aber es ist nicht mehr trivial). Ihre Etiketten können Sie bewegen, wie Sie möchten. Der fetchBefehl kümmert sich um diejenigen, die mit beginnen remotes/. Es ist üblich, "Ihre" mit "Ihnen" abzugleichen (wenn sie also einen haben remotes/origin/mauve, würden Sie auch Ihren Namen nennen mauve), aber Sie können "Ihre" eingeben, wann immer Sie Commits benennen / sehen möchten, die Sie "von ihnen" erhalten haben. (Denken Sie daran, dass "ein Commit" ein ganzer Quellbaum ist. Sie können eine bestimmte Datei aus einem Commit auswählen, git showz.


12
Ich habe viel aus Ihrer hervorragenden Antwort gelernt. Aber ich bin immer noch verwirrt darüber, warum ich die Git-Statusmeldung erhalte: "Ihre Filiale ist mit 'origin / master' auf dem neuesten Stand", wenn das Upstream-Repo mehrere Commits vor meinem aktuellen Repo liegt. Ich kann mit git pull auf dem neuesten Stand sein, aber woher weiß ich, dass ich ziehen muss, wenn die Nachricht besagt, dass ich auf dem neuesten Stand bin?
Christopher Werby

@ChristopherWerby: Es hört sich so an, git mergeals würden Sie als Befehlszeilenbefehl ausgeführt (was ich selbst mache, es ist eine vernünftige Methode). Beachten Sie jedoch, dass dies git pullzuerst ausgeführt wird git fetch, dann ausgeführt wird git merge(oder git rebasewenn Sie es stattdessen anweisen). Es ist der Abrufschritt , die tatsächlich bringt über die neuen Commits (oder umbasiert-only) zusammengeführt werden.
Torek

@torek Gibt es einen anderen Befehl als den git status, mit dem ich sehen kann, ob das Upstream-Repo meinem aktuellen Repo voraus ist? Die Nachricht, die ich mit der Meldung git status"Ihre Filiale ist mit 'origin / master' auf dem neuesten Stand" erhalte, verwirrt mich zu der Annahme, dass ich die neuesten Änderungen habe, wenn ich dies nicht tue. Manchmal erhalte ich eine Nachricht mit der Aufschrift "Ursprung / Master ist 5 Commits vor Ihrem Zweig" (Paraphrasierung). Aber es ist nicht konsistent.
Christopher Werby

1
Dies antwortet immer noch nicht, warum git status"Ihr Zweig ist auf dem neuesten Stand" lautet, wenn ein Sofort git fetchüber hundert Objekte herunterzieht und fast hundert Deltas auflöst, mehrere neue Zweige und ein paar neue Tags erwähnt und die Haupt- (Fernbedienung) ändert Tracking) Branch Head Commit - und dann sagt ein anderer Git-Status fröhlich und unaufrichtig immer noch "Ihre Filiale ist auf dem neuesten Stand". Es ist klar, dass viel vom Ursprung kam, aber der Zweig war vorher und nachher "auf dem neuesten Stand des Ursprungs"?
NeilG

1
git pullläuft git fetchzuerst, dann git merge(oder einem anderen zweiten Befehl Ihrer Wahl). Der git fetchSchritt aktualisiert die Erinnerung Ihres Git an den Status ihres Git, indem er seinen Git aufruft und etwas Neues von ihm erhält. Sie git statusüberprüfen nur die Erinnerung Ihres Git an deren Git.
Torek

18

Ich hatte das gleiche Problem wie du.

Ich tat es git status git fetch git pull, aber mein Zweig war immer noch im Rückstand. Ich hatte Ordner und Dateien auf Remote verschoben und ich sah die Dateien im Web, aber auf meinem lokalen fehlten sie.

Schließlich aktualisierten diese Befehle alle Dateien und Ordner auf meinem lokalen:

git fetch --all
git reset --hard origin/master 

oder wenn Sie eine Niederlassung wollen

git checkout your_branch_name_here
git reset --hard origin/your_branch_name_here

1
Vielen Dank! das hat tatsächlich funktioniert. Beachten Sie, dass bei den Filialnamen zwischen Groß- und Kleinschreibung unterschieden wird!
André Ramon

4

Alle Änderungen, die Sie festschreiben, wie das Löschen aller Ihrer Projektdateien, bleiben auch nach einem Pull erhalten. Alles, was Sie tun, ist, die neuesten Änderungen von einem anderen Ort in Ihrem eigenen Zweig zusammenzuführen. Wenn Ihr Zweig alles gelöscht hat, kommt es bestenfalls zu Zusammenführungskonflikten, wenn sich vorgelagerte Änderungen auf von Ihnen gelöschte Dateien auswirken. Kurz gesagt, ja, alles ist auf dem neuesten Stand.

Wenn Sie beschreiben, welches Ergebnis Sie anstelle von "Alle Dateien gelöscht" haben möchten, kann möglicherweise jemand eine geeignete Vorgehensweise vorschlagen.

Aktualisieren:

Holen Sie sich die aktuellste Version des Codes auf meinem System

Was Sie nicht zu verstehen scheinen, ist, dass Sie bereits den neuesten Code haben, der Ihnen gehört. Wenn Sie wirklich die neueste Arbeit eines anderen sehen möchten , die sich in der Hauptniederlassung befindet, gehen Sie einfach wie folgt vor :

git fetch upstream
git checkout upstream/master

Beachten Sie, dass Sie dadurch nicht in der Lage sind, Ihre eigene Arbeit sofort (neu) zu beginnen. Wenn Sie wissen müssen, wie Sie etwas, das Sie getan haben, rückgängig machen oder Änderungen, die Sie oder eine andere Person vorgenommen haben, auf andere Weise rückgängig machen können, geben Sie bitte Details an. Informieren Sie sich auch darüber, wozu die Versionskontrolle dient, da Sie den Grundzweck falsch zu verstehen scheinen.


Ich möchte tatsächlich die neueste Version des Codes eines anderen auf meinem System. Diese beiden Befehle haben dies jedoch nicht getan. Alles was ich bekomme ist "schon am Filialleiter". Der Code in meinen Dateien spiegelt nicht den Code der anderen Person wider.
user1971506

Entschuldigung, hätte sein sollen upstream/master. Meine Antwort wurde aktualisiert.
Ryan Stewart

3

Ziehen Sie, wie auf den anderen Postern angegeben, Änderungen aus dem Upstream in Ihr Repository. Wenn Sie das, was sich in Ihrem Repository befindet, durch das ersetzen möchten, was sich im Upstream befindet, haben Sie mehrere Möglichkeiten. Von der Manschette würde ich mit gehen

git checkout HEAD^1  # Get off your repo's master.. doesn't matter where you go, so just go back one commit
git branch -d master  # Delete your repo's master branch
git checkout -t upstream/master  # Check out upstream's master into a local tracking branch of the same name

1

Die beste Antwort ist in Bezug auf Breite und Tiefe der gegebenen Informationen viel besser, aber es scheint, als ob Sie Ihr Problem fast sofort beheben möchten und es Ihnen nichts ausmacht, auf einige der Grundprinzipien der Versionskontrolle zu treten, Sie könnten ...

  1. Zum Master wechseln

    $ git checkout upstream master
    
  2. Löschen Sie Ihren unerwünschten Zweig. (Hinweis: Es muss das -D anstelle des normalen -d-Flags haben, da Ihr Zweig dem Commit viele Commits voraus ist.)

    $ git branch -d <branch_name>
    
  3. Erstellen Sie einen neuen Zweig

    $ git checkout -b <new_branch_name>
    

0

Während keine dieser Antworten für mich funktionierte, konnte ich das Problem mit dem folgenden Befehl beheben.

git fetch origin

Das hat mir einen Trick getan.


0

Nur eine freundliche Erinnerung, wenn Sie lokal Dateien haben, die nicht in Github sind und doch Ihre git statussagt

Ihre Filiale ist mit 'origin / master' auf dem neuesten Stand. nichts zu begehen, Baum sauber zu arbeiten

Es kann passieren, wenn sich die Dateien in befinden .gitignore

Versuche zu rennen

cat .gitignore 

und zu sehen, ob diese Dateien dort angezeigt werden. Das würde erklären, warum Git sie nicht auf die Fernbedienung verschieben möchte.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.