Grundlagen: lokales Repository (GIT)

Aus Siduction Wiki DE
Wechseln zu: Navigation, Suche

GIT-Tutorial: Übersicht

Vorbemerkung

Dieser Teil führt in die grundlegenden Arbeiten mit GIT ein. Als Beispiel wird ein Backupscript entwickelt. Das Tutorial setzt keine Kenntnis von Versionskontrollsystem voraus, aber das Arbeiten mit der Konsole muss vertraut sein.

Anlegen des Repositories

Das Repository ist ein Verzeichnisbaum. In ihm findet die Pflege der Dateien statt (Arbeitsverzeichnis, "working directory"), es ist aber auch die GIT-Datenbank enthalten.

 REP=~/git/backup
 mkdir -p $REP
 cd $REP
 git init
Initialized empty Git repository in /home/hm/git/backup/.git/
 find
.
./.git
./.git/hooks
./.git/hooks/update.sample
...
./.git/info/exclude

Wir sehen, dass das Unterverzeichnis .git angelegt wurde, die Datenbank von GIT.

Datei ins Repository bringen

Erstellen der ersten Quelldatei:

 cat >backup.sh <<EOS
#! /bin/sh
cp -a /home /data/backup
EOS
 ls -l
-rw-r--r-- 1 hm hm 41 23. Aug 20:33 backup.sh

Jetzt schauen wir uns an, was GIT zu unserem Werk meint:

 git status
# On branch master
# Initial commit
# Untracked files:
#   (use "git add <file>..." to include in what will be committed)
#       backup.sh

GIT hat bemerkt, dass im Arbeitsverzeichnis eine Datei erstellt wurde. Sie gehört aber noch nicht zum Repository ("untracked"). Wir müssen explizit sagen, wenn die Datei "dazugehören" soll:

 git add backup.sh
 git status
# On branch master
# Initial commit
# Changes to be committed:
#   (use "git rm --cached <file>..." to unstage)
#       new file:   backup.sh

Damit ist backup.sh "unter Aufsicht", jedoch noch nicht in der Datenbank. Das erreichen wir mit

 git commit -m "Backup mittels Kopieren" backup.sh
[master (root-commit) 2d6da1e] Backup mittels Kopieren
 1 files changed, 5 insertions(+), 0 deletions(-)
 create mode 100644 backup.sh
 git status
# On branch master
nothing to commit (working directory clean)

Da fällt uns auf, dass als /bin/sh verwendet wird, wir aber mit dieser Einfachvariante nicht zurechtkommen. Wir wollen mit /bin/bash arbeiten:

 cat >backup.sh <<EOS
#! /bin/bash
cp -a /home /data/backup
EOS

Änderungen anzeigen

Ob GIT was von der Änderung merkt?

 git status
# On branch master
# Changes not staged for commit:
#   (use "git add <file>..." to update what will be committed)
#   (use "git checkout -- <file>..." to discard changes in working directory)
#       modified:   backup.sh

Mit GIT können wir den Unterschied zur Version in der Datenbank anzeigen lassen:

 git diff backup.sh
diff --git a/backup.sh b/backup.sh
index efc03ba..e23c985 100644
--- a/backup.sh
+++ b/backup.sh
@@ -1,2 +1,2 @@
-#! /bin/sh
+#! /bin/bash
 cp -a /home /data/backup

Komfortabler geht es mit einem GUI-Difftool, z.B. kdiff3:

 git difftool backup.sh

Dazu muss GIT allerdings passend konfiguriert werden: Siehe Konfiguration (GIT)

 git commit -m "/bin/bash statt /bin/sh" -a backup.sh
[master cac8976] /bin/bash statt /bin/sh
 1 files changed, 1 insertions(+), 1 deletions(-)
 git status
# On branch master
nothing to commit (working directory clean)

Die Änderung ist in der Datenbank angekommen.

Verarbeitungszustände einer Datei

Eine Datei kann also verschiedene Verarbeitungszustände haben:

  • unbeaufsichtigt ("untracked"). Nur im Arbeitsverzeichnis.
  • neu ("new") Nur im Arbeitsverzeichnis.
  • unverändert ("clean") Identisch im Arbeitsverzeichnis und in der Datenbank.
  • verändert ("modified") Unterschiedlich im Arbeitsverzeichnis und in der Datenbank.

Anzeige der Log-Meldungen

Ein anständiges Projekt braucht Release-Notes:

 echo "V0.1: Backup durch kopieren" >releasenotes.txt
 git add releasenotes.txt
 git commit -m "Release-Notes für V0.1" *.txt
 git log
