Wie machst du eigentlich - Git

8 Min Lesezeit CC BY-ND 4.0 how-do-i command-line git

Etwas das beim Entwickeln ganz nebensächlich passiert: Die Versionsverwaltung nutzen. Macht man halt so. Aber wie mache ich das eigentlich?

Dies ist nicht als Einführung gedacht, sondern mehr als Hintergrundwissen wie und warum ich etwas mache. Ich nehme an, das man schon grundsätzliches von Git versteht, wie staged files, Branches, … und erkläre solches hier nicht im Detail.

Und wie immer gilt: Man Pages sind dein Freund: man git.

Ordnerstruktur

Projekte, die ich mit Git verwalte, habe ich alle unter einem Ordner, in meinem Fall ~/git. Darunter befinden sich mehrere Ordner zum jeweiligen Thema des Projekts, wie beispielsweise der Ort, für den ein Projekt entsteht (study, <company-name>, …) oder das grobe Thema des Projekts (telegram-bots, smarthome, …). Passt ein eigenes Repo bisher in keine dieser Kategorien, dann landet es erstmal in personal. Projekte die ich von anderen anschauen will oder Pull Requests dafür mache, kommen in den Ordner other.

.gitconfig

Meine Git Config mit all ihren Einstellungen habe ich in meinen Configs verewigt und aktualisiere diese regelmäßig mal.

Auch hier versuche ich den Weg zu gehen, möglichst wenig zu konfigurieren. Damit kann ich leichter noch mal zum Beispiel bei fremden Git Problemen helfen. Auch habe ich so nicht so viele Probleme, wenn ich mal eben auf einem Server oder Raspberry irgendwas tue, wo meine gitconfig fehlt.

Alias

Push

Pull

Rebase

Rebase ist tendenziell fortgeschritten, da es einen History Rewrite durchführt. Wenn man Commits, die bereits auf dem Remote sind, mit in den History Rewrite einbezieht, dann muss man force pushen. Ich persönlich will nur History Rewrites mit noch nicht gepushten Commits machen. Dann kann auch nicht so leicht aus Versehen etwas kaputtgehen. (Kleine Fehlerwahrscheinlichkeit bei häufigem Nutzen geht irgendwann auch mal schief.)

Probiere dich damit auf jeden Fall aus, bevor du das produktiv nutzt. Aber habe auch keine Angst davor, dich auszuprobieren.

Commit

User

Verwendung im Projekt

Wenn ich mit einem Projekt anfangen will etwas zu tun, gehe ich meistens mit einem Terminal in genau diesen Ordner: cd git/personal/iPhoneBatteryHealth (Tab für autocomplete ist super). Dann hole ich mir den aktuellen Stand vom Remote (meistens GitHub) via git fetch. Mit git status kann ich dann sehen, was grade los ist. Da ich grade mit dem Projekt anfange, wieder etwas zu tun, sollte es grade auf dem Standard-Branch sein, keine lokalen Änderungen haben und seit dem Fetch auf gleichem Stand wie der Remote sein. Ich habe mir den alias git s konfiguriert, der git status --short --branch ausführt. Damit sehe ich quasi dasselbe wie durch git status auf einen Blick, nur ohne dabei erklärenden Text zwischen den gewünschten Informationen zu haben. Außerdem zeigt meine Shell den aktuellen Branch, ob es Änderungen gibt oder ob möglicherweise Commits auf dem Remote sind, die ich noch reinholen muss oder anders herum noch pushen muss, an. Damit spare ich mir dann den Aufruf von git s, wenn ich es nicht genauer wissen will.

Dann arbeite ich an dem Projekt.

Aktuell verwende ich dazu Visual Studio Code. Tendenziell funktioniert, rein für die Git Nutzung, Atom noch mal besser für mich. Zum Beispiel macht Visual Studio Dinge komplizierter zu verstehen, weil so etwas wie “sync” nicht in Git existiert, sondern quasi git fetch && git merge && git push ist. Atom ist da sehr nah an Git Commands und das hilft beim Verstehen, was Git tut.

Auf meinem Arbeitslaptop verwende ich neben Visual Studio (kein VS Code) Atom, mit dem ich die meisten Git Dinge mache. Visual Studio Code ist da nicht so gut wie Atom, aber gut genug. Immer mal, selten, fehlt mir etwas, das mache ich dann mit der Konsole.

