Git, GitHub & Version Control

Chapter 5
Branching, Merging and Integration

Bachelors Program in Full Stack Development
Git, GitHub & Version Control   •   Bachelor

Branching, Merging and Integration

Introduction

Version control becomes strategically valuable when several developers work on the same codebase, when features must be developed independently, or when releases need to be reproduced reliably. A Git branch is not a separate copy of an entire repository. It is a movable reference to a commit, allowing development histories to diverge and later converge. Branching therefore supports parallel work, experimentation, release maintenance, and controlled integration.

Integration is the process of bringing changes from one line of development into another. Git provides several integration mechanisms, including fast-forward merges, three-way merges, rebasing, and cherry-picking. Each produces different history characteristics and has different implications for collaboration, traceability, and risk.

This chapter examines these mechanisms and develops a systematic approach to conflict resolution. It also evaluates linear, merge-based, and hybrid integration models used in professional software teams.

Learning Objectives

By the end of this chapter, you should be able to:

  • Create, inspect, rename, publish, and delete Git branches.
  • Explain branch references, commits, ancestry, and reachability.
  • Create and use annotated and lightweight tags.
  • Distinguish fast-forward merges from three-way merges.
  • Apply merge, rebase, and cherry-pick safely.
  • Resolve conflicts systematically and verify the result.
  • Compare linear, merge-based, and hybrid integration strategies.
  • Select an integration model appropriate to a project’s risk and collaboration needs.

1. Git’s Commit Graph and Branch References

A Git repository stores commits in a directed acyclic graph. Each commit records a snapshot of tracked files, metadata, and one or more parent commits. Ordinary commits have one parent; merge commits generally have two or more parents.

A branch is a reference containing the identifier of a commit. When a new commit is created while the branch is checked out, the branch reference advances to that commit. Earlier commits remain available because the new commit points to its parent.

For example:

A---B---C  main
     \
      D---E  feature

Here, feature and main share commits A and B but have different descendants. The branch names are labels, not containers. The commits themselves form the history.

HEAD identifies the currently checked-out branch or commit. In normal branch work, HEAD points symbolically to a branch, and that branch points to the current commit. A detached HEAD occurs when HEAD points directly to a commit rather than to a branch. Detached HEAD is useful for inspection or temporary experimentation, but new commits may become difficult to locate unless a branch or tag is created.

Useful inspection commands include:

git status
git branch
git branch --all
git log --oneline --graph --decorate --all
git show-branch

The commit graph is more informative than a list of file versions because it shows ancestry, divergence, and integration points.

2. Creating and Managing Branches

A branch should usually represent a coherent line of work: a feature, defect correction, release, experiment, or maintenance stream. Short-lived branches reduce integration difficulty because fewer unrelated changes accumulate before integration.

Common commands are:

git switch main
git switch -c feature/payment-validation
git branch --list
git switch feature/payment-validation
git branch -m old-name new-name
git branch -d feature/payment-validation
git branch -D feature/payment-validation

The -d option normally refuses to delete a branch whose commits have not been merged. The force option -D bypasses that protection and should be used only after confirming that the commits are no longer needed.

A remote-tracking branch such as origin/main is a local reference describing the last known state of the remote branch. It is updated by fetching:

git fetch origin
git switch -c feature/reporting origin/main
git push -u origin feature/reporting

Fetching downloads remote objects and updates remote-tracking references; it does not merge changes into the current branch. Pulling usually combines fetching with an integration operation, commonly merge or rebase depending on configuration. Explicit commands are often clearer in professional workflows:

git fetch origin
git rebase origin/main

or:

git fetch origin
git merge origin/main

Branch naming conventions should be consistent and informative, for example feature/, bugfix/, release/, and hotfix/. Names should not expose confidential information such as customer names, security details, or credentials.

3. Tags and Release Identity

A tag is a reference intended to identify a significant point in history. Tags are commonly used for releases, milestones, or audit references.

A lightweight tag is simply a name pointing to an object:

git tag v2.0.0

An annotated tag is a Git object containing a message, tagger identity, timestamp, and target reference. Annotated tags are generally preferable for releases:

git tag -a v2.0.0 -m "Release 2.0.0"
git show v2.0.0

Tags can be published explicitly:

git push origin v2.0.0
git push origin --tags

A tag should normally be immutable in organizational practice. Moving a published release tag can cause different users to associate the same version name with different source code. If a tag must be corrected, teams should document the change and communicate it clearly; creating a new version is often safer.

Semantic Versioning uses the form MAJOR.MINOR.PATCH. A major version indicates incompatible public changes, a minor version indicates backward-compatible functionality, and a patch version indicates backward-compatible fixes. This convention is a project policy rather than a Git requirement.

4. Fast-Forward and Three-Way Merges

Suppose main has not advanced since a feature branch was created:

