Die Schritte sind alle für den Umgang mit der Kommando-Zeile erklärt. Das lässt sich aber auch auf Visual Studio übertragen. In VS gibt es auch das Icon für „Source Control“ mit dem Repos hinzugefügt und virtuelle Maschinen erstellt werden können.
Check aktuelle Version:
python3 --version
Besser >= Python 3.9
einrichten. Auf Windows direkt über Microsoft Store installieren. Für Mac und manuelle Installation über Python.org.
Um zu schauen, ob Git bereits installiert ist, gib im Terminal / CMD folgenden Befehl ein:
git --version
Ist noch kein Git installiert, gibt es hier die entsprechenden Download-Files. Nach der Installation wieder mit git --version
überprüfen.
Beim ersten Verbinden eines lokalen Repo's mit einem remote Repo kann es sein, dass noch der Uername und die E-Mail hinterlegt werden müssen.
git --global user.name "John Smith"
git config --global user.email "[email protected]"
In gewünschtes Arbeitsverzeichnis wechseln:
cd <dir>
Oder (einfacher) über Dateien / Finder in das Verzeichnis wechseln und:
-
für Windows:
cmd
in die Suchleiste schreiben -
für Mac:
Rechtsklick
auf aktuelles Verzeichnis ->In Terminal öffnen
Anschließend dann das remote Repo clonen:
git clone https://gitlab.hrz.tu-chemnitz.de/tud-fgdh/software-development/software-development-ws-23/swdev-23-ws-g2.git
Danach sollte Ordner mit dem Namen SWDEV-23-WS-G2 erstellt worden sein.
In manchen Fällen wird anstelle eines Passwortes ein eigener „Personal Access Token“ gefordert, um Zugriff auf das Repo zu bekommen. Den kann man sich einfach im Gitlab unter seinem Account -> „Preferences“ -> „Access Tokens“ erstellen, kopieren und dann als Passwort verwenden.
Zum überprüfen der Verbindung:
git remote -v
Nun sind jeweils das globale und lokale Repo aufgesetzt und über git remote -v
miteinander verbunden.
Benötigt Python3.x Installation! Check mit
python3 --version
. Besser >=Python 3.9
einrichten.
In virtuellen Umgebungen können alle benötigten Pakete wie Pandas, Numpy, etc. eingerichtet und nach dem Projekt einfach wieder gelöscht werden. Bekannt ist sicherlich Anaconda, womit automatisch viele Pakete für Data Science Projekte installiert werden. Außerdem kann man mit Anaconda auch verschiedene Python-Versionen für verschiedene Umgebungen nutzen und beim installieren von zusätzlichen Paketen werden abhängigkeiten sehr genau geprüft (conda als Paketverwaltung). Nachteil allerdings: kostet Geld sobald man mal Kommerziell arbeitet, deshalb hier noch mal ein Intro, um direkt mit dem zuvor installierten Python eine virtuelle Umgebung zu erstellen:
Dafür zwei Möglichkeiten:
Benötigt make
-Befehl. Mit make --version
testen.
Im Terminal von Visual Studio:
make run
Damit ist sowohl die virtuelle Umgebung aktiviert als auch alle Pakete aus requirements.txt
installiert.
In Arbeitsumgebung wechseln:
cd SWDEV-23-WS-G2
Virtuelle Umgebung erstellen:
python3 -m venv .venv
Virtuelle Umgebung aktivieren:
-
auf Mac / Linux:
source .venv/bin/activate
-
auf Windows:
.venv\Scripts\activate
Sobald Umgebung aktiviert ist, erscheint der Name der Umgebung in Klammern vor dem Arbeitsverzeichnis (.venv)
.
Virtuelle Umgebung deaktivieren mit:
deactivate
Aktuell ist die virtuelle Umgebung noch "plain", sprich es sind keine individuellen Pakete installiert!
Wer bisher immer mit Anaconda gearbeitet hat, kennt bereits conda install ...
als Paketverwaltung. Die von Python selber bereitgestellte Paketverwaltung heißt pip
und damit können genauso alle möglichen Pakete installiert werden: pip install <paket>==<Version>
. (Über)
Installierte Pakete sehen:
pip list
Pip updaten:
pip install --upgrade pip
In einer requirements.txt
werden alle für das Projekt benötigten Pakete gespeichert, um das Einrichten für alle Entwickler zu erleichtern. Zur Installation einfach mit aktivierter virtueller Umgebung den Befehl ausführen:
pip install -r requirements.txt
Für eine genauere Erklärung was Branches eigentlich sind, gibt es unten noch den Git-Workshop mit Erklärungen mit dem Unterkapitel Branches. Damit es zu keinen Konflikten beim Upload kommt und jeder direkt starten kann, sei dem aber vorweggegriffen und hier eine kurze Erklärung zu Branches gegebenen:
Quelle: Bitbucket - Using Branches
Mit einem Branch (==Zweig), kann ausgehend von einem bestimmten Arbeitsstand, eine Kopie erzeugt und der Code darauf aufbauend weiter entwicklt werden. Um die Neuerungen aus dem Branch wieder mit dem „Hauptzweig“ zusammenzuführen, gibt es entweder den Merge-Befehl (lokal) oder den „Pull / Merge Request“ (global).
Eine übersicht aller Branches erhalten:
git branch -r
git branch -a
Einen neuen Branch erstellen:
git branch -b <new-branch> <Referenz Branch>
oder:
git checkout -b <Branch Name> <Referenz Branch>
Schauen in welchem Branch man sich befindet:
git status
Den Branch wechseln:
git checkout <new-branch>
Neuen Branch uploaden:
git push -u origin HEAD:<branch-name>
„-u“ fügt den online-Branch als Tracking-Branch hinzu, wodurch zukünftig nur noch git push
nötig ist. „origin“ ist der „Upstream“, also die URL des gesamten Repositories. „HEAD“ referenziert auf den aktuellen Stand des Branches in dem man sich befindet. Durch :<branch-name>
wird dann der Stand von HEAD in den Branch geschoben und falls nötig, noch erstellt.
Arbeitet man an eigenen Features kommen sicher auch neue Pakete hinzu, die dann jeder andere auch bei sich installieren muss, sobald er den Code lokal ausführen möchte. Dafür gibt es auch ein Paket, was die Verwaltung und Erstellung der requirements.txt
vereinfacht.
pip install pipreqs
pipreqs ./src --ignore .venv (--force)
Option --force
, falls existierende requirements.txt
überschrieben werden soll.
- Atlassian Git Tutorial: Komplettes Git-Tutorial
Um zu schauen, ob Git bereits installiert ist, gib im Terminal / CMD folgenden Befehl ein:
git --version
Ist noch kein Git installiert, gibt es hier die entsprechenden Download-Files.
Atlassian Tutorial - Setting Up A Repo
Git erleichert das gemeinsame Bearbeiten und Entwicklen von Code. Dafür wird ein zentrales (globales) Repository (Repo) bei einem Git-Anbieter wie Bitbucket, GitHub oder GitLab erzeugt, auf dem dann alle Teilnehmer Zugriff haben. Neben dem globalen Repo ist ein lokales Repo nötig, um lokal am Code mit Hilfe seiner IDE VisualStudio, IntelliJ, etc. zu arbeiten.
Beim ersten Verbinden eines lokalen Repo's mit einem gloabeln Repo kann es sein, dass noch der Uername und die E-Mail hinterlegt werden müssen.
git --global user.name "John Smith"
git config --global user.email "[email protected]"
Prinzipiell gibt es zwei Möglichkeiten um mit einem Git-Projekt zu starten:
git init <project-name>
cd <project-name>
git remote add origin https://gitlab.com/<username>/<global-repo-name>.git
Beim erstellen eines globalen Repo's wird automatisch ein „Branch“ mit dem Namen „Main“ oder „Master“ erstellt. Dieser existiert lokal noch nicht und muss dementsprechend vom globale Repo heruntergeladen werden.
Zum überprüfen:
git branch -r
oder
git branch -a
-r
/ -a
steht jeweils für remote
/ all
.
Zum herunterladen:
git pull origin main
git clone https://gitlab.com/<username>/<global-repo-name>.git
Zum überprüfen der Verbindung:
git remote -v
Nun sind jeweils das globale und lokale Repo aufgesetzt und über git remote -v
miteinander verbunden.
Atlassian Tutorial - Saving Changes
Alle bereits getätigten Änderungen können mit git status
oder im Git-Plugin bei Visual Studio unter „Changes“ überprüft werden. Bei git status
gibt es entweder „changes“ oder „(un-)tracked files“, also Änderungen in bereits exisitierenden Files oder neu erstellte Files.
Untracked files (und directories) können mit git clean -d -f
entfernt werden (KANN NICHT MEHR RÜCKGÄNGIG GEMACHT WERDEN!). -f
steht für force
und -d
für directory
. Mit der flag -n
kann man sich auch erstmal nur anzeigen lassen, welche Files gelöscht werden.
git clean -n (zeigt nur zu löschende files)
git clean -dn (zeigt zu löschende files & dirs)
git clean -f (löscht nur files)
git clean -df (löscht files & dirs)
Mit -i
lässt sich auch ein interactive
Modus starten bei dem man da für jedes File separat entscheiden kann, was damit passieren soll.
Änderungen in der .gitignore
können mit dem Befehl git rm -rf --cached .
berücksichtigt werden (insbesondere das nachträgliche Löschen von Files).
Git arbeitet mit den „three trees“:
- Working Directory
- Staging Area
- Commit History
Nach den Änderungen an einem File befinden sich die Änderungen lediglich im Working Directory. Das wird dadurch gekennzeichnet, dass bei git status
steht „Changes not staged [...]“ oder „Untracked files:“. Möchte man die Änderungen in die Staging Area überführen und damit bereitmachen, um in die Commit History zu gehen, führt man
git add <file-name> (einzelne Datei)
git add . (alle Änderungen im Repo)
Bei git status
oder Visual Studio sind alle Änderungen jetzt als „Changes to be committed:“ oder „Staged Changes“ aufgeführt. Möchte man einzelne oder alle Dateien wieder zurück in das Working Directory bringen, um noch Änderungen daran zu machen:
git reset <file>
git reset
Sind alle Ändernungen gemacht und sollen in die „Commit History“ gebracht werden, geht das mit
git commit -m "Kommentar was gemacht wurde etc.."
git status
ist wieder leer und ein neuer „Commit“ wurde erzeugt. Die gesamte Commit History kann via git log
oder (schöner)
git log --graph --oneline --decorate
angeschaut werden. Mit git commit -a -m "Message"
kann git add .
und kann git commit
zusammengefasst werden.
Wurde ausversehen eine Änderung commited, die wieder rückgängig gemacht werden soll oder möchte generell an einen früheren Punkt des Projektes springen, geht das mit:
git rebase <commit-id>
sowie
git reset <commit-id>
git rebase <commit-id>
ist eine schwächere Version des Reset und versetzt den HEAD lediglich an die Stelle der commit-ID. Dort kann dann der Stand zu dem Zeitpunkt angeschaut werden. Änderungen allerdings immer in einem neuen Branch!
Mit git reset <commit-id>
(implizit --mixed
) bleiben alle Änderungen im Working Directory erhalten, lediglich die Commits & Stages werden zum Zeitpunkt der commit-ID zurückgesetzt. Das heißt es befinden sich Dateien im Working Directory, die noch nicht gestaged sind (git status
).
Mit git git reset <commit-id> --hard
werden auch alle Änderungen im Working Directory überschrieben. Also Änderungen rückgängig gemacht und git status
ist up-to-date mit dem Stand des commit-id.
git reset <commit-id> --soft
liegt genau dazwischen und setzt ledglich die Commit-Historie zurück und lässt alle Änderungen in der Staging Area.
Für Änderungen im Kommentar des letzten commits:
git commit --amend -m "an updated commit message"
Für Änderungen im Code, die nachträglich zum letzten commit hinzugefügt werden sollen:
git add .
git commit --amend --no-edit
Möchten wir die Arbeit der letzten lokalen commits zusammenfassen geht das mit
git rebase -i HEAD:~x
wobei x die Anzahl der letzten commits beschreibt die zusammengefasst werden sollen. Anstelle von HEAD:~x geht auch die commit-ID (git log
).
Ist nun alles bereit zum Upload, kann mit dem nachfolgenden Befehl alles in den master-Branch geschoben werden.
git push origin HEAD:master
Um die Arbeit mit Git noch besser zu verstehen, noch ein kurzes Intro zu „Branches“ (Zweige).
Quelle: Bitbucket - Using Branches
Bisher haben wir nur vom „Main“- oder „Master“-Branch geredet, der am Ende auch den finalen lauffähigen Code beinhaltet. Bei mehrere Developern kann es allerdings hinderlich sein, wenn jeder seine individuellen Änderungen in den Main-Branch pusht und damit dann Konflikte bei anderen auftreten („Centralized WorkFlow“, hier mehr). Besser ist der „Feature Branch Workflow“, bei dem jedes zu entwickelnde Feature einen eigenen Branch enthält und dann zum Schluss komplett in den Main-Branch überführt wird.
Eine übersicht aller Branches erhalten:
git branch -r
git branch -a
Einen neuen Branch erstellen:
git branch -b <new-branch> <Referenz Branch>
oder:
git checkout -b <Branch Name> <Referenz Branch>
Branch Löschen
git branch -d <branch>
git branch -D <branch>
Schauen in welchem Branch man sich befindet:
git status
In einen neuen Branch wechseln:
git checkout <new-branch>
Den aktuellen Branch umbennenen:
git branch -m <new-branch-name>
Neuen Branch uploaden:
git push -u origin HEAD:<branch-name>
„-u“ fügt den online-Branch als Tracking-Branch hinzu, wodurch zukünftig nur noch git push
nötig ist. „origin“ ist der „Upstream“, also die URL des gesamten Repositories. „HEAD“ referenziert auf den aktuellen Stand des Branches in dem man sich befindet. Durch :<branch-name>
wird dann der Stand von HEAD in den Branch geschoben und falls nötig, noch erstellt.
Fast-Forward-Merge vs. 3-Way-Merge
Angenommen man hat an einem Feature gearbeitet, während sich der Stand vom Main nicht, oder nur in andere Files geändert hat. Dann gibt es den Fast-Forward-Merge, der das aktuelle Feature an die Spitze vom Main setzt und dann den Main mit dem Feature vereint, sodass Main und der neue Branch auf dem selben Stand sind.
git checkout main
git merge --no-ff <feature-branch>
git branche -d <feature-branch> (löscht Branch)
Die Flag „-no-ff“ fügt für den Merge einen neuen commit hinzu, alo einen Eintrag, dass ein Merge stattgefunden hat. Das würde normalerweise durch die Fast-Forward-Struktur verloren gehen. Die Funktion git merge
führt dann automatisch einen git rebase
durch, der auch zum zusammenfassen von Commits genutzt wird. Weitere Infos dazu unten in Rebase.
Quelle: Bitbucket - Using Branches
Jetzt zum 3-Way-Merge. Dabei ändert sich auch der Inhalt im Main-Branch und bildet quasi den normalen Workflow ab.
git checkout main
git merge <feature-branch>
git branche -d <feature-branch> (löscht Branch)
Im Laufe der Entwicklung eines Feature kommen einige Commits zusammen (git log --graph --oneline --decorate
). Falls man da etwas aufräumen möchte, schaut weiter bei Zusammenfassen von Commits nach.
Mit dem Pull / Merge Request, können Änderungen aus einem Branch in einen anderen Branch integriert werden. Für gewöhnlich macht man das für die Entwicklung neuer Features im Main-Branch. Ist man mit der Entwicklung eines Features in einem separaten Branch fertig, pusht man seinen Code in den zugehörigen remote Branch und erstellt über die Benutzeroberfläche von GitLab einen „Merge Request“.
Dabei wird festgelegt welcher „Source Branch“ in welchen „Target Branch“ gemergt werden soll und wer als „Approver“ noch mal über den Code schauen soll, um die Änderungen quasi „abszusegnen“.
Hier sei einfach noch mal auf die Doku von GitLab verwiesen: Merge Request
Falls andere Developer Änderungen an ihrem Code in das Repo gepusht haben, gibt es zwei Varianten, diese in den lokalen Code zu integrieren:
Git Fetch:
git fetch --dry-run
git fetch origin
git checkout <branch>
git log --oneline <fetched_remote_branch>
git merge <fetched_remote_branch>
Git Pull:
git pull
Git pull führt die oben genannten Befehle automatisch aus.
Sollen Files aus dem Repo entfernt werden, kommt es häufig vor, dass die Änderung nicht registriert wird (insbesondere, wenn das .gitignore
-File angepasst wird).
Dafür werden mit git rm -r --cached .
erst alle bisher getrackten Files entfernt und mit der Flag --cached
bleiben diese allerdings im Working Directory enrhalten. Anschließend erstellt man dafür einen neuen Commit und die gelöschten Files werden nicht mehr hinzugefügt.
git rm -r --cached .
git add .
git commit -m ".gitignore is now working"
OPTIONAL: Um sein aktuelles Feature an die Spitze von Main zu bringen gibt es die Funktion git rebase
. Diese ordnet dem aktuellen Branch eine neue „Base“ zu -> „RE-base“. Die Base wird dann entsprechend bei git log --graph --oneline --decorate
angezeigt.
Dafür:
git checkout <feature-branch>
git rebase main
Im Laufe der Entwicklung eines Feature kommen einige Commits zusammen (git log --graph --oneline --decorate
). Falls man da etwas aufräumen möchte, kann man das mit dem Befehl machen:
git rebase -i HEAD~3
Danach öffnet sich ein Text-Editor mit einigen Optionen:
pick ba80f58 new update on README
pick 3ddb80f Update README.md
pick 607343a Update README.md
Rebase b900b43..607343a onto b900b43 (3 commands)
Commands:
p, pick = use commit
r, reword = use commit, but edit the commit message
e, edit = use commit, but stop for amending
s, squash = use commit, but meld into previous commit
f, fixup = like "squash", but discard this commit's log message
x, exec = run command (the rest of the line) using shell
d, drop = remove commit
These lines can be re-ordered; they are executed from top to bottom.
If you remove a line here THAT COMMIT WILL BE LOST.
However, if you remove everything, the rebase will be aborted.
Note that empty commits are commented out
Um commits zusammenzuführen wählt man „squash“ wie folgt aus (Shift + I zum bearbeiten):
pick ba80f58 new update on README
squash 3ddb80f Update README.md
squash 607343a Update README.md
Mit „Esc“ + „:wq!“ verlässt man den Editor und speichert. Der Commit erhält den Kommentar des oberen Commits „new update on README“. Falls man den anpassen möchte:
reword ba80f58 new update on README
squash 3ddb80f Update README.md
squash 607343a Update README.md
Es öffnet sich ein neues Fenster mit:
This is a combination of 3 commits.
This is the 1st commit message:
New Squash on Commit
With new line
This is the commit message #2:
adjustments on app.py
This is the commit message #3:
Merged Commits
Update README.md
Message anpassen und wieder mit „:wq!“ schließen.
Anstelle von
git rebase -i HEAD~3
Kann auch die entsprechende Commit-ID benutzt werden. Diese steht bei git log
neben den entsprechenden Commits
git rebase -i a6f040abf48df4f00185f097cb17a62aded27b4b
Der Rest verhält sich analog.
-
Atlassian Git Tutorial: Komplettes Git-Tutorial
-
draw.io: Umgebung um Skizzen anzufertigen. Bspw. Darstellen von Architekturen oder Funktionen einzelner Features
-
Markdown-Syntax: Erklärung zur Markdown-Syntax
-
src
:git-cheat-sheet.pdf
: Alle wichtigen Git-Kommandos auf einen Blick