Schlagwort-Archive: git

Wie synchronisiere ich ein Projekt mit einem schon existierendem Repository in GitHub?

Wer erst nachträglich auf die Idee kommt, den eigenen Entwicklungsserver mit einem Produktionsserver per Git und GitHub zu synchronisieren, steckt vor dem Problem, wie man eine Verbindung zu GitHub herstellt und einen erstmaligen Abgleich der Dateien herstellt. Danach kann und sollte ein Deployment dann nur noch per git erfolgen.

Wie immer ist es einfach, wenn man weiß, wie es geht, oder welche Fragen man stellen muss.

Problembeschreibung

Problem: ein Projekt (auf Produktion), das bisher nur mit FTP deployt wurde, soll nachträglich nur noch mit einem GitHub Repository ohne FTP synchronisiert werden.

SSH-Schlüssel bei GitHub hinterlegen

Da es sich aller Wahrscheinlichkeit nach um ein privates Projekt handelt, muss sich der Produktionsserver (=Ziel) gegenüber GitHub authentifizieren. Dazu muss man einen öffentlichen Schlüssel erzeugen und bei GitHub hinterlegen. Erklärt habe ich das bereits hier (für Windows) und hier (für Linux).

ls -al ~/.ssh # testen, ob schon Keys vorhanden sind
mkdir ~/.ssh # wenn nicht, Ordner anlegen
cd ~/.ssh
ssh-keygen -t rsa -b 4096 -C "<BESCHREIBUNG>"
ls -la

Danach muss git wissen, wo es die SSH-Schlüssel findet.

nano ~/.ssh/config

Der einfachste und funktionsfähige Inhalt wäre folgender:

# Private github account: 1manfactory
Host github-private
HostName github.com
IdentityFile ~/.ssh/id_rsa
IdentitiesOnly yes

Wir müssen GitHub als bekannten Host hinzufügen:

ssh-keyscan github.com >> ~/.ssh/known_hosts

Ich authentifiziere mich als git@github-private bei GitHub.

ssh -T git@github-private

Das git Repository auf Produktion anlegen und mit dem remote Repository verbinden

Navigieren Sie zum Verzeichnis Ihres lokalen Projekts auf dem Produktionsserver und führen Sie folgende Befehle aus.

cd <PROJEKTVERZEICHNIS>
git init
git config -l
git remote add origin git@github-private:<USER>/<REPOSITORY>.git
git remote -v
git pull origin main
git checkout main -f
git branch --set-upstream-to origin/main

Ich erkläre die einzelnen Schritte.

git init ist ein Befehl, der ein neues Git-Repository in einem lokalen Verzeichnis erstellt. Er legt einen versteckten Ordner namens .git an, der die Repository-Daten enthält. Er macht das Verzeichnis bereit für die Versionskontrolle mit Git.

git config -l ist ein Befehl, der alle Git-Konfigurationsoptionen anzeigt, die für das aktuelle Repository oder den aktuellen Benutzer gesetzt sind. Er liest die Werte aus den Dateien .git/config, ~/.gitconfig und /etc/gitconfig. Er kann nützlich sein, um die Einstellungen zu überprüfen oder zu ändern.

git remote add origin ist ein Befehl, der einen Remote-Namen namens origin zu einem lokalen Repository hinzufügt. Er verbindet das lokale Repository mit einem Remote-Repository, das an den Befehl angehängt wird. Er ermöglicht das Hochladen und Herunterladen von Änderungen zwischen den Repositories.

git remote -v zeigt die Liste der Remote-Namen und ihre URLs an. Er hilft zu überprüfen, ob die Remote-Verbindungen korrekt sind.

git pull origin main ist ein Befehl, der den lokalen Branch main mit dem Remote-Branch main von origin aktualisiert. Er lädt zuerst alle Änderungen vom Remote-Repository herunter und führt dann einen Merge oder einen Rebase aus. Er bringt das lokale Repository auf den neuesten Stand.

git branch --set-upstream-to origin/main ist ein Befehl, der den aktuellen lokalen Branch mit dem Remote-Branch main von origin verknüpft. Er legt fest, welcher Remote-Branch als Standard für das Pushen und Pullen verwendet wird. Er erleichtert die Synchronisation zwischen den Branches.

Als Ergebnis sollte jetzt der Produktionsserver auf demselben Stand sein wie das GitHub-Repository (und damit auch wie der Entwicklungsserver).

Das zukünftige Deployment

Ab jetzt können wir den Weg über git pull oder git fetch && git merge gehen, um Änderungen aus dem remote Repository bei GitHub zu übernehmen.

Die schnelle Methode ‘git pull’

git pull

git pull ist ein Befehl, der den aktuellen lokalen Branch mit dem entsprechenden Remote-Branch aktualisiert. Er entspricht einem git fetch gefolgt von einem git merge oder einem git rebase. Er benötigt einen Remote-Namen und einen Branch-Namen oder eine Verknüpfung zwischen den Branches.

Die vorsichtigere Methode mit ‘get fetch’

git fetch origin
git log origin/main ^main
git diff main origin/main
git merge

git fetch origin ist ein Befehl, der alle Änderungen vom Remote-Repository origin herunterlädt. Er aktualisiert die lokalen Referenzen zu den Remote-Branches, aber nicht die lokalen Branches. Er ermöglicht es, die Differenzen zwischen den Branches zu sehen oder einen Merge oder einen Rebase auszuführen.

git log origin/main ^main ist ein Befehl, der die Commit-Historie vom Remote-Branch origin/main anzeigt, die nicht im lokalen Branch main enthalten ist. Er hilft, zu sehen, welche Änderungen noch nicht synchronisiert sind.

