Installation und Konfiguration aktuelles OpenJDK-Java�a0;15, JavaFX, Eclipse 2020‑09, e(fx)clipse, GIT

Das vorliegende Skriptum soll die Hürden von Konfiguration und Einstieg in diese Themen beim autonomen Arbeiten möglichst gut bewältigbar machen.

Hier ist die Installation der benötigten Tools u.ä. sowie deren Handhabung beschrieben. Im Zweifelsfalle ist es empfehlenswert, alle Elemente auf den aktuellsten Stand zu bringen, da damit am wenigsten Probleme zu erwarten sind und durch die Homogenität der Infrastruktur bei allen Teilnehmern die Betreuung einfacher sein sollte.

Es wird nur Windows 10 behandelt – vermutlich verwendet in der Klasse niemand ein anderes System (falls doch, kann leicht Information dazu ergänzt werden)

Neu-Installation von Eclipse und OpenJDK ist allerdings nur nötig, wenn noch nicht mindestens JDK 11 bzw. Eclipse 2019-09 installiert sind.

Falls die Anleitung wichtige Fragen, Entscheidungen oder Probleme nicht behandelt, bitte ich um Rückmeldung – sie wird nach Möglichkeit ergänzt.

1. Installation und Konfiguration von OpenJDK-Java�a0;15

Es gibt seit kurzer Zeit (irgendwann 2019?) eine Organisation (unterstützt von IT-Firmen wie IBM, RedHat, Amazon, Microsoft) – Website mit dem Titel AdoptOpenJDK - Open Source, vorkonfigurierte OpenJDK Binärdateienhttps://adoptopenjdk.net, die für alle Plattformen alle OpenJDK-Versionen seit OpenJDK 8 bereitstellt.

Damit ist eine branchenweit akzeptierte und unterstützte Möglichkeit vorhanden, Java in hoher, gesicherter Qualität unter freier Lizenz zu installieren.

Spätestens beim Aktualisieren von Eclipse ist es ratsam, OpenJDK 15 zu installieren.

1.1. Vorgehensweise

1.1.1. Download OpenJDK 15

Stand 2020-09-23: unter AdoptOpenJDK – Open Source – vorkonfigurierte OpenJDK Binärdateien  —  https://adoptopenjdk.net/?variant=openjdk15&jvmVariant=hotspot ist für die aktuell verwendete Plattform (Windows, Linux, OS X, …​) der Download direkt möglich – es lässt sich aber auch eine andere Ziel-Plattform auswählen.

1.1.2. Entfernen aller bestehenden Java-Installationen:

  • Windows-Start-Button → unten links Zahnrad-Icon (Einstellungen) → Windows Einstellungen → Apps → Apps & Features → Im Suchfeld eingeben: java

  • Löschen der/des JDKs, die JREs werden vermutlich mit deinstalliert, verbleibende JREs ebenfalls löschen, wenn nicht expizit für bestimmte Apps benötigt.

1.1.3. Installation des heruntergeladenen OpenJDK

einfach per Doppelklick – alle Komponenten auswählen:

AdoptOpenJDK-Setup – alle Komponenten ausgewählt

TODO: image missing!

Nach Fertigstellen der Installation Kontrolle mit der "Eingabeaufforderung":
java -version …​ liefert vermutlich eine Fehlermeldung.
Falls dies der Fall ist, einfach Windows neu starten, dann nochmals obiges Kommando – jetzt sollte es klappen.

2. Installation und Konfiguration von Eclipse

Da wir – falls es die Zeit erlaubt oder falls es in eurem Mini-Gruppen-Projekt Bedarf gibt – auch mit CSS und vielleicht sogar mit Verwendung von HTML und Javascript innerhalb von JavaFX arbeiten werden, ist die Installation der Eclipse-Variante Eclipse IDE for Enterprise Java Developers empfehlenswert (aber nicht notwendig).

Am einfachsten den Installer herungerladen:
https://www.eclipse.org/downloads/download.php?file=/oomph/epp/2020-09/R/eclipse-inst-jre-win64.exe
und die oben genannte Variante installieren - eher nicht als Administrator, sondern als normaler Benutzer im eigenen Benutzerverzeichnis. Das vorgeschlagene Verzeichnis C:\Users\<username>\Eclipse ist recht vernünftig.

Wichtig: Vor oder nach der Installation und ersten Tests die alte Eclipse-Version löschen - Workspaces werden u. U. mit der alten Version nicht mehr verwendbar und die Chance auf irrtümliche Verwendung der alten Version ist groß!

3. Installation und Konfiguration von JavaFX

3.1. Download und Installation

Die Pakete sind verfügbar unter https://gluonhq.com/products/javafx/.

Die Versionsnummern zwischen JDK und OpenJFX müssen nicht übereinstimmen - beide Projekte werden separat entwickelt, Kompatibilität ist in den OpenJFX Release-Notes nachzulesen - siehe Link auf https://gluonhq.com/products/javafx/.

Da es eine große Zahl von Java-Zusatzbibliotheken gibt, von denen möglicherweise einige für die Projekte benötigt werden, sollte man einen sinnvollen Platz wählen, in dem all diese untergebracht werden. Ein guter Platz als Basis ist z.B.: C:\Users\<username>\Java, damit ergibt sich C:\Users\<username>\Java\OpenJFX\ (u.U. Benutzer statt Users), wohin das extrahierte Verzeichnis javafx-sdk-15 und die ZIP-Datei mit Javadoc: openjfx-15-javadoc.zip zu kopieren ist.

3.2. Erstellen einer JavaFX-User-Library in Eclipse

Damit JavaFX in Eclipse verwendbar ist, muss eine User-Library erstellt werden:

Eclipse-Menü → Window → Preferences → Preferences-Dialog öffnet.
Darin: Java → Build Path → User Libraries.
Dialog User Libraries öffnet, Button New …​ → Eingabefeld User library name: JFX-15OK.
Nun erscheint die Library JFX-15 in der Liste.
Selektieren, dann Add External JARs …​ → Dateiauswahl-Box öffnet.
Dort wird das obige Verzeichnis C:\Users\<username>\Java\OpenJFX\javafx-sdk-15\lib\ geöffnet.
Alle Dateien mit Endung .jar (d.h. alle außer src.zip) werden selektiert und mit *OK übernommen.
Um zu JavaFX in Eclipse auch Javadoc-Information zu sehen, muss nun noch für alle JARs jeweils zumindest einer der Einträge Source attachment oder Javadoc location gefüllt werden.

Also z.B. Source attachment auswählen, Button Edit …​ .
Dialog Source Attachment Configuration → External location → Pfad schreiben oder → External File → auswählen:
C:\Users\<username>/Java/OpenJFX/javafx-sdk-15/lib/src.zip und Zeichensatz UTF-8 selektieren.

Alternativ/ergänzend zu Source Attachment analog für Javadoc location:
selektieren → Edit …​ → im Dialog: Javadoc in archive und External file auswählen, direkt Pfad C:\Users\<username>\Java\OpenJFX\openjfx-15-javadoc.zip eintippen oder per Browse …​.
Dann Path in Archive: javafx-15-javadoc und zuletzt sicherheitshalber Validate …​. Sollte liefern: Location is likely valid …​ .

Nachdem dies für alle JARs getan ist (außer für SWT - da gibt es hier kein Javadoc) können die Preferenzen geschlossen werden.

3.3. Erstellen einer String-Substitution in Eclipse (derzeit nicht verwendet)

Um sich bei der Projekt-Konfiguration die Eingabe des Pfades zu den JavaFX-Bibliotheken zu ersparen, ist die Definition einer String-Substitution (eine Textersetzungs-Variable) empfehlenswert. Dazu öffnet man nochmals den Preferences-Dialog.
Darin: Run/Debug → String Substitution → New …​ . Im nun geöffneten Dialog die 3 geforderten Werte eingeben:
Name: JFX-15 (aus praktischen Gründen selber Name wie User Library)
Value: C:\Users\<username>\Java\OpenJFX\javafx-sdk-15\lib Description: JavaFX 15 LibraryOKApply and closeOK.

4. Installation und Test von e(fx)clipse: fällt derzeit weg!

Die JavaFX-Eclipse-e(fx)clipse Erweiterung (Version 3.6.0) ist in aktuellen Versionen von Eclipse/Java nur mehr teilweise funktionsfähig.
Es ist für die Erstellung von JavaFX-Projekten nicht nötig und erleichtert die Arbeit im derzeitigen Status insgesamt nicht wesentlich.

Nachteile des Weglassens:
  • die automatisch generierte JavaFX-Klasse Main, die ein leeres Fenster öffnet, muss händisch (sinnvollerweise durch Kopieren einer Vorlage) erstellt werden.

  • JavaFX-Properties müssen händisch erstellt werden.

  • vermutlich weitere.

Vorteile des Weglassens:
  • nicht funktionsfähige Bibliothek JavaFX SDK muss nicht mehr entfernt/verschoben werden

  • Es kann nicht irrtümlich ein erst händisch korrigierbares JavaFX-Projekt angelegt werden

  • Es gibt keine Probleme, die App "laufen zu lassen".

  • etc.

5. Erste Experimente mit JavaFX in Eclipse – Probe-Projekt

5.1. Probe-Projekt Überblick

Es wird nun ein normales Java-Projekt angelegt und die erzeugte User-Library JFX-15 eingebunden. Da JavaFX in Java 11 (und neuer) nicht mehr Teil des JDK ist, sondern unter Nutzung der neuen Modularisierungsmöglichkeiten bereitgestellt wird, ist die einfachste Lösung zur Einbindung, auch unsere JavaFX-Projekte als modularisiertes Java-Projekt zu organisieren.

Der wichtigste Schritt dazu ist das Erstellen einer Datei module-info.java direkt im Folder src des Eclipse-Projekts.

JavaFX in Java 11 nutzt ein neues, ergänzendes Strukturierungskonzept in Java-Projekten – Module.
Zusätzlich zu den Packages gibt es nun eine "darüber liegende" Struktur, die v.a. für große Projekte wesentliche Möglichkeiten bereitstellt.

Technisch muss dazu eine Datei direkt im Eclipse-Folder src angelegt werden – mit dem oben angeführten fixen Namen module-info.java.
Hier eine Beispiel-Datei – diese enthält für unsere Zwecke (JavaFX) nötige Einträge – Modul-Name my_unique.module und exportierter Package-Name my.unique.basepkg.proj_pkg sind anzupassen, u.U. weitere benötigte JavaFX-Module zu aktivieren:

Module-Descriptor in ${proj_root_srcdir}: module-info.java
module my_unique.module {                (1)
    exports my.unique.basepkg.proj_pkg;  (2)
    //
    requires javafx.base;                (3)
    requires javafx.graphics;            (4)
    requires javafx.controls;            (5)
    //
    // requires javafx.media;            (6)
    // requires javafx.web;
    // requires javafx.fxml;
    //.
    // requires javafx.swing;            (7)
    // requires javafx.swt;
}
1 der Module-Name (Konventionen wie bei Packages – Kleinbuchstaben, Unterstriche, u.U. Punkte).
Die Punkte werden – anders als bei Packages – nicht in Subfolders "übersetzt".
2 das Package, ab dem das Mudul "beginnt"
3 das Basis-Package, das immer benötigt wird - es ist allerdings indirekt vorhanden – wird in den Modul-Descriptoren des jeweiligen Pakets als "requires transitive" gekennzeichnet. Bei Weglassen entsteht jedoch eine lästige Warnung.
4 ein benötigtes JavaFX-Modul ("requires transitive" würde bedeuten, dass die indirekten Abhängigkeiten – in diesem Fall javafx.base automatisch berücksichtigt würden, d.h. Zeile <3> könnte weggelassen werden)
5 ein zweites JavaFX-Modul (es gibt insgesamt 8)
6 weitere in späteren Projekten benötigte JavaFX-Module
7 die restlichen 2, vermutlich von uns in nächster Zeit nicht benötigten JavaFX-Module

5.2. Probe-Projekt Step-For-Step

5.2.1. Rohfassung estellen

  • Eclipse-Menü File → New → Project …​ → Dialog New Project öffnet → NORMALES Java Project (KEIN JavaFX-Projekt) → Projekt-Dialog öffnet sich.

  • Nur Projekt-Name - z.B. JfxTest1 eintragen, Execution Environment Use Default JRE …​

  • Next (noch nicht 'Finish'!) �a0;�a0; → im Dialog auf Tab: Libraries �a0; → In Liste obersten Eintrag: Modulepath selektieren !!

  • add Libraries …​ → in Liste: User Library → Next > �a0; → JFX-15 auswählen → Finish.
    Nun sollte in der Liste unterhalb von Modulepath der Eintrag JFX-15 zu sehen sein.

  • Nochmals Finish, um das Prolekt anzulegen.

  • Es erscheint erstaunlicherweise ein weiterer (nun wirklich letzter) Dialog: Create module-info.java mit Feld Module name:, Name eintragen (siehe anschließender "TIP"). Selektieren von Generate comments ist generell eine gute Idee.

Module sollten, falls 'öffentlich' nutzbar, global eindeutige Namen haben, aber in jedem Fall den Konventionen für Package-Namen folgen (KLeinbuchstaben + '_' + '.') – z.B.: inverser Domainname + interne Eindeutigkeit + Projekt.
Konkret: at.htlw5_1920.pos_2dhif_mustermann.jfxtest1
oder einfacher: mustermann_2dhif.jfxtest1
  • Create klicken. Nun ist das Projekt vorhanden und die Datei module-info.java liegt direkt im Ordner src. Sie enthält außer dem Modul-Namen noch keine Information.

  • Klasse erzeugen, die den Startpunkt des Programms darstellt, Name häufig Main oder App. Am besten die Checkboxen fürs Erzeugen von public static void main(…​) und Constructors from super class abwählen, dann ist das Hineinkopieren des nachfolgenden Codes am einfachsten.

  • Nachstehende Methoden + Konstruktor direkt in die eben erzeugte Klasse hineinkopieren, Main von 'Application' erben lassen (wir damit zu einer JavaFX-Klasse) und die nötigen Importe (mit IDE-Unterstützung) durchführen (Details siehe nach dem Listing):

Klasse in ${proj_root_srcdir}: my.unique.pkg.Main.java
    public Main() {
        System.out.println("Constructor Main() called");
    }

    public static void main(String[] args) {
        System.out.println("main(...) called, now calling launch(...)");
        launch(args); // ruft indirekt start(...) auf
        System.out.println("main(...) finished");
    }

    @Override
    public void init() throws Exception { // Optional Initialisierung VOR Zugriff auf GUI (Dateien auslesen, etc.)!!
        super.init();
        System.out.println("init() - initialization (BEFORE access to GUI) called");
    }

    @Override
    public void stop() throws Exception {
        // Aufraeumen - MIT Zugriff auf GUI
        System.out.println("stop() called");
        super.stop();
    }

    @Override
    public void start(Stage primaryStage) throws Exception { // , bekommt das Hauptfenster als Parameter mit.
        // start(...) indirekt aufgerufen von launch(...), ihrerseits in main(...) aufgerufen
        System.out.println("start(...)- the GUI activities - called)");
        // Vom JavaFX Laufzeitsystem wird schon das Hauptfenster (hier 'primaryStage' genannt) bereitgestellt.
        // Erzeugen des Basis-Containers - entspricht in HTML ungefähr dem Bereich innerhalb <body>...</body>:
        BorderPane root = new BorderPane(); // Wurzel-Container für alle GUI-Elemente, wird unten 'scene' übergeben
        //
        // Scene ist der gesamte Window-Inhalt - vom Fenstertitel zu UI-Elementen wie Menü, Hauptbereich -
        // in Analogie zu Webseite entspricht es allem innerhalb von <html>...</html>.
        // Bei Erzeugung der Scene wird Basis-Container, Breite, Höhe des Fensters übergeben:
        Scene scene = new Scene(root, 300, 200);
        // Es können CSS-Stylesheets verwendet werden. Hier wird die aktuelle Stylesheet-Liste
        // abgefragt und eine eigene Stylesheet-Datei hinzugefügt (Pfad rel. zu Module-Basis-Dir):
        scene.getStylesheets().add(getClass().getResource("fx-app.css").toExternalForm());
        //
        // nun wird dieser Basis-Container dem Hauptfenster zugeordnet:
        primaryStage.setScene(scene);
        //
        // der Fenstertitel wird gesetzt (wie HTML-<title>):
        primaryStage.setTitle("Mein erstes JavaFX-Programm");
        //
        // Nun erstellen wir einige "richtige" UI-Elemente: ein Label, anschließend
        // einem der Container-Arten: VBox ...
        Label lbl1 = new Label("Hello User!"); // Erzeugen
        // Erscheinungsbild des Labels z.B. einfach mit CSS stylen - spezielle CSS-Namen mit Prefix '-fx-':
        lbl1.setStyle("-fx-font-size: 2em;-fx-background-color:yellow;");
        //
        // Erzeugen eines zweiten Containers (kann Untereinander-Anordnung seiner Elemente)
        VBox vbox1 = new VBox();
        vbox1.setStyle("-fx-border-color: red;"); // wieder stylen
        // lbl1 anfügen an Liste der 'children' von vbox1 ...
        vbox1.getChildren().add(lbl1);
        // noch minimale Größe für VBox festlegen (füllt verfügbaren Platz, wächst bei Bedarf automatisch):
        vbox1.setMinSize(250, 150); // Obergrenze: vbox1.setMaxSize(maxWidth, maxHeight);
        //
        // Auch vbox1 muss in den Basis-Container eingefügt werden. Dieser ist vom Typ BorderPane,
        // die 5 beschickbare Regionen hat: Top, Left, Center, Right, Bottom
        root.setCenter(vbox1); // hier wird im Center plaziert
        //
        // Zur Demo noch schnell ein Label im rechten Bereich:
        Label lbl4RootRight = new Label("hier\nist\nrechts!"); // \n ... Zeilenschaltung
        root.setRight(lbl4RootRight);
        //
        primaryStage.show(); // das erzeugte Fenster wird erst nach expliziter Aufforderung angezeigt.
        System.out.println("start(...) finished");
    }

5.2.2. Syntaxfehler-Bereinigung

Um die vielen Fehler zu beseitigen, ist es zuerst nötig, Klasse Main von JavaFX-Klasse javafx.application.Application erben zu lassen, d.h. umzustellen auf public class Main extends Application { …​ }.
Das könnte – und sollte – man schon im Eclipse-Wizard zur Klassenerstellung tun, womit schon zu Beginn ein syntaxfehlerfreier Source-Code entsteht – da man dies aber leicht vergisst, ist hier die daraus folgende Situation beschrieben.

Danach liefern die Eclipse-Quick-Fixes u.a. den Eintrag: Import 'Application' (javafx.application) and add 'requires javafx.graphics' to module-info.java – dieser ist zu wählen (genau schauen, es gibt einen ähnlichen mit (com.sun.glass.ui), der falsch ist!).
Achtung: nun NICHT bei Main auf Add unimplemented methods klicken, sondern nun alle vorgeschlagenen Importe in der gesamten Klasse durchführen (für Stage, BorderPane, Label, VBox, etc. – immer die Variante mit import '…​' (javafx.*), aber nie die mit javafx.swing.*).
Nun ist die Klasse syntaktisch fehlerfrei – weitere (beim Start auftretende) Fehler werden aber noch zu beseitigen sein.

5.2.3. Tipps zur Syntaxfehler-Bereinigung

Folgende Fehler können leicht auftreten:

Die JavaFX-Klassen werden nicht gefunden, Importe schlagen fehl

Kontrolle, ob die User-Library (bei uns JFX-15 genannt) im Package-Explorer sichtbar ist (eine Ebene unter dem Projekt, anschließend an src und JRE).

  • Wenn nicht: Angelegte User-Library JFX-15 zum Projekt hinzufügen:
    Rechtsklick auf Projekt im Package Explorer → Im Menu: Build PathConfigure Build Path …​ → im Dialog auf Tab: Libraries → analog zu Abschnitt 5.2.1, “Rohfassung estellen” vorgehen.

  • Wenn schon: User-Library ist vermutlich nicht korrekt konfiguriert - nochmals prüfen (siehe obigen Abschnitt Abschnitt 3.2, “Erstellen einer JavaFX-User-Library in Eclipse ”).
    Die User-Library JFX-15 sollte hierarchisch "aufklappbar" sein, darunter sollten zumindest alle von uns benötigten JavaFX-JARSs sichtbar sein (entsprechen den im module-info.java mit requires gelisteten JavaFX-Modulen):

    • javafx.base.jar

    • javafx.controls.jar

    • javafx.graphics.jar

5.2.4. Startvorbereitung – Run Configuration erstellen

Zum Starten der App muss eine Run Configuration erstellt werden: → Rechtsklick auf das Projekt im Package-Explorer → unterster Eintrag: PropertiesRun/Debug SettingsNew …​Java ApplicationOK.
Im nun geöffneten Dialog in Tab Main zuerst sinnvollen Namen für die Runtime-Configuration wählen
– z.B.: JfxTest1_Main (<Projektname>_<App-Klassen-Name>).
Das richtige Projekt sollte schon ausgewählt sein (sonst unter Browse …​ auswählen). → den "Main-class"-Eintrag mit der eigenen Klasse unter Search …​ wählen (z.B. Main - mein.pkg) → OK. Im Tab Arguments ist nun keinerlei Eingabe erforderlich. → OK → nun sollte die neue Launch Configuration in der Liste sichtbar sein. → Apply and Close.

5.2.5. Erster Startversuch – Laufzeitfehler-1-Bereinigung

Erster Startversuch wirft Exception.
Die Fehlermeldung enthält (meine Klassen und Packages) die Zeile: Caused by: java.lang.IllegalAccessException: class com.sun.javafx​.application​.LauncherImpl (in module javafx.graphics) cannot access class rx1920_2dhif.jfxtest5.Main (in module rx1920_2dhif.jfxtest5) because module rx1920_2dhif.jfxtest5 does not export rx1920_2dhif.jfxtest5 to module javafx.graphics.

Daraus ist ersichtlich, dass das Modul javafx.graphics den 'export' meines Moduls erfordert. Somit ergänzen wir in Datei module-info.java den Eintrag (irgendwo innerhalb des Blocks module …​ {exports <strg><leerzeichen>} - und Eclipse bietet uns den richtigen Eintrag an – den Namen des eigenen 'module'. → Speichern, fertig.

5.2.6. Zweiter Startversuch – Laufzeitfehler-2-Bereinigung

Zweiter Startversuch: neuerliche Exception.
Der erste Fehler-Message aus einer eigenen Klasse ist: Caused by: java.lang.NullPointerException
at rx1920_2dhif.jfxtest5/rx1920_2dhif.jfxtest5.Main.start(Main.java:48)

Zeile Main.java:48 ist:
scene.getStylesheets().add(getClass().getResource("fx-app.css").toExternalForm()); Es sollte hier eine CSS-Datei geladen werden, die ist aber nicht da. Lösung: direkt 'neben' Klasse Main Datei fx-app.css erzeugen – mit dzt. nur einem Kommentar als Inhalt (sinnvoller Inhalt wird später besprochen), z.B.:
/* JavaFX CSS - Leave this comment until you have created at least one rule which uses -fx-Property */.

5.2.7. Dritter Start – Erfolg

keine Exception mehr – die erste JavaFX-App öffnet ihr GUI (vorerst keine weitere Funktion):

5.3. Mögliche Probleme beim Arbeiten an JavaFX-Apps

Die laufende JavaFX-App
  • Falls der Modul-Namen geändert wird, muss die Run Configuration neu erstellt werden - wegen eines Bugs in Eclipse wird diese Änderung nicht automatisch übernommen und der Programmstart kann fehlschlagen mit der Fehlermeldung:
    Error occurred during initialization of boot layer
    java.lang.module.FindException: Module RX-JFX-Scribble2 not found

    Beim Neu-Erstellen einer Run Configuration wird der aktuelle Modul-Name jedoch korrekt verwendet und das Problem ist behoben.

  • Weiteres folgt bei Bedarf

6. Tutorial Blitzeinstieg GIT mit Eclipse und GitLab

Da wir GIT vorerst nur sehr minimalistisch verwenden werden, vermeiden wir hier nahezu alle Theorie.

Nur einige grundlegende Begriffe und Konzepte, auf die man bei der Bedienung häufig trifft, werden nachstehend kompakt und minimalistisch erläutert und können bei Bedarf hier nachgelesen werden.

Für weitergehende Infos wird – neben vielen weiteren Web-Tutotials und sonstigen Infos – direkt von der hinter GIT stehenden Open-Source Organsiation Git eine sehr gute, leicht verständlich geschriebene, umfassende Git Dokumentation bereitgestellt:
Direkt über dem Text links ist ein Popup-Menü vorhanden: Chapters�a0;V. Dieses gibt übersichtlichen Zugriff auf das Inhaltsverzeichnis.
Es gibt viele gut gepflegte Sprach-Versionen – auch eine deutsche Fassung.

Weitere gute Tutorials bieten die großen GIT-Hosting-Anbieter – die 3 bekanntesten vermutlich:

6.1. Essentielle Begriffe

CLI, GUI

Die Abkürzing CLI steht für Command Line Interface, in Windows Eingabeaufforderung, für Apple OS X, Linux und Unix allgemein: Shell.
GUI steht für Graphical User Interface, d.h. heute übliche Windows-App bzw. die Äquivalente für Apple und Linux.

Versions-Management

Auch Version Control System (VCS), Software Configuration Management (SCM, enthält noch weitere Funktionalitäten) genannt. Aktuell verbreitete VCS-Systeme (Open-Source): GIT, Mercurial, Subversion. GIT dominiert die Branche - auch Microsoft verwendet es als Basis für seine Entwicklung. Es ist ein Distributed VCS, das sehr viel Spielraum für die organisatorische Gestaltung des Entwicklungsprozesses lässt. Im Prinzip geht es u.a. um:

  • Rekonstruierbarkeit bzw. Umschalten zwischen älteren und neuen Versionen bzw. Entwicklungszuständen - Checkout

  • Auffinden, Darstellen und Erzeugen/Anwenden von Änderungs-Dateien der Änderungen zwischen (beliebigen) 2 Versionen – diff und patch

  • Erläutern/Begründen der Arbeiten/Änderungen, die nun fertig in der jeweiligen Version vorliegen – Commit-Messages

  • Paralleles Entwickeln mehrerer Team-Mitglieder am selben Projekt – Clone und Push, Fetch, Pull

  • Arbeiten an mehreren Varianten eines Projekts (Pflege Version 1, Entwicklung Version 2) – Branch, Merge

SHA1-Hash

Die zu versionierenden Daten werden in GIT durch einen aus Dateninhalt und Metadaten generierten, aus 40 Hexadezimal-Ziffern bestehenden Hash-Code (Typ SHA-1) identifiziert. D.H. man kann identischen Inhalt (samt Metadaten) an übereinstimmendem Hash-Code erkennen.
Die Wahrscheinlichkeit, dass 2 Dateien bei unterschiedlichem Inhalt den selben Hash-Wert erhalten ist dermaßen gering, dass sie um viele, viele Größenordnungen unter der Wahrscheinlichkeit von Software-Bugs, Hardware-Problemen oder anderen Datenkorruptions-Ursachen liegt. Man kann den Hash-Wert also ohne Bedenken als ID für einen bestimmten Inhalt verwenden.
Das hat zumindest folgende Konsequenzen:

  • über alle Versionen hinweg wird jeder Datei-Inhalt (incl. Metadaten) nur ein einziges Mal in der Datenbank abgelegt, alle Commits, in denen eine Datei im selben Zustand vorliegt, teilen sich den selben Datenbank-Inhalt für diese Datei(en).

  • die Identität zweier Dateien ist weltweit durch Vergleich der Hash-Werte – der ID – extrem effizient und ohne jede Koordination möglich (Analoges macht z.B. Microsoft in seinem Netzwerk-Verwaltungssystem ActiveDirectory bzw. sogenannte UUIDs). Das bildet die Basis für ein flexibles Verteiltes (Distributed) Version-Control-System (DVCS) bzw. Source-Code-Management (SCM).

Snapshot

GIT verwaltet im Gegensatz zu den meisten anderen Versionsmanagement-Systemen keine Differenzen, sondern jede Datei-Version ist komprimiert vollständig in der GIT-Datenbank enthalten.
Da aber der Inhalt einer Datei durch den SHA1-Hash quasi-eindeutig identifiziert ist, kann eine ungeänderte Datei in jeder Vesion, in der sie in diesem Status enthalten ist, referenziert werden und existiert physisch nur ein einziges Mal. Dies reduziert die Repository-Größe enorm und macht Speichern per Differenzen unnötig.

GIT Objekte und sonstige Daten

GIT kennt 4 fundamentale Objekt-Typen, die über ihre Hash-Werte identifiziert werden und im GIT�a0;Object�a0;Store verwaltet werden, sowie einige weitere Datenarten:

  • Blob – Snapshot einer Datei – nur Größe und Inhalt

  • Tree – Snapshot eines Ordners mit Einträgen für jedes Element: Typ, Dateinamen, Zugriffsrechte

  • Commit – siehe unten – Hülle um den Snapshot des Basisordners mit Commit-Message, Commit-Zeitpunkt, Name und E‑Mail‑Adr. von Autor und Committer.

  • annotated Tag – im Gegensatz zu "lightweight Tag". �a0; ToDo: Beschreibung dazu.

    Dazu noch (einfach im .git-Verzeichnis in Dateien verwaltet):

  • Branches und lightweight Tags

  • URLs und Kurznamen für Remote-Repositories

  • sowie Key-Value Paare (Optionen und Attribute) für viele Eigenschaften, die Details steuern bzw. Info enthalten (user.name=Max�a0;Mustermann, user.email=maximus@mustermann.or.at, …​ ) – siehe Git - Git Basis-Konfiguration und etwas detaillierter: Git - Git Konfiguration.

Repository

im Prinzip ein Verzeichnis, das entweder über GUI durch Mausklick oder über CLI durch ein einziges Kommando: git init mit den benötigten GIT-Verwaltungsstrukturen versehen wird. Diese sind vollständig – inklusive der Datenbank aller versionsmäßig verwalteten Objekte – im dabei angelegten direkten Unter-Ordner .git enthalten.
Auf dem eigenen Rechner ist es praktisch, ein Basis-Verzeichnis für alle lokal vorliegenden Repositories zu definieren – z.B. in
C:\Users\<username>\GIT-Repos\. Die Repositories erhalten dann einen thematischen Namen
– z.B. Sj1920-POS. Das Repository liegt somit in:
C:\Users\<username>\GIT-Repos\Sj1920-POS\).
Mit git init bzw. einem Klick in GUI wird das der GIT-Verwaltungsordner erzeugt als:
C:\Users\<username>\GIT-Repos\Sj1920-POS\.git\.
Vielleicht kommt später parallel ein Repository für das Team-Projekt dazu –
z.B.: C:\Users\<username>\GIT-Repos\Sj1920-POS-Projekt\.
Für andere Gegenstände z.B.: C:\Users\<username>\GIT-Repos\Sj1920-TINF\.

