Git Rebase ohne Änderung der Commit-Zeitstempel

157

Wäre es sinnvoll, git rebaseunter Beibehaltung der Commit-Zeitstempel eine Leistung zu erbringen?

Ich glaube, eine Konsequenz wäre, dass die neue Niederlassung nicht unbedingt chronologisch festgeschriebene Daten haben wird. Ist das theoretisch überhaupt möglich? (zB mit Sanitärbefehlen; hier nur neugierig)

Wenn es theoretisch möglich ist, ist es dann in der Praxis mit Rebase möglich, die Zeitstempel nicht zu ändern?

Angenommen, ich habe den folgenden Baum:

master <jun 2010>
  |
  :
  :
  :     oldbranch <feb 1984>
  :     /
oldcommit <jan 1984>

Wenn ich jetzt auf oldbranchBasis mastervon Commit bin, ändert sich das Datum des Commits von Februar 1984 bis Juni 2010. Ist es möglich, dieses Verhalten so zu ändern, dass der Commit-Zeitstempel nicht geändert wird? Am Ende würde ich also erhalten:

      oldbranch <feb 1984>
      /
 master <jun 2010>
    |
    :

Wäre das überhaupt sinnvoll? Ist es in git überhaupt erlaubt, eine Historie zu haben, in der ein altes Commit ein neueres Commit als Elternteil hat?

Olivier Verdier
quelle
3
Es ist irre, dass die Antwort auf die Frage in der Tat lautet "Sie müssen nichts tun - so funktioniert es standardmäßig". Angenommen, Sie möchten, dass das Commit während der Rebase in der richtigen Datumsreihenfolge sortiert wird (was ein ziemlich natürliches Szenario ist, wenn Sie darüber nachdenken). Jetzt konnte ich nicht herausfinden, wie ich das erreichen konnte, und veröffentlichte mein q als stackoverflow.com/questions/12270357/really-flatten-a-git-merge
pfalcon
1
David erwähnt eine weitere Option zum Zurücksetzen des Committer-Datums : git rebase --committer-date-is-author-date SHA. Siehe meine bearbeitete Antwort unten
VonC
Ich habe gerade eine ausführliche Antwort auf eine ähnliche Frage geschrieben, deren Autor die hier erläuterten Antworten ausprobiert hat und sie nicht zufriedenstellend anwenden konnte.
Axiac

Antworten:

149

Update Juni 2014: David Fraser erwähnt in den Kommentaren eine Lösung, die ebenfalls unter " Ändern von Zeitstempeln beim erneuten Basieren des Git-Zweigs " unter Verwendung der Option --committer-date-is-author-date(ursprünglich im Januar 2009 in Commit 3f01ad6 eingeführt) aufgeführt ist

Beachten Sie, dass die --committer-date-is-author-dateOption den Autorenzeitstempel zu belassen scheint und den Committer-Zeitstempel auf den ursprünglichen Autorenzeitstempel einstellt, was der OP Olivier Verdier wollte.

Ich habe das letzte Commit mit dem richtigen Datum gefunden und Folgendes getan:

git rebase --committer-date-is-author-date SHA

Siehe git am:

--committer-date-is-author-date

Standardmäßig zeichnet der Befehl das Datum aus der E-Mail-Nachricht als Datum des Festschreibungsautors auf und verwendet den Zeitpunkt der Festschreibungserstellung als Festschreibungsdatum.
Auf diese Weise kann der Benutzer über das Committer-Datum lügen, indem er denselben Wert wie das Autorendatum verwendet .


(Ursprüngliche Antwort, Juni 2012)

Sie könnten versuchen, eine nicht interaktive Basis zu erstellen

git rebase --ignore-date

(aus dieser SO Antwort )

Dies wird weitergegeben an git am, in dem Folgendes erwähnt wird:

 --ignore-date

Standardmäßig zeichnet der Befehl das Datum aus der E-Mail-Nachricht als Datum des Festschreibungsautors auf und verwendet den Zeitpunkt der Festschreibungserstellung als Festschreibungsdatum.
Auf diese Weise kann der Benutzer über das Autorendatum lügen, indem er denselben Wert wie das Committer-Datum verwendet.

