Resolving Git Merge Conflicts Manually on Ubuntu 22.04 LTS: HEAD Branch Changes
Learn to confidently resolve Git merge conflicts involving the HEAD branch on Ubuntu 22.04. This guide provides step-by-step instructions for manual resolution.
Learn to confidently resolve Git merge conflicts involving the HEAD branch on Ubuntu 22.04. This guide provides step-by-step instructions for manual resolution.
Introduction
As a seasoned Systems Administrator or DevOps engineer, you understand that collaboration is key to modern software development. With collaboration comes the inevitable: Git merge conflicts. While Git is remarkably adept at automatically merging diverging codebases, there are instances where changes overlap on the exact same lines in the same file. In these scenarios, Git flags a merge conflict, halting the merge process and requiring manual intervention.
This guide provides a highly technical, step-by-step approach to manually resolving Git merge conflicts on Ubuntu 22.04 LTS, with a particular focus on understanding and arbitrating changes involving your current HEAD branch against an incoming branch. Mastering this skill is crucial for maintaining clean, stable deployments, especially when managing critical configuration files (e.g., Nginx virtual hosts, Docker Compose files) or application code.
Symptom & Error Signature
When a merge conflict occurs, Git will pause the merge operation and report the conflict directly in your terminal. You'll typically see messages indicating which files are conflicted and that the automatic merge failed.
Typical git merge Output:
$ git merge feature/my-new-feature
Auto-merging src/app/web/index.js
CONFLICT (content): Merge conflict in src/app/web/index.js
Automatic merge failed; fix conflicts and then commit the result.
Checking the Status (git status):
After a merge conflict, git status will clearly list the "unmerged paths" (conflicted files) and provide guidance.
$ git status
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: src/app/web/index.js
both modified: config/nginx/my-app.conf
no changes added to commit (use "git add" and/or "git commit -a")
Inside a Conflicted File:
The most direct symptom is within the conflicted file itself. Git injects special markers to delineate the different versions of the conflicting code blocks.
// src/app/web/index.js
const serverPort = 3000;
function initializeApp() {
console.log("Application initializing...");
<<<<<<< HEAD
// Existing log for server startup on current 'main' branch
console.log(`Server starting on port ${serverPort} with basic logging.`);
setupBasicRoutes();
=======
// Feature branch added detailed logging and health check
console.log(`Web server launching on port ${serverPort}. Verbose logging enabled.`);
setupRoutes();
setupHealthCheckEndpoint();
>>>>>>> feature/my-new-feature
}
// ... rest of the file
In this example:
- Lines between
<<<<<<< HEADand=======represent the changes from your current branch (main). - Lines between
=======and>>>>>>> feature/my-new-featurerepresent the changes from thefeature/my-new-featurebranch you are trying to merge.
Root Cause Analysis
A Git merge conflict primarily arises from simultaneous, divergent modifications to the same lines of code within the same file from two different branches that share a common ancestor. Git attempts a three-way merge: it compares the common ancestor version of the file with the versions from both the HEAD (your current) branch and the incoming (the one you're merging) branch.
The key reasons for conflicts include:
- Direct Overlap: Both branches have modified the exact same lines of code, making it impossible for Git to automatically choose which change takes precedence.
- Deletion vs. Modification: One branch modified a section of code that another branch deleted entirely.
- File Renames: Sometimes, a file might be renamed in one branch and modified in another, leading to Git seeing it as two distinct files.
- Configuration Drift: In hosting environments, this often manifests when managing configuration files (e.g.,
.env, Nginx configs,systemdunit files) where different environments (dev, staging, prod) require slightly different values, and a change on one branch clashes with a manual adjustment or another branch's change on the same line.
When Git encounters such a scenario, it deliberately stops the merge process, marks the conflicted files, and relies on human judgment to resolve the ambiguity.
Step-by-Step Resolution
Follow these steps to systematically resolve Git merge conflicts on your Ubuntu 22.04 LTS system.
1. Assess the Conflict State
Before diving into editing, understand the scope of the problem.
# Display general status and unmerged files
git status
# View detailed differences for conflicted files, ignoring markers
git diff
# See a quick overview of commits involved in the merge
git log --merge
This initial assessment helps you identify all affected files and get a high-level view of the divergent changes.
2. Open and Understand Conflicted Files
Navigate to each file listed under "Unmerged paths" by git status and open it with your preferred text editor (e.g., nano, vim, vscode).
Examine the conflict markers:
<<<<<<< HEAD
// Your changes from the current branch (e.g., 'main')
=======
// Incoming changes from the branch being merged (e.g., 'feature/my-new-feature')
>>>>>>> feature/my-new-feature
<<<<<<< HEAD: Marks the beginning of the conflicting block from your current branch.=======: Acts as a separator between the two conflicting blocks.>>>>>>> <branch-name-or-commit-hash>: Marks the end of the conflicting block, indicating the source of the incoming changes.
3. Manually Edit the File to Resolve Conflicts
This is the most critical step. For each conflicted block in the file, you must decide:
- Keep
HEAD's changes: Delete the incoming changes and the markers. - Keep incoming changes: Delete
HEAD's changes and the markers. - Combine both: Carefully integrate relevant parts from both, ensuring the resulting code is correct and coherent, then delete all markers.
- Discard both: Replace the entire block with new, correct code, then delete all markers.
Example Resolution:
Using our src/app/web/index.js example:
// Before resolution
const serverPort = 3000;
function initializeApp() {
console.log("Application initializing...");
<<<<<<< HEAD
// Existing log for server startup on current 'main' branch
console.log(`Server starting on port ${serverPort} with basic logging.`);
setupBasicRoutes();
=======
// Feature branch added detailed logging and health check
console.log(`Web server launching on port ${serverPort}. Verbose logging enabled.`);
setupRoutes();
setupHealthCheckEndpoint();
>>>>>>> feature/my-new-feature
}
Let's assume we want to keep the detailed logging and health check from the feature/my-new-feature branch, but also ensure setupBasicRoutes() is called (if it contains essential base routes).
// After resolution (Combined approach)
const serverPort = 3000;
function initializeApp() {
console.log("Application initializing...");
// Integrated logic from both branches for comprehensive startup.
console.log(`Web server launching on port ${serverPort}. Verbose logging and health checks enabled.`);
setupBasicRoutes(); // Ensure base routes are always set up
setupRoutes();
setupHealthCheckEndpoint();
}
After resolving the conflict, you must remove all
<<<<<<<,=======, and>>>>>>>markers from the file. Leaving these markers will result in syntax errors, compilation failures, or unexpected application behavior. Ensure the resolved section is syntactically and logically correct.
Repeat this process for all conflicted files identified by git status.
4. Stage the Resolved File(s)
Once you've manually edited a file and removed all conflict markers, you need to tell Git that the file has been resolved and is ready to be included in the merge commit.
# Stage each resolved file
git add src/app/web/index.js
git add config/nginx/my-app.conf
# Check status again to confirm all conflicts are fixed
git status
git status should now show "all conflicts fixed but you are still merging." and the files under "Changes to be committed".
5. Commit the Merge
After all conflicted files are staged, you can finalize the merge.
git commit
Git will typically generate a default merge commit message, similar to:
Merge branch 'feature/my-new-feature' into main
# Conflicts:
# config/nginx/my-app.conf
# src/app/web/index.js
#
# It looks like you may be committing a merge.
# If this is not correct, please remove the file
# .git/MERGE_MSG
# and try again.
# Please enter the commit message for your changes. Lines starting
# with '#' will be ignored, and an empty message aborts the commit.
# On branch main
# All conflicts fixed but you are still merging.
#
# Changes to be committed:
# modified: config/nginx/my-app.conf
# modified: src/app/web/index.js
#
Review this message. It's often beneficial to add a more descriptive note about how the conflicts were resolved, especially for complex merges. Save and exit the editor to complete the commit.
After committing, the merge is complete. You can verify your repository history:
git log --oneline --graph --all
Optional: Using a Graphical Merge Tool
For highly complex conflicts or when dealing with many conflicted files, a graphical merge tool can significantly streamline the process. Git integrates with tools like meld, kdiff3, vscode, sublime merge, etc.
Configure a merge tool (if not already done):
git config --global merge.tool meld # Replace 'meld' with your preferred toolIf you're using VSCode:
git config --global merge.tool vscode git config --global mergetool.vscode.cmd 'code --wait --merge $LOCAL $REMOTE $BASE $MERGED' git config --global mergetool.vscode.trustExitCode falseLaunch the merge tool:
git mergetoolThis will open the merge tool for each conflicted file, presenting a visual interface to compare the
BASE,LOCAL(HEAD), andREMOTE(incoming) versions, and allowing you to construct theMERGEDoutput. After resolving a file in the tool, save it and close the tool.git mergetoolwill automaticallygit addthe file for you.
Graphical merge tools can greatly enhance productivity for large conflicts by providing a visual side-by-side comparison and automated merging options. However, always review the resulting file carefully after using an automated tool.
Optional: Aborting a Merge
If you find yourself overwhelmed by the conflicts, or decide that the current merge strategy is incorrect, you can abort the merge operation and revert your repository to its state before the merge attempt.
git merge --abort
Using
git merge --abortwill discard all changes made during the merge attempt, including any manual conflict resolutions you've performed that haven't been committed. Your working directory will be reset to the state it was in before you rangit merge. Use this command judiciously.
By following these steps, you can confidently navigate and resolve Git merge conflicts, ensuring your codebase remains consistent and deployments proceed smoothly on your Ubuntu 22.04 LTS systems.
Our Production Verification Guarantee
Encountering a bug not covered here or running a non-standard kernel configuration? Our solutions are continually refined against real production incidents. Submit an environment trace for our editorial team to replicate.