Kombinieren Sie zwei Branches aus zwei Repos mit disjunkten Inhalten und bewahren Sie den Verlauf in einem einzigen Branch mit Zeitstempel

Lesezeit: 4 Minuten

Ryans Benutzeravatar
Ryan

Ich kenne Git nicht sehr gut. :-/

Hintergrund

Ich habe zwei unabhängige Git-basierte Dokument-Repositorys, die ich zu einem einzigen Repository kombinieren möchte. Ich möchte die ursprünglichen Zeitstempel (aus dem Jahr 2005) und einzelne Dateiverläufe beibehalten. Die beiden Repos enthalten keine Zweige, keine Ordner und es gibt keine Überschneidungen in Bezug auf die Dateibenennung.

Im ASCII-Land sieht das so aus:

REPO A    |-------------------------|
REPO B                    |===============|

Wo die Überlappung die Zeit bezeichnet.

Ziel

Mein Ziel ist es, die überlappenden Zeitstempel zu “verkleinern”, sodass die beiden Repos wie eine einzige, ununterbrochene Geschichte aussehen:

REPO A+B  |-------------------==--=---============|

Was ich versucht habe

Auch hier kenne ich Git nicht sehr gut, also könnte ich etwas vermasselt haben.

Zuerst habe ich versucht, das neuere, kleinere Repo als Remote für das größere, ältere Repo hinzuzufügen, die Änderungen abzurufen und das Ergebnis zu übertragen. Ich endete damit, dass alle neuen Repo-Änderungen in einem Zweig nach dem älteren Repo zusammengefasst wurden:

MERGE  |-------------------------                 -|
                                 \===============/

Als nächstes versuchte ich eine Neubasierung (mit --committer-date-is-author-date), von dem ich dachte, dass es funktionieren würde, aber stattdessen habe ich am Ende einen langen Commit-Verlauf, der die beiden Repos einfach übereinander stapelt.

REBASE |-------------------------===============|

Ich konnte keine Möglichkeit finden, den kombinierten Verlauf “zu wiederholen”. Ich hatte wirklich gehofft, dass Rebase die Antwort sein würde.

Antworten, die ich mir angesehen habe

  • Zwei Git-Repositories zusammenführen, ohne den Dateiverlauf zu beschädigen (#1)
  • Git-Rebase ohne Änderung der Commit-Zeitstempel (Nr. 2 oben, hat die Historien nicht “gezippt”)
  • So kombinieren Sie zwei separate, nicht zusammenhängende Git-Repositories zu einem mit einer einzigen Verlaufszeitachse
  • Kombinieren nicht verwandter Git-Repositories, die Verlauf/Zweige beibehalten

  • Bei Verwendung der verschmelzen Ansatz, git log --date-order zeigt die Commits, geordnet nach ihrer Commit-Zeit, wie Sie es wünschen, und git log --date-order --graph zeigt auch den Zweigbaum.

    – David Pärsson

    9. Juni 2016 um 11:43 Uhr


Obwohl die Antwort von @codeWizard hilfreich war, behielt dieser Ansatz die Zeitstempel nicht so bei, wie ich es wollte. Es hat mich in ein Kaninchenloch geführt, das mir jedoch geholfen hat, eine Lösung zu finden …

  1. Erstellen Sie ein neues, leeres Repository

    git init
    
  2. Fügen Sie die alten Repositorys als Remotes hinzu und rufen Sie sie ab

    git remote add -f oldRepoA ../oldRepoA
    git remote add -f oldRepoB ../oldRepoB
    
  3. Exportieren Sie den kombinierten Commit-Verlauf nach Zeitstempel und Hash und leiten Sie die Ausgabe an weiter sortverwerfen Sie die Zeitstempel über cutund leiten Sie dann die Liste der chronologisch sortierten Hashes an weiter xargsdas ein Shell-Skript ausführt, um einen Patch für jeden einzelnen Hash zu exportieren und den Patch dann sofort auf das neue Repo anzuwenden.

    git log --all --oneline --format="%at %H" | sort | cut -c12- | 
        xargs -I {} sh -c 
            'git format-patch -1 {} --stdout | 
             git am --committer-date-is-author-date'
    

Der --committer-date-is-author-date ist der Schlüssel zur Beibehaltung der ursprünglichen Zeitstempel. Es gibt vielleicht einen besseren Weg, dies zu tun, aber das funktioniert gut genug für meinen Anwendungsfall!

  • Was ist mit dem Vorschlag von @CodeWizard passiert? Jeder Cherry-Pick setzt das Datum des Commit auf die aktuelle Datetime? Ich versuche, etwas Ähnliches wie Sie zu tun, aber die Repositories sind ähnlich, daher weiß ich nicht, ob es funktionieren wird.

    – NobleUplift

    8. August 2016 um 21:54 Uhr


  • Ja, das führt schließlich dazu X: already exists in working directory Patch failed at 0001. Würde dies für ein Repository mit mehreren Zweigen wie z master Und develop?

    – NobleUplift

    9. August 2016 um 14:59 Uhr


Sie müssen ein Skript schreiben, das dies tut.

Wie es geht

  1. erhalten Sie eine Liste aller Ihrer Commits-Zeitstempel pro Zweig

    # print out the commits time stamp & sha-1 of each commit
    # do it for all your branches
    git log --oneline --format="%at %H"
    

    Geben Sie hier die Bildbeschreibung ein

  2. Kombinieren Sie die beiden Listen und sortieren Sie sie mit einem beliebigen Sortierwerkzeug (Sublime, Unix Sort usw.) nach dem Zeitstempel.

  3. Checken Sie den neuen Zweig aus, indem Sie mit dem ersten Commit beginnen, das Sie in Ihren Dateien haben

    git checkout <first commit id>
    

    Geben Sie hier die Bildbeschreibung ein

  4. Erstellen Sie ausgehend von diesem Commit einen neuen Zweig

    git checkout -b <new_branch_name>
    
  5. Schleifen Sie alle anderen Commits und verwenden Sie Cherry-Pick, um sie in Ihren Zweig (Skript) zu bringen.

    git cherry-pick <next commit id>
    

  • Würde dies für zwei Repositories funktionieren, die dieselbe Dateistruktur haben, aber eines ist ein gegabelter Snapshot des anderen zu einem späteren Zeitpunkt? Ich versuche dieses Problem hier anzugehen.

    – NobleUplift

    9. August 2016 um 20:44 Uhr

1445510cookie-checkKombinieren Sie zwei Branches aus zwei Repos mit disjunkten Inhalten und bewahren Sie den Verlauf in einem einzigen Branch mit Zeitstempel

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

Privacy policy