Von Tom Fischer | Werkstudent Java Development
Lesedauer: 10 Minuten
Zielgruppe: Studierende, Junior Devs mit Git-Grundkenntnissen
⏱️ 30-Sekunden-Zusammenfassung
Du kennst git add, git commit, git push. Cool. Aber was machst du bei Merge-Conflicts? Wie rettest du einen kaputten Commit? Wie arbeitest du mit Feature-Branches? Hier sind die Git-Commands, die ich bei Java Fleet jeden Tag brauche – erklärt von jemandem, der vor 3 Monaten auch noch Anfänger war. Mit echten Beispielen, echten Fehlern, echten Lösungen. 🔧
👋 Hi! Tom hier
Hi! 👋
Tom hier. Nach meinem letzten Post über IntelliJ-Setup kamen ein paar Fragen zu Git. „Wie machst du Branches?“ „Wie gehst du mit Merge-Conflicts um?“ „Was ist Rebase?“
Warum dieser Artikel? Weil ich in der Uni Git gelernt hab. Theorie. Solo-Projekte. git add ., git commit -m "fix", git push. Done.
Bei Java Fleet? Ganz andere Welt.
- 8 Entwickler arbeiten am gleichen Repo
- Feature-Branches für jedes Ticket
- Pull Requests mit Code Reviews
- Merge-Conflicts täglich
- Release-Branches und Hotfixes
Ich hab in den ersten 2 Wochen ALLES falsch gemacht:
- Direkt auf
maincommitted (oh no 😅) - Merge-Conflict mit
git push --force„gelöst“ (Cassian war not amused) - Vergessen zu pullen, dann Chaos
Nova hat mir dann das Git-Survival-Kit gezeigt. Die Commands, die du wirklich brauchst. Keine fancy Tricks, sondern das Daily Business.
Zeit, das anzugehen! 🔧
🎯 Git-Workflow bei Java Fleet
Unser Standard-Flow
So läuft es bei uns ab:
1. Ticket bekommen (JIRA) 2. Feature-Branch erstellen 3. Code schreiben + Committen 4. Pull Request erstellen 5. Code Review durchlaufen 6. Merge in main 7. Deployment
Klingt simpel, oder?
In der Praxis gibt’s 1000 Sachen, die schiefgehen können. Lass uns durchgehen, wie ich damit umgehe.
🌿 Feature-Branches – Der richtige Weg
Branch erstellen und wechseln
Das hab ich früher gemacht:
git branch feature/neue-funktion git checkout feature/neue-funktion
Was ich jetzt mache:
git checkout -b feature/TOM-123-neue-validierung
Ein Command statt zwei. -b erstellt den Branch UND wechselt direkt hin.
Branch-Naming Convention
Bei Java Fleet:
feature/TICKET-NR-kurze-beschreibung bugfix/TICKET-NR-kurze-beschreibung hotfix/TICKET-NR-kurze-beschreibung
Beispiele:
feature/TOM-123-user-validation bugfix/TOM-124-null-pointer-fix hotfix/PROD-99-critical-security-patch
Warum das wichtig ist:
- Jeder weiß sofort, was der Branch macht
- JIRA-Integration funktioniert automatisch
- Nachvollziehbar in Git-History
Branch-Status checken
Bevor ich anfange zu coden:
# Wo bin ich gerade? git branch # Was ist der Status? git status # Was ist auf Remote neu? git fetch --all
Das zeigt mir:
- Auf welchem Branch ich bin
- Welche Dateien geändert sind
- Ob remote neue Commits sind
Pro-Tipp von Cassian: „Mach git fetch bevor du anfängst. Dann weißt du, ob jemand parallel an was arbeitet.“
📝 Commits – Wie ich’s richtig mache
Commit-Messages die Sinn machen
Früher:
git commit -m "fix" git commit -m "update" git commit -m "changes"
Cassian beim Code Review: „Tom, was hast du gefixt? Was ist der Kontext?“
Jetzt nutze ich:
git commit -m "TOM-123: Add email validation to UserService - Validate email format with regex - Add unit tests for invalid emails - Update UserDTO with validation annotations"
Die Struktur:
TICKET-NR: Kurze Summary (max 50 Zeichen) [Leerzeile] - Detail 1 - Detail 2 - Detail 3
Warum das besser ist:
- Code Reviews gehen schneller
git logist lesbar- Jeder versteht, was du gemacht hast
Commits zusammenfassen mit Interactive Rebase
Situation: Ich hab 10 kleine Commits gemacht während Development:
fix typo add test fix test fix test again update documentation fix documentation typo
Problem: Das sieht chaotisch aus im PR.
Lösung: Interactive Rebase
# Letzten 10 Commits bearbeiten git rebase -i HEAD~10
Das öffnet einen Editor:
pick abc1234 TOM-123: Add user validation pick def5678 fix typo pick ghi9012 add test pick jkl3456 fix test pick mno7890 fix test again pick pqr1234 update documentation pick stu5678 fix documentation typo
Was ich ändere:
pick abc1234 TOM-123: Add user validation squash def5678 fix typo squash ghi9012 add test squash jkl3456 fix test squash mno7890 fix test again pick pqr1234 update documentation squash stu5678 fix documentation typo
Ergebnis: Aus 7 Commits werden 2 saubere Commits.
WICHTIG: Das machst du NUR auf deinem Feature-Branch, BEVOR du pushst oder einen PR erstellst!
Einzelne Dateien stagen
Früher:
git add . git commit -m "stuff"
Problem: Ich hab versehentlich Config-Dateien oder Debug-Logs committed.
Jetzt:
# Nur bestimmte Dateien git add src/main/java/UserService.java git add src/test/java/UserServiceTest.java # Oder interaktiv git add -p
git add -p ist Magic:
- Git zeigt dir jeden Chunk einzeln
- Du entscheidest:
y(yes),n(no),s(split) - Super für „ich hab an 3 Sachen gleichzeitig gearbeitet“
Nova’s Tipp: „Denk an Commits wie an Kapitel in einem Buch. Jeder Commit sollte eine logische Einheit sein.“
🔄 Pulling & Merging – Konflikte vermeiden
Pull bevor du pushst
Die Regel:
# IMMER vor git push git pull origin main
Warum? Wenn jemand anderes parallel auf main committed hat, musst du das erst mergen.
Besser: Pull with Rebase
git pull --rebase origin main
Was das macht:
- Holt die neuen Commits von main
- Legt DEINE Commits DARÜBER (statt Merge-Commit)
- Sauberere Git-History
Merge-Conflicts lösen
Das passiert:
Auto-merging src/main/java/UserService.java CONFLICT (content): Merge conflict in src/main/java/UserService.java Automatic merge failed; fix conflicts and then commit the result.
Schritt 1: Status checken
git status
Zeigt:
Unmerged paths:
(use "git add <file>..." to mark resolution)
both modified: src/main/java/UserService.java
Schritt 2: Datei öffnen
IntelliJ zeigt Conflicts direkt:
<<<<<<< HEAD
public void validateUser(User user) {
if (user.getEmail() == null) {
throw new ValidationException("Email required");
}
}
=======
public void validateUser(User user) {
if (user.getEmail() == null || user.getEmail().isEmpty()) {
throw new ValidationException("Email cannot be empty");
}
}
>>>>>>> feature/TOM-123-validation
Schritt 3: Entscheiden
<<<<<<< HEAD= Was auf main ist======== Trenner>>>>>>> feature/...= Deine Änderungen
Meine Entscheidung:
public void validateUser(User user) {
if (user.getEmail() == null || user.getEmail().isEmpty()) {
throw new ValidationException("Email cannot be empty");
}
}
Schritt 4: Als resolved markieren
git add src/main/java/UserService.java git commit -m "Merge main into feature/TOM-123"
Merge vs. Rebase
Die ewige Frage.
Merge:
git merge main
- Erstellt einen Merge-Commit
- History zeigt alle Branches
- Sicherer für Anfänger
Rebase:
git rebase main
- Legt deine Commits auf main drauf
- Lineare History
- Sieht cleaner aus
Bei Java Fleet:
- Feature-Branch: Rebase von main (saubere History)
- Zurück in main: Merge (nachvollziehbar)
Cassian’s Regel: „Rebase für lokale Branches. Merge für öffentliche Integration.“
🆘 Git-Notfall-Commands
„Oh shit, ich hab was Falsches committed“
Letzten Commit rückgängig machen (aber Änderungen behalten):
git reset --soft HEAD~1
Was das macht:
- Commit ist weg
- Dateien sind noch geändert (staged)
- Du kannst neu committen
Alles rückgängig machen (Änderungen verwerfen):
git reset --hard HEAD~1
⚠️ VORSICHT: Das löscht deine Änderungen!
„Ich hab auf dem falschen Branch committed“
Situation: Ich arbeite an feature/TOM-123, committe, und merke: Ich war noch auf main. 😅
Lösung:
# Commit-Hash kopieren git log # z.B. abc1234 # Auf richtigen Branch wechseln git checkout feature/TOM-123 # Commit hierher holen git cherry-pick abc1234 # Zurück zu main git checkout main # Letzten Commit entfernen git reset --hard HEAD~1
Cherry-Pick holt einen einzelnen Commit von einem Branch in einen anderen.
„Ich hab git push --force gemacht und alles gelöscht“
Real Story: Das hab ich gemacht. In meiner ersten Woche.
Was passiert ist: Mein push --force hat Cassians Commits überschrieben. Er hatte 2 Stunden Arbeit verloren.
Die Rettung:
# Git Reflog zeigt ALLES git reflog # Finde den Commit vor dem Force-Push # z.B. abc1234 # Setze Branch zurück git reset --hard abc1234 # Push (diesmal richtig) git push
Lesson learned: NIEMALS git push --force ohne Rücksprache!
Bei Java Fleet ist --force verboten, außer du bist allein auf einem Branch.
„Ich hab eine Datei gelöscht und will sie zurück“
Option 1: Noch nicht committed
git checkout -- dateiname.java
Option 2: Schon committed
# Finde Commit wo Datei noch existierte git log -- dateiname.java # Hole Datei von dort zurück git checkout abc1234 -- dateiname.java
Option 3: Ich weiß nicht mehr wo sie war
# Suche in der History git log --all --full-history -- dateiname.java
🔍 Git-History durchsuchen
Commits filtern
Alle Commits von Nova:
git log --author="Nova"
Alle Commits zu einer Datei:
git log -- src/main/java/UserService.java
Commits in den letzten 7 Tagen:
git log --since="7 days ago"
Kombiniert:
git log --author="Tom" --since="1 week ago" --oneline
Suche nach Code-Änderungen
„Wer hat diese Zeile geändert?“
git blame UserService.java
In IntelliJ: Rechtsklick auf Zeile → Git → Annotate
„Wo wurde dieser String zuletzt geändert?“
git log -S "validateUser" --source --all
Das findet: Alle Commits, wo „validateUser“ hinzugefügt oder entfernt wurde.
🎯 Branch-Management
Alte Branches aufräumen
Lokale Branches anzeigen:
git branch
Branch löschen:
git branch -d feature/TOM-122-old-feature
Branch force-löschen (wenn nicht gemerged):
git branch -D feature/TOM-122-old-feature
Remote Branches anzeigen:
git branch -r
Remote Branch löschen:
git push origin --delete feature/TOM-122-old-feature
Merged Branches finden
Welche Branches sind schon in main gemerged?
git branch --merged main
Alle löschen:
git branch --merged main | grep -v "main" | xargs git branch -d
Nova’s Script: Sie hat ein Alias dafür:
git config --global alias.cleanup '!git branch --merged main | grep -v "main" | xargs git branch -d'
Jetzt kann sie einfach git cleanup machen. Smart!
📦 Stashing – Code kurz parken
Wann brauche ich Stash?
Situation: Ich arbeite an Feature A. Cassian ruft an: „Tom, Bug in Production! Kannst du schnell fixen?“
Problem: Ich hab unfertige Änderungen, will aber auf main wechseln.
Lösung: Stash
# Änderungen temporär speichern git stash # Auf main wechseln git checkout main # Hotfix machen... # Zurück zu meinem Branch git checkout feature/TOM-123 # Änderungen zurückholen git stash pop
Stash mit Message
Besser:
git stash push -m "WIP: User validation unfinished"
Liste aller Stashes:
git stash list
Output:
stash@{0}: On feature/TOM-123: WIP: User validation unfinished
stash@{1}: On feature/TOM-122: Testing DB migration
Bestimmten Stash anwenden:
git stash apply stash@{1}
Stash löschen:
git stash drop stash@{0}
🔧 Git-Config Tipps
Nützliche Aliases
Was ich in meiner .gitconfig hab:
[alias]
st = status
co = checkout
br = branch
ci = commit
lg = log --oneline --graph --decorate --all
undo = reset --soft HEAD~1
amend = commit --amend --no-edit
cleanup = !git branch --merged main | grep -v "main" | xargs git branch -d
Jetzt kann ich machen:
git st # statt git status git co main # statt git checkout main git lg # schöne Graph-Ansicht git undo # letzten Commit rückgängig git amend # letzten Commit erweitern
Globale Einstellungen
User-Info:
git config --global user.name "Tom Fischer" git config --global user.email "tom.fischer@javafleet.de"
Default Branch:
git config --global init.defaultBranch main
Editor:
git config --global core.editor "vim" # oder git config --global core.editor "code --wait" # VS Code
Pull Strategy:
git config --global pull.rebase true
💡 Praxis-Tipps aus echten Projekten
Was ich in 3 Monaten gelernt hab
1. Committe oft, pushe später
Früher: Warte bis Feature komplett fertig ist, dann ein riesiger Commit.
Jetzt: Viele kleine Commits lokal. Vor dem Push: Interactive Rebase, um sie zu squashen.
Warum besser:
- Bei Fehlern nur letzten Commit verwerfen
- Einfacher zu debuggen
- Kann Teile verwerfen ohne alles zu verlieren
2. Pull Requests früh erstellen
Bei Java Fleet: Ich erstelle PR, sobald erste Tests grün sind. Mit Label: WIP (Work in Progress).
Warum?
- Team sieht, woran ich arbeite
- Frühe Feedback-Möglichkeit
- Keine Überraschungen beim finalen Review
Cassian sagt: „Lieber 5 kleine PRs als 1 riesiger mit 50 Files changed.“
3. Commit vor Feierabend
Die Regel: Auch wenn’s nicht perfekt ist: Commit + Push vor Feierabend.
Warum?
- Laptop könnte kaputt gehen
- Andere können sehen, wo ich stehe
- Morgen weiß ich noch, wo ich war
Mein Workflow:
git add . git commit -m "WIP: User validation - tests still failing" git push
Am nächsten Tag:
git commit --amend # Commit-Message verbessern git push --force-with-lease # Sicher force-pushen
4. Force-Push sicher machen
Das hab ich gelernt:
git push --force-with-lease
Statt:
git push --force
Was ist der Unterschied?
--forceüberschreibt ALLES auf remote--force-with-leaseprüft erst, ob remote sich geändert hat
Szenario: Nova hat auf deinen Branch committed. Du willst force-pushen.
--force: Novas Commit ist weg 😱--force-with-lease: Error! Git sagt „Remote hat neue Commits, erst pullen“
5. .gitignore richtig nutzen
Was ich ignoriere:
# IDE .idea/ *.iml .vscode/ # Build target/ build/ out/ # OS .DS_Store Thumbs.db # Logs *.log # Env Files .env application-local.properties
Tipp: gitignore.io generiert .gitignore für dein Stack.
❓ FAQ
Q: Wann soll ich rebase und wann merge?
A:
- Feature-Branch updaten:
git pull --rebase origin main(saubere History) - Feature in main integrieren: Merge via Pull Request (Nachvollziehbarkeit)
- Golden Rule: Rebase nur lokale Branches. Nie rebased Branches die andere nutzen!
Q: Wie viele Commits sollte ein PR haben?
A: Bei Java Fleet: 1-5 Commits. Jeder Commit sollte eine logische Einheit sein. Wenn du 20 „fix typo“ Commits hast, nutze Interactive Rebase zum Squashen. Cassian reviewt lieber 3 saubere Commits als 20 chaotische.
Q: Ich hab versehentlich git add . gemacht und zu viel staged. Wie rückgängig?
A:
# Alles unstagen git reset # Einzelne Datei unstagen git reset HEAD dateiname.java
Dann stage nur das, was du wirklich committen willst.
Q: Wie sehe ich, was in einem Commit geändert wurde?
A:
# Letzter Commit git show # Bestimmter Commit git show abc1234 # Nur Dateiliste git show --name-only abc1234
In IntelliJ: Alt+9 (Git) → Rechtsklick auf Commit → Show Diff
Q: Was macht git fetch vs git pull?
A:
git fetch: Holt neue Commits von remote, ändert aber nichts an deinen lokalen Branchesgit pull: Machtfetch+merge(oderrebasewenn konfiguriert)
Mein Workflow: git fetch mehrmals am Tag, um zu sehen was andere machen. git pull nur wenn ich wirklich mergen will.
Q: Kann ich einen Commit aus einem anderen Branch holen ohne den ganzen Branch zu mergen?
A: Ja! git cherry-pick abc1234. Das holt nur diesen einen Commit. Super für Hotfixes, die du in mehrere Branches brauchst.
Q: Wie finde ich raus, welcher Commit einen Bug eingeführt hat?
A: git bisect ist dafür da, aber honestly – das hab ich noch nie gebraucht. Meist reicht git log + git blame. Aber wenn’s komplex wird, frag einen Senior. Bisect ist powerful aber tricky.
Q: Bernd hat gesagt „merge fast-forward only“. Was heißt das? 🤔
A: Real talk: Fast-Forward bedeutet Git schiebt einfach den Branch-Pointer vor, ohne Merge-Commit zu erstellen. Das geht nur, wenn dein Branch linear auf main aufbaut (kein Konflikt).
Command:
git merge --ff-only feature-branch
Wenn es nicht funktioniert: Erst git rebase main, dann nochmal mergen.
Warum Bernd das will: Sauberere Git-History. Keine unnötigen Merge-Commits. Typisch Bernd – minimalistisch aber correct. Aber lowkey ist das advanced stuff. Für Junior-Devs ist normales Mergen erstmal okay.
🎓 Weiterführende Ressourcen
Für Vertiefung:
- Pro Git Book – Kostenlos, umfassendes Handbuch
- Learn Git Branching – Interaktive Visualisierung
- Oh Shit, Git!?! – Für „oh shit“ Momente 😅
Meine Empfehlung: Lies Pro Git Kapitel 2 (Git Basics) und Kapitel 3 (Git Branching). Das sind maybe 30 Seiten, aber du verstehst danach 90% von dem, was du brauchst.
Unsere nächsten Themen:
- Docker verstehen – Erklärt von jemandem, der es gerade selbst lernt (Next Week)
- Testing-Strategien – Unit, Integration, End-to-End (Coming Soon)
💬 Real Talk: Learning Friday
Java Fleet Meeting-Raum, Freitag 14:30 Uhr. Learning Friday Session. Thema: „Git Horror Stories“
Franz-Martin: „So, wer hat diese Woche etwas Interessantes mit Git erlebt?“
Tom (hebt Hand): „Ich hab… versehentlich… 50 Commits… gesquashed… in einen einzigen.“
Nova (lacht): „How?!“
Tom: „Interactive Rebase. Ich wollte nur die letzten 5 zusammenfassen, hab aber HEAD~50 statt HEAD~5 getippt.“
Cassian: „Und? Konntest du’s retten?“
Tom: „Reflog. Hab den alten HEAD gefunden und zurückgesetzt. Aber 10 Minuten Panik pur.“
Elyndra: „Das ist der Grund, warum wir git reflog lernen. Git vergisst nichts.“
Kat: „Ich hab letzte Woche git push --force gemacht und Kofis Branch überschrieben.“
Kofi (grinst): „Yeah, das war fun. Good thing ich hatte alles lokal.“
Franz-Martin: „Force-Push ist wie sudo rm. Macht es nur, wenn ihr WIRKLICH wisst was ihr tut.“
Nova: „Real talk though – ich mach noch immer Merge-Conflicts manuell falsch. Gibt’s da einen Trick?“
Cassian: „Nutzt IntelliJ’s Merge-Tool. Zeigt dir drei Spalten: Your Changes | Base | Their Changes. Viel übersichtlicher als roher Text.“
Tom: „Oh! Das wusste ich gar nicht. Wo finde ich das?“
Cassian: „Bei Conflict: Rechtsklick auf Datei → Git → Resolve Conflicts. Probier’s mal aus.“
Elyndra: „Eine Sache noch: Macht kleine Commits. Wenn ein Commit 500 Lines ändert, ist Merge fast unmöglich.“
Franz-Martin: „Genau. Ich sage immer: Ein Commit sollte eine Story erzählen. Nicht ein ganzes Buch.“
Tom: „Noted! Also zusammengefasst: Kleine Commits, Reflog kennen, Force-Push vermeiden, IntelliJ Merge-Tool nutzen?“
Nova: „Und immer pullen vor dem pushen!“
Alle (im Chor): „IMMER pullen vor dem pushen!“ ☕
📌 Zusammenfassung
Was ich in 3 Monaten gelernt hab:
- Feature-Branches nutzen – Nie direkt auf main arbeiten
- Commit-Messages wichtig – „fix“ ist keine Message
- Pull before Push – Merge-Conflicts früh erkennen
- Rebase für saubere History – Aber nicht auf shared Branches
- Reflog ist dein Freund – Git vergisst nie
- Force-Push = Danger – Nur mit
--force-with-lease - Stash für Unterbrechungen – Code-Parking deluxe
Bottom Line: Git ist mächtig. Und manchmal gruselig. Aber mit den richtigen Commands und etwas Übung wird’s zur Routine. Ich mach noch immer Fehler. Aber ich kann sie jetzt fixen.
Die wichtigste Lektion von Cassian: „Es ist okay, Fehler zu machen. Solange du lernst, wie du sie behebst.“
Fragen? Andere Git-Horror-Stories? Bessere Workflows?
Schreib mir! Ich lerne selbst noch jeden Tag dazu. 🚀
Tom Fischer
Werkstudent bei Java Fleet Systems Consulting
„Still learning to git gud since September 2024“
📝 Letzte Aktualisierung: Oktober 2024

