2013-07-25 13 views
9

Ich frage das nur aus Neugier. Es gibt andere Möglichkeiten, um mit dieser Art von Situation im wirklichen Leben umzugehen, aber ich finde das folgende Verhalten von Git etwas seltsam.Rebasing aus dem Versteck, seltsames Ergebnis

Zusammenfassung: Stashing erstellt, hinter dem Vorhang, zwei Commits, eine enthält den Index und die andere die nicht hinzugefügten Bearbeitungen. Wenn wir Letztere auschecken und versuchen, sie zu rebasen, bekommen wir irgendwie nur die Änderungen aus dem Index. Warum das?

Detaillierte Beispiel folgt:

Lassen Sie uns zunächst ein Repo mit einem machen begehen, dann ein mehr bearbeiten, die zum Index hinzugefügt wird, dann ein mehr bearbeiten, die nicht zu Index hinzugefügt wird, und dann verschwinden lassen:

git init 
echo 1 > a.txt 
git add a.txt 
git commit -m"First commit" 
echo 2 >> a.txt 
git add a.txt 
echo 3 >> a.txt 
git stash 
git log --all --graph --oneline 

    * 5c00fc0 WIP on master: c8af537 First commit 
    |\ 
    | * 965c986 index on master: c8af537 First commit 
    |/ 
    * c8af537 First commit 

So scheint git stash sowohl den Index als auch die nicht hinzugefügte Bearbeitung als commits mit ihren eigenen Hashes (in meinem Fall 965c986 für Index und 5c00fc0 für die nicht hinzugefügten Bearbeitungen) zu speichern.

nun eine neue Datei bearbeiten und begehen:

echo x >> b.txt 
git add b.txt 
git commit -m"Second commit" 

So alle Commits nun wie folgt aussehen:

git log --all --graph --oneline 

    * b589f50 Second commit 
    | * 5c00fc0 WIP on master: c8af537 First commit 
    | |\ 
    |// 
    | * 965c986 index on master: c8af537 First commit 
    |/ 
    * c8af537 First commit 

sagen, dass wir die verstaute Änderungen jetzt nehmen wollen und kombinieren sie mit der zweites Festschreiben. Es gibt auch andere Möglichkeiten, um dies (wie git stash apply, aber was, wenn wir schon die Stash gereinigt hatten, und dann die von der reflog begehen digged) zu tun, aber sie versucht, nur mit:

git checkout 5c00fc0 
[warning message here] 
cat a.txt 
    1 
    2 
    3 
git rebase master 
    First, rewinding head to replay your work on top of it... 
    Applying: index on master: c8af537 First commit 

Aber jetzt, die resultierenden Datei a.txt ist einfach:

cat a.txt 
    1 
    2 

das ist die ganze graph ist:

git log --all --graph --oneline 
    * 5fc3ade index on master: c8af537 First commit 
    * b589f50 Second commit 
    | * 5c00fc0 WIP on master: c8af537 First commit 
    | |\ 
    |// 
    | * 965c986 index on master: c8af537 First commit 
    |/ 
    * c8af537 First commit 

So ist es aussieht, auch wenn wir ausgecheckt commit 5c00fc0, das Fütterungsmaterial nur ap die Änderungen aus dem Commit 965c986, d. h. die Editierungen, die im Index waren, als wir uns versteckten. Aber was auch immer in 5c00fc0 war wurde ignoriert.

Frage: Warum ist das? Gibt es eine vernünftige Erklärung für dieses Verhalten? Oder sollte dies als Fehler angesehen werden?

Antwort

1

Es stellt sich heraus, ignoriert Git nur (standardmäßig) Merge Commits beim Rebasing. Und das Stashing erzeugt das WIP-Commit und das Index-Commit, und das WIP-Commit ist ein Merge, da es sowohl das Index-Commit als auch das c8af537 als Eltern hat.

Nichts mit Verstauen als solches zu tun.

+0

Das erklärt nicht, warum es das Index-Commit ignorieren würde. Bei der Neuzuordnung werden normalerweise die Zusammenführungs-Commits entfernt. Dies bedeutet jedoch nicht, dass der Code, der zusammengeführt wurde, gelöscht wird. – Ilion

+0

Es ignoriert das Index-Commit nicht. –

-1

Massive Bearbeitung meiner ursprünglichen Antwort.

Ich tauchte etwas in den Code und einige Tests von meinen eigenen und ich fand das Problem. Wenn du deinen kopflosen Zweig rebst, machst du einen Master. Der Rebase-Befehl überprüft den Kopf des Zweigs, den Sie zurückbuchen, der in diesem Fall den Stash nicht enthält. Versuchen Sie stattdessen:

git checkout -b stashbranch 5c00fc0 
git rebase stashbranch 
git log --oneline --decorate --all 

Sie sollten wie etwas sehen:

b589f50 (HEAD, refs/stash, stashbranch) Second commit 

Hinweis: Wenn Sie in einem frei stehenden Kopf Zustand sind, aber laufen git rebase master es wird, nach meinen Tests, stellen Sie Ihren Kopf auf die Meisterkopf. Sie hätten git rebase 5c00fc0 machen können und die gleichen Ergebnisse wie bei der Verzweigung erreicht.

+0

Sieht aus wie Sie nicht verstanden haben, dass (oben) die Commits 5c00fc0 und 965c986 durch den Stash-Befehl erstellt werden. –

+0

Ich verstehe das. Sie versuchen immer noch, das normale Verhalten des Stash-Befehls zu umgehen. – Ilion

+0

Ja, der obige Fall ist vielleicht Missbrauch, oder zumindest nicht sehr normal. Aber IMHO ist es nicht intuitiv, dass wenn ich versuche, '5c00fc0' zu rebasen, dann' 5c00fc0' ** nicht ** rebased ist, aber '965c986' ist. In welchem ​​Sinne ist das schützend? Hätte ich '965c986' umbuchen wollen, könnte ich von '965c986' umbuchen, könnte ich nicht. –

0

Ich habe dieses Problem heute morgen durchgelaufen, nachdem ich versehentlich einen Stash in einer GUI-App gelöscht hatte. Am Anfang habe ich versucht, wie andere es zu tun, weil das natürlich ist. Dann habe ich mit duckduckgo gesucht und gefunden, aber keine wirkliche Lösung. Also habe ich versucht, ein bisschen härter und kam mit dieser:

Angenommen, wir haben die folgenden Zweige/Refs:

  • droppedStash bei der künstlichen merge zeigt begehen mit dem gewünschten Inhalt
  • parentOfStash zeigt auf die ursprüngliche Basis für diese Ex-Stash-Zweig

Th en wir einfach tun können:

  1. git Kasse parentOfStash
  2. git cherry-Pick -m 1 droppedStash

Wo -m 1 git sagt einer der Vorfahren zu betrachten Hauptlinie zu sein. Ta da! Genießen Sie :-)

Verwandte Themen