git rebase -i — warum ändert es Commit-Hashes?

Lesezeit: 6 Minuten

Ich bin also mehr oder weniger damit vertraut, wie Rebasing funktioniert, aber bis vor kurzem habe ich normalerweise nur a gemacht git rebase -i HEAD~20und geändert, was geändert werden musste.

Ich war überrascht zu erfahren, dass dies die Hashes aller 20 Commits ändern wird, selbst wenn die einzige Aktion, die ich ergreife, darin besteht, die letzten beiden zu quetschen.

Ich bin mir jedoch nicht sicher, was die Hash-Änderung für die anderen 18 Commits verursacht, da sich weder ihre Eltern noch ihr Inhalt ändern … Oder doch? Vielleicht ein Zeitstempel?

Gibt es auch eine Möglichkeit, das zu verhindern?

  • Mögliches Duplikat von Why does git commit –amend change the hash, selbst wenn ich keine Änderungen vornehme?

    – Jonsharpe

    5. Februar 2018 um 16:18 Uhr

  • TL;DR: Weil Wenn Das Commit ist Teil des Hashs.

    – Jonsharpe

    5. Februar 2018 um 16:18 Uhr

  • Teilweise nur ein Duplikat, da selbst das künstliche Beibehalten des gleichen Zeitstempels die sha1 nicht identisch machen würde (siehe meine Antwort aus anderen Gründen).

    – Matthieu Moy

    5. Februar 2018 um 16:53 Uhr


  • Waren diese Commits bereits gepusht worden?

    – luizfls

    2. Juni 2020 um 21:54 Uhr

  • Nein sie waren nicht

    – Akos Vandra-Meyer

    2. Juni 2020 um 22:09 Uhr

Benutzer-Avatar
Jonathan.Brink

Von dem rebase doc:

Die Commits, die zuvor in den temporären Bereich gespeichert wurden, sind dann erneut auf den aktuellen Zweig angewendeteins nach dem anderen, in der Reihenfolge.

Wenn die Commits “erneut angewendet” werden, wird wirklich ein brandneues Commit erstellt … der Inhalt mag derselbe sein, aber es wird einen anderen Zeitstempel haben Das ist ein Teil davon, wie sein SHA generiert wird … daher werden die neuen Commits einen neuen SHA haben.

Sie können mehr darüber lesen, wie SHAs berechnet werden hier.

  • Dies war die Frage – gibt es eine Möglichkeit, das Ändern des Zeitstempels zu verhindern?

    – Akos Vandra-Meyer

    5. Februar 2018 um 17:37 Uhr


  • Ich glaube nicht, dass es eine Möglichkeit gibt, zu verhindern, dass sich der Commit-Hash ändert, aber eine Möglichkeit, den Zeitstempel eines Commits festzulegen, wird hier gezeigt: stackoverflow.com/a/2179876/2295034

    – Jonathan.Brink

    5. Februar 2018 um 17:40 Uhr

Sie haben vielleicht das Gefühl, dass Sie einige Commits nicht geändert haben, aber Sie haben sie tatsächlich auf verschiedene Weise geändert:

  • Jeder Commit enthält die sha1 seiner Eltern. Wenn Sie also den sha1 eines übergeordneten Elements ändern, wird der Commit geändert, daher sein sha1. Die Hashes sind verkettet, Änderungen in der Vergangenheit ändern die Zukunft. Technisch nennt man das a Merkle-Baum. Dies ist eine wichtige Eigenschaft von Git, denn bei einem sha1 garantiert es nicht nur die Integrität des aktuellen Commits, sondern auch der gesamten Historie, die dazu geführt hat (vorausgesetzt, Sie können in sha1 keine Kollision finden, was heute nicht mehr wirklich der Fall istaber Kollisionen sind immer noch sehr schwer zu finden).

  • Jeder Commit enthält eine Momentaufnahme des aktuellen Status Ihres Projekts. Selbst wenn ein Commit identisch zu sein scheint, weil es denselben Unterschied einführt, entspricht es möglicherweise nicht demselben Zustand des Projekts (demselben Baumobjekt).

  • Wie bereits erwähnt, enthalten Commits Zeitstempel (ein Zeitstempel für den Autor, einer für den Commiter, der zweite wird beim Rebase geändert).

  • Punkt 1: Wenn ich nur die letzten beiden Commits ändere, ändert das nicht den Zustand von HEAD~20..HEAD~3, aber auch nicht ihre Eltern …

    – Akos Vandra-Meyer

    5. Februar 2018 um 17:35 Uhr


  • Punkt 2: Was besteht aus diesem „Zustand“?

    – Akos Vandra-Meyer

    5. Februar 2018 um 17:35 Uhr

  • Punkt 3: Das war die Frage: Gibt es eine Möglichkeit, das Ändern des Zeitstempels des Committers zu deaktivieren?

    – Akos Vandra-Meyer

    5. Februar 2018 um 17:36 Uhr

Benutzer-Avatar
jthill

Dadurch werden die Hashes aller 20 Commits geändert, selbst wenn die einzige Aktion, die ich ergreife, darin besteht, die letzten beiden zu quetschen.

Wenn Sie mit “die letzten beiden” die letzten beiden Commits in der Historie meinen, dann nein, das wird es nicht.