A---B  main
     \
      C---D  feature

A fast-forward merge moves main directly to D because B is an ancestor of D:

git switch main
git merge feature

The resulting history is linear. No merge commit is created.

If both branches have new commits, a fast-forward is impossible:

C---D  feature
     /
A---B
     \
      E---F  main

Git performs a three-way merge using the two branch tips and their best common ancestor, B. If the merge succeeds automatically, Git creates a merge commit with two parents. The merge commit records that two lines of development were integrated.

A project can require an explicit merge commit even when fast-forwarding is possible:

git merge --no-ff feature

This preserves the existence of the feature branch as a visible integration event. Conversely, --ff-only refuses to merge unless a fast-forward is possible, which is useful when a strictly linear history is required.

The choice is not merely aesthetic. Fast-forward histories are compact and easy to read, while merge commits preserve branching context and may improve auditability. A merge commit does not automatically mean that the code is safer; its value depends on review, testing, and project practice.

5. Rebasing

Rebase changes the base of a sequence of commits. If feature commits C and D were based on B, and main has advanced to F, rebasing replays the changes represented by C and D on top of F:

Before:       B---C---D  feature
             \
              E---F  main

After:        B---E---F---C'---D'  feature

The apostrophes indicate new commits. Rebase does not move the original commits; it creates replacement commits with different parent relationships and therefore different identities.

Typical commands are:

git switch feature
git fetch origin
git rebase origin/main

If a conflict occurs:

git status
# edit conflicted files
git add path/to/resolved-file
git rebase --continue

Other controls are:

git rebase --skip
git rebase --abort

Rebasing can produce a clean linear history and expose conflicts before a feature is integrated. However, because it rewrites commit identities, published commits should not normally be rebased. A practical rule is: rewrite private history, but coordinate carefully before rewriting history shared by others.

When a rebased branch has already been published, updating it may require:

git push --force-with-lease

--force-with-lease is safer than --force because it refuses to overwrite the remote branch if it has changed unexpectedly. It is still a history rewrite and requires team agreement.

Interactive rebase can reorder, edit, squash, or drop commits:

git rebase -i HEAD~4

This is valuable for preparing a coherent review, but it must not be used to conceal relevant history or remove evidence required for compliance.

6. Cherry-Picking

Cherry-pick applies the change introduced by a selected commit onto the current branch by creating a new commit:

git switch release/2.0
git cherry-pick abc1234

It is useful when a specific bug fix must be transferred to a maintenance branch without integrating an entire feature branch. Multiple commits may be selected, but the resulting history may obscure the relationship between the original and copied changes.

If conflicts occur:

git status
# resolve files
git add resolved-file
git cherry-pick --continue

Abort with git cherry-pick --abort. A copied commit has a different identity from the original, even if it introduces equivalent content. Teams may record the relationship with a message or a reference such as -x when appropriate:

git cherry-pick -x abc1234

Cherry-picking should not become a substitute for understanding branch relationships. Repeatedly copying commits between long-lived branches can create duplicate changes, difficult future merges, and maintenance burden.

7. Conflict Resolution as a Systematic Process

A conflict occurs when Git cannot safely combine changes. Textual conflicts commonly arise when two changes affect overlapping lines, but conflicts may also involve renamed files, deleted files, binary files, directory changes, or semantic incompatibilities that Git cannot detect.

A disciplined process is:

  1. Read the operation status: git status identifies the operation and affected files.
  2. Identify the intended result by consulting the issue, design, or pull request.
  3. Inspect conflict markers such as <<<<<<<, =======, and >>>>>>>.
  4. Compare each side with the common ancestor where necessary.
  5. Edit the file into a valid, coherent result; do not merely choose one side automatically.
  6. Run formatting, static analysis, unit tests, and relevant integration tests.
  7. Stage the resolved file with git add.
  8. Continue the operation, or abort if the intended result cannot be established.
  9. Review the resulting diff and commit history.

Useful tools include:

git diff
git diff --ours
git diff --theirs
git diff --cc
git mergetool

The labels “ours” and “theirs” depend on the operation. During a rebase, the terminology can be counterintuitive because the commit being replayed is treated differently from the new base. Always inspect the status and history rather than relying on memory.

Conflicts are often symptoms of process problems: branches are too long-lived, interfaces change without coordination, commits are too large, or tests are inadequate. Conflict resolution must therefore include both technical repair and verification of behavior.

8. Integration Models

Linear integration

In a linear model, changes are rebased or fast-forwarded so that the principal branch contains a single chain of commits. Advantages include simple log traversal, easy release comparison, and compatibility with tools that expect linear history. Disadvantages include rewritten history, reduced visibility of branch boundaries, and potential pressure to force-push shared branches.

Merge-based integration

