Zentrales Repository (GIT)

Aus Siduction Wiki DE
Wechseln zu: Navigation, Suche

GIT-Tutorial: Übersicht

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 Synchronisation 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=~/git-depot
 mkdir $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 ~/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
   mkdir ~/$usr
   cd ~/$usr
   git clone ~/git-depot/backup.git
   cd ~/$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

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 ~/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

Gitk-backup-alice-v0.3.png

Änderungen bei Bob

Bob braucht keinen eigenen Branch für die Weiterentwicklung, er arbeitet auf master:

 cd ~/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

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 ~/git-depot/backup
 cd backup
 gitk --all

Gitk-backup-bob-v0.3.png

Das Repository entspricht dem von Bob.

Alices Änderungen ins Depot

Zuerst muss Alice ihren Branch logging mit master zusammenbringen, da nachher nur master automatisch ins Depot gebracht wird:

 cd ~/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

Git-backup-alice-merge-logging-master.png

Ab ins Depot...

 git push
To ~/git-depot/backup.git
 ! [rejected]        master -> master (non-fast-forward)
error: failed to push some refs to '~/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 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 ~/git-depot/backup
395540c..60ba035  master     -> origin/master
 gitk --all

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

Gitk-backup-alice-nach-mergen-origin-master.png

Änderungen ins Depot bringen

Jetzt kann Alice den Abgleich ins Depot nochmal probieren:

 git push
To ~/git-depot/backup.git
60ba035..71d2af8  master -> master
 gitk --all

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:

    • git pull
  • Zusammengeführten Branch ins Depot bringen
  • 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 push