Schlagwort-Archive: Repository

Kennst du schon Gitflow und SourceTree?

Auf Community Treffen stelle ich immer wieder fest, dass viele, mich eingeschlossen, das Gefühl haben, dass sie Git nicht ausreizen und viele Möglichkeiten, die ein dezentrales Versionskontrollsystem bietet, nicht nutzen. Manchmal wird es unter vorgehaltener Hand, im Vertrauen oder unter dem Deckmantel der Anonymität geäußert. Auf dem Open Space Leipzig gab es hierzu sogar eine eigene Session. Ich mache es an dieser Stelle öffentlich und sage: Ich möchte mehr wissen!

Nachdem ich mich vor Monaten einmal mit Gitflow beschäftigt habe, stehe ich aktuell an dem Punkt es bei uns einzuführen. Dabei handelt es sich um einen Aufsatz für Git, mit welchem diverse Branching Workflows automatisieren und standardisieren werden können. Es ist eine angenehme Abstraktionsschicht zu einem Set an Befehlen, welche sonst von Hand durchgeführt werden müssten. Eine gute Illustration gibt es hier. Atlassian nennt es den Gitflow Workflow. Mein Entwicklerkollege beschreibt dazu in unserem Team Blog die Installation für msysgit.

Jetzt trifft es sich gut, dass ich kürzlich durch unseren Webentwickler auf SourceTree aufmerksam wurde, welches dem Gitflow Modell eine intuitive Oberfläche verleiht. Bisher habe ich einen Bogen um UI Tools gemacht. Damit nehme ich jetzt meinen ersten Anlauf weg von der Konsole. Martin Fowler schreibt dazu:

A shout out to developers of SourceTree – a nice GuI for git and hg. Useful even for a command-line fan like me.

Über diesen Blogeintrag möchte ich mir Rückmeldungen einholen. Nutzt ihr die vorgestellten Programme bereits? Zur Umfrage geht es hier. Wie geht es euch bei Git? Denkt ihr auch, dass ihr Wissenslücken habt, die geschlossen werden müssen? Gebt hier Antwort.

Und wenn ihr gutes Infomaterial habt, z.B. Online Videos, dann postet es als Kommentar dazu.

Meine tägliche Portion Git – Passwort Eingabe deaktivieren

Wer nicht bei jeder Git Operation wie dem Pushen oder Pullen ein Passwort eingeben will, der muss dazu den Private Key im Verzeichnis %userprofile%\.ssh\ ändern. Dazu führt man in der Git Bash folgenden Befehl aus:

ssh-keygen -f id_rsa -p

Enter old passphrase:

Key has comment ‚id_rsa‘

Enter new passphrase (empty for no passphrase):

Enter same passphrase again:

Your identification has been saved with the new passphrase.

 

Wer erst noch ein Schlüsselpaar erzeugen muss, kann natürlich von Anfang an das Passwort auslassen. Eine sicherere Alternative ist es einen SSH Agent zu installieren, der den Key entschlüsselt vorhält.

Meine tägliche Portion Git – Remote Branches synchronisieren

Über

   1: git branch -a

kann man sich alle lokalen und remote Branches anzeigen lassen. Den lokalen löscht man über

   1: g branch -D <branch name>

während der Remote Branche über

   1: git push --delete origin <branch name>

entfernt wird.

Nun kann es im letzten Beispiel zu folgendem Fehler kommen:

error: unable to delete ‚branch_name‘: remote ref does not exist

error: failed to push some refs to ‚git@ci:comwork‘

 

Das liegt daran, dass die angezeigt Liste aus dem ersten Beispiel nicht mit dem Server abgeglichen und somit nicht mehr existierende Remote Branches ausgegeben wurden. Der Befehl

   1: git remote prune origin

korrigiert diesen Missstand. Falls also auf dem Server Branches gelöscht wurden, werden diese aus dem lokalen Repository bzw. aus dem Cache ebenfalls entfernt.

Meine tägliche Portion Git – Tags

Wer vor der Aufgabe steht alle bestehenden Tags aus Git zu löschen, kann dies wie folgt bewerkstelligen:

   1: git tag | xargs git push --delete origin

   2: git tag | xargs git tag -d

Über “git tag” holt man sich alle vorhandenen Tags, welche durch ‚”|” an den nächsten Befehl weitergereicht (Pipe) werden. “xargs” besagt, dass die übergebenen Werte per Schleife durchlaufen und ans Ende des Befehls angefügt werden. Somit werden zunächst alle Remote Tags gelöscht (Zeile 1) und im Anschluss alle lokalen Tags (Zeile 2). Mit

   1: git tag

