it-swarm.com.de

Erstellen Sie ein Submodul-Repository aus einem Ordner und behalten Sie dessen Git-Commit-Verlauf bei

Ich habe eine Webanwendung, die andere Webanwendungen auf bestimmte Weise untersucht. Es enthält einige Web-Demos in einem demos -Ordner und eines der Demos sollte nun ein eigenes Repository haben. Ich möchte ein separates Repository für diese Demo-Anwendung erstellen und es zu einem machen unterpaket Submodul aus dem Haupt-Repository, ohne den Commit-Verlauf zu verlieren.

Ist es möglich, den Commit-Verlauf aus den Dateien im Ordner eines Repositorys zu speichern, ein Repository daraus zu erstellen und es stattdessen als Submodul zu verwenden?

94
GabLeRoux

Detaillierte Lösung

Siehe den Hinweis am Ende dieser Antwort (letzter Absatz) für eine schnelle Alternative zu Git-Submodulen mit npm;)

In der folgenden Antwort erfahren Sie, wie Sie einen Ordner aus einem Repository extrahieren, ein Git-Repository daraus erstellen und dann als Submodul anstelle eines Ordners einfügen.

Inspiriert von Gerg Bayers Artikel Verschieben von Dateien von einem Git-Repository in ein anderes, Beibehalten des Verlaufs

Am Anfang haben wir so etwas:

<git repository A>
    someFolders
    someFiles
    someLib <-- we want this to be a new repo and a git submodule!
        some files

In den folgenden Schritten werde ich dieses someLib als <directory 1> Bezeichnen.

Am Ende werden wir so etwas haben:

<git repository A>
    someFolders
    someFiles
    @submodule --> <git repository B>

<git repository B>
    someFolders
    someFiles

Erstellen Sie ein neues Git-Repository aus einem Ordner in einem anderen Repository

Schritt 1

Holen Sie sich eine neue Kopie des zu teilenden Repository.

git clone <git repository A url>
cd <git repository A directory>

Schritt 2

Der aktuelle Ordner ist das neue Repository. Entfernen Sie daher die aktuelle Fernbedienung.

git remote rm Origin

Schritt 3

Extrahieren Sie den Verlauf des gewünschten Ordners und schreiben Sie ihn fest

git filter-branch --subdirectory-filter <directory 1> -- --all

Sie sollten jetzt ein Git-Repository mit den Dateien von directory 1 Im Stammverzeichnis Ihres Repos mit dem gesamten zugehörigen Commit-Verlauf haben.

Schritt 4

Erstellen Sie Ihr Online-Repository und verschieben Sie Ihr neues Repository!

git remote add Origin <git repository B url>
git Push

Möglicherweise müssen Sie den Zweig upstream für Ihren ersten Push festlegen

git Push --set-upstream Origin master

Clean <git repository A> (Optional, siehe Kommentare)

Wir möchten Traces (Dateien und Commit-Verlauf) von <git repository B> Aus <git repository A> Löschen, sodass der Verlauf für diesen Ordner nur einmal vorhanden ist.

Dies basiert auf Entfernen vertraulicher Daten von Github.

Gehe in einen neuen Ordner und

git clone <git repository A url>
cd <git repository A directory>
git filter-branch --force --index-filter 'git rm --cached --ignore-unmatch <directory 1> -r' --Prune-empty --tag-name-filter cat -- --all

Ersetzen Sie <directory 1> Durch den Ordner, den Sie entfernen möchten. -r Macht das rekursiv im angegebenen Verzeichnis :). Nun mit Origin/master Auf --force Drücken

git Push Origin master --force

Boss Stage (siehe Hinweis unten)

Erstellen Sie ein Submodul von <git repository B> In <git repository A>

git submodule add <git repository B url>
git submodule update
git commit

Überprüfen Sie, ob alles wie erwartet funktioniert hat und Push

git Push Origin master

Hinweis

Nachdem ich all dies getan hatte, wurde mir klar, dass es sinnvoller war, npm zu verwenden, um stattdessen meine eigenen Abhängigkeiten zu verwalten. Wir können Git-URLs und Versionen angeben, siehe package.json Git-URLs als Abhängigkeiten .

Wenn Sie dies auf diese Weise tun, muss das Repository, das Sie als Voraussetzung verwenden möchten, ein npm-Modul sein, sodass es einen package.json Enthalten muss. Datei oder Sie erhalten diesen Fehler: Error: ENOENT, open 'tmp.tgz-unpack/package.json'.

tldr (alternative lösung)

Möglicherweise ist es einfacher, npm und Abhängigkeiten mit Git-URLs verwalten zu verwenden:

  • Ordner in ein neues Repository verschieben
  • führen Sie npm init in beiden Repositorys aus
  • führen Sie npm install --save git://github.com/user/project.git#commit-ish aus, wo Ihre Abhängigkeiten installiert werden sollen
165
GabLeRoux

Die Lösung von @GabLeRoux quetscht die Filialen und die damit verbundenen Commits.

Ein einfacher Weg, um all diese zusätzlichen Zweige und Commits zu klonen und zu behalten:

1 - Stellen Sie sicher, dass Sie diesen Git-Alias ​​haben

git config --global alias.clone-branches '! git branch -a | sed -n "/\/HEAD /d; /\/master$/d; /remotes/p;" | xargs -L1 git checkout -t'

2 - Klonen Sie die Fernbedienung, ziehen Sie alle Zweige, ändern Sie die Fernbedienung, filtern Sie Ihr Verzeichnis, drücken Sie

git clone [email protected]:user/existing-repo.git new-repo
cd new-repo
git clone-branches
git remote rm Origin
git remote add Origin [email protected]:user/new-repo.git
git remote -v
git filter-branch --subdirectory-filter my_directory/ -- --all
git Push --all
git Push --tags
6
oodavid

Die GabLeRoux-Lösung funktioniert gut, es sei denn, Sie verwenden git lfs und hat große Dateien unter dem Verzeichnis, das Sie trennen möchten. In diesem Fall bleiben nach Schritt 3 alle großen Dateien Zeigerdateien anstelle von echten Dateien. Ich denke, es liegt wahrscheinlich an der .gitattributes Datei wird im Filterverzweigungsprozess entfernt.

Als ich das erkenne, finde ich, dass die folgende Lösung für mich funktioniert:

cp .gitattributes .git/info/attributes

Kopieren von .gitattributes mit welchem ​​git lfs große dateien nachverfolgen bis .git/ Verzeichnis, um das Löschen zu vermeiden.

Wenn der Filter-Branch fertig ist, vergiss nicht das .gitattributes Wenn Sie immer noch Git LFS für das neue Repository verwenden möchten:

mv .git/info/attributes .gitattributes
git add .gitattributes
git commit -m 'added back .gitattributes'
2
ls.