Submodule unter Git nutzen

Manchmal möchte man Git-Repository in einer bestimmten Art strukturieren. So will man unter Umständen mehrere Repositories logisch zu einem Repository gesellen. Dafür gibt es unter Git Submodule. Gegeben sei folgende Repositorystruktur:

Framework
Library1
Library2
Library3

Möchte man die Bibliotheken Library1, Library2 und Library3 logisch in das Repository Framework einbinden, kann man die Submodule nutzen. Dazu geht man in das Repository Framework und fügt die andere Repositories als Submodule hinzu:

git submodule add :Library1
git submodule add :Library2
git submodule add :Library3

Damit wird im Repository Framework eine Datei mit dem Namen .gitmodules angelegt, in welcher folgender Inhalt zu finden ist:

[submodule "Library1"]
	path = Library1
	url = :Library1

[submodule "Library2"]
	path = Library2
	url = :Library2

[submodule "Library3"]
	path = Library3
	url = :Library3

Diese Datei kann dann per Commit dem Repository hinzugefügt werden. Beim klonen eines solchen Repositories, muss man nur darauf achten das es rekursiv geklont und gepullt (git submodule foreach git pull) wird, damit die Submodule ebenfalls aktualisiert werden.

Git Repository in Subrepository verwandeln

Auf mactricks.de gibt es eine schöne Anleitung um aus einem Teil eines Git Repositories ein Subrepository zu erzeugen. Allerdings gibt es mit der Variante ein Problem. Wenn man das ganze mehr als zwei oder dreimal machen möchte, wird es mit der Zeit nervig all diese Befehle einzugeben.

Aus diesem Grund habe ich für das Extrahieren eines Subprojektes aus einem Git Repository ein Skript geschrieben:

#!/bin/sh
# extractSubproject <orignal repopath> <new repopath> <subfolder> <new remote (optional)>

# clone repository
git clone --no-hardlinks $1 $2

# extract subproject
cd $2
git filter-branch --subdirectory-filter $3 HEAD
git reset --hard
git remote rm origin
rm -r .git/refs/original/
git reflog expire --expire=now --all
git gc --aggressive
git prune

# Add optional remote and push
if [ "$4" != "" ]; then
git remote add origin $4
  git push origin master
fi

Heruntergeladen werden kann sich das Skript auch unter https://github.com/seeseekey/archive/blob/master/Bash/Git/extractSubproject.sh.

Bashskript zur Aktualisierung von Repositories

Bei mir auf der Festplatte liegen einige Quelltext in Form von Subversion und Git Repositories. Da es mühsam wäre jedes einzelne Repository zu aktualisieren, habe ich mir ein kleines Skript geschrieben, welches diese Aufgabe abnimmt:

#bash

#Update repositories script
#Copyright (c) 2012 by seeseekey <>
#
#This program is free software: you can redistribute it and/or modify
#it under the terms of the GNU General Public License as published by
#the Free Software Foundation, either version 3 of the License, or
#(at your option) any later version.
#
#This program is distributed in the hope that it will be useful,
#but WITHOUT ANY WARRANTY; without even the implied warranty of
#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#GNU General Public License for more details.
#
#You should have received a copy of the GNU General Public License
#along with this program.  If not, see <http://www.gnu.org/licenses/>.

SCRIPTPATH=$(pwd);

#Git
for directory in `find $SCRIPTPATH -name ".git" -type d`;
do
  echo $directory;
  cd $directory/..;
  git pull;
done

#Subversion
for directory in `find $SCRIPTPATH -name ".svn" -type d`;
do
  echo $directory;
  cd $directory/..;
  svn update;
done

#Pfad zurücksetzen
cd $SCRIPTPATH;

Das Skript selbst steht dabei unter GPLv3 und kann auch direkt auf Github unter https://github.com/seeseekey/archive/blob/master/Bash/Git/updateRepositories.sh gefunden werden.

Dateien von einem in ein anderes Git Repostory überführen

Man nehme die Git Repositories A und B:

A
|_.git
|_file01.txt
|_file02.txt
|_file03.txt

B
|_.git
|_Zeugs
|_image01.txt
|_image02.txt
|_image03.txt

Im Verzeichnisbaum sieht das ganze dabei so aus:

*
|_A
|_B

Nun soll der Inhalt des Repositories B im Repository A landen. Wichtig hierbei ist das die History erhalten bleiben soll. Dazu legen wir in Repository A einen Branch an und laden das Repository B in diesen. Im Repository A öffnen wir eine Konsole und geben dort folgendes ein:

git remote add other ../B
git fetch other
git checkout -b tmpBranch other/master
git checkout master
git merge tmpBranch
git branch -d tmpBranch
git remote rm other
git push                           

Sollte es nach dem „merge tmpBranch“ zu Konflikten kommen, so müssen diese gelöst werden und das ganze dann mittels „git commit“ bzw. „git commit -a“ fixiert werden. Danach sieht das Repository dann so aus:

A
|_.git
|_Zeugs
|_file01.txt
|_file02.txt
|_file03.txt
|_image01.txt
|_image02.txt
|_image03.txt

Für Git Neulinge das ganze nochmal ein wenig genauer. Mittels „git remote add other ../B“ wird dem Repository A ein neuer Remote hinzugefügt. Die Daten aus diesem werden dann mittels „git fetch other“ geladen und anschließend werden diese „git checkout -b tmpBranch other/master“ in einen neuen Branch namens „tmpBranch“ gepackt.

Nun machen wir mit „git checkout master“ den Masterbranch wieder zum aktiven Branch und mergen den „tmpBranch“ mittels „git merge tmpBranch“ in den Masterbranch. Danach wird der „tmpBranch“ mittels „git branch -d tmpBranch“ gelöscht und der nicht mehr benötige Remote mittels „git remote rm other“ entfernt.

Nun wird das ganze noch mit „git push“ auf den Remote des Repositories gepusht und fertig ist die Überführung.

Weitere Informationen gibt es unter:
http://de.wikipedia.org/wiki/Git
http://progit.org/book/de/ch3-4.html
http://de.gitready.com/beginner/2009/01/25/branching-and-merging.html
http://stackoverflow.com/questions/1683531/how-to-import-existing-git-repository-into-another

Bestehendes Subversion Repository in Google Code importieren

Möchte man ein bestehendes Subversion Repository ín Google Code importieren so geht muss man im ersten Schritt auf seine Google Code Seite dort dann auf Source -> Browser und unten dann auf „reset this repository“ und dort klickt man dann den Punkt „Did you just start this project and do you want to ’svnsync‘ content from an existing repository into this project?“ an.

Danach ist das Repository auf Revision 0 zurückgesetzt worden. Nun wird in der Konsole mittels

svnsync init –username YOURUSERNAME https://YOURPROJECT.googlecode.com/svn file:///path/to/localrepos

das Projekt initialisiert und mittels

svnsync sync –username YOURUSERNAME https://YOURPROJECT.googlecode.com/svn

die Synchronisation begonnen werden. Das ganze kann dabei durchaus ein paar Stunden dauern. Ausgefüllt sieht das ganze dann z.B. so aus:

svnsync init –username seeseekey https://invertika.googlecode.com/svn https://invertika.svn.sourceforge.net/svnroot/invertika

svnsync sync –username seeseekey https://invertika.googlecode.com/svn

Sollte die Synchronisation zwischendurch unterbrochen werden so ist das kein Problem da sie jederzeit wieder gestartet werden kann und bei der letzten synchronisierten Revision anfängt.