In a merge-based model, branches are integrated with merge commits. Advantages include preservation of historical relationships, explicit integration points, and safer handling of already-published work. Disadvantages include a more complex graph and the possibility of noisy or poorly structured merge histories.

Hybrid integration

A hybrid model uses different strategies for different contexts. For example, developers may rebase private feature branches onto the current integration branch, then use a no-fast-forward merge through a reviewed pull request. Release and hotfix branches may use cherry-picks when only selected corrections are required.

No model is universally superior. Selection should consider branch lifetime, team size, review requirements, release risk, regulatory traceability, and the maturity of automated testing.

StrategyMain strengthMain riskSuitable use
Fast-forwardSimple linear historyBranch context may disappearSmall, controlled changes
Merge commitPreserves integration historyMore complex graphShared branches and auditable integration
RebaseClean preparation historyRewrites commit identitiesPrivate or coordinated branches
Cherry-pickSelective transferDuplicate or disconnected historyTargeted maintenance fixes
HybridContext-sensitive flexibilityRequires clear policyProfessional teams with varied workflows

9. Applied Case: Online Retail Checkout Service

The following is an illustrative case. A university project team maintains an online retail checkout service. The main branch represents deployable code. A team develops payment validation on feature/payment-validation, while another team prepares a tax-rate correction for the maintenance branch release/3.1.

Problem

The payment feature takes two weeks, during which main receives changes to address logging and database performance. The tax correction is urgent but should not include the unfinished payment feature.

Analysis

The payment branch is private to its team and has diverged from main. Rebasing it onto the latest main will expose integration conflicts before review. The tax correction is a small, isolated commit already tested on main; cherry-picking it to release/3.1 is appropriate.

Approach

The payment team fetches the repository and rebases:

git switch feature/payment-validation
git fetch origin
git rebase origin/main

A conflict occurs in CheckoutService.java because logging and payment validation changed the same method. The team consults the design specification, combines both behaviors, runs unit and integration tests, and continues the rebase. After review, the branch is integrated through a pull request using a merge commit so that the feature boundary remains visible.

For the maintenance fix, the release manager identifies the tested commit and runs:

git switch release/3.1
git cherry-pick -x <tested-commit>

The release branch is tested independently and tagged:

git tag -a v3.1.1 -m "Release 3.1.1"
git push origin v3.1.1

Outcome

The main branch records the payment feature as a reviewed integration event. The maintenance release receives only the tax correction. The annotated tag identifies the exact source used for release 3.1.1.

Learning points

  • Integration strategy should reflect the purpose of the branch.
  • Rebasing is useful before publication but requires care after publication.
  • Cherry-picking is effective for isolated fixes, not broad synchronization.
  • Tests are essential after conflict resolution because syntactic success does not guarantee behavioral correctness.
  • Tags provide stable release identity only when teams treat them consistently.

10. Best Practices, Governance, and Contemporary Practice

Keep branches focused and short-lived. Pull or fetch regularly. Use small, logically complete commits with messages that explain intent. Protect important branches with required reviews, status checks, and restrictions on force-pushing. Establish a documented policy for rebasing, merge commits, release tags, and emergency fixes.

Never commit passwords, private keys, access tokens, or personal data. Git history is durable, and deleting a file in a later commit does not guarantee that the sensitive content has disappeared from all clones. Secret scanning, least-privilege access, signed commits or tags where appropriate, and repository audit logs strengthen governance.

Continuous integration systems should build and test proposed integrations rather than merely testing branch tips. Modern platforms can automatically calculate mergeability, run security scans, and require approvals. AI-assisted conflict suggestions may accelerate routine work, but generated resolutions must be reviewed by developers because tools may preserve syntax while changing business meaning or security behavior.

Integration metrics should be interpreted carefully. A high merge count is not automatically poor, and a linear history is not automatically high quality. More meaningful indicators include time to integrate, defect escape rate, change failure rate, review quality, and the proportion of conflicts resolved with verified tests.

Chapter Summary

Branches are movable references to commits and allow independent lines of development. Tags identify important repository states, with annotated tags generally preferred for releases. Fast-forward merges preserve a linear chain, while three-way merges create explicit integration commits when histories have diverged. Rebasing replays commits onto a new base and creates new commit identities, so it is best applied to private or coordinated history. Cherry-picking selectively transfers a commit but can produce duplicated or disconnected history.

Conflict resolution requires more than removing markers: developers must understand intent, inspect ancestry, produce a coherent result, and verify behavior through tests. Linear, merge-based, and hybrid models each balance readability, traceability, collaboration, and history stability differently. Professional teams select strategies deliberately and support them with review, automation, security controls, and clear governance.

Key Terms

Branch: A movable reference to a commit.

Commit: A recorded repository snapshot with metadata and parent references.

HEAD: The current checkout position.

