Unsere Git-Repositories begannen als Teile eines einzelnen Monster-SVN-Repositorys, in dem die einzelnen Projekte jeweils einen eigenen Baum hatten:
project1/branches
/tags
/trunk
project2/branches
/tags
/trunk
Offensichtlich war es ziemlich einfach, Dateien mit einem von einem zum anderen zu verschieben svn mv
. Aber in Git befindet sich jedes Projekt in einem eigenen Repository, und heute wurde ich gebeten, ein Unterverzeichnis von project2
nach zu verschieben project1
. Ich habe so etwas gemacht:
$ git clone project2
$ cd project2
$ git filter-branch --subdirectory-filter deeply/buried/java/source/directory/A -- --all
$ git remote rm origin # so I don't accidentally overwrite the repo ;-)
$ mkdir -p deeply/buried/different/java/source/directory/B
$ for f in *.java; do
> git mv $f deeply/buried/different/java/source/directory/B
> done
$ git commit -m "moved files to new subdirectory"
$ cd ..
$
$ git clone project1
$ cd project1
$ git remote add p2 ../project2
$ git fetch p2
$ git branch p2 remotes/p2/master
$ git merge p2 # --allow-unrelated-histories for git 2.9+
$ git remote rm p2
$ git push
Aber das scheint ziemlich verworren zu sein. Gibt es einen besseren Weg, um so etwas im Allgemeinen zu tun? Oder habe ich den richtigen Ansatz gewählt?
Beachten Sie, dass dies das Zusammenführen des Verlaufs in ein vorhandenes Repository umfasst, anstatt einfach ein neues eigenständiges Repository aus einem Teil eines anderen Repositorys zu erstellen ( wie in einer früheren Frage ).
quelle
git fetch p2 && git merge p2
stattgit fetch p2 && git branch .. && git merge p2
? Bearbeiten: Okay, es sieht so aus, als ob Sie die Änderungen in einem neuen Zweig namens p2 erhalten möchten, nicht in dem aktuellen Zweig.--allow-unrelated-histories
zum Letzten hinzugit merge
, damit es funktioniert.Antworten:
Ja, auf das
--subdirectory-filter
von zu schlagenfilter-branch
war der Schlüssel. Die Tatsache, dass Sie es verwendet haben, beweist im Wesentlichen, dass es keinen einfacheren Weg gibt - Sie hatten keine andere Wahl, als den Verlauf neu zu schreiben, da Sie nur eine (umbenannte) Teilmenge der Dateien haben wollten, und dies ändert per Definition die Hashes. Da keiner der Standardbefehle (z. B.pull
) den Verlauf neu schreibt, können Sie sie auf keinen Fall verwenden, um dies zu erreichen.Sie könnten natürlich die Details verfeinern - ein Teil Ihres Klonens und Verzweigens war nicht unbedingt erforderlich -, aber der Gesamtansatz ist gut! Es ist eine Schande, dass es kompliziert ist, aber es geht natürlich nicht darum, es einfach zu machen, die Geschichte neu zu schreiben.
quelle
--index-filter
in derfilter-branch
Manpage nach.Wenn Ihr Verlauf korrekt ist, können Sie die Commits als Patch entfernen und im neuen Repository anwenden:
Oder in einer Zeile
(Entnommen aus Exherbos Dokumenten )
quelle
git log --pretty=email --patch-with-stat --full-index --binary --reverse -- client > patch
. Funktioniert ohne Probleme AFAICT.--committer-date-is-author-date
Option verwendet, um das ursprüngliche Festschreibungsdatum anstelle des Datums, an dem die Dateien verschoben wurden, beizubehalten.git log
, so dass es nicht mit beiden--follow
und--reverse
korrekt funktioniert ). Ich habe diese Antwort verwendet , und hier ist ein vollständiges Skript, das ich jetzt zum Verschieben von Dateien verwendeNachdem Sie verschiedene Ansätze ausprobiert haben, um eine Datei oder einen Ordner von einem Git-Repository in ein anderes zu verschieben, wird im Folgenden der einzige beschrieben, der zuverlässig zu funktionieren scheint.
Dazu gehört das Klonen des Repositorys, aus dem Sie die Datei oder den Ordner verschieben möchten, das Verschieben dieser Datei oder des Ordners in das Stammverzeichnis, das Umschreiben des Git-Verlaufs, das Klonen des Ziel-Repositorys und das direkte Abrufen der Datei oder des Ordners mit Verlauf in dieses Ziel-Repository.
Bühne eins
Erstellen Sie eine Kopie von Repository A, da die folgenden Schritte wesentliche Änderungen an dieser Kopie vornehmen, die Sie nicht verschieben sollten!
CD hinein
Löschen Sie den Link zum ursprünglichen Repository, um zu vermeiden, dass versehentlich Remote-Änderungen vorgenommen werden (z. B. durch Drücken von).
Durchsuchen Sie Ihren Verlauf und Ihre Dateien und entfernen Sie alles, was sich nicht in Verzeichnis 1 befindet. Das Ergebnis ist der Inhalt von Verzeichnis 1, der in die Basis von Repository A gespuckt wird.
Nur für das Verschieben einzelner Dateien: Gehen Sie die verbleibenden Dateien durch und entfernen Sie alles außer der gewünschten Datei. (Möglicherweise müssen Sie nicht gewünschte Dateien mit demselben Namen löschen und festschreiben.)
Stufe zwei
Bereinigungsschritt
Bereinigungsschritt
Bereinigungsschritt
Möglicherweise möchten Sie diese Dateien in das Repository B in einem Verzeichnis importieren, das sich nicht im Stammverzeichnis befindet:
Machen Sie dieses Verzeichnis
Verschieben Sie Dateien in dieses Verzeichnis
Fügen Sie diesem Verzeichnis Dateien hinzu
Übernehmen Sie Ihre Änderungen und wir sind bereit, diese Dateien in das neue Repository zusammenzuführen
Stufe drei
Erstellen Sie eine Kopie von Repository B, falls Sie noch keine haben
(Angenommen, FOLDER_TO_KEEP ist der Name des neuen Repositorys, in das Sie kopieren.)
CD hinein
Erstellen Sie eine Remoteverbindung zu Repository A als Zweig in Repository B.
Ziehen Sie aus diesem Zweig (der nur das Verzeichnis enthält, das Sie verschieben möchten) in das Repository B.
Der Pull kopiert sowohl Dateien als auch den Verlauf. Hinweis: Sie können eine Zusammenführung anstelle eines Pulls verwenden, aber Pull funktioniert besser.
Schließlich möchten Sie wahrscheinlich ein wenig aufräumen, indem Sie die Remoteverbindung zum Repository A entfernen
Drücken Sie und Sie sind fertig.
quelle
Ich fand das sehr nützlich. Es ist ein sehr einfacher Ansatz, bei dem Sie Patches erstellen, die auf das neue Repo angewendet werden. Weitere Informationen finden Sie auf der verlinkten Seite.
Es enthält nur drei Schritte (aus dem Blog kopiert):
Das einzige Problem, das ich hatte, war, dass ich nicht alle Patches gleichzeitig anwenden konnte
Unter Windows wurde ein InvalidArgument-Fehler angezeigt. Also musste ich alle Patches nacheinander anwenden.
quelle
BEHALTEN DES VERZEICHNISNAMENS
Der Unterverzeichnisfilter (oder der kürzere Befehl git-Teilbaum) funktioniert gut, hat aber bei mir nicht funktioniert, da sie den Verzeichnisnamen aus den Festschreibungsinformationen entfernen. In meinem Szenario möchte ich nur Teile eines Repositorys in ein anderes zusammenführen und den Verlauf MIT dem vollständigen Pfadnamen beibehalten.
Meine Lösung bestand darin, den Baumfilter zu verwenden und einfach die unerwünschten Dateien und Verzeichnisse aus einem temporären Klon des Quell-Repositorys zu entfernen und dann in 5 einfachen Schritten von diesem Klon in mein Ziel-Repository zu ziehen.
quelle
Die, die ich immer benutze, ist hier http://blog.neutrino.es/2012/git-copy-a-file-or-directory-from-another-repository-preserving-history/ . Einfach und schnell.
Um die Stackoverflow-Standards einzuhalten, gehen Sie wie folgt vor:
quelle
Diese Antwort enthält interessante Befehle, die auf
git am
Beispielen basieren und anhand von Beispielen Schritt für Schritt dargestellt werden.Zielsetzung
Verfahren
git log --pretty=email -p --reverse --full-index --binary
git am
1. Extrahieren Sie den Verlauf im E-Mail-Format
Beispiel: Extrahieren Sie den Verlauf von
file3
,file4
undfile5
Reinigen Sie das temporäre Verzeichnis Ziel
Reinigen Sie die Repo- Quelle
Extrahieren Sie den Verlauf jeder Datei im E-Mail-Format
Leider Option
--follow
oder--find-copies-harder
kann nicht mit kombiniert werden--reverse
. Aus diesem Grund wird der Verlauf beim Umbenennen der Datei (oder beim Umbenennen eines übergeordneten Verzeichnisses) abgeschnitten.Nachher: Temporärer Verlauf im E-Mail-Format
2. Reorganisieren Sie den Dateibaum und aktualisieren Sie die Änderung des Dateinamens im Verlauf [optional]
Angenommen, Sie möchten diese drei Dateien in diesem anderen Repo verschieben (kann dasselbe Repo sein).
Organisieren Sie daher Ihre Dateien neu:
Ihre vorübergehende Geschichte ist jetzt:
Ändern Sie auch Dateinamen innerhalb des Verlaufs:
Hinweis: Dadurch wird der Verlauf neu geschrieben, um die Änderung von Pfad und Dateiname widerzuspiegeln.
(dh die Änderung des neuen Ortes / Namens innerhalb des neuen Repos)
3. Wenden Sie einen neuen Verlauf an
Dein anderes Repo ist:
Übernehmen Sie Commits aus temporären Verlaufsdateien:
Dein anderes Repo ist jetzt:
Verwenden Sie
git status
diese Option, um die Anzahl der Commits anzuzeigen, die zum Pushing bereit sind :-)Hinweis: Da der Verlauf neu geschrieben wurde, um die Änderung von Pfad und Dateiname widerzuspiegeln:
(dh verglichen mit dem Ort / Namen im vorherigen Repo)
git mv
den Speicherort / Dateinamen nicht ändern.git log --follow
den vollständigen Verlauf zugreifen.Zusätzlicher Trick: Erkennen Sie umbenannte / verschobene Dateien in Ihrem Repo
So listen Sie die umbenannten Dateien auf:
Weitere Anpassungen: Sie können den Befehl
git log
mit den Optionen--find-copies-harder
oder ausführen--reverse
. Sie können die ersten beiden Spalten auch mitcut -f3-
dem vollständigen Muster '{. * =>. *}' Entfernen und erfassen.quelle
Dieses Skript hatte einen ähnlichen Juckreiz (obwohl nur für einige Dateien eines bestimmten Repositorys) und erwies sich als sehr hilfreich: Git-Import
Die Kurzversion besteht darin, dass Patch-Dateien der angegebenen Datei oder des angegebenen Verzeichnisses (
$object
) aus dem vorhandenen Repository erstellt werden:die dann auf ein neues Repository angewendet werden:
Für Details schauen Sie bitte nach:
quelle
Versuche dies
cd repo1
Dadurch werden alle Verzeichnisse außer den genannten entfernt, und der Verlauf wird nur für diese Verzeichnisse beibehalten
Jetzt können Sie Ihr neues Repo in Ihre Git-Fernbedienung einfügen und darauf verschieben
-f
zum Überschreiben hinzufügenquelle
Unter Inspiration von http://blog.neutrino.es/2012/git-copy-a-file-or-directory-from-another-repository-preserving-history/ habe ich diese Powershell-Funktion erstellt, um dasselbe zu tun hat bisher großartig für mich funktioniert:
Verwendung für dieses Beispiel:
Nachdem Sie dies getan haben, können Sie die Dateien in der
migrate-from-project2
Verzweigung neu organisieren, bevor Sie sie zusammenführen.quelle
Ich wollte etwas Robustes und Wiederverwendbares (One-Command-and-Go + Undo-Funktion), also schrieb ich das folgende Bash-Skript. Ich habe mehrmals für mich gearbeitet, also dachte ich, ich würde es hier teilen.
Es ist möglich, einen beliebigen Ordner
/path/to/foo
vonrepo1
in/some/other/folder/bar
nach zu verschiebenrepo2
(Ordnerpfade können gleich oder unterschiedlich sein, der Abstand zum Stammordner kann unterschiedlich sein).Da nur die Commits durchlaufen werden, die die Dateien im Eingabeordner berühren (nicht alle Commits des Quell-Repos), sollte es auch bei großen Quell-Repos recht schnell sein, wenn Sie nur einen tief verschachtelten Unterordner extrahieren, der nicht in jedem Ordner berührt wurde verpflichten.
Da dies dazu führt, dass ein verwaister Zweig mit dem gesamten Verlauf des alten Repos erstellt und dann mit dem HEAD zusammengeführt wird, funktioniert dies sogar bei Dateinamenkonflikten (dann müssten Sie am Ende natürlich eine Zusammenführung auflösen). .
Wenn keine Dateinamenkonflikte auftreten, müssen Sie nur
git commit
am Ende die Zusammenführung abschließen.Der Nachteil ist, dass es wahrscheinlich nicht nach dem Umbenennen von Dateien (außerhalb von
REWRITE_FROM
Ordners) im Quell-Repo - Pull-Anfragen, die auf GitHub willkommen sind, um dies zu berücksichtigen.GitHub-Link: Git-Move-Ordner-zwischen-Repos-Keep-Verlauf
quelle
In meinem Fall musste ich das Repo, aus dem ich migriert habe, nicht beibehalten oder einen früheren Verlauf beibehalten. Ich hatte einen Patch des gleichen Zweigs von einer anderen Fernbedienung
In diesen beiden Schritten konnte ich den Zweig des anderen Repos im selben Repo anzeigen lassen.
Schließlich habe ich diesen Zweig (den ich aus dem anderen Repo importiert habe) so eingestellt, dass er der Hauptlinie des Ziel-Repos folgt (damit ich sie genau unterscheiden kann).
Jetzt verhielt es sich so, als wäre es nur ein weiterer Zweig, den ich gegen dasselbe Repo gedrückt hatte.
quelle
Wenn die Pfade für die betreffenden Dateien in den beiden Repos identisch sind und Sie nur eine Datei oder einen kleinen Satz verwandter Dateien übertragen möchten, können Sie dies auf einfache Weise verwenden
git cherry-pick
.Der erste Schritt besteht darin, die Commits aus dem anderen Repo mit in Ihr eigenes lokales Repo zu bringen
git fetch <remote-url>
. Dadurch wirdFETCH_HEAD
auf das Head Commit des anderen Repos verwiesen. Wenn Sie einen Verweis auf dieses Commit beibehalten möchten, nachdem Sie andere Abrufe durchgeführt haben, möchten Sie ihn möglicherweise mit einem Tag versehengit tag other-head FETCH_HEAD
.Sie müssen dann ein erstes Commit für diese Datei erstellen (falls nicht vorhanden) oder ein Commit, um die Datei in einen Zustand zu versetzen, der mit dem ersten Commit des anderen Repos, das Sie einbringen möchten, gepatcht werden kann Sie können dies mit einem tun,
git cherry-pick <commit-0>
wenncommit-0
die gewünschten Dateien eingeführt wurden, oder Sie müssen das Commit möglicherweise "von Hand" erstellen. Fügen Sie-n
die Cherry-Pick-Optionen hinzu, wenn Sie das anfängliche Commit ändern müssen, um beispielsweise Dateien aus diesem Commit zu löschen, die Sie nicht einbringen möchten.Danach können Sie mit
git cherry-pick
nachfolgenden Commits fortfahren und diese-n
bei Bedarf erneut verwenden . Im einfachsten Fall (alle Commits sind genau das, was Sie wollen und sauber anwenden) können Sie die vollständige Liste der Commits in der Cherry-Pick-Befehlszeile angeben :git cherry-pick <commit-1> <commit-2> <commit-3> ...
.quelle
Dies wird durch die Verwendung von Git-Filter-Repo einfacher.
Um zu bewegen
project2/sub/dir
zuproject1/sub/dir
:So installieren Sie das Tool einfach:
pip3 install git-filter-repo
( Weitere Details und Optionen in README )quelle
Die folgende Methode zum Migrieren meines GIT-Stashs zu GitLab durch Verwalten aller Zweige und Beibehalten des Verlaufs.
Klonen Sie das alte Repository auf lokal.
Erstellen Sie ein leeres Repository in GitLab.
Das obige habe ich durchgeführt, als wir unseren Code von Stash auf GitLab migriert haben und es hat sehr gut funktioniert.
quelle