kann mich sich zur Verifizierung nochmals alle Tags ausgeben lassen. Das Ergebnis sah bei mir im Testszenario dann so aus:

image

Meine tägliche Portion Git – Ambiguous Refname

Kürzlich habe ich aus versehen einen Branch namens “Head” angelegt. Im Anschluss bekam ich immer folgende Warning von Git:

warning: refname ‚HEAD‘ is ambiguous.image

Über “git show-ref” habe ich mir alle Referenzen anzeigen lassen. Folgerichtig war dieser dort auch aufgelistet. Head ist allerdings ein reservierter Name, der immer dem Pointer des aktuell verwendeten Branches entspricht. In diesem Artikel habe ich bereits dazu gebloggt.

Das Problem hat übrigens jemand bereits hier beschrieben. Um das Ganze abzukürzen. Wenn ihr den Branch über “git branch -d head” löscht, ist alles wieder in Butter.

Meine tägliche Portion Git

Heute habe ich auf Grund einer Unachtsamkeit einen falschen Merge getätigt. Die Folge war, dass mein Stand nach dem Rebase fehlte. Konkret kann euch dies passieren, wenn ihr beispielsweise an einer Klasse entwickelt, die Änderungen eincheckt und euch dann das aktuelle Repository über einen Pull zieht. Hat nun ein anderer Entwickler ebenfalls etwas an dieser Datei geändert, so schlägt das Mergen fehl und ihr seid in eurem Branch abgezweigt. In der Regel löst man dies, indem man manuell mergt. Danach führt man über “git rebase –continue” das Zusammenführen des Remote Repository und eures lokalen Repository zu Ende. Stell ihr nun fest, dass ihr falsch gemergt habt, könnt ihr nicht ohne weiteres eure Datei wiederherstellen.

In dem Falle ruft ihr “git reflog” auf. In dem Falle seht ihr alle je getätigten Commits.

image

Nun könnt ihr über “git reset –hard SHA” auf den commit zurück, den ihr vor dem Rebasing hattet. SHA entspricht dabei dem SHA eures Commits. Danach könnt ihr erneut pullen und korrekt mergen.

Meine tägliche Portion Git

Wer eine Änderung gepusht hat und diese rückgängig machen will, sollte wie folgt vorgehen:

  • Gleich alle Entwickler informieren, dass sie nicht mehr pullen sollen (idealerweise hat noch niemand den neuen Stand gepullt!)
  • Über den Befehl “git reset —hard head~1” (geht eine Revision zurück) oder über “git reset —hard  fa0f23d” (wobei fa0f23d dem SHA des Commits entspricht, auf den man zurück will), könnt ihr zunächst lokal den gewünschten Stand wiederherstellen. Über git log könnt ihr auch die Historie anschauen.
  • Danach setzt ihr mit “git push -f origin master” das öffentliche Repository zurück

Anmerkung: Das funktioniert z.B. nicht, wenn der entsprechende Developer nicht die benötigten Rechte hat oder Git so eingestellt ist, dass es “git push -f” nicht zulässt. Wie ihr dieses Problem löst und einen alternativen Weg findet ihr hier (Eintrag 2 anschauen!).

Meine tägliche Portion Git

Wer eigene Merge Tools in Git verwenden will, der muss ein paar Kleinigkeiten beachten:

1. %userprofile%\.gitconfig anpassen: Neuer Abschnitt für das Mergetool der eigenen Wahl anlegen

[mergetool "P4"]
    cmd = /Pfad/p4merge-merge.sh \"$BASE\" \"$LOCAL\" \"$REMOTE\" \"$MERGED\"
    trustExitCode = true

Gegebenenfalls auch unter [merge] dieses als Standard definieren:

[merge]
    tool = P4
    log = true

 

2. Shell-Skript schreiben und dort ablegen, worauf ihr in der .gitconfig verwiesen habt

#!/bin/sh
script_dir=/Pfad

local="$($script_dir/cygpath –mixed –absolute "$2")"
base="$($script_dir/cygpath –mixed –absolute "$1")"
baseUnixFormat="$($script_dir/cygpath –unix –absolute "$1")"
remote="$($script_dir/cygpath –mixed –absolute "$3")"
result="$($script_dir/cygpath –mixed –absolute "$4")"
tool="/Pfad/P4Merge/p4merge.exe"

if [ ! -f "$baseUnixFormat" ]
then
    base="$($script_dir/cygpath –mixed –absolute $script_dir/p4merge-empty.txt)"
fi

"$tool" "$local" "$remote" "$base" "$result"

 