Bitte seien Sie konkret, zeigen Sie die tatsächlichen Beweise, die Sie sich ansehen, die Todo-Liste, die Sie erhalten haben, und die, die Sie ausgeführt haben. Charakterisierungen sind auch weit unzuverlässiganfällig für nicht freigegebenen Kontext.

Hier ist zum Beispiel, was passiert, wenn ich die letzten beiden Commits zerquetsche, wie ich es verstehe:

$ git log --oneline --reverse @{u}..
00f53a2 echo >master6
afcef3e echo >master7
1f55c48 echo >master8
c3197a0 echo >master9
d30bb35 (HEAD -> master) echo >master10
$ GIT_SEQUENCE_EDITOR='sed -i 5s/pick/squash/' git rebase -i
[detached HEAD 16dc80d] echo >master9
 Date: Mon Feb 5 09:25:55 2018 -0800
 2 files changed, 2 insertions(+)
 create mode 100644 master10
 create mode 100644 master9
Successfully rebased and updated refs/heads/master.
$ git log --oneline --reverse @{u}..
00f53a2 echo >master6
afcef3e echo >master7
1f55c48 echo >master8
16dc80d (HEAD -> master) echo >master9
$ 

Sie können sehen, dass die letzten beiden Commits zusammengequetscht wurden, die IDs aller Commits, deren Verlauf sich nicht geändert hat, bleiben unberührt.

  • Das ist die wirklich gute Antwort. Wenn bei einem Commit während einer Rebase keine Aktion ausgeführt wurde, wird der sha1 nur geändert, wenn sich eine Abstammung geändert hat …

    – Philipp

    5. Februar 2018 um 19:10 Uhr

  • Hmm, dann muss es wohl ein Fehler gewesen sein.

    – Akos Vandra-Meyer

    5. Februar 2018 um 21:49 Uhr

  • Ich finde das TBH kaum erhellend und auch nicht reproduzierbar. Das raffinierte (aber sehr obskure) 5s/pick/squash/ bit tut nichts, wenn ich versuche, es zu reproduzieren, zumindest nicht mit git 2.19.2. Ich vermute, dass die Git-Version von @jhill (die er nicht spezifiziert) einige Kommentare ausgibt, die er auf diese Weise überspringt. Ungeachtet dessen denke ich, dass Vandra möglicherweise eine GUI verwendet hat oder so, dass irgendwie winzige Änderungen an den dazwischenliegenden Commits (EOLs? Dateizugriffsberechtigungen?) vorgenommen wurden, die die sich ändernden SHA1s erklären würden.

    – plijnzaad

    26. August 2019 um 16:06 Uhr


Benutzer-Avatar
VonC

Beachten Sie, dass Git vor Git 2.29 (4. Quartal 2020) auch den Hash des Commits ändern konnte, auf den Sie in der rebasieren todo Nachricht, Commit, die sollte nicht ändern (da Sie alte Commits auf diese wiedergeben).

Sehen Commit 5da69c0 (13.08.2020) von Antti Keränen (Detegr).
(Zusammengeführt von Junio ​​C. Hamano — gitster in Commit 4499a4219.08.2020)

rebase -i: Korrigieren Sie möglicherweise falsch auf Hash in todo

Gefunden von: Jussi Keränen
Unterzeichnet von: Antti Keränen
Bestätigt von: Alban Gruin

todo_list_write_to_file‘ kann den statischen Puffer überschreiben, der von ‘ stammtfind_unique_abbrev‘, die verwendet wurde, um den kurzen Commit-Hash zu speichern ‘c‘ zum “# Rebase a..b onto c” Nachricht im Todo-Editor.

Dies liegt daran, dass der Puffer, der von ‘find_unique_abbrev‘ gilt bis zu 4 weiteren Aufrufen find_unique_abbrev werden hergestellt.

Wie ‘todo_list_write_to_file‘ Anrufe ‘find_unique_abbrev‘ für jeden rebasierten Commit den Hash für ‘c‘ wird überschrieben, wenn 4 oder mehr Commits in der Rebase vorhanden sind.
Dieses Verhalten wurde seit seiner Einführung gebrochen.

Beheben Sie das Problem, indem Sie den Short-on-Commit-Hash in einem anderen Puffer speichern, der gültig bleibt, bevor Sie ‘ aufrufentodo_list_write_to_file‘.

Benutzer-Avatar
cptwonton

Dies liegt daran, dass Sie beim interaktiven Rebase des Knotens in HEAD, der 20 Commits vor dem aktuellen liegt, bei dem Knoten in HEAD beginnen, der 20 Commits vor liegt, und die nachfolgenden 20 Commits erneut anwenden, als ob sie neu wären, mit der Option, Änderungen vorzunehmen . Selbst wenn Sie nur Commit -20 und -19 ändern (squash), wenden Sie immer noch die nachfolgenden 18 Commits erneut an, als ob sie neue Commits wären. Sie verwenden nicht denselben Knoten für diese 18 Commits wieder, Sie kopieren ihren Inhalt, hängen aber neue an Ihren rebasierten HEAD an.

Aus dem Git-Buch zum Rebasing:

Denken Sie noch einmal daran, dass dies ein Rebasing-Befehl ist – jeder Commit im Bereich HEAD~3..HEAD wird neu geschrieben, unabhängig davon, ob Sie die Nachricht ändern oder nicht.

1019820cookie-checkgit rebase -i — warum ändert es Commit-Hashes?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy