Git Merge Concept :
Git merge is a command used in Git to combine the changes from two different branches into
one. It allows you to bring together the history of two separate branches into a unified branch.
Here's how it works:
Merge a feature branch into the main branch: If you're working on a feature branch
and have completed your changes, you can merge it back into the main branch (like main
or master).
Merge Commit: Git creates a new "merge commit" that ties together the histories of the
merged branches.
Handling Conflicts: If there are conflicting changes (i.e., the same lines of code were
modified in both branches), Git will ask you to resolve the conflicts before completing
the merge.
Lab
1. Switch to the target branch: git checkout main
2. Merge the feature branch into the main branch: git merge feature-branch
3. Resolve conflicts (if any), and commit the changes.
4. Push the merged changes to the remote repository: git push origin main
Merge Conflict Concept:
Merge conflicts occur when Git is unable to automatically combine changes from two different
branches due to conflicting changes in the same part of a file. This usually happens when:
Two developers modify the same line in the same file on different branches.
One developer deletes a file that another developer has modified.
There are overlapping changes in the same section of a file, and Git can't determine
which change should take priority.
How merge conflicts happen:
When you try to merge two branches and Git detects conflicts, it will stop the merge process and
mark the affected files as having conflicts. You'll need to resolve these conflicts manually before
proceeding.
Example:
Let's say you have two branches- main and feature
On the main branch, a developer changes the line in [Link] from:
Hello, world to: Hello, Git!
On the feature branch, a different developer changes the same line in [Link] to:
Hello, Merge!
When you try to merge feature into main, Git will detect a conflict in [Link] because it
doesn't know whether to use "Hello, Git!" or "Hello, Merge!" — this is where a merge conflict
occurs.
Resolving Merge Conflicts:
1. Identify the conflicting files: Git will mark the conflicting files, usually with <<<<<<<,
=======, and >>>>>>>.
o <<<<<<< HEAD shows the changes from the current branch.
o ======= separates the changes.
o >>>>>>> feature shows the changes from the branch you're merging.
2. Resolve the conflict: Manually edit the file to choose which changes to keep, or combine
the changes. Remove the conflict markers (<<<<<<<, =======, >>>>>>>).
Mark the conflict as resolved: After resolving the conflict, add the file to the staging
area using: git add [Link]
Complete the merge: After all conflicts are resolved and staged, complete the merge with a
commit: git commit
Push the changes: Finally, push the merged changes to the remote repository: git push origin
main
Conditions when git Conflict occurs :
A Git merge conflict occurs when Git is unable to automatically merge changes from two
branches because it encounters conflicting modifications in the same part of a file. This usually
happens when:
1. Changes to the Same Line of Code:
When two branches modify the same line of code in a file, Git won't know which change
to keep.
Example:
In branch A, you modify the line:
print("Hello, world!")
In branch B, you modify the same line to:
print("Hello, Git!")
When merging, Git can't decide which version to keep, causing a conflict.
2. File Deletions:
If one branch deletes a file, but the other branch modifies the same file, Git will conflict
because it doesn't know if the file should be deleted or merged.
Example:
In branch A, you delete [Link].
In branch B, you modify [Link].
When merging, Git will report a conflict because the file was deleted in one branch but
edited in the other.
3. Simultaneous Modifications to Different Parts of the Same File:
If both branches modify different parts of the same file, Git may be able to merge them
automatically. However, if the changes are near each other, Git might struggle to merge
the changes without a conflict.
Example:
In branch A, you add a line at the beginning of a file.
In branch B, you add a line at the end of the file.
Git may merge this automatically without a conflict, but if the changes overlap or are
near each other, it could cause a conflict.
4. Renaming the Same File in Both Branches:
If two branches rename the same file differently, Git won't be able to decide which new
name to use.
Example:
In branch A, you rename [Link] to [Link].
In branch B, you rename [Link] to [Link].
Git can't automatically merge these changes, and a conflict occurs.
5. Changes to the Same Path or Directory:
If both branches make changes to the same directory or file path in different ways, such
as moving files around in the directory, Git may not know how to combine those changes
without a conflict.
When Merge Conflicts Do Not Occur:
Git will successfully merge changes if they happen in separate files, separate parts of
the same file, or if one branch modifies a file while the other branch doesn't touch it.
Techniques to avoid git conflicts
1. Frequent Pulls and Updates:
Pull changes often: Regularly pull the latest changes from the remote repository to stay
updated. This reduces the chances of major conflicts when merging later.
Rebase instead of merge: Before pushing your changes, use git rebase to apply your
changes on top of the latest branch. This keeps your branch history linear and reduces the
likelihood of conflicts.
git fetch origin
git rebase origin/main
2. Small, Focused Commits:
Break your work into smaller, manageable tasks and make frequent commits with
clear, specific messages. This helps others review your changes easily and reduces the
risk of overlapping changes.
3. Communicate with Your Team:
Coordinate with team members: Before working on a feature, especially if it’s large or
involves shared files, discuss with your team to avoid duplicating efforts.
Branching conventions: Adopt a clear branching strategy like Git Flow or Feature
Branching to avoid confusion about which branch to work on.
4. Work in Feature Branches:
Always create a separate branch for your work, instead of making changes directly on
the main branch. This allows you to isolate your changes and only merge when your
work is complete and ready to be shared.
5. Merge Often, Don't Wait:
Regularly merge changes from the main branch into your feature branch. This keeps your
branch up to date and helps you catch conflicts early, rather than waiting until the end
when the conflict might be larger and harder to resolve.
git fetch origin
git merge origin/main
6. Lock Critical Files:
If you're working with critical files (e.g., configuration files or deployment scripts), try to
lock or restrict who can modify them. Alternatively, you can make the changes to these
files in isolation to avoid conflicts with others.
7. Use Git Hooks for Consistency:
Use pre-commit hooks to enforce code style or formatting checks before committing,
ensuring that developers follow consistent coding practices and reducing unnecessary
differences between branches.
8. Resolve Conflicts Early:
If you do encounter a conflict, resolve it as soon as possible. Don't wait until the last
minute to address it, as it could cause bigger issues during the merge.
9. Avoid Large Merges:
Don't leave large features or changes for a long time before merging. A large merge is
more likely to result in conflicts. Instead, try to merge small changes regularly, even if
they aren't feature-complete.
10. Automated Testing:
Implement automated tests (like unit tests, integration tests, and continuous integration)
to quickly identify issues as soon as they arise. This can alert you to problems during
merges, reducing the risk of broken code.
11. Use Merge Tools:
If conflicts are inevitable, use Git’s built-in merge tools (like git mergetool) or third-party
merge tools (such as Meld, KDiff3, or P4Merge) to make resolving conflicts easier and
faster.
12. Avoid Force Pushing:
Avoid using git push --force unless absolutely necessary. Force pushing can overwrite
other people's work and cause additional merge headaches.
GIT Rebase Concept
Git rebase is a command used in Git to move or combine a sequence of commits to a new
base commit. It is an alternative to merging and is typically used to maintain a cleaner,
more linear project history.
What does Git rebase do?
When you rebase, Git applies the changes from your current branch on top of another branch
(usually the latest version of the main branch or the branch you’re working on). This process
rewrites the commit history, making it appear as though your changes were made on top of
the latest code.
Why use rebase?
Linear history: Rebase creates a linear history without merge commits, which makes
the project history easier to read and understand.
Avoid merge commits: When you use rebase, you avoid the extra merge commits
that happen during a merge. This is especially useful when you're working on a
feature branch and want to integrate changes from the main branch without creating
extra commits.
Example Scenario:
Let’s say you have two branches:
main: the base branch.
feature: the branch you are working on.
Before rebase:
main: A---B---C
feature: D---E---F
You are working on feature and want to update it with the latest changes from main.
Rebase the feature branch onto main:
git checkout feature //here we moved to feature branch
git rebase main
This takes the changes from feature (commits D, E, and F) and re-applies them on top of
the latest commit in main.
After rebase:
main: A---B---C
feature: D'---E'---F'
The commits D, E, and F are now rewritten as D', E', and F' on top of the latest commit from main.
This results in a linear history.
LAB Session
Steps to use rebase:
1. Check out your branch:
Make sure you’re on the branch that you want to rebase (e.g., the feature branch).
git checkout feature
Fetch the latest changes from the remote repository:
Always ensure you’re working with the most up-to-date code.
git fetch origin
Rebase your branch onto the target branch:
Typically, you rebase onto main or the branch you want to integrate with.
git rebase main
Resolve any conflicts (if any):
If Git encounters conflicts during the rebase, it will pause and let you resolve them. After
resolving conflicts, you need to add the changes and continue the rebase:
git add <conflicted_files>
git rebase --continue
Push the rebased changes:
If you’re pushing to a remote repository, you may need to force push if the history has been
rewritten:
1. git push origin feature --force-with-lease
2. Note: Be cautious when using --force-with-lease, as it rewrites history on the remote.
It’s safer than using --force because it only forces the push if your local copy is up to
date with the remote.
Gist :
Work on your feature branch: You're working in the feature branch, making your
changes.
Get the latest code from the main branch: You fetch the latest changes from the main
branch from the remote repository. This makes sure you're aware of any new changes made by
others in the main branch.
Rebase your feature branch onto the main branch: This step applies your feature branch
changes on top of the latest changes from the main branch. It's like saying, "Take my changes
and apply them after the most recent updates from the main branch."
This process will update your feature branch with the latest code from the main branch, keeping
your work up-to-date without adding extra merge commits.
Git rebase conflicts Concept
Git rebase conflicts occur when Git is unable to automatically apply changes from one branch
onto another during a rebase operation. This happens when there are overlapping changes
between the commits you are rebasing and the target branch (usually main or master).
How Git Rebase Conflicts Happen:
When you rebase your branch (e.g., feature) onto another branch (e.g., main), Git tries
to replay your changes from the feature branch on top of the latest changes from the main
branch.
If Git detects that the changes made in your branch and the changes in the target branch
(main) are in the same part of the file (e.g., same line or same block of code), it won't
know which change to keep.
This creates a conflict, and Git will pause the rebase process, asking you to resolve the
conflict manually.
Example of How Rebase Conflict Happens:
Let's say you have two branches:
main: the target branch.
feature: the branch you're working on.
1. On the main branch, someone changed this line of code:
print("Hello, world!") to: print("Hello, Git!")
On the feature branch, you also changed the same line to:
1. print("Hello, Rebase!")
Now, when you try to rebase the feature branch onto main, Git finds the same line changed in
both branches and doesn't know whether to use "Hello, Git!" or "Hello, Rebase!". This is a
rebase conflict.
Resolving a Git Rebase Conflict:
1. Git will stop and notify you of the conflict.
2. You need to manually resolve the conflict by editing the conflicted files.
Git will mark the conflicted areas in the file like this:
<<<<<<< HEAD
print("Hello, Git!")
=======
print("Hello, Rebase!")
>>>>>>> feature
The code between <<<<<<< HEAD and ======= is from the target branch (e.g., main).
The code between ======= and >>>>>>> feature is from your feature branch.
Edit the file to decide which changes to keep. You can either:
Keep one change.
Merge the changes manually.
Choose the latest update.
After making the decision, the code should look like:
print("Hello, Rebase and Git!")
Mark the conflict as resolved:
After fixing the conflict, stage the file for commit by using:
git add <file>
Continue the rebase:
Once all conflicts are resolved, continue the rebase operation:
1. git rebase --continue
2. If there are more conflicts, Git will stop again and ask you to resolve them. Repeat the
process until the rebase is complete.
What Happens After Resolving Conflicts:
After resolving all conflicts and completing the rebase, your feature branch will have the
latest changes from main applied first, followed by your feature branch changes.
Your branch history will be linear without the need for an additional merge commit, as if
your changes were made after the latest changes from the main branch.
Difference git merge and git rebase
Git Merge and Git Rebase are both used to integrate changes from one branch into another, but
they handle conflicts in different ways. Here's a breakdown of the differences between merge
conflicts and rebase conflicts:
1. When Do Conflicts Happen?
Git Merge Conflicts:
o Occur when you attempt to merge two branches, and there are conflicting changes
in the same file or part of the code that Git can't automatically resolve.
o Example: You merge a feature branch into main, and both branches modified
the same line of code in a file.
Git Rebase Conflicts:
o Occur when you rebase one branch (e.g., feature) onto another (e.g., main), and
Git can't automatically apply the commits from your feature branch on top of the
changes from the target branch.
o Example: You try to rebase feature onto main, and there are conflicting changes
in the same file on both branches.
2. Conflict Context
Git Merge:
o Conflicts happen at the point of merging the branches. Git tries to merge the
histories and changes of the two branches together. If there’s a conflict, Git will
try to merge the changes in a way that doesn't break the code, but if it can't, you
have to resolve it manually.
o Outcome: A merge commit is created that brings together the histories of both
branches.
Git Rebase:
o Conflicts happen during the rebase process when Git attempts to apply each
commit from your branch onto the target branch (usually main). If Git encounters
conflicting changes, it will stop and ask you to resolve them before continuing the
rebase.
o Outcome: The commits from your branch are re-applied on top of the target
branch, rewriting the commit history.
3. Commit History
Git Merge:
o Creates a merge commit that ties the histories of the two branches together. After
a merge, the commit history will show both branches coming together at the
merge point.
o The history looks like a branching tree, showing both branches diverging and
then coming together at the merge commit.
Git Rebase:
o Rewrites the commit history by reapplying the commits from your branch on top
of the target branch. This results in a linear history.
o The commit history is cleaner and doesn’t have extra merge commits, but it can
change the commit hashes, which can affect collaboration if other developers
have already pulled your branch.
4. Conflict Resolution Flow
Git Merge Conflicts:
o When you merge and there’s a conflict, Git stops and marks the files with
conflicts. You resolve the conflicts, then commit the changes, and a new merge
commit is created.
o The conflict resolution process happens after the merge (i.e., after merging both
branches), and you can continue working after resolving conflicts.
Git Rebase Conflicts:
o When you rebase, Git stops when it encounters a conflict and requires you to
resolve the conflict before proceeding with the rebase.
o You resolve the conflict and continue the rebase with git rebase --continue.
If there are multiple commits in your branch, Git will continue applying the rest
of your commits one by one until all conflicts are resolved.
5. Handling Conflict History
Git Merge:
o Merge conflicts create a merge commit, which is added to the project’s history.
This helps you see the point where branches were merged but also introduces
extra merge commits into the history.
o Example: The history will show something like:
A---B---C---M (merge commit)
\ /
D---E (feature)
Git Rebase:
Rebase conflicts do not create a merge commit, but they rewrite the commit history.
After resolving the conflicts, your changes are applied on top of the main branch as new
commits with new commit hashes.
Example: The history after rebase will look like:
o A---B---C (main)
o \
o D'---E' (feature)
o
6. Use Case and Best Practice
Git Merge:
o Best used when you want to combine two branches while preserving the full
commit history and showing where the merge happened.
o It’s ideal for collaborative workflows where multiple people work on the same
branch, as it doesn’t rewrite history.
Git Rebase:
o Best used when you want to keep a cleaner, linear commit history without
merge commits, especially in feature development.
o It’s ideal for solo development or before merging your feature branch back into
main to make the history look cleaner and easier to read.