Git und Intellij und Encoding

Neulich™ hatte ich das Problem, dass ein UTF-8-enthaltender String falsch nach XML transformiert wurde. UTF-8 ist (? war es zumindest früher oft) so eine Sache in Java, man muss(te) an drölf Stellen das Encoding explizit setzen; dazu gehörten zB Stream, Writer/Reader, StringBuilder, etc pp. Das mag inzwischen anders sein, denn nach langem Debugging stellte sich raus, dass nur das File-Encoding in IntelliJ falsch gesetzt war – der Code funkionierte ohne Änderung, die Quelle des Strings war bereits fehlerhaft gespeichert. Irreführenderweise hatte der IntelliJ-Debugger den String die ganze Kette hindurch korrekt angezeigt. “Nimm IntelliJ” haben sie gesagt, “das funktioniert super” haben sie gesagt. m(

Wie dem auch sei: Da UTF-8 an der Stelle zwingend gefordert war, musste sichergestellt werden, dass kein Entwickler, aus welchen Gründen auch immer, ein anderes Encoding einschleust, bzw., wie in diesem Fall, UTF-8 durch falsch konfiguriertes Encoding kaputtspeichert. Ein Ansatz könnte sein, im Git-Repo UTF-8 zu erzwingen. Ein Ansatz dafür kann sein, das Encoding in einem Git-Hook zu prüfen. Anbieten tun sich pre-commit (der erste Hook, der greift; client-seitig; Beispiel [1] [2]) und pre-receive (der erste serverseitige Hook; Beispiel).

[Für Stash/Bitbucket Server scheint es auch Möglichkeiten zu geben; ein fertiges Plugin habe ich aber nicht gefunden.]

pre-commit hat den Vorteil, dass sich keine Commits aufstauen, bevor das Problem auffällt. Dafür müssen lokale Hooks aufwändig verteilt/aktiviert werden – bsplw. über separat eingecheckte Verzeichnisse, die gesymlinkt (aber was ist mit Windows? Was mit wirklich lokalen Hooks? Und was ist noch zu beachten?) oder kopiert werden. Für pre-receive gelten Vor- und Nachteile inversiert, außerdem benötigt man Zugriff auf den Server auf Dateisystemebene.

Lange Rede, kurzer Sinn: Aus Gründen haben wir uns für einen pre-commit entschieden. Das Skript muss dabei .git/hooks/pre-commit heißen. Ich hätte ein Verzeichnis pre-commit mit Skripten darin erwartet, aber das wirft einen

cannot spawn .git/hooks/pre-commit: No such file or directory

Und es war gar nicht so einfach, eine Datei überhaupt mit dem falschen Encoding abzuspeichern. Sublime und Notepad++ haben sich (stillschweigend, was Notepad++ angeht) geweigert. Schließlich habe ich es mit IntelliJ geschafft, was allerdings auch gewarnt hat. Keine Ahnung, wie das ursprüngliche Problem überhaupt zustande kam.

Lokale Kopie des Skripts:

[Achtung: Das Skript kann nicht mit Binaries umgehen! Und das schließt bereits .woff ein. Offenbar ist es auch nicht trivial, Binaries zu erkennen; Internet nutzt dazu die Dateigröße oder auch Fileextensions. Ersteres scheint mir unzuverlässig, man denke an kleine Grafiken. Zweiteres ist sehr aufwändig…]

Beispielhafte Ausgabe (“ISO 8859-1.txt” heißt die Datei):

Und, der Vollständigkeit halber: Die Einstellung von Intellij:

btw: In Eclipse kann man Settings als Textfile exportieren und bsplw. in einem Repo ablegen – in IntelliJ scheint das nur als .jar exportierbar zu sein, bzw. über einen “IntelliJ Configuration Server” (WTF!?) verteilbar?

SourceTree/Windows: “The server’s host key is not cached in the registry”

Folgende Meldung

git -c diff.mnemonicprefix=false -c core.quotepath=false fetch origin
The server’s host key is not cached in the registry. You
have no guarantee that the server is the computer you
think it is.
The server’s rsa2 key fingerprint is:
ssh-rsa 2048 xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx
If you trust this host, enter “y” to add the key to
PuTTY’s cache and carry on connecting.
If you want to carry on connecting just once, without
adding the key to the cache, enter “n”.
If you do not trust this host, press Return to abandon the
connection.

bei jeder Operation (fetch, pull, …). Jede dieser Operationen funktioniert auf Kommandozeilenebene. Internet sagt, dieser Fall würde behandelt; ein entsprechender Dialog würde sich öffnen. Das ist nicht der Fall. Internet sagt weiterhin, man möge sich per SSH zum Server verbinden, um den Fingerprint in die known_hosts zu bekommen. Dort ist er bereits, und/denn die Meldung kommt nicht von SSH, sondern von PuTTY, das von SourceTree benutzt wird. Deswegen sagt Internet ([1], [2], [3]), man möge plink.exe <hostname> aufrufen. plink.exe kommt mit PuTTY. Das bringt aber keine Änderung.

Geht aber in die richtige Richtung: SourceTree benutzt offenbar PuTTY, allerdings finde ich keine putty.exe. Wenn ich mir diese ziehe, starte, und mich mit dem Zielserver verbinde, bekomme ich endlich den erwünschten Dialog – und ab dem Moment auch in SourceTree m(

UPDATE

Nach einem Reboot gab es wieder Probleme; die Lösung war: Pageant starten (läuft vermutlich schon), öffnen (über das Icon im System Tray!), den .ppk-Key von PuTTY/SourceTree manuell hinzufügen.

git: svn:externals-Äquivalent

Vorab: Ich bin git-Anfänger.

Wenn man nach einem git-Äquivalent zu svn:externals sucht, liest man von zwei Optionen:

  • Subtree merges: “very easy on other users, because it is automatically included when the repository is checked out or cloned”
  • Submodules: “all users have to manage the submodules, which are not automatically included in checkouts”

Die Zitate sind aus dem verlinkten Beitrag, aber die Tendenz “Submodules will man nicht” liest man auch an anderer Stelle [1, 2]. Meiner Meinung nach ist es genau andersrum:

Bei Subtree merges werden die externen Sourcen in das aktuelle Projekt gelegt – und nicht nur verlinkt! Das heißt, man pusht die (vermeintlich) externen Sourcen in das aktuelle Projekt. Ja, dadurch klont sie ab dem Moment auch jeder automatisch (vgl. Zitat oben), trotzdem entspricht das nicht dem Sinn und Zweck.

Darüber hinaus hatte ich zeitweise das Problem, dass Dateien aus dem externen Projekt gleich benamte lokale Dateien überschreiben wollten (bei README.md, composer.json, .gitignore, make, … durchaus ein Problem!). Das mag aber ein Anwenderfehler gewesen sein; nachdem mir Problem #1 klar wurde, habe ich Subtree merges nicht weiter verfolgt.

Submodules erfordern zwei zusätzliche Schritte beim Klonen (git submodule init, git submodule update), sowie einen beim Update, wenn sich das Submodule ebenfalls geändert hat (git submodule update). Dafür sind die externen Sourcen nun “nur” verlinkt, also wie bei SVN Externals. Dumm: Wenn sich das externe Projekt ändert, muss man den “Link” auf den entsprechenden neuen Hash zeigen lassen, und das auch commiten. Passt jemand nicht auf und commitet nun wieder den alten Link, revertet er dadurch die Änderung.

Das spricht aber nicht gegen Submodules als Externals-Ersatz – es spricht höchstens gegen git, wo alles “ein wenig” komplizierter ist, als es sein sollte :-/ PS dazu: Ich habe mein Glück die meiste Zeit auf der Kommandozeile versucht, erst später zeigte Tobi mir Sourcetree. Damit sollte das leichter sein.

Composer: Von git importieren

Am Beispiel von serbanghita/Mobile-Detect:

Im Code dann:

Learnings hier:

  • Repo-Type ist “vcs” (“git” ist veraltet)
  • Als Repository-URL genügt die oben genannte – Groß-/Kleinschreibung ist egal, .git nicht nötig
  • Der “require”-Name ergibt sich nicht von selbst – insbesondere ist es nicht das “serbanghita/Mobile-Detect” aus der Repo-URL! Um an den korrekten Namen zu kommen, guckt man entweder in die composer.json auf Git (sofern vorhanden), oder man ruft composer update -v auf (“-v” für “verbose”)
  • Ist kein Namespace definiert, darf der Slash vor “Mobile_Detect” trotzdem nicht fehlen

Git als offline-Verlängerung von SVN

Ja, dafür ist git nicht gedacht, und ja, git ist viel besser als SVN.

Aber.

Angenommen, man hat ein Projekt im SVN. Und muss nun zum Kunden, bei dem kein Zugriff auf dieses SVN möglich ist. Dann wäre es doch potentiell elegant, das Projekt als git-Projekt auf einen USB-Stick auszuchecken, und gegen dieses portable Repository zu arbeiten. Gesagt, getan:

Dann, beim Kunden, checkt man vom USB-Stick aus:

bzw. arbeitet man dort wie (von git) gewohnt. Später synchronisiert man Stick und lokalen SVN-Checkout, und diesen spielt man zurück in’s SVN.

Danke an Arndt! Quellen: [1], [2], [3], git-svn