Version/Revision

wieder abrufbare Konstellation des Repositories - ein Entwicklungsstatus, der den Inhalt aller verwalteten Dateien eines Repositories umfasst. Wird auch oft salopp als Commit (siehe unten) bezeichnet.

Datei-Zustände

Eine Datei kann in GIT 3 Zustände haben:

  • Modified: Datei wurde geändert, dies ist noch NICHT in die GIT-Datenbank eingetragen. Im Detail kann die Datei neu, geändert oder gelöscht sein.

  • Staged: Die Datei wurde erstellt/geändert/gelöscht und diese Veränderung ist für den nächsten Commit vorgemerkt.

  • Committed: Die Datei ist in ihrem aktuellen Zustand bereits in der GIT-Datenbank enthalten.

Working Tree

Das Arbeitsverzeichnis, der gerade "aktive" Zustand - hier wird normal am Projekt gearbeitet. Liegt direkt im Repository-Verzeichnis und kann beliebige Unterverzeichnis-Struktur haben (daher "Tree" – in diesen liegen keine eigenen Verwaltungsdaten – diese alle zentralisiert in .git im obersten Verzeichnis). Daten, die hier liegen, werden von GIT zwar "bemerkt", aber nicht versionsmäßig verwaltet. Wenn eine ältere oder andere (parallel bearbeitete) Version "aktiviert" wird (heißt "checkout"), werden alle dazugehörigen Dateien in der richtigen Version hierher kopiert und können normal verwendet werden. Änderungen an Dateien führen zum obigen Zustand Modified.

Staging-Area/ Index

Für Aufnahme bearbeiteter/erstellter/gelöschter Dateien des Working Tree in die "Warteliste" für Commits müssen diese mit git add <Dateinamen-Liste> oder/und git add <Dateinamen-Muster> (bzw. einer GUI-Auswahl) in den Index aufgenommen werden.
Auch gegenüber der letzten Version geänderte Dateien müssen "ge-added" werden. Inzwischen gelöschte Dateien werden mit git rm …​ zur "offiziellen" Entfernung für die nächste Version vorgemerkt. Das wäre mühsam, wenn GIT nicht mit git status (oder einer GUI-Aktion) die betroffenen Dateien und ihren Änderungszustand übersichtlich ausgeben würde. Dateien sind mit der Aufnahme in den Index im obigen Zustand Staged.

Commit

Das "umfassendste" oben kurz skizzierte Basis-Objekt. Verursacht eine neue Version, umfasst die gegenüber der letzten Version gemachten Änderungen, soweit sie .
Weiß auch, was sein Vorgänger-Commit (beim "Merge" sogar mehrere Vorgänger, die durchnummeriert sind) war.
Damit kann die gesamte Versionsgeschichte aller verwalteten Dateien lückenlos rekonstruiert werden. Man kann sehr einfach die Differenzen zwischen 2 beliebigen Versionen anzeigen - welche Dateien, aber auch für jede Datei ihre Änderungen. Alle Dateien, die Teil des Commits waren, sind damit im obigen Zustand Committed.

Clone

Bei Team-Arbeit am Projekt-Repository erstellt jeder Beteiligte einen Klon. Mit GIT ist es extrem einfach, ein Repository beliebig oft zu klonen.
Jeder Beteiligte hat eine vollständige Kopie samt allen alten Commits und kann offline am Projekt arbeiten. Natürlich macht häufiges Abgleichen der Repositories die Arbeit effizienter, v.a. wenn es Überschneidungen der bearbeiteten bzw. benötigten Dateien gibt.
Die Klone können/werden oft auf unterschiedlichen Rechnern liegen und naturgemäß unabhängig verändert werden. Sie wissen aber über ihre "Verwandtschaft" und können bei "Kontakt" leicht wieder abgeglichen werden. Dabei werden nicht nur die aktuellen Zustände abgeglichen, sondern auch alle Commits, die jeweils gemacht wurden. GitLab zeigt in der Web-Oberfläche den nötigen, per Copy/Paste verwendbaren Kommando-Text des Clone-Kommando an.

Branch

GIT erlaubt es, mehrere Entwicklungszweige parallel zu betreiben – das ist z.B. für die Entwicklung einer Version 2.0 nötig, wenn parallel noch Version 1.0 weitergepflegt werden muss. Auch wenn ein Fehlerkorrektur oder Weiterentwicklung erfolgen soll, macht man das meist in einem eigenen, nur für eine bestimmte Zeit vorhandenen Branch, um während der Arbeit die Produktiv-Version nicht unbrauchbar zu machen. Im Prinzip zeigt der Branch-Name auf den neuesten Commit des betreffenden Entwicklungszweiges. Da jeder Commit seine(n) Vorgänger-Commit(s) kennt, ist damit der gesamte Entwicklungszweig definiert.
Weiteres siehe Git - Branches auf einen Blick und Folgeseiten.

Checkout

Checkout kann drei Aufgaben erfüllen:

  • Aktivieren eines anderen Branch – die vermutlich häufigste Operation. Dabei wird der aktuellste Commit des angegebenen Branch aktiviert und der Working Tree erhält alle Dateien/Verzeichnisse, wie sie im Commit enthalten sind. Untracked Files (nicht unter GIT-Verwaltung stehend) werden bei Namenskonflikt überschrieben, sonst bleiben sie erhalten.

  • Aktivieren eines bestimmten (älteren) Commits – erzeugt einen Detached Head (siehe unten). Sonst wie oben.

  • Extrahieren einer Datei eines anderen als des aktuellen Commits – z.B. zum Verwenden einer Datei aus einem anderen Commit als Basis.
    Um eine bestimmte Version aus dem Repository zu "aktivieren", d.h. in das Arbeitsverzeichnis (den "Working Tree") zu kopieren, muss ein "checkout" erfolgen.
    Sehr häufig wird hier ein Branch angegeben (z.B. "master" oder "fix-issue234"), dann wird auf Basis des aktuellsten Commits des genannten Entwicklungszweiges gearbeitet. Falls eine ältere Version genauer angesehen werden soll, kann diese per "Tag" oder direkt mit dem SHA1-Wert des anvisierten Commits angesprochen werden.

HEAD

zeigt auf den Commit, in dem man gerade "ist". Das ist im Normalfall der gerade aktive – "ausgecheckte" Branch (d.h. der letzte Commit im aktiven Entwicklungszweig).

Detached Head

Da man aber jeden beliebigen Commit (Version) in der Historie des Repositories aktivieren kann, kann er auch auf einen älteren Commit zeigen – dann ist man im "Detached Head"-Modus.
Hier gehen Änderungen ohne spezielle Schritte verloren – eignet sich z.B. zum schnellen Ausprobieren etc. – oder um daraus später einen neuen Branch zu machen, womit HEAD nicht mehr "detached" ist.

'master'-Branch

Zum Arbeiten mit Git wird mindestens ein Branch benötigt. Daher wird schon beim Anlegen eines neuen Repositories ein solcher erzeugt und erhält den Namen "master" (Master-Branch). Dieser wird naheliegenderweise als Hauptzweig genutzt und entspricht oft der gerade produktiv eingesetzten Version.

Feature-Branch

Wenn eine nicht-triviale Änderung am Master-Branch erfolgen soll, wird üblicherweise ein eigener Branch erzeugt, in dem die Arbeit erfolgt. Nach Abschluss wird dieser Branch mit dem Master-Branch zusammengeführt.

Branches zusammenführen

Sehr häufig ist das Ziel, nach der Entwicklung einer Funktionalität (eines Features) oder eines Bugfixes die abgeschlossene Arbeit in den Produktiv-Zweig (oft 'master'-Branch) einzupflegen. Dazu gibt es im wesentlichen 2 Grund-Techniken: Merge und Rebase. Beides hat Implikationen und ist für bestimmte Situationen günstig oder ungünstig – siehe beide nachfolgenden Einträge.

Merge

