seeseekey.net - Invictus Deus Ex Machina

Auf mactricks.de gibt es eine schöne Anlei­tung um aus einem Teil eines Git Repo­si­to­ries ein Sub­re­po­sitory zu erzeu­gen. Aller­dings gibt es mit der Vari­ante ein Pro­blem. Wenn man das ganze mehr als zwei oder drei­mal machen möchte, wird es mit der Zeit ner­vig all diese Befehle einzugeben.

Aus die­sem Grund habe ich für das Extra­hie­ren eines Sub­pro­jek­tes aus einem Git Repo­sitory 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

Her­un­ter­ge­la­den wer­den kann sich das Skript auch unter https://github.com/seeseekey/archive/blob/master/Bash/Git/extractSubproject.sh.

Wie man Git auf einem Ubun­tu­ser­ver auf­setzt hatte ich vor eini­ger Zeit in einem Arti­kel beschrie­ben. Nach­teil der vor­ge­stell­ten Methode ist, das sie sich nur für einen Nut­zer eig­net. Natür­lich kann man mit die­ser Methode auch meh­rere Nut­zer zu dem Repo­si­to­ries ver­bin­den, hat damit aber keine Mög­lich­keit mehr Zugriffs­be­rech­ti­gun­gen für die Repo­si­to­ries zu setzen.

Als Lösung für das Pro­blem wird Gito­lite für die Nut­zer und Rech­te­ver­wal­tung genutzt. Im ers­ten Schritt wer­den auf dem Ser­ver die not­wen­di­gen Pakete installiert:

sudo apt-get install git openssh-server perl

Als nächs­ter Schritt wird der Nut­zer ange­legt, in wel­chem Gito­lite läuft und in die­sen gewechselt:

sudo useradd -m git
sudo su git

Danach geht es auch schon an die Instal­la­tion von Gitolite:

cd ~
git clone git://github.com/sitaramc/gitolite
mkdir bin
cd gitolite
./install -ln

Anschlie­ßend muss der öffent­li­che SSH Schlüs­sel von dem Rech­ner mit wel­chem auf das Sys­tem zugrif­fen wer­den soll in den Home Ord­ner des „git“ Nut­zers kopiert wer­den. Anschlie­ßend kann das Setup abge­schlos­sen werden:

cd ~/bin
./gitolite setup -pk $HOME/seeseekey.pub

Damit ist das Setup abge­schlos­sen und es kann an die Kon­fi­gu­ra­tion gehen. Dazu wird vom Rech­ner des­sen Public Key beim Setup benutzt wurde das ent­spre­chende admi­nis­tra­tive Repo­sitory geklont:

git clone git@192.168.1.128:gitolite-admin

Die Datei­struk­tur des Repo­si­to­ries sieht dabei wie folgt aus:

conf
  gitolite.conf
keydir
  seeseekey.pub

In dem Ver­zeich­nis „key­dir“ sind die SSH Schlüs­sel ent­hal­ten. Um einen Nut­zer hin­zu­zu­fü­gen reicht es ein­fach einen neuen öffent­li­chen Schlüs­sel in das Ver­zeich­nis zu legen und das ganze ins Git Repo­sitory ein­zu­brin­gen. Die eigent­li­che Kon­fi­gu­ra­tion der Repo­si­to­ries erfolgt in der „gitolite.conf“ Datei. Diese sieht nach der Erzeu­gung so aus:

repo gitolite-admin
    RW+     =   seeseekey

repo testing
    RW+     =        @all

Das bedeu­tet das es zwei Repo­si­to­res gibt, eines trägt den Namen „gitolite-admin“ und dient der Ver­wal­tung. Das zweite Repo­sitory ist „tes­ting“ auf das alle Nut­zer zugrei­fen dür­fen. Benö­tigt man nun ein neues Repo­sitory, so fügt man einen neuen „repo“ Abschnitt mit dem Namen und den ent­spre­chen­den Rech­ten hinzu. Sobald das ganze com­mi­tet und gepusht wurde, legt Gito­lite das neue Repo­sitory an. Wenn man bei den Schlüs­seln meh­rere SSH Schlüs­sel pro Nut­zer wünscht, so legt man dafür am bes­ten eine Ver­zeich­nis­struk­tur an:

keydir
  seeseekey
    rechner1
      seeseekey.pub
    rechner2
      seeseekey.pub

Möchte man ein Repo­sitory löschen so ent­fernt man es aus der „gitolite.conf“ und löscht es anschlie­ßend auch vom Ser­ver. Damit hat man eine Lösung für Git Ser­ver mit meh­ren Nut­zern und und ent­spre­chen­der Verwaltung.

Möchte man auf einem Ubun­tu­sys­tem einen Git Ser­ver auf­set­zen, so ist dies rela­tiv schnell erle­digt. Zuerst muss dafür „git“ mittels:

apt-get install git

instal­liert wer­den. Danach wird der pas­sende Nut­zer für die Git Repo­si­to­ries angelegt:

adduser git

Nun kann man ein beste­hen­des Repo­sitory zu die­sem Ser­ver hoch­la­den. Auf dem Ser­ver wird in den Kon­text des Nut­zers „git“ gewech­selt und dort ein pas­sen­der Ord­ner sowie ein „rohes“ Git Repo­sitory angelegt:

su git
mkdir testproject.git
cd testproject.git
git init --bare

Dem loka­len Git Repo­sitory wird mittels:

git remote add origin git@example.org:testproject.git

ein neuer Remote zuge­wie­sen. Sollte bereits ein „remote“ für „ori­gin“ exis­tie­ren, so wird die­ser mit:

git remote rm origin

ent­fernt. Anschlie­ßend kann das lokale Repo­sitory an den Ser­ver über­tra­gen wer­den und auf Updates über­prüft werden:

git push origin master
git pull origin master

Wenn gewünscht kann man nun noch ver­hin­dern das man sich mit­tels des „git“ Accounts auf dem Ser­ver anmel­den kann. Dazu muss die Datei „/etc/passwd“ edi­tiert wer­den. Für den Nut­zer „git“ wird die Shell dabei von „/bin/bash“ in „/usr/bin/git-shell“ geän­dert. Anschlie­ßend kann man sich mit dem Account nicht mehr an der Shell anmelden.

Möchte man die lokale Revi­sion eines Git Repo­si­to­ries ermit­teln so reicht es in der Konsole:

git log -n 1

ein­zu­ge­ben. Das ganze sieht auf dem Ter­mi­nal dann so aus:

commit 1c40074d28676ec996ec91f1719cff43077f15f6
Author: Example 
Date:   Tue Jan 3 09:52:23 2013 +0800

    Bugfixes in example function.

Soll nur der Hash aus­ge­ben wer­den so muss die Kom­man­do­zeile wie folgt aussehen:

git log -n 1 --pretty=format:"%H"

Damit bekommt man dann nur den ent­spre­chen­den Hashwert ausgegeben.

Bei mir auf der Fest­platte lie­gen einige Quell­text in Form von Sub­ver­sion und Git Repo­si­to­ries. Da es müh­sam wäre jedes ein­zelne Repo­sitory zu aktua­li­sie­ren, habe ich mir ein klei­nes Skript geschrie­ben, wel­ches diese Auf­gabe abnimmt:

#bash

#Update repositories script
#Copyright (c) 2012 by seeseekey <seeseekey@gmail.com>
#
#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 Git­hub unter https://github.com/seeseekey/archive/blob/master/Bash/Git/updateRepositories.sh gefun­den werden.

Manch­mal möchte man ein Git Repo­sitory von Ser­ver A auf Ser­ver B umzie­hen (in die­sem Fall von Google Code zu Git­hub). Das ganze ist dabei rela­tiv unpro­ble­ma­tisch. Zuerst wird das beste­hende Repo­sitory geklont:

git clone https://code.google.com/p/cscl/

In der Git­Hub Ober­flä­che erstel­len wir nun ein neues Repo­sitory (in die­sem Fall mit dem Namen „CSCL“). Danach ent­fer­nen wir den alten Remote und wei­sen einen neuen hinzu:

git remote rm origin
git remote add origin git@github.com:seeseekey/CSCL.git

Mit­tels „git remote -v“ kann man sich die beste­hen­den „Remo­tes“ anschauen. Nach­dem der neue Remote gesetzt wur­den laden wir das Repo­sitory (mit­tels „push“) bei Git­Hub hoch:

git push -u origin master

Damit ist der Umzug abgeschlossen.

Wei­tere Infor­ma­tio­nen gibt es unter:
https://help.github.com/articles/removing-a-remote

Manch­mal gibt es selt­same Ideen, wie z.B. sämt­li­che Gesetze in ein Git Repo­sitory zu packen. Was auf den ers­ten Blick skur­ril klingt, hat aber durch­aus einen inter­es­san­ten Neben­as­pekt. So kann man bereits heute die Gesetze im Inter­net ein­se­hen. Das Git Repo­sitory hat aller­dings den Vor­teil, dass man nun auch die Ände­run­gen der Gesetzte ver­fol­gen kann. Wer sich das ganze anschauen möchte fin­det das Repo­sitory unter https://github.com/bundestag/gesetze.

Wei­tere Infor­ma­tio­nen gibt es unter:
http://www.golem.de/news/bundesgit-ein-git-repository-fuer-deutsche-gesetze-1208-93709.html

Eine schöne Seite über Git ist sicher­lich http://gitready.com/ bzw. deren deut­sches Äqui­va­lent wel­ches unter http://de.gitready.com/ zu fin­den ist. Dort gibt es Tipps rund um Git in klei­nen hand­li­chen und leicht ver­ständ­li­chen Arti­keln. Die Tipps sind dabei in Kate­go­rien (Anfän­ger, Fort­ge­schrit­tene Anfän­ger und Fort­ge­schrit­tene) unter­teilt, so das man sich zuerst an die ein­fa­che­ren The­men her­an­tas­ten kann und so Stück für Stück sein Wis­sen über Git erwei­tern kann.

Wei­tere Infor­ma­tio­nen gibt es unter:
http://de.wikipedia.org/wiki/Git

Unter Git kann man mittels:

git add test.txt

eine Datei dem Repo­sitory hin­zu­fü­gen. Beim nächsten:

git commit

befin­den sich die ent­spre­chen­den Dateien dann im Repo­sitory. Möchte man nun aber eine bestimmte Datei im Com­mit doch nicht hin­zu­fü­gen, so geschieht dies mittels:

git reset test.txt

Beim anschlie­ßen­den Com­mit wird diese Datei dann nicht mehr berücksichtigt.

Wei­tere Infor­ma­tio­nen gibt es unter:
http://stackoverflow.com/questions/348170/undo-git-add-before-commit

Man nehme die Git Repo­si­to­ries A und B:

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

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

Im Ver­zeich­nis­baum sieht das ganze dabei so aus:

*
|_A
|_B

Nun soll der Inhalt des Repo­si­to­ries B im Repo­sitory A lan­den. Wich­tig hier­bei ist das die History erhal­ten blei­ben soll. Dazu legen wir in Repo­sitory A einen Branch an und laden das Repo­sitory B in die­sen. Im Repo­sitory A öff­nen wir eine Kon­sole und geben dort fol­gen­des 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 tmp­Branch“ zu Kon­flik­ten kom­men, so müs­sen diese gelöst wer­den und das ganze dann mit­tels „git com­mit“ bzw. „git com­mit -a“ fixiert wer­den. Danach sieht das Repo­sitory dann so aus:

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

Für Git Neu­linge das ganze noch­mal ein wenig genauer. Mit­tels „git remote add other ../B“ wird dem Repo­sitory A ein neuer Remote hin­zu­ge­fügt. Die Daten aus die­sem wer­den dann mit­tels „git fetch other“ gela­den und anschlie­ßend wer­den diese „git check­out -b tmp­Branch other/master“ in einen neuen Branch namens „tmp­Branch“ gepackt.

Nun machen wir mit „git check­out mas­ter“ den Mas­ter­branch wie­der zum akti­ven Branch und mer­gen den „tmp­Branch“ mit­tels „git merge tmp­Branch“ in den Mas­ter­branch. Danach wird der „tmp­Branch“ mit­tels „git branch -d tmp­Branch“ gelöscht und der nicht mehr benö­tige Remote mit­tels „git remote rm other“ entfernt.

Nun wird das ganze noch mit „git push“ auf den Remote des Repo­si­to­ries gepusht und fer­tig ist die Überführung.

Wei­tere Infor­ma­tio­nen 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