GIT-Tutorial: Verwenden eines zentralen Repositories
Einrichten[Bearbeiten]
- 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[Bearbeiten]
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[Bearbeiten]
Das Script kopiert ein oder mehrere per Konfiguration festgelegte Quellverzeichnisse in ein Zielverzeichnis.
Veränderung während des Tutorials[Bearbeiten]
- Protokoll des Backupvorgangs (Entwicklerin Alice)
- Ersetzen von cp durch rsync (Entwickler Bob)
Einrichten der Entwicklungssrepositories[Bearbeiten]
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[Bearbeiten]
Änderungen bei Alice[Bearbeiten]
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[Bearbeiten]
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[Bearbeiten]
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[Bearbeiten]
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[Bearbeiten]
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[Bearbeiten]
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[Bearbeiten]
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=[Bearbeiten]
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[Bearbeiten]
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[Bearbeiten]
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