Git Branches

Aus Thomas-Krenn-Wiki
Wechseln zu: Navigation, Suche

Ein erster Blick auf Branches wird bereits im Artikel Git Grundbefehle geworfen. In diesem Artikel wird näher auf die Funktionen und das Arbeiten mit Branches eingegangen. Dabei wird auch behandelt, wie lokale Branches in Repo gepusht werden und wie tracking Branches mit remote Branches verknüpft werden können.

Die kommenden Beispiele stellen dar, wie zwei Entwickler über ein zentrales Repo am Server ihre Fortschritte über Branches austauschen.

Branch erstellen und ins Repo pushen

Im ersten Schritt wird ein Klon eines bestehenden Repos erstellt:

:~/repos/dev-1/dev-1$ git clone ssh://tktest@192.168.56.101/home/tktest/repos/dev-1

Per default werden von Git schon Branches erstellt, die wie folgt lauten:

:~/repos/dev-1/dev-1$ git branch -a
* master
  remotes/origin/HEAD -> origin/master
  remotes/origin/master

Der lokale Branch "master" ist jener Branch der mittels "git init" automatsch erstellt wurde. Bei "git clone" werden außerdem die "remote tracking Branches" erstellt, die sich im zu klonenden Repo befinden (sichtbar mit "git branch -r). Nach dem Klon-Befehl wird außerdem ein "git fetch" durchgeführt, welches diese remote Branches aktualisiert. Ein "git pull" merged den Remote-Master-Branch in den lokalen Branch "master".[1]

Entwickler 1 erstellt daraufhin in seinem lokalen Repo einen neuen Branch, in dem er dann eine Zeile Code verändert:

:~/repos/dev-1$ git branch dev-v1.1
:~/repos/dev-1$ git checkout dev-v1.1 
Switched to branch 'dev-v1.1'
:~/repos/dev-1$ ls
function1.c  function2.c  function2.h
:~/repos/dev-1$ vi function1.c 
:~/repos/dev-1$ git status
# On branch dev-v1.1
# 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:   function1.c
#
no changes added to commit (use "git add" and/or "git commit -a")
:~/repos/dev-1$ git commit -a -m "version 1.1 in function"
[dev-v1.1 c55afd6] version 1.1 in function
 1 files changed, 1 insertions(+), 0 deletions(-)

Branches sind bei Git etwas sehr einfaches und können zügig und ohne Probleme erstellt werden. Sie eignen sich zum Entwickeln von neuen Features, die erst nach ausführlichen Tests wieder in den Haupt-Zweig gespielt werden. Sie können aber auch einfach nur dazu verwendet werden, um experimentell Dinge auszuprobieren.[2]

Entwickler 1 entscheidet sich im nächsten Schritt seinen Branch ins Repo am Server zu spielen:

:~/repos/dev-1$ git push origin dev-v1.1 
tktest@192.168.56.101's password: 
Counting objects: 5, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (3/3), done.
Writing objects: 100% (3/3), 348 bytes, done.
Total 3 (delta 1), reused 0 (delta 0)
To ssh://tktest@192.168.56.101/home/tktest/repos/dev-1
 * [new branch]      dev-v1.1 -> dev-v1.1
:~/repos/dev-1$ git branch -a
  dev-v1.1
* master
  remotes/origin/HEAD -> origin/master
  remotes/origin/dev-v1.1
  remotes/origin/master

Mittels "git push", der Angabe der Wurzel ("origin") von der er geklont hat und dem Branch "dev-v1.1" spielt er explizit seinen Branch ins Repo. Anschließend wird überprüft, ob der remote Branch auch erstellt wurde ("git branch -a"). Der neue Branch kann nun von anderen Entwicklern dazu genutzt werden, um den Entwicklungsstand in diesem Branch voranzutreiben.

Branches aktualisieren und mergen

Entwickler 2 klont nun ebenfalls das Repo und überprüft die vorhandenen Branches:

:~/repos/dev-2$ git clone ssh://tktest@192.168.56.101/home/tktest/repos/dev-1 .
Cloning into ....
tktest@192.168.56.101's password: 
remote: Counting objects: 24, done.
remote: Compressing objects: 100% (22/22), done.
remote: Total 24 (delta 3), reused 0 (delta 0)
Receiving objects: 100% (24/24), 2.47 KiB, done.
Resolving deltas: 100% (3/3), done.
:~/repos/dev-2$ git branch -a
* master
  remotes/origin/HEAD -> origin/master
  remotes/origin/dev-v1.1
  remotes/origin/master

"Git fetch" aktualisiert die Remote Branches, erstellt aber noch keine lokalen Branches.[3] Die Remote Branches erhalten ihre Aktualisierungen über das Remote Repo und werden nicht direkt vom Benutzer bearbeitet. Sie werden zuerst in einen lokalen Branch ausgecheckt bzw. gemerged, dann evtl. bearbeitet und erst dann wieder ins Remote Repo gepusht. Für die Erstellung eines lokalen Branches, basierend auf einem Remote Branch, kann folgendes Git-Kommando eingesetzt werden:

:~/repos/dev-2$ git checkout -t origin/dev-v1.1 
Branch dev-v1.1 set up to track remote branch dev-v1.1 from origin.
Switched to a new branch 'dev-v1.1'

Der Parameter "-t" gleicht der Verwendung von "--track" beim Verwenden von "git branch". Dieser Parameter garantiert die Konfiguration eines Upstreams, sodass Befehle wie "git pull" mit dem referenzierten Remote Branch arbeiten.[4] Nachdem der lokale Branch erstellt wurde, kann in diesem gearbeitet werden:

:~/repos/dev-2$ vi function1.c 
:~/repos/dev-2$ git status
# On branch dev-v1.1
# 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:   function1.c
#
no changes added to commit (use "git add" and/or "git commit -a")
:~/repos/dev-2$ git commit -a -m "version 1.2"

Ein weiteres Feature, dass ein tracking Branch bietet, sind Informationen über den aktuellen Stand gegenüber dem Remote Branch:

:~/repos/dev-2$ git status
# On branch dev-v1.1
# Your branch is ahead of 'origin/dev-v1.1' by 1 commit.
#
nothing to commit (working directory clean)

Wie oben in der Ausgabe ersichtlich, ist der lokale Branch dem Remote Branch ein Commit voraus. Diese Information ist sehr nützlich, da immer genau überprüft werden kann, inwiefern die eigene Arbeit gegenüber dem Stand im Repo voran geschritten ist. Abschließend soll der temporäre Branch von Entwickler 2 zurück in den Master Branch gemerged werden:

:~/repos/dev-2$ git checkout master
Switched to branch 'master'
:~/repos/dev-2$ git status
# On branch master
nothing to commit (working directory clean)
:~/repos/dev-2$ git merge dev-v1.1 
Updating 55e54e4..cd490b9
Fast-forward
 function1.c |    1 +
 1 files changed, 1 insertions(+), 0 deletions(-)
:~/repos/dev-2$ git status
# On branch master
# Your branch is ahead of 'origin/master' by 2 commits.

Die beiden Branches wurden durch einen sogenannten "Fast forward merge" zusammengeführt. Bei diesen Merges inkludiert der zu mergende Branch bereits alle Commits des aktuellen, es genügt daher die beiden ohne neue Commits zusammenzuführen. Normaleweise entsteht bei einem Merge immer ein neuer Commit, der die beiden aktuellsten Commits der Branches referenziert.[5] Bevor der Master Branch zurück auf den Server gepusht wird, werden die Änderungen zwischen dem lokalen und dem remote Branch inspiziert:

:~/repos/dev-2$ git diff master origin/master 
diff --git a/function1.c b/function1.c
index 633686b..90fa944 100644
--- a/function1.c
+++ b/function1.c
@@ -3,6 +3,7 @@
 
 void function1(void){
        print("function from dev-1\n");
+       printf("Version 1.2\n");
        //a comment
 }
:~/repos/dev-2$ git push origin master
tktest@192.168.56.101's password: 
Counting objects: 5, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (3/3), done.
Writing objects: 100% (3/3), 325 bytes, done.
Total 3 (delta 1), reused 0 (delta 0)
To ssh://tktest@192.168.56.101/home/tktest/repos/dev-1
   55e54e4..cd490b9  master -> master
:~/repos/dev-2$ git push origin dev-v1.1 
tktest@192.168.56.101's password: 
Total 0 (delta 0), reused 0 (delta 0)
To ssh://tktest@192.168.56.101/home/tktest/repos/dev-1
   c55afd6..cd490b9  dev-v1.1 -> dev-v1.1

Einzelnachweise

  1. Git clone man page (linux.die.net)
  2. Git Community Book - Basic branching an merging (book.git-scm.com)
  3. Tracking-branches-and-remote-tracking-branches (gitguys.com)
  4. Git branch man page (linux.die.net)
  5. Git merge man page (linux.die.net)

Das könnte Sie auch interessieren

Git Daemon
Git diff mit odt-Dateien
Git-annex