Versionsverwaltung mit Git
Das Problem
Wie kann ich …
- … mit mehreren Leuten an einem Projekt entwickeln
- … die Historie der Änderungen der Quellen behalten
- … in der Zeit zurückreisen und alte Stände wieder herstellen
- … herausfinden, welcher Entwickler ein Problem ausgelöst hat
- … verschiedene Versionen der Software entwickeln
- … meine Code ablegen und konsistent per Backup sichern
- … Änderungen aus verschiedenen Quellen zusammenführen
Die Lösung: Versionsverwaltung (VCS)
- Versions-Verwaltungssysteme (Version Control Systems) (VCS) verwalten Source Code
- Eigenschaften
- Historie aller Änderungen
- Vergleich (diff) verschiedener Stände
- Abzweigen (branching) und Zusammenführen (merging)
- Koordinierung des gemeinsamen Zugriffs auf Source Code
- Man unterscheidet
- Lokale Versionsverwaltungssysteme
- Zentrale Versionsverwaltungssysteme
- Verteilte Versionsverwaltungssysteme
Man spricht auch von Software Configuration Management Systems (SCM) und meint damit Systeme, die neben der Funktionalität von VCSs noch weitergehende Dienste anbieten. Häufig werden VCS und SCM aber synonym verwendet.
Zentrales VCS
Ein zentralisiertes VCS (z. B. SVN oder CVS) verfolgt die Änderungen an Dateien und Projekten, indem es diese in einem zentralen Repository speichert. Die grundlegende Idee ist, dass alle Entwickler:innen mit diesem zentralen Speicherort interagieren, um ihre Arbeiten zu speichern und abzurufen.
- Zentrales Repository: Alle Versionsdaten, d. h. die gesamte Historie der Projektdateien, werden auf einem zentralen Server gespeichert. Dieses Repository ist der „Single Source of Truth“, wo die aktuelle und vergangene Version der Dateien abgelegt ist.
- Check-out: Entwickler:innen holen eine Arbeitskopie des Projekts aus dem zentralen Repository auf ihren lokalen Computer. Dies geschieht durch das sogenannte „Check-out“, bei dem sie die neueste Version der Dateien abrufen.
- Änderungen durchführen: Entwickler:innen arbeiten lokal an den Dateien. Sie können Änderungen vornehmen, neue Dateien hinzufügen oder bestehende Dateien entfernen.
- Check-in: Nach der Arbeit an den Dateien laden sie ihre Änderungen wieder in das zentrale Repository hoch, indem sie einen Check-in durchführen. Hierbei wird die Änderung als neue Version im Repository gespeichert.
- Konflikte: Wenn mehrere Entwickler:innen gleichzeitig an denselben Dateien arbeiten, kann es zu Konflikten kommen, wenn ihre Änderungen nicht miteinander kompatibel sind. In solchen Fällen müssen sie die Konflikte manuell lösen, bevor sie ihre Änderungen hochladen.
Der Vorteil eines zentralen Versionsverwaltungssystems ist, dass es einfach zu verstehen und zu administrieren ist, da es nur einen zentralen Speicherort für die Versionierung gibt. Der Nachteil ist, dass das System nur dann funktioniert, wenn der Server verfügbar ist. Ein Ausfall des zentralen Repositories kann das gesamte Team blockieren.
Verteiltes VCS
Ein verteiltes VCS (z. B. Git, Mercurial) verwenden anstatt eines einzigen zentralen Server, auf den alle Entwickler:innen zugreifen, mit vollständigen Kopien des gesamten Repositories auf den lokalen Rechner.
- Vollständige Kopie: Jeder hat ein eigenes vollständiges Repository auf dem eigenen Computer, das die gesamte Historie des Projekts enthält. Es ist keine ständige Verbindung zu einem zentralen Server notwendig, um lokal zu arbeiten.
- Unabhängige Arbeit: Entwickler:innen können lokal Änderungen vornehmen und Commits durchführen, ohne dass eine Verbindung zu einem zentralen Server besteht. Die Änderungen bleiben zunächst in ihrem lokalen Repository.
- Verteilen von Änderungen: Um Änderungen mit anderen zu teilen, müssen die Entwickler:innen ihre lokalen Änderungen ins zentrale Repository „pushen“. Ebenso können sie Änderungen von anderen „pullen“ (herunterladen), um ihre lokalen Repositories zu aktualisieren.
Ein verteiltes Versionsverwaltungssystem wie Git bietet mehr Flexibilität und Unabhängigkeit für Entwickler:innen und Teams. Die Möglichkeit, lokal zu arbeiten und dann später zu synchronisieren sowie die einfache Handhabung von Branches und Merges, macht es besonders für komplexe und kollaborative Projekte geeignet. Es bringt jedoch auch zusätzliche Komplexität mit sich, besonders wenn es um die Verwaltung von Versionskonflikten und das richtige Zusammenspiel zwischen den Entwickler:innen geht.
Wichtige Begriffe und Konzepte
- revision – Version einer Datei im Repository
- branch – Verschiedene Code-Linien, um an parallelen Versionen arbeiten zu können
- add – eine neue lokale Datei dem Repository hinzufügen
- checkout – eine Kopie der Datei aus dem Repository holen, um sie lokal zu bearbeiten
- commit – eine Datei in das Repository zurückstellen
- revert – lokale Änderungen verwerfen und durch den letzten Stand aus dem Repository ersetzen
- blame – anzeigen, wer welche Änderungen an einer Datei gemacht hat
- tag – Revisionen im Repository mit einer Markierung versehen (z. B. „Release 1.0“)
- merge – parallele Änderungen an einer Datei zusammenführen
- resolve – Konflikte beim merge auflösen
- diff – Unterschiede zwischen der lokalen und einer zentralen oder zwischen verschiedenen Revisionen einer Datei anzeigen
- clone – Repository kopieren (nur bei verteilten VCSs)
- push – Änderungen in ein anderes Repository übertragen (nur bei verteilten VCSs)
- pull – Änderungen aus einem anderen Repository ziehen (nur bei verteilten VCSs)
Zentrale Versionsverwaltungssysteme
Open Source
- CVS - Urvater, inzwischen veraltet
- Subversion - Populärste zentrale System
Closed Source
- Visual SourceSafe - Veraltet, viele Probleme
- Team Foundation Server - Nachfolger von Visual Source Safe, Microsoft zentrisch
- Perforce - Kostenlos für Open Source oder max. zwei Benutzer:innen
Verteilte Versionsverwaltungssysteme
Open Source
- Git - Linux Kernel Community
- Mercurial - Python Community
- Bazaar - Ubuntu als Hauptnutzer
Closed Source
- Bitkeeper
- ClearCase
- Subversion
Git
- Für alle Betriebssysteme verfügbar
http://git-scm.com - Eclipse-Integration über eGit
http://www.eclipse.org/egit - Zentrales Repository kann über Hoster angelegt werden
http://www.github.com - Konzepte sehr ähnlich mit Mercurial (hg)
Beispiel: Git lokal verwenden
> cat ~/.gitconfig
[user]
name = Thomas Smits
email = t.smits@th-mannheim.de
> cd project
> git init
Initialized empty Git repository in /Users/thomas/project/.git/
> cat .gitignore
.DS_Store
bin/
.gitignore
.metadata
.gitconfigenthält die grundlegende Konfiguration von git- mit
git initwird ein neues Verzeichnis für die Versionskontrolle vorbereitet .gitignoreenthält Dateien, die von git ignoriert werden sollen
> git add io
> git status
# On branch master
#
# Initial commit
#
# Changes to be committed:
# (use "git rm --cached <file>..." to unstage)
#
# new file: io/.classpath
# new file: io/.project
# new file: io/src/de/smits_net/pr2/console/Echo.java.
...
Mit git add werden neue Dateien hinzugefügt, hier die beiden Ordner io und status.
git status zeigt den aktuellen Zustand an, insbesondere welche Dateien noch nicht unter Versionskontrolle stehen oder gegenüber dem Repository verändert wurden.
> git commit -m "Erster Commit des Projektes"
[master (root-commit) b63be32] Erster Commit des Projektes
40 files changed, 1240 insertions(+), 0 deletions(-)
create mode 100644 io/.classpath
create mode 100644 io/.project
create mode 100644 io/src/de/smits_net/pr2/console/Echo.java
...
> git status
# On branch master
nothing to commit (working directory clean)
> git log
commit b63be3267c18e3f24db7b36498133a8183a1df49
Author: Thomas Smits <thomsmits@googlemail.com>
Date: Sat Mar 27 17:28:05 2010 +0100
Erster Commit des Projektes
git commit bringt die aktuellen Versionen der Dateien, die mit git add hinzugefügt wurden, in das Repository. git log zeigt die Historie des Projekts an.
> vi CreateDir.java
> git status
# On branch master
# Changed but not updated:
# (use "git add <file>..." to update what will be committed)
# (use "git checkout -- <file>..." to discard changes)
#
# modified: CreateDir.java
#
no changes added to commit (use "git add" and/or "git commit -a")
> git add CreateDir.java
> git commit -m "Fixed copyright date"
[master d565a0f] Fixed copyright date
1 files changed, 1 insertions(+), 1 deletions(-)
> git log
macbook:file thomas$ git log
commit d565a0f757595c83ee265948476ea1ebb461c1ed
Author: Thomas Smits <thomsmits@googlemail.com>
Date: Sat Mar 27 17:34:10 2010 +0100
Fixed copyright date
commit b63be3267c18e3f24db7b36498133a8183a1df49
Author: Thomas Smits <thomsmits@googlemail.com>
Date: Sat Mar 27 17:28:05 2010 +0100
Erster Commit des Projektes
> git diff d565a b63be
diff --git a/io/src/de/smits_net/pr2/file/CreateDir.java
b/io/src/de/smits_net/t
index ef41ca1..05e3ed9 100644
--- a/io/src/de/smits_net/pr2/file/CreateDir.java
+++ b/io/src/de/smits_net/pr2/file/CreateDir.java
@@ -1,5 +1,5 @@
/*
- * (c) 2010 Thomas Smits
+ * (c) 2009 Thomas Smits
*/
package de.smits_net.pr2.file;
Mit git diff kann man sich die Unterschiede zwischen Dateien anzeigen lassen.
Beispiel: Git verteilt verwenden
> git remote add sharedrepo /network/share/pr2/git
> git remote
sharedrepo
> git push sharedrepo
Counting objects: 17, done.
Delta compression using up to 2 threads.
Compressing objects: 100% (5/5), done.
Writing objects: 100% (9/9), 582 bytes, done.
Total 9 (delta 4), reused 0 (delta 0)
Unpacking objects: 100% (9/9), done.
To /network/share/pr2/git
e26823c..91adf73 master -> master
git remote legt in diesem Beispiel fest, dass mein Repository mit einem anderen verbunden werden soll und das andere als „sharedrepo“ benannt wird.
Mit git push wird der lokale Stand des Repositories in das zentrale geschoben.
> git clone /network/share/pr2/git
Initialized empty Git repository in /Users/thomas/git/.git/
sharedrepo
> git pull
remote: Counting objects: 17, done.
remote: Compressing objects: 100% (5/5), done.
remote: Total 9 (delta 4), reused 0 (delta 0)
Unpacking objects: 100% (9/9), done.
From /Users/thomas/git/ /network/share/pr2/git
91adf73..f83d24f master -> origin/master
Updating 91adf73..f83d24f
Fast-forward
io/src/de/smits_net/pr2/nio/KopierprogrammNIO.java | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
git clone kopiert ein Repository und git pull importiert die Änderungen aus dem entfernten Repository in mein eigenes Repository.
Git und Eclipse
Git kann direkt aus Eclipse heraus verwendet werden