====== Git ====== Git ist eine freie Software zur [[versionsverwaltung:versionsverwaltungssysteme|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. [[wpde>Git|Quelle]] ===== Links ===== * [[http://chaosradio.ccc.de/cre130.html|Ausführlicher Podcast zu Verteilten Versionskontrollsystemen]] * **[[http://git.or.cz/course/svn.html|Git - SVN Crash Course]]** * [[http://git-scm.com/documentation|git-scm documentation]] * [[http://code.google.com/p/gitextensions/|Git Extensions]] * [[http://progit.org/|Pro Git book]] * [[http://book.git-scm.com/|The Git Community Book]] * [[http://www.pragprog.com/titles/tsgit/pragmatic-version-control-using-git|Pragmatic Version Control Using Git]] * [[http://wiki.ubuntuusers.de/Git|Git (ubuntuusers)]] * [[https://github.com/sitaramc/gitolite|Gitolite]] - Einen zentralen Git-Server mit Zugriffsrechten verwalten ===== Serversoftware ===== selbst-gehostet: * [[https://gitea.io/en-us/|gitea]] * [[https://gogs.io/docs|gogs]] * gitolite * [[software:gitlab]] * [[https://bitbucket.org/|bitbucket server]] (kommerziell, nur noch in datacenter-variante für $$$$$) * ... cloud-hosting: * [[https://github.com/|github]] * [[https://bitbucket.org/|bitbucket]] (kommerziell) * ... ===== Clientsoftware ===== * [[http://code.google.com/p/tortoisegit/|TortoiseGit]] * [[http://sourcetreeapp.com/|sourcetree]] - Git & Mercurial client (win / mac) * [[http://www.syntevo.com/smartgithg/index.html|smartgit]] - java-basierter Git & Mercurial client (kostenpflichtig) * [[https://code.google.com/p/gitextensions/|Git Extensions]] ===== 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 ([[http://www.kernel.org/pub/software/scm/git/docs/git-push.html|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): * [[netzwerke: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 * [[http://www.kernel.org/pub/software/scm/git/docs/user-manual.html#resolving-a-merge|Resolving a merge]] * [[http://weblog.masukomi.org/2008/07/12/handling-and-avoiding-conflicts-in-git|Handling and Avoiding Conflicts in Git]] * 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**: [[http://github.com/guides/ignore-for-git|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 [[https://help.github.com/en/articles/changing-a-commit-message|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 " * 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 verwerfen((alternativ: temporäres Wegräumen geänderter Dateien mit git stash)): 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 [[https://www.git-tower.com/learn/git/faq/change-author-name-email|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 ==== [[https://git-scm.com/book/en/v2/Git-Basics-Tagging|Git Basics - Tagging]] git tag -a 1.0 [-m "message like version 1.0"] **Tags übertragen**: git push --follow-tagsdauerhaft konfigurieren:git config --global push.followTags true ((''followTags = true'' in der [push]-Sektion von ~/.gitconfig)) bestimmten Tag übertragen:git push origin ((push all tags at once (not recommended!):git push --tags)) === Ä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 [[https://stackoverflow.com/a/15878581|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 https://www.atlassian.com/git/tutorials/git-lfs ===== 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-Funktion|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). [[https://www.git-tower.com/learn/git/ebook/en/command-line/advanced-topics/submodules#start|Dokumentation zu Submodulen]]. === anlegen === * Entfernte Repos: ''git submodule add URL [lokaler_Pfad_im_Repo]'' ((standard wäre der Reponame)) * 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 Zugangsdaten((siehe auch [[https://docs.gitlab.com/ee/ci/git_submodules.html|die gitlab-Doku]] dazu)). [[https://github.com/ansible/awx/issues/594|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 --recursivebzw. 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_NAMEg * Branch **lokal löschen**: git branch -d BRANCH_NAME ((forcen wenn nicht alles committed wurde: git branch -D BRANCH_NAME)) * Branch **auf Server löschen**: git push REMOTE_NAME :SERVER_BRANCH_NAME * Branch umbenennen((sollte nicht allzu leichtfertig gemacht werden, Link: https://stackoverflow.com/questions/6591213/how-do-i-rename-a-local-git-branch)): 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 * 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'' ((ggf. mit submodulen: --recurse-submodules)) * ''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 [[software:gitlab]]. ===== Einrichtung Apache + Git und webdav (Debian) ===== FIXME Diese Sektion ist wahrscheinlich veraltet und nicht mehr sinnvoll. Lieder gibt es für git und [[Apache:Apache]] kein vergleichbares Modul wie für [[versionsverwaltung: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 ==== * [[http://www.kernel.org/pub/software/scm/git/docs/howto/setup-git-server-over-http.txt|englische Anleitung]] ==== 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 [[linux:rechte#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: 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 - 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 [[netzwerke:ssl-und-tls|SSL/TLS]]-Zertifikats u. a. in diesen Fällen: - man hat ein selbst-signiertes Zertifikat erstellt bzw. - eine [[netzwerke:eigene ca für ssl|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:linux]]: eigene CA im System anmelden - [[windows:Windows]]: FIXME Lösung bei [[http://code.google.com/p/msysgit/|msysgit]]? * 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.