Basics of branch merging (git merge)
Branch Merging Basics (git merge)
Branch merging in Git is the process of integrating the history of two or more branches. Merge operations allow developers to combine changes from different branches into a unified history line, which is very common in team collaboration and feature development.
Basic Concepts of Merging
There are two main types of merges in Git: fast-forward merges and three-way merges. When the branch to be merged is a direct descendant of the current branch, Git performs a fast-forward merge; otherwise, it performs a three-way merge.
Fast-forward merge example:
A---B---C (main)
\
D---E (feature)
If the main
branch merges the feature
branch, Git simply moves the main
pointer to commit E.
A three-way merge occurs when branch histories diverge:
A---B---C (main)
\
D---E (feature)
If the main
branch has a new commit F after C:
A---B---C---F (main)
\
D---E (feature)
In this case, a new merge commit is required.
Merge Conflicts and Their Resolution
When two branches modify the same part of the same file, Git cannot automatically decide which change to keep, resulting in a merge conflict. Conflicted files are marked as "unmerged."
Conflict marker example:
<<<<<<< HEAD
const greeting = 'Hello from main branch';
=======
const greeting = 'Hi from feature branch';
>>>>>>> feature
Steps to resolve conflicts:
- Open the conflicted file
- Decide which version to keep or manually merge the changes
- Remove the conflict markers (
<<<<<<<
,=======
,>>>>>>>
) - Use
git add
to mark the conflict as resolved - Complete the merge commit
Merge Strategies
Git provides several merge strategies, commonly used ones include:
- recursive: Default strategy for handling three-way merges
- resolve: Similar to recursive but only handles two branches
- octopus: Used for merging multiple branches
- ours: Keeps the current branch's content and discards changes from other branches
- subtree: Adjusts directory structures during merging
Syntax for specifying a merge strategy:
git merge -s <strategy> <branch>
Practical Merge Example
Assume we have a simple JavaScript project to demonstrate the merge process:
- Create and switch to a new branch:
git checkout -b feature/login
- Modify a file on the
feature/login
branch:
// auth.js
function login(username, password) {
console.log('Login attempt for:', username);
// Validation logic
}
- Switch back to the
main
branch and modify the same file:
// auth.js
function login(user) {
console.log('Trying to login:', user.name);
// Validation logic
}
- Attempt to merge:
git merge feature/login
A conflict will occur, requiring manual resolution:
function login(user, password) {
console.log('Login attempt for:', user.name);
// Validation logic
}
Best Practices for Merging
- Ensure the working directory is clean before merging
- Frequent merges reduce the complexity of conflicts
- Use
git merge --no-ff
to force a merge commit - Run tests before merging to ensure code quality
- Use graphical tools for complex merges
Advanced Merge Techniques
- Aborting a merge: If conflicts cannot be resolved, abort the merge process:
git merge --abort
- Skipping conflicted files: Temporarily skip conflicts for specific files:
git checkout --ours <file>
git checkout --theirs <file>
- Redoing a merge: If the merge result is unsatisfactory, reset and retry:
git reset --hard HEAD^
git merge <branch>
- Merging specific files: Merge only specific files from another branch:
git checkout <branch> -- <file>
Differences Between Merging and Rebasing
Although both merging and rebasing integrate branch changes, they differ fundamentally:
- Merging preserves the original commit history and creates a new merge commit
- Rebasing rewrites commit history to make it more linear
- Merging is better suited for public branches, while rebasing is better for local branches
Example rebase command:
git checkout feature
git rebase main
Viewing Merge Logs
To view merge history, use:
git log --merges
To view the topology of all branches:
git log --graph --oneline --all
Merge Hooks and Automation
Git hooks can be used to execute custom scripts before or after merging, such as:
- Adding a check script in
.git/hooks/pre-merge
- Adding a deployment script in
.git/hooks/post-merge
Example pre-merge
hook:
#!/bin/sh
npm test
if [ $? -ne 0 ]; then
echo "Tests failed, aborting merge"
exit 1
fi
Merge Strategies in Team Collaboration
Common merge strategies in team development include:
- Trunk-based development: Frequent merges into the main branch
- Feature branches: Each feature has its own branch, merged upon completion
- Git Flow: A strict branching model with
develop
,feature
,release
, etc. - GitHub Flow: A simplified workflow based on Pull Requests
Merge Performance Optimization
For large repositories, merging can be time-consuming. Try:
- Using shallow clones to reduce data:
git clone --depth=1 <repo>
- Enabling filesystem caching:
git config --global core.fscache true
- Using sparse checkout:
git config core.sparsecheckout true
echo "src/" >> .git/info/sparse-checkout
git read-tree -mu HEAD
Merging and Continuous Integration
In CI/CD pipelines, merging often triggers builds and tests:
Example GitLab CI configuration:
merge_request:
script:
- npm install
- npm test
only:
- merge_requests
Graphical Tools for Merging
In addition to the command line, graphical tools can be used for merging:
- GitKraken
- SourceTree
- GitHub Desktop
- VS Code's Git extension
These tools typically provide intuitive conflict resolution interfaces, making them suitable for complex merge scenarios.
本站部分内容来自互联网,一切版权均归源网站或源作者所有。
如果侵犯了你的权益请来信告知我们删除。邮箱:cc@cccx.cn