-
1. Erste Schritte
- 1.1 Über Versionskontrolle
- 1.2 Eine kurze Geschichte von Git
- 1.3 Was ist Git?
- 1.4 Die Kommandozeile
- 1.5 Git installieren
- 1.6 Erstmalige Git-Einrichtung
- 1.7 Hilfe bekommen
- 1.8 Zusammenfassung
-
2. Git Grundlagen
-
3. Git Branching
- 3.1 Branches im Überblick
- 3.2 Grundlegendes Branching und Merging
- 3.3 Branch-Management
- 3.4 Branching-Workflows
- 3.5 Remote-Branches
- 3.6 Rebasing
- 3.7 Zusammenfassung
-
4. Git auf dem Server
- 4.1 Die Protokolle
- 4.2 Git auf einem Server einrichten
- 4.3 Generieren Ihres SSH-Public-Keys
- 4.4 Einrichten des Servers
- 4.5 Git Daemon
- 4.6 Smart HTTP
- 4.7 GitWeb
- 4.8 GitLab
- 4.9 Drittanbieter-Hosting-Optionen
- 4.10 Zusammenfassung
-
5. Verteiltes Git
-
6. GitHub
-
7. Git-Werkzeuge
- 7.1 Revisionsauswahl
- 7.2 Interaktives Staging
- 7.3 Stashing und Bereinigen
- 7.4 Ihre Arbeit signieren
- 7.5 Suchen
- 7.6 Historie umschreiben
- 7.7 Reset entmystifiziert
- 7.8 Fortgeschrittenes Merging
- 7.9 Rerere
- 7.10 Debugging mit Git
- 7.11 Submodule
- 7.12 Bundling
- 7.13 Ersetzen
- 7.14 Credential-Speicher
- 7.15 Zusammenfassung
-
8. Git anpassen
-
9. Git und andere Systeme
- 9.1 Git als Client
- 9.2 Migration zu Git
- 9.3 Zusammenfassung
-
10. Git-Interna
- 10.1 Plumbing und Porcelain
- 10.2 Git-Objekte
- 10.3 Git-Referenzen
- 10.4 Packfiles
- 10.5 Die Refspec
- 10.6 Übertragungsprotokolle
- 10.7 Wartung und Datenwiederherstellung
- 10.8 Umgebungsvariablen
- 10.9 Zusammenfassung
-
Anhang A: Git in anderen Umgebungen
- A1.1 Grafische Oberflächen
- A1.2 Git in Visual Studio
- A1.3 Git in Visual Studio Code
- A1.4 Git in IntelliJ / PyCharm / WebStorm / PhpStorm / RubyMine
- A1.5 Git in Sublime Text
- A1.6 Git in Bash
- A1.7 Git in Zsh
- A1.8 Git in PowerShell
- A1.9 Zusammenfassung
-
Anhang B: Git in Ihre Anwendungen einbetten
- A2.1 Kommandozeilen-Git
- A2.2 Libgit2
- A2.3 JGit
- A2.4 go-git
- A2.5 Dulwich
-
Anhang C: Git-Befehle
- A3.1 Einrichtung und Konfiguration
- A3.2 Projekte abrufen und erstellen
- A3.3 Grundlegendes Snapshotting
- A3.4 Branching und Merging
- A3.5 Projekte teilen und aktualisieren
- A3.6 Inspektion und Vergleich
- A3.7 Debugging
- A3.8 Patching
- A3.9 E-Mail
- A3.10 Externe Systeme
- A3.11 Administration
- A3.12 Plumbing-Befehle
7.11 Git-Tools - Submodule
Submodule
Es kommt häufig vor, dass Sie bei der Arbeit an einem Projekt ein anderes Projekt innerhalb dieses Projekts verwenden müssen. Vielleicht handelt es sich um eine Bibliothek, die von Drittanbietern entwickelt wurde oder die Sie separat entwickeln und in mehreren übergeordneten Projekten verwenden. In diesen Szenarien entsteht ein häufiges Problem: Sie möchten die beiden Projekte als getrennt behandeln und dennoch das eine innerhalb des anderen verwenden können.
Hier ist ein Beispiel. Angenommen, Sie entwickeln eine Website und erstellen Atom-Feeds. Anstatt Ihren eigenen Code zum Generieren von Atom zu schreiben, entscheiden Sie sich für die Verwendung einer Bibliothek. Wahrscheinlich müssen Sie diesen Code entweder aus einer gemeinsam genutzten Bibliothek wie einer CPAN-Installation oder einem Ruby-Gem einbinden oder den Quellcode in Ihren eigenen Projektbaum kopieren. Das Problem bei der Einbindung der Bibliothek besteht darin, dass es schwierig ist, die Bibliothek in irgendeiner Weise anzupassen, und oft noch schwieriger, sie bereitzustellen, da Sie sicherstellen müssen, dass jeder Client diese Bibliothek verfügbar hat. Das Problem beim Kopieren des Codes in Ihr eigenes Projekt besteht darin, dass alle benutzerdefinierten Änderungen, die Sie vornehmen, nur schwer zusammenzuführen sind, wenn Änderungen aus dem Upstream verfügbar werden.
Git löst dieses Problem mithilfe von Submodulen. Mit Submodulen können Sie ein Git-Repository als Unterverzeichnis eines anderen Git-Repositorys beibehalten. Dies ermöglicht es Ihnen, ein anderes Repository in Ihr Projekt zu klonen und Ihre Commits getrennt zu halten.
Erste Schritte mit Submodulen
Wir werden die Entwicklung eines einfachen Projekts durchgehen, das in ein Hauptprojekt und einige Teilprojekte aufgeteilt wurde.
Beginnen wir damit, ein vorhandenes Git-Repository als Submodul des Repositorys hinzuzufügen, an dem wir arbeiten. Um ein neues Submodul hinzuzufügen, verwenden Sie den Befehl git submodule add mit der absoluten oder relativen URL des Projekts, das Sie verfolgen möchten. In diesem Beispiel fügen wir eine Bibliothek namens „DbConnector“ hinzu.
$ git submodule add https://github.com/chaconinc/DbConnector
Cloning into 'DbConnector'...
remote: Counting objects: 11, done.
remote: Compressing objects: 100% (10/10), done.
remote: Total 11 (delta 0), reused 11 (delta 0)
Unpacking objects: 100% (11/11), done.
Checking connectivity... done.
Standardmäßig werden Submodule das Teilprojekt in ein Verzeichnis mit demselben Namen wie das Repository legen, in diesem Fall „DbConnector“. Sie können am Ende des Befehls einen anderen Pfad angeben, wenn er woanders hingehören soll.
Wenn Sie zu diesem Zeitpunkt git status ausführen, werden Sie ein paar Dinge bemerken.
$ git status
On branch master
Your branch is up-to-date with 'origin/master'.
Changes to be committed:
(use "git reset HEAD <file>..." to unstage)
new file: .gitmodules
new file: DbConnector
Zuerst sollten Sie die neue Datei .gitmodules bemerken. Dies ist eine Konfigurationsdatei, die die Zuordnung zwischen der URL des Projekts und dem lokalen Unterverzeichnis speichert, in das Sie es heruntergeladen haben.
[submodule "DbConnector"]
path = DbConnector
url = https://github.com/chaconinc/DbConnector
Wenn Sie mehrere Submodule haben, haben Sie mehrere Einträge in dieser Datei. Es ist wichtig zu beachten, dass diese Datei mit Ihren anderen Dateien versioniert wird, wie Ihre .gitignore-Datei. Sie wird zusammen mit dem Rest Ihres Projekts gepusht und gezogen. Auf diese Weise erfahren andere Personen, die dieses Projekt klonen, woher sie die Submodulprojekte beziehen können.
|
Hinweis
|
Da die URL in der Datei .gitmodules diejenige ist, von der andere Personen zuerst versuchen werden, zu klonen/abzurufen, stellen Sie sicher, dass Sie eine URL verwenden, auf die sie zugreifen können, wenn möglich. Wenn Sie beispielsweise eine andere URL zum Pushen als andere zum Ziehen verwenden, verwenden Sie diejenige, auf die andere Zugriff haben. Sie können diesen Wert lokal mit |
Der andere Eintrag in der git status-Ausgabe ist der Eintrag für den Projektordner. Wenn Sie git diff darauf ausführen, sehen Sie etwas Interessantes
$ git diff --cached DbConnector
diff --git a/DbConnector b/DbConnector
new file mode 160000
index 0000000..c3f01dc
--- /dev/null
+++ b/DbConnector
@@ -0,0 +1 @@
+Subproject commit c3f01dc8862123d317dd46284b05b6892c7b29bc
Obwohl DbConnector ein Unterverzeichnis in Ihrem Arbeitsverzeichnis ist, betrachtet Git es als Submodul und verfolgt seinen Inhalt nicht, wenn Sie sich nicht in diesem Verzeichnis befinden. Stattdessen betrachtet Git es als einen bestimmten Commit aus diesem Repository.
Wenn Sie eine etwas schönere Diff-Ausgabe wünschen, können Sie die Option --submodule an git diff übergeben.
$ git diff --cached --submodule
diff --git a/.gitmodules b/.gitmodules
new file mode 100644
index 0000000..71fc376
--- /dev/null
+++ b/.gitmodules
@@ -0,0 +1,3 @@
+[submodule "DbConnector"]
+ path = DbConnector
+ url = https://github.com/chaconinc/DbConnector
Submodule DbConnector 0000000...c3f01dc (new submodule)
Wenn Sie committen, sehen Sie etwas wie das hier
$ git commit -am 'Add DbConnector module'
[master fb9093c] Add DbConnector module
2 files changed, 4 insertions(+)
create mode 100644 .gitmodules
create mode 160000 DbConnector
Beachten Sie den Modus 160000 für den Eintrag DbConnector. Das ist ein spezieller Modus in Git, der im Grunde bedeutet, dass Sie einen Commit als Verzeihniseintrag statt als Unterverzeichnis oder Datei aufzeichnen.
Zuletzt pushen Sie diese Änderungen
$ git push origin master
Klonen eines Projekts mit Submodulen
Hier klonen wir ein Projekt mit einem Submodul darin. Wenn Sie ein solches Projekt klonen, erhalten Sie standardmäßig die Verzeichnisse, die Submodule enthalten, aber noch keine Dateien darin.
$ git clone https://github.com/chaconinc/MainProject
Cloning into 'MainProject'...
remote: Counting objects: 14, done.
remote: Compressing objects: 100% (13/13), done.
remote: Total 14 (delta 1), reused 13 (delta 0)
Unpacking objects: 100% (14/14), done.
Checking connectivity... done.
$ cd MainProject
$ ls -la
total 16
drwxr-xr-x 9 schacon staff 306 Sep 17 15:21 .
drwxr-xr-x 7 schacon staff 238 Sep 17 15:21 ..
drwxr-xr-x 13 schacon staff 442 Sep 17 15:21 .git
-rw-r--r-- 1 schacon staff 92 Sep 17 15:21 .gitmodules
drwxr-xr-x 2 schacon staff 68 Sep 17 15:21 DbConnector
-rw-r--r-- 1 schacon staff 756 Sep 17 15:21 Makefile
drwxr-xr-x 3 schacon staff 102 Sep 17 15:21 includes
drwxr-xr-x 4 schacon staff 136 Sep 17 15:21 scripts
drwxr-xr-x 4 schacon staff 136 Sep 17 15:21 src
$ cd DbConnector/
$ ls
$
Das Verzeichnis DbConnector ist vorhanden, aber leer. Sie müssen zwei Befehle aus dem Hauptprojekt ausführen: git submodule init, um Ihre lokale Konfigurationsdatei zu initialisieren, und git submodule update, um alle Daten aus diesem Projekt abzurufen und den entsprechenden Commit auszuchecken, der in Ihrem Superprojekt aufgeführt ist.
$ git submodule init
Submodule 'DbConnector' (https://github.com/chaconinc/DbConnector) registered for path 'DbConnector'
$ git submodule update
Cloning into 'DbConnector'...
remote: Counting objects: 11, done.
remote: Compressing objects: 100% (10/10), done.
remote: Total 11 (delta 0), reused 11 (delta 0)
Unpacking objects: 100% (11/11), done.
Checking connectivity... done.
Submodule path 'DbConnector': checked out 'c3f01dc8862123d317dd46284b05b6892c7b29bc'
Jetzt ist Ihr DbConnector-Unterverzeichnis im exakten Zustand, in dem es sich befand, als Sie zuvor committet haben.
Es gibt jedoch noch eine weitere, etwas einfachere Methode, dies zu tun. Wenn Sie --recurse-submodules an den Befehl git clone übergeben, werden alle Submodule im Repository automatisch initialisiert und aktualisiert, einschließlich verschachtelter Submodule, falls eines der Submodule im Repository selbst Submodule hat.
$ git clone --recurse-submodules https://github.com/chaconinc/MainProject
Cloning into 'MainProject'...
remote: Counting objects: 14, done.
remote: Compressing objects: 100% (13/13), done.
remote: Total 14 (delta 1), reused 13 (delta 0)
Unpacking objects: 100% (14/14), done.
Checking connectivity... done.
Submodule 'DbConnector' (https://github.com/chaconinc/DbConnector) registered for path 'DbConnector'
Cloning into 'DbConnector'...
remote: Counting objects: 11, done.
remote: Compressing objects: 100% (10/10), done.
remote: Total 11 (delta 0), reused 11 (delta 0)
Unpacking objects: 100% (11/11), done.
Checking connectivity... done.
Submodule path 'DbConnector': checked out 'c3f01dc8862123d317dd46284b05b6892c7b29bc'
Wenn Sie das Projekt bereits geklont haben und --recurse-submodules vergessen haben, können Sie die Schritte git submodule init und git submodule update kombinieren, indem Sie git submodule update --init ausführen. Um auch verschachtelte Submodule zu initialisieren, abzurufen und auszuchecken, können Sie das narrensichere git submodule update --init --recursive verwenden.
Arbeiten an einem Projekt mit Submodulen
Nun haben wir eine Kopie eines Projekts mit Submodulen darin und werden mit unseren Teamkollegen sowohl am Hauptprojekt als auch am Submodulprojekt zusammenarbeiten.
Abrufen von Upstream-Änderungen vom Submodul-Remote
Das einfachste Modell der Verwendung von Submodulen in einem Projekt wäre, wenn Sie ein Teilprojekt einfach nur konsumieren und von Zeit zu Zeit Updates von ihm erhalten möchten, aber tatsächlich nichts in Ihrem Checkout ändern würden. Gehen wir ein einfaches Beispiel durch.
Wenn Sie nach neuen Arbeiten in einem Submodul suchen möchten, können Sie in das Verzeichnis wechseln und git fetch ausführen und den Upstream-Branch mergen, um den lokalen Code zu aktualisieren.
$ git fetch
From https://github.com/chaconinc/DbConnector
c3f01dc..d0354fc master -> origin/master
$ git merge origin/master
Updating c3f01dc..d0354fc
Fast-forward
scripts/connect.sh | 1 +
src/db.c | 1 +
2 files changed, 2 insertions(+)
Wenn Sie nun zurück ins Hauptprojekt gehen und git diff --submodule ausführen, können Sie sehen, dass das Submodul aktualisiert wurde, und erhalten eine Liste der hinzugefügten Commits. Wenn Sie --submodule nicht jedes Mal eingeben möchten, wenn Sie git diff ausführen, können Sie es als Standardformat festlegen, indem Sie den Konfigurationswert diff.submodule auf „log“ setzen.
$ git config --global diff.submodule log
$ git diff
Submodule DbConnector c3f01dc..d0354fc:
> more efficient db routine
> better connection routine
Wenn Sie zu diesem Zeitpunkt committen, sperren Sie das Submodul mit dem neuen Code, wenn andere Personen aktualisieren.
Es gibt auch eine einfachere Methode, wenn Sie es vorziehen, nicht manuell im Unterverzeichnis abzurufen und zu mergen. Wenn Sie git submodule update --remote ausführen, wechselt Git in Ihre Submodule und ruft für Sie ab und aktualisiert.
$ git submodule update --remote DbConnector
remote: Counting objects: 4, done.
remote: Compressing objects: 100% (2/2), done.
remote: Total 4 (delta 2), reused 4 (delta 2)
Unpacking objects: 100% (4/4), done.
From https://github.com/chaconinc/DbConnector
3f19983..d0354fc master -> origin/master
Submodule path 'DbConnector': checked out 'd0354fc054692d3906c85c3af05ddce39a1c0644'
Dieser Befehl geht standardmäßig davon aus, dass Sie den Checkout auf den Standard-Branch des Remote-Submodul-Repositorys aktualisieren möchten (den, auf den HEAD im Remote zeigt). Sie können dies jedoch auch anders festlegen, wenn Sie möchten. Wenn Sie beispielsweise möchten, dass das DbConnector-Submodul den „stable“-Branch dieses Repositorys verfolgt, können Sie dies entweder in Ihrer .gitmodules-Datei (damit alle anderen ihn ebenfalls verfolgen) oder nur in Ihrer lokalen .git/config-Datei festlegen. Lassen Sie uns es in der .gitmodules-Datei festlegen
$ git config -f .gitmodules submodule.DbConnector.branch stable
$ git submodule update --remote
remote: Counting objects: 4, done.
remote: Compressing objects: 100% (2/2), done.
remote: Total 4 (delta 2), reused 4 (delta 2)
Unpacking objects: 100% (4/4), done.
From https://github.com/chaconinc/DbConnector
27cf5d3..c87d55d stable -> origin/stable
Submodule path 'DbConnector': checked out 'c87d55d4c6d4b05ee34fbc8cb6f7bf4585ae6687'
Wenn Sie -f .gitmodules weglassen, wird die Änderung nur für Sie vorgenommen, aber es ist wahrscheinlich sinnvoller, diese Informationen mit dem Repository zu verfolgen, damit dies auch für alle anderen gilt.
Wenn wir zu diesem Zeitpunkt git status ausführen, zeigt Git uns, dass wir „neue Commits“ im Submodul haben.
$ git status
On branch master
Your branch is up-to-date with 'origin/master'.
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git checkout -- <file>..." to discard changes in working directory)
modified: .gitmodules
modified: DbConnector (new commits)
no changes added to commit (use "git add" and/or "git commit -a")
Wenn Sie die Einstellung status.submodulesummary festlegen, zeigt Git auch eine kurze Zusammenfassung der Änderungen an Ihren Submodulen.
$ git config status.submodulesummary 1
$ git status
On branch master
Your branch is up-to-date with 'origin/master'.
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git checkout -- <file>..." to discard changes in working directory)
modified: .gitmodules
modified: DbConnector (new commits)
Submodules changed but not updated:
* DbConnector c3f01dc...c87d55d (4):
> catch non-null terminated lines
Zu diesem Zeitpunkt, wenn wir git diff ausführen, können wir sehen, dass wir unsere .gitmodules-Datei geändert haben und dass es auch eine Reihe von Commits gibt, die wir heruntergeladen haben und die wir für unser Submodulprojekt committen können.
$ git diff
diff --git a/.gitmodules b/.gitmodules
index 6fc0b3d..fd1cc29 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -1,3 +1,4 @@
[submodule "DbConnector"]
path = DbConnector
url = https://github.com/chaconinc/DbConnector
+ branch = stable
Submodule DbConnector c3f01dc..c87d55d:
> catch non-null terminated lines
> more robust error handling
> more efficient db routine
> better connection routine
Das ist ziemlich cool, da wir tatsächlich das Commit-Log sehen können, das wir in unserem Submodul committen werden. Sobald es committet ist, können Sie diese Informationen auch nachträglich sehen, wenn Sie git log -p ausführen.
$ git log -p --submodule
commit 0a24cfc121a8a3c118e0105ae4ae4c00281cf7ae
Author: Scott Chacon <schacon@gmail.com>
Date: Wed Sep 17 16:37:02 2014 +0200
updating DbConnector for bug fixes
diff --git a/.gitmodules b/.gitmodules
index 6fc0b3d..fd1cc29 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -1,3 +1,4 @@
[submodule "DbConnector"]
path = DbConnector
url = https://github.com/chaconinc/DbConnector
+ branch = stable
Submodule DbConnector c3f01dc..c87d55d:
> catch non-null terminated lines
> more robust error handling
> more efficient db routine
> better connection routine
Git versucht standardmäßig, **alle** Ihre Submodule zu aktualisieren, wenn Sie git submodule update --remote ausführen. Wenn Sie viele davon haben, möchten Sie möglicherweise nur den Namen des Submoduls übergeben, das Sie zu aktualisieren versuchen.
Abrufen von Upstream-Änderungen vom Projekt-Remote
Betreten wir nun die Rolle Ihres Mitarbeiters, der seinen eigenen lokalen Klon des MainProject-Repositorys hat. Einfach git pull auszuführen, um Ihre neu committeten Änderungen zu erhalten, reicht nicht aus.
$ git pull
From https://github.com/chaconinc/MainProject
fb9093c..0a24cfc master -> origin/master
Fetching submodule DbConnector
From https://github.com/chaconinc/DbConnector
c3f01dc..c87d55d stable -> origin/stable
Updating fb9093c..0a24cfc
Fast-forward
.gitmodules | 2 +-
DbConnector | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
$ git status
On branch master
Your branch is up-to-date with 'origin/master'.
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git checkout -- <file>..." to discard changes in working directory)
modified: DbConnector (new commits)
Submodules changed but not updated:
* DbConnector c87d55d...c3f01dc (4):
< catch non-null terminated lines
< more robust error handling
< more efficient db routine
< better connection routine
no changes added to commit (use "git add" and/or "git commit -a")
Standardmäßig ruft der Befehl git pull Submodule rekursiv ab, wie wir in der Ausgabe des ersten obigen Befehls sehen können. Er **aktualisiert** die Submodule jedoch nicht. Dies zeigt die Ausgabe des Befehls git status, der besagt, dass das Submodul „modifiziert“ ist und „neue Commits“ hat. Darüber hinaus zeigen die Klammern, die die neuen Commits anzeigen, nach links (<), was bedeutet, dass diese Commits in MainProject aufgezeichnet sind, aber nicht im lokalen DbConnector-Checkout vorhanden sind. Um die Aktualisierung abzuschließen, müssen Sie git submodule update ausführen.
$ git submodule update --init --recursive
Submodule path 'vendor/plugins/demo': checked out '48679c6302815f6c76f1fe30625d795d9e55fc56'
$ git status
On branch master
Your branch is up-to-date with 'origin/master'.
nothing to commit, working tree clean
Beachten Sie, dass Sie zur Sicherheit git submodule update mit der Option --init ausführen sollten, falls die gerade gezogenen MainProject-Commits neue Submodule hinzugefügt haben, und mit der Option --recursive, falls einige Submodule verschachtelte Submodule haben.
Wenn Sie diesen Prozess automatisieren möchten, können Sie die Option --recurse-submodules zum Befehl git pull hinzufügen (seit Git 2.14). Dadurch wird Git direkt nach dem Pull git submodule update ausführen und die Submodule in den richtigen Zustand versetzen. Darüber hinaus, wenn Sie möchten, dass Git immer mit --recurse-submodules pullen soll, können Sie die Konfigurationsoption submodule.recurse auf true setzen (dies funktioniert für git pull seit Git 2.15). Diese Option veranlasst Git, das Flag --recurse-submodules für alle Befehle zu verwenden, die es unterstützen (außer clone).
Es gibt eine besondere Situation, die beim Abrufen von Superprojekt-Updates auftreten kann: Es könnte sein, dass das Upstream-Repository die URL des Submoduls in der Datei .gitmodules in einem der Commits, die Sie abrufen, geändert hat. Dies kann beispielsweise passieren, wenn das Submodulprojekt seine Hosting-Plattform wechselt. In diesem Fall ist es möglich, dass git pull --recurse-submodules oder git submodule update fehlschlagen, wenn das Superprojekt auf einen Submodul-Commit verweist, der im lokal konfigurierten Submodul-Remote Ihres Repositorys nicht gefunden wird. Um diese Situation zu beheben, ist der Befehl git submodule sync erforderlich.
# copy the new URL to your local config
$ git submodule sync --recursive
# update the submodule from the new URL
$ git submodule update --init --recursive
Arbeiten an einem Submodul
Es ist sehr wahrscheinlich, dass Sie Submodule verwenden, weil Sie wirklich gleichzeitig am Code im Submodul und am Code im Hauptprojekt arbeiten möchten. Andernfalls würden Sie wahrscheinlich stattdessen ein einfacheres Abhängigkeitsverwaltungssystem (wie Maven oder Rubygems) verwenden.
Lassen Sie uns nun ein Beispiel durchgehen, bei dem wir Änderungen am Submodul gleichzeitig mit dem Hauptprojekt vornehmen und diese Änderungen gleichzeitig committen und veröffentlichen.
Bisher hat Git beim Ausführen des Befehls git submodule update, um Änderungen von den Submodul-Repositories abzurufen, die Änderungen abgerufen und die Dateien im Unterverzeichnis aktualisiert, aber das Sub-Repository in einem Zustand namens „detached HEAD“ belassen. Das bedeutet, dass kein lokaler Arbeitsbranch (wie z. B. master) die Änderungen verfolgt. Da kein Arbeitsbranch die Änderungen verfolgt, bedeutet dies, dass selbst wenn Sie Änderungen am Submodul committen, diese Änderungen wahrscheinlich beim nächsten Ausführen von git submodule update verloren gehen. Sie müssen zusätzliche Schritte ausführen, wenn Änderungen in einem Submodul verfolgt werden sollen.
Um Ihr Submodul so einzurichten, dass es einfacher zu bearbeiten ist, müssen Sie zwei Dinge tun. Sie müssen in jedes Submodul wechseln und einen Branch zum Arbeiten auschecken. Dann müssen Sie Git mitteilen, was zu tun ist, wenn Sie Änderungen vorgenommen haben und später git submodule update --remote neue Arbeiten aus dem Upstream abruft. Die Optionen sind, dass Sie sie mit Ihrer lokalen Arbeit zusammenführen oder versuchen können, Ihre lokale Arbeit auf die neuen Änderungen zu rebasen.
Zuerst wechseln wir in unser Submodulverzeichnis und checken einen Branch aus.
$ cd DbConnector/
$ git checkout stable
Switched to branch 'stable'
Lassen Sie uns versuchen, unser Submodul mit der Option „merge“ zu aktualisieren. Um dies manuell anzugeben, können wir einfach die Option --merge zu unserem update-Aufruf hinzufügen. Hier sehen wir, dass es eine Änderung auf dem Server für dieses Submodul gab und sie zusammengeführt wird.
$ cd ..
$ git submodule update --remote --merge
remote: Counting objects: 4, done.
remote: Compressing objects: 100% (2/2), done.
remote: Total 4 (delta 2), reused 4 (delta 2)
Unpacking objects: 100% (4/4), done.
From https://github.com/chaconinc/DbConnector
c87d55d..92c7337 stable -> origin/stable
Updating c87d55d..92c7337
Fast-forward
src/main.c | 1 +
1 file changed, 1 insertion(+)
Submodule path 'DbConnector': merged in '92c7337b30ef9e0893e758dac2459d07362ab5ea'
Wenn wir in das Verzeichnis DbConnector wechseln, haben wir die neuen Änderungen bereits in unseren lokalen stable-Branch eingearbeitet. Sehen wir uns nun an, was passiert, wenn wir unsere eigene lokale Änderung an der Bibliothek vornehmen und jemand anderes gleichzeitig eine weitere Änderung am Upstream pusht.
$ cd DbConnector/
$ vim src/db.c
$ git commit -am 'Unicode support'
[stable f906e16] Unicode support
1 file changed, 1 insertion(+)
Wenn wir nun unser Submodul aktualisieren, können wir sehen, was passiert, wenn wir eine lokale Änderung vorgenommen haben und der Upstream ebenfalls eine Änderung hat, die wir integrieren müssen.
$ cd ..
$ git submodule update --remote --rebase
First, rewinding head to replay your work on top of it...
Applying: Unicode support
Submodule path 'DbConnector': rebased into '5d60ef9bbebf5a0c1c1050f242ceeb54ad58da94'
Wenn Sie --rebase oder --merge vergessen, aktualisiert Git das Submodul nur auf das, was sich auf dem Server befindet, und setzt Ihr Projekt in den Zustand „detached HEAD“ zurück.
$ git submodule update --remote
Submodule path 'DbConnector': checked out '5d60ef9bbebf5a0c1c1050f242ceeb54ad58da94'
Wenn dies passiert, machen Sie sich keine Sorgen, Sie können einfach wieder in das Verzeichnis wechseln und Ihren Branch erneut auschecken (der Ihre Arbeit immer noch enthalten wird) und manuell origin/stable (oder welchen Remote-Branch auch immer Sie möchten) mergen oder rebasen.
Wenn Sie Ihre Änderungen in Ihrem Submodul nicht committet haben und ein submodule update ausführen, das Probleme verursachen würde, ruft Git die Änderungen ab, überschreibt aber keine ungespeicherte Arbeit in Ihrem Submodulverzeichnis.
$ git submodule update --remote
remote: Counting objects: 4, done.
remote: Compressing objects: 100% (3/3), done.
remote: Total 4 (delta 0), reused 4 (delta 0)
Unpacking objects: 100% (4/4), done.
From https://github.com/chaconinc/DbConnector
5d60ef9..c75e92a stable -> origin/stable
error: Your local changes to the following files would be overwritten by checkout:
scripts/setup.sh
Please, commit your changes or stash them before you can switch branches.
Aborting
Unable to checkout 'c75e92a2b3855c9e5b66f915308390d9db204aca' in submodule path 'DbConnector'
Wenn Ihre Änderungen mit etwas kollidieren, das am Upstream geändert wurde, wird Git Sie informieren, wenn Sie das Update ausführen.
$ git submodule update --remote --merge
Auto-merging scripts/setup.sh
CONFLICT (content): Merge conflict in scripts/setup.sh
Recorded preimage for 'scripts/setup.sh'
Automatic merge failed; fix conflicts and then commit the result.
Unable to merge 'c75e92a2b3855c9e5b66f915308390d9db204aca' in submodule path 'DbConnector'
Sie können in das Submodulverzeichnis wechseln und den Konflikt wie gewohnt beheben.
Veröffentlichen von Submoduländerungen
Nun haben wir einige Änderungen in unserem Submodulverzeichnis. Einige davon wurden durch unsere Updates vom Upstream abgerufen, andere wurden lokal vorgenommen und sind noch für niemanden sonst verfügbar, da wir sie noch nicht gepusht haben.
$ git diff
Submodule DbConnector c87d55d..82d2ad3:
> Merge from origin/stable
> Update setup script
> Unicode support
> Remove unnecessary method
> Add new option for conn pooling
Wenn wir im Hauptprojekt committen und es hochpushen, ohne auch die Submoduländerungen hochzupushen, werden Personen, die versuchen, unsere Änderungen auszuchecken, in Schwierigkeiten geraten, da sie keine Möglichkeit haben, die benötigten Submoduländerungen abzurufen. Diese Änderungen existieren nur in unserer lokalen Kopie.
Um sicherzustellen, dass dies nicht passiert, können Sie Git bitten zu überprüfen, ob alle Ihre Submodule ordnungsgemäß gepusht wurden, bevor Sie das Hauptprojekt pushen. Der Befehl git push nimmt das Argument --recurse-submodules entgegen, das entweder auf „check“ oder „on-demand“ gesetzt werden kann. Die Option „check“ bewirkt, dass push einfach fehlschlägt, wenn nicht alle committeten Submoduländerungen gepusht wurden.
$ git push --recurse-submodules=check
The following submodule paths contain changes that can
not be found on any remote:
DbConnector
Please try
git push --recurse-submodules=on-demand
or cd to the path and use
git push
to push them to a remote.
Wie Sie sehen können, gibt er uns auch einige hilfreiche Ratschläge, was wir als Nächstes tun könnten. Die einfache Option besteht darin, in jedes Submodul zu wechseln und manuell zu den Remotes zu pushen, um sicherzustellen, dass sie extern verfügbar sind, und dann diesen Push erneut zu versuchen. Wenn Sie möchten, dass das „check“-Verhalten für alle Pushes erfolgt, können Sie dieses Verhalten zum Standard machen, indem Sie git config push.recurseSubmodules check ausführen.
Die andere Option ist die Verwendung des Wertes „on-demand“, der versucht, dies für Sie zu tun.
$ git push --recurse-submodules=on-demand
Pushing submodule 'DbConnector'
Counting objects: 9, done.
Delta compression using up to 8 threads.
Compressing objects: 100% (8/8), done.
Writing objects: 100% (9/9), 917 bytes | 0 bytes/s, done.
Total 9 (delta 3), reused 0 (delta 0)
To https://github.com/chaconinc/DbConnector
c75e92a..82d2ad3 stable -> stable
Counting objects: 2, done.
Delta compression using up to 8 threads.
Compressing objects: 100% (2/2), done.
Writing objects: 100% (2/2), 266 bytes | 0 bytes/s, done.
Total 2 (delta 1), reused 0 (delta 0)
To https://github.com/chaconinc/MainProject
3d6d338..9a377d1 master -> master
Wie Sie dort sehen können, hat Git das DbConnector-Modul durchlaufen und es gepusht, bevor es das Hauptprojekt gepusht hat. Wenn dieser Submodul-Push aus irgendeinem Grund fehlschlägt, wird auch der Push des Hauptprojekts fehlschlagen. Sie können dieses Verhalten zum Standard machen, indem Sie git config push.recurseSubmodules on-demand ausführen.
Zusammenführen von Submoduländerungen
Wenn Sie eine Submodulreferenz gleichzeitig mit jemand anderem ändern, können einige Probleme auftreten. Das heißt, wenn sich die Submodulhistorien verzweigt haben und in verzweigten Branches in einem Superprojekt committet sind, kann es etwas Arbeit erfordern, um sie zu beheben.
Wenn einer der Commits ein direkter Vorfahre des anderen ist (ein Fast-Forward-Merge), wählt Git einfach den letzteren für den Merge aus, so dass das gut funktioniert.
Git wird jedoch keinen auch nur trivialen Merge für Sie versuchen. Wenn sich die Submodul-Commits verzweigen und zusammengeführt werden müssen, erhalten Sie etwas, das wie folgt aussieht
$ git pull
remote: Counting objects: 2, done.
remote: Compressing objects: 100% (1/1), done.
remote: Total 2 (delta 1), reused 2 (delta 1)
Unpacking objects: 100% (2/2), done.
From https://github.com/chaconinc/MainProject
9a377d1..eb974f8 master -> origin/master
Fetching submodule DbConnector
warning: Failed to merge submodule DbConnector (merge following commits not found)
Auto-merging DbConnector
CONFLICT (submodule): Merge conflict in DbConnector
Automatic merge failed; fix conflicts and then commit the result.
Grundsätzlich ist hier passiert, dass Git festgestellt hat, dass die beiden Branches Punkte in der Historie des Submoduls aufzeichnen, die sich verzweigen und zusammengeführt werden müssen. Es erklärt dies als „merge following commits not found“ (nachfolgende Commits zum Mergen nicht gefunden), was verwirrend ist, aber wir werden erklären, warum das so ist.
Um das Problem zu lösen, müssen Sie herausfinden, in welchem Zustand sich das Submodul befinden soll. Seltsamerweise gibt Git Ihnen nicht viele Informationen zur Hilfe, nicht einmal die SHA-1s der Commits beider Seiten der Historie. Glücklicherweise ist es einfach herauszufinden. Wenn Sie git diff ausführen, erhalten Sie die SHA-1s der Commits, die in beiden Branches aufgezeichnet sind, die Sie zusammenführen wollten.
$ git diff
diff --cc DbConnector
index eb41d76,c771610..0000000
--- a/DbConnector
+++ b/DbConnector
In diesem Fall ist eb41d76 der Commit in unserem Submodul, den **wir** hatten, und c771610 ist der Commit, den der Upstream hatte. Wenn wir in unser Submodulverzeichnis wechseln, sollte es bereits auf eb41d76 stehen, da der Merge es nicht berührt hätte. Wenn es aus irgendeinem Grund nicht der Fall ist, können Sie einfach einen Branch erstellen und ihn auschecken.
Wichtig ist hierbei die SHA-1 des Commits von der anderen Seite. Dies ist das, was Sie zusammenführen und lösen müssen. Sie können entweder versuchen, den Merge direkt mit der SHA-1 durchzuführen, oder Sie können einen Branch dafür erstellen und dann versuchen, diesen zu mergen. Wir würden Letzteres vorschlagen, allein schon, um eine schönere Merge-Commit-Nachricht zu erstellen.
Wir wechseln also in unser Submodulverzeichnis, erstellen einen Branch namens „try-merge“ basierend auf der zweiten SHA-1 aus git diff und führen manuell einen Merge durch.
$ cd DbConnector
$ git rev-parse HEAD
eb41d764bccf88be77aced643c13a7fa86714135
$ git branch try-merge c771610
$ git merge try-merge
Auto-merging src/main.c
CONFLICT (content): Merge conflict in src/main.c
Recorded preimage for 'src/main.c'
Automatic merge failed; fix conflicts and then commit the result.
Wir haben hier einen tatsächlichen Merge-Konflikt, also wenn wir diesen beheben und committen, können wir einfach das Hauptprojekt mit dem Ergebnis aktualisieren.
$ vim src/main.c (1)
$ git add src/main.c
$ git commit -am 'merged our changes'
Recorded resolution for 'src/main.c'.
[master 9fd905e] merged our changes
$ cd .. (2)
$ git diff (3)
diff --cc DbConnector
index eb41d76,c771610..0000000
--- a/DbConnector
+++ b/DbConnector
@@@ -1,1 -1,1 +1,1 @@@
- Subproject commit eb41d764bccf88be77aced643c13a7fa86714135
-Subproject commit c77161012afbbe1f58b5053316ead08f4b7e6d1d
++Subproject commit 9fd905e5d7f45a0d4cbc43d1ee550f16a30e825a
$ git add DbConnector (4)
$ git commit -m "Merge Tom's Changes" (5)
[master 10d2c60] Merge Tom's Changes
-
Zuerst lösen wir den Konflikt.
-
Dann wechseln wir zurück in das Verzeichnis des Hauptprojekts.
-
Wir können die SHA-1s noch einmal überprüfen.
-
Lösen Sie den konfliktreichen Submodul-Eintrag auf.
-
Commiten Sie unseren Merge.
Es kann etwas verwirrend sein, aber es ist eigentlich nicht sehr schwierig.
Interessanterweise gibt es einen weiteren Fall, den Git behandelt. Wenn im Submodulverzeichnis ein Merge-Commit vorhanden ist, der **beide** Commits in seiner Historie enthält, schlägt Git ihn Ihnen als mögliche Lösung vor. Er sieht, dass an einem bestimmten Punkt im Submodulprojekt jemand Branches zusammengeführt hat, die diese beiden Commits enthalten, also möchten Sie vielleicht diesen.
Deshalb lautete die Fehlermeldung von zuvor „merge following commits not found“, weil es **dies** nicht tun konnte. Es ist verwirrend, denn wer würde erwarten, dass es **versucht**, dies zu tun?
Wenn es einen einzelnen akzeptablen Merge-Commit findet, sehen Sie etwas wie das hier
$ git merge origin/master
warning: Failed to merge submodule DbConnector (not fast-forward)
Found a possible merge resolution for the submodule:
9fd905e5d7f45a0d4cbc43d1ee550f16a30e825a: > merged our changes
If this is correct simply add it to the index for example
by using:
git update-index --cacheinfo 160000 9fd905e5d7f45a0d4cbc43d1ee550f16a30e825a "DbConnector"
which will accept this suggestion.
Auto-merging DbConnector
CONFLICT (submodule): Merge conflict in DbConnector
Automatic merge failed; fix conflicts and then commit the result.
Der vorgeschlagene Befehl, den Git bereitstellt, aktualisiert den Index so, als hätten Sie git add ausgeführt (was den Konflikt löst) und committet dann. Dies sollten Sie jedoch wahrscheinlich nicht tun. Sie können genauso gut in das Submodulverzeichnis wechseln, den Unterschied feststellen, zu diesem Commit springen, ihn ordnungsgemäß testen und dann committen.
$ cd DbConnector/
$ git merge 9fd905e
Updating eb41d76..9fd905e
Fast-forward
$ cd ..
$ git add DbConnector
$ git commit -am 'Fast forward to a common submodule child'
Dies erreicht dasselbe, aber auf diese Weise können Sie zumindest überprüfen, ob es funktioniert und Sie die Dateien nach Abschluss in Ihrem Submodulverzeichnis haben.
Submodul-Tipps
Es gibt ein paar Dinge, die Sie tun können, um die Arbeit mit Submodulen etwas einfacher zu gestalten.
Submodule ForEach
Es gibt einen foreach-Befehl für Submodule, um einen beliebigen Befehl in jedem Submodul auszuführen. Dies kann sehr hilfreich sein, wenn Sie mehrere Submodule im selben Projekt haben.
Nehmen wir zum Beispiel an, wir möchten eine neue Funktion starten oder einen Fehler beheben und wir haben Arbeit in mehreren Submodulen. Wir können ganz einfach die gesamte Arbeit in all unseren Submodulen stashen.
$ git submodule foreach 'git stash'
Entering 'CryptoLibrary'
No local changes to save
Entering 'DbConnector'
Saved working directory and index state WIP on stable: 82d2ad3 Merge from origin/stable
HEAD is now at 82d2ad3 Merge from origin/stable
Dann können wir einen neuen Branch erstellen und in all unseren Submodulen zu ihm wechseln.
$ git submodule foreach 'git checkout -b featureA'
Entering 'CryptoLibrary'
Switched to a new branch 'featureA'
Entering 'DbConnector'
Switched to a new branch 'featureA'
Sie verstehen das Prinzip. Eine wirklich nützliche Sache, die Sie tun können, ist, eine schöne einheitliche Diff-Ausgabe dessen zu erstellen, was in Ihrem Hauptprojekt und allen Ihren Teilprojekten geändert wurde.
$ git diff; git submodule foreach 'git diff'
Submodule DbConnector contains modified content
diff --git a/src/main.c b/src/main.c
index 210f1ae..1f0acdc 100644
--- a/src/main.c
+++ b/src/main.c
@@ -245,6 +245,8 @@ static int handle_alias(int *argcp, const char ***argv)
commit_pager_choice();
+ url = url_decode(url_orig);
+
/* build alias_argv */
alias_argv = xmalloc(sizeof(*alias_argv) * (argc + 1));
alias_argv[0] = alias_string + 1;
Entering 'DbConnector'
diff --git a/src/db.c b/src/db.c
index 1aaefb6..5297645 100644
--- a/src/db.c
+++ b/src/db.c
@@ -93,6 +93,11 @@ char *url_decode_mem(const char *url, int len)
return url_decode_internal(&url, len, NULL, &out, 0);
}
+char *url_decode(const char *url)
+{
+ return url_decode_mem(url, strlen(url));
+}
+
char *url_decode_parameter_name(const char **query)
{
struct strbuf out = STRBUF_INIT;
Hier sehen wir, dass wir eine Funktion in einem Submodul definieren und sie im Hauptprojekt aufrufen. Dies ist offensichtlich ein vereinfachtes Beispiel, aber hoffentlich gibt es Ihnen eine Vorstellung davon, wie dies nützlich sein kann.
Nützliche Aliase
Sie möchten vielleicht einige Aliase für einige dieser Befehle einrichten, da sie ziemlich lang sein können und Sie für die meisten keine Konfigurationsoptionen festlegen können, um sie zum Standard zu machen. Wir haben die Einrichtung von Git-Aliassen in Git Aliases behandelt, aber hier ist ein Beispiel dafür, was Sie einrichten möchten, wenn Sie vorhaben, viel mit Submodulen in Git zu arbeiten.
$ git config alias.sdiff '!'"git diff && git submodule foreach 'git diff'"
$ git config alias.spush 'push --recurse-submodules=on-demand'
$ git config alias.supdate 'submodule update --remote --merge'
Auf diese Weise können Sie einfach git supdate ausführen, wenn Sie Ihre Submodule aktualisieren möchten, oder git spush, um mit der Prüfung von Submodulabhängigkeiten zu pushen.
Probleme mit Submodulen
Die Verwendung von Submodulen ist jedoch nicht ohne Schwierigkeiten.
Wechseln von Branches
Zum Beispiel kann das Wechseln von Branches mit Submodulen in Git-Versionen vor Git 2.13 schwierig sein. Wenn Sie einen neuen Branch erstellen, dort ein Submodul hinzufügen und dann zurück zu einem Branch ohne dieses Submodul wechseln, haben Sie das Submodulverzeichnis immer noch als nicht verfolgtes Verzeichnis.
$ git --version
git version 2.12.2
$ git checkout -b add-crypto
Switched to a new branch 'add-crypto'
$ git submodule add https://github.com/chaconinc/CryptoLibrary
Cloning into 'CryptoLibrary'...
...
$ git commit -am 'Add crypto library'
[add-crypto 4445836] Add crypto library
2 files changed, 4 insertions(+)
create mode 160000 CryptoLibrary
$ git checkout master
warning: unable to rmdir CryptoLibrary: Directory not empty
Switched to branch 'master'
Your branch is up-to-date with 'origin/master'.
$ git status
On branch master
Your branch is up-to-date with 'origin/master'.
Untracked files:
(use "git add <file>..." to include in what will be committed)
CryptoLibrary/
nothing added to commit but untracked files present (use "git add" to track)
Das Entfernen des Verzeichnisses ist nicht schwierig, aber es kann etwas verwirrend sein, dass es dort ist. Wenn Sie es entfernen und dann zurück zu dem Branch wechseln, der dieses Submodul hat, müssen Sie submodule update --init ausführen, um es wieder aufzufüllen.
$ git clean -ffdx
Removing CryptoLibrary/
$ git checkout add-crypto
Switched to branch 'add-crypto'
$ ls CryptoLibrary/
$ git submodule update --init
Submodule path 'CryptoLibrary': checked out 'b8dda6aa182ea4464f3f3264b11e0268545172af'
$ ls CryptoLibrary/
Makefile includes scripts src
Auch das ist nicht wirklich sehr schwierig, aber es kann ein wenig verwirrend sein.
Neuere Git-Versionen (Git >= 2.13) vereinfachen dies, indem sie dem Befehl git checkout die Option --recurse-submodules hinzufügen, die dafür sorgt, dass die Submodule für den Branch, zu dem wir wechseln, in den richtigen Zustand versetzt werden.
$ git --version
git version 2.13.3
$ git checkout -b add-crypto
Switched to a new branch 'add-crypto'
$ git submodule add https://github.com/chaconinc/CryptoLibrary
Cloning into 'CryptoLibrary'...
...
$ git commit -am 'Add crypto library'
[add-crypto 4445836] Add crypto library
2 files changed, 4 insertions(+)
create mode 160000 CryptoLibrary
$ git checkout --recurse-submodules master
Switched to branch 'master'
Your branch is up-to-date with 'origin/master'.
$ git status
On branch master
Your branch is up-to-date with 'origin/master'.
nothing to commit, working tree clean
Die Verwendung der Option --recurse-submodules von git checkout kann auch dann nützlich sein, wenn Sie an mehreren Branches im Superprojekt arbeiten, die jeweils Ihr Submodul auf verschiedene Commits verweisen. Tatsächlich wird das Submodul bei der Ausführung von git status als „modifiziert“ angezeigt und „neue Commits“ anzeigen, wenn Sie zwischen Branches wechseln, die das Submodul auf verschiedenen Commits aufzeichnen. Dies liegt daran, dass der Submodulstatus standardmäßig beim Wechseln von Branches nicht übernommen wird.
Dies kann sehr verwirrend sein, daher ist es eine gute Idee, immer git checkout --recurse-submodules auszuführen, wenn Ihr Projekt Submodule enthält. Für ältere Git-Versionen, die die Option --recurse-submodules nicht haben, können Sie nach dem Checkout git submodule update --init --recursive verwenden, um die Submodule in den richtigen Zustand zu versetzen.
Glücklicherweise können Sie Git (>=2.14) mitteilen, immer die Option --recurse-submodules zu verwenden, indem Sie die Konfigurationsoption submodule.recurse einstellen: git config submodule.recurse true. Wie oben erwähnt, wird Git dadurch auch rekursiv in Submodule für jeden Befehl durchlaufen, der eine Option --recurse-submodules hat (außer git clone).
Wechseln von Unterverzeichnissen zu Submodulen
Die andere Haupt-Caveat, auf die viele Leute stoßen, betrifft den Wechsel von Unterverzeichnissen zu Submodulen. Wenn Sie Dateien in Ihrem Projekt verfolgt haben und diese in ein Submodul verschieben möchten, müssen Sie vorsichtig sein, sonst wird Git böse. Angenommen, Sie haben Dateien in einem Unterverzeichnis Ihres Projekts und möchten es in ein Submodul umwandeln. Wenn Sie das Unterverzeichnis löschen und dann submodule add ausführen, schreit Git Sie an.
$ rm -Rf CryptoLibrary/
$ git submodule add https://github.com/chaconinc/CryptoLibrary
'CryptoLibrary' already exists in the index
Sie müssen das Verzeichnis CryptoLibrary zuerst ausstagen. Dann können Sie das Submodul hinzufügen.
$ git rm -r CryptoLibrary
$ git submodule add https://github.com/chaconinc/CryptoLibrary
Cloning into 'CryptoLibrary'...
remote: Counting objects: 11, done.
remote: Compressing objects: 100% (10/10), done.
remote: Total 11 (delta 0), reused 11 (delta 0)
Unpacking objects: 100% (11/11), done.
Checking connectivity... done.
Nehmen wir nun an, Sie haben dies in einem Branch getan. Wenn Sie versuchen, zu einem Branch zurückzuwechseln, in dem sich diese Dateien immer noch im tatsächlichen Baum und nicht in einem Submodul befinden, erhalten Sie diese Fehlermeldung.
$ git checkout master
error: The following untracked working tree files would be overwritten by checkout:
CryptoLibrary/Makefile
CryptoLibrary/includes/crypto.h
...
Please move or remove them before you can switch branches.
Aborting
Sie können es mit checkout -f erzwingen, aber seien Sie vorsichtig, dass Sie keine ungespeicherten Änderungen darin haben, da diese mit diesem Befehl überschrieben werden könnten.
$ git checkout -f master
warning: unable to rmdir CryptoLibrary: Directory not empty
Switched to branch 'master'
Dann, wenn Sie zurückwechseln, erhalten Sie aus irgendeinem Grund ein leeres CryptoLibrary-Verzeichnis und git submodule update behebt es möglicherweise nicht. Sie müssen möglicherweise in Ihr Submodulverzeichnis wechseln und git checkout . ausführen, um alle Ihre Dateien zurückzubekommen. Sie könnten dies in einem submodule foreach-Skript ausführen, um es für mehrere Submodule auszuführen.
Es ist wichtig zu beachten, dass Submodule heutzutage alle ihre Git-Daten im .git-Verzeichnis des Top-Projekts speichern. Im Gegensatz zu viel älteren Git-Versionen gehen beim Zerstören eines Submodulverzeichnisses keine Commits oder Branches verloren, die Sie hatten.
Mit diesen Werkzeugen können Submodule eine ziemlich einfache und effektive Methode sein, um gleichzeitig an mehreren verwandten, aber dennoch getrennten Projekten zu entwickeln.