Der Befehl git diff main origin/main zeigt die Unterschiede zwischen dem lokalen Zweig main und dem entfernten Zweig origin/main an². Er kann verwendet werden, um zu sehen, welche Änderungen Sie noch nicht mit dem entfernten Repository synchronisiert haben.

Git und GitHub für Windows mit Sourcetree, Teil 3: Branches, Pull Requests und Fetch

Das Thema Branches ist sehr wichtig für die Arbeit mit GitHub. Im Grunde kommt man nicht an ihnen vorbei, spätestens wenn man nicht mehr allein an einem Projekt arbeitet.

Was sind Branches?

In Git sind Branches (dt. Zweige) Versionen des Projekts, die sich inhaltlich voneinander unterscheiden und dabei gleichzeitig parallel existieren können.

Branches sind eine wichtige Funktion in Git, da sie es Entwicklern ermöglichen, verschiedene Ideen oder Experimente gleichzeitig auszuprobieren, ohne die ursprüngliche Version des Projekts zu beeinträchtigen. Zum Beispiel kann man einen neuen Branch erstellen, um eine neue Funktion auszuprobieren, während der Haupt-Branch stabil bleibt. Wenn die neue Funktion erfolgreich getestet wurde, kann sie in den Haupt-Branch übernommen („gemerged“) werden.

Git ermöglicht auch, zwischen Branches zu wechseln und zu arbeiten, wodurch Entwickler effizienter arbeiten können, ohne dass sie separate Arbeitskopien erstellen müssen.

Das Wechseln zwischen Branches ist einfach und schnell, sodass Entwickler problemlos zwischen verschiedenen Versionen ihres Projekts navigieren können.

Wir legen einen neuen Branch an

  1. Öffnen Sie Ihr Repository in Sourcetree.
  2. Klicken Sie auf den Button „Branch“ in der oberen Menüleiste.
  3. Klicken Sie auf den Reiter „New Branch“ im neuen Fenster.
  4. Geben Sie einen Namen für Ihren neuen Branch ein und wählen Sie den Branch aus, von dem Sie den neuen Branch ableiten möchten. Standardmäßig wird der neue Branch von dem aktuell ausgewählten Branch (hier: main) abgeleitet.
  5. Klicken Sie auf den Button „Create Branch“.

Ich nenne den neuen Branch „new_feature“. Allerdings werden wir kein neues Feature einführen, sondern lediglich an der schon bekannten Datei „README.md“ etwas ändern.

Fortan wollen wir also im „new_feature“-Branch arbeiten. In unserem Repository wird aber weiterhin das Projekt in seiner ursprünglichen Version verbleiben und parallel existieren.

Mit einem Doppelklick auf der linken Seite auf den Namen der Branch springen wir zwischen „main“ und „new_feature“ hin und her.

Wir fügen jetzt in unserer bekannten Datei „README.md“ eine neue Zeile, genauer eine neue Überschrift hinzu. Außerdem ist mir gerade aufgefallen, dass ich „turotial“ statt „tutorial“ geschrieben habe. Das wird auch korrigiert.

Nach dem Speichern wechseln wir wieder zu Sourcetree und sehen nach wenigen Sekunden Wartezeit erwartungsgemäß unsere Datei wieder im Status „Unstaged“. Rechts oben erkennen wir die vorgenommenen Änderungen.

Wie bereits durchexerziert, schieben wir die Datei in den „Staged“ Bereich und führen anschließend ein Commit durch.

Nun sehen wir einen veränderte History-Bereich:

In dem neuen Branch wurden die Änderungen übernommen. Klicken wir nun wieder auf den ursprünglichen Branch, sehen wir noch den alten, ursprünglichen Stand der Datei.

Jetzt sorgen wir mit „Push“ dafür, dass die veränderte Datei bei GitHub landet. Im aufgehenden Fenster nehmen Sie bitte folgende Anpassungen vor:

Und wieder ist eine kleine Änderung im History-Bereich zu sehen.

Schauen wir jetzt in GitHub nach, was passiert ist. Sie wechseln jetzt in den Status, und damit in die Perspektive, des Administrators. Sie sind also jetzt eine andere Person als die, die die Änderungen vorgenommen hat.

GitHub weist uns darauf hin, dass ein neuer Branch angelegt worden ist und dass in diesen Branch neue Dateien (in unserem Falle nur eine) gepusht wurden.

Da wir uns aber noch im Hauptbranch „main“ befinden, sind die Änderungen noch nicht zu sehen – was ja Sinn der Aktion war. Denn noch wissen wir nicht, ob die Änderungen fehlerfrei sind und bei den anderen (spekulativen) Administratoren im Projekt Akzeptanz finden.

Wir zeigen jetzt den Branch „new_feature“ an. Dazu drücken wir den Dropdown-Button mit der Aufschrift „main“ und wechseln auf „new_feature“

Wir sehen jetzt den neuen Branch „new_feature“

Dieser Branch hat jetzt (auch wieder wie erwartet) unsere Änderungen und befindet sich „1 commit ahead of main“. Was bedeutet das?

Der aktuelle Branch hat einen Commit mehr als der Branch „main“. Die Änderungen im neuen Feature-Branch wurden noch nicht in den „main“-Branch übertragen (=gemerged). Auch das ist ein schlüssiges, gewolltes Verhalten von git bzw. GitHub.

Compare & pull request

Sehen Sie den Button mit der Aufschrift “Compare & pull request”?

„Compare“ und „Pull Request“ sind Funktionen in Git und GitHub, die es Entwicklern ermöglichen, Änderungen an einem Repository vorzuschlagen und sie in den Hauptzweig (z.B. „main“ oder „master“) zu integrieren.

„Compare” ermöglicht es, den Unterschied zwischen zwei Branches aufzuzeigen, indem Änderungen, die gemacht wurden, gegenübergestellt werden. Dadurch können Entwickler sehen, welche Dateien und Zeilen geändert wurden und welche Auswirkungen die Änderungen haben werden.

Ein „Pull Request“ ist eine Anfrage an den Repository-Administrator (in diesem Falle ausschließlich an uns selbst), um Änderungen in den Hauptzweig des Repositorys zu übernehmen. Der Administrator kann dann die Änderungen überprüfen, Kommentare dazu abgeben und sie gegebenenfalls genehmigen und zusammenführen oder auch ablehnen.

Nach Klick auf den Button „Compare & pull request“ gibt es folgendes Fenster in GitHub.

Wir sehen praktischerweise schon den Kommentar, den wir beim Commit der Änderungen angegeben haben. Es gibt aber auch die Möglichkeit, einen längeren, erkenntnisreichen Kommentar zu hinterlassen.

Wenn wir etwas nach unten scrollen, sehen wir die erfolgten Änderungen im Detail, wie wir es schon in Sourcetree kennenlernen durften.

Mit „Create pull request“ werden wir nun die Anfrage an den Administrator (auch wenn wir das selbst sind) stellen, unseren neuen Code in dem Branch „new_feature“ zu kontrollieren und bei Akzeptanz, in den Haupt-Branch „main“ zu übernehmen.

Schauen wir, was passiert, wer wir den Knopf drücken. Es öffnet sich ein neues Fenster im Browser.

Die Änderungen akzeptieren

Wir sehen oben die Überschrift des Commits, eine Beschreibung hatten wir nicht angegeben. Interessanterweise kann GitHub schon feststellen, dass es voraussichtlich keine Konflikte beim Zusammenführen der README.md-Datei auf dem Hauptbranch geben wird.

Bevor wir den Request jetzt final akzeptieren, scrollen wir noch kurz nach unten.

Hier könnten wir, wenn wir wollten, den Request ablehnen (und vorher noch einen Kommentar dazu hinterlassen.)

Aber wir haben uns ja dazu entschieden, den Request zu akzeptieren, also drücken wir beherzt auf „Merge pull request“.

Nach einer kleinen Zwischenfrage, auf die wir einen kleinen Kommentar (z.B. einen Dank an den fleißigen Programmierer) hinterlassen können, drücken wir jetzt aber wirklich final auf „Confirm merge“.

So sieht dann das Ergebnis aus:

Der Pull request wurde erfolgreich eingebunden und wurde jetzt geschlossen. Der Administrator hat nun noch die Gelegenheit den „new_feature“-Branch zu löschen oder nicht.

Es hängt von den individuellen Projektanforderungen und -richtlinien ab, ob er dies tut. Einige Teams bevorzugen das Löschen des Feature-Branches, um eine saubere und übersichtliche Branch-Historie zu erhalten, während andere Teams den Feature-Branch behalten möchten, um mögliche zukünftige Probleme leichter zu identifizieren und zu debuggen.

Es gibt jedoch auch Kompromisslösungen, wie zum Beispiel das Umbenennen des Feature-Branches in einen entsprechenden Namen, um anzuzeigen, dass er bereits gemerged wurde. In jedem Fall ist es wichtig, klare Richtlinien für das Branching-Verhalten im Team zu definieren und sicherzustellen, dass alle Teammitglieder diese Richtlinien verstehen und befolgen.

So sieht jetzt der Hauptbranch aus. Die Änderungen wurden komplett übernommen.

Die Änderungen im lokalen Repository – Pull oder Fetch

Damit jetzt alle am Projekt Beteiligten wieder auf den gleichen Stand der Entwicklung kommen – z.B. am Beginn eines neuen Arbeitstages, müssen sie die aktuellen Änderungen aus dem entfernten (remote) Repository auf GitHub übernehmen. Das schließt übrigens auch den Einreicher des „Pull requests“ selbst mit ein, denn er weiß ja noch nicht, dass seine Änderungen akzeptiert worden sind.

Um das zu erreichen, gibt es die Befehle „pull“ und „fetch“, die beide dafür da sind, Änderungen aus dem entfernten Repository zu übernehmen, sich aber in einem wichtigen Punkt unterscheiden.

Der Befehl „fetch” ruft alle Änderungen ab, die in einem Remote-Repository vorgenommen wurden, ohne diese in das lokale Repository zu integrieren. Dadurch können Sie sehen, welche Änderungen in dem Remote-Repository vorliegen, bevor Sie entscheiden, ob Sie sie zusammenführen möchten oder nicht.

Im Gegensatz zum Befehl „pull“ führt „fetch“ keine automatische Zusammenführung durch. Stattdessen müssen Sie entscheiden, ob Sie die Änderungen in Ihr lokales Repository integrieren möchten. Wir werden das jetzt mal machen.

Nach Klick auf „Fetch“ in der oberen Menüleiste erhalten wir drei Optionen zur Auswahl:

„Fetch from all remotes“ in Git bedeutet, dass alle Remote-Repositories, die mit dem lokalen Repository verbunden sind, nach Aktualisierungen durchsucht werden.

“Prune tracking branches no longer present on remote(s)?” entfernt die lokalen Tracking-Branches irreversible, die nicht mehr auf dem Remote-Repository vorhanden sind.

„Fetch all tags“ lädt alle Tags aus dem Repository herunter. Ein Tag ist ein Name, der einem bestimmten Commit zugewiesen wird, um ihn zu markieren. Es kann nützlich sein, alle Tags herunterzuladen, um sicherzustellen, dass Sie alle Informationen zu bestimmten Commits haben, einschließlich Informationen zu veröffentlichten Versionen oder Meilensteinen.

Ich belasse es fürs Erste bei den Default-Einstellungen.