Achtet genau auf die Pfade! Für Teams bietet sich an, dass man alle Tools und Skripte ins Repository mit aufnimmt. Danach erstellt man ein symbolisches Verzeichnis auf der Platte, welches bei jedem Entwickler auf den Pfad des Repository verweist. Wir haben uns z.B. darauf verständigt, dass jeder Entwickler ein Verzeichnis D:\Development\Repository haben muss. Bei mir zeigt das dann beispielsweise auf G:\heco\comwork. Bei dem Kollegen wiederum auf einen anderen Pfad. Aber da wir mit dem symbolischen Verzeichnis arbeiten, können wir alle die Skripte und Tools verwenden ohne sie anpassen zu müssen. Da die Git\.gitconfig wiederum pro Entwickler konfiguriert wird, kann trotzdem jeder das Merge Tool seiner Wahl als Standard einstellen.

Noch zwei wichtige Punkte:

  • Im Pfad muss eine p4merge-empty.txt liegen, sonst schmeißt das Skript einen Fehler. Die Dateien wird verwendet, wenn es beim Merge keine gemeinsame Basis gibt, also statt /dev/null. Damit haben die meisten Programme und Windows Probleme.
  • Ich verwende das Kommandozeilentool cygpath (Teil von cygwin), um Windows Pfade in Unix Pfade zu konvertieren. Wenn ihr dieses nicht verwendet, dann müsst ihr die Befehle abändern und alle Pfadangaben im Unix Format angeben.

Weiterführender Link zum Blogeintrag von agross.

Meine tägliche Portion Git

Gehen wir davon aus, dass wir lokal 2 Branches haben mit den Namen Branch1 und Branch2. Dann sind beide Branches unter zwei Namen zu erreichen.

image

Dem eigentlichen Alias, sprich der Branch Name, z.B. Branch1. Außerdem unter dem eindeutigen SHA. Sprich folgende Befehle sind syntaktisch gleich:

  • git checkout Branch1
  • git checkout 56789

Mit git checkout wechselt man zwischen Branches. Steht man aktuell auf Branch1, so ist dieser noch unter einem dritten Alias erreichbar: HEAD.

Wenn ich nun über git checkout Branch2 mache, so wechselt der HEAD Pointer auf Branch2, sodass Branch1 nur noch unter 2 Namen erreichbar ist, wohingegen Branch2 nun 3 Namen hat: Den SHA, Branch2 und HEAD.

Gut zu wissen: Über git reflog kann man sich die komplette Historie von HEAD anzeigen, sprich alle Änderungen die man auf jedem Branch, auf dem man jemals war, anzeigen lassen und ggf. darauf wechseln.

Lokale Branches lässt man sich über git branch anzeigen, Remote Branches über git branch –r (git branch –a listet lokale und remote Branches auf). Wichtig zu wissen: Per Default sind Branches, die man anlegt, lokal. Über git push origin branchname -u (funktioniert immer, egal wo man steht) kann man den Branch veröffentlichen. Wird ein Branch veröffentlicht, so wird er auch in die .git/config (sprich die Repository spezifische config) eingetragen! Bei lokalen ist dies nicht der Fall. Wenn ein Kollege einen Branch veröffentlicht hat, so kann man diesen sich lokal ziehen:

  • git fetch (lädt erst mal eine lokale Kopie des Origin Repository runter)
  • git checkout –b lokalername –track origin/remotename

ziehen.

Mit git checkout –b name erzeugt man übrigens einen lokalen Branch.

Meine tägliche Portion Git – Cleaning

Wer Änderungen, welche noch nicht ins Repository commited wurden, rückgängig machen will, kennt vielleicht den Befehl

  • git checkout .

oder

  • git reset –-hard head

welcher Änderungen an Dateien, die bereits im Repository enthalten sind, rückgängig macht.

Wer aber untracked files hat oder Dateien, die über gitignore ausgeschlossen und somit nicht Teil des Repository sind, der benötigt den Befehl

  • git clean –xdf

Meine tägliche Portion Git – Revert vs. Reset

Wenn man eine Änderung, die man bereits gepusht hat, rückgängig machen will, hat man 2 Optionen:

  • Revert: git revert head
  • Reset: git reset –-hard head~1 gefolgt von git push –f

Hintergrund ist folgender:

Client und Server befinden sich auf dem gleichen Ausgangsstand zum Zeitpunkt 0. Der Client macht ein commit und push die Änderung, sodass sowohl Client, als auch Server auf dem neuen Stand 1 stehen. Als konkretes Beispiel soll das hinzufügen der Datei ‘test.cs’ dienen, welche dem Repository hinzugefügt wurde.

