Git

Workflow & Begriffe


Setup

Angenommen, man hat einen Ordner, der von Git versioniert werden soll:

 > cd /Pfad/zu/Projekt/Ordner

 > git init

 > ls                                --------------------------
   + /Pfad/zu/Projekt/Ordner/     <- working directory
   |- .git/                       <- git directory / repository
   |- Datei1                         --------------------------
   |- Datei2


Von nun an ist jede Datei in einem der vier Stadien:

  • "untracked" / unprotokolliert
  • "modified" / geändert
  • "staged" / vorgemerkt
  • "commited" / gesichert

Zu Begin sind alle Dateien nicht versioniert (also untracked).


Des Weiteren gibt es drei Orte, in/zwischen denen sich die Aktionen abspielen können:

+---------------------+ +---------------------+ +----------------------+
|      working        | |       staging       | |     git directory    |
|     directory       | |         area        | |     (repository)     |
+---------------------+ +---------------------+ +----------------------+

        Datei1       stage      Datei1
          v1         ---->        v1

        Datei2       stage      Datei2       commit       (5b27c3e)
          v1         ---->        v1         ----->    Datei1, Datei2
                                                         v1      v1


          v


        Datei2       stage      Datei2       commit       (fz93gb2)
          v2         ---->        v2         ----->    Datei1, Datei2
                                                          v1      v2


------------------------------------------------------------------------

    Datei1, Datei2              checkout                  (5b27c3e)
      v1      v1     <-----------------------------    Datei1, Datei2
                                                         v1      v1

Begriffe

working directory / Arbeitskopie:

  • Dateien im working directory, die von Git versioniert werden, repräsentieren LEDIGLICH DIE VERSION, DIE ZULETZT AUSGECHECKT WURDE.
  • Macht euch immer bewusst, an welcher Version einer Datei ihr gerade arbeitet.

commit:

  • wird durch eine Prüfsumme (checksum) eindeutig referenziert
  • enthält, datum, einen "snapshot" des Ordners zu einem bestimmten Zeitpunkt und Informationen über den Commiter - Name und Email.
  • Referenz zum vorhergehenden commit. (können mehrere sein)
  • commit-message

             (fz93gb2)    ...
        (5b27c3e)  (k1621kb)
            o————o————o————o————o
                                ^
                               master
                               HEAD

checkout:

  • checksum oder branch kann ausgecheckt werden
  • Wichtig: checkout ist nur möglich, wenn das Wechseln in keinem Konflikt mit der staging area steht. Dies ist immer der Fall, wenn keine Änderung seit dem letzten Commit gestaged wurde.

HEAD & master:

  • sind also eine Art "Referenzen"
  • "HEAD" zeigt auf den Status des working directory
  • vorerst nur zum Verständnis: "master" zeigt auf den neusten Git zur Verfügung stehenden commit.

Branches: (Gits killer-feature)

  • Abzweigungen in eurem commit-tree.
  • das zusammenführen zweier Branches heißt "merge"
  • Beispiel mit merge

Operationen

Rücksetzen/Checkout
(HEAD zeigt nicht mehr auf den selben commit, wie master)


                     (fz93gb2)    ...
                (5b27c3e)  (k1621kb)
                    o————o————o————o————o
                             HEAD     master


Branch setzen
(Nicht vergessen auch auf den branch zu wechseln!)

                     (fz93gb2)    ...
                (5b27c3e)  (k1621kb)
                    o————o————o————o————o
                             HEAD     master
                           myBranch

Ändern & Commiten
(Beachte: mybranch läuft mit)

                               HEAD
                             mybranch
                                o
                               /
                    o————o————o————o————o
                                      master

                                         HEAD
                                       mybranch
                                o————o————o
                               /
                    o————o————o————o————o
                                      master

checkout master

                                       mybranch
                                o————o————o
                               /
                    o————o————o————o————o
                                      master
                                       HEAD

weiterarbeiten (optional)

                                       mybranch
                                o————o————o
                               /
                    o————o————o————o————o————o
                                           master
                                            HEAD

merge (neuer commit wird angelegt)

                                           mybranch
                                o——————o——————o
                               /               \
                    o————o————o————o————o———o———o
                                               master
                                               HEAD

beliebig verzweigbar

                               branch2
                              (81fokva)
                                  o          branch1
                                 /          (pa203jk)
                     (fz93gb2)  o————o————o————o
                (5b27c3e)    ../
                    o————o————o————o————o
                                       HEAD
                                       master


Merge im Detail

Angenommen wir wechseln auf einen neuen branch


                    o————o————o
                             HEAD
                            master
                           mybranch

                               HEAD
                             mybranch
                                o
                               /
                    o————o————o
                            master

                                    HEAD
                                  mybranch
                                o————o
                               /
                    o————o————o
                            master

Fast-Forward


                                       HEAD
                                     mybranch
                                      master
                    o————o————o————o————o

detached State

                     (fz93gb2)    ...
                (5b27c3e)  (k1621kb)
                    o————o————o————o————o
                                      master
                                       HEAD

                     (fz93gb2)    ...
                (5b27c3e)  (k1621kb)
                    o————o————o————o————o
                            HEAD      master
                           mybranch <-------------- HEAD ist aber detached, also
                                                    zwar auf dem commit, folgt aber
                                                    nicht dem branch "mybranch"

                               HEAD
                                o
                               /
                    o————o————o————o————o
                           mybranch   master

