Branching, Merging, and Conflicts
Branching and merging are fundamental concepts in Git that enable parallel development and collaboration. They allow you to isolate work on new features, bug fixes, or experiments without affecting the main codebase. This section covers creating, switching, pushing, and merging branches, as well as how to resolve merge conflicts.
Branches
A branch represents an independent line of development. Think of it as a parallel version of your project. The default branch is usually main
(or sometimes master
). Branches allow you to work on different features or fixes concurrently without interfering with each other.
Creating and Managing Branches Locally
-
git branch
(List, Create, Delete)- Description: Manages branches locally. Used to list existing branches, create new branches, and delete branches.
-
Example Usage:
git branch # List all *local* branches. The current branch is marked with an asterisk (*). git branch my-new-feature # Create a new branch named 'my-new-feature' (but don't switch to it). git branch -d my-old-feature # Delete the branch 'my-old-feature' (only if it's fully merged). git branch -D my-old-feature # Force delete the branch 'my-old-feature' (even if it's not fully merged - BE CAREFUL!). git branch -a # List all branches: local and remote-tracking branches. git branch -vv # List local branches with verbose information, including the upstream branch (if set). git branch --merged # List branches that have been merged into the current branch. git branch --no-merged # List branches that have *not* been merged into the current branch.
-
git checkout
(Switch Branches / Create and Switch)- Description: Traditionally used to switch between branches. This updates your working directory to match the state of the selected branch. It can also create and switch to a new branch in one step.
-
Example Usage:
git checkout main # Switch to the 'main' branch. git checkout my-feature # Switch to the 'my-feature' branch. git checkout -b my-new-feature # Create a *new* branch named 'my-new-feature' AND switch to it (very common).
-
git switch
(Switch Branches - Recommended)- Description: A newer command (introduced in Git 2.23) specifically designed for switching branches. It’s more focused and less overloaded than
git checkout
, making its purpose clearer and reducing the risk of accidental errors. Usegit switch
for switching branches, andgit checkout
for working with files (e.g., discarding changes). -
Example Usage:
git switch main # Switch to the 'main' branch. git switch my-feature # Switch to the 'my-feature' branch. git switch -c my-new-feature # Create a *new* branch named 'my-new-feature' AND switch to it. (-c is short for --create)
- Description: A newer command (introduced in Git 2.23) specifically designed for switching branches. It’s more focused and less overloaded than
Pushing a Branch to a Remote Repository
To share your branch with others (or create a backup), you need to push it to a remote repository (like GitHub, GitLab, or Bitbucket).
-
Make sure you’re on the branch you want to push:
git switch your_branch_name
-
Commit any local changes.
-
Push the branch:
git push -u origin your_branch_name # The *first* time you push a new branch git push # On subsequent pushes (after setting the upstream with -u)
Explanation:
git push
: Uploads your local branch to the remote repository.-u origin your_branch_name
:-u
(or--set-upstream
): Sets the “upstream” tracking branch for your local branch. This creates an association between your local branch and a branch on the remote repository (usually namedorigin
). This simplifies future pushes and pulls. You only need to use-u
the first time you push a new branch.origin
: The name of the remote repository (by convention,origin
is the default name for the primary remote).your_branch_name
: The name of your local branch.
After setting the upstream, you can simply use
git push
andgit pull
without specifying the remote and branch name.
Merging a Branch
Merging combines the changes from one branch (the “source” branch) into another (the “target” branch). This is how you integrate the work done on a feature branch back into the main line of development.
-
Switch to the target branch (the branch you want to merge into):
git switch main # Typically, you merge feature branches *into* 'main'
-
Ensure your target branch is up-to-date:
git pull origin main # Get the latest changes from the remote 'main' branch
-
Merge the source branch:
git merge your_feature_branch # Merge 'your_feature_branch' into the current branch (which should be 'main')
-
(If there are no conflicts): Git will create a “merge commit” that combines the changes. Your editor will open to allow you to write a commit message (a default message is usually provided). Save and close the editor to complete the merge.
-
(If there are conflicts): Git will tell you which files have conflicts. You’ll need to manually resolve these conflicts (see the “Merge Conflicts” section below).
-
Push the merged changes (if working with a remote):
git push origin main
-
Delete the feature branch (optional, but good practice):
git branch -d your_feature_branch # Delete the local branch (safe if fully merged) git push origin --delete your_feature_branch # Delete the remote branch
Use
-d
to delete a branch only if it has been fully merged. If Git detects unmerged changes, it will prevent the deletion. Use-D
(uppercase) to force deletion, even if the branch has unmerged changes (use with caution!).
Merge Conflicts
A merge conflict occurs when Git cannot automatically merge changes because two branches have modified the same line(s) of the same file(s), or when one branch deletes a file that another branch modifies. Git needs your help to decide which changes to keep.
-
Identify Conflicting Files: After a failed merge attempt (
git merge
orgit pull
), Git will output a message indicating which files have conflicts:Auto-merging file.txt CONFLICT (content): Merge conflict in file.txt Automatic merge failed; fix conflicts and then commit the result.
You can also use
git status
to see a list of unmerged paths:git status # ... # Unmerged paths: # (use "git add <file>..." to mark resolution) # # both modified: file.txt
-
Open the Conflicting File(s): Open the conflicting file(s) in your text editor. Git has added special markers to show the conflicting sections:
<<<<<<< HEAD This is the content from the current branch (e.g., main). ======= This is the content from the branch you're merging in (e.g., feature_branch). >>>>>>> feature_branch
Marker Explanation:
<<<<<<< HEAD
: Beginning of the changes from your current branch (HEAD
).=======
: Separator between the changes from the two branches.>>>>>>> feature_branch
: End of the changes from the other branch (the branch name or commit hash will be shown).
-
Resolve the Conflict: Edit the file to decide how to combine the changes. You have several options:
- Keep your changes (HEAD): Delete the lines from the other branch and all the conflict markers.
- Keep the other branch’s changes: Delete the lines from your current branch (
HEAD
) and all the conflict markers. - Combine the changes: Edit the file to create a new, merged version that incorporates parts of both versions. Remove all conflict markers.
- Rewrite the section: If neither version is suitable, rewrite the entire section. Remove all conflict markers.
After resolving the conflict, the file should look like normal code, with no Git conflict markers.
-
Stage the Resolved File(s): After resolving conflicts in a file, stage it using
git add
:git add file.txt # Stage the resolved 'file.txt' git add . # Stage *all* resolved files
-
Commit the Resolution: Create a commit to finalize the merge. This commit records how you resolved the conflicts.
git commit # Opens your editor to create a commit message
Or, for a one-line message:
git commit -m "Resolved merge conflict in file.txt"
It is not necessary to add the file name to the commit message, but it can improve readability.
-
Push (If Applicable): If working with a remote repository,
push
your changes after resolving conflicts and committing.git push origin main
Merge Conflict Tools and Strategies
-
Visual Merge Tools: For complex conflicts, visual merge tools can be invaluable. They offer a graphical interface to compare conflicting versions and select changes.
- meld (cross-platform, open-source)
- Beyond Compare (commercial, cross-platform)
- KDiff3 (cross-platform, open-source)
- Visual Studio Code (built-in merge conflict resolution)
- IntelliJ IDEA / PyCharm / WebStorm (built-in)
- …and many others
Configure Git to use your merge tool:
git config --global merge.tool meld # Example using meld git mergetool # Open the configured merge tool
-
git merge --abort
: If you get stuck or make a mistake during conflict resolution, you can abort the merge withgit merge --abort
. This returns your working directory and index to the state they were in before you started the merge. It’s a safe way to “undo” a problematic merge. -
git checkout --ours
/git checkout --theirs
(Use with CAUTION): These commands provide a shortcut for accepting either your version (--ours
) or the other branch’s version (--theirs
) of an entire file during a conflict.git checkout --ours path/to/file.txt
: Keep your version offile.txt
.git checkout --theirs path/to/file.txt
: Keep the other branch’s version.
Use these commands only when you’re absolutely sure you want to completely discard one version of the file. They are not suitable for combining changes.
- Communication: If working on a team, communicate with the other developer(s) involved to understand their changes and agree on the best resolution.
- Testing: Always thoroughly test your code after resolving merge conflicts to ensure that the merged code works correctly and that no bugs were introduced.