Zusammenführen zweier oder mehrerer Branches – z.B. soll nach Fertigstellung (samt Test) eine in eigenem Branch erarbeitete Fehlerkorrektur in die Produktiv-Version (z.B. master-Branch) übernommen werden.
Davor müssen u.U. parallel durchgeführte Änderungen an der Produktiv-Version (z.B. eine andere Fehlerbereinigung) in den "eigenen" Branch (Topic-Branch) übernommen und das Zusammenspiel mit den eigenen Änderungen getestet und gegebenenfalls weiter überarbeitet werden.
Anschließend kann die Änderung in die Produktiv-Version übernommen werden. Bei einem Merge können die einzelnen "Eltern" gezielt angesprochen werden, sie sind geordnet (durchnummeriert).
Zu diesen Abläufen gibt es IT-Tools - z.B. integriert in Eclipse oder Visual Studio Code oder auch separat – z.B.: Meld. Auch GIT selbst bietet im CLI dazu sehr umfangreiche Möglichkeiten, die von Profis oft bevorzugt werden.

Rebase

Quasi (vom Effekt her) "Merge light" – es dient ebenfalls dem Zusammenführen zweier Branches. Im Prinzip passiert folgendes:

  • Als Basis wird der letzte Commit, den die beiden Branches gemeinsam haben, eruiert

  • Der Reihe nach für alle seitdem erfolgten eigenen Commits temporär Differenz-Dateien erstellen. Diese ergeben, hintereinander auf den gemeinsamen Branch angewendet, wieder den aktuellen Datei-Status.

  • Der letzte Commit des Branches, in den hinein integriert werden soll, wird nun als neue Basis genommen. Die Differenz-Dateien der "eigenen" Commits werden zur Erzeugung neuer Commits auf der neuen Basis der Reihe nach angewendet.

  • Am Ende entsteht der selbe Zustand, als wenn beim Mergen immer die eigene Version bevorzugt worden wäre.

  • Es gibt auch die Möglichkeit des interaktiven Rebase, hier kann gezielt entschieden und gesteuert werden.

  • Rebasing ist oft sinnvoll, solange die eigenen Commits nicht irgend jemandem anderen übermittelt worden sind und wenn kaum unkoordinierte thematische Überschneidungen im Team auftreten).

  • Beim Einpflegen von Beiträgen z.B. in Open-Source-Projekten ist meist ein Rebase gewünscht, da die Entwicklungshistorie sonst mit vielen unnötigen Details "verschmutzt" wird.

origin

siehe nachstehend – remote.

remote

Bei kooperativer Arbeit ist es nötig, Repositories abzugleichen. Man kann daher bieliebig viele remote "Partner"-Repositories definieren, die durch Klonen aus der selben Quelle stammen. Das Repository, von dem das eigene geklont ist, wird standardmäßig "origin" genannt. Man kann es aber problemlos auch anders nennen – in unserem Falle z.B. "gitlab". Dieser Name wird in diesem Dokument auch oft anstelle von "origin" verwendet.

Push

Senden der lokal erfolgten Änderungen an ein Remote Repository (z.B. bei GitLab)

Pull

Abholen der Änderungen/Commits, die seit dem letzten Abgleich auf dem Remote Repository eingetroffen sind und Aktivieren dieses Commits. Im Hintergrund erfolgt zuerst ein Fetch (Abholen aller im Remote Repository eingetroffenen Commits) und anschließendem Merge oder Rebase (je nach Konfiguration).

Datei ".gitignore"

In Dateien dieses Namens können Datei- und Verzeichnismuster angegeben werden, die von GIT verwaltungsmäßig ignoriert werden sollen.
Beispiel-Muster: *.class, *.tmp, .settings/, Thumbs.db, etc. .
Diese Datei wird selbst versioniert und liegt normalerweise direkt im Repository-Basisverzeichnis. Damit ist sie für alle User des Repositories übereinstimmend konfiguriert und niemand "verschmutzt" das Repository unbeabsichtigt. Für zusätzlich nur auf dem eigenen Rechner zu ignorierende Dateien und Verzeichnisse kann die gleich aufgebaute Datei .git/info/exclude angelegt werden.
Da es schwierig ist, an alle zu ignorierenden Dateien und Verzeichnisse zu denken, gibt es ein freies Online-Service unter gitignore.io - Create Useful .gitignore Files For Your Project.
Hier kann – komfortabel unterstützt – mit Eingabe von z.B. Windows, Eclipse, Maven, Java, Python, Angular, Web, etc. eine ausgereifte .gitignore-Datei erstellt werden. Diese enthält sogar einen Kommentar mit der URL samt allen Parametern, um sie wieder (in vielleicht weiter entwickelter Variante) generieren oder ändern zu können.
Ein Beispiel findet sich in den von mir generierten Schüler-Repositories. Die zur Erzeugung nötige URL ist https://www.gitignore.io/?templates=java,kotlin,android,web,windows,linux,macos,maven,gradle,eclipse,intellij,netbeans,androidstudio,visualstudiocode

6.2. Überblick GitLab

GitLab ist einer der 3 bekanntesten GIT-Hosting-Provider. Die Software ist zum größten für uns interessanten Teil frei und Open Source. Sie kann auch sehr gut auf einem eigenen Server betrieben werden.

Wir nutzen die gehostete Version, die auch in der kostenlosen Variante alle für uns benötigten Funktionalitäten bietet und für uns im Unterricht einschränkungsfrei nutzbar ist.

Diese ist erreichbar unter https://gitlab.com. Vor Benutzung ist eine Registrierung nötig. Mit dem Account kann man zu allen "Projekten" eingeladen werden. Bei öffentlichen Projekten kann man ohne Einladung mitwirken.

Als Benutzer hat man die Möglichkeit, beliebig viele Projekte zu erstellen und auch beliebig viele "Mitarbeiter" einzuladen. Es ist sogar möglich, hierarchische Gruppen zu definieren, um die Projekte logisch zu organisieren.
In unserem Fall habe ich auf oberster Ebene die Gruppe at-htlw5 definiert.
Darunter gibt es die Gruppe 1920-2dhif-pos, in der für jeden Schüler ein eigenes Projekt angelegt ist – Namens-Schema (aus Handhabungs-Gründen teils redundant): 1920-2dhif-pos-<schüler-kurzname>.
In den Schüler-Projekten bin ich und Koll. Michel als Administrator zugeordnet, der Schüler als Developer.

Ein GitLab-Projekt enthält im Normalfall ein einziges Repository, ein Wiki, einen "Issue-Tracker".

Nach dem Login wird eine Liste der GitLab-"Projekte" angezeigt, an denen man mitarbeitet, dazu die eigene Rolle im Projekt: Owner, Developer, …​ .

Mit Anklicken eines Projektes wird dieses und darin das Repository geöffnet.
Angezeigt wird die Verzeichnis- und Dateienstruktur der aktuellen Version und oben die dazugehörige Commit-Message und die Commit-ID (die zur Identifikation ausreichenden ersten 8 Zeichen), dazu noch einige weitere Infos.
Im unteren Bereich wird standardmäßig die üblicherweise vorhandene README.md-Datei angezeigt - diese ist in einer Variante der Markup-Sprache Markdown (GitLab flavored Markdown) erstellt und frei gestaltbar.

Markdown ist eine sehr leicht schreibbare (dramatisch einfacher als HTML, LaTeX, etc.), in einfachen Fällen fast wie normaler ASCII-Text aussehende Markup-Language. Details siehe:

Rechts oben ein blauer Button: Clone, der bei Bedarf die genaue Kommandozeile samt richtiger URL für das Clonen auf den eigenen Rechner anzeigt.

Im (oberen) Hauptbereich wird ein navigierbares Verzeichnis-Listing des Repository-Basisverzeichnisses angezeigt.

Darunter der Inhalt der automatisch anlegbaren, editierbaren README.md Datei. Diese ist im Markdown-Format verfasst - eine sehr effiziente Form der formatierten Inhaltserstellung.
Bei Anklicken des Dateinamens wird sie geöffnet und ein blauer Button Edit erlaubt das Ansehen und Editieren des rohen Markdown-Texts.

Rechts oben gibt es sogar eine Web-IDE, mit der man kleine Änderungen am Projekt-Code erledigen kann!  —  Sogar Kompilieren und automatisches Testen wäre unter "CI/CD" und Pipelines möglich.

In der linken Navigationsleiste sind für uns derzeit vor allem die Sub-Einträge zu Project Overview, Repository, Issues, Wiki, vielleicht noch Snipplets und Settings von Bedeutung – bitte ein bisschen explorativ durchklicken!
In der horizontalen Navigationsleiste rechts oben finden sich Icons etc. für Funktionalitäten wie Account-Einstellungen, Hilfe, ToDo-Liste, Snipplets, Suchfeld, New …​ (Zum Erstellen diverser Elemente).

Hinweis: Anlegen neuer Projekte ist leicht möglich, allerdings ist dann der Ersteller für die Verwaltung zuständig – Lehrer sind nicht automatisch kooperationsfähig.
GitLab-Projekte sind NICHT ähnlich zu Eclipse-Projekten – in einem GitLab-Projekt können viele Eclipse-Projekte enthalten sein – und das ist für unsere schulische Anwendungssituation sehr praktisch.
Daher Empfehlung: vorerst keine weiteren Projekte anlegen – außer man ist bereit und motiviert, den Lern- und Verwaltungs-Aufwand in Kauf zu nehmen.

Wichtig: da Lehrer oft mit sehr vielen Repositories zu tun haben (>1 je Schüler), ist eine Vereinbarung zur Benennung und Strukturierung WICHTIG, um sinnvolle Betreuung zu ermöglichen. Einfacher ist vermutlich, Lehrer legen die Repositories an.
Aus dem gleichen Grund ist es wichtig, die enthaltenen Eclipse-Projekte lehrer-freundlich zu benennen (fürs Test-Eclipse-Projekt im Repository verwendetes Namensschema bitte EXAKT einhalten).

Details siehe auch im umfangreichen Dokumentationsbestand von GitLab:

6.3. Eclipse GIT-Funktionalität nutzen

Eclipse benutzt einen eingebauten, rein Java-basieren GIT-Client – JGit (als Java-Bibliothek implementiert, wird auch in vielen anderen Java-Tools eingesetzt, auch in eigenen Projekten verwendbar). Daher ist keine externe GIT-Installation nötig (allerdings ist eine solche sehr praktisch).