Für git rebase, ist diese Option „Nicht kompatibel mit der --interactive Option.“

Da Sie den Zeitstempel des alten Festschreibungsdatums (mit git filter-branch) nach Belieben ändern können, können Sie Ihren Git-Verlauf vermutlich in der gewünschten / benötigten Reihenfolge des Festschreibungsdatums organisieren und sogar auf die Zukunft einstellen! .


Wie Olivier in seiner Frage erwähnt, wird das Autorendatum niemals durch eine Rebase geändert.
Aus dem Pro Git Book :

  • Der Autor ist die Person, die das Werk ursprünglich geschrieben hat.
  • Der Auftraggeber ist die Person, die die Arbeit zuletzt angewendet hat.

Wenn Sie also einen Patch an ein Projekt senden und eines der Kernmitglieder den Patch anwendet, erhalten Sie beide eine Gutschrift.

Um es in diesem Fall besonders deutlich zu machen, wie Olivier kommentiert:

Das --ignore-datemacht das Gegenteil von dem, was ich erreichen wollte !
Es löscht nämlich den Zeitstempel des Autors und ersetzt ihn durch die Commit-Zeitstempel!
Die richtige Antwort auf meine Frage lautet also:
Tun Sie nichts, da git rebase sich die Zeitstempel der Autoren standardmäßig nicht ändern.


VonC
quelle
1
Interessant über die willkürlichen Termine zu begehen. Funktioniert jedoch git rebase --ignore-datenicht. Es ändert die Daten der neu basierten Commits.
Olivier Verdier
@Olivier: seltsam: hast du eine nicht interaktive Rebase gemacht? Und werden wir zwischen dem Autorendatum und dem Committer-Datum sicher das "richtige" Datum überwachen?
VonC
1
Dank VonC, dem Unterschied zwischen Autoren- und Committer-Zeitstempel, wird alles plötzlich klar. Ich habe die Antwort auf meine Frage in meinem Beitrag geschrieben, kann Ihre Antwort jedoch gerne anpassen, um dies widerzuspiegeln.
Olivier Verdier
4
genauer gesagt: das --ignore-datemacht das Gegenteil von dem, was ich erreichen wollte! Es löscht nämlich den Zeitstempel des Autors und ersetzt ihn durch die Commit-Zeitstempel! Die richtige Antwort auf meine Frage lautet also: Tu nichts, da git rebasesich die Zeitstempel der Autoren standardmäßig nicht ändern.
Olivier Verdier
5
Beachten Sie, dass die --committer-date-is-author-dateOption den Autorenzeitstempel zu verlassen scheint und den Committer-Zeitstempel auf den ursprünglichen Autorenzeitstempel einstellt, was Olivier wollte ...
David Fraser
118

Wenn Sie die Festschreibungsdaten bereits verkorkst haben (möglicherweise mit einer Rebase) und sie auf die entsprechenden Autorendaten zurücksetzen möchten, können Sie Folgendes ausführen:

git filter-branch --env-filter 'GIT_COMMITTER_DATE=$GIT_AUTHOR_DATE; export GIT_COMMITTER_DATE'

Andy
quelle
1
Ich habe es gerade versucht, aber keine Wirkung. Ich habe die folgende Ausgabe erhalten : WARNING: Ref 'refs/heads/master' is unchanged. Ich benutze Git Version 1.7.9.5 unter Linux (64 Bit)
Markus N.
20
Ich möchte einen weiteren Ansatz hinzufügen, wenn Sie es bereits vermasselt haben, aber nicht den gesamten Verlauf durchlaufen möchten: Auf git rebase --committer-date-is-author-date <base_branch> diese Weise setzt git das Festschreibungsdatum nur für die auf <base_branch> angewendeten Festschreibungen zurück (was wahrscheinlich der ist der gleiche Filialname, den Sie verwendet haben, als Sie es vermasselt haben).
Speakman
Die akzeptierte Antwort hat 2016 nicht funktioniert, aber die Antwort von @ speakman hat funktioniert!
Theodore R. Smith
2
Die Antwort von @ speakman hat im Oktober 2016 nicht funktioniert, aber die von Andy!
Amedee Van Gasse
2
Dies funktioniert nicht unter Windows. Ich konnte es mit Windows Bash zum Laufen bringen.
Vaindil
33

