Git and GitHub / Basic: the local Git model / Lesson 5
Merging, ancestry, and integration results
Choose an integration operation by graph shape and verify the resulting content rather than relying on a success message.
On this page
Lesson goals
- Distinguish fast-forward updates from merge commits.
- Verify integrated behavior and preserve parent meaning.
Ask whether one tip already contains the other
Integration begins with ancestry. If the current branch tip is an ancestor of the topic tip, the current reference can advance directly to the topic: a fast-forward. If both branches added commits after a common base, integration may require a merge commit or another chosen workflow. Equal file contents do not imply equal ancestry, and a clean merge does not prove semantic compatibility. Inspect the graph, identify the destination branch, and protect local work before beginning. The command acts on the current branch, so reversing the checkout reverses which line receives the result.
Require a fast-forward when that is the policy
git merge --ff-only advances the current branch only when no merge commit is needed; otherwise it refuses. This is useful when a workflow expects a linear update and wants divergence to receive an explicit decision. In the lab, main has not advanced since feature/title branched, so the merge simply moves main to the topic tip. It does not create a second copy of the topic commits. If the lab has diverged, stop and inspect rather than replacing --ff-only with a forceful command to make the example appear successful.
git switch main
git merge --ff-only feature/title
git merge-base --is-ancestor feature/title main
Requires a clean lab where main is an ancestor of feature/title. The final ancestry check exits 0 and prints nothing, indicating the topic tip is reachable from main. It is an exit-status assertion, not an empty-result failure.
Understand what a merge commit records
A true merge combines changes relative to common ancestry and records multiple parents. For an ordinary two-parent merge, the first parent is the previous destination tip and the second is the integrated tip. The resulting tree can include conflict resolutions and other content, so inspecting only one parent comparison can miss context. A project may prefer merge commits to preserve branch integration structure, squash merges to consolidate a change, or rebasing to maintain a linear presentation. These choices affect history and review expectations. Agree on policy before rewriting or integrating shared work.
Inspect an explicit merge result
The next fragment assumes the temporary branches lab-left and lab-right diverged from one base and changed independent files. Merging while on lab-left creates a merge commit. The parent-count check verifies its shape without predicting object ids. No conflict in this setup means Git could combine the text automatically; it does not mean the combined program has been tested. Run the relevant tests and inspect the staged or committed result under the project’s workflow. Keep integration commits understandable so later first-parent history can explain when a feature entered the destination.
git switch lab-left
git -c user.name="Lab Author" -c user.email="lab@example.invalid" merge --no-edit lab-right
git rev-list --parents -n 1 HEAD | awk '{print NF-1}'
With the stated diverged, nonconflicting branches, the last command prints 2. The shell pipeline is an inspection aid in a POSIX lab. A merge failure must be diagnosed separately; do not continue as though the parent count were guaranteed after any merge attempt.
Validate the integration, not only the operation
Two branches can modify different files yet disagree about an API, schema, unit, or feature assumption. Textual conflict detection cannot discover every semantic conflict. Review the combined diff, run relevant tests, and check migration and compatibility requirements. If a merge stops for conflicts, the repository enters an in-progress state that must be completed or deliberately aborted. Beginning with a clean working tree makes recovery easier because pre-existing edits can complicate restoration. Preserve important work before starting, and use a named temporary branch to rehearse a complicated integration without altering shared history.
Common errors and fixes
Fast-forward-only integration is refused
- Why it happens
- Both tips contain independent commits.
- How to fix it
- Inspect the graph and select the agreed integration strategy.
- Prevent it next time
- Treat divergence as a decision rather than an obstacle to bypass.
A clean merge breaks behavior
- Why it happens
- Text combined while assumptions remained incompatible.
- How to fix it
- Review and test the combined behavior.
- Prevent it next time
- Include cross-component integration checks.
The wrong branch receives the merge
- Why it happens
- The current destination was not verified.
- How to fix it
- Preserve the result and plan correction based on sharing state.
- Prevent it next time
- Check current branch and clean status before integration.
Check your understanding
1. main is an ancestor of topic and policy allows fast-forward. What changes after integration?
Show worked solution
main moves to the topic tip and the working snapshot follows it. Existing topic commits retain identity; no new merge commit is required. Verify ancestry and the expected content rather than assuming a new commit must appear.
2. Two branches change separate files, but one renames a function used by the other. What catches the risk?
Show worked solution
Semantic review and tests of the combined snapshot can reveal the broken call. Automatic text merging may succeed completely. Add a regression test for the shared contract and keep the integration result reviewable.
Key takeaways
- Ancestry determines whether an update can fast-forward.
- Merge parents preserve integration relationships.
- Textual success requires semantic verification.