Documentation Index
Fetch the complete documentation index at: https://resources.devweekends.com/llms.txt
Use this file to discover all available pages before exploring further.
Git Branching & Merging
Branching is Git’s killer feature. Create branches in milliseconds, experiment freely, and merge with confidence.Why Branching Matters
Parallel Development
Multiple features in progress simultaneously without interference
Safe Experimentation
Try ideas without risking the main codebase
Code Review
Review changes before merging to main
Clean History
Organize work into logical units
Understanding Branches
A branch is just a pointer to a commit. That is it. It is a 41-byte file containing a commit hash. This is why Git branches are so cheap to create — there is no copying of files, no duplicating directories. Creating a branch is like putting a sticky note on a page in a book: the book does not change, you just marked where you are.Creating Branches
Switching Branches
Branch Naming Conventions
Merging Branches
Fast-Forward Merge
When there are no new commits on the target branch:Three-Way Merge
When both branches have new commits:Resolving Merge Conflicts
Conflicts happen when the same lines are changed in both branches. They are not failures — they are Git honestly telling you, “I found changes in both branches that touch the same code, and I do not want to guess which one you intended.” Conflicts are normal, expected, and a sign that your team is actively working on the same codebase.Example Conflict
Conflict Markers
<<<<<<< HEAD: Your current branch’s version=======: Separator>>>>>>> feature/redesign: Incoming branch’s version
Resolving
Conflict Resolution Tools
Deleting Branches
Branch Management
Viewing Branches
Renaming Branches
Common Branching Workflows
Feature Branch Workflow
Gitflow Workflow
Gitflow is designed for software with scheduled release cycles — mobile apps, desktop software, libraries with semantic versioning. It adds ceremony (more branches, more rules), so only use it when you genuinely need release branches.Trunk-Based Development
Everyone commits to main (the “trunk”) or uses extremely short-lived branches (hours, not days). This is how Google, Meta, and most high-velocity SaaS teams operate. The key insight: merging frequently with small changes is far less risky than merging infrequently with large changes.Merge Strategies
Merge (Default)
Cons: Can create a messy history with many merge commits
Squash Merge
Cons: Loses individual commit history (the 47 “WIP” and “fix typo” commits disappear, which is usually a feature, not a bug)
Rebase (Advanced)
Cons: Rewrites history (don’t rebase public branches!)
Practical Examples
Example 1: Feature Development
Example 2: Handling Conflicts
Best Practices
Keep Branches Short-Lived
Keep Branches Short-Lived
- Merge within days, not weeks
- Reduces merge conflicts
- Easier code review
Pull Before Push
Pull Before Push
Delete Merged Branches
Delete Merged Branches
Use Descriptive Names
Use Descriptive Names
✅
✅
❌
❌
feature/user-authentication✅
fix/login-timeout❌
my-branch❌
testTroubleshooting
”Cannot switch branches - uncommitted changes”
This happens because Git refuses to overwrite your uncommitted work when switching branches — it is protecting you, not blocking you.”Merge conflict in binary file”
Binary files (images, fonts, compiled assets) cannot be auto-merged because there is no meaningful “line-by-line diff.” You must choose one version or the other.”Accidentally committed to wrong branch”
This happens more often than anyone admits. The fix is straightforward: cherry-pick the commit to the correct branch, then remove it from the wrong one.Key Takeaways
- Branches are lightweight pointers
- Create branches freely for features, fixes, experiments
- Merge conflicts are normal—learn to resolve them
- Delete branches after merging
- Choose a workflow that fits your team
Interview Deep-Dive
Your team uses squash merges for all PRs into main. A staff engineer argues you should switch to regular merge commits. Present both sides of this debate.
Your team uses squash merges for all PRs into main. A staff engineer argues you should switch to regular merge commits. Present both sides of this debate.
Strong Answer:
- Squash merges collapse all commits from a feature branch into a single commit on main. The main branch tells the story of “what shipped” — one commit per feature/fix. This makes
git log mainclean,git bisecton main fast (fewer commits to search), and reverts trivial (git revert <single-sha>). Companies like GitHub, Shopify, and Stripe use this model. The individual commit history is preserved in the pull request UI if anyone needs it. - Regular merge commits preserve full branch history and add an explicit merge commit that records when and how branches were integrated. The benefit is complete traceability: you can see every intermediate step, every WIP commit, every fix-after-code-review commit. This matters in regulated environments where auditors want to see the exact sequence of changes. It also means
git blameshows the original author of each line, not “the person who clicked merge.” - The trade-off comes down to: do you optimize for reading history (squash) or writing history (merge)? Squash merges require discipline in writing a good squash commit message (the default auto-generated message is usually garbage). Merge commits require discipline in keeping individual commits clean (otherwise main history is polluted with “WIP” and “fix typo”).
- My recommendation depends on team culture. If the team writes clean, atomic commits with good messages, regular merges work well. If commits tend to be messy (most teams), squash merges produce a cleaner main branch. A third option — rebase-and-merge — replays the individual commits linearly on main without a merge commit, giving you clean history if the individual commits are clean.
(#456)) serves as the source of truth. I also recommend using the Co-authored-by trailer in squash commit messages to credit all contributors. For deep-dive blame, git log --follow -p file.txt and the PR history are more reliable than git blame alone.You are resolving a complex merge conflict in a file with 500 lines. The conflict markers span 100 lines and you are not sure which version is correct. What is your systematic approach?
You are resolving a complex merge conflict in a file with 500 lines. The conflict markers span 100 lines and you are not sure which version is correct. What is your systematic approach?
Strong Answer:
- First, I understand the three-way merge. There are three versions of the file: the common ancestor (base), our version (HEAD), and their version (the branch being merged). I view all three explicitly:
git show :1:file.txt(base),git show :2:file.txt(ours),git show :3:file.txt(theirs). This gives me the full context that conflict markers alone do not. - Second, I examine the intent of each change. I run
git log --oneline main..feature -- file.txtto see what commits from the feature branch touched this file, andgit log --oneline feature..main -- file.txtfor changes on main. Reading the commit messages tells me what each side was trying to accomplish. - Third, I use a visual merge tool.
git mergetoolopens a three-pane view showing base, ours, and theirs side by side. VS Code, IntelliJ, and Beyond Compare all support this. For a 100-line conflict, visual diffing is essential — raw conflict markers are unreadable at that scale. - Fourth, if the conflict is in code (not prose), I resolve it and immediately run the test suite. Tests catch logical errors in my resolution that I might miss visually. If tests pass, I am confident in the resolution.
- Fifth, I make the resolution its own atomic step. I do not combine conflict resolution with other changes. The merge commit should contain only the resolution so that future reviewers can audit exactly what decisions were made during the merge.
Compare Gitflow, Feature Branch, and Trunk-Based Development. When would you choose each, and what are the failure modes of each?
Compare Gitflow, Feature Branch, and Trunk-Based Development. When would you choose each, and what are the failure modes of each?
Strong Answer:
- Feature Branch (the default for most teams): every feature gets a branch off main, merged via PR after review. Failure mode: long-lived feature branches that diverge significantly from main, leading to painful merge conflicts. Prevention: merge main into feature branches daily, keep branches under a week.
- Gitflow: adds
develop,release/*, andhotfix/*branches on top of feature branches. Best for software with versioned releases (mobile apps, desktop software, libraries). Failure mode: excessive ceremony. Teams spend more time managing branches than writing code. I have seen teams with 5 developers maintaining 4 concurrent release branches. Prevention: only adopt Gitflow if you genuinely ship versioned releases to different customers simultaneously. - Trunk-Based: everyone commits to main (or very short-lived branches that merge within hours). Used by Google, Meta, and most high-velocity SaaS companies. Failure mode: broken main. If the CI pipeline is slow or flaky, developers merge untested code. If there are no feature flags, half-built features ship to users. Prevention: fast CI (under 10 minutes), comprehensive test coverage, feature flags for in-progress work.
- The pattern I see: most teams start with Feature Branch workflow. As the team grows and the deployment cadence increases, they either evolve toward trunk-based (SaaS products) or toward Gitflow (versioned products). The most common mistake is adopting a workflow that is too complex for the team’s maturity — a 3-person startup using full Gitflow is adding process overhead with no benefit.
Next: Git Collaboration →