reparierbar durch merge:

                               HEAD
                             mybranch
                                o
                               /
                    o————o————o————o————o
                                      master

Branches in der Softwareentwicklung

Einsetzen von Branches als Stabilitätsmarker: (vorallem bei größeren Projekten ... nicht unbedingt in der Übungsgruppe)


                            master
                    o————o————o
                               \                  develop
                                o————o————o————o————o
                                                     \       proposed
                                                      o————o————o

Hauptbranches:

  • "master" zeigt auf den aktuellen Release
  • "develop" zeigt auf dne aktuellen Entwicklerstatus
  • "proposed" vorgeschlagene Änderungen

Ist genug Stabilität oder die Aufgabenverteilung gewährleistet, werden die Marker verschoben / Branches gemerged. (Die Begriffe und anzahl an Abstufungen sind von Projekt zu Projekt unterschiedlich)

Remote Repositories

clone:

  • Spiegel des Servers, auf dem die Kollaboration stattfindet

    Situation auf dem Server:
                 (fz93gb2)    ...
            (5b27c3e)  (k1621kb)
                o————o————o————o————o
                                   master
                                   HEAD
    


    Situation auf dem lokalen Rechner nach einem clone:
                 (fz93gb2)    ...
            (5b27c3e)  (k1621kb)
                o————o————o————o————o
                                origin/master
                                   master
                                   HEAD
    


    Nach einigen commits:
                 (fz93gb2)    ...
            (5b27c3e)  (k1621kb)
                o————o————o————o————o————o————o————o
        master
                                origin/master     HEAD
    
  • "durchstöbern" per checkout origin/16sdk5l checkout origin/master <- remote branch
  • die origin/branchname-zweige sind lokal nicht veränderbar
  • "freischalten" drei neuer Befehle "pull","fetch" und "push"
    • fetch: update des lokalen origin-trees

      Situation nach fetch:
      
                                 origin/master
                          o————o————o
                         /
              o————o————o————o————o————o
                        ^            master
              alter origin/master     HEAD
      


      Bemerke: dies ist die gleiche Situation, wie vor dem mergen zweier Branches.

      fetch bietet die Möglichkeit vor dem merge mit dem lokalen master-branch die Änderungen genau zu untersuchen.
    • pull: fetch & merge meistens reicht jedoch ein pull aus.
    • push: hochladen des lokalen origin-trees auf den Server

remote Repositories:

  • neben dem origin-Repository können auch andere remote Repos angefügt werden
  • diese können auch heruntergeladen und ausgecheckt werden
    • fetch, pull, push jeweils mit dem namen des Repos als Argument
    (siehe Kapitel 2.5 und 3.5 in "progit" für genaure Infos)

Rebase

erinnerung merge:

    vorher:             d, branch
                        o
            a    b     /
            o————o————o————o
                      c    f, master

    nachher:          d, branch ——
                        o—————    |> (könnte gelöscht werden)
            a    b     /      \ ——
            o————o————o————o———o
                      c    f   g, master
                               ^merge commit

nun zum Rebase Ein Rebase ermittelt, was im ersten Branch geändert wurde und wiederholt die Änderungen der commits für den zweiten Branch.


nach dem rebase:


            a    b
            o————o————o————o———o
                      c    f   d',branch
                        master

nun fast-forward / merge


Rebase - etwas komplexer

                                 client
                             o————o
                            /
                           /      server
                     o————o————o————o
                    /
                   /
        o————o————o————o————o
                           master

Problem:
Für verschieden (Haupt-)Programmteile "client" und "server" wurden an verschiedenen Stellen im Projekt Änderungen vorgenommen.


Angenommen der Branch "client" ist fertig, "server" jedoch noch nicht. Wie könnte man die Änderungen "sauber" commiten?


Ein Merge ist zwar meist einfacher, dennoch nicht immer angebracht, denn dadurch würde ein Verzweigter, meist unübersichtlicher Baum enstehen.


Der Rebase ermöglicht in diesem Fall die Änderungen, die seit dem Abzweigen des "master" entstanden, neu anzuwenden als wäre nie gebrancht worden.


                                server
                 o————o————o————o
                /
               /                  client
    o————o————o————o————o————o————o
                       master

Angenommen "server" ist doch fertig. Auch dessen Änderungen können neu auf client angewendet werden.


                                          client              server
    o————o————o————o————o————o————o————o————o————o————o————o————o
                       master


Rebase keine Commits die Du in ein öffentliches Repository hochgeladen hast. Wenn Du diesem Ratschlag folgst ist alles in Ordnung. Falls nicht, werden die Leute Dich hassen und Du wirst von Deinen Freunden und Deiner Familie verachtet. Wenn Du rebasing als Weg behandelst um aufzuräumen und mit Commits zu arbeiten, bevor Du sie hochlädst und wenn Du nur Commits rebased, die noch nie publiziert wurden, dann fährst Du goldrichtig. Wenn Du Commits rebased die bereits veröffentlicht wurden und Leute vielleicht schon ihre Arbeit darauf aufgebaut haben, dann bist Du vielleicht für frustrierenden Ärger verantwortlich. Quelle: progit: Kapitel 3.6