Für Commits will ich immer möglichst kleine, eindeutig nur eine Sache “erfüllende” Commits haben. Das hat später den Vorteil, genau zu sehen, was der Grund für eine geänderte Zeile ist oder um genau ein Feature wieder rückgängig zu machen.

Für die Commit-Message halte ich mich an Conventional Commits.

Manchmal ist noch nicht klar abzusehen, ob etwas funktioniert, dann committe ich nicht ganz so schnell, wie ich manchmal gern würde und entwickle weiter. Dann sortiere ich später die jeweiligen Änderungen in mehrere unterschiedliche Commits. Dabei verwende ich quasi den patch mode (git add --patch), nur mit GUI durch Visual Studio Code oder Atom. Ich füge also Zeilen/Blockweise Änderungen zum Commit hinzu, nicht ganze Dateien.

Manchmal kommt es vor, das ich später noch eine Zeile finde, die in einem früheren Commit fehlt. Entweder es ist der direkt vorher gemachte Commit, dann arbeite ich quasi wie vorher mit git add, sodass diese Änderung gestaged ist. Dann füge ich diese Änderung zum vorherigen Commit hinzu: git commit --amend. Wenn der Commit früher passiert ist, verwende ich meinen git lg alias, um den Hash des jeweiligen Commits zu kopieren. Dann kann ich mit git commit --fixup=<hash> einen fixup Commit erzeugen. Dieser unterscheidet sich quasi nicht von einem normalen Commit, außer das die Commit-Message fixup! <old commit message> ist. Dies allein hilft jetzt noch nicht, kann aber bei einem Rebase genutzt werden.

Immer mal oder wenn ich fertig bin, verwende ich git rebase --interactive --autosquash (oder kurz mit meiner gitconfig: git rebase -i). Dabei wird automatisch der Remote Branch verwendet, wenn dies richtig aufgesetzt ist. Alle Commits bis zu dem, den der Remote kennt, werden zum Rebase todo hinzugefügt und in einem Editor angezeigt. Durch das --autosquash wurden bereits die fixup Commits an die richtige Stelle verschoben und als fixup markiert. Hier können Commits beliebig in ihrer Reihenfolge geändert werden, gelöscht werden, zusammen gefügt werden, Commit-Messages editiert, …. Speichert und schließt man den Editor, wird genau dieses todo ausgeführt.

Ich empfehle allerdings, sich mal mit git rebase auszuprobieren, bevor man das produktiv nutzt. Ein guter Tipp an der Stelle: nur weil Commits nicht mehr in dem Branch sind, sind sie noch nicht weg. Mit git reflog oder git log --reflog (und damit auch git lg --reflog) kann man sich diese noch mal anzeigen, um an seine verschollenen Commits zu kommen.

Immer einmal häufiger als man so denkt, sollte man git push -u nutzen (gilt auch für mich). Damit sind die Commits auch auf dem Remote und nicht weg. Das -u, kurz für --set-upstream setzt das Tracking zwischen dem lokalen und dem remote Branch. Ansonsten verrennt man sich, grade am Anfang mit git, etwas leichter.

Branches

Die meisten meiner Projekte sind allein, daher habe ich bisher noch nicht so viel schreibwürdige Erfahrung mit gutem Zusammenarbeiten. Tendenziell machen mehrere Branches pro Person Dinge einfacher, da man nicht so häufig Merge Commits oder Rebases braucht. Allerdings hat man dann auch nicht exakt die Dinge, die die andere Person grade jetzt gebaut hat.

Ich verwende Branches meistens nur, um Dinge auszuprobieren, für die ich länger brauche. Diese kann ich dann problemlos pushen ohne das der Standard-Branch in Mitleidenschaft gezogen wird.

Schlusswort

Wie bei so ziemlich allem kann man überall noch etwas lernen. Wenn du denkst, ich habe etwas vergessen oder etwas kennst, dass das Leben erleichtern kann, dann gern her damit!

Und wenn du Fragen zu einem “Wie machst du eigentlich X” Thema hast, dann wird daraus vielleicht auch ein Blog Eintrag.