Als Ergebnis erhalten wir … nichts, oder zumindest keine Änderungen. Woran liegt das? Das ist in unserem Falle leicht zu erklären, da wir ja die Einzigen sind, die Änderungen vorgeschlagen haben. Dementsprechend werden uns keine Differenzen aus anderen Pull/Merge requests angezeigt.

Wir können daher beruhigt „Pull“ in der Menüzeile drücken, um den Abgleich mit dem remote Repository abzuschließen

Nun haben wir vier Optionen zur Auswahl.

Mit „Commit merged changes immediately“ wird Git automatisch einen neuen Commit erstellen, der die zusammengeführten Änderungen beim Zusammenführen von Branches enthält. Wenn Sie das nicht möchten, bspw. aus Kontrollgründen, müssen Sie das später von Hand machen.

„Include messages from commits merged in merge commit“. Wenn diese Option ausgewählt ist, werden die Commit-Messages der zusammengeführten Commits in den Merge-Commit übernommen. Ich würde aus Gründen der Übersichtlichkeit darauf verzichten.

„Create a new commit even if fast-forward is possible?“ lassen wir fürs Erste deaktiviert, ansonsten könnten wir die neuen Commits aus dem Merge nicht mehr rückgängig machen.

„Rebase instead of merge“ – dieser Punkt dient dazu, die komplette Commit-Historie in einem linearen Verlauf zusammenzuführen. Das kann übersichtlicher sein, kann aber dazu führen, dass Informationen verloren gehen. Bei neuen Projekten sollte man sich einmalig festlegen, welcher der beiden Methoden genutzt wird. Es sollte tunlichst darauf geachtet werden, beide Methoden nicht zu vermischen. Ich lasse dieses Feld deaktiviert, da ich immer der Merge-Methode den Vorzug vor Rebase gebe.

Ich setze jetzt lediglich den Haken bei „Commit merged changes immediatly“, da ich davon ausgehe, dass beim Merge in GitHub alles richtig war.

Wie Sie sehen, hat sich nichts großartig getan, außer dass die kleine „2“ verschwunden ist, denn jetzt haben wir eigentlich unsere zuvor selbst erstellten Änderungen „gepullt“ haben. Das Ergebnis wäre ein anderes, wenn wir auch Änderungen anderer Personen übernommen hätten. Das werden wir im nächsten Kapitel sehen.

Zusammenfassung: Wir wissen nun, wie wir Änderungen über einen neuen Branch zu GitHub einspielen, wie wir diese Änderungen in den Hauptbranch einfügen und wie wir externe Änderungen im Code in unser Repository übernehmen können.

Git und GitHub für Windows mit Sourcetree, Teil 2: Stages, Commit und Push

In dieser Fortsetzung des ersten Teils (Git und GitHub für Windows mit Sourcetree, Teil 1: Grundlagen) möchte ich zeigen, wie man die allererste Datei bearbeitet, im lokalen Repository speichert und danach zu GitHub überträgt.

Wir rufen uns zunächst die Startseite von Sourcetree in Erinnerung, nachdem wir unser erstes Repository geklont haben.

Wenn wir auf „Open in Explorer“ klicken, öffnet sich das bekannte Explorer-Fenster im Verzeichnis des angelegten Repositorys/Projektes.

Momentan befindet sich dort erst die Datei „README.md“. Wir öffnen diese direkt mit einem Editor ihrer Wahl.

Im Editor sehen wir, dass es sich um eine simple Textdatei mit speziellen Formatierungsanweisungen handelt. Das Gatter „#“ kennzeichnet dabei zum Beispiel eine Überschrift erster Ebene.

Wir ergänzen jetzt den Text um einen beliebigen Text (hier: Hello World!) und speichern diesen.

Und jetzt vollzieht sich ein elementarer Schritt in Git bzw. Sourcetree. Wenn wir auf die Software blicken, sehen wir, dass sich etwas geändert hat.

Sourcetree hat erkannt, dass sich die Datei „README.md“ geändert hat. Und wenn wir den Namen der Datei im Feld „Unstanged files“ anklicken, sehen wir oben rechts die zeilenweise registrierten Änderungen.

Wir können sehen, dass die Zeile „A nice description.“ entfernt wurde, dann wurde die Zeile „A nice description. Hello World!“ hinzugefügt. Git registriert Änderungen im Code immer zeilenweise und nicht zeichenweise, daher die auf den ersten Blick umständliche Darstellung.

Exkurs: die Zustände in Git

In Git gibt es drei Bereiche (oder Zustände), in denen Änderungen an Dateien verfolgt werden: unstaged, staged und committed.

Unstaged: Hier werden alle Änderungen angezeigt, die seit dem letzten Commit an einer Datei vorgenommen wurden, aber noch nicht zum Staging-Bereich hinzugefügt wurden.

Staged: Hier werden Änderungen angezeigt, die mit dem Befehl „git add“ (oder dem Äquivalent in Sourcetree) zum Staging-Bereich hinzugefügt wurden, aber noch nicht zum Commit vorgesehen sind.

Committed: Hier werden alle Änderungen gespeichert, die mit dem Befehl „git commit“ (oder dem Äquivalent in Sourcetree) vorgenommen wurden und somit in der Git-History festgehalten sind.

Der Unterschied zwischen den Bereichen ist also, ob Änderungen noch gespeichert oder nur vorgesehen sind. Durch das Hinzufügen zum Staging-Bereich kann man einzelne Änderungen separat commiten und somit die Git-History übersichtlicher gestalten.

Zu Beginn des Arbeitens mit Git wird sich unweigerlich auf die Frage auftun: „Warum gibt es einen Staging-Bereich, warum committe ich nicht sofort?“

Die Antwort erschließt sich, wenn man einen kompletten Arbeitstag mit Git hinter sich gebracht hat:

Der Staging-Bereich in Git ermöglicht es Entwicklern, bestimmte Änderungen an ihren Dateien zu wählen und separat von anderen Änderungen zu commiten. Dadurch kann man gezielter arbeiten und Änderungen besser organisieren.

Ein weiterer Vorteil des Staging-Bereichs ist die Möglichkeit, Änderungen zu überprüfen und sicherzustellen, dass sie korrekt sind, bevor sie endgültig commitet werden. Auf diese Weise kann man sichergehen, dass man keine unerwünschten Änderungen in das Repository hochlädt und die Versionsgeschichte des Projektes sauber bleibt.

Der Staging-Bereich ein wichtiges Werkzeug ist, um Änderungen effektiv und sicher in Git zu managen.

Mit „Stage all“, „Stage selected“ oder dem Pluszeichen neben dem Dateinamen befördern wir jetzt die Datei „README.md“ aus dem „Unstanged“ Bereich in den „Staged“ Bereich. Die Unterschiede in der Datei sind weiterhin einsehbar.

Übrigens können wir mit „Unstage all“, „Unstaged Selected“ oder dem Minuszeichen neben dem Dateinamen die Datei wieder in den Zustand/Bereich „Unstaged“ zurückversetzen. Probieren Sie es aus, es kann nichts passieren. Befördern Sie die Datei aber danach wieder in den Bereich „Staged“, denn wir sind noch nicht fertig mit unserem kleinen Workflow.

Schreiben Sie jetzt einen Kommentar in das untere Feld. Dies ist wichtig, um später noch zu wissen, warum Sie welche Änderungen veranlasst haben, und drücken Sie „Commit“.

Wie Sie sehen, ist die Software nach wenigen Augenblicken in den Bereich „History“ gesprungen. Diese Commit-History hilft Ihnen, die Branches- (der Begriff wird später noch erklärt) und den Commit-Verlauf zu visualisieren. Er hilft, die jüngsten Git-Aktionen im Projektarchiv zu überprüfen, und zeigt, wer wann welche Codeänderungen vorgenommen hat, sodass es einfach ist, herauszufinden, wann ein Fehler eingeführt wurde und zu einer früheren Version zurückzukehren.

Der finale Schritt wird jetzt sein, diese über den Commit erfolgten Änderungen auf GitHub online zu stellen (im Jargon von GitHub: pushen). Dazu gibt es den Button „Push“ in der Menüleiste von Sourcetree. Hier ist bereits eine kleine 1 zu sehen, die sich auf die einzelne zu pushende Datei „README.md“ bezieht.

Nach einem „Push“ erscheint ein schwebendes Fenster, das nach weiteren Angaben fragt. Wir können jetzt vorerst die Default-Einstellungen übernehmen und erneut „Push“ drücken.

Der History-Bereich hat sich scheinbar nicht geändert. Aber beim genauen Betrachten ist zu erkennen, die Markierung “origin/HEAD” in der History eine Position nach oben gerutscht ist. Das “origin/HEAD” bedeutet, dass es sich um den aktuellen Commit des entfernten Repositorys handelt, auf das unser lokales Repository verweist. Das remote Repository in GitHub und das lokale Repository auf unserer Festplatte befinden sich jetzt also wieder auf dem selben Stand.

Und um zu prüfen, ob die Änderungen tatsächlich korrekt bei GitHub angekommen sind, öffnen wir den Browser und öffnen das Repository. Wie wir sehen, hat sich der Text der README.md-Datei geändert. Und das wollten wir erreichen.

Zusammenfassung: Wir haben gelernt, wie wir eine Datei in unserem eigenen, lokalen Repository speichern und wie diese Datei dann auf GitHub übertragen werden.

Vorschau: Im nächsten Beitrag beschäftigen wir uns mit dem Thema, was passiert, wenn mehrere Personen parallel an einer Datei arbeiten. Wer gewinnt? Wie wird entschieden, was übernommen wird?

Git und GitHub für Windows mit Sourcetree, Teil 1: Grundlagen

Ich möchte hier eine Schnell-Anleitung (eventuell mit Fortsetzung) zur Nutzung von Git (und GitHub) allein mit Windows-Tools aufzeigen, wobei bewusst auf Linux-Mitteln wie z.B. die Konsole, wo möglich und zweckdienlich, verzichtet wird.

Die Software

Wir benötigen: Sourcetree

Sourcetree ist ein Git-Client, der eine grafische Benutzeroberfläche bereitstellt. Mit Sourcetree können Benutzer Repositories erstellen, klonen, committen und pushen sowie alle Änderungen protokollieren und vergleichen. (Git-)Repositories sind Speicherorte, in denen Git-Projekte verwaltet werden, einschließlich aller Dateiversionen und des Projektverlaufs.

Die Installation gestaltet sich einfach. Einen Bitbucket-Account benötigen wir nicht, daher drücken wir „Skip“.

SourceTree Installation

Im nächsten Schritt deaktivieren wir „Mercurial“, das ebenfalls nicht benötigt wird. Aber ich würde empfehlen, den Haken bei „Configure automatic line handling …“ zu setzen. Das ist praktischer, falls wir irgendwann einmal zwischen dem Windows- und Linux-Universum Dateien austauschen möchten. Ansonsten würden sich bei jedem Auschecken von Code die Zeilenumbrüche verdoppeln, das liegt an der Art und Weise, wie Windows Zeilenumbrüche speichert und würde jetzt en détail zu weit führen.

SourceTree Installation

In den Preferences geben Sie zum Schluss noch ihre Daten ein.

SourceTree Installation

Die Startseite der Software sollte sich uns folgendermaßen präsentieren:

SourceTree
Sourcetree

Um nun weiterzukommen, müssen wir unbedingt verstehen, was es mit SSH-Schlüsseln auf sich hat, daher an dieser Stelle ein kleiner Exkurs über das Thema. Kenner können darüber hinweglesen.

Exkurs: SSH und SSH-Schlüsselpaare

SSH steht für „Secure Shell“ und ist ein Verschlüsselungsprotokoll, das für die Kommunikation zwischen zwei Computern verwendet wird.

Zur Anwendung kommen dabei SSH-Schlüsselpaare, die jeder Nutzer zunächst individuell erzeugen muss. Dieses Schlüsselpaar ist weltweit einzigartig. Ein Schlüsselpaar besteht immer aus einem privaten und einem öffentlichen Schlüssel. Nur der öffentliche und der private Schlüssel desselben Schlüsselpaares passen zusammen. Besitzt man nur einen von beiden Schlüssel, kann man nichts damit anfangen, man benötigt immer beide.

Der öffentliche SSH-Schlüssel ist für alle zugänglich (so verrät es ja der Name) und sollte allen Parteien, mit denen man kommunizieren möchte, zur Verfügung gestellt werden, indem man ihn zum Beispiel auf der eigenen Website veröffentlicht.

Der private Schlüssel hingegen – auch das verrät schon der Name – darf unter keinen Umständen in fremde Hände geraten, denn sonst wäre das gesamte Schlüsselpaar kompromittiert.

Möchte man also mit einem Server kommunizieren, muss man dafür sorgen, dass der Server den öffentlichen Schlüssel erhält (wie das funktioniert, erkläre ich gleich). Man selbst identifiziert sich dann mit dem auf dem eigenen Rechner verbliebenen privaten Schlüssel. Wenn man alles richtig eingestellt hat, erfolgt die weitere Arbeit bzw. Kommunikation von da an reibungslos und automatisch.

Wir erzeugen ein Schlüsselpaar

Ich empfehle, auch wenn man dafür mit der Kommandozeile arbeiten muss, das Schlüsselpaar mit Windows-Bordmitteln zu erzeugen, da es mit Sourcetree meinem Erachten nach zu kompliziert ist.

Wir öffnen die Kommandozeile auf Windows und geben folgende Befehle ein:

cd %USERPROFILE%
mkdir .ssh
cd .ssh
ssh-keygen

Kurze Erklärung: Wir legen in unserem Benutzer-Verzeichnis den Ordner „.ssh“ an. Bitte den Punkt nicht vergessen! Wir wechseln in das Verzeichnis und legen ein Schlüsselpaar an.

Als Ergebnis erhalten wir zwei Dateien:

  • id_rsa – das ist der private Schlüssel
  • id_rsa.pub – das ist der öffentliche Schlüssel

Wer möchte, kann den privaten Schlüssel mit einem Passwort absichern (siehe roter Pfeil). Dies verschafft zusätzliche Sicherheit, falls der private Schlüssel doch einmal in die falschen Hände geraten sollte. Allerdings hat das auch den Nachteil, dass fortan bei jeder verschlüsselten Kommunikation nach dem Passwort gefragt wird, was den Arbeitsfluss unterbrechen kann. Das zusätzliche Passwort ist keine Pflicht, jeder muss für sich selbst darüber entscheiden.

Der öffentliche Schlüssel erhält die Endung „.pub“, der private gar keine.

WICHTIG: Denken Sie daran, für beide Schlüssel Backups anzulegen. Denn sollten Sie einen von beiden verlieren, müssen Sie wieder ein neues Paar anlegen.

Was ist denn jetzt GitHub und was haben wir damit zu tun?

GitHub ist eine Webplattform, die auf das Git-basierte Versionskontrollsystem spezialisiert ist. Mit GitHub können Entwickler, Teams und Organisationen ihre Softwareprojekte hosten, verwalten und mit anderen teilen. Die Funktionen von GitHub erleichtern die Zusammenarbeit zwischen Entwicklern und die Fehlerbehebung und Verbesserung von Softwareprojekten. GitHub bietet Entwicklern und Teams eine Plattform zur Verwaltung von Code, zur Zusammenarbeit und zur Integration in Workflow-Tools.

Damit wir jetzt mit GitHub kommunizieren können, müssen wir dort unseren öffentlichen Schlüssel hinterlassen. Dazu können Sie entweder selbst ein Konto bei GitHub anlegen oder Sie nutzen ein bereits bestehendes Konto, z.B. ein Konto ihres Unternehmens. Im letzten Fall müssen Sie ihren öffentlichen Schlüssel an den Administrator des Kontos schicken, damit dieser die folgenden Schritte erledigt.

GitHub bekommt unseren öffentlichen Schlüssel

Um einen öffentlichen SSH-Schlüssel Ihrem GitHub-Konto hinzuzufügen, können Sie die folgenden Schritte ausführen:

Kopieren Sie den Inhalt der öffentlichen Schlüsseldatei (hier: .ssh/id_rsa.pub) komplett in die Zwischenablage. Das können Sie wie gewohnt mit der Maus erledigen: Markieren und mit STRG+C kopieren.

type id_rsa.pub

Gehen Sie zu Ihrem GitHub-Konto und klicken Sie auf das Dropdown-Menü in der oberen rechten Ecke. Wählen Sie „Settings“ aus.

Klicken Sie im linken Menü auf „SSH and GPG Keys“.

Klicken Sie dann auf „new SSH key“

Geben Sie einen Titel für den Schlüssel ein (z.B. „RSA Schüssel von Martin Mustermann für Maschine 1“). Behalten Sie die Auswahl „Authentication key“ bei. Fügen Sie den Inhalt des öffentlichen Schlüssels in das Feld „Key“ ein. Klicken Sie auf „Add SSH key“.

Danach sollten Sie folgenden Bildschirm erhalten:

Mehr Informationen zum Thema SSH und GitHub

Der private Schlüssel für Sourcetree

