Git Guide: Branches, Merge, Rebase and Recovery
Git is an essential version control system for engineers worldwide. However, historical command overloading (like git checkout handling both branches and files) and rebase hazards cause frequent code losses. This article offers a complete, safety-first Git guide.
1. Problem: 3-area architecture and VCS snapshot models
Unlike centralized version control systems (such as SVN), Git uses a distributed snapshot model. The key to mastering Git is understanding its 3 main areas: Working Directory (local physical files), Staging Area / Index (prepared snapshot index), and Git Repository (commit history DAG). Most Git commands simply transfer data between these areas.
2. Minimal reproduction: state transitions across Working Directory, Index, and Repository
This command sequence illustrates standard code state transitions from editing to staging, committing, and inspecting logs:
# 1. Inspect Working Directory and Staging Area status
git status
# 2. Stage modified files from Working Directory to Index
git add src/index.ts
# 3. Persist staged snapshot into Commit History
git commit -m "feat: add user authentication module"
# 4. Inspect commit DAG topology history
git log --oneline --graph3. Root cause: modern command separation (git switch / git restore) and Rebase trade-offs
1. Legacy `git checkout` Overloading: historically, git checkout handled both branch switching (git checkout main) and workspace file discarding (git checkout -- file.ts). This overloading invited accidental file deletions. 2. Modern Separated Commands: Git 2.23+ introduced git switch for branch operations (git switch main, git switch -c feature/auth) and git restore for resetting files (git restore file.ts, git restore --staged file.ts). 3. Merge vs. Rebase: git merge preserves true timeline history by creating a merge commit; git rebase replays commits on top of a target base, maintaining a linear history.
4. Recommendation: safety rules for team collaboration
1. Embrace Modern Commands: adopt git switch and git restore in daily workflows instead of legacy git checkout. 2. Never Rebase Public Branches: never execute `git rebase` on shared public branches (such as main/master/release)! Rebase rewrites shared commit hashes, corrupting collaborator histories. 3. Safer Force Push: use git push --force-with-lease instead of dangerous git push --force. 4. Beware of git reset --hard: git reset --hard permanently wipes uncommitted working directory changes. Always run git stash before hard resetting.
5. Complete code: disaster recovery via git reflog after accidental hard reset or branch deletion
This step-by-step procedure demonstrates recovering lost commits using Git's low-level reflog after accidental git reset --hard or branch deletion.
# Scenario: Accidental 'git reset --hard HEAD~3' discarded 3 important commits!
# Step 1: Print low-level reference mutation log (Reflog)
git reflog
# Sample Output:
# e4a21d8 (HEAD -> main) HEAD@{0}: reset: moving to HEAD~3
# a1b2c3d HEAD@{1}: commit: feat: complete core algorithm optimization <-- Target commit!
# f9e8d7c HEAD@{2}: commit: feat: add API validation
# Option A: Reset HEAD back to the target commit hash
git reset --hard a1b2c3d
# Option B: Recreate a deleted branch from the Reflog commit hash
git switch -c recovered-feature a1b2c3d
# Note: Any committed object remains safely stored in .git for 30 days even if branches are deleted!6. Incorrect approaches
Executing git rebase on shared public branches. Deleting conflict marker blocks during merge conflict resolution without aligning business logic. Executing git reset --hard without stashing uncommitted changes. Deleting committed secrets using only git rm (leaving secrets in historical commits).
7. Boundaries: Conflict Resolution and .gitignore tracking caveats
During merge conflicts, Git inserts <<<<<<< HEAD, =======, and >>>>>>> markers. After resolving conflicts manually, run git add to mark files resolved before running git merge --continue or git rebase --continue. If tracked files ignore .gitignore, untrack them first via git rm --cached <file>.
8. Verification
Run git status to verify a clean working directory. Clean up merged local branches via git branch -d. Prune deleted remote branch references via git remote prune origin. Remove accidentally committed large files or secrets using git filter-repo.
9. FAQ
What is the difference between git pull and git fetch? git fetch downloads remote objects without mutating local branches; git pull equals git fetch + git merge (or git pull --rebase equals git fetch + git rebase).
How do I fix accidentally committed secret passwords? If un-pushed, run git reset --soft HEAD~1 and remove the secret; if pushed, rotate the password immediately and scrub history with git filter-repo.
What is the difference between git stash pop and git stash apply? stash pop restores changes and deletes the stash entry; stash apply restores changes while retaining the stash entry.
10. Summary
Mastering the 3-area model, adopting modern git switch/restore commands, avoiding public branch rebases, and leveraging git reflog for recovery ensures a robust version control workflow.
Sources and further reading
Specifications and references for checking the article’s technical details.
- Git Documentation
Git project
Related articles
Notion Guide: Knowledge Bases and Databases
A comprehensive guide to Notion's Block-based architecture, slash commands, 6 Database views (Table, Board, Timeline), Relation & Rollup linking, Formula 2.0, and building team Wiki templates.
PitfallsCRLF vs LF: Fix Line Ending Diffs with Git
Analyze how line ending mismatches between Windows (CRLF, \r\n) and Linux/macOS (LF, \n) cause whole-file false diffs, and configure Git line ending normalization.
How it worksCode Diff Algorithms: LCS, Myers and Patience
Examine the evolution of sequence comparison algorithms from dynamic programming LCS to Myers Diff and Patience Diff in version control systems.
Keep exploring
Continue with the related article and software collection.
Explore related resources