Darauf baut der graphische GIT-Client auf, der im GUI der IDE integriert ist: EGit. Diesen werden wir hier besprechen.

Eclipse stellt eine sehr gute Hilfe bereit: online unter https://help.eclipse.org/2020-09/index.jsp, aber auch lokal.

Die lokale Hilfe kann/sollte nach den eigenen Präferenzen konfiguriert werden: Eclipse Menü → Window → Preferences → im Suchfeld: help filtert den passenden Eintrag heraus, man öffnet den Help-Konfigurationsdialog. Setzen von: Open help contents: In an external browswer bewirkt nun bei → Eclipse-Menü → Help → Help Contents das Öffnen des eingestellten Web-Browsers mit URL (bei mir) http://127.0.0.1:38963/help/index.jsp.

Für GIT-Verwendung in Eclipse (im nun offenen Hilfe-Browserfenster) im linken Hilfe-Inhaltsverzeichnis → EGit Documentation → EGit User Guide: Unterpunkte Getting Started, Concepts, Tasks, Reference sowie GIT for Eclipse Users. Themen zu JGit können vorerst beiseite gelassen werden.

Auch Menü Help → Search ist sehr leistungsfähig und nützlich - z.B. einmal mit Suchbegriff git merge oder breakpoint probieren!

6.3.1. Grund-Konfiguration

Zu Beginn werden zwei Grundeinstellungen vorgenommen:
Eclipse-Menü → Window → Preferences → Team → Git → Configuration → Tab User Settings :
Im Dialog rechts: Zwei Einträge sind zu machen mit Add Entry …​ →

  • für Key eintragen: user.name, beim Value z.B. Max Mustermann → Add.

  • und nochmals für: user.email, Value z.B. max@mustermann.at → Add.

Damit ist die Konfiguration vorläufig beendet. Diese beiden Einstellungen sind v.a. in Teams wichtig, da diese Daten in jedem Commit aufscheinen und den richtigen Ansprechpartner identifizieren, falls Fragen oder Probleme auftreten.

Wichtig: In der Eclipse-Menüstruktur sind GIT-Einträge oft innerhalb von Team zu finden!

6.3.2. GitLab-Repository einbinden

Nun wechseln wir zur GIT-Perspektive (Perspektiven sind Konstellationen der Eclipse-IDE - welche Views wo geöffnet sind, etc.):

Eclipse-Perspektiven: �a0; Eclipse-Menü → Window → Perspective > → Open Perspective > → Other …​ → Liste erscheint. Hier GIT auswählen → Open. Damit ändert sich die IDE-Fensteraufteilung, etc.
Wechseln zwischen Perspektiven: �a0; Rechts oben (rechts neben dem Suchfeld mit 'Lupe') werden alle derzeit aktiven Perspektiven als Icons angezeigt - damit kann man rasch zwischen ihnen wechseln.
Die sichtbaren, rechteckigen, funktionellen Einheiten werden View genannt: Eclipse Menü → Window → Show View > → Liste aller Views wird angezeigt (viele auch unter other …​).
Diese können jederzeit geöffnet und auch beliebig mit der Maus plaziert und in der Größe beeinflusst werden.

Links erscheint nun anstelle des Package Explorers der View Git Repositories.
Darin wählen wir den Link Clone a Git Repository Im nun offenen Formular sind u.a. Daten des Remote GitLab Repositories einzutragen. Daher öffnen wir im Webbrowser unser GitLab-Repository → Projects: unseres ankicken → Links auf Repositories, es öffnet sich die schon oben beschriebene Seite, in der rechts oben der blaue Button Clone geklickt werden muss. Damit wird die GitLab-Repository-URL angezeigt. Die URL bei HTTPS kopieren wir.

Zurück in Eclipse kopieren wir die URL in Feld URI. Damit sollten sich die meisten Felder des Formulars gefüllt haben, nur die Login-Daten (Authentication) fehlen noch: User: der eigene GitLab-Username, weiters das korrekte Passwort. Store in secure Store kann aktiviert werden. Danach Next > klicken.

Nun ist in der Branch Selection der einzig vorhandene Branch master auszuwählen, danach Next >.

Hier ist der Pfad des Repositories einzugeben. Empfehlenswert ist z.B.:
C:\Users\<WindowsUserName>\Documents\GIT-Repos\1920-2dhif-pos-<kurzname>, d.h. der Repository-Name sollte (aus rein praktischen Gründen) der selbe wie auf GitLab sein. Alle weiteren Einstellungen können beibehalten werden, zum Abschluss → Finish

Nun wird das Repository geklont und sollte in wenigen Sekunden links im View Git Repositories zu sehen sein.
Klick auf den Eintrag öffnet rechts unten die Versions-History und es können weitere Information durch Ankliccken, andere Tabe etc. gefunden werden.

Damit ist die Arbeitsbasis hergestellt (ist möglicherweise für das restliche Semester erledigt).

6.3.3. Aus Source-Code Verzeichnis ein Eclipse-Projekt erstellen

Nun können wir aus dem Inhalt des jeweils eigenen Repositories, z.B.
C:\Users\<WindowsUserName>\Documents\GIT-Repos\1920-2dhif-pos-<kurzname>, ein Verzeichnis wählen – bereitgestellt ist nun für alle das "Roh-Material" für ein Eclipse-Projekt 2dhif-pos-<kurzmane>-GitScribble1 – und daraus ein Eclipse-Projekt machen:

Eclipse Menü → File → New → Java Project.

Im nun offenen Formular das Feld Project name noch LEER lassen. Die Checkbox Use default location auf NICHT AKTIV�a0;�a0; setzen und mit Browse …​ das oben besprochene und festgelegte Repository und darin das oben genannte Verzeichnis des zukünftigen Eclipse-Projekts selektieren. → Ordner auswählen klicken, damit wird der Pfad ins Feld Location �a0; übernommen und der Project Name �a0; auch gleich gesetzt.

Jetzt klicken wir Finish�a0; und erledigen das "Fine-Tuning" hinterher in den Project Properties.

Es erscheint noch ein Dialog zur Erstellung einer Datei namens module-info.java, wir können aufAnzeigesprache konfigurieren Don’t Create klicken, da diese für unser einfaches Projekt nicht benötigt wird.

Im Package Explorer wird nun rechts neben dem Projekt-Namen in eckigen Klammern der Repo-Name und 'master' angezeigt. Nach Änderungen erscheint auch ein ⬆ mit Anzahl der Commits gegenüber dem Remote Repository (bei uns GitLab)

6.3.4. Projekt "laufen lassen"

Nun ist aus dem Verzeichnis ein vollständiges Eclipse-Projekt geworden und wir können am besten mit Rechtsklick auf das Projekt im Package ExplorerRun as >1 Java Application die Applikation laufen lassen. Sie liefert eine Consolen-Ausgabe mit einigen Eckdaten des jeweiligen Schülers.

6.3.5. JUnit-Tests vom normalen Code separieren

Ein Schritt sollte noch erledigt werden, um die Konfigutarion sinnvoll abzuschließen:
Wir wollen festlegen, dass alle JUnit-Test-Klassen in einem eigenen Source-Folder liegen (mit identischer, automatisch generierbarer Package-Struktur):
Project Explorer → Rechtsklick auf Projekt 2dhif-pos-<kurzmane>-GitScribble1 → letzter Menü-Eintrag: Properties → Das Formular Properties for 2dhif-pos-<kurzmane>-GitScribble1 öffnet. Wir wählen rechts in der Liste Java Build Path → Formular → erster Tab: Source. Man sieht den Bereich Source folders on build path:, in dem unser Source-Folder
2dhif-pos-<kurzmane>-GitScribble1\src gelistet ist.
Add Folder …​ → Zusätzlich zum selektierten src selektieren wir testOK → auch Folder 2dhif-pos-<kurzmane>-GitScribble1\test wird angezeigt.

Noch weiß Eclipse nicht, dass alle Test-Klassen hier "hinein sollen". Daher definieren wir für den "normalen" (ursprünglich einzigen) src-Folder einen Exclude Filter – dann müssen zwangsläufig alle Testklassen in den Ordner test :
Wir "expandieren" src�a0; und sehen nun u.a. den Eintrag: Excluded: (None), den wir doppelklicken.
Es öffnet sich Formular Inclusion and Exclusion Patterns:
Nun klicken wir im unteren Bereich Exclusion Filters 2 mal auf Add …​, um die beiden Patterns **/Test* und **/*Test (erst für alle Klassen, die mit Test…​ beginnen und dann für die, die mit …​Test enden) zu definieren. → Finish
Nun sollten zum src-Folder zu sehen sein: Excluded: �a0; **/*Test �a0; **/Test*
Wichtig ist ab jetzt, KEINE Nicht-Test-Klassen zu erstellen, deren Name mit "Test" beginnt oder endet.

Da wir auch die Binaries in einem separaten Folder test-bin haben wollen (dann kann die Produktiv-Version leicht ohne die Test-Klassen in ein Installationspaket oder eine JAR-Datei gepackt werden):
Checkbox Allow output folders for source folders (unten) aktivieren und dann im Verzeichnis-Listing das Verzeichnis test auswählen, Eintrag Output folder: (Default autput folder) → Radio Button Specific output folder (…​) selektieren und dann im Textfeld test-bin eintippen oder per Browse …​ wählen. Der obige Eintrag sollte dann enthalten: Output folder: (2dhif-pos-<kurzname>-GitScribble1/test-bin) .

6.3.6. Nach Editieren: Staging, Commit, Push auf GitLab

