## Einleitung Dieses Kapitel bietet einen Überblick über Git, ein verteiltes Versionskontrollsystem, das hauptsächlich in der Softwareentwicklung eingesetzt wird. Git wurde 2005 von Linus Torvalds entwickelt und wird von großen Unternehmen wie Google und Microsoft sowie von mittleren und kleinen Unternehmen und Hobbyentwicklern auf der ganzen Welt eingesetzt. Es ermöglicht die Verwaltung von Änderungen an Quellcodedateien und anderen Dokumenten und erleichtert die Zusammenarbeit von Teams an gemeinsamen Datensätzen und Codebasen. Im Vergleich zu anderen Versionskontrollsystemen bietet Git den Vorteil, dass es schnell und effizient arbeitet und nur die Unterschiede/Änderungen zwischen verschiedenen Versionen von Dateien im Repository speichert. Zudem ist es flexibel und kann sowohl lokal als auch remote verwendet werden, was es zu einem unverzichtbaren Werkzeug für die Zusammenarbeit an Softwareprojekten macht. Die Konfliktlösungswerkzeuge für inkonsistente Änderungen sind ebenfalls sehr ausgefeilt und sorgen dafür, dass das Repository in einem konsistenten Zustand bleibt. ### Motivation Als Team haben wir uns dafür entschieden, uns mit Git auseinanderzusetzen, weil wir der Meinung sind, dass es ein unverzichtbares Werkzeug für die Zusammenarbeit an Softwareprojekten ist. Durch die Verwendung von Git können wir Zeit sparen und Fehler vermeiden, die oft bei der Zusammenarbeit an komplexen Projekten auftreten können. Git ermöglicht es uns, Änderungen an unseren Dateien zu verfolgen und sicherzustellen, dass jeder Entwickler auf dem neuesten Stand ist. ## Grundlagen ### Was ist ein Versionskontrollsystem (VCS)? Ein Versionskontrollsystem (VCS) ist ein Software-Tool, das dazu dient, Änderungen an Dokumenten, Code und anderen Dateien zu verfolgen und zu verwalten. Es ermöglicht Entwicklern, gemeinsam an Projekten zu arbeiten, ohne sich Sorgen machen zu müssen, dass Änderungen von anderen überschrieben werden oder verloren gehen. Im Laufe der Zeit gab es verschiedene Arten von VCS, darunter zentralisierte und dezentralisierte Systeme. Zentralisierte VCS wie Subversion (SVN) oder Concurrent Versions System (CVS) verwenden einen zentralen Server, um alle Änderungen zu speichern. Entwickler können Änderungen an Dateien vornehmen, aber sie müssen sie auf den zentralen Server hochladen, damit sie für andere zugänglich sind. Zentralisierte VCS sind zwar einfach zu bedienen und eignen sich gut für kleine Teams, aber sie haben auch einige Nachteile. Zum Beispiel können sie bei Konflikten oder Serverausfällen zu Datenverlusten führen. Dezentralisierte Systeme wie Git oder Mercurial haben hingegen keine zentrale Autorität und erlauben es Entwicklern, Änderungen lokal zu speichern und zwischen den verschiedenen Kopien auszutauschen. Dezentralisierte VCS sind oft schneller und flexibler als zentralisierte VCS. Sie ermöglichen es Entwicklern, unabhängig voneinander zu arbeiten und die Änderungen anderer zu verfolgen, ohne sich auf einen zentralen Server verlassen zu müssen. ### Architektur Die Architektur von Git basiert auf verschiedenen Komponenten, die eng miteinander verbunden sind und zusammenarbeiten, damit das System funktioniert. Folgend einige wichtige Aspekte der Git-Architektur: - Das Repository ist der zentrale Speicherort für alle Dateien und den Versionsverlauf des Projekts. - Ein Commit ist eine spezifische Änderung an einer oder mehreren Dateien, die im Repository gespeichert wird. - Ein Branch oder Zweig ist eine Kopie des Repositorys, die unabhängig von anderen Branches bearbeitet werden kann. Dies ermöglicht es mehreren Entwicklern, an verschiedenen Teilen des Projekts zu arbeiten, ohne sich gegenseitig zu beeinträchtigen. - Beim Merging werden Änderungen aus verschiedenen Zweigen bzw. Branches kombiniert, um eine neue Version des Projekts zu erstellen. - Ein Remote ist ein Verweis auf eine Kopie des Repositores, die sich an einem anderen Ort befindet. Dies kann zum Beispiel ein Repository-Hosting-Service wie GitHub oder GitLab sein. Heutzutage gibt es viele Hosting-Anbieter für Git. Die Wahl des Git-Hosting-Dienstes hängt von den spezifischen Anforderungen des Projekts und den persönlichen Vorlieben ab. Zu den größten Anbietern gehören GitHub und GitLab, die von Millionen von Entwicklern weltweit genutzt werden. Auch die Hochschule betreibt mehrere GitLab-Instanzen, z. B. die der Informatik (unter https://gitlab.informatik.hs-augsburg.de). ### Git vs. Subversion (SVN) Subversion (SVN) und Git sind zwei der am häufigsten verwendeten Versionskontrollsysteme. Während SVN lange Zeit das bevorzugte System war, hat Git in den letzten Jahren an Bedeutung gewonnen und gilt heute als Industriestandard. Um die beiden VCS genauer zu beleuchten werden hier die Unterschiede der beiden VCS erläutert und aufgezeigt, warum Git zum Industrierstandard wurde. #### Funktionsweise beider VCS SVN speichert Dateien und ihre Änderungen in einem zentralen Repository, auf das alle Entwickler zugreifen können. Wenn ein Entwickler Änderungen an einer Datei vornimmt, müssen diese Änderungen zuerst zum zentralen Repository hochgeladen werden, bevor andere Entwickler darauf zugreifen können. Im Gegensatz dazu ist Git ein verteiltes Versionskontrollsystem, das jede Arbeitskopie als eigenständiges Repository behandelt. Dadurch können Entwickler Änderungen an ihren lokalen Repositories vornehmen und dann ihre Änderungen mit anderen Repositories zusammenführen. #### Flexibilität Git ist in der Regel flexibler als SVN. Zum Beispiel können Entwickler ihre eigenen Branches erstellen und unabhängig von anderen Entwicklern arbeiten. Git ermöglicht auch das Ändern von früheren Commits, das Verwalten von Submodulen und das Durchführen von Interaktionen mit entfernten Repositories. SVN hingegen ist weniger flexibel und bietet weniger Möglichkeiten zur individuellen Anpassung. #### Werkzeuge für die Konfliktlösung Git bietet bessere Konfliktlösungsmöglichkeiten als SVN. Bei SVN kann es schwierig sein, Konflikte zu erkennen und zu beheben, insbesondere wenn mehrere Entwickler gleichzeitig an einer Datei arbeiten. Git verfügt über integrierte Tools zur Konfliktlösung, die es Entwicklern erleichtern, Konflikte zu erkennen und zu lösen. #### Fazit des Vergleichs Zusammenfassend lässt sich sagen, dass Git im Vergleich zu SVN viele Vorteile bietet. Git ist schneller, flexibler und bietet bessere Konfliktlösungsmöglichkeiten. Diese Vorteile haben dazu geführt, dass Git heute der Industriestandard für Versionskontrollsysteme ist. ### Konfiguration von Git Im Normalfall sollte man Git an die eigenen Bedürfnisse anpassen. Das beginnt mit der Festlegung eines Benutzernamens und einer E-Mail-Adresse, die mit den Git-Commits hinterlegt werden. Das Setzen oder Abfragen von Konfigurationsoptionen ist sehr einfach. ```bash $ git config user.email git@hs-augsburg.de $ git config user.email "git@dva.hs-augsburg.de" git@dva.hs-augsburg.de ``` Es ist zu beachten, dass es bei Git verschiedene Konfigurationslevel gibt. Für die Verwendung ist es wichtig zu wissen, wann man welche setzen sollte. - Systemebene: - Flag: `--system` - Die Konfiguration gilt für alle Benutzer auf dem gesamten System. Diese Ebene sollte verwendet werden, wenn die Konfiguration für alle Nutzer des Systems gelten soll. - Globale Ebene: - Flag: `--global` - Die Konfiguration gilt für einen bestimmten Benutzer auf allen Projekten. Diese Ebene sollte verwendet werden, wenn die Konfiguration für alle Git-Projekte gelten soll. - Lokale-/Projekt Ebene: - Flag: `--local`. **ABER:** Die Flag ist nicht erforderlich. - Die Konfiguration gilt nur für ein bestimmtes Projekt. Diese Ebene sollte verwendet werden, wenn die Konfiguration für ein bestimmtes Git-Projekt gelten soll. Die Projekt-Konfiguration kann jedoch durch die globalen Einstellungen überschrieben werden. #### Aliase setzen Wer regelmäßig die gleichen Befehle ausführt, will zwangsläufig auch Abkürzungen für die Kommandos verwenden. Diese lassen sich ebenfalls via Git konfigurieren. In unserem fall bietet es sich an, diese Aliase global zu setzen. Hier ein paar Beispiele: ```bash $ git config --global alias.co checkout $ git config --global alias.br branch $ git config --global alias.ci commit $ git config --global alias.st status # Neue Kommandos git config --global alias.unstage 'reset HEAD --' ``` ### Grundlegende Befehle Für die Verwendung von Git sind vor allem folgenden Kommandos sinnvoll zu wissen. #### `git add` Der `git add` Befehl fügt Änderungen hinzu, die für die nächste Commit-Operation berücksichtigt werden sollen. Es gibt zwei Möglichkeiten, git add zu verwenden: - Um bestimmte Änderungen hinzuzufügen: ```bash $ git add ``` Zum Beispiel: `git add dva.html` - Um alle Änderungen hinzuzufügen: ```bash $ git add . ``` Hier wird ein Punkt verwendet, um alle Änderungen im aktuellen Verzeichnis hinzuzufügen. #### `git commit` Der `git commit` Befehl speichert die Änderungen, die mit git add hinzugefügt wurden, als neues Commit. Jedes Commit enthält eine Beschreibung der Änderungen und einen eindeutigen Hash-Code. ```bash $ git commit -m "Beschreibung der Änderungen" ``` Die Option -m wird verwendet, um eine kurze Beschreibung der Änderungen bereitzustellen. Zum Beispiel: git commit -m "Aktualisiere die Startseite" #### `git diff` Der `git diff` Befehl zeigt die Unterschiede zwischen verschiedenen Commits, Branches oder Dateien an. - Um die Unterschiede zwischen dem Arbeitsverzeichnis und dem letzten Commit anzuzeigen: ```bash $ git diff ``` - Um die Unterschiede zwischen verschiedenen Commits anzuzeigen: ```bash $ git diff ``` Zum Beispiel: `git diff abc123 def456` - Um die Unterschiede zwischen verschiedenen Branches anzuzeigen: ```bash $ git diff ``` Zum Beispiel: `git diff main feature/dva` #### `git stash` Der git stash Befehl ermöglicht es, Änderungen zu speichern, ohne sie zu commiten, und später wieder abzurufen. Dies kann nützlich sein, wenn man Änderungen an einem Feature vornimmt und schnell zu einem anderen Feature wechseln muss. - Um Änderungen zu speichern: ```bash $ git stash save "Beschreibung der Änderungen" ``` Zum Beispiel: `git stash save "Bearbeite Feature XYZ"` - Um Änderungen abzurufen und wieder aufzunehmen: ```bash $ git stash apply ``` - Um Änderungen abzurufen und den Stash zu löschen: ```bash $ git stash pop ``` - Um alle Stashes zu löschen: ```bash $ git stash clear ``` #### `git branch` Mit diesem Befehl kann man eine neue Branch in Git erstellen oder alle bestehenden Branches auflisten. - Um eine neue Branch zu erstellen, gibt man einfach den Namen der neuen Branch an: ```bash $ git branch new_feature ``` - Um alle Zweige/Branche aufzulisten, kann man den Befehl ohne Argumente ausführen ```bash $ git branch ``` Mit diesen grundlegenden Befehlen lassen sich schon viele Alltagsaufgaben bei der Git-Versionierung meistern! #### `git checkout` Mit diesem Befehl kann man zwischen verschiedenen Branches wechseln oder bestimmte Dateien aus einem anderen Branch wiederherstellen. - Um zu einem anderen Branch zu wechseln, gibt man den Namen des Ziels an: ```bash $ git checkout feature_branch ``` - Um eine bestimmte Datei aus einem anderen Branch wiederherzustellen, gibt man den Pfad zur Datei an: ```bash $ git checkout other_branch path/to/file.txt ``` #### `git merge` Mit diesem Befehl kann man verschiedene Branches zusammenführen. Um eine Branch in den aktuellen Branch zu mergen, gibt man den Namen des Zielbranches an: ```bash $ git merge other_branch ``` #### `git status` Dieser Befehl zeigt den Status der Arbeitskopie im Verhältnis zum Git-Repository an. Er gibt Auskunft darüber, welche Änderungen noch nicht committed wurden, welche Dateien im Staging-Bereich sind und welche Dateien im Working Directory geändert wurden. Mit diesem Befehl kann man also schnell einen Überblick darüber bekommen, welche Änderungen an der Codebasis noch nicht versioniert wurden. ```bash $ git status On branch master Your branch is up to date with 'origin/master'. Changes not staged for commit: (use "git add ..." to update what will be committed) (use "git restore ..." to discard changes in working directory) modified: file.txt no changes added to commit (use "git add" and/or "git commit -a") ``` #### `git tag` Mit diesem Befehl kann man Tags in Git erstellen. Tags werden verwendet, um bestimmte Versionen oder Meilensteine des Projekts zu kennzeichnen. Ein Tag kann auf einen bestimmten Commit im Repository gesetzt werden. Dadurch kann man später einfach auf eine bestimmte Version des Codes zurückgreifen. Tags können auch mit einer Nachricht versehen werden, um den Grund für das Tagging zu dokumentieren. ```bash $ git tag -a v1.0 -m "DVA release" ``` #### `git blame` Dieser Befehl zeigt an, wer eine bestimmte Zeile im Code zuletzt geändert hat. Dadurch kann man schnell herausfinden, wer für einen bestimmten Code-Abschnitt verantwortlich ist. Der Befehl gibt den Autor, den Zeitpunkt und den Commit-Hash der letzten Änderung an. ```bash $ git blame dva.txt e442f837 (Fabian Hammerschmidt 2023-04-13 09:00:00 +0100 1) This is a line of code s4f8s4f8 (Felix Golatofski 2023-04-13 10:00:00 +0100 2) This is another line of code e442f837 (Milan Cieliebak 2023-04-13 09:00:00 +0100 3) This is yet another line of code ``` In diesem Beispiel zeigt der Befehl `git blame` die letzten Änderungen an der Datei "file.txt" an. Man kann sehen, wer welche Zeile zuletzt geändert hat. #### Git Commits zusammenfassen Wenn man mit Git arbeitet und mehrere Commits in einem Zweig hat, die inhaltlich zusammenhängen, kann es sinnvoll sein, sie zu einem einzigen Commit zusammenzufassen. Das nennt man "Squashing". Dadurch bleibt der Commit-Verlauf des Branches übersichtlicher und besser nachvollziehbar. Um Commits zu squashen, muss zunächst der Hashwert des Commits bekannt sein, der als neuer `HEAD` gelten soll. Dann kann man mit dem Befehl `git rebase -i` in den interaktiven Modus gehen und die Commit-Historie bearbeiten. Dort kann man die einzelnen Commits zu einem Squash-Commit zusammenführen, indem man den Befehl `squash` oder ein kurzes `s` vor den entsprechenden Commit setzt. Nachdem man die Änderungen gespeichert und den Editor geschlossen hat, erstellt Git automatisch den neuen Squash-Commit. Ein Beispiel:\ Es existieren drei Commits mit folgenden Commit-Nachrichten: ```bash $ git log commit abcdef1 (HEAD) Author: Muster Student Date: Tue Apr 13 10:00:00 2023 +0200 Fix bug commit 1234567 Author: Muster Student Date: Mon Apr 12 10:00:00 2023 +0200 Refactor code commit 9876543 Author: Muster Student Date: Sun Apr 11 10:00:00 2023 +0200 Add new feature ``` Um die Commits nun zusammenfassen zu können, wird auf den rebase im interaktiven Modus gewechselt. ```bash $ git rebase -i HEAD~3 pick 9876543 Add new feature squash 1234567 Refactor code squash abcdef1 Fix bug ``` Danach muss der interaktive Modus durch ein Speichern verlassen werden. Git erstellt automatisch den Squash-Commit und öffnet den Editor für die Commit-Nachricht. Hier kann eine neue Commit-Nachricht verfasst oder einfach die ursprüngliche Nachricht beibehalten werden. Nach dem Speichern der Commit-Nachricht und dem Schließen des Editors wird der Squash-Commit erstellt und die Commit-Historie des Zweigs ist übersichtlicher. ## Versuchsdurchführung ### Vorbereitung Um den Versuch durchführen zu können, ist es zunächst erforderlich, dass Git auf dem betreffenden System installiert ist. Git ist für alle gängigen Systeme verfügbar. Außerdem sollte bereits ein Konto bei einem Git-Hosting-Dienst der Wahl vorhanden sein, um Änderungen auch für andere verfügbar machen zu können. Bei der Git-Platform haben wir uns in unserem Fall für Microsoft's GitHub entschieden, weil es sich um die derzeit größte Git-Plattform der Welt handelt und viele Studenten bereits Erfahrung mit der Plattform gesammelt haben. Zu diesem Zweck erstellen wir zunächst ein Repository auf unserem lokalen System. Dieser Vorgang wird auch init genannt. Wir werden später unser GitHub-Repository definieren, in das wir unsere Änderungen pushen werden. Zunächst sollten wir ein neues Verzeichnis auf unserem System anlegen, in dem wir das Repository erstellen möchten. Danach werden wir die folgenden Befehle ausführen, um eine Datei zu erstellen und sie schließlich auf GitHub verfügbar zu machen. Die einzelnen Befehle werden später erklärt. ```bash $ echo "# Git_Versuch" >> README.md $ git init $ git add README.md $ git commit -m "first commit" $ git branch -M main $ git remote add origin https://github.com/Arathes/Git_Versuch.git $ git push -u origin main ``` Bei der ersten Änderung des Testprojekts trat bereits der erste Anwendungsfall auf. Da beim Push nicht bemerkt wurde, dass die Binärdateien auch im Staging waren, befinden sie sich nun auch im Repository. Daher sollten wir den ersten Push wieder rückgängig machen. Das geht am einfachsten, indem man den vorhandenen Zweig löscht und den ersten Commit neu erstellt. ```bash $ git update-ref -d HEAD ``` `main`-Branch: ```csharp class Program { static void Main(string[] args) { Console.WriteLine("Hello Git!"); Console.WriteLine("This is a simple C# program."); Console.WriteLine("It prints a message to the console."); } } ``` Danach wurde der erste Commit erneut ausgeführt und ein neuer Branch für die Entwicklung erstellt. ```bash $ git checkout -b development Switched to a new branch 'development' ``` Im Branch `development` wurde die Entwicklung weitergeführt. `development`-Branch: ```csharp class Program { static void Main(string[] args) { Console.WriteLine("Hello Git!"); Console.WriteLine("This is a simple C# program."); Console.WriteLine("It prints a message to the console."); Console.WriteLine("Git is awesome!"); } } ``` Ein Kollege hatte eine Idee für eine experimentelle Funktion, die nicht im Entwicklungszweig erscheinen sollte. Also erstellte er einen neuen Zweig und schob seine Arbeit in das Repository. `feature`-Branch: ```csharp public class Calculator { public int addNumbers(int a, int b) { return a + b; } } ``` In der Zwischenzeit wurde jedoch auch eine Änderung `development`-Branch durchgeführt. `development`-Branch: ```csharp class Program { static void Main(string[] args) { Console.WriteLine("Hello Git!"); Console.WriteLine("This is a simple C# program."); Console.WriteLine("It prints a message to the console."); Console.WriteLine("Git is awesome!"); Console.WriteLine("I have no idea of the new feature!"); } } ``` Der Chef war von der Innovation des Kollegen begeistert und möchte diese Änderungen mit den Änderungen des `development`-Branches zusammenführen, um zu sehen, ob es hier zu Problemen kommt. ```bash $ git checkout feature Switched to branch 'feature' $ git rebase development Successfully rebased and updated refs/heads/feature. ``` ![](assets/branch.png) ![](assets/rebasefeature.jpg) Nach einem weiteren Push befindet sich die Funktion nun auf dem letzten Commit des `development-Zweigs`. Die Änderungen im `development`-Zweig waren bisher funktionsfähig. Daher werden die Änderungen nun mit dem Produktivbranch zusammengeführt. ```bash $ git checkout main Switched to branch 'main' Your branch is up to date with 'origin/main'. $ git merge feature Updating 44be827..e0a9441 Fast-forward Git_Versuch/Calculator.cs | 17 +++++++++++++++++ Git_Versuch/Program.cs | 5 +++-- 2 files changed, 20 insertions(+), 2 deletions(-) ``` ![](assets/merge.png) Da die innovative Funktion bereits existiert und sogar in einem öffentlichen Git-Repository mit besserer Funktionalität verfügbar ist, wurde beschlossen, sie als Submodul in das eigene Repository aufzunehmen. ```bash $ git submodule add https://github.com/Arathes/Git_Submodule.git lib/calculator Cloning into 'C:/Users/accou/source/repos/Git_Versuch/lib/calculator'... remote: Enumerating objects: 5, done. remote: Counting objects: 100% (5/5), done. remote: Compressing objects: 100% (4/4), done. remote: Total 5 (delta 0), reused 5 (delta 0), pack-reused 0 Receiving objects: 100% (5/5), done. warning: in the working copy of '.gitmodules', LF will be replaced by CRLF the next time Git touches it $ git submodule update --init ``` ![](assets/submodule_1.png) Ein Problem in der Produktivumgebung aufgetreten und die gerade bearbeitete Änderung in der Feature-Branch ist noch nicht abgeschlossen bzw. nicht für einen Commit geeignet. Daher wird diese Änderung nun vorübergehend gestasht. ```bash $ git stash save "WIP: Work in progress" Saved working directory and index state On feature: WIP: Work in progress ``` Zur Lösung des Problems können wir zum Glück auf "git bisect" zurückgreifen: ```bash $ git bisect start status: waiting for both good and bad commits $ git bisect good 44be82799d402ec2ed9a0ed444cc54174df1ce87 status: waiting for bad commit, 1 good commit known $ git bisect bad 2cbf9e569eed2b05e5a0f43a71b10c22377303ac Bisecting: 1 revision left to test after this (roughly 1 step) [8f0e30235caea8df860539cfb53605e905d0cfc2] Changes to the development branch without knowing about the feature $ git bisect reset ``` Nachdem das Problem behoben wurde, können die vorher abgespeicherten Änderungen nun wieder abgerufen werden. ```bash $ git stash apply ``` Da die aktuellen Commit-Messages in unserem Projektteam meist wenig aussagekräftig bzw. mangelhaft sind, verwenden wir nun einen Hook um unsere Entwickler bei jedem Commit darauf hinzuweisen, dass aussagekräftige Commit-Messages wichtig sind (z.B. um den Entwicklungsprozess zu dokumentieren). Zum Glück liefert Git bereits ein sample, um eine derartige Meldung anzuzeigen. ```bash cd .git/hooks $ mv prepare-commit-msg.sample prepare-commit-msg ``` Zwei neue Features wurden in der Feature-Branch entwickelt. Allerdings soll nur eines vorerst in der Entwicklungsumgebung übernommen werden. Daher wenden wir nun den Cherry-Pick an. ```bash $ git log $ git checkout development $ git cherry-pick 18cdd2d0f9624fa44303bec065ae56385760657f [development 032187b] Added a feature to help our suicidal developers Date: Thu Apr 13 03:29:48 2023 +0200 1 file changed, 47 insertions(+) create mode 100644 Git_Versuch/MotivationalDeveloper.cs ``` Nun wollen wir uns einmal anschauen welche Änderungen wir durchgeführt haben und wo die aktuellen HEADs in jedem Branch liegen. Dies können wir mit dem Befehl "git reflog" erreichen. ```bash $ git reflog 032187b (HEAD -> development, origin/development) HEAD@{0}: cherry-pick: Added a feature to help our suicidal developers 8f0e302 HEAD@{1}: checkout: moving from feature to development 18cdd2d (origin/feature, feature) HEAD@{2}: commit: Added a feature to help our suicidal developers d14bb31 HEAD@{3}: commit: Added new feature for calculating interest e0a9441 HEAD@{4}: checkout: moving from main to feature 2cbf9e5 (origin/main, main) HEAD@{5}: checkout: moving from feature to main e0a9441 HEAD@{6}: checkout: moving from 8f0e30235caea8df860539cfb53605e905d0cfc2 to feature 8f0e302 HEAD@{7}: checkout: moving from main to 8f0e30235caea8df860539cfb53605e905d0cfc2 2cbf9e5 (origin/main, main) HEAD@{8}: checkout: moving from main to main 2cbf9e5 (origin/main, main) HEAD@{9}: checkout: moving from feature to main e0a9441 HEAD@{10}: reset: moving to HEAD e0a9441 HEAD@{11}: checkout: moving from main to feature 2cbf9e5 (origin/main, main) HEAD@{12}: commit: Added Submodule e0a9441 HEAD@{13}: merge feature: Fast-forward 44be827 HEAD@{14}: checkout: moving from feature to main e0a9441 HEAD@{15}: checkout: moving from development to feature 8f0e302 HEAD@{16}: checkout: moving from feature to development e0a9441 HEAD@{17}: rebase (finish): returning to refs/heads/feature e0a9441 HEAD@{18}: rebase (pick): Added new experimental Feature 8f0e302 HEAD@{19}: rebase (start): checkout development 87be1ba HEAD@{20}: checkout: moving from development to feature 8f0e302 HEAD@{21}: commit: Changes to the development branch without knowing about the feature 16881b6 HEAD@{22}: checkout: moving from feature to development 87be1ba HEAD@{23}: commit: Added new experimental Feature 16881b6 HEAD@{24}: checkout: moving from development to feature 16881b6 HEAD@{25}: commit: Commit First Change 44be827 HEAD@{26}: checkout: moving from main to development 44be827 HEAD@{27}: commit (initial): Initial commit cad47e7 HEAD@{29}: Branch: renamed refs/heads/main to refs/heads/main cad47e7 HEAD@{31}: Branch: renamed refs/heads/master to refs/heads/main cad47e7 HEAD@{33}: commit (initial): First Commit of Project ``` ## Literaturverzeichnis - https://git-scm.com/docs/git, abgerufen am 11.04.2023 - https://git-scm.com/docs/git-cherry-pick, abgerufen am 11.04.2023 - https://git-scm.com/docs/git-bisect, abgerufen am 11.04.2023 - https://www.atlassian.com/git, abgerufen am 12.04.2023 - https://de.wikipedia.org/wiki/Git, abgerufen am 11.04.2023 - https://www.perforce.com/blog/vcs/git-vs-svn-what-difference, abgerufen am 12.04.2023