Git
Git ist eine freie Software zur verteilten Versionsverwaltung von Dateien. Es wurde ursprünglich für die Quellcode-Verwaltung des Linux-Kernels entwickelt.
Die Entwicklung von Git wurde im April 2005 von Linus Torvalds begonnen, um das bis dahin verwendete Versionskontrollsystem BitKeeper zu ersetzen, welches durch eine Lizenzänderung vielen Entwicklern den Zugang verwehrte. Die erste Version erschien bereits wenige Tage nach der Ankündigung.
Links
- Gitolite - Einen zentralen Git-Server mit Zugriffsrechten verwalten
Serversoftware
selbst-gehostet:
- gitolite
- bitbucket server (kommerziell, nur noch in datacenter-variante für $$$$$)
- …
cloud-hosting:
- bitbucket (kommerziell)
- …
Clientsoftware
- sourcetree - Git & Mercurial client (win / mac)
- smartgit - java-basierter Git & Mercurial client (kostenpflichtig)
Befehle
Liste der Befehl ausgeben:
git help
usage: git [--version] [--exec-path[=GIT_EXEC_PATH]] [-p|--paginate|--no-pager] [--bare] [--git-dir=GIT_DIR] [--work-tree=GIT_WORK_TREE] [--help] COMMAND [ARGS] The most commonly used git commands are: add Add file contents to the index bisect Find the change that introduced a bug by binary search branch List, create, or delete branches checkout Checkout a branch or paths to the working tree clone Clone a repository into a new directory commit Record changes to the repository diff Show changes between commits, commit and working tree, etc fetch Download objects and refs from another repository grep Print lines matching a pattern init Create an empty git repository or reinitialize an existing one log Show commit logs merge Join two or more development histories together mv Move or rename a file, a directory, or a symlink pull Fetch from and merge with another repository or a local branch push Update remote refs along with associated objects rebase Forward-port local commits to the updated upstream head reset Reset current HEAD to the specified state rm Remove files from the working tree and from the index show Show various types of objects status Show the working tree status tag Create, list, delete or verify a tag object signed with GPG See 'git help COMMAND' for more information on a specific command.
Export eines Repos
branch master archivieren („exportieren“), normalerweise geht das direkt in ein .tar.gz, hier in ein Verzeichnis /tmp/meinRepo
:
cd $Repo && git archive master | tar -x -C /tmp/meinRepo
Arbeiten mit Repositories
Lokales Repo neu anlegen (Unterordner .git wird erstellt):
git init
Änderungen in anderes Repo übertragen (git-push)
Client konfigurieren
Globale Einstellungen (ohne –global gilt es nur für das aktuelle Repo):
git config --global user.name "Vorname Nachname" git config --global user.email meine.email@domain.tld
- Einstellungen anzeigen (globale und die vom Repo):
git config --list
Adress-Schema
Entfernte Repositories werden über diese Wege angesprochen (hier Beispiel mit clone):
- SSH:
git clone user@domain.tld/local/path/to/git/repo
- HTTP/HTTPS: git clone https://domain.tld
Methode 1: leeres Repo clonen und eine erste Änderung vornehmen
Lokal ist nichts vorhanden und das Zielrepo ist leer:
git clone $ADRESSE cd $REPONAME touch README.md git add README.md git commit -m "habe README angelegt" git push -u origin master
Methode 2: vorhandener Ordner (ohne git)
cd Ordner_ohne_git_versionierung git init git remote add origin $ADRESSE git add . git commit -m "Initial commit" git push -u origin master
Methode 2: vorhandener Ordner (mit git)
cd Ordner_mit_git_repo git remote rename origin old-origin git remote add origin $ADRESSE git push -u origin --all git push -u origin --tags
Änderungen vornehmen und tracken
- Dateien hinzufügen:
git add Datei/Verzeichnis
- Commit (=Änderungen übertragen) absetzen:
- beim ersten mal:
git commit -m "Kommentar";
danach:
- Fall 1: Datei hingekommen?
git add neueDatei
- Fall 2: nur vorhandene Dateien geändert?
git commit -a -m "Kommentar"
- Konflikte beheben
- Anzeige der Änderungen
- Commit-Historie:
git log
- seit letztem Commit (bzw. dem aktuellen Stand, also der letzten Aktualisierung des Repository-Index):
git diff
- seit letztem Commit und Stand:
git diff HEAD
- Änderungen zwischen dem letzten Commit und dem Tag „TestTag“:
git diff TestTag HEAD
- Commit-Vergleich vom letzten Commit zum vorletzten Commit:
git show
- Dateien ignorieren: Guides: Ignore for Git
sauberes git pull
Wenn in einem lokalen Repo viele Änderungen vorgenommen werden (die nicht committed sind) kann git pull schlägt fehlschlagen weil lokale Dateien und Änderungen überschrieben werden würden. In diesem Fall kann es sinnvoll sein das lokale Verzeichnis komplett „sauber“ zu machen, also alles nicht versionierte zu löschen:
git reset --hard git clean -fdx git pull
Änderungen zurücknehmen
- lokale Änderungen zurücknehmen (wie svn revert):
git checkout PFAD_ODER_DATEI
- Datei doch nicht committen:
git reset HEAD PFAD_ODER_DATEI
- letzte commit message ändern (öffnet Editor zur Änderung):
git commit --amend
- Falls der commit bereits an entfernte Repositories gesendet wurde ist die Reparatur mit rebase und force push möglich (hat aber gravierende Auswirkungen auf Dritte)
- Author / E-Mail beim letzten commit ändern:
git commit --amend --author="John Doe <john@doe.org>"
- mehrere lokale commits mit der falschen user.email sind mit diesem Skript änderbar (leider nicht mit rebase), erfordert aber wieder force push falls bereits übertragen:
git filter-branch --env-filter ' OLD_EMAIL="OLD@example.com" NEW_NAME="NEW NAME" NEW_EMAIL="NEW@example.com" if [ "$GIT_COMMITTER_EMAIL" = "$OLD_EMAIL" ] then export GIT_COMMITTER_NAME="$NEW_NAME" export GIT_COMMITTER_EMAIL="$NEW_EMAIL" fi if [ "$GIT_AUTHOR_EMAIL" = "$OLD_EMAIL" ] then export GIT_AUTHOR_NAME="$NEW_NAME" export GIT_AUTHOR_EMAIL="$NEW_EMAIL" fi ' --tag-name-filter cat -- --branches --tags
weitere Informationen bei der Quelle: https://mhagemann.medium.com/how-to-change-the-user-for-all-your-git-commits-ffefbacf2652
- Modifizierungen endgültig verwerfen1):
git checkout -- PFAD_ODER_DATEI
- rebase: grundlegende Änderungen vornehmen (potentiell desktruktiv, es sollten keine gepushten Commits verändert werden!):
- git rebase -i -p $HASH_DES_LETZEN_GUTEN_COMMITS
- Anschließend können für die nachfolgenden Commits diese Befehle ausgeführt werden:
# Befehle: # p, pick = Commit verwenden # r, reword = Commit verwenden, aber Commit-Beschreibung bearbeiten # e, edit = Commit verwenden, aber zum Nachbessern anhalten # s, squash = Commit verwenden, aber mit vorherigem Commit vereinen # f, fixup = wie "squash", aber diese Commit-Beschreibung verwerfen # x, exec = Befehl (Rest der Zeile) mittels Shell ausführen # d, drop = Commit entfernen
weitere Informationen siehe How can I change the author name / email of a commit?.
Pull Request (PR) erstellen
Ein Pull Request (PR) bietet die Möglichkeit der vier (oder mehr) Augenprüfung.
# branch erstellen git branch myChanges origin/master git checkout myChanges # Änderungen vornemen + committen git push --set-upstream origin myChanges
Kurzform (commit ID: b50b2e7):
git checkout -b miniBranch b50b2e7 git push --set-upstream origin miniBranch
Bei beiden Methoden wird die URL zurückgeliefert wo der PR erstellt werden kann.
Tags
git tag -a 1.0 [-m "message like version 1.0"]
Tags übertragen:
git push --follow-tags
dauerhaft konfigurieren:
git config --global push.followTags true
bestimmten Tag übertragen:
git push origin <tag_name>
Änderungen zwischen Tags anzeigen
Hier zwischen $TAG (ersetzen!) und HEAD:
git log --pretty=oneline $TAG...HEAD
Anderes Format:
git log --pretty=format:"%h; author: %cn; date: %ci; subject:%s" $TAG...HEAD
→ auf branch master beschränken: --first-parent master (Einschränkung: funktioniert nicht für fast-forward-merges, siehe git log to return only the commits made to the master branch?.
Leere Verzeichnisse einchecken
Leere Verzeichnisse werden standardmäßig nicht benutzt, ein verbreiteter work-around ist eine Datei .gitkeep in das Verzeichnis zu legen.
find . -type d -empty -not -path "./.git/*" -exec touch {}/.gitkeep \;
git lfs (Large File Storage)
du brauchst serverseitig nur die Unterstützung. Im Repo musst du das mit dem client machen:
- git-lfs lokal installieren (bei ubuntu ein extra Paket)
- repo clonen
- cd repo
- git lfs install
- git lfs track *.iso (behandelt als iso-Dateien mit lfs)
- → legt .gitattributes an mit Inhalt: *.iso filter=lfs diff=lfs merge=lfs -text
- git add .gitattributes
- git commit .gitattributes
Verzeichnisaufbau
- Aufbau des internen .git Verzeichnissses:
- config (Datei): Konfiguration, sehr einfaches Beispiel:
[core] repositoryformatversion = 0 filemode = true bare = false logallrefupdates = true
- index (Datei): Metadaten, auch als „Staging Area“ bezeichnet
- info (Unterverzeichnis):
- exclude : enthält Dateinamen von Dateien die von der Versionverwaltung ausgeschlossen sind
- logs (Unterverzeichnis): Historie
- objects (Unterverzeichnis): Repository Struktur
- refs (Unterverzeichnis): Verweise innerhalb des Repository
Objektypen
- Objektypen (zlib-komprimiert; mit SHA-1 Hash ansprechbar)
- Commit - bestimmter Änderungszeitpunkt, besteht aus diesen Elementen:
- Kommentar (auch „Commit-message“)
- Information über Zeit und Autor
- Verweise auf (beliebig viele) übergeordnete Commits („parents“)
- Zeiger auf einen Tree
- Tree - Liste von Dateien
- Blob - speichert beliebige Dateinhalte
- Tag - Beschriftung oder Etikett (Verweis auf ein Commit-Objekt das mit Namen und Kommentar „tag message“). Nützlich für Versionbezeichnung und auch GPG-Signatur möglich.
Submodules
Git kann andere Repositories referenzieren (diese als Submodule einbinden). Dokumentation zu Submodulen.
anlegen
- Entfernte Repos:
git submodule add URL [lokaler_Pfad_im_Repo]
4) - Auf gleichem Speicherort/Ebene mit relativer URL:
git submodule add ../URL [lokaler_Pfad_im_Repo]
. Relative Adresse verhindern eine Mischung unterschiedlicher Zugriffsformen (ssh/https) und ggf. damit extra Abfragen von Zugangsdaten5). awx kommt mit einer Mischung nicht klar. - Gefolgt von
git commit -a
(und ggf.git push
)
benutzen
Der Clone-Befehl erweitert sich dadurch:
git clone --recurse-submodules URL
Sub-Module aktualisieren:
git submodule update --init --recursive
bzw. im Verzeichnis des Submoduls:
git pull origin master
Links: https://www.git-tower.com/learn/git/ebook/en/command-line/advanced-topics/submodules#start
Submodule entfernen
git submodule deinit path/to/submodule
git rm path/to/submodule
workflow Spiegelung entfernter Repos
Für den Fall das ein entferntes Repo gespiegelt werden soll, aber entfernte Änderungen nochmal überprüft werden sollen:
- Repo auf Server anlegen
- clonen nach Lokal
- Lokales Repo bekommt upstream:
git remote add upstream https://github.com/REPO
- Lokales Repo abgleichen mit entfernt:
git pull upstream master
- Lokales Repo mit eigenem Server syncronisieren:
git push origin master
Branches
- Branches (master ist der standard-branch; aktiver Branch mit „*“ gekennzeichnet)
- Liste der Branches ausgeben:
git branch
- neuen Branch anlegen:
git branch BRANCH_NAME
- Wechsel in (diesen) neuen Branch:
git checkout BRANCH_NAME
- zurückführen in master:
- zuerst zurück in master wechseln:
git checkout master
- Änderung aus BRANCH_NAME in master mergen:
git pull . BRANCH_NAME
- neuen Branch auch in entfernten Repos anlegen:
git push -u origin BRANCH_NAME
- Branch lokal löschen:
git branch -d BRANCH_NAME
- Branch auf Server löschen:
git push REMOTE_NAME :SERVER_BRANCH_NAME
- Branch umbenennen7):
git branch -m ALT NEU
- lokale Branches aufräumen, wenn bereits auf Server gelöscht:
git remote prune [SERVER_BRANCH_NAME]
oder besser: verbindet sich vorher nochmal mit dem entfernten repo und aktualisiert die branch-liste:
git fetch -p
- in welchem branch ist der commit ID?:
git branch -r --contains <commit>
- commits in myBRANCH zu einem commit zusammenfügen („squashen“):
git checkout master git merge --no-commit --squash $myBRANCH git commit
- Änderungen auf HEAD losgelöst von $CommitID („detached HEAD“)
git push origin HEAD:master
git checkout master && git merge [ref of HEAD]
gemeinsamer Zugriff
- Mehrbenutzerzugang (zentral erreichbarer Datei-Speicher)
- Benutzerberechtigungen in Datei „allowed-users“ in Verzeichnis:
.git/info/
- Patches austauschen (geht auch per eMail die sich als mbox-Datei wieder einzupflegen gehen); Beispiel: alle Änderungen als Patch die NICHT in „original“ enthalten sind:
git format-patch original
workflow-Beispiel merge-request mit gitlab
Ablauf: auschecken, eigenen branch anlegen, committen, pushen, merge-request
git clone REPOADRESSE
8)git checkout -b Zweck
(branch „Zweck“ anlegen)git commit -a -m Änderungsmitteilung
git push origin Zweck
(branch „Zweck“ wieder auf den ursprünglichen branch, z.B. master, zurückübertragen)- ⇒ Bei Erfolg gibt es einen Meldung mit dem Deeplink für den merge-request zurück
Einrichtung Gitlab
siehe Seite von gitlab.
Einrichtung Apache + Git und webdav (Debian)
Diese Sektion ist wahrscheinlich veraltet und nicht mehr sinnvoll.
Lieder gibt es für git und Apache kein vergleichbares Modul wie für Subversion. Somit hat diese Zugangsmethode folgende Nachteile:
- es können keine detaillierten Rechte für die unterschiedlichen Benutzer gesetzt werden
- git-hooks werden nicht ausgeführt
Links
Server konfigurieren
- Git installieren (als root bzw. mit sudo):
aptitude install git-core
- Verzeichnis für das Repository anlegen:
mkdir /srv/git/git-repos
- optional:
- Gruppe für git-Benutzer erstellen:
groupadd gitusers
- Benutzer hinzufügen:
addgroup [USER] gitusers
- Leeres git-Repository erzeugen:
cd /srv/git/git-repos/REPO1 && git --bare init
- Verzeichnis-/Dateirechte erteilen, Beispiel mit umask 027 (Gruppe ggf. von gitusersändern falls sie oben nicht angelegt wurde):
chmod 770 /srv/git/git-repos && chown -R www-data:gitusers /srv/git/git-repos/* && chmod g+wX /srv/git/git-repos/*
- Module für WebDAV aktivieren:
a2enmod dav dav_fs
- Apache2 konfigurieren: in /etc/apache2/sites-available einen virtuellen Host konfigurieren und zusätzlich für die Git-Location folgendes konfigurieren:
<Location /git-repos > DAV on AuthType Basic AuthName "Git Repository - consider using ssl to protect your credentials" #AuthBasicProvider file # (is default anyway; needs mod_authn_file which is loaded) AuthUserFile /etc/apache2/git_passwd Require valid-user #for inital tests: #Allow from all </Location>
- Zugangsdaten in
/etc/apache2/git_passwd
hinterlegen:htpasswd -c /etc/apache2/git_passwd USER
- Syntax überprüfen:
apache2 -t
- Apache2 neustarten:
apache2ctl restart
ODER
/etc/init.d/apache2 restart
Fehlerbehebung
src refspec master does not match any
Dieser Fehler tritt bei ersten push auf, wenn lokal noch gar kein master-branch existiert. Lösung: Den ersten commit machen und dann den push.
SSL-Verifizierung schlägt fehl (return code 60)
Ein push schlägt mit folgender Fehlermeldung fehl:
error: Cannot access URL https://user@host.old/repo/, return code 60 error: failed to push some refs to 'https://user@host.old/repo/'
Der Grund ist eine fehlgeschlagene Verifizierung des SSL/TLS-Zertifikats u. a. in diesen Fällen:
- man hat ein selbst-signiertes Zertifikat erstellt bzw.
- eine eigene CA aufgesetzt hat, die dem System unbekannt ist.
Temporäre Lösung (für selbst-signierte Zertifikate)
- in der Datei ~./bashrc folgendes eintragen
export GIT_SSL_NO_VERIFY=true
- oder in
~/.gitconfig
http.sslVerify=false
Permanente Lösung
- linux: eigene CA im System anmelden
- http.sslCAInfo: File containing the certificates to verify the peer with when fetching or pushing over HTTPS. Can be overridden by the GIT_SSL_CAINFO environment variable.
- http.sslCAPath: Path containing files with the CA certificates to verify the peer with when fetching or pushing over HTTPS. Can be overridden by the GIT_SSL_CAPATH environment variable.
followTags = true
in der [push]-Sektion von ~/.gitconfiggit push --tags
git branch -D BRANCH_NAME