Remote-tracking branch: A local reference to the last known state of a remote branch.

Fast-forward: An integration that advances a branch without creating a merge commit.

Three-way merge: A merge using two branch tips and their common ancestor.

Merge commit: A commit with multiple parents recording integration.

Rebase: Replaying commits onto a different base commit.

Cherry-pick: Applying the change from a selected commit to another branch.

Conflict: A condition in which Git cannot automatically determine the correct combined result.

Conflict marker: Text inserted to identify competing file regions.

Annotated tag: A tag object containing metadata and a message.

Lightweight tag: A simple reference to an object.

Remote: A named reference to another repository.

Fast-forward-only: A policy that rejects non-linear merges.

Force-with-lease: A guarded update used when replacing remote history.

Reachability: Whether a commit can be located by following references and parents.

Integration branch: A branch used to combine work from multiple contributors.

Semantic versioning: A versioning convention based on major, minor, and patch components.

Protected branch: A branch subject to repository rules such as review or status checks.

Review Questions

Short Answer Questions

  1. What is the relationship between a branch and a commit?
  2. Why are annotated tags commonly preferred for releases?
  3. What condition permits a fast-forward merge?
  4. Why can rebasing published commits be disruptive?
  5. What is the purpose of git rebase --abort?

Long Answer Questions

  1. Explain the difference between fast-forward and three-way merges, using commit graphs.
  2. Describe a systematic conflict-resolution process and explain why testing is necessary after resolution.
  3. Compare rebasing and merging in terms of history, collaboration, and auditability.
  4. Explain the appropriate and inappropriate uses of cherry-picking.
  5. Evaluate the advantages and disadvantages of linear, merge-based, and hybrid integration models.

Analytical / Application Questions

  1. A feature branch has been published and used by three developers. It is two weeks behind main. Should the team rebase it? Justify a safe integration plan.
  2. A critical security fix exists as one tested commit on main, but the production maintenance branch lacks it. Which integration strategy should be considered first, and what verification is required?
  3. During a merge, two developers modify the same payment-calculation method. Explain how you would determine the correct resolution and demonstrate that the result preserves both correctness and security.

Multiple Choice Questions with Answers

Question 1

What does a Git branch primarily represent?

A. A complete independent copy of the repository

B. A movable reference to a commit

C. A remote server containing repository objects

D. A list of unresolved conflicts

Correct Answer: B. A movable reference to a commit

Question 2

Which command creates an annotated tag named v1.0.0?

A. git branch -a v1.0.0

B. git tag v1.0.0 -b

C. git tag -a v1.0.0 -m "Release 1.0.0"

D. git commit --tag v1.0.0

Correct Answer: C. git tag -a v1.0.0 -m "Release 1.0.0"

Question 3

When is a fast-forward merge possible?

A. When the current branch tip is an ancestor of the other branch tip

B. Only when both branches contain conflicts

C. Only when a merge commit already exists

D. When the repository has no remote

Correct Answer: A. When the current branch tip is an ancestor of the other branch tip

Question 4

What is the principal effect of rebasing a sequence of commits?

A. It deletes all parent commits

B. It replays commits onto a different base and creates new commit identities

C. It converts every commit into a tag

D. It permanently disables merging

Correct Answer: B. It replays commits onto a different base and creates new commit identities

Question 5

Which command abandons an in-progress rebase and restores the pre-rebase state?

A. git rebase --skip

B. git merge --abort

C. git rebase --abort

D. git reset --publish

Correct Answer: C. git rebase --abort

Question 6

What does cherry-pick do?

A. Copies a selected commit’s change onto the current branch as a new commit

B. Deletes a selected commit from every branch

C. Renames a remote repository

D. Automatically resolves every conflict

Correct Answer: A. Copies a selected commit’s change onto the current branch as a new commit

Question 7

After manually resolving a merge conflict, what normally marks the file as resolved?

A. git fetch

B. git add

C. git branch -d

D. git tag -l

Correct Answer: B. git add

Question 8

Why is force-with-lease generally safer than force-push?

A. It prevents all history rewriting

B. It checks that the remote reference has not changed unexpectedly

C. It automatically merges all remote commits

D. It removes conflicts without user input

Correct Answer: B. It checks that the remote reference has not changed unexpectedly

Question 9

Which integration model most explicitly preserves branch integration points?

A. Merge-based integration with merge commits

B. Fast-forward-only integration

C. Uncommitted local development

D. Detached HEAD usage

Correct Answer: A. Merge-based integration with merge commits

Question 10

Which operation is most suitable for transferring one isolated tested fix to a maintenance branch?

A. Cherry-pick

B. Deleting the maintenance branch

C. Creating a detached HEAD

D. Renaming the remote

Correct Answer: A. Cherry-pick

Git, GitHub & Version Control
Chapter 5 of 14