Let's put the concepts of branching and merging into practice. This hands-on exercise simulates a common development workflow: creating a separate branch for a new feature, making changes, and then integrating those changes back into the main line of development. We will also simulate and resolve a merge conflict.
First, ensure you have a Git repository to work in. If you completed the practice section in Chapter 2, you can use that repository. Otherwise, create a new one:
# Create a directory for our practice project
mkdir git-branch-practice
cd git-branch-practice
# Initialize a Git repository
git init
# Create an initial file and commit it
echo "Project Initial Content." > README.md
git add README.md
git commit -m "Initial commit with README"
# Add another small change for history
echo "Version 1.0" >> README.md
git add README.md
git commit -m "Add version info to README"
You should now be on the default branch (likely named main
or master
) with two commits. You can verify this with git log --oneline
.
Imagine we need to add a new section to our README.md
file describing a new feature. It's best practice to do this on a separate branch.
Create a new branch called add-feature-description
:
git branch add-feature-description
This command creates the branch but doesn't switch to it yet.
List branches to see the new branch:
git branch
Output:
* main
add-feature-description
The asterisk (*) indicates the currently active branch (main
).
Switch to the new branch:
git switch add-feature-description
(Alternatively, you could use git checkout add-feature-description
).
Git will confirm: Switched to branch 'add-feature-description'
You can also create and switch in one step using git switch -c add-feature-description
or git checkout -b add-feature-description
.
Now that you're on the add-feature-description
branch, any commits you make will be recorded on this branch, separate from main
.
Modify the file: Add the feature description to README.md
.
echo "" >> README.md # Add a blank line for separation
echo "## New Feature" >> README.md
echo "This section describes the amazing new feature." >> README.md
Check the status:
git status
Output:
On branch add-feature-description
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git restore <file>..." to discard changes in working directory)
modified: README.md
no changes added to commit (use "git add" and/or "git commit -a")
Stage and commit the changes:
git add README.md
git commit -m "Add feature description section"
Your feature branch now has a commit that main
does not.
Let's simulate work happening on the main branch while the feature was being developed. Perhaps a typo needs fixing.
Switch back to the main
branch:
git switch main
Modify the file on main
: Let's correct the first line in README.md
. Open README.md
in a text editor and change Project Initial Content.
to Project Initial Content
. (Remove the trailing period). Save the file.
Stage and commit this change on main
:
git add README.md
git commit -m "Fix typo in README title"
At this point, the main
branch and the add-feature-description
branch have diverged. Each has one new commit that the other doesn't.
Repository state before merging.
main
points to commitC3
(typo fix), andadd-feature-description
points toC2
(feature description). Both branches originate from commitC1
.
The feature is complete, and we want to integrate it into the main project.
Ensure you are on the receiving branch (main
in this case). We already switched in the previous step. If unsure, run git status
or git branch
.
Run the merge command:
git merge add-feature-description
Since both branches had changes originating from the same common ancestor (C1
), and the changes were in different parts of the file (title vs. new section at the end), Git can likely perform the merge automatically. Because the histories diverged, Git will create a merge commit.
You might see an editor open asking for a merge commit message. The default message is usually sufficient. Save and close the editor if it appears.
Output might look like:
Merge made by the 'recursive' strategy.
README.md | 4 ++++
1 file changed, 4 insertions(+)
git log --oneline --graph
Output will show the merge commit, bringing the histories together:
* commit-hash-M (HEAD -> main) Merge branch 'add-feature-description'
|\
| * commit-hash-C2 (add-feature-description) Add feature description section
* | commit-hash-C3 Fix typo in README title
|/
* commit-hash-C1 Add version info to README
* commit-hash-C0 Initial commit with README
Your README.md
file on the main
branch now contains both the typo fix and the new feature section.
Now, let's create a situation where Git cannot automatically merge changes because both branches modified the same line.
Create another branch off main
(which now includes the first feature):
git switch -c update-version main
Modify README.md
on this new branch. Change the version line:
Edit README.md
so the second line reads Version 1.1
instead of Version 1.0
. Save the file.
Stage and commit on update-version
:
git add README.md
git commit -m "Update version to 1.1"
Switch back to main
:
git switch main
Modify README.md
on main
: Simulate another developer updating the version independently, perhaps to Version 1.0.1
.
Edit README.md
so the second line reads Version 1.0.1
. Save the file.
Stage and commit on main
:
git add README.md
git commit -m "Update version to 1.0.1"
Now, both main
and update-version
have modified the same line (the version line) since their last common ancestor (the merge commit from Step 4).
update-version
into main
:
git merge update-version
Git will detect the conflict:
Auto-merging README.md
CONFLICT (content): Merge conflict in README.md
Automatic merge failed; fix conflicts and then commit the result.
Git couldn't decide which version of the line to keep, so it marked the conflict in the file and paused the merge.
Check the status:
git status
Output:
On branch main
You have unmerged paths.
(fix conflicts and run "git commit")
(use "git merge --abort" to abort the merge)
Unmerged paths:
(use "git add <file>..." to mark resolution)
both modified: README.md
no changes added to commit (use "git add" and/or "git commit -a")
It clearly indicates README.md
has unmerged paths (conflicts).
Open the conflicted file (README.md
) in your editor. You will see conflict markers added by Git:
Project Initial Content.
<<<<<<< HEAD
Version 1.0.1
=======
Version 1.1
>>>>>>> update-version
## New Feature
This section describes the amazing new feature.
<<<<<<< HEAD
: Indicates the start of the conflicting lines from the current branch (main
).=======
: Separates the conflicting lines from the two branches.>>>>>>> update-version
: Indicates the end of the conflicting lines from the branch being merged (update-version
).Edit the file to resolve the conflict: You need to manually edit this section to contain the content you want to keep. Remove the conflict markers (<<<
, ===
, >>>
). For instance, let's decide that Version 1.1
is the correct one:
Project Initial Content.
Version 1.1
## New Feature
This section describes the amazing new feature.
Save the file after making the desired changes and removing the markers.
Stage the resolved file: Tell Git you've fixed the conflict:
git add README.md
Commit the merge: Finalize the merge operation. Git often suggests a commit message.
git commit
(If your editor opens, just save and close the default message: "Merge branch 'update-version'").
The conflict is resolved, and the merge is complete.
Once a feature branch has been successfully merged and you no longer need it, you can delete it.
List branches:
git branch
Output:
* main
add-feature-description
update-version
Delete the merged branches:
git branch -d add-feature-description
git branch -d update-version
Output:
Deleted branch add-feature-description (was commit-hash-C2).
Deleted branch update-version (was commit-hash-...).
The -d
flag only allows deletion if the branch has been fully merged. Use -D
(capital D) to force deletion if needed, but be cautious.
You have now successfully practiced creating branches, making independent changes, merging them back (including a non-fast-forward merge), resolving a merge conflict, and cleaning up obsolete branches. This workflow forms the basis of many collaborative development strategies using Git.
© 2025 ApX Machine Learning