Ergänzen der Eclipse-Java-Perspektive mit GIT-Views:
Es ist recht praktisch, 3 GIT-Views immer griffbereit zu haben, ohne in die GIT-Perspektive wechseln zu müssen:
* Git Repositories-View
* Git Staging-View
* History-View (zu finden unter "Team", nicht unter GIT!) Daher sollten wir sie in die Java-Perspektive "einbauen":
Views sind zu finden unter: Eclipse Menü → Window → Show View > → Liste aller Views wird angezeigt (viele auch unter other …​).
Views können per Drag&Drop in jeden Bereich verschoben werden – durch ungefähres Platzieren können sie oben dazu, unterhalb, links oder rechts abgelegt werden (eine Trennlinie wird zur Visualisierung angezeigt, sobald nicht mehr oben als weiterer Tab dazugefügt würde).
Praktikable Plazierungen z.B.: Repositories View unterhalb des Package Explorer, der Staging View und der History-View unterhalb des Editor-Bereiches.
Wechseln der Perspektive: wie erwähnt finden sich rechts oben die Icons (rechts neben dem Such-Icon …​).
Hinweis: Jeder View (auch Editor-Tab) kann durch Doppelklick auf den Tab temporär auf volle Größe gebracht werden, nochmaliger Doppelkliclk auf den Tab reduziert wieder auf die vorige Größe und Position.

Nach einigen Änderungen z.B. Datei Demo1.java und Erstellen einer weiteren Klasse Demo3.java wollen wir einen Commit machen (d.h. die Änderungen als Snapshot in GIT dauerhaft ablegen):

Rechtsklick auf das Projekt → Popup-Menü → Team > → Commit …​ → unterhalb des Edit View öffnet sich der View mit Tab Git Staging. Links oben ein Bereich: Unstaged Changes (…​), darunter Staged Changes (0). Mit den '+'-Symbolen können die Unstaged Changes teilweise oder vollständig nach Staged Changes transferiert werden. Damit ändert sich auch das Datei-Icon im Package Explorer - ein Sternchen wird dazugefügt.

Durch Doppelklick wird ein Datei-Differenz-View im Editor-Bereich geöffnet. Er zeigt die aktuelle Fassung der Datei gegen die aus dem aktuellsten Commit und zeigt alle Änderungen an. Oben rechts können diverse Aktionen deurchgeführt werden - Sprung zur nächsten Differenz, etc.

Nach Durchsicht kann entschieden werden, ob der Commit in dieser Form erfolgen soll oder ob Dateien vom geplanten Commit ausgeschlossen werden sollen – weil noch nicht fertig, etc.

Für den Commit ist noch eine Message zu verfassen, die Idee/Grund/etc. und weitere Info zu diesem Commit enthält, damit sein Zweck später ohne Analyse des Source-Codes leicht erkennbar ist – z.B. "Korrektur Rechtschreibfehler in mehreren Dateien". Welche Dateien betroffen sind, muss nicht unbedingt erwähnt werden (falls nur wenige commited wurden), da die Dateien des Commits von GIT aufgelistet werden und man leicht einen Diff-View öffnen kann, um die konkreten Änderungen zu sehen.

Zuletzt sollte am besten Commit and Push …​ geklickt werden, dann wird der lokale Commit durchgeführt und direkt anschließend der Push (die Übertragung des Commits) auf GitLab erfolgen.

Sinnvoll ist es, lieber mehrere kleine Commits mit jeweils einem kompakten Zweck zu erzeugen als alles in einen zu packen - dann müsste korrekterweise eine umfangreiche Commit-Message geschrieben werden, wo auch jeweils betroffene Dateien aufgezählt sind.

Wenn alles geklappt hat, unter https://gitlab.com/ nachsehen: nach Öffnen des Projekts links in der Navigationsleiste: Repository → Commits wählen → die Commits werden mit Commit-Message, Committer und Zeitangabe gelistet. Als oberster Eintrag sollte der soeben durchgeführte Commit sichtbar sein.

6.3.7. Behebung von Bearbeitungskonflikten

Für die im Folgenden nötigen Operationen sollte man die GIT-Funktionalitäten in Eclipse ein bisschen genauer kennen. Wir sehen uns – zusätzlich zum schon besprochenen Git Staging View wichtige Views und Darstellungsformen an (alle standardmäßig in der GIT-Perspektive eingeblendet) und Dialoge an:

6.3.7.1. Git Repositories View

Zeigt alle in Eclipse eingebundenen Repositories. Zeigt den Repository-Namen, in eckigen Klammern den aktuellen lokalen Branch (oft [master]) und den vollen Pfad zum Repository-Git-Verzeichnis (endend mit …​/.git).
Nach Öffnen (Klick auf Hierarchiesymbol oder Doppelklick auf Titel) ist für uns nun vor allem der oberste Eintrag wichtig: Branches. Öffnen zeigt die beiden Einträge Local und Remote Tracking, die nach öffnen jeweils den derzeit einzigen vorhandenen Branch: master bzw. gitlab/master oder origin/master und die ersten ca. 7 Zeichen des Commit-Hashes + Commit-Message anzeigen.
Wenn nach dem letzten Abgleich (Pull, Push) kein neuer lokaler Commit erfolgt ist, zeigen beide den selben Commit an.

6.3.7.2. History View History-TEAM-View

Dieser findet sich im Eclipse-Menü → Window → Show View → Other …​ → TeamHistory. Ist, wenn offen, standardmäßig unterhalb der Editoren zu finden.
Er zeigt die Commits des aktiven Branches (im aktiven Repository) tabellarisch an:
Spalte Id enthält die ersten ca. 7 Zeichen des Commit-Hashes an, danach ist eine vertikale Linie mit eventuellen Verzweigungen (den Branches) zu sehen, die zumindest den master-Branch zeigt. Anschließend die Commit-Message, Autor und Committer samt Zeitpunkten.
Darunter im linken Bereich die Details des gerade ausgewählten Commits, rechts die im Commit enthaltenen Dateien.
Beim obersten Commit sollten 3 Labels zu sehen sein: master, gitlab/master (oder origin/master), HEAD. Unter bestimmten Umständen ist noch ein viertes Label zu sehen: gitlab/HEAD (oder origin/HEAD). Dieses stammt vom Klonen und wird später nicht mehr benötigt.
Im History View lassen sich auch 2 beliebige Commits sehr rasch vergleichen – wenn genau 2 Commits selektiert sind (<strg>-Klick zum Selektieren des zweiten), kann im Rechtsklick-Menü sowohl Compare with Each Other als auch Show Unified Diff gewählt werden.

6.3.7.3. Fetch-Vorgang

Wenn im Remote Repository (GitLab) ein neuerer Commit vorliegt, möchte man diesen normalerweise möglichst bald ins lokale Repository übernehmen. Falls lokal noch keine Änderungen erfolgt sind, ist der einfachste Weg ein Pull – Fetch + Checkout (aktivieren der neuen Version im Working Tree). Dieser kann aber den letzten Schritt – das (lokale) Aktualisieren des aktiven Working Tree auf diesen Commit – nicht durchführen, wenn seitdem lokal eine Änderung oder sogar ein lokaler Commit erfolgt ist. Dann ist ein (manueller) Merge-Vorgang nötig. Wenn man diese Sachverhalt schon weiß, kann man sich gleich explizit auf einen "nackten" Fetch beschränken. Beides findet man im Git Repositories View: Recht-Klick auf Repository → Fetch from origin bzw. gitlab oder Pull. Rechts unten in der Eclipse-Statusleiste sieht man kurz den Vorgang laufen bei Pull u.U. anschließend die oben angesprochene Fehlermeldung.

6.3.7.4. Merge-Vorgang

wenn im lokalen und im Remote Branch unterschiedliche Commits vorliegen (NACH einem Fetch – siehe oben), gibt es die Möglichkeit, einen Merge durchzuführen. Es gibt verschiedene Arten, dies zu tun, der klarste scheint mir der folgende zu sein: Im Git Repositories View → öffnen → Branches → Local → master 1a2b…​Merge …​.
Im öffnenden Dialog sieht man Local und Remote Tracking Branch (müssen für sinnvolle Aktion unterschiedlich sein) – unten die Merge options und Fast forward options am einfachsten beide auf dem obersten Radio-Button stehen lassen → Merge. Falls noch uncommited Changes vorliegen, muss man die Aktion abbrechen oder einen Commit durchführen und danach nochmals den Merge starten. Nun werden alle Dateien, die einen Konflikt enthalten, in je einem Editor-Tab geöffnet und zeigen folgendes Muster im Text:

 <<<<<<< HEAD                                               (1)
 // Einzeilige Lokale Zeilen-Kommentar-Änderung in Eclipse  (2)
 =======                                                    (3)
 // In selber Zeile Zeilen-Kommentar-Änderung auf GitLab    (4)
 >>>>>>> refs/remotes/gitlab/master                         (5)
1 Markierung, die vom Merge-Tool eigefügt wurde. HEAD bedeutet: gerade aktiver Commit, die Basis der aktuellen Arbeit
2 der konfliktverursachende Abschnitt der lokalen Datei
3 Trennlinie - Ende HEAD Datei, Anfang des konkurrierenden Inhalts
4 der konkurrierende Inhalt der anderen Version
5 Ende-Markierung mit Klarstellung, von welcher Stelle (refs/remotes/gitlab) er stammt, und von welchem Commit: /master (der aktuellst remote vorliegende)

Dieser Bereich muss nun so bearbeitet werden, dass der gewünschte Inhalt den gesamten gekennzeichneten Block ersetzt
(Beginn Zeile mit <<<<<<<�a0;…​ bis Ende Zeile mit >>>>>>>�a0;…​ ). Weiters müssen allfällig nötige weitere Änderungen vorgenommen werden. D.h. die Datei enthält nun den gewünschten, aus beiden Commits "synthetisierten" und inhaltlich insgesamt bereinigten Inhalt.

Diese Datei wird nun wieder gespeichert und auf "gewohnte Weise" ein Commit durchgeführt (auch andere, semantisch angepasste Dateien sollten darin enthalten sein). Git betrachtet diesen Commit als Signal, dass die die beiden konfliktverursachenden Commits nun auf diese neue Fassung zusammengeführt wurden und produziert einen Merge-Commit, der 2 "Eltern" hat und im History View eine Zusammenführung der 2 Linien verursacht.
ACHTUNG: GIT analysiert NICHT weiter, ob tatsächlich eine Bereinigung erfolgt ist (es können die Markierungen also in den Dateien vergessen worden sein). Dann ist ein weiterer Commit nötig, der die Bereinigung enthält (GIT kennt auch mehrere Möglichkeiten, NACH erfolgtem Commit noch etwas zu ändern – z.B. unter Stichwort amend, stash oder reset).

