Erste Entwicklungs-Branch

Nun können wir mit tatsächlicher Entwicklungsarbeit beginnen. Nachdem wir unseren master-root-Commit erstellt haben sollte die Arbeit in einer Branch erstellt werden. Wir erstellen sie und wechseln von master zu ihr:

$ git branch feature/simple-build-system
$ git checkout feature/simple-build-system
Switched to branch 'feature/simple-build-system'

Branch-Namen dürfen viele Zeichen enthalten, es ist aber Empfehlenswert sich auf die Kleinbuchstaben des lateinischen Alphabets, Zahlen, das Minus - und Schrägstriche zu beschränken. Die Schrägstriche können als Hierarchieebenen-Trenner verwendet werden. Es empfiehlt sich, eine begrenzte Zahl von Hierarchie-Prefixen zu verwenden. Für unsere Zwecke sind das:

  • workflow/ für Workflow-Neuentwicklungen.
  • feature/ für neu hinzugefügte Logiken.
  • fix/ für Korrekturen von Fehlern.
  • change/ für Änderungen an bestehenden Logiken.

Die git-branch-git-checkout-Kombination wird häufig genug gebraucht dass es dafür einen Shortcut gibt: git checkout -b <branch>. Dieser wird im Folgenden verwendet werden.

In unserer neuen Branch erstellen wir nun eine erste Quellcode-Datei, mit der wir unser Build-System testen können.

$ vim Main.java
public class Main {
public static void main(String[] args) {
System.out.println("Hello, World!");
}
}

Inhalt Main.java

Im Anschluss wird die Datei wie gehabt committed:

$ git add Main.java
$ git commit

Add a source file for testing compilation

Um nicht javac von Hand bedienen zu müssen erstellen wir uns ein kleines Makefile. Hierbei muss aufgepasst werden, dass Einrückung mittels Tab-Zeichen stattfindet. Ein Texteditor, der Makefile-Dateitypen kennt, sollte das automatisch berücksichtigen.

$ vim Makefile
JC=javac
JAVA=java
CLASSES = \
Main.java
.SUFFIXES: .java .class
.java.class:
$(JC) $*.java
.PHONY: compile
compile: $(CLASES:.java=.class)
.PHONY: clean
clean:
-$(RM) *.class
.PHONY: run
run: compile
@$(JAVA) Main
.PHONY: all
default: compile

Inhalt Makefile

Auch diese Datei können wir nun wieder committen:

$ git add Makefile
$ git commit

Add Makefile for compiling and runinng

Vielleicht wäre aber ein Test vor dem Commit angebracht gewesen. Holen wir dies nach:

$ make
make: Nothing to be done for `compile'.
$ make run
Error: Could not find or load main class Main
make: *** [run] Error 1

Das sieht nicht gut aus. Bei genauem Hinsehen offenbart sich ein fehlendes "S" in Zeile 12 des Makefiles (CLASESCLASSES). Nach dieser Korrektur sieht es besser aus:

$ make run
javac Main.java
Hello, World!

Wir könnten die Korrektur in einem neuen Commit hinzufügen. Da unsere lokale Entwicklungsbranch, und insbesondere der initiale Makefile-Commit, aber noch nicht veröffentlicht wurden, können wir den letzten Commit aber alternativ auch anpassen:

$ git add Makefile
$ git commit --amend

Es öffnet sich wieder ein Editor, dieses Mal aber mit der Commit-Message vom letzten Commit bereits vorhanden. Speichern, schließen, und niemand hat wird unseren voreiligen ersten Commit jemals sehen!

Dass es keinen dritten Commit gibt, lässt sich auch mithilfe der Historie prüfen:

$ git log
commit 822c56d6760226203d76014fcc489998233ded64 (HEAD -> feature/simple-build-system)
Author: Some One <some.one@proclane.com>
Date: Mon Nov 25 13:43:34 2019 +0100
Add Makefile for compiling and runinng
commit 062eda185e8b66aed570cba0fb9b12279a22c110
Author: Some One <some.one@proclane.com>
Date: Mon Nov 25 13:26:17 2019 +0100
Add a source file for testing compilation
commit ad65f62c553c0bff5e63725c868cf1938ed32742 (master)
Author: Some One <some.one@proclane.com>
Date: Mon Nov 25 11:45:51 2019 +0100
Initial commit, add .gitignore and empty README

Leider hat sich beim Verfassen der Message ein Fehler eingeschlichen. Auch so ein Fehler lässt sich via --amend korrigieren. Ohne eine Datei zu stagen wird der folgende Befehl erneut ausgeführt:

$ git commit --amend

Nun korrigieren wir "runinng" zu "running" und sollten damit unseren Makefile-Commit endlich fertig haben.

Die Tests haben jedoch Dateien erzeugt, die wir nicht committen wollen:

$ git status
On branch feature/simple-build-system
Untracked files:
(use "git add <file>..." to include in what will be committed)
Main.class
nothing added to commit but untracked files present (use "git add" to track)

Wir könnten die .class-Datei zwar löschen, aber jedes Kompilieren würde die Datei neu anlegen. Wir sollten stattdessen alle Dateien dieser Art ignorieren. Dafür fügen wir einen neuen Eintrag in unserer .gitignore ein, dieses Mal kommentiert und direkt von der Kommandozeile:

$ echo > .gitignore
$ echo '# Build artifacts' >> .gitignore
$ echo '*.class' >> .gitignore

Git ignoriert schon jetzt die .class-Datei, die Änderungen in der .gitignore müssen allerdings noch committed werden.

$ git status
On branch feature/simple-build-system
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git restore <file>..." to discard changes in working directory)
modified: .gitignore
no changes added to commit (use "git add" and/or "git commit -a")

Ein solcher Commit passt inhaltlich zu unserer aktuellen Branch, also machen wir das auch hier. Bevor wir die Datei stagen, gucken wir noch einmal schnell welche Änderungen aus Gits Sicht gemacht wurden:

$ git diff
diff --git a/.gitignore b/.gitignore
index 956ec59..9b4caac 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,3 @@
-%SystemDrive%
-Thumbs.db
-.DS_Store
+
+# Build artifacts
+*.class

Die drei mit + beginnenden Zeilen wurden neu hinzugefügt. Die drei Zeilen, die mit - beginnen wurden entfernt - das war nicht unser Ziel. Der erste der drei echo-Befehle hätte auch "append" (>>) statt "overwrite" (>) verwenden müssen. Zum Glück war die Datei schon committed, wir können sie einfach wieder herstellen. Um unsere Änderungen nicht doppelt machen zu müssen, sichern wir sie kurz weg, fügen sie an die wiederhergestellte Datei an, und löschen die Kopie danach:

$ cp .gitignore bak
$ git restore .gitignore
$ cat bak >> .gitignore
$ rm bak
$ git diff
diff --git a/.gitignore b/.gitignore
index 956ec59..ac75306 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,6 @@
%SystemDrive%
Thumbs.db
.DS_Store
+
+# Build artifacts
+*.class

Das sieht schon besser aus. Es folgt ein Commit.

$ git add .gitignore
$ git commit

Ignore .class files

Hinweis: git diff liefert die nicht gestageden Änderungen, git diff --cached stattdessen alles, was schon mit git add hinzugefügt wurde.