Wie füge ich alten Git-Commits zusätzliche Eltern hinzu?

Lesezeit: 7 Minuten

Benutzer-Avatar
Quuxplusone

Ich habe ein Projekt mit zwei Zweigen: Master- und GH-Seiten. Es handelt sich im Wesentlichen um zwei verschiedene Projekte, wobei das gh-pages-Projekt vom Master-Projekt abhängt (und nicht umgekehrt). Stellen Sie sich vor, “master enthält den Quellcode, gh-pages enthält die aus diesen Quelldateien erstellte Binärdatei”. In regelmäßigen Abständen nehme ich die Änderungen, die sich im Master angesammelt haben, und mache einen neuen Commit zum gh-pages-Zweig mit der Commit-Nachricht „In Übereinstimmung mit Master-Commit xxxxxxxx bringen“.

wie das Netzwerkdiagramm aktuell aussieht

Nach einer Weile wurde mir klar, dass es schön wäre, wenn der gh-pages-Commit „In Einklang mit Master-Commit xxxxxxxx bringen“ tatsächlich xxxxxxxx als Elternteil im Git-Repository hätte. So (schlechte MSPaint-Kunst):

wie es idealerweise aussehen würde

Gibt es eine Möglichkeit, das Repository wie das zweite Bild oben aussehen zu lassen? Ich weiß, wie man neue Commits nach diesem Muster erstellt: Ich kann “git merge -s ours master” (was die Eltern eines ansonsten leeren Commits festlegt) gefolgt von “git commit –amend adv550.z8” (wobei adv550.z8 ist die Binärdatei, die sich tatsächlich ändert). Aber macht es Git einfach, in der Zeit zurückzureisen und alten Commits neue Eltern hinzuzufügen?

Ich bin durchaus bereit, “git push -f” zu verwenden und den aktuellen Verlauf meines Github-Repositorys wegzublasen, sobald mein lokales Repo richtig aussieht. Die Frage ist, kann Ich sehe mein lokales Repo richtig?


BEARBEITET JAHRE SPÄTER, UM HINZUZUFÜGEN: Ich habe schließlich meine Versuche aufgegeben, die Git-Geschichte zu schreiben gh-pages Sieht danach aus; Ich entschied, dass es zu viel Arbeit für null Gewinn war. Meine neue Praxis besteht darin, Commits aggressiv zu quetschen gh-pages, weil das Speichern dieser Commit-Nachrichten in meinem Fall wirklich keine Rolle spielt. (Es ist nur eine lange Reihe von „Mit Master-Commit in Einklang bringen …“, von denen keines historisch interessant ist.) Wenn ich dies jedoch noch einmal tun müsste, würde ich mir die Antworten anhören, die besagten

git merge $intended_parent_1 $intended_parent_2
git checkout $original_commit -- .
git commit --amend -a -C $original_commit

git replace --graft $original_commit \
    $(git show --pretty=%P $original_commit) \
    $additional_parent

Erläuterung:
git replace –graft ermöglicht es, neu anzugeben, welche die Eltern eines bestimmten Commits sind. Dies funktioniert, indem ein neuer Commit mit den entsprechenden Änderungen geschrieben wird und eine Ersetzungsreferenz geschrieben wird, die git veranlasst, bei jedem Zugriff nach dem neuen Commit anstelle des ursprünglichen zu suchen.

git show --pretty=%P $original_commit listet nur die ursprünglichen Eltern auf.

  • Das ist [nearly] die richtige Antwort. Fast, denn ich musste gebrauchen git show --pretty=%P $original_commit | head -n1 – mein Git (2.11.1) hat viel mehr ausgegeben als nur die übergeordnete Zeile.

    – kgadek

    13. Februar 2017 um 1:08 Uhr

  • dies ist eine Nachricht aus der apokalyptischen Zukunft, die besagt, dass Sie beide mein Leben um einiges einfacher gemacht haben und ich Ihnen sehr dankbar bin

    – das richtige Zeug

    24. März 2020 um 17:19 Uhr

  • Verwenden git show --pretty="format:%P" --no-abbrev-commit --no-patch ${original_commit} vermeiden head -n 1

    – Maddes

    31. Dezember 2020 um 1:10 Uhr

  • Beachten Sie, dass auf diese Weise hinzugefügte Eltern nicht auf Github angezeigt werden

    – falscher Benutzername

    10. Januar 2021 um 23:48 Uhr

  • @wrongusername Weißt du, ob es eine Möglichkeit gibt, sie in Github anzuzeigen?

    – Emon

    16. September 2021 um 12:06 Uhr

Benutzer-Avatar
krlmlr

Das sind Ihre Zauberworte:

git merge origin/master --strategy ours

Führen Sie diese in der aus gh-pages Filiale, um die Beziehung zu erfassen master ohne wirklich etwas zu ändern. Dies funktionierte für mich, als ich die erstellte gh-pages Zweig als --orphanwie in dieser Antwort.

Du kannst sogar --amend diesen leeren Merge-Commit hinterher, um die Änderungen einzuführen, die Sie tatsächlich an Ihren “Seiten” vornehmen möchten. Sehen https://github.com/krlmlr/pdlyr/network für ein aktuelles Beispiel auf GitHub.

  • Dies, kombiniert mit Informationen, die der Frage in einer Bearbeitung hinzugefügt wurden (z git commit --amend -a -C ..., etc.) hat sich für mich als nützlich erwiesen. Vielen Dank.

    – Linde

    20. Januar 2016 um 19:45 Uhr

  • Das braucht ein --allow-unrelated-histories -Flag nun funktioniert, da Git seit Git 2.9 standardmäßig nicht mehr zulässt, dass nicht zusammenhängende Historien zusammengeführt werden

    – jitin

    20. April um 8:22 Uhr


Sie können nicht in der Zeit zurückgehen und bestehende Commits ändern. Auch wenn Sie so etwas tun git commit --amend, Sie ändern den Commit nicht wirklich; Sie erstellen an derselben Stelle im Baum ein neues mit dem gesamten Inhalt des Originals (plus Ihren Änderungen). Sie werden feststellen, dass sich der Commit-Hash nach dem ändert --amendund das Original ist immer noch in Ihrem Repo vorhanden – Sie können mit darauf zurückgreifen git reflog.

Andererseits du kann Reise in die Vergangenheit und erschaffe ein alternatives Universum. Im Wesentlichen würden Sie zu Ihrem zurückkehren gh-pages Verzweigungspunkt und erstelle das Ganze neu (mit zB git cherry-pick oder so) als Parallelzweig. Die Hashes würden sich ändern, weil die Commits unterschiedliche Objekte sind.

(Ich bin neugierig, warum Sie Ihr Repo als separate Zweige eingerichtet haben, anstatt als separate Verzeichnisse im selben Zweig. Es scheint, als würde der Code -> Build-Prozess langweilig werden.)

  • “Sie werden feststellen, dass sich der Commit-Hash nach dem –amend ändert”: Aber nur, wenn sich der Inhalt ändert, richtig? Das Ändern der Commit-Log-Nachricht scheint den Hash nicht zu ändern, und ich hoffe, dass das Ändern der Eltern auch nicht der Fall sein wird. “warum separate Branches”: Genau so macht GitHub ihre “GitHub Pages” -Funktion, die ich zum Hosten verwende quuxplusone.github.com/Advent/play-550.html. Sie erstellen einen neuen Zweig mit dem Namen “gh-pages”, und alles, was sich darin befindet, wird automatisch auf die Live-Webseite gespiegelt. Es ist irgendwie seltsam, aber ich denke, es macht unter den Umständen einen gewissen Sinn.

    – Quuxplusone

    30. Mai 2012 um 1:15 Uhr


  • “Im Wesentlichen würden Sie zu Ihrem gh-pages-Verzweigungspunkt zurückkehren und das Ganze neu erstellen”: Ich wäre damit einverstanden. Aber wie erhalte ich die Zeitstempel der ursprünglichen Commits? Ich will sie nicht verlieren. Deshalb habe ich gefragt, wie man in der Zeit zurückgeht.

    – Quuxplusone

    30. Mai 2012 um 1:20 Uhr

  • Ich bekomme einen neuen Hash auch mit a commit --amend -C mit leerem Index.

    – ellotheth

    30. Mai 2012 um 2:16 Uhr

  • Nun, da ich genauer darüber nachdenke, wäre es sinnvoll, wenn Sie nur versuchen, die Herkunftsinformationen beizubehalten, die Idee des Zusammenführens der Eltern zu überspringen und stattdessen Tags zu verwenden? Sie könnten kommentierte Tags auf die werfen gh-pages Zweig mit der master Commit-Eltern für alte Commits und verwenden Sie in Zukunft Ihr Zusammenführungs-/Änderungs-System.

    – ellotheth

    30. Mai 2012 um 2:18 Uhr


  • Der Commit-Hash deckt alles ab, was mit diesem Commit zu tun hat. Der Inhalt, die übergeordnete Referenz, der Kommentar, das Datum/die Uhrzeit. Wenn Sie ein einzelnes Bit in einem Commit ändern, wird ein neuer Hash generiert.

    – Wattwelt

    30. Mai 2012 um 16:03 Uhr

@rumpel hat die richtige Antwort gegeben. Erlauben Sie mir, die Snippets zu teilen, die ich verwende.

Zuerst habe ich orphan erstellt master Zweig:

git checkout --orphan master
git commit --allow-empty -m 'Init'

Mein Anwendungsfall ist etwas anders, die Website, die ich möchte, ist in _site Verzeichnis an develop Zweig. Deshalb mache ich:

git checkout master
git rm -rf .
git read-tree develop^{tree}:_site
git checkout -- .
git commit -m "Update from develop SHA1:$(git rev-parse --short develop) ($(git log -1 --format=%cd develop))"
git replace --graft @ $(git show --pretty=%P @ | head -n1) develop

Beachten Sie, dass ich im letzten Befehl filtern musste | head -n1 seit mein git Ausgabe viel mehr als nur Eltern.

Sie können die Commits neu schreiben, aber es erfordert das Neuschreiben des gesamten Zweigs, beginnend mit dem ersten Commit, das ein zusätzliches übergeordnetes Element benötigt, bis zur Spitze des Zweigs. Es ist (wie bei Rebases) ein neuer Zweig, der nur den gleichen Inhalt hat.

Der Trick besteht darin, den Commit-Baum zu verwenden, der alles übernimmt (Committer/Autor-Informationen, Zeitstempel, Commit-Nachricht, Liste der Eltern), wenn auch auf ziemlich unpraktische Weise. Ein bisschen Scripting erledigt dann den Job.

  • Sie würden positiv bewertet, wenn Ihr zweiter Absatz nicht so bizarr vage wäre.

    – Quuxplusone

    26. Februar 2014 um 4:26 Uhr

  • Ich weiss. Aber es ist ein bisschen Arbeit, und ich brauche dieses Skript jetzt nicht.

    – Andreas Krey

    28. März 2014 um 14:33 Uhr

  • Sie würden positiv bewertet, wenn Ihr zweiter Absatz nicht so bizarr vage wäre.

    – Quuxplusone

    26. Februar 2014 um 4:26 Uhr

  • Ich weiss. Aber es ist ein bisschen Arbeit, und ich brauche dieses Skript jetzt nicht.

    – Andreas Krey

    28. März 2014 um 14:33 Uhr

1017000cookie-checkWie füge ich alten Git-Commits zusätzliche Eltern hinzu?

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

Privacy policy