Nun kann man einen sogenannten Negativ-Commit machen, bei dem der letzte Commit negiert wird. In unserem Beispiel mit der Datei test.cs wäre das ein Delete der Datei. Als Grundlage dient somit bei Client Stand 1, sodass problemlos der Commit auch gepusht werden kann, da auf dem Server ebenfalls Stand 1 vorliegt.

Bei einem Reset wird der letzte Commit rückgängig gemacht, sodass beim Client Stand 0 der aktuelle Stand ist. Wenn der Client nun auf den Server pushen will, dann versucht er Stand 0 gegen Stand 1 zu pushen, was der Server verweigert. Deshalb muss man mit git push –f explizit sagen, dass der Server den Push akzeptieren soll. Das entspricht also dem Verschieben des head-Zeigers in der Timeline.

Accessing Git without VPN/LAN connection

Setting up your Git repository while you’re in your company domain will bring up some trouble because the connection string is stored in your config. Follow these steps:

  • Navigate into the invisible directory “.git” of your repository
  • Open the “config”-File with notepad
  • Search for “[remote "origin"]”
  • Change the value of “URL”

For example, in my case it was git@ci:comwork which works fine, if i have VPN access. If i want to sychronate over the internet, i need to use git@repository.heco.de:comwork.git (notice: the suffix .git is optional; replace repository.heco.de with your address).

Nützliche Git und Bash Shell Tipps

In dem Artikel Git Aliase habe ich kurz die “.gitconfig” erwähnt. Da so gut wie jeder Entwickler mehrere Maschinen nutzt und normalerweise gerne mit den gleichen Einstellungen arbeitet, gilt es die benötigten config-Files zu synchronisieren. Neben der zuvor erwähnten Datei sollte man auch noch die “.bashrc” (ebenfalls im Homeverzeichnis des Users) sichern, die die Einstellungen für die Bash Shell enthält. Ich für meinen Teil habe das so gemacht, dass ich die Dateien in einem Verzeichnis, welches ich über alle meine Maschinen synchronisiere, abgelegt und mit hard links darauf referenziert habe. Windows bietet dafür den Befehl “mklink” an. Für die ganz faulen Tipper unter euch, poste ich hier den Inhalt aus meinen 2 config-Files:

.gitconfig

[alias]
    review = log -1 –patch
    unstage = reset head
    aa = add –all
    au = add –update
    s = status
    p = pull
    l = log –oneline -10
    k = !gitk –all & –all &
    aua = !git add –update && git commit –amend –reuse-message=HEAD
    aaa = !git add –all && git commit –amend –reuse-message=HEAD
    amend = commit –amend –reuse-message=HEAD
    aucp = !sh -c ‚git add –update && git commit -m \"$1\" && git push‘ –
    aacp = !sh -c ‚git add –all && git commit -m \"$1\" && git push‘ –

.bashrc

alias g=’git‘

Außerdem will ich noch kurz auf Einstellungen für die Bash Shell verweisen, welche ich sinnvollerweise von Alexander Groß übernommen habe:

imageimage

 

Öffnet dafür die Bash Shell, klickt rechts auf dem Rahmen und geht in Standardwerte. Schaut euch insbesondere die Fensterpuffergröße und die Bearbeitungsoptionen an. Um auch diese Einstellungen einfach auf alle Maschinen zu bringen, könnt ihr euch den Registry-Schlüssel “HKEY_CURRENT_USER\Console” exportieren.

Git Aliase

Wer wie ich nicht immer die gleichen 3 Befehle zum Hinzufügen, Commiten und Pushen von Änderungen zum Git Repository ausführen will, kann sich sogenannte Aliase definieren. Der folgende Screenshot zeigt 2 Aliase, die ich mir in meine benutzerbezogene “.gitconfig” eingetragen habe. Zeile 1 fügt lediglich geänderte Dateien hinzu, während Zeile 2 alle Änderungen hinzufügt:

 image

Hier noch textuell:

!sh -c ‚git add –update && git commit -m \"$1\" && git push‘ –

!sh -c ‚git add –all && git commit -m \"$1\" && git push‘ –

Alternativ sollten auch folgende Zeilen funktionieren:

"!f() { git add –-update; git commit -m \"$1\"; git push; }; f"

"!f() { git add –all; git commit -m \"$1\"; git push; }; f"

 

Beachtet, dass ihr die Aliase nicht über den entsprechenden Git Befehl anlegen solltet, da es sonst ggf. Probleme mit den Hochkommata gibt. Editiert stattdessen die besagte .gitconfig in eurem Homeverzeichnis. Das könnt ihr über den Befehl

vim .gitconfig

machen, wenn ihr euch im richtigen Pfad befindet.

Danke an dieser Stelle an Alexander Groß für seine Hilfe dabei.

%d Bloggern gefällt das: