GIT-Tutorial: Verwenden eines zentralen Repositories
Einrichten
- Das zentrale Repository wird in der GIT-Literatur oft auch als Depot oder authoritatives Repository bezeichnet.
- Ein Depot unterscheidet sich von anderen Repositories:
- Es wurde durch "git init --bare" oder mit "git clone --bare" erzeugt.
- Es hat keinen Verweis zu seinem Eltern-Repository, wenn es durch Clonen erzeugt wurde.
- Es hat kein Arbeitsverzeichnis, ein Auschecken ist nicht möglich. Änderungen kommen auschließlich durch Sychronisation von den geklonten Kind-Repositories ("push") ins Depot.
- Ein Depot muss nicht notwendigerweise auf einem Server liegen, sondern kann - wie in unserem Fall - auch lokal angelegt sein.
Um für das Tutorial einen nützlichen Ausgangspunkt zu haben, wird das Depot von einer Vorlage geklont:
DEPOT=/opt/git-depot
sudo mkdir $DEPOT
sudo chmod uog+rwx $DEPOT
cd $DEPOT
git clone --bare git://f-r-e-i.de/backup
- --bare sorgt dafür, dass das Zielverzeichnis die Endung .git bekommt, hier also backup.git
- Die Vorlage im Netz ist scheibgeschützt, ein Clonen ohne --bare wäre also nicht sinnvoll
- Ab jetzt ist das Depot des Musterprojekts unter /opt/git-depot/backup.git zu finden.
Das Musterprojekt
Als Beispielsprojekt dient das Backupscript das im Kapitel GIT-Tutorial: Grundlagen (lokales Repository) entwickelt wurde. Wir führen die gleichen Änderungen durch wie im Kapitel GIT-Tutorial: Erweitertes Mergen, jedoch findet die Parallelentwicklung nicht in zwei Branches statt, sondern wird von zwei Entwicklern (Alice und Bob) in verschieden Repositories durchgeführt.
Ausgangslage
Das Script kopiert ein oder mehrere per Konfiguration festgelegte Quellverzeichnisse in ein Zielverzeichnis.
Veränderung während des Tutorials
- Protokoll des Backupvorgangs (Entwicklerin Alice)
- Ersetzen von cp durch rsync (Entwickler Bob)
Einrichten der Entwicklungssrepositories
for usr in alice bob ; do
sudo mkdir /opt/$usr
sudo chmod uog+rwx /opt/$usr
cd /opt/$usr
git clone /opt/git-depot/backup.git
cd /opt/$usr/backup
# GIT-User für dieses Repository einstellen:
git config user.name $usr
git config user.email $usr@localhost
done
Vorgehensweise
Änderungen bei Alice
Nach dem Clonen:
gitk --all
Datei:Gitk-backup-alice-v0.2.png
Es fallen zwei Branche auf: remotes/origin/master und remotes/origin/dev. Diese wurde automatisch durch GIT beim Clonen angelegt.
Alice geht auf Nummer Sicher und arbeitet auf einem eigenen Branch:
cd /opt/alice/backup
git branch logging
git checkout logging
cat >backup.sh <<'EOS'
#! /bin/bash
CONF=/etc/backup/$HOST.conf
if [ ! -f $CONF ] ; then
echo "SRC=/home\nTRG=/data/backup" > $CONF
fi
source $CONF
date "+%Y.%m.%sd %H:%M: Starting backup $SRC" >>/var/log/backup.log
cp -a $SRC $TRG
date "+%Y.%m.%sd %H:%M: Finished" >>/var/log/backup.log
EOS
echo >>releasenotes.txt "V0.3: Logging"
git commit -m "Logging" -a
git tag -m "logging" v0.3
gitk --all
Datei:Gitk-backup-alice-v0.3.png
Änderungen bei Bob
Bob braucht keinen eigenen Branch für die Weiterentwicklung, er arbeitet auf master:
cd /opt/bob/backup
git checkout master
perl -pi -e 's/cp/rsync \$1 --delete'/ backup.sh
echo >>releasenotes.txt "V0.3: More performance using rsync"
git commit -m "Using rsync" -a
git tag -m "using rsync" v0.3
gitk --all
Datei:Gitk-backup-bob-v0.3.png
Bobs Änderungen ins Depot
git push
gitk
Das war doch einfach! "push" führt automatisch einen Merge mit dem Branch remotes/origin/master durch und überträgt diesen Stand ins Depot.
Depot nach Bobs push
Den Zustand des Depots bekommen wird am einfachsten heraus, wenn wir erneut clonen:
cd /tmp
git clone /opt/git-depot/backup
cd backup
gitk --all
Datei:Gitk-backup-bob-v0.3.png
Das Repository entspricht dem von Bob.
Alices Änderungen ins Depot
Zuerst muss Alice ihren Branch logging mit master zusamenbringen, da nachher nur master automatisch ins Depot gebracht werden kann:
cd /opt/alice/backup
git checkout master
git merge logging
Updating 395540c..0fe01d3 Fast-forward backup.sh | 2 ++ releasenotes.txt | 1 + 2 files changed, 3 insertions(+), 0 deletions(-)
gitk --all
Datei:Git-backup-alice-merge-logging-master.png
Ab ins Depot...
git push
To /opt/git-depot/backup.git ! [rejected] master -> master (non-fast-forward) error: failed to push some refs to '/opt/git-depot/backup.git' To prevent you from losing history, non-fast-forward updates were rejected Merge the remote changes (e.g. 'git pull') before pushing again. See the 'Note about fast-forwards' section of 'git push --help' for details.
Was ist passiert? GIT weigert sich, die Änderungen auf dem Depot einfach durchzuführen, da sonst Datenverlust drohen würde: Die Änderungen von Bob wären weg.
Der Ausweg wird ja schon vorgeschlagen: Die Änderungen vom Depot holen, mit Alices Änderungen zusammenführen und dann mergen.
Änderungen aus dem Depot holen
Der vorige Vorschlag von GIT war das Kommando pull. Das ist eine Kombination von fetch und merge. Alice bevorzugt die Variante mit den Einzelbefehlen:
git fetch
From /opt/git-depot/backup 395540c..60ba035 master -> origin/master
gitk
Datei:Gitk-backup-alice-nach-fetch.png
Das fetch-Kommando schreibt den Branch origin/master, der den Branch master im Depot repräsentiert, fort. Die Änderungen von Bob ("Using rsync") sind angekommen.
Mergen des Depot-Masterbranches
Was jetzt kommt, ist Standard (siehe GIT-Tutorial: Erweitertes Mergen: Alice merged den Zweig origin/master in ihren Branch master:
git merge origin/master
Auto-merging backup.sh CONFLICT (content): Merge conflict in backup.sh Auto-merging releasenotes.txt CONFLICT (content): Merge conflict in releasenotes.txt Automatic merge failed; fix conflicts and then commit the result.
Konfliktbehandlung=
Es gibt die zwei Konflikte, die behoben werden müssen:
cat backup.sh
#! /bin/bash CONF=/etc/backup/$HOST.conf if [ ! -f $CONF ] ; then echo "SRC=/home\nTRG=/data/backup" > $CONF fi source $CONF <<<<<<< HEAD date "+%Y.%m.%sd %H:%M: Starting backup $SRC" >>/var/log/backup.log cp -a $SRC $TRG date "+%Y.%m.%sd %H:%M: Finished" >>/var/log/backup.log ======= rsync $1 --delete -a $SRC $TRG >>>>>>> origin/master
Beheben des Konflikts von backup.sh:
cat >backup.sh <<'EOS'
#! /bin/bash
CONF=/etc/backup/$HOST.conf
if [ ! -f $CONF ] ; then
echo "SRC=/home\nTRG=/data/backup" > $CONF
fi
source $CONF
date "+%Y.%m.%sd %H:%M: Starting backup $SRC" >>/var/log/backup.log
rsync $1 --delete -a $SRC $TRG
date "+%Y.%m.%sd %H:%M: Finished" >>/var/log/backup.log
EOS
Der zweite Konflikt (releasenotes.txt):
cat releasenotes.txt
V0.1: Backup durch kopieren V0.2: Nutzen einer hostspezifischen Konfiguration <<<<<<< HEAD V0.3: Logging ======= V0.3: More performance using rsync >>>>>>> origin/master
Beheben:
perl -ni -e 'print unless /^(<<|==|>>)/;' releasenotes.txt
echo "V0.4: Logging and rsync" >>releasenotes.txt
Jetzt sollte der Commit klappen:
git commit -m "Logging and rsync" -a
git tag -m "Logging and rsync" v0.4
gitk --all
Datei:Gitk-backup-alice-nach-mergen-origin-master.png
Änderungen ins Depot bringen
Jetzt kann Alice den Abgleich ins Depot nochmal probieren:
git push
To /opt/git-depot/backup.git 60ba035..71d2af8 master -> master
gitk --all
Datei:Gitk-backup-alice-v0.4.png
Damit sind die Änderungen von Bob und Alice im Depot, unser Ziel ist erreicht.
Zusammenfassung
Die normale Vorgehensweise im Umgang mit einem Depot:
- Einrichten einer Kopie des Depots:
- git clone <depot>
- Änderungen im lokalen Repository durchführen.
Wenn die Entwicklung einen Stand hat, die ins Depot zurückfließen soll:
- Eigenen Entwicklungszweig in den Master bringen, wenn ein solcher existiert:
- git checkout master
- git merge dev
- Wenn Konflikte auftreten, diese bereinigen und Ergebnis committen:
- git commit -m "kommentar" -a
- Änderungen aus dem Depot holen und mit master zusammenführen:
- git pull
- Zusammengeführten Branch ins Depot bringen
- git push