Git Workflow
Overview
This skill provides a disciplined, safe workflow for everyday Git: branching, crafting clean atomic commits, rewriting history with interactive rebase, resolving conflicts, and recovering from mistakes using the reflog. The guiding principle is safety first — never destroy work you cannot recover, always know your escape hatch before running a history-rewriting command.
Keywords: git, branch, commit, rebase, interactive rebase, squash, fixup, reword, cherry-pick, merge, conflict, conflict resolution, reflog, recover lost commits, undo, reset, revert, detached HEAD, force-push, stash, clean history, conventional commits, PR prep.
Golden rules
- Never rewrite history that others have already pulled (shared branches like
main/develop). Rewrite only your own unmerged feature branches.
- Before any
rebase, reset --hard, or force-push, note the current commit: git rev-parse HEAD or just trust the reflog — it remembers.
- Prefer
git push --force-with-lease over --force. It refuses to clobber commits you haven't seen.
- Commit early, commit often locally; clean up into atomic commits before sharing.
- If something looks lost, it almost certainly isn't — go to
git reflog (see references/reflog-recovery.md).
Workflow
1. Orient before acting
Always understand current state first:
git status # working tree + branch
git log --oneline -10 # recent history
git branch -vv # branches + tracking
2. Branch
- Update the base first:
git switch main && git pull --ff-only.
- Create the branch:
git switch -c feat/short-description.
- Naming:
<type>/<slug> e.g. feat/oauth-login, fix/null-deref, chore/bump-deps, docs/readme. See references/branch-naming.md.
3. Make atomic commits
4. Keep up to date with the base
Choose merge vs rebase intentionally (see decision framework below). For a private feature branch, rebasing keeps history linear:
git fetch origin
git rebase origin/main
5. Clean up history before opening a PR
Squash noise ("wip", "fix typo"), reword unclear messages, reorder for logical flow:
git rebase -i origin/main
Full guidance and the command cheat sheet: references/interactive-rebase.md. Validate the result before pushing: scripts/rebase-safety-check.sh.
6. Resolve conflicts methodically
When a rebase/merge stops on a conflict, follow the step-by-step protocol in references/conflict-resolution.md. Summary:
git status # see conflicted files
# edit files, remove <<<<<<< ======= >>>>>>> markers
git add <resolved-files>
git rebase --continue # or: git merge --continue
# abort anytime: git rebase --abort / git merge --abort
7. Share
git push -u origin feat/short-description # first push
git push --force-with-lease # after a rebase/amend
8. Recover when things go wrong
Nothing is lost until garbage collection runs (default ~30–90 days). See references/reflog-recovery.md and run scripts/git-recover.sh to surface candidate lost commits.
Decision Framework: Merge vs Rebase
| Situation |
Use |
Updating your private, unpushed feature branch with latest main |
git rebase origin/main (linear history) |
| Branch is shared / others have it checked out |
git merge origin/main (don't rewrite shared history) |
Combining a finished feature into main (team prefers linear) |
rebase then fast-forward / squash-merge |
| Combining a feature, preserving full context & merge point |
git merge --no-ff |
| You just want to grab one commit from another branch |
git cherry-pick <sha> |
Rule of thumb: rebase local, merge shared.
Interactive Rebase Quick Reference
In the git rebase -i todo list, set the action keyword on each line:
| Keyword |
Effect |
pick |
keep the commit as-is |
reword (r) |
keep changes, edit the message |
edit (e) |
stop to amend the commit (split, add files) |
squash (s) |
merge into previous commit, combine messages |
fixup (f) |
merge into previous commit, discard this message |
drop (d) |
remove the commit entirely |
| reorder |
move lines up/down to reorder commits |
Targeted fixup workflow (best for PR review fixes):
git commit --fixup=<sha> # creates "fixup! ..." commit
git rebase -i --autosquash origin/main # auto-positions & marks it fixup
Recovery Cheat Sheet
| Problem |
Fix |
| Bad last commit, want to redo message |
git commit --amend |
| Undo last commit, keep changes staged |
git reset --soft HEAD~1 |
| Undo last commit, keep changes unstaged |
git reset HEAD~1 |
| Discard last commit AND its changes |
git reset --hard HEAD~1 (recoverable via reflog) |
| Revert a commit already pushed/shared |
git revert <sha> (new commit, safe) |
| Lost commits after bad reset/rebase |
git reflog then git reset --hard <sha> |
| Deleted a branch by accident |
git reflog → find tip sha → git branch <name> <sha> |
| Detached HEAD with work to keep |
git switch -c rescue-branch immediately |
Accidentally committed to main |
branch it off, then reset main: see references/reflog-recovery.md |
| Drop unstaged local changes |
git restore <file> / git restore . |
| Stash WIP to switch context |
git stash push -m "msg" → git stash pop |
Best Practices
- Make the first line of a commit ≤ 50 chars, imperative mood ("add", not "added").
- Run
scripts/rebase-safety-check.sh after a rebase to confirm no commits were silently dropped and the tree still matches expectations.
- Use
git add -p to keep commits atomic instead of git add ..
- Prefer
git switch/git restore over the overloaded git checkout.
- Tag the pre-rebase state if nervous:
git tag backup-before-rebase. Delete it when done.
- Configure
git config rerere.enabled true to let Git remember conflict resolutions across repeated rebases.
Common Pitfalls
- Force-pushing a shared branch and erasing teammates' commits. Use
--force-with-lease, and never on main.
- Rebasing
main/develop — rewriting public history breaks everyone. Use revert instead.
git reset --hard without checking — you lose uncommitted working-tree changes permanently (these are NOT in the reflog). Stash first.
- Resolving a conflict by deleting the wrong side — read both sides; the markers are
<<<<<<< HEAD (current/your side during merge) vs >>>>>>> branch (incoming). During rebase the sides are swapped — see references/conflict-resolution.md.
- Committing generated files / secrets — review
git diff --staged; use .gitignore.
- Assuming work is gone after a botched rebase — check
git reflog before doing anything else.
Bundled Files
references/interactive-rebase.md — complete interactive rebase guide with worked scenarios.
references/conflict-resolution.md — step-by-step conflict protocol, marker semantics, rerere, tools.
references/reflog-recovery.md — recover lost commits, branches, resets, detached HEAD, wrong-branch commits.
references/conventional-commits.md — message format, types, scopes, breaking changes, examples.
references/branch-naming.md — naming conventions and branching models.
scripts/git-recover.sh — list recently dangling/unreachable commits with previews to aid recovery.
scripts/rebase-safety-check.sh — sanity-check history after a rebase against the upstream base.
examples/squash-feature-branch.md — end-to-end worked example of cleaning a messy branch.
1---2name: git-workflow3description: Guides safe, professional Git usage — branching strategies, atomic clean commits, conventional commit messages, interactive rebase (squash/fixup/reword/reorder), merge vs rebase decisions, conflict resolution, and recovery of lost work via reflog. Use this skill when the user asks to create or clean up a branch, write or amend commits, squash or reorder history, rebase onto main, resolve merge conflicts, undo a bad commit/merge/reset, recover deleted commits or branches, find lost work, fix a detached HEAD, force-push safely, or generally "clean up my git history" before opening a PR.4license: MIT5---67# Git Workflow89## Overview1011This skill provides a disciplined, safe workflow for everyday Git: branching, crafting clean atomic commits, rewriting history with interactive rebase, resolving conflicts, and recovering from mistakes using the reflog. The guiding principle is **safety first** — never destroy work you cannot recover, always know your escape hatch before running a history-rewriting command.1213Keywords: git, branch, commit, rebase, interactive rebase, squash, fixup, reword, cherry-pick, merge, conflict, conflict resolution, reflog, recover lost commits, undo, reset, revert, detached HEAD, force-push, stash, clean history, conventional commits, PR prep.1415**Golden rules**161. Never rewrite history that others have already pulled (shared branches like `main`/`develop`). Rewrite only your own unmerged feature branches.172. Before any `rebase`, `reset --hard`, or force-push, note the current commit: `git rev-parse HEAD` or just trust the reflog — it remembers.183. Prefer `git push --force-with-lease` over `--force`. It refuses to clobber commits you haven't seen.194. Commit early, commit often locally; clean up into atomic commits before sharing.205. If something looks lost, it almost certainly isn't — go to `git reflog` (see references/reflog-recovery.md).2122## Workflow2324### 1. Orient before acting25Always understand current state first:26```27git status # working tree + branch28git log --oneline -10 # recent history29git branch -vv # branches + tracking30```3132### 2. Branch33- Update the base first: `git switch main && git pull --ff-only`.34- Create the branch: `git switch -c feat/short-description`.35- Naming: `<type>/<slug>` e.g. `feat/oauth-login`, `fix/null-deref`, `chore/bump-deps`, `docs/readme`. See references/branch-naming.md.3637### 3. Make atomic commits38- One logical change per commit. Stage selectively: `git add -p` to split a working tree into focused hunks.39- Write a Conventional Commit message (see references/conventional-commits.md):40 ```41 feat(auth): add OAuth2 PKCE login flow4243 Body explaining WHY, wrapped at ~72 cols. Reference issues.44 ```45- Verify before committing: re-read `git diff --staged`.4647### 4. Keep up to date with the base48Choose merge vs rebase intentionally (see decision framework below). For a private feature branch, rebasing keeps history linear:49```50git fetch origin51git rebase origin/main52```5354### 5. Clean up history before opening a PR55Squash noise ("wip", "fix typo"), reword unclear messages, reorder for logical flow:56```57git rebase -i origin/main58```59Full guidance and the command cheat sheet: references/interactive-rebase.md. Validate the result before pushing: scripts/rebase-safety-check.sh.6061### 6. Resolve conflicts methodically62When a rebase/merge stops on a conflict, follow the step-by-step protocol in references/conflict-resolution.md. Summary:63```64git status # see conflicted files65# edit files, remove <<<<<<< ======= >>>>>>> markers66git add <resolved-files>67git rebase --continue # or: git merge --continue68# abort anytime: git rebase --abort / git merge --abort69```7071### 7. Share72```73git push -u origin feat/short-description # first push74git push --force-with-lease # after a rebase/amend75```7677### 8. Recover when things go wrong78Nothing is lost until garbage collection runs (default ~30–90 days). See references/reflog-recovery.md and run scripts/git-recover.sh to surface candidate lost commits.7980## Decision Framework: Merge vs Rebase8182| Situation | Use |83|-----------|-----|84| Updating your private, unpushed feature branch with latest `main` | `git rebase origin/main` (linear history) |85| Branch is shared / others have it checked out | `git merge origin/main` (don't rewrite shared history) |86| Combining a finished feature into `main` (team prefers linear) | rebase then fast-forward / squash-merge |87| Combining a feature, preserving full context & merge point | `git merge --no-ff` |88| You just want to grab one commit from another branch | `git cherry-pick <sha>` |8990Rule of thumb: **rebase local, merge shared.**9192## Interactive Rebase Quick Reference9394In the `git rebase -i` todo list, set the action keyword on each line:9596| Keyword | Effect |97|---------|--------|98| `pick` | keep the commit as-is |99| `reword` (r) | keep changes, edit the message |100| `edit` (e) | stop to amend the commit (split, add files) |101| `squash` (s) | merge into previous commit, combine messages |102| `fixup` (f) | merge into previous commit, discard this message |103| `drop` (d) | remove the commit entirely |104| reorder | move lines up/down to reorder commits |105106Targeted fixup workflow (best for PR review fixes):107```108git commit --fixup=<sha> # creates "fixup! ..." commit109git rebase -i --autosquash origin/main # auto-positions & marks it fixup110```111112## Recovery Cheat Sheet113114| Problem | Fix |115|---------|-----|116| Bad last commit, want to redo message | `git commit --amend` |117| Undo last commit, keep changes staged | `git reset --soft HEAD~1` |118| Undo last commit, keep changes unstaged | `git reset HEAD~1` |119| Discard last commit AND its changes | `git reset --hard HEAD~1` (recoverable via reflog) |120| Revert a commit already pushed/shared | `git revert <sha>` (new commit, safe) |121| Lost commits after bad reset/rebase | `git reflog` then `git reset --hard <sha>` |122| Deleted a branch by accident | `git reflog` → find tip sha → `git branch <name> <sha>` |123| Detached HEAD with work to keep | `git switch -c rescue-branch` immediately |124| Accidentally committed to `main` | branch it off, then reset `main`: see references/reflog-recovery.md |125| Drop unstaged local changes | `git restore <file>` / `git restore .` |126| Stash WIP to switch context | `git stash push -m "msg"` → `git stash pop` |127128## Best Practices129- Make the first line of a commit ≤ 50 chars, imperative mood ("add", not "added").130- Run `scripts/rebase-safety-check.sh` after a rebase to confirm no commits were silently dropped and the tree still matches expectations.131- Use `git add -p` to keep commits atomic instead of `git add .`.132- Prefer `git switch`/`git restore` over the overloaded `git checkout`.133- Tag the pre-rebase state if nervous: `git tag backup-before-rebase`. Delete it when done.134- Configure `git config rerere.enabled true` to let Git remember conflict resolutions across repeated rebases.135136## Common Pitfalls137- **Force-pushing a shared branch** and erasing teammates' commits. Use `--force-with-lease`, and never on `main`.138- **Rebasing `main`/`develop`** — rewriting public history breaks everyone. Use `revert` instead.139- **`git reset --hard` without checking** — you lose uncommitted working-tree changes permanently (these are NOT in the reflog). Stash first.140- **Resolving a conflict by deleting the wrong side** — read both sides; the markers are `<<<<<<< HEAD` (current/your side during merge) vs `>>>>>>> branch` (incoming). During rebase the sides are swapped — see references/conflict-resolution.md.141- **Committing generated files / secrets** — review `git diff --staged`; use `.gitignore`.142- **Assuming work is gone after a botched rebase** — check `git reflog` before doing anything else.143144## Bundled Files145- `references/interactive-rebase.md` — complete interactive rebase guide with worked scenarios.146- `references/conflict-resolution.md` — step-by-step conflict protocol, marker semantics, rerere, tools.147- `references/reflog-recovery.md` — recover lost commits, branches, resets, detached HEAD, wrong-branch commits.148- `references/conventional-commits.md` — message format, types, scopes, breaking changes, examples.149- `references/branch-naming.md` — naming conventions and branching models.150- `scripts/git-recover.sh` — list recently dangling/unreachable commits with previews to aid recovery.151- `scripts/rebase-safety-check.sh` — sanity-check history after a rebase against the upstream base.152- `examples/squash-feature-branch.md` — end-to-end worked example of cleaning a messy branch.