Damit nun die verschlüsselte Kommunikation mit GitHub und Sourcetree erfolgen kann, müssen Sie in Sourcetree ihren privaten Schlüssel hinterlegen.

In Tools->Options->General nehmen Sie unter „SSH Client Configuration“ folgende Anpassungen vor:

Und natürlich geben Sie in „SSH Key“ ihren privaten Schüssel an, nicht den öffentlichen.

Das sollte es dann schon gewesen sein.

GitHub – der erste Kontakt

Wenn wir jetzt zum ersten Mal mit GitHub arbeiten möchten, gibt es zwei initiale Möglichkeiten, die den allergrößten Teil der Varianten abdecken. a) Entweder es existiert schon ein Repository auf GitHub, weil z.B. schon andere Kollegen damit arbeiten oder b) Sie legen selbst ein Repository dafür an, weil Sie selbst der Verantwortliche sind.

a) Das Repository existiert bereits.

Sollten Sie neu zu einem Projekt dazustoßen, so müssen Sie zunächst dafür sorgen, dass sie das entfernte Repository von GitHub (man sagt auch „remote Repository“) auf ihren lokalen Rechner kopieren. (Kleine Anmerkung: Sie können das auch auf mehrere ihrer Entwicklungs- und/oder Testrechner parallel machen, Git und GitHub koordinieren das automatisch.)

In der Sprache von Git heißt dieses Kopieren „Klonen“.

Der Verantwortliche für das Repository sollte Ihnen eine spezielle URL mitteilen, die in unserem Falle folgendermaßen aussieht:

git@github.com:martin-mustermann-firmenname/sourcetree-tutorial.git

Wenn Sie die URL nun in das Feld für „Source Path/URL“ eintragen, sollte Sourcetree keine Beanstandungen melden. Das lokale Verzeichnis auf ihrem Rechner wird automatisch vorgeschlagen, Sie können hier auch ein anderes wählen. (In diesem Beispiele sieht die URL etwas anders auf. Aber grundsätzlich ist der Aufbau identisch.)

Nach dem Klonen sollte ihr Bildschirm noch recht „jungfräulich“ aussehen.

Wie wir die ersten Dateien lokal verändern und zu GitHub hochladen, werden wir im nächsten Artikel besprechen. Kommen wir nun zu dem Fall, dass Sie das lokale Repository selbst anlegen.

b) Wir legen das Repository selbst an

Dazu wechseln wir zur Website von GitHub und wählen uns dort mit unseren Konto-Daten ein. In dem Menü rechts oben legen wir mit „New repository“ ein neues remote Repository an.

Den Namen des Projekts dürfen Sie frei wählen, sofern nicht schon ein gleichnamiges in ihrem Konto existiert.

Ich würde bei Projekten in Unternehmen auf jeden Fall die Option „Private“ aktivieren, weil sonst der Code jedem Nutzer weltweit zum Download bereitgestellt wird. Dieser Umstand rührt daher, dass GitHub ursprünglich eine Website zum gemeinschaftlichen Erstellen von Software-Projekten im Open-Source-Bereich war.

Damit wir wenigstens schon eine Datei im Repository haben, lassen wir die Datei „README.md“ automatisch anlegen. Diese können wir dann nachträglich noch anpassen.

Die README.md Datei ist eine zentrale Komponente eines jeden GitHub Repositories. Sie ist ein Markdown-Dokument, das im Hauptverzeichnis platziert wird, und dient dazu, eine Beschreibung des Projekts zu geben. Ferner kann sie als Einstiegspunkt in das Projekt dienen, indem sie den Benutzern Informationen zum Einrichten, Ausführen und Testen des Codes gibt. Die README.md Datei kann auch genutzt werden, um Links zu wichtigen Ressourcen wie Dokumentation, Demo-Videos, Support-Websites und anderen Projekt-Tools bereitzustellen.

Auf der Startseite des Projekts wird dann automatisch der Inhalt der README.md-Dateien angezeigt.

Unter dem grün hinterlegten Knopf „Code“ können wir jetzt die URL aufrufen, wie wir sie aus dem Kapitel „c) Das Repository existiert bereits“ schon kennen. Bitte verfahren Sie damit analog, um das neue Repository auf ihren lokalen Rechner zu klonen.

Zusammenfassung: Wir haben jetzt gelernt, wie wir für Git und GitHub eine einfache Software (Sourcetree) installieren, die zur verschlüsselten Kommunikation wichtigen SSH-Schlüssel nutzten und wie wir ein erstes Repository anlegen und mit GitHub verknüpfen.

Vorschau: In den nächsten Beiträgen wird es darum gehen, Dateien im Repository zu ändern, sie in der History mit Kommentaren abzulegen und für unsere Kollegen auf GitHub zur Verfügung zu stellen, und das möglichst konfliktfrei und automatisch.

Wie nutzt man mehrere GitHub-Accounts auf einem Rechner?

Wenn Sie mehrere GitHub-Accounts haben und auf demselben Rechner arbeiten möchten, können Sie Ihre Git-Konfiguration anpassen, um sicherzustellen, dass die richtigen Anmeldeinformationen für die jeweiligen Repositories verwendet werden.

1. Legen Sie für jeden GitHub-Account, den Sie verwenden möchten, ein neues SSH-Schlüsselpaar an.

Zunächst prüfen wir, ob schon ein SSH-Schlüssel auf ihrem Rechner existiert:

ls -al ~/.ssh

Sollte kein Schlüssel angelegt sein, müssen wir eben einen erzeugen:

ssh-keygen -t rsa -b 4096 -C "Ihr Kommentar"

Es ist nicht unbedingt nötig, das Schlüsselpaar mit einem Passwort zu sichern – vorausgesetzt, Sie sind sich sicher, dass keine unbefugte Person Zugriff auf Ihr Home-Verzeichnis hat. Ich gehe folgendermaßen vor:

mkdir ~/.ssh
cd ~/.ssh
ssh-keygen -t rsa -b 4096 -C "Schlüssel 1 auf masch1"
ls -la

Das Schlüsselpaar nenne ich beispielhaft „id_rsa_01“

Im Verzeichnis befinden sich dann zwei zusammengehörende Dateien: „id_rsa_01“ und „id_rsa_01.pub“. Erstere beinhaltet den privaten und Letztere den öffentlichen Schlüssel.

Generierung eines RSA-Schlüsselpaares
ssh-keygen -t rsa -b 4096 -C "Schlüssel 1 auf masch1"
Generierung eines RSA-Schlüsselpaares

Man sollte sich den Inhalt beider Dateien einmal anschauen, um den Aufbau zu kennen.

cat id_rsa_01
cat id_rsa_01.pub
Der private RSA-Schlüssel
Der private RSA-Schlüssel
Der öffentliche RSA-Schlüssel
Der öffentliche RSA-Schlüssel

WICHTIG: Sie dürfen den privaten Schlüssel „id_rsa_01“ niemals an Dritte geben, schon gar nicht ohne eine Passwortsicherung. Ich werde nach dem Schreiben dieses Artikels das Schlüsselpaar löschen und ein neues anlegen, damit niemand es aus der Grafik kopieren kann.

2. Fügen Sie jeden öffentlichen SSH-Schlüssel Ihrem GitHub-Konto hinzu.

Um einen öffentlichen SSH-Schlüssel zu Ihrem GitHub-Konto hinzuzufügen, können Sie die folgenden Schritte ausführen:

Kopieren Sie den Inhalt der öffentlichen Schlüsseldatei (hier: ~/.ssh/id_rsa_01.pub) komplett in die Zwischenablage.

cat ~/.ssh/id_rsa_01.pub

Gehen Sie zu Ihrem GitHub-Konto und klicken Sie auf das Dropdown-Menü in der oberen rechten Ecke. Wählen Sie „Settings“ aus.

Klicken Sie im linken Menü auf „SSH and GPG Keys“.

Klicken Sie dann auf „new SSH key“

Geben Sie einen Titel für den Schlüssel ein (z.B. „RSA 1 Key für Maschine 1“). Behalten Sie die Auswahl „Authentication key“ bei. Fügen Sie den Inhalt des öffentlichen Schlüssels in das Feld „Key“ ein. Klicken Sie auf „Add SSH key“.

Danach sollten Sie folgenden Bildschirm erhalten:

Mehr Informationen zum Thema SSH und GitHub

Da wir mindestens zwei Schlüsselpaare für diese Aufgabe benötigen, legen Sie bitte gemäß Schritt 1 und 2 ein neues, zweites Paar an und nennen es „id_rsa_02“.

Anschließen öffnen Sie ihren zweiten GitHub-Account und fügen diesem den zweiten, privaten Schlüssel hinzu.

3. Konfigurieren Sie Git so, dass es den richtigen Schlüssel für jedes Repository verwendet.

Nun legen wir die Datei „~/.ssh/config“ an (wenn sie noch nicht existieren sollte) und bearbeiten sie.

nano ~/.ssh/config

Hier ein Beispiel

# Private github account: 1manfactory
Host github-private
   HostName github.com
   IdentityFile ~/.ssh/id_rsa_01
   IdentitiesOnly yes

# Company github account: Umbrella Corporation
Host github-umbrella
   HostName github.com
   IdentityFile ~/.ssh/id_rsa_02
   IdentitiesOnly yes

Falls Sie ihre Schlüsselpaare mit einem Passwort gesichert haben, sollten Sie beide Schlüssel dem SSH-Agenten hinzufügen. Somit werden Sie in dieser Session nur einmal nach dem Passwort gefragt, wenn Sie mit GitHub kommunizieren.

eval $(ssh-agent) # Sonderbefehl zum Start des SSH-Agenten
ssh-add ~/.ssh/id_rsa_01
ssh-add ~/.ssh/id_rsa_02
SSH-Agent: Schlüssel hinzufügen
SSH-Agent: Schlüssel hinzufügen

Damit es nicht zu einer Fehlermeldung kommt, müssen wir jetzt auch den öffentlichen Schlüssel von GitHub herunterladen. Der Befehl „ssh-keyscan“ sammelt öffentliche Schlüssel und speichert sie in der Datei „~/.ssh/known_hosts“, so dass Sie bei zukünftigen SSH-Verbindungen nicht mehr danach gefragt werden.

ssh-keyscan github.com >> ~/.ssh/known_hosts

Jetzt testen wir beide Verbindungen.

ssh -T git@github-private
ssh -T git@github-umbrella

4. Der Beweis: Wir klonen ein Repository und pushen eine Änderung

Wenn alles geklappt hat, sollte es inzwischen kein Problem mehr sein, ein Repository zu klonen.

eval $(ssh-agent) # den SSH-Agenten starten
cd ~
git clone git@github-private:1manfactory/demoprojekt.git # ein simples Demo
cd demoprojekt
dir
cat README.md
Ein Repository aus GitHub klonen per SSH-Schlüssel
Ein Repository aus GitHub klonen per SSH-Schlüssel

Bei Bedarf kann/sollte man noch die E-Mail-Adresse und den Namen für dieses lokale Repository anpassen:

git config user.email "name@domain.org"
git config user.name "Martin Mustermann"

Eine Datei können wir jetzt wie gewohnt ins Repository übernehmen (=commit) und zu GitHub übertragen (=push).

nano README.md # ein bisschen was ändern
git add .
git commit -m "zweites commit von lokal"
git push # und hochladen nach GitHub