Damit ist der Konflikt bereinigt.

6.3.8. Notfalls-Lösungen, falls die "elegante GIT-Art" irgendwie fehlschlägt:

Falls Probleme wegen paralleler Bearbeitung etc. auftreten, kann das Problem vermutlich immer auf eine der folgenden "primitiven" Weisen gelöst werden:

6.3.8.1. Vorbereitung für alle Fälle

Am einfachsten außerhalb von Eclipse mit Dateimanager Kopie des gesamten Working Tree (enthält alle Projekte), d.h. des gesamten lokalen Repositories irgendwo außerhalb des Repositories ablegen.
Falls man Platz sparen möchte, kann auch nur das aktuelle Eclipse-Projekt kopiert werden (falls in den anderen Projekten seit dem letztem Commit keine Änderungen gemacht wurden) – am besten mit Dateiänderungs-Datum prüfen - allerdings in ALLEN Unterverzeichnissen! Man kann auch die Windows-Suchfunktion nutzen und den Zeitpunkt des letzten Commits als Zeit-Eingrenzung verwenden.
Das .git-Verzeichnis kann mitgesichert werden, darf aber hinterher NICHT über das bestehende .git-Verzeichnis kopiert werden, sonnst hat man den alten, "kaputten" Zustand wieder hergestellt und muss nochmals von vorne mit der Korrektur beginnen.

6.3.8.2. Fall A – der letzte Commit wurde erfolgreich auf GitLab gepusht

In Eclipse:

  • Im Git Repositories View (entweder in der Java-Perspektive, falls obiger View-Hinweis umgesetzt, oder in der GIT-Perspektive) Rechtsklick auf das Repository → Reset …​ → unter Local → master …​ remote tracking branch 'gitlab/master' auswählen → unten Radio-Button Hard (HEAD, index and working tree updated) selektieren → ResetWarnung "Reset and overwrite any changes in your working tree?" beachten und nochmals prüfen, ob das Verzeichnis-Backup erfolgt ist → Reset.

6.3.8.3. Fall B – es ist seit dem letzten Push schon mindestens ein weiterer lokaler Commit erfolgt

In den meisten Fällen kann man ohne wesentliche Verluste (oft sogar gewünscht) all diese lokalen Commits zusammenfassen (sollten im Normalfall nie sehr viele sein - schon aus Backup-Gründen).
In Eclipse:

  • In die GIT-Perspektive wechseln. Im Git-Repositories View das Repository auswählen. Nun den History-View (unter dem Editoren-View) öffnen (Tab anklicken). Dort sind alle Commits samt Hash und Commit-Message sichtbar.

  • Parallel Das GitLab-Repository im Web-Browser öffnen, auf Projects das Projekt wählen → Repository → Commits.

  • Nun den letzten gemeinsamen Commit zwischen Eclipse History und GitLab Commits anhand der Message oder des Commit-Hash herausfinden und die ID sicherheitshalber in Depot-Datei o.ä. notieren. (in GitLab werden jeweils rechts die ersten 8 Zeichen angezeigt, bei Bedarf ganzen Hash kopieren. In Eclipse sieht man unter Id die ersten 7 Zeichen und unten im Detailbereich den ganzen Hash)

  • Lokale Commit-Messages ab (exclusive) diesem Commit in Depot-Datei kopieren (nach den Korrektur-Operationen etwas mühsam auszulesen) und ihren Inhalt für die neue Commit-Message berücksichtigen.
    Für Notfälle kann man auch noch die neueren Commit-IDs kopieren, damit kann auf die demnächst "verwaisten" Commits weiterhin zugreifen.

  • Nun in Eclipse im History-View den oben eruierten letzten gemeinsamen Commit rechtsklicken (doppelt kontrollieren!) → Reset → Hard (HEAD, index and working tree) wählen, Warnung "Reset and overwrite any changes in your working tree?" beachtenReset.

  • Nun sollte der oberste Eintrag in der Eclipse-History folgende Labels anzeigen: master, gitlab/master, HEAD. Diese 3 Zustände müssen auf dem selben Commit liegen, damit alles passt.

6.3.8.4. Fall C – irgendwie passt trotzdem etwas nicht …​

Man kann immer einen neuen Klon von GitLab anlegen. Allerdings muss man ALLE Eclipse-Projekte, die in diesem Repository liegen und an denen man noch Commits machen möchte, aus dem Workspace löschen und wieder neu im Workspace einbinden - sonst hat man das selbe Repository, in dem ja alle unserer Eclipse-Projekte GEMEINSAM liegen, in 2 Fassungen lokal vorliegen – das eine mit Problemen – man kann sich vorstellen, dass dann WIRKLICH Chaos entsteht.

Was ist also zu tun (vorher versierte Kollegen oder Lehrer um Hilfe bitten – macht vermutlich weniger Mühe):

  • Alle im Repository liegenden Eclipse-Projekte aus dem Workspace entfernen (oder neuen Workspace anlegen - der alte sollte aber NICHT mehr schreibend verwendet werden):
    Rechtsklick auf Projekt → DeleteNICHT Delete content from Disk anklicken! → OK

  • Repository im Dateisystem in einen Backup-Bereich verschieben

  • neuen Clon von GitLab erstellen (Anleitung siehe oben).

6.3.8.5. Abschluss für alle Fälle

Nun ist der Zustand des letzten gemeinsamen Commit wiederhergestellt. Es bleibt noch folgendes zu tun:

  • Zunächst mittels Pull die Remote Commits von GitLab holen, die vermutlich die Probleme verursacht haben:
    im Git Repositories View → Rechtsklick auf Projekt → Pull → es wird vom (einzigen konfigurierten) Remote Repository der Master-Branch per Fast forward aktualisiert und ein Info-Dialog angezeigt → OK.

  • Kontrolle: weiter im Git Repositories View → aufklappen des Projekts → Branches → Local: nun sieht man den aktuellen Commit mit den ersten ca. 7 Zeichen des Commit-Hashes und der Commit-Message. Der sollte mit dem letzten auf GitLab übereinstimmen.

  • wieder im Dateimanager: (falls gelöscht) alle nicht von GIT verwalteten Verzeichnisse und Dateien wieder in den Working Tree zurückkopieren

  • Alle seit dem letzten Commit geänderten bzw. neu angelegten oder umbenannten Dateien werden anstelle der beim Pull restaurierten Versionen zurückkopiert (bzw. gelöschte und durch umbenennen veraltete wieder gelöscht).

Nun ist das System aktuell.
Möglichst unverzüglich in Eclipse im Git Staging View die für Staging gewünschten Dateien auswählen, die Commit-Message formulieren (im Fall B die aufbewahrten alten Messages berücksichtigen) und einen Commit durchführen – am besten gleich die Kombination Commit and Push …​ (sonst separaten Push hinterher nicht vergessen!).

Da nun hoffenlich kein neuer Commit von anderer Seite vorgelegen hat, sollte der Push auf GitLab gelungen sein und das Problem ist gelöst.

6.3.9. Erzeugen eines Bearbeitungskonflikts zum Probieren

Um diese häufige Problem-Art lösen zu lernen, erzeugen wir nun einen Bearbeitungskonflikt: Wir editieren eine Datei direkt in GitLab.
Beim Speichern wird (sinnvollerweise nach Adaption der Default-Commit-Message) ein Commit durchgeführt (Pushen muss GitLab nicht, da das Projekt lokal auf dem Server liegt).

Wir sehen uns unter Repositoy → Commits den Commit an - er enthält die Differenzen - die entfernten (rosa) und die hinzugefügten Teile (grün). Zum Ansehen der kompletten aktuellen Datei-Version: klick auf View file * 1a2b3c4d (der Anfang des 40-Zeichen-Hashes, der die Datei identifiziert).

Nun arbeiten wir – wieder lokal – in Eclipse weiter editieren die selbe Datei an der gleichen Stelle und machen einen Commit (siehe oben). Das gelingt noch. Aber sobald wir ein Push probieren, schlägt dies fehl (leider nicht immer mit einer hilfreichen Fehlermeldung).

Jedenfalls sollte man als versierter GIT-Nutzer nun in GitLab nachsehen, ob es zwischenzeitlich einen Commit seitens eines anderen Team-Mitglieds oder von einem anderen Clon aus gegeben hat (oder wie in unserem Fall einer direkt in GitLab) – oder sofort eine Aktualisierung des lokalen Repository vornehmen:
Eclipse-Package-Explorer → Projekt-Rechtsklick → Team → Fetch. Damit wird der problematische Remote-Commit in das lokale Repository geholt, aber nicht aktiviert – das geht problemlos – die Aufnahme eines Commits in das lokale Repository führt ja nicht zum Konflikt, sondern die Kombination meiner Änderungen mit konkurrierenden Änderungen muss mit menschlicher Intelligenz erfolgen.

Generell muss gesagt werden, dass beim Zusammenführen immer über das mechanische Zusammenführen hinaus mitgedacht werden sollte – es können sogar Syntax-Fehler entstehen, da GIT keinerlei Kenntnis über die Programmiersprache hat. Darüber hinaus muss natürlich semantische Korrektheit erreicht werden.
Es zeigt sich aber, dass in erstaunlich vielen Fällen ein sehr geringer Intelligenzaufwand nötig ist, um die Zusammenführung sinnvoll zu erledigen.

7. Installation des separaten, "offiziellen" GIT-Clients (CLI + GUI)

folgt später.
…​

8. Konfiguration des GIT-Clients

folgt später.
…​

9. Arbeiten mit dem GIT-Client

folgt später.
…​

10. Arbeiten mit GIT auf der Kommandozeile

folgt später.
…​

Index