Git Voorbij de Basis: Workflows Die Je Elke Week Uren Besparen
Interactive rebase, cherry-pick, bisect, worktrees, reflog-redding en de branching-strategieën die echt werken. Git-commando's die ik dagelijks gebruik en die de meeste developers niet kennen.
De meeste developers leren vijf Git-commando's en stoppen daar. add, commit, push, pull, merge. Misschien checkout en branch als ze zich avontuurlijk voelen. Dat brengt je door het eerste jaar. Dan heeft je branch 47 commits met berichten als "fix" en "wip" en "please work," reset je per ongeluk iets wat je niet had moeten resetten, en breng je 40 minuten door op Stack Overflow om een foutgelopen merge ongedaan te maken.
Ik gebruik Git al jaren. Niet terloops — intensief. Meerdere branches, meerdere repo's, meerdere medewerkers, de hele dag, elke dag. Wat volgt zijn de commando's en workflows die ik daadwerkelijk gebruik. Niet degene die er goed uitzien in een tutorial. Degene die me elke week echt tijd besparen.
Interactive Rebase: Ruim Je Rommel Op Voordat Iemand Het Ziet#
Je branch heeft twaalf commits. De helft daarvan is "fix typo." Eentje zegt "undo previous commit." Een andere zegt "actually fix it this time." Je staat op het punt een PR te openen. Niemand hoeft die geschiedenis te zien.
Interactive rebase is hoe je de geschiedenis op je branch herschrijft voordat je hem deelt. Je kunt er commits mee samenvoegen, berichten herformuleren, volgorde wijzigen of ze helemaal verwijderen.
Het Basiscommando#
git rebase -i HEAD~5Dit opent een editor met je laatste 5 commits, oudste eerst:
pick a1b2c3d Add user authentication endpoint
pick d4e5f6g Fix typo in auth middleware
pick h7i8j9k Add rate limiting
pick l0m1n2o Fix rate limit bug
pick p3q4r5s Update auth testsElke regel begint met een commando. Verander pick naar een van deze:
squash(ofs) — Voeg deze commit samen met de bovenstaande, combineer de berichtenfixup(off) — Hetzelfde als squash, maar gooi het bericht van deze commit wegreword(ofr) — Behoud de commit maar wijzig het berichtdrop(ofd) — Verwijder deze commit helemaaledit(ofe) — Pauzeer de rebase bij deze commit zodat je hem kunt aanpassen
Een Echte Opschoonsessie#
Hier is wat ik in de praktijk doe. Die rommelige geschiedenis hierboven wordt:
pick a1b2c3d Add user authentication endpoint
fixup d4e5f6g Fix typo in auth middleware
pick h7i8j9k Add rate limiting
fixup l0m1n2o Fix rate limit bug
pick p3q4r5s Update auth testsOpslaan en sluiten. Nu heb je drie schone commits in plaats van vijf. De typofix wordt samengevoegd met de auth-commit. De rate-limit-bugfix wordt samengevoegd met de rate-limit-commit. Je PR-reviewer ziet een schone, logische opbouw.
Commits Herordenen#
Je kunt de regels letterlijk herschikken. Als de test-commit vóór de rate-limiting-commit moet komen, verplaats je gewoon de regel:
pick a1b2c3d Add user authentication endpoint
pick p3q4r5s Update auth tests
pick h7i8j9k Add rate limitingGit herhaalt je commits in deze nieuwe volgorde. Als er conflicten zijn, pauzeert Git en laat je ze oplossen.
De Autosquash-snelkoppeling#
Als je weet dat een commit een fix is voor een eerdere, markeer hem dan al bij het committen:
git commit --fixup=a1b2c3dDit maakt een commit aan met het bericht fixup! Add user authentication endpoint. Als je dan rebased:
git rebase -i --autosquash HEAD~5Git herordent automatisch de fixup-commits recht onder hun doelen en markeert ze als fixup. Je hoeft alleen op te slaan en te sluiten. Geen handmatig bewerken.
Ik gebruik dit voortdurend. Het is de snelste manier om aan een branch te itereren terwijl je de uiteindelijke geschiedenis schoon houdt.
De Gouden Regel#
Rebase nooit commits die naar een gedeelde branch zijn gepusht. Als andere mensen werk op die commits hebben gebaseerd, veroorzaakt het herschrijven van de geschiedenis echte problemen. Rebase je eigen feature-branches vóór het mergen. Rebase nooit main.
Als je je feature-branch al hebt gepusht en moet rebasen:
git push --force-with-leaseDe --force-with-lease flag is veiliger dan --force. Het weigert te pushen als iemand anders naar dezelfde branch heeft gepusht sinds je laatste fetch. Het voorkomt niet alle problemen, maar vangt het meest voorkomende op.
Cherry-Pick: Chirurgische Commit-overdrachten#
Cherry-pick pakt een specifieke commit van de ene branch en past hem toe op een andere. Geen merge. Geen rebase. Gewoon één commit, schoon toegepast.
Wanneer Ik Dit Echt Gebruik#
Het meest voorkomende scenario: ik heb een bug opgelost op mijn feature-branch, maar de fix moet ook nu naar main of een release-branch. Ik wil niet mijn hele feature-branch mergen. Ik wil alleen die ene fix.
# Find the commit hash of the fix
git log --oneline feature/user-auth
# a1b2c3d Fix null pointer in session validation
# Switch to main and cherry-pick it
git checkout main
git cherry-pick a1b2c3dKlaar. De fix staat op main als een nieuwe commit met dezelfde wijzigingen.
Cherry-Pick Zonder Te Committen#
Soms wil je de wijzigingen toepassen maar nog niet committen. Misschien wil je meerdere cherry-picks combineren in één commit, of de wijzigingen iets aanpassen:
git cherry-pick --no-commit a1b2c3dDe wijzigingen zijn gestaged maar niet gecommit. Je kunt ze aanpassen, meer wijzigingen toevoegen en committen wanneer je klaar bent.
Range Cherry-Pick#
Meerdere opeenvolgende commits nodig? Gebruik range-syntax:
git cherry-pick a1b2c3d..f6g7h8iDit cherry-pickt alles na a1b2c3d tot en met f6g7h8i. Let op dat a1b2c3d zelf is uitgesloten. Als je hem ook wilt meenemen:
git cherry-pick a1b2c3d^..f6g7h8iConflicten Afhandelen#
Cherry-pick-conflicten werken zoals merge-conflicten. Als er een optreedt:
# Git will tell you there's a conflict
# Fix the conflicting files, then:
git add .
git cherry-pick --continueOf als je je bedenkt:
git cherry-pick --abortEén ding om op te letten: cherry-picked commits krijgen nieuwe commit-hashes. Als je later de originele branch merged, is Git meestal slim genoeg om de duplicatie af te handelen. Maar als je agressief cherry-pickt tussen branches die uiteindelijk worden gemerged, kun je onverwachte conflicten zien. Gebruik het chirurgisch, niet als merge-strategie.
Git Bisect: Binair Zoeken naar Bugs#
Er is iets stuk. Je weet dat het twee weken geleden nog werkte. Er zijn sindsdien 200 commits geweest. Welke heeft het kapotgemaakt?
Je zou elke commit handmatig kunnen controleren. Of je kunt git bisect gebruiken, dat een binaire zoekopdracht uitvoert om de exacte brekende commit te vinden in log2(n) stappen. Voor 200 commits zijn dat zo'n 7-8 controles in plaats van 200.
De Handmatige Manier#
# Start bisecting
git bisect start
# Mark the current commit as bad (the bug exists here)
git bisect bad
# Mark a known good commit (the bug didn't exist here)
git bisect good v2.1.0Git checkt een commit uit halverwege goed en slecht. Test hem. Dan:
# If the bug exists at this commit:
git bisect bad
# If the bug doesn't exist at this commit:
git bisect goodGit halveert het bereik elke keer. Na 7-8 stappen vertelt het je:
a1b2c3d4e5f6g7h is the first bad commit
commit a1b2c3d4e5f6g7h
Author: Some Developer <dev@example.com>
Date: Tue Feb 18 14:23:01 2026 +0300
Refactor session handling to use async middlewareNu weet je precies welke commit de bug introduceerde. Als je klaar bent:
git bisect resetDit brengt je terug naar waar je begon.
De Geautomatiseerde Manier (Dit Is de Echte Kracht)#
Als je een test hebt die de bug kan detecteren, kun je het hele proces automatiseren:
git bisect start
git bisect bad HEAD
git bisect good v2.1.0
git bisect run npm test -- --grep "session validation"Git checkt automatisch commits uit, voert de test uit en markeert ze als goed of slecht op basis van de exit-code. Nul betekent goed, niet-nul betekent slecht. Loop weg, kom terug, en het vertelt je de exacte commit.
Je kunt elk script gebruiken:
git bisect run ./test-regression.shWaarbij test-regression.sh is:
#!/bin/bash
npm run build 2>/dev/null || exit 125 # 125 means "skip this commit"
npm test -- --grep "session" || exit 1 # 1 means "bad"
exit 0 # 0 means "good"Exit-code 125 is speciaal — het vertelt bisect om die commit over te slaan (handig als een commit niet compileert). Dit is een van die features die niche lijken totdat je ze nodig hebt, en dan besparen ze je een hele middag.
Een Echte Bisect-sessie#
Zo ziet het er in de praktijk uit:
$ git bisect start
$ git bisect bad HEAD
$ git bisect good abc1234
Bisecting: 97 revisions left to test after this (roughly 7 steps)
[def5678...] Commit message here
$ npm test -- --grep "login flow"
# Tests fail
$ git bisect bad
Bisecting: 48 revisions left to test after this (roughly 6 steps)
[ghi9012...] Another commit message
$ npm test -- --grep "login flow"
# Tests pass
$ git bisect good
Bisecting: 24 revisions left to test after this (roughly 5 steps)
...
# After ~7 iterations:
abc1234def5678ghi is the first bad commitZeven stappen om een naald in een hooiberg van 200 commits te vinden.
Git Worktrees: Meerdere Branches, Nul Stashing#
Dit is de meest onderbenutte Git-feature. Ik ben ervan overtuigd dat de meeste developers niet weten dat het bestaat.
Het probleem: je zit diep in een feature-branch. Overal zijn bestanden gewijzigd. Dan zegt iemand "kun je even naar deze productiebug kijken?" Je hebt drie opties:
- Alles stashen, van branch wisselen, fixen, terugwisselen, stash poppen. Hopen dat er niets misgaat.
- Je halfaf werk committen met een "wip"-bericht. Lelijk maar functioneel.
- De repo opnieuw clonen in een andere directory.
Of optie 4: worktrees.
Wat een Worktree Is#
Een worktree is een tweede (of derde, of vierde) werkdirectory gekoppeld aan dezelfde repository. Elke worktree heeft zijn eigen uitgecheckte branch, zijn eigen werkbestanden, zijn eigen index. Maar ze delen dezelfde .git-data, dus je dupliceert niet de hele repo.
Een Worktree Toevoegen#
# You're on feature/user-auth, deep in work
# Need to fix a bug on main:
git worktree add ../hotfix-session mainDit maakt een nieuwe directory ../hotfix-session aan met main uitgecheckt. Je huidige directory blijft precies zoals hij was. Niets gestasht, niets gecommit, niets verstoord.
cd ../hotfix-session
# Fix the bug
git add .
git commit -m "Fix null pointer in session validation"
git push origin main
cd ../my-project
# Continue working on your feature as if nothing happenedEen Nieuwe Branch in een Worktree Aanmaken#
git worktree add ../hotfix-nav -b hotfix/nav-crash mainDit maakt de worktree aan EN maakt een nieuwe branch hotfix/nav-crash op basis van main.
Worktrees Beheren#
# List all worktrees
git worktree list
# /home/dev/my-project abc1234 [feature/user-auth]
# /home/dev/hotfix-session def5678 [main]
# Remove a worktree when done
git worktree remove ../hotfix-session
# If the directory was already deleted:
git worktree pruneWaarom Dit Beter Is Dan Stashen#
Stashen is prima voor snelle contextswitch. Maar worktrees zijn beter voor alles wat langer dan vijf minuten duurt:
- Je IDE blijft open op je feature-branch. Geen herindexering, geen verloren scrollpositie.
- Je kunt in beide directories tegelijk tests draaien.
- Geen risico op stash-conflicten of vergeten wat je hebt gestasht.
- Je kunt een lang-draaiende dev-server in de ene worktree draaien en een schone build in een andere.
Ik houd doorgaans twee of drie worktrees actief: mijn belangrijkste feature-branch, een main-worktree voor snelle controles, en soms een review-worktree waar ik iemands PR bekijk.
De Enige Kanttekening#
Je kunt niet dezelfde branch in twee worktrees uitgecheckt hebben. Dat is by design — het voorkomt dat je tegenstrijdige wijzigingen maakt aan dezelfde branch op twee plaatsen. Als je het probeert, weigert Git.
Reflog: De Ongedaan-knop voor Alles#
Je hebt een hard reset gedaan en commits verloren. Je hebt een branch verwijderd. Je hebt gerebaset en het ging verschrikkelijk mis. Je denkt dat je werk weg is.
Dat is het niet. Git verwijdert bijna nooit echt iets. De reflog is je vangnet.
Wat de Reflog Is#
Elke keer dat HEAD beweegt — elke commit, checkout, rebase, reset, merge — registreert Git het in de reflog. Het is een logboek van overal waar je HEAD is geweest, op volgorde.
git reflogUitvoer:
a1b2c3d (HEAD -> main) HEAD@{0}: reset: moving to HEAD~3
f4e5d6c HEAD@{1}: commit: Add payment processing
b7a8c9d HEAD@{2}: commit: Update user dashboard
e0f1g2h HEAD@{3}: commit: Fix auth token refresh
i3j4k5l HEAD@{4}: checkout: moving from feature/payments to mainElke vermelding heeft een index (HEAD@{0}, HEAD@{1}, etc.) en een beschrijving van wat er gebeurde.
Herstellen Na een Hard Reset#
Je hebt per ongeluk git reset --hard HEAD~3 uitgevoerd en drie commits verloren. Ze staan gewoon in de reflog:
# See what you lost
git reflog
# The commit before the reset is HEAD@{1}
git reset --hard f4e5d6cAlle drie de commits zijn terug. Crisis afgewend.
Een Verwijderde Branch Herstellen#
Je hebt een branch verwijderd met ongmerged werk:
git branch -D feature/experimental
# Oh no, that had two weeks of workDe commits bestaan nog. Zoek ze op:
git reflog | grep "feature/experimental"
# Or just look through the reflog for the last commit on that branch
# Found it. Recreate the branch at that commit:
git branch feature/experimental a1b2c3dDe branch is terug, met al zijn commits.
Herstellen Na een Foutgelopen Rebase#
Je hebt gerebaset en alles ging fout. Overal conflicten, verkeerde commits, chaos:
# The reflog shows where you were before the rebase
git reflog
# a1b2c3d HEAD@{0}: rebase (finish): ...
# ...
# f4e5d6c HEAD@{5}: rebase (start): checkout main
# b7a8c9d HEAD@{6}: commit: Your last good commit
# Go back to before the rebase
git reset --hard b7a8c9dJe bent terug op precies waar je was voordat de rebase begon. Alsof het nooit is gebeurd.
Het Vangnet van 30 Dagen#
Standaard bewaart Git reflog-vermeldingen 30 dagen (90 dagen voor bereikbare commits). Daarna kunnen ze worden opgeruimd door de garbage collector. Je hebt dus een maand om te beseffen dat je een fout hebt gemaakt. In de praktijk is dit meer dan genoeg.
Je kunt de vervaldatum controleren:
git config gc.reflogExpire
# default: 90.days.ago (for reachable)
git config gc.reflogExpireUnreachable
# default: 30.days.ago (for unreachable)Als je paranoïde bent, verhoog het:
git config --global gc.reflogExpireUnreachable "180.days.ago"Een Persoonlijke Regel#
Voordat ik een destructieve operatie uitvoer — hard reset, force push, branch verwijderen — draai ik altijd eerst git log --oneline -10. Ik onthoud mentaal de huidige HEAD. Het kost twee seconden en heeft me meer dan eens gered van een paniekaanval die niet nodig was.
Stash Goed: Het Is Niet Alleen git stash#
De meeste mensen gebruiken stash zo:
git stash
# do something
git stash popDat werkt, maar het is het equivalent van alles in een doos gooien met het label "spullen." Als je drie stashes hebt, heb je geen idee welke wat is.
Geef Je Stashes een Naam#
git stash push -m "WIP: user auth form validation"Nu als je stashes oplijst:
git stash list
# stash@{0}: On feature/auth: WIP: user auth form validation
# stash@{1}: On main: Quick fix attempt for nav bug
# stash@{2}: On feature/payments: Experiment with Stripe webhooksJe kunt precies zien wat elke stash bevat.
Inclusief Untracked Bestanden#
Standaard stasht git stash alleen getrackte bestanden. Nieuwe bestanden die je nog niet hebt toegevoegd worden achtergelaten:
# Stash everything, including new files
git stash push --include-untracked -m "WIP: new auth components"
# Or even include ignored files (rarely needed)
git stash push --all -m "Full workspace snapshot"Ik gebruik --include-untracked bijna altijd. Nieuwe bestanden achterlaten als je van branch wisselt veroorzaakt verwarring.
Gedeeltelijk Stashen#
Dit is degene die de meeste mensen niet kennen. Je kunt specifieke bestanden stashen:
# Stash only specific files
git stash push -m "Just the auth changes" src/auth/ src/middleware.tsOf gebruik patch-modus om specifieke stukken binnen bestanden te stashen:
git stash push --patch -m "Partial: only the validation logic"Git gaat interactief door elke wijziging en vraagt of je het wilt stashen. y voor ja, n voor nee, s om het stuk op te splitsen in kleinere delen.
Apply vs Pop#
# Pop: apply and remove from stash list
git stash pop stash@{2}
# Apply: apply but keep in stash list
git stash apply stash@{2}Ik gebruik apply als ik niet zeker weet of de stash schoon kan worden toegepast. Als er een conflict is, blijft de stash bewaard. Met pop, als er een conflict is, blijft de stash sowieso in de lijst (veel mensen weten dit niet), maar ik geef de voorkeur aan de expliciete intentie van apply.
Stash-inhoud Bekijken#
# See what files changed in a stash
git stash show stash@{0}
# See the full diff
git stash show -p stash@{0}Een Branch Maken van een Stash#
Als je stash is uitgegroeid tot iets substantieels:
git stash branch feature/auth-validation stash@{0}Dit maakt een nieuwe branch aan vanaf de commit waar je oorspronkelijk stashte, past de stash toe en verwijdert hem. Netjes.
Branching-strategieën: Welke Werkt Echt#
Er zijn drie gangbare branching-strategieën. Elk heeft een context waarin het uitblinkt en contexten waarin het problemen veroorzaakt.
Gitflow#
De klassieker. main, develop, feature/*, release/*, hotfix/*. Bedacht door Vincent Driessen in 2010.
# Feature branch
git checkout -b feature/user-auth develop
# ... work ...
git checkout develop
git merge --no-ff feature/user-auth
# Release branch
git checkout -b release/2.1.0 develop
# ... final fixes ...
git checkout main
git merge --no-ff release/2.1.0
git tag -a v2.1.0 -m "Release 2.1.0"
git checkout develop
git merge --no-ff release/2.1.0
# Hotfix
git checkout -b hotfix/session-fix main
# ... fix ...
git checkout main
git merge --no-ff hotfix/session-fix
git checkout develop
git merge --no-ff hotfix/session-fixWanneer het werkt: Mobiele apps, desktopsoftware, alles met genoemde versiereleases en meerdere versies die tegelijk worden ondersteund. Als je v2.1 en v3.0 uitbrengt en beide moet patchen, kan Gitflow dat aan.
Wanneer het niet werkt: Webapplicaties met continuous deployment. Als je vijf keer per dag naar productie deployt, is de ceremonie van release-branches en develop-branches puur overhead. De meeste webteams die Gitflow adopteren, eindigen met een develop-branch die permanent kapot is en release-branches die niemand begrijpt.
GitHub Flow#
Simpel. Je hebt main. Je maakt feature-branches. Je opent PR's. Je merged naar main. Je deployt main.
git checkout -b feature/user-auth main
# ... work ...
git push origin feature/user-auth
# Open PR, get reviewed, merge
# main is always deployableWanneer het werkt: Kleine tot middelgrote teams die webapps bouwen. Continuous deployment. Als main altijd gedeployd is, is dit alles wat je nodig hebt. Het is wat deze site gebruikt.
Wanneer het niet werkt: Als je meerdere release-versies moet onderhouden, of als je een lang QA-traject hebt vóór deployment. GitHub Flow gaat ervan uit dat main snel naar productie gaat.
Trunk-Based Development#
Iedereen commit rechtstreeks naar main (de "trunk") of via zeer kortlevende branches (minder dan een dag). Geen langlopende feature-branches.
# Short-lived branch (merged same day)
git checkout -b fix/auth-token main
# ... small, focused change ...
git push origin fix/auth-token
# PR reviewed and merged within hours, not daysWanneer het werkt: High-performing teams met goede CI/CD, uitgebreide testsuites en feature flags. Google, Meta en de meeste grote techbedrijven gebruiken trunk-based development. Het dwingt kleine, incrementele wijzigingen af en elimineert merge-hel.
Wanneer het niet werkt: Teams zonder goede testdekking of CI. Als mergen naar trunk betekent dat je ongeteste code deployt, breek je voortdurend productie. Je hebt ook feature flags nodig voor alles dat langer dan een dag duurt om te bouwen:
# Feature flag in code
if (featureFlags.isEnabled('new-checkout-flow')) {
renderNewCheckout();
} else {
renderLegacyCheckout();
}Mijn Aanbeveling#
Voor de meeste webdevelopment-teams: begin met GitHub Flow. Het is simpel, het werkt, en het vereist geen tooling buiten wat GitHub/GitLab al biedt.
Als je team groeit voorbij 15-20 engineers en je meerdere keren per dag deployt, kijk dan naar trunk-based development met feature flags. De investering in feature flag-infrastructuur verdient zichzelf terug door minder merge-conflicten en snellere iteratie.
Als je versioned software uitbrengt (mobiele apps, CLI-tools, libraries): Gitflow of een vereenvoudigde versie ervan. Die release-branches heb je dan echt nodig.
Kies geen strategie omdat een blogpost zegt dat het de beste is. Kies degene die past bij hoe je daadwerkelijk levert.
Git Hooks: Automatiseer Wat Je Steeds Vergeet#
Git hooks zijn scripts die automatisch draaien op specifieke momenten in de Git-workflow. Ze zijn lokaal op je machine (niet naar de remote gepusht), wat betekent dat je een manier nodig hebt om ze met je team te delen.
De Hooks Die Er Echt Toe Doen#
pre-commit — Draait vóór elke commit. Gebruik het voor linting en formatting:
#!/bin/bash
# .git/hooks/pre-commit
# Run ESLint on staged files only
STAGED_FILES=$(git diff --cached --name-only --diff-filter=ACM | grep -E '\.(js|ts|tsx)$')
if [ -n "$STAGED_FILES" ]; then
echo "Running ESLint on staged files..."
npx eslint $STAGED_FILES --quiet
if [ $? -ne 0 ]; then
echo "ESLint failed. Fix errors before committing."
exit 1
fi
fi
# Run Prettier on staged files
if [ -n "$STAGED_FILES" ]; then
echo "Running Prettier..."
npx prettier --check $STAGED_FILES
if [ $? -ne 0 ]; then
echo "Prettier check failed. Run 'npx prettier --write' first."
exit 1
fi
ficommit-msg — Valideert het format van het commit-bericht. Perfect voor het afdwingen van conventional commits:
#!/bin/bash
# .git/hooks/commit-msg
COMMIT_MSG=$(cat "$1")
PATTERN="^(feat|fix|docs|style|refactor|test|chore|perf|ci|build|revert)(\(.+\))?: .{1,72}"
if ! echo "$COMMIT_MSG" | grep -qE "$PATTERN"; then
echo "Invalid commit message format."
echo "Expected: type(scope): description"
echo "Example: feat(auth): add session refresh endpoint"
echo ""
echo "Valid types: feat, fix, docs, style, refactor, test, chore, perf, ci, build, revert"
exit 1
fipre-push — Draait voor het pushen. Gebruik het voor tests:
#!/bin/bash
# .git/hooks/pre-push
echo "Running tests before push..."
npm test
if [ $? -ne 0 ]; then
echo "Tests failed. Push aborted."
exit 1
fiHusky vs Native Hooks#
Native hooks leven in .git/hooks/. Het probleem: de .git-directory wordt niet door Git getrackt, dus je kunt hooks niet via de repo delen. Iedereen moet ze handmatig opzetten.
Husky lost dit op. Het bewaart hook-configuraties in de repo en zet .git/hooks automatisch op bij npm install:
npx husky initDit maakt een .husky/-directory aan. Voeg hooks toe als bestanden:
# .husky/pre-commit
npx lint-stagedGecombineerd met lint-staged krijg je snelle, gerichte pre-commit-controles:
{
"lint-staged": {
"*.{js,ts,tsx}": ["eslint --fix", "prettier --write"],
"*.css": ["prettier --write"],
"*.json": ["prettier --write"]
}
}Dit draait ESLint en Prettier alleen op de bestanden die je daadwerkelijk commit. Niet de hele codebase. Snel.
Wanneer Hooks Overslaan#
Soms moet je committen zonder dat hooks draaien. Noodhotfixes, work-in-progress commits op je eigen branch:
git commit --no-verify -m "WIP: debugging production issue"Gebruik dit spaarzaam. Als je merkt dat je hooks regelmatig overslaat, zijn je hooks waarschijnlijk te traag of te streng.
Aliases Die Tijd Besparen#
Mijn .gitconfig is door de jaren heen geëvolueerd. Dit zijn de aliases die het hebben overleefd — degene die ik daadwerkelijk dagelijks gebruik, niet degene die ik toevoegde omdat ze er slim uitzagen.
Pretty Log#
De standaard git log is uitgebreid. Dit geeft je een schone, kleurrijke, graph-gebaseerde weergave:
git config --global alias.lg "log --oneline --graph --all --decorate"Gebruik:
git lg
# * a1b2c3d (HEAD -> main) Fix session validation
# | * d4e5f6g (feature/payments) Add Stripe integration
# | * h7i8j9k Update payment models
# |/
# * l0m1n2o Merge PR #42
# * p3q4r5s Add user dashboardIk draai dit 20 keer per dag. Het is de snelste manier om de staat van je repository te begrijpen.
Laatste Commit Ongedaan Maken#
Behoud de wijzigingen, maak alleen de commit ongedaan:
git config --global alias.undo "reset HEAD~1 --mixed"Gebruik:
git undo
# Commit is gone, but all changes are still in your working directoryIk gebruik dit als ik te vroeg commit, een bestand vergeet, of de wijzigingen wil herstructureren.
Alles Unstagen#
git config --global alias.unstage "reset HEAD --"Gebruik:
git unstage src/auth/session.ts
# File is unstaged but changes are preservedAlle Aliases Oplijsten#
Omdat je vergeet wat je hebt ingesteld:
git config --global alias.aliases "config --get-regexp ^alias\\."Meer Aliases Die Ik Gebruik#
# Show what you're about to commit
git config --global alias.staged "diff --staged"
# Short status
git config --global alias.st "status -sb"
# Amend without changing the message
git config --global alias.amend "commit --amend --no-edit"
# Show the last commit
git config --global alias.last "log -1 HEAD --stat"
# Pull with rebase instead of merge
git config --global alias.up "pull --rebase --autostash"
# Delete branches that have been merged to main
git config --global alias.cleanup "!git branch --merged main | grep -v '^[ *]*main$' | xargs git branch -d"De up-alias is bijzonder goed. pull --rebase houdt je geschiedenis lineair in plaats van merge-commits te maken voor elke pull. --autostash stasht en herstelt automatisch je wijzigingen als je dirty files hebt. Het is wat pull standaard had moeten zijn.
De cleanup-alias verwijdert lokale branches die naar main zijn gemerged. Na een tijdje verzamel je tientallen verouderde branches. Draai dit wekelijks.
De Commando's Die Ik Dagelijks Gebruik#
Dit zijn geen aliases of geavanceerde features. Het zijn gewoon commando's die ik voortdurend gebruik en die veel developers niet lijken te kennen.
Het Ultieme Log-commando#
git log --oneline --graph --allDit toont elke branch, elke merge, de hele topologie van je repo in een compacte weergave. Het is het eerste wat ik draai als ik wijzigingen pull. Het beantwoordt "wat gebeurt er nu in deze repo?"
Diff van Gestage Wijzigingen#
git diff --stagedDit toont wat er op het punt staat gecommit te worden. Niet wat er in je werkdirectory is gewijzigd — wat er daadwerkelijk gestaged is. Ik draai dit altijd voor het committen. Altijd. Het vangt onbedoelde toevoegingen, debug-statements, console.logs die er niet horen te zijn.
# See unstaged changes
git diff
# See staged changes
git diff --staged
# See both
git diff HEADEen Specifieke Commit Bekijken#
git show a1b2c3dToont de volledige diff van een enkele commit. Handig bij het reviewen van de geschiedenis, om te begrijpen wat een commit daadwerkelijk veranderde.
# Show just the files that changed
git show --stat a1b2c3d
# Show a specific file at a specific commit
git show a1b2c3d:src/auth/session.tsDie laatste is ongelooflijk handig. Je kunt elk bestand op elk punt in de geschiedenis bekijken zonder die commit uit te checken.
Blame met Regelbereiken#
git blame -L 42,60 src/auth/session.tsToont wie als laatste regels 42-60 heeft aangepast. Nuttiger dan het hele bestand blamen, wat meestal overweldigend is.
# Show the commit message too, not just the hash
git blame -L 42,60 --show-name src/auth/session.ts
# Ignore whitespace changes (very useful)
git blame -w -L 42,60 src/auth/session.ts
# Show the commit before the blamed one (dig deeper)
git log --follow -p -- src/auth/session.tsDe -w flag is belangrijk. Zonder die flag schrijft blame regels toe aan degene die het bestand het laatst heeft herformateerd, en dat is zelden de persoon die je zoekt.
Een String Vinden Doorheen de Hele Geschiedenis#
# Find when a function was added or removed
git log -S "validateSession" --oneline
# Find when a regex pattern appeared
git log -G "session.*timeout" --oneline-S (de "pickaxe") vindt commits waar het aantal voorkomens van een string is veranderd. -G vindt commits waar de diff overeenkomt met een regex. Beide zijn krachtig voor archeologie — uitzoeken wanneer iets werd geïntroduceerd of verwijderd.
Tonen Wat Er Veranderde Tussen Twee Punten#
# What changed between two branches
git diff main..feature/auth
# What changed on this branch since it diverged from main
git diff main...feature/auth
# List just the changed files
git diff main...feature/auth --name-only
# Stat view (files + insertions/deletions)
git diff main...feature/auth --statTwee puntjes versus drie puntjes maakt uit. Twee puntjes toont het verschil tussen de tips van beide branches. Drie puntjes toont wat er aan de rechterkant veranderde sinds het afsplitste van de linkerkant. Drie puntjes is meestal wat je wilt bij het reviewen van een feature-branch.
Untracked Bestanden Opruimen#
# See what would be deleted (dry run)
git clean -n
# Delete untracked files
git clean -f
# Delete untracked files and directories
git clean -fd
# Delete untracked and ignored files (nuclear option)
git clean -fdxDraai altijd eerst met -n. git clean -fdx verwijdert je node_modules, .env, build-artefacten — alles wat niet door Git wordt getrackt. Handig voor een echt schone start, maar destructief.
Een Enkel Bestand Herstellen van een Andere Branch#
# Get the main branch version of a file without switching branches
git restore --source main -- src/config/database.tsOf van een specifieke commit:
git restore --source a1b2c3d -- src/config/database.tsDit is schoner dan de oude git checkout main -- path/to/file-syntax, en het raakt HEAD niet aan.
Alles Samenbrengen: Een Echte Workflow#
Zo ziet een typische dag eruit met deze tools:
# Morning: check what's happening
git lg
git fetch --all
# Start a feature
git checkout -b feature/session-refresh main
# Work, commit incrementally
git add -p # Stage specific hunks, not entire files
git commit -m "Add token refresh endpoint"
git commit -m "Add refresh token rotation"
git commit -m "Fix: handle expired refresh tokens"
git commit -m "Add integration tests"
# Interrupted: need to fix a production bug
git worktree add ../hotfix main
cd ../hotfix
# ... fix, commit, push, PR merged ...
cd ../my-project
git worktree remove ../hotfix
# Back to feature work
git commit -m "Fix edge case in token validation"
# Ready for PR: clean up history
git rebase -i main
# Squash the fix commits, reword for clarity
# Push and open PR
git push -u origin feature/session-refresh
# Something broke in staging? Find out which commit:
git bisect start
git bisect bad HEAD
git bisect good main
git bisect run npm test
# Oops, I hard-reset the wrong thing
git reflog
git reset --hard HEAD@{2}Elk van deze commando's kost seconden. Samen besparen ze uren. Geen hypothetische uren — echte uren, elke week, die ik anders zou besteden aan het ontwarren van Git-puinhopen, handmatig zoeken naar bugs, of werk verliezen door contextwisselingen.
Git is een tool dat diepgang beloont. De basis brengt je door de dag. Maar de commando's in dit artikel zijn wat het verschil maakt tussen "ik gebruik Git" en "Git maakt me echt sneller." Leer ze stap voor stap. Kies deze week één nieuwe techniek en gebruik hem totdat het automatisme is. Kies dan de volgende.
Je toekomstige zelf, starend naar een productiebug om 23:00, zal je dankbaar zijn dat je git bisect kent.