commit bc515ac5af1c75e6e9f654171e90512a4e913627
Author: hamatoma <hamatoma@gmx.de>
Date:   Tue Aug 23 22:08:19 2011 +0200
    Release-Notes für V0.1
commit cac89761c748c3221ba20420646672cccc9e681c
Author: hamatoma <hamatoma@gmx.de>
Date:   Tue Aug 23 22:06:06 2011 +0200
    /bin/bash statt /bin/sh
commit df231468f88d5f49ca9a171015471ed041d6d4c8
Author: hamatoma <hamatoma@gmx.de>
Date:   Tue Aug 23 21:56:04 2011 +0200
    Backup mittels Kopieren

Mit dem log-Kommando sehen wir die Historie des Projekts. Hier tauchen die Texte auf, die wir beim Commit mit der -m-Option angegeben haben. Es ist also wichtig, beim Commit informative Texte als Kommentar anzugeben!

Tag erstellen

Unser Script ist soweit funktionstüchtig, also wollen wir den Zustand markieren. Diese Markierung wird "Tag" genannt. Ein Tag hat einen Namen und einen Kommentar:

 git tag -m "Backup mittels Kopieren" v0.1
 git tag
v0.1
 git log

Unter GIT sind Tags nur Namen für einen Commit. Sie haben den Vorteil, mit "git tag" gelistet werden zu können und sprechendere Namen zu haben als die SHA-1-Hashes der Commits.

Branch einrichten

Unser Backupscript funktioniert, kann also produktiv eingesetzt werden. Andererseits ist es verbesserungsfähig. Damit die Produktionsversion aber erhalten bleibt, legen wir einen Entwicklungszweig ("Branch") an:

 git branch dev
 git branch
dev
* master

Es werden zwei Branches angezeigt, der neue "dev" und der "master". Letzterer ist der Branch, der automatisch mit Anlegen eines Repositories vorhanden ist. Der '*' zeigt den aktiven Branch an: Das Arbeitsverzeichnis ist immer einem Branch zugeordnet. Wir wechseln in den Branch dev:

 git checkout dev
Switched to branch 'dev'
 git branch
* dev
  master

Aha, jetzt ist dev als aktiver Branch eingestellt.

Änderungen im neuen Branch

Eine bahnbrechende Idee: Nutzung des Scripts auf verschiedenen Rechnern, die unterschiedliche Sicherungsverzeichnisse haben. Also jetzt eine Version, die die Konfiguration aus einer rechnerspezifischen Datei holt:

 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
cp -a $SRC $TRG
EOS
 echo >>releasenotes.txt "V0.2: Nutzen einer hostspezifischen Konfiguration"
 git status
# On branch dev
# Changes not staged for commit:
#   (use "git add <file>..." to update what will be committed)
#   (use "git checkout -- <file>..." to discard changes in working directory)
#       modified:   backup.sh
#       modified:   releasenotes.txt
 git commit -m "hostspezifischen Konfiguration" -a
[dev 96b634d] hostspezifischen Konfiguration
 2 files changed, 7 insertions(+), 1 deletions(-)
 git tag -m "hostspezifischen Konfiguration" v0.2

Die Option -a bewirkt, dass der Index angepasst und die Änderungen dann ins die Datenbank übernommen werden. Da keine Dateien angegeben sind, werden alle geänderten Dateien committed, hier also backup.sh und releasenotes.txt.

 gitk --all

Gitk-backup-v0.2-dev.png

Gitk ist ein GUI-Programm, das umfangreiche Anzeige- und Suchmöglichkeiten für GIT-Repositories bietet.

Mergen

Das Script bewährt sich, wir lassen es produktiv gehen: Es soll in den master-Branch übernommen werden. Das Zusammenführen von Entwicklungszweigen wird "Mergen" genannt. Zuerst stellen wir den zu änderenden Branch ein, also master:

 git checkout master
Switched to branch 'master'

Die Änderungen von dev nach master übernehmen:

 git merge -v dev
Fast-forward
backup.sh        |    7 ++++++-
releasenotes.txt |    1 +
2 files changed, 7 insertions(+), 1 deletions(-)
 git log --graph --pretty=oneline --abbrev-commit
* 96b634d hostspezifischen Konfiguration
* bc515ac Release-Notes für V0.1
* cac8976 /bin/bash statt /bin/sh
* df23146 Backup mittels Kopieren

Das letzte log-Kommando mit den vielen Optionen liefert eine kompaktere Information als ohne Optionen. Ist eine GUI vorhanden, ist gitk bequemer und ansprechender:

 gitk --all

Gitk-backup-v0.2.png

Wir sehen, die Historie von dev ist jetzt in die Historie von master übernommen worden.