Eine entscheidende Frage von Von C hat mir geholfen zu verstehen, was los ist: Wenn Sie Ihre Basis neu festlegen, ändert sich der Zeitstempel des Committers , nicht jedoch der Zeitstempel des Autors , was plötzlich alles Sinn macht. Meine Frage war also eigentlich nicht präzise genug.

Die Antwort ist, dass Rebase die Zeitstempel des Autors nicht ändert (dafür müssen Sie nichts tun), was perfekt zu mir passt.

Olivier Verdier
quelle
3
+1 - Ich habe einen Git-Alias ​​( coderwall.com/p/euwpig/a-better-git-log ), der anscheinend den Zeitstempel des Committers verwendet, was mich verwirrte. Gitk und Git Log zeigen beide den Zeitstempel des Autors.
1615903
15

Standardmäßig setzt git rebase den Zeitstempel des Committers auf den Zeitpunkt, zu dem das neue Commit erstellt wird, behält jedoch den Zeitstempel des Autors bei. Meistens ist dies das gewünschte Verhalten, aber in einigen Szenarien möchten wir auch den Zeitstempel des Commiters nicht ändern. Wie können wir das erreichen? Nun, hier ist der Trick, den ich normalerweise mache.

Stellen Sie zunächst sicher, dass jedes Commit, das Sie neu erstellen möchten, eine eindeutige Commit-Nachricht und einen Zeitstempel für den Autor enthält (hier muss der Trick verbessert werden, derzeit entspricht er jedoch meinen Anforderungen).

Notieren Sie vor dem Rebase den Zeitstempel des Committers, den Zeitstempel des Autors und die Commit-Nachricht aller Commits, die in eine Datei zurückgesetzt werden.

#NOTE: BASE is the commit where your rebase begins
git log --pretty='%ct %at %s' BASE..HEAD > hashlog

Lassen Sie dann die eigentliche Rebase stattfinden.

Schließlich ersetzen wir den Zeitstempel des aktuellen Committers durch den in der Datei aufgezeichneten, wenn die Commit-Nachricht mit identisch ist git filter-branch.

 git filter-branch --env-filter '__date=$(__log=$(git log -1 --pretty="%at %s" $GIT_COMMIT); grep -m 1 "$__log" ../../hashlog | cut -d" " -f1); test -n "$__date" && export GIT_COMMITTER_DATE=$__date || cat'

Wenn etwas schief geht, einfach auschecken git reflogoder alle refs/original/Refs.

Darüber hinaus können Sie das Gleiche wie mit dem Zeitstempel des Autors tun.

Wenn beispielsweise der Zeitstempel des Autors für einige Commits nicht in der richtigen Reihenfolge ist und diese Commits nicht neu angeordnet werden sollen, soll der Zeitstempel des Autors nur in der richtigen Reihenfolge angezeigt werden. Die folgenden Befehle helfen dabei.

git log --pretty='%at %s' COMMIT1..COMMIT2 > hashlog
join -1 1 -2 1 <(cat hashlog | cut -f 1 | sort -nr | awk '{ print NR" "$1 }') <(cat hashlog | awk '{ print NR" "$0 }') | cut -d" " -f2,4- > hashlog_
mv hashlog_ hashlog
git filter-branch --env-filter '__date=$(__log=$(git log -1 --pretty="%s" $GIT_COMMIT); grep -m 1 "$__log" ../../hashlog | cut -d" " -f1); test -n "$__date" && export GIT_AUTHOR_DATE=$__date || cat'
weynhamz
quelle
Das ist ein toller Trick! Es erlaubte mir, nur 75 Commits anstatt 1100+ neu zu schreiben, wenn ich die anderen Antworten verwendete.
Audun
Das ist fantastisch! Gibt es eine Möglichkeit, das Skript so zu ändern, dass auch der ursprüngliche Committer erhalten bleibt?
David DeMar
@DavidDeMar sollte genauso sein, ändern Sie einfach das Git-Protokoll --pretty, um die ursprüngliche E-Mail aufzuzeichnen, und ändern Sie das Skript entsprechend.
Weynhamz