Git

aus www.kruedewagen.de, Homepage von Ralf und Judith Krüdewagen (Kruedewagen)
Wechseln zu: Navigation, Suche

Git ist ein verteiltes Revision Control System für Software und Dateien aller Art (Versionsverwaltung).

Allgemeines

worktree, Triangular Workflows
  • Git FAQ: siehe c't 20/15 S.164

Cheat Sheets

Bücher und Training

Videos

Communities

Tipps und Tricks

Git mit großen Dateien

Git wurde nicht für das Speichern sehr großer Dateien konzipiert. So werden alle Dateien vor dem Speichern auf Festplatte erst in das RAM geladen, um z.B. SHA-1 Checksummen zu bilden. Daher muss so viel RAM installiert sein, dass jede Datei einzeln hinein passt. Auch ist der I/O-Durchsatz entscheidend für die Performance.

Falls Git große Dateien verwalten soll, bietet sich die Verwendung von git-submodule an.

Alternativen:

Siehe auch:

Performance

Man sollte von Zeit und Zeit die Garbage Collection laufen lassen. Siehe GC.

Git hinter einem HTTP-Proxy

Entweder über Shell-Variable

export http_proxy=http://localhost:3128
export https_proxy=http://localhost:3128

oder in globaler Git Config ~/.gitconfig eingebaut

git config --global http.proxy http://localhost:3128
git config --global https.proxy http://localhost:3128

oder in Git Config des Repositories .git/config eingebaut

git config http.proxy http://localhost:3128
git config https.proxy http://localhost:3128

Abfrage (Resultat je nach Kontext):

git config --get http.proxy
git config --get https.proxy

Siehe auch Git Tutorial.

Achtung: Git Repositories müssen dann auch per HTTP/HTTPS angesprochen werden (nicht per git Protokoll).

Einen einfachen Git Server aufsetzen

Man benötigt nur einen Linux-Server mit Git und einem laufenden SSH Daemon.

Siehe:

Hooks

Mit Hooks können bei bestimmten Aktionen (z.B. einem Push) Scripte ausgeführt werden.

Siehe

Beispiel

Beispiel für ein Hook zum automatischen Generieren einer HTML Datei README.html aus einer Markdown Datei README.md nach einem Push:

#!/bin/sh
/usr/bin/git cat-file blob HEAD:README.md | /usr/bin/Markdown.pl > $GIT_DIR/README.html

Hinweise:

  • Der Hook wird auf dem Server im Bare-Repository als Datei .git/hooks/post-receive erstellt.

Siehe:

Hooks bei Gerrit

Gerrit unterstützt leider keine Standard-Hooks von Git, sondern nur eigene Hooks unterhalb des Installationsverzeichnisses $site_path/hooks. Daher ist es z.B. nicht so einfach möglich, nach einem erfolgten Push für jedes Repository eigene Aktionen anzustoßen.

Siehe:

Beispiel /srv/gerrit/hooks/ref-update

#!/bin/sh
/usr/bin/git cat-file blob HEAD:README.md | /usr/bin/Markdown.pl > $GIT_DIR/README.html

Hinweise:

  • ref-update wird vor einem Push ausgeführt. Daher wird ggf. eine alte README Datei umgewandelt.
  • $GIT_DIR wird auf jeden Fall unterstützt.

Upstream Branches

Tools und Software

Desktop GUIs

  • Git-GUIs im Test: siehe LM 03/14 S.56
  • gitk
  • Qgit (KDE)
  • SourceTree - für Windows und Mac
  • Smart Git (Closed Source, aber für privaten Einsatz kostenlos)
  • DeepGit (Closed Source, aber für privaten und kommerziellen Einsatz kostenlos) pro-linux.de
  • Gitg
  • Git Cola
  • Git Eye (Closed Source)
  • SmartGit, pro-linux.de, multi-RCS Client, Java, proprietär aber für private Zwecke kostenlos.

Git und KDE

Unter KDE wird beim Pushen auf Kommandozeile i.d.R. das Programm /usr/lib/ssh/ssh-askpass verwendet. Siehe Eintrag mittels:

echo $SSH_ASKPASS

Normalerweise startet dann ein KDE-Dialog zur Eingabe des Passworts und das Passwort wird im KDE-Wallet gespeichert.

Wichtig: Für das HTTP(S)-Protokoll muss in der Git-Config auch der Username hinterlegt sein, sonst klappt das Authentifizieren nicht, also z.B. so:

[remote "origin"]
        url = https://USERNAME@github.com/pfad/zum.git
        fetch = +refs/heads/*:refs/remotes/origin/*

Weblinks:

Server GUIs

  • GitLab, als Community Edition, fast wie GitHub, Issues mit Markdown etc., Ruby-basiert, am besten mit PostgreSQL und Nginx - aber auch mit MySQL und Apache möglich.
  • Gitorious Community Edition, Ruby/Rails-basiert, im Web-DocumentRoot installiert, dedizierter Installer nur für CentOS
    • noch kein Issue Tracker (aber geplant)
  • Stash, kommerziell von Atlassian, Github sehr ähnlich
  • gitweb, einfach, als CGI in Webserver eingebettet
  • Gerrit - Git Code Review und Repository Server: steuert Access Control, Projekte

Online-Dienste

Als Dienstleister:

  • Github - Free public repositories, collaborator management, issue tracking, wikis, downloads, code review, graphs and much more
    • Gist zur Verwaltung von Code-Schnipseln (simple way to share snippets and pastes with others), können secret (hidden) oder public sein, können per <script> eingebettet werden, können geklont werden.
    • GitHub Pages zur Erstellung statischer Webpages unter http://username.github.io, DNS CNAME möglich zur Verbindung zu eigener Domain, HTML-Generatoren Jekyll oder Octopress mit direkter Anbindung
  • Gitorious - Host your open source projects and their repositories for free on Gitorious to enable community contributions.
    • Plattform ist OSS
  • Bitbucket - Store all of your Git and Mercurial source code in one place with unlimited private repositories. Includes issue tracking, wiki, and pull requests. Secure hosting with flexible permissions for your repositories. Integrates with JIRA, Jenkins, Pivotal, Cloud9 IDE and other developer tools.

Continuous Integration

IDEs

Integration in Editoren und IDEs:

Git und Eclipse

Git Workflow

Git Reporting

Begriffe

  • Index = Staging Area

Kommandos

Konfiguration

  • Konfiguration von $HOME/.gitconfig
git config --global user.name 'Max Mustermann'
git config --global user.email Max.Mustermann@example.com
git config --global color.ui auto
git config --global -l
git config --global -e
man git-config
Hinweis: ohne --global wird lokale Repository-Konfig editiert, mit --system die systemweite Konfig
  • Konfiguration für einzelnes Repository
git config user.email Max.Mustermann@example.com

Lokales Repository

  • Projekt initialisieren (Vereichnis darf schon Files enthalten)
cd /etc
git init apache2

oder gleichwertig

cd /etc/apache2
git init

Hinweise:

  • erzeugt /etc/apache2/.git
  • apache2 ist das Reposhttp://stackoverflow.com/questions/2199897/how-to-convert-a-git-repository-from-normal-to-bareitory
  • Alle Files zum Index hinzufügen
cd apache2
git add *
  • Veränderung an einer einzelnen Datei zum Index hinzufügen
git add <datei>
  • Interaktiver Modus bei add zur selektiven Auswahl der Dateien
git add -i
  • Veränderungen aller Dateien in Index übertragen (Update), jedoch noch kein Commit
git add -u
  • Datei wieder aus dem Index entfernen
git rm --cached <datei>
  • Commit (direkt mit Kommentar, Kommentar wird abgefragt, verbose)
git commit -m "First commit"
git commit
git commit -v
Hinweis: git commit zeigt Änderungen an, die noch nicht im Index sind (staged), und listet noch nicht hinzugefügte Dateien
  • Commit mit Umgehung des Index (sofort vom Working Tree ins Repository)
git commit -a -m "Comment"
  • Letzten Commit widerrufen und mit neuem Kommentar bzw. neuen Dateien erneuern
git commit --amend
git commit --amend --reset-author
  • Inhalt eines Commits anzeigen (Patch Format):
git show HEAD
git show 5203edd
  • Einen Branch erzeugen
git branch next
  • Einen Branch erzeugen und direkt auschecken
git checkout -b next
  • Alle lokalen Branches anzeigen
git branch
  • Alle Branches anzeigen - auch die Remote-Tracking-Branches
git branch -a
  • Einen Branch auschecken (auf den dann die Änderungen im Working Tree wirken)
git checkout master
git checkout next
  • Einen Branch löschen
git branch -d next
  • Commit Hash zu ggf. gelöschten Branches herausfinden mittels
git reflog
  • Einen Commit auschecken
git checkout 2f562s
  • Nur eine Datei eines Braches oder Commits auschecken
git checkout master <datei>
git checkout 2f562s <datei>
  • Einen Branch next mit Änderungen nach master mergen
git checkout next
-> Datei editieren
git add <datei>
git commit
git checkout master
git merge next
git push (Änderungen Richtung Remote)
  • Empfehlenswert: Bei einem Merge auf jeden Fall eine Commit-Message erzeugen (entfällt sonst bei fast-forward Merge):
git merge next --no-ff
  • Einen Merge zurücknehmen (z.B. wenn Fehler oder Probleme auftauchten)
git reset --merge
  • Änderungen ab einem bestimmten Commit zurücknehmen (Historie bleibt aber erhalten mit git log -g)
git reset --hard 2f562s
  • Merged Branches ausgeben
git branch --merged
  • Unmerged Branches ausgeben
git branch --no-merged
  • Rebase - sinvoll um zwischenzeitige Änderungen in master in meinen Entwicklungs-Branch next zu mergen (siehe GitLab Cookbook S.53)
git checkout next
git rebase master
Hinweis: Kann sein, dass der Branch next danach mit -f gepusht werden muss.
  • Squashing - sinnvoll um Historie zu säubern, z.B. um Commits zusammenzufassen, bevor sie nach master gemerged werden [1]. Beispiel: die letzten beiden Commit zusammenfassen:
git checkout next
git rebase -i HEAD~2
Dann im Editor in der zweiten Zeile das "pick" in "squash" ändern. Und danach Commit-Message erstellen.
Hinweis: Der erste Commit kann nicht "squashed" werden.
Alternative: merge mit --squash
  • Projektgeschichte ansehen (letzte 4 Commits, zeitliche Einschränkung)
git log -4 --color-words
git log --after='2011-31-12'
git log --before='2011-31-12'
git log --since='yesterday'
git log --format=fuller
  • In Commit Message suchen
git log --grep "Bugfix:" v3..HEAD
git log --grep "README" --oneline --all
  • Nach Änderungen im Code suchen (String im Patch)
git log -G"mySuperMethod" --oneline
  • Auch tags sehen mit "decorate"
git log --oneline --decorate
  • Änderungen (Log) seit dem Tag "v3"
git log v3..HEAD
  • Unterscheide anzeigen (zum letzten Commit)
git show --color-words
git log -p --color-words
  • Unterschiede anzeigen zw. Working Tree und Index (vor Commit)
git diff --color-words
  • Unterschiede anzeigen zw. Index und Repository
git diff --staged --color-words
  • Unterschiede einer Datei zum letzten Commit
git diff <datei>
  • Unterschiede aller oder einer Datei zwischen aktueller Version und einem bestimmten Commit
git diff 6d4f69
git diff 6d4f69 <datei>
  • Zeigen welche Dateien sich seit dem Tag "v3" geändert haben
git diff --name-only v3..HEAD
git diff --name-only --diff-filter=M v3..HEAD
  • Änderungen einer Datei verfolgen
git log -p -- <datei>
git log -p --follow -p -- <datei>
  • Muster in allen Dateien durchsuchen
git grep muster
  • Muster in bestimmten Dateien durchsuchen (hier .conf)
git grep muster -- '*.conf'
  • Den aktuellsten (letzten) Tag anzeigen ausgehend von Commit
git describe

Remote Repository

  • ein existierendes lokales Repository erstmals auf einen Server pushen
git remote add origin ssh://user@gitserver/repo.git
git push -u origin master
Hinweis: "origin" ist der Name, mit dem man im folgenden das Remote Repository ansprechen kann.
  • Verbundene Remote Repositories listen
git remote
  • Komplette Zusammenfassung mit allen verfügbaren und verbundenen Branches und dem Tracking-Status
git remote show origin
  • Änderungen in den Remote Repositories in allen Remote Tracking Branches nachziehen (herunterladen)
git remote update
  • Status der Remote Tracking Branches abfragen:
git branch -vv
  • Änderungen des Remote Tracking Branches (per "fetch" oder "remote update" zuvor aktualisiert) zum ausgecheckten Branch anzeigen (ohne vorheriges "pull", d.h. ohne Änderungen bereits im lokalen Branch übernommen zu haben) und erst dann übernehmen
git log -p ..@{u}
git merge --ff-only @{u}

  • URL eines Remote Repositorys ändern
git remote set-url origin https://...
  • Clone erzeugen mit Referenz auf Origin
git clone ssh://user@gitserver/repo.git
  • Nach einem Fork zukünftig auch Updates der Originals einpflegen (Branch updates/master)
git remote add updates ssh://user@gitserver/repo.git
git fetch updates
git merge updates/master
  • Einen (lokalen) Branch auschecken (auf den dann die Änderungen im Working Tree wirken)
git checkout master

oder für Branch next

git checkout next
  • Einen Remote-Branch auschecken (der lokal noch nicht existiert) und dabei einen neuen lokal erzeugen [2]
 git checkout -b local-name origin/remote-name
  • Einen neuen Remote-Branch, der nicht lokal existiert, in den aktuellen Branch mergen (ohne Remote-Branch zuvor lokal auszuchecken):
git fetch     (nicht "git merge" !!!)
git log origin/branch-new
git merge origin/branch-new
  • Änderungen vom Remote herunterladen und direkt mergen
git pull
  • Auch Tags herunterladen
git pull --tags
  • Änderungen nach Commit zum Remote hochladen (Origin darf nicht bare sein, s.u.)
git push
  • Auch Tags hochladen
git push --tags
  • Lokal gelöschte Tags remote löschen
git push --prune --tags
  • Neue lokale Branches nach Remote pushen
Einen (neuen) Branch einmalig nach Remote pushen (wird dort automatisch erzeugt)
git push origin next
git push --all
Oder besser den neuen Branch dabei sofort in die Upstream-Konfig übernehmen, damit nachfolgend git push ausreicht:
git push -u origin next
Oder (nachträglich) den Upstream umkonfigurieren, Remote Branch origin/alpha muss jedoch schon existieren - ggf. mit Gerrit anlegen und pullen [3]
git branch -u origin/alpha alpha
  • Konfig .git/config
[remote "origin"]
        url = ssh://user@gitserver/repo
        fetch = +refs/heads/*:refs/remotes/origin/*
[branch "master"]
        remote = origin
        merge = refs/heads/master
[branch "next"]
        remote = origin
        merge = refs/heads/next
  • Eine Branch remote löschen
git push origin --delete branch-to-delete

Remote Repository auf gleichem Host

  • Clone erzeugen mit Referenz auf Origin
cd /tmp
git clone /etc/apache2

erzeugt /tmp/apache2

  • Für einen Push von Änderungen nach Origin muss das Origin bare sein (ohne .git, ohne working directory). Siehe auch [4]. Daher sollte in so einem Fall das Origin so erzeugt werden:
cd /etc/apache2
git init --bare
Server wie Gerrit erzeugen Repositories standardmäßig als "bare" ohne working directory.
Siehe [5] wie man von non-bare nach bare konvertiert, z.B. mittels
git clone --bare /etc/apache2

erzeugt Verzeichnis

apache2.git

Patches

Patch erzeugen

  • Repository auschecken
  • Datei(en) ändern
  • Prüfen der Änderungen
git status
git diff
  • Änderungen committen
git commit -a -m "Fixed ...."
  • Patch-Datei erzeugen (zum letzten Commit mit "-1") mit Endung .patch
git format-patch -1

Beispiel-Datei:

From 41a9da71595c9d2d793cbbb678b720f000c5c9d9 Mon Sep 17 00:00:00 2001
From: Max Mustermann <max@mustermann.de>
Date: Sun, 5 Apr 2015 17:49:02 +0200
Subject: [PATCH] declare i outside the loop fixes C99 compile error

refs #8986
---
 base/utils.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/base/utils.c b/base/utils.c
index 9924a03..53f8a69 100644
--- a/base/utils.c
+++ b/base/utils.c
@@ -300,7 +300,8 @@ pthread_mutex_t registered_fds_lock;
 
 int init_registered_fds(void)
 {
-	for (int i = 0; i < REGISTERED_FD_MAX; i++) {
+	int i;
+	for (i = 0; i < REGISTERED_FD_MAX; i++) {
 		registered_fds[i] = -1;
 	}
 
-- 
2.3.4

Patch einspielen

  • neuen Branch in master erzeugen
git checkout -b newbranch
  • Patch anwenden
git am --signoff <patchfile>
  • Commit ersetzen/ergänzen
git commit --amend

Siehe auch

Siehe auch