Branches dienen also dazu von einem bestimmten Entwicklungszweig (meistens dem Haupt-Branch) wieder abzuzweigen. Einen Branch kann man auf zwei unterschiedliche Arten erstellen.
Mit git checkout -b <neuer-branch>
wird ein neuer Branch erstellt und gleich in diesen gewechselt:
$ git checkout -b feat/mfa
Switched to a new branch 'feat/mfa'
Mit git branch <neuer-branch>
wird nur ein neuer Branch erstellt, aber noch nicht in diesen Branch gewechselt.
Zum Wechseln muss man git switch <branch>
ausführen.
$ git branch feat/mfa
$ git switch feat/mfa
Switched to branch 'feat/mfa'
In der git-bash sieht man den Branch, in dem man gerade arbeitet, auch in der Befehlszeile!
Ein Branch kann mit git branch -d <branch-name>
wieder gelöscht werden. Aber Achtung, nicht den Zweig abschneiden,
auf dem man sitzt ;)
$ git branch -d feat/mfa
error: cannot delete branch 'feat/mfa' used by worktree at 'C:/Users/[email protected]/git-schulung/projekt1'
besser:
$ git switch main
Switched to branch 'main'
$ git branch -d feat/mfa
Deleted branch feat/mfa (was 02f7cd7).
$ git checkout -b feat/mfa
$ echo "feature: 123" >> neues-file.txt
$ git add neues-file.txt
$ git commit -a -m "feat: erster versuch des neuen features"
$ git log --all --oneline --graph
* a20f10d (HEAD -> feat/mfa) feat: erster versuch des neuen features
* ae3e653 (main) Revert "das file gefällt mir nicht mehr"
* 10128d1 ich möchte nochmal commits erklären
* 0e3d42a das file gefällt mir nicht mehr
Im Git-Log sieht man jetzt dass der main-Branch beim Commit ae3e653 endet, der feat/mfa-Branch gerade beim darauf folgenden Commit a20f10d steht. Dort ist auch der HEAD, weil der aktuell ausgecheckte Branch der Branch feat/mfa ist.
Jetzt erstellen wir noch im main-Branch ein paar Commits, um die Weiterentwicklung im main-Branch zu simulieren.
Wieder in den main-Branch wechseln (kann über git switch main
oder git checkout main
erfolgen):
$ git checkout main
Switched to branch 'main'
$ echo "main: weiterentwicklung" >> dasisteinfile.txt
$ git add dasisteinfile.txt
$ git commit -a -m "kleine weiterentwicklung im main-Branch"
$ echo "main: weiterentwicklung teil 2" >> dasisteinfile.txt
$ git commit -a -m "noch eine weiterentwicklung im main-Branch"
$ git log --all --oneline --graph
* 3f8fb95 (HEAD -> main) noch eine weiterentwicklung im main-Branch
* e2d83b4 kleine weiterentwicklung im main-Branch
| * a20f10d (feat/mfa) feat: erster versuch des neuen features
|/
* ae3e653 Revert "das file gefällt mir nicht mehr"
* 10128d1 ich möchte nochmal commits erklären
Etwas schöner sieht man es im VS Code mit der Git-Graph Extension:
Wenn ein main-Branch und ein Feature/Fix-Branch parallel weiterentwickelt werden, gibt es zwei Gründe Änderungen von einem in den anderen Branch zu übernehmen.
Das ist dann wichtig, wenn sich der main-Branch weiterentwickelt hat, und man will im Feature-Branch wissen ob der aktuellste Code vom main-Branch auch mit den Neuentwicklungen vom Feature-Branch funktioniert.
Das will man im Feature-Branch testen, bevor man das Feature im main-Branch public macht.
Mit git rebase
werden die Commits vom Feature-Branch auf den letzten Commit des main-Branch gelegt.
Damit ändern sich die Commits des Feature-Branches natürlich, weil ihr Inhalt ein anderer ist. Das macht git automatisch.
Vor dem Rebase:
Nach dem Rebase:
Hintergrund: Eigentlich macht Git für jeden Commit den er "verschieben" muss ein git cherry-pick
.
Git schaut sich den Unterschied zwischen den Commits in der "alten" Commit-Reihe an,
und packt diese Änderungen in neuen Commits auf die neue Commit-Reihe.
Der Command um einen Rebase des Feature-Branches auf den Master-Branch zu machen:
$ git rebase main feat/mfa
Successfully rebased and updated refs/heads/feat/mfa.
Wenn man sich jetzt das Git-Log ansieht, sieht man dass der Commit vom Feature-Branch nach dem letzten Commit vom main-Branch erfolgt und eine neue Commit-ID bekommen hat:
$ git log --all --oneline --graph
* b83a7e8 (HEAD -> feat/mfa) feat: erster versuch des neuen features
* 3f8fb95 (main) noch eine weiterentwicklung im main-Branch
* e2d83b4 kleine weiterentwicklung im main-Branch
* ae3e653 Revert "das file gefällt mir nicht mehr"
Vergleiche diesen Git-Log mit dem vorigen von oben!
Die Änderungen die im main-Branch gemacht wurden, sieht man jetzt auch im Feature-Branch:
$ git switch feat/mfa
Already on 'feat/mfa'
$ cat dasisteinfile.txt
main: weiterentwicklung
main: weiterentwicklung teil 2
Statt einem Rebase kann auch ein Merge-Commit gemacht werden.
Dazu wieder ein paar Commits im main-Branch erstellen:
$ git checkout main
$ echo "main: weiterentwicklung teil 3" >> dasisteinfile.txt
$ git commit -a -m "wieder aenderungen im main-Branch"
$ echo "main: weiterentwicklung teil 4" >> dasisteinfile.txt
$ git commit -a -m "schon wieder aenderungen im main-Branch"
$ git log --all --oneline --graph
Jetzt ist der main-Branch wieder zwei Commits weiter als der Feature-Branch.
Jetzt bringen wir diese zwei Commits vom main-Branch über einen merge-Commit in den Feature-Branch:
$ git switch feat/mfa
$ git merge main --no-edit
Merge made by the 'ort' strategy.
dasisteinfile.txt | 2 ++
1 file changed, 2 insertions(+)
$ git log --all --oneline --graph
* 932e922 (HEAD -> feat/mfa) Merge branch 'main' into feat/mfa
|\
| * 901eef7 (main) schon wieder aenderungen im main-Branch
| * 2958d1d wieder aenderungen im main-Branch
* | 2bf8a3f feat: erster versuch des neuen features
|/
* dbaa640 noch eine weiterentwicklung im main-Branch
* 512c2b9 kleine weiterentwicklung im main-Branch
* ae3e653 Revert "das file gefällt mir nicht mehr"
* 10128d1 ich möchte nochmal commits erklären
Der offensichtliche Unterschied ist, dass die Commits im Feature-Branch bei einem Merge nicht verschoben oder verändert werden. Bei einem Rebase aber schon!
Außerdem wurde ein zusätzlicher Commit erzeugt um die Änderungen vom main-Branch in den Feature-Branch zu bringen.
Aber wichtig: es sind immer noch erst die Änderungen vom main-Branch im Feature-Branch:
$ cat dasisteinfile.txt
main: weiterentwicklung
main: weiterentwicklung teil 2
main: weiterentwicklung teil 3
main: weiterentwicklung teil 4
Aber im main-Branch sind noch keine Änderungen vom Feature-Branch:
$ git switch main
Switched to branch 'main'
$ cat neues-file.txt
hallo ich bin da
Wie könnte man mit git diff
diese Unterschiede anzeigen lassen? Hat jemand eine Idee?
Um jetzt den Feature-Branch in den main-Branch zu mergen, kann man folgendes aufrufen:
$ git switch main
Switched to branch 'main'
$ git merge feat/mfa --no-edit
Updating 3f8fb95..5a68398
Fast-forward
neues-file.txt | 1 +
1 file changed, 1 insertion(+)
Es wird "Fast-Forward" ausgegeben (sog. "Fast-Forward"-Merge), weil der main-Branch-Zeiger nur auf den nächsten Commit verschoben werden muss (Fast-Forward).
$ git log --all --oneline --graph
* 932e922 (HEAD -> main, feat/mfa) Merge branch 'main' into feat/mfa
|\
| * 901eef7 schon wieder aenderungen im main-Branch
| * 2958d1d wieder aenderungen im main-Branch
* | 2bf8a3f feat: erster versuch des neuen features
|/
* dbaa640 noch eine weiterentwicklung im main-Branch
* 512c2b9 kleine weiterentwicklung im main-Branch
* ae3e653 Revert "das file gefällt mir nicht mehr"
* 10128d1 ich möchte nochmal commits erklären
git rebase
kann eine gute Wahl sein, um die neuesten Commits vom main-Branch in den Feature-Branch zu bringen.
Da sich dann aber alle Commits vom Feature-Branch ändern müssen (warum eigentlich??) müssen das alle beteiligten Entwickler vom Feature-Branch wissen.
Der Vorteil ist, dass kein weiterer Merge-Commit im Feature-Branch erstellt wird.
Wann man auf jeden Fall kein Rebase machen sollte, ist im main-Branch wo sehr sehr viele Entwickler daran arbeiten, weil die alle andere Commits in ihrem lokalen Repository haben!
$ git reflog
Dann ID lt. reflog finden
$ git reset --hard HEAD@{8}
$ git log --all --oneline --graph
* b83a7e8 (feat/mfa) feat: erster versuch des neuen features
* 3f8fb95 (HEAD -> main) noch eine weiterentwicklung im main-Branch
* e2d83b4 kleine weiterentwicklung im main-Branch
* ae3e653 Revert "das file gefällt mir nicht mehr"