Unterschiede
Hier werden die Unterschiede zwischen zwei Versionen angezeigt.
| Beide Seiten der vorigen Revision Vorhergehende Überarbeitung Nächste Überarbeitung | Vorhergehende Überarbeitung | ||
| versionsverwaltung:git [2020/09/13 07:14] – [Änderungen zwischen Tags anzeigen] st | versionsverwaltung:git [2025/03/30 22:15] (aktuell) – [Änderungen zurücknehmen] st | ||
|---|---|---|---|
| Zeile 1: | Zeile 1: | ||
| + | ====== Git ====== | ||
| + | |||
| + | |||
| + | Git ist eine freie Software zur [[versionsverwaltung: | ||
| + | |||
| + | 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> | ||
| + | |||
| + | ===== Links ===== | ||
| + | |||
| + | * [[http:// | ||
| + | * **[[http:// | ||
| + | * [[http:// | ||
| + | * [[http:// | ||
| + | * [[http:// | ||
| + | * [[http:// | ||
| + | * [[http:// | ||
| + | * [[http:// | ||
| + | * [[https:// | ||
| + | |||
| + | |||
| + | ===== Serversoftware ===== | ||
| + | |||
| + | selbst-gehostet: | ||
| + | * [[https:// | ||
| + | * [[https:// | ||
| + | * gitolite | ||
| + | * [[software: | ||
| + | * [[https:// | ||
| + | * ... | ||
| + | |||
| + | cloud-hosting: | ||
| + | * [[https:// | ||
| + | * [[https:// | ||
| + | * ... | ||
| + | |||
| + | ===== Clientsoftware ===== | ||
| + | |||
| + | * [[http:// | ||
| + | * [[http:// | ||
| + | * [[http:// | ||
| + | * [[https:// | ||
| + | |||
| + | |||
| + | ===== 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: | ||
| + | | ||
| + | | ||
| + | | ||
| + | | ||
| + | | ||
| + | | ||
| + | | ||
| + | | ||
| + | | ||
| + | | ||
| + | | ||
| + | | ||
| + | | ||
| + | | ||
| + | | ||
| + | | ||
| + | | ||
| + | | ||
| + | | ||
| + | | ||
| + | | ||
| + | |||
| + | See 'git help COMMAND' | ||
| + | </ | ||
| + | |||
| + | ==== Export eines Repos ==== | ||
| + | |||
| + | branch master archivieren (" | ||
| + | <code bash>cd $Repo && git archive master | tar -x -C / | ||
| + | ===== Arbeiten mit Repositories ===== | ||
| + | |||
| + | Lokales Repo neu anlegen (Unterordner .git wird erstellt): < | ||
| + | |||
| + | Änderungen in anderes Repo übertragen ([[http:// | ||
| + | |||
| + | ==== Client konfigurieren ==== | ||
| + | |||
| + | **Globale Einstellungen** (ohne --global gilt es nur für das aktuelle Repo): | ||
| + | * <code bash>git config --global user.name " | ||
| + | git config --global user.email meine.email@domain.tld</ | ||
| + | * Einstellungen anzeigen (globale und die vom Repo): <code bash>git config --list</ | ||
| + | |||
| + | ==== Adress-Schema ==== | ||
| + | |||
| + | Entfernte Repositories werden über diese Wege angesprochen (hier Beispiel mit clone): | ||
| + | * [[netzwerke: | ||
| + | * HTTP/HTTPS: git clone https:// | ||
| + | |||
| + | ==== Methode 1: leeres Repo clonen und eine erste Änderung vornehmen ==== | ||
| + | |||
| + | Lokal ist nichts vorhanden und das Zielrepo ist leer: | ||
| + | |||
| + | <code bash> | ||
| + | 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) ==== | ||
| + | |||
| + | <code bash> | ||
| + | cd Ordner_ohne_git_versionierung | ||
| + | git init | ||
| + | git remote add origin $ADRESSE | ||
| + | git add . | ||
| + | git commit -m " | ||
| + | git push -u origin master | ||
| + | </ | ||
| + | |||
| + | ==== Methode 2: vorhandener Ordner (mit git) ==== | ||
| + | |||
| + | <code bash> | ||
| + | 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**: | ||
| + | * **Commit** (=Änderungen übertragen) absetzen: | ||
| + | * beim ersten mal: < | ||
| + | * Fall 1: Datei hingekommen? | ||
| + | * Fall 2: nur vorhandene Dateien geändert? < | ||
| + | * **Konflikte** beheben | ||
| + | * [[http:// | ||
| + | * [[http:// | ||
| + | * Anzeige der **Änderungen** | ||
| + | * Commit-Historie: | ||
| + | * seit letztem Commit (bzw. dem aktuellen Stand, also der letzten Aktualisierung des Repository-Index): | ||
| + | * seit letztem Commit und Stand: < | ||
| + | * Änderungen zwischen dem letzten Commit und dem Tag " | ||
| + | * Commit-Vergleich vom letzten Commit zum vorletzten Commit: < | ||
| + | * **Dateien ignorieren**: | ||
| + | |||
| + | ==== 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 " | ||
| + | |||
| + | < | ||
| + | git reset --hard | ||
| + | git clean -fdx | ||
| + | git pull | ||
| + | </ | ||
| + | ==== Änderungen zurücknehmen ==== | ||
| + | |||
| + | * lokale Änderungen zurücknehmen (wie svn revert): < | ||
| + | * Datei doch nicht committen: < | ||
| + | git restore --staged UNGEWOLLTER_PFAD_ODER_DATEI | ||
| + | # man kann sogar den gleichen commit wieder benutzen: | ||
| + | git commit -c ORIG_HEAD | ||
| + | </ | ||
| + | * letzte commit message ändern (öffnet Editor zur Änderung): < | ||
| + | * Falls der commit bereits an entfernte Repositories gesendet wurde ist die [[https:// | ||
| + | * Author / E-Mail beim letzten commit ändern: <code bash>git commit --amend --author=" | ||
| + | * nachträglich letzten commit signen: <code bash>git commit -S --amend</ | ||
| + | * 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: | ||
| + | OLD_EMAIL=" | ||
| + | NEW_NAME=" | ||
| + | NEW_EMAIL=" | ||
| + | if [ " | ||
| + | then | ||
| + | export GIT_COMMITTER_NAME=" | ||
| + | export GIT_COMMITTER_EMAIL=" | ||
| + | fi | ||
| + | if [ " | ||
| + | then | ||
| + | export GIT_AUTHOR_NAME=" | ||
| + | export GIT_AUTHOR_EMAIL=" | ||
| + | fi | ||
| + | ' --tag-name-filter cat -- --branches --tags</ | ||
| + | * Modifizierungen endgültig verwerfen((alternativ: | ||
| + | * rebase: grundlegende Änderungen vornehmen (potentiell desktruktiv, | ||
| + | * git rebase -i -p $HASH_DES_LETZEN_GUTEN_COMMITS | ||
| + | * Anschließend können für die nachfolgenden Commits diese Befehle ausgeführt werden:< | ||
| + | # 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 " | ||
| + | # x, exec = Befehl (Rest der Zeile) mittels Shell ausführen | ||
| + | # d, drop = Commit entfernen | ||
| + | </ | ||
| + | |||
| + | |||
| + | |||
| + | ==== Pull Request (PR) erstellen ==== | ||
| + | |||
| + | Ein Pull Request (PR) bietet die Möglichkeit der vier (oder mehr) Augenprüfung. | ||
| + | <code bash> | ||
| + | # branch erstellen | ||
| + | git branch myChanges origin/ | ||
| + | git checkout myChanges | ||
| + | # Änderungen vornemen + committen | ||
| + | git push --set-upstream origin myChanges | ||
| + | </ | ||
| + | |||
| + | Kurzform (commit ID: b50b2e7): | ||
| + | <code bash> | ||
| + | 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. | ||
| + | |||
| + | ==== PGP signing ==== | ||
| + | |||
| + | **Keymanagement**: | ||
| + | * erstellen: < | ||
| + | gpg (GnuPG) 2.2.20; Copyright (C) 2020 Free Software Foundation, Inc. | ||
| + | This is free software: you are free to change and redistribute it. | ||
| + | There is NO WARRANTY, to the extent permitted by law. | ||
| + | |||
| + | Please select what kind of key you want: | ||
| + | (1) RSA and RSA (default) | ||
| + | (2) DSA and Elgamal | ||
| + | (3) DSA (sign only) | ||
| + | (4) RSA (sign only) | ||
| + | (14) Existing key from card | ||
| + | Your selection? 1 | ||
| + | RSA keys may be between 1024 and 4096 bits long. | ||
| + | What keysize do you want? (2048) 4096 | ||
| + | Requested keysize is 4096 bits | ||
| + | Please specify how long the key should be valid. | ||
| + | 0 = key does not expire | ||
| + | < | ||
| + | <n>w = key expires in n weeks | ||
| + | <n>m = key expires in n months | ||
| + | <n>y = key expires in n years | ||
| + | Key is valid for? (0) | ||
| + | Key does not expire at all | ||
| + | Is this correct? (y/N) y | ||
| + | |||
| + | GnuPG needs to construct a user ID to identify your key. | ||
| + | |||
| + | Real name: Stefan Schwarz | ||
| + | Email address: stefan.schwarz@domain.tld | ||
| + | Comment: | ||
| + | You selected this USER-ID: | ||
| + | " | ||
| + | |||
| + | Change (N)ame, (C)omment, (E)mail or (O)kay/ | ||
| + | We need to generate a lot of random bytes. It is a good idea to perform | ||
| + | some other action (type on the keyboard, move the mouse, utilize the | ||
| + | disks) during the prime generation; this gives the random number | ||
| + | generator a better chance to gain enough entropy. | ||
| + | We need to generate a lot of random bytes. It is a good idea to perform | ||
| + | some other action (type on the keyboard, move the mouse, utilize the | ||
| + | disks) during the prime generation; this gives the random number | ||
| + | generator a better chance to gain enough entropy. | ||
| + | gpg: key 3DD879D552CC995F marked as ultimately trusted | ||
| + | gpg: directory '/ | ||
| + | gpg: revocation certificate stored as '/ | ||
| + | public and secret key created and signed. | ||
| + | |||
| + | pub | ||
| + | CFEF13CC5040450E63CC1BC43DD879D552CC995F | ||
| + | uid Stefan Schwarz < | ||
| + | sub | ||
| + | * anzeigen: <code bash>gpg --list-secret-keys --keyid-format=long</ | ||
| + | gpg: checking the trustdb | ||
| + | gpg: marginals needed: 3 completes needed: 1 trust model: pgp | ||
| + | gpg: depth: 0 valid: | ||
| + | / | ||
| + | ------------------------------- | ||
| + | sec | ||
| + | CFEF13CC5040450E63CC1BC43DD879D552CC995F | ||
| + | uid | ||
| + | ssb | ||
| + | * testen: <code bash> | ||
| + | * Pubkey anzeigen: <code bash>gpg --armor --export 3DD879D552CC995F # kurze ID</ | ||
| + | * Backup des private keys: <code bash>gpg --export-secret-keys --armor CFEF13CC5040450E63CC1BC43DD879D552CC995F > ~/ | ||
| + | |||
| + | * pgp-signing in git aktivieren: | ||
| + | * <code bash>git config --global commit.gpgsign true</ | ||
| + | * <code bash>git config --global user.signingkey 3DD879D552CC995F # KurzID</ | ||
| + | * :!: Auf dem git-server muss noch im Benutzerprofil der pubkey hinterlegt werden. | ||
| + | |||
| + | Quelle: https:// | ||
| + | === Fehlerbehandlung === | ||
| + | |||
| + | < | ||
| + | Lösung: <code bash> | ||
| + | |||
| + | -> permanent in z.B. .bashrc eintragen. | ||
| + | |||
| + | |||
| + | ==== Tags ==== | ||
| + | |||
| + | [[https:// | ||
| + | |||
| + | <code bash>git tag -a 1.0 [-m " | ||
| + | |||
| + | **Tags übertragen**: | ||
| + | |||
| + | bestimmten Tag übertragen:< | ||
| + | |||
| + | |||
| + | |||
| + | === Änderungen zwischen Tags anzeigen === | ||
| + | |||
| + | |||
| + | Hier zwischen $TAG (ersetzen!) und HEAD: | ||
| + | <code bash>git log --pretty=oneline $TAG...HEAD</ | ||
| + | |||
| + | Anderes Format: | ||
| + | <code bash>git log --pretty=format:" | ||
| + | |||
| + | -> auf branch master beschränken: | ||
| + | |||
| + | |||
| + | ==== Leere Verzeichnisse einchecken ==== | ||
| + | |||
| + | Leere Verzeichnisse werden standardmäßig nicht benutzt, ein verbreiteter work-around ist eine Datei .gitkeep in das Verzeichnis zu legen. | ||
| + | |||
| + | <code bash> | ||
| + | |||
| + | |||
| + | |||
| + | ==== 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:// | ||
| + | ===== Verzeichnisaufbau ===== | ||
| + | |||
| + | * **Aufbau des internen .git Verzeichnissses**: | ||
| + | * config (Datei): Konfiguration, | ||
| + | [core] | ||
| + | repositoryformatversion = 0 | ||
| + | filemode = true | ||
| + | bare = false | ||
| + | logallrefupdates = true</ | ||
| + | * index (Datei): Metadaten, auch als " | ||
| + | * info (Unterverzeichnis): | ||
| + | * exclude : enthält Dateinamen von Dateien die von der Versionverwaltung ausgeschlossen sind | ||
| + | * logs (Unterverzeichnis): | ||
| + | * objects (Unterverzeichnis): | ||
| + | * refs (Unterverzeichnis): | ||
| + | |||
| + | |||
| + | ==== Objektypen ==== | ||
| + | |||
| + | * **Objektypen** (zlib-komprimiert; | ||
| + | * Commit - bestimmter Änderungszeitpunkt, | ||
| + | - Kommentar (auch " | ||
| + | - Information über Zeit und Autor | ||
| + | - Verweise auf (beliebig viele) übergeordnete Commits (" | ||
| + | - 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" | ||
| + | |||
| + | |||
| + | |||
| + | |||
| + | ==== Submodules ==== | ||
| + | |||
| + | Git kann andere Repositories referenzieren (diese als Submodule einbinden). | ||
| + | [[https:// | ||
| + | |||
| + | === anlegen === | ||
| + | |||
| + | * Entfernte Repos: '' | ||
| + | * Auf gleichem Speicherort/ | ||
| + | * Gefolgt von '' | ||
| + | |||
| + | === benutzen === | ||
| + | |||
| + | Der Clone-Befehl erweitert sich dadurch: < | ||
| + | |||
| + | Sub-Module aktualisieren: | ||
| + | |||
| + | Links: https:// | ||
| + | |||
| + | === Submodule entfernen === | ||
| + | |||
| + | '' | ||
| + | git rm path/ | ||
| + | |||
| + | === 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: '' | ||
| + | * Lokales Repo abgleichen mit entfernt: '' | ||
| + | * Lokales Repo mit eigenem Server syncronisieren: | ||
| + | |||
| + | ==== Branches ==== | ||
| + | |||
| + | * **Branches** (master ist der standard-branch; | ||
| + | * Liste der Branches ausgeben: < | ||
| + | * **neuen** Branch anlegen: < | ||
| + | * **Wechsel** in (diesen) neuen Branch: < | ||
| + | * **zurückführen** in master: | ||
| + | * zuerst zurück in master wechseln: < | ||
| + | * Änderung aus BRANCH_NAME in master mergen: < | ||
| + | * neuen Branch auch in entfernten Repos anlegen: < | ||
| + | * Branch **lokal löschen**: < | ||
| + | * Branch **auf Server löschen**: < | ||
| + | * Branch umbenennen((sollte nicht allzu leichtfertig gemacht werden, Link: https:// | ||
| + | * **lokale Branches aufräumen**, | ||
| + | * in welchem branch ist der commit ID?: < | ||
| + | * commits in myBRANCH zu einem commit zusammenfügen (" | ||
| + | git merge --no-commit --squash $myBRANCH | ||
| + | git commit</ | ||
| + | * Änderungen auf HEAD losgelöst von $CommitID (" | ||
| + | * <code bash>git push origin HEAD: | ||
| + | * <code bash>git checkout master && git merge [ref of HEAD]</ | ||
| + | |||
| + | |||
| + | ==== gemeinsamer Zugriff ==== | ||
| + | |||
| + | * **Mehrbenutzerzugang** (zentral erreichbarer Datei-Speicher) | ||
| + | * Benutzerberechtigungen in Datei " | ||
| + | * | ||
| + | * **Patches** austauschen (geht auch per eMail die sich als mbox-Datei wieder einzupflegen gehen); Beispiel: alle Änderungen als Patch die NICHT in " | ||
| + | |||
| + | ==== workflow-Beispiel merge-request mit gitlab ==== | ||
| + | |||
| + | Ablauf: auschecken, eigenen branch anlegen, committen, pushen, merge-request | ||
| + | |||
| + | * '' | ||
| + | * '' | ||
| + | * '' | ||
| + | * '' | ||
| + | * => Bei Erfolg gibt es einen Meldung mit dem Deeplink für den merge-request zurück | ||
| + | |||
| + | ===== Einrichtung Gitlab ===== | ||
| + | |||
| + | siehe Seite von [[software: | ||
| + | |||
| + | ===== Einrichtung Apache + Git und webdav (Debian) ===== | ||
| + | |||
| + | FIXME Diese Sektion ist wahrscheinlich veraltet und nicht mehr sinnvoll. | ||
| + | |||
| + | Lieder gibt es für git und [[Apache: | ||
| + | - es können keine detaillierten Rechte für die unterschiedlichen Benutzer gesetzt werden | ||
| + | - git-hooks werden nicht ausgeführt | ||
| + | |||
| + | |||
| + | |||
| + | ==== Links ==== | ||
| + | |||
| + | * [[http:// | ||
| + | |||
| + | ==== Server konfigurieren ==== | ||
| + | |||
| + | |||
| + | - Git installieren (als root bzw. mit sudo): <code bash> | ||
| + | - Verzeichnis für das Repository anlegen: < | ||
| + | - optional: | ||
| + | - Gruppe für git-Benutzer erstellen: <code bash> | ||
| + | - Benutzer hinzufügen: | ||
| + | - Leeres git-Repository erzeugen: <code bash>cd / | ||
| + | - Verzeichnis-/ | ||
| + | - Module für WebDAV aktivieren: '' | ||
| + | - Apache2 konfigurieren: | ||
| + | < | ||
| + | DAV on | ||
| + | AuthType Basic | ||
| + | AuthName "Git Repository - consider using ssl to protect your credentials" | ||
| + | # | ||
| + | # (is default anyway; needs mod_authn_file which is loaded) | ||
| + | AuthUserFile / | ||
| + | Require valid-user | ||
| + | #for inital tests: | ||
| + | #Allow from all | ||
| + | </ | ||
| + | - Zugangsdaten in ''/ | ||
| + | - Syntax überprüfen: | ||
| + | - Apache2 neustarten: <code bash> | ||
| + | |||
| + | |||
| + | ===== 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:// | ||
| + | error: failed to push some refs to ' | ||
| + | </ | ||
| + | |||
| + | Der Grund ist eine fehlgeschlagene Verifizierung des [[netzwerke: | ||
| + | - man hat ein selbst-signiertes Zertifikat erstellt bzw. | ||
| + | - eine [[netzwerke: | ||
| + | |||
| + | **Temporäre Lösung** (für selbst-signierte Zertifikate) | ||
| + | - in der Datei ~./bashrc folgendes eintragen < | ||
| + | - oder in '' | ||
| + | |||
| + | **Permanente Lösung** | ||
| + | - [[linux: | ||
| + | - [[windows: | ||
| + | |||
| + | |||
| + | * http.sslCAInfo: | ||
| + | * http.sslCAPath: | ||