Documentation/content/collaborating/resolve-conflicts.md
Jan Klippel 5a1fdc201e
Article on conflict resolution
Initial version of an article on conflict resolution

Fixes: #14
2022-05-28 16:30:19 +02:00

11 KiB

eleventyNavigation
key title parent order
ResolveConflicts Resolve Conflicts Collaborating 60

When collaborating with others on a big project, sometimes the situation occurs that a change of someone conflicts with another change introduced in the meantime (e.g by another person).

First of all: Do not panic! You should be able to resolve merge conflicts with a little time, Git and patience.

While it is a good idea to rebase your branch prior to creating a pull request, as described in the article on Pull requests and Git flow sometimes merge conflicts are unavoidable.

This article will try to explain what to do in case of a merge conflict and how to resolve the conflicts using the command line.

Unfortunately Gitea currently does not provide a GUI to resolve conflicts.

An upstream issue https://github.com/go-gitea/gitea/issues/9014 already exists asking for this feature.

If you want to skip the setup of the examples, you can skip to the sections explaining the resolutions:

Example of a conflict and its resolution

To easier understand the steps to be taken during the resolution of a conflict, lets actually create an example of such a conflict:

Clone example repository

This example uses Knut's example repository. Let us create a clone of Knut's examples repository for this example:

git clone git@codeberg.org:knut/examples.git
cd examples

We will not change anything on the main-branch just now.

Set up a branch with a first change

So we create another branch with our first commit:

git switch -c add-link-to-readme

In the README.md file we change the following line:

An example repository for Codeberg Docs.

to

An example repository for [Codeberg Docs](https://docs.codeberg.org).

Now we add the change to our branch:

git add README.md
git commit -m "Added link to Codeberg docs to README" 

We will leave the branch and not merge it into main just now.

Setup branch with another change

Now we create another branch based on main and edit the README.md file in a different way:

git switch main
git switch -c update-last-sentence-in-readme

Again we change the last line, this time we adjust the text slightly:

From

An example repository for Codeberg Docs.

To

An example repository to use with the Codeberg Documentation.
git add README.md
git commit -m "Adjusted last sentence in README"

We now have two branches with conflicting changes to the same line:

git switch main
git branch
  add-link-to-readme
* main
  update-last-sentence-in-readme

Merging the first branch

Now let us assume we want to merge the branches into the main branch.

First we merge the branch named "add-link-to-readme". As this is a simple change to a yet unchanged main-branch, there is no conflict.

git switch main
git merge add-link-to-readme

Trying to merge the second branch

Now the second branch is merged:

git merge update-last-sentence-in-readme

As expected there is a conflict:

$ git merge update-last-sentence-in-readme
Auto-merging README.md
CONFLICT (content): Merge conflict in README.md
Automatic merge failed; fix conflicts and then commit the result.

Issuing a git status show us that there are unmerged paths.

❱ 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:   README.md

no changes added to commit (use "git add" and/or "git commit -a")

Issuing git diff shows the conflict:

diff --cc README.md
index 616dc84,088249f..0000000
--- a/README.md
+++ b/README.md
@@@ -1,3 -1,3 +1,7 @@@
  ![](https://docs.codeberg.org/assets/images/getting-started/knut.svg)
  
++<<<<<<< HEAD
 +An example repository for [Codeberg Docs](https://docs.codeberg.org).
++=======
+ An example repository to use with the Codeberg Documentation.
++>>>>>>> update-last-sentence-in-readme

You have to resolve this conflict manually. As Git cannot know how the resulting line should look like.

Resolving the conflict

Use your editor of choice and open the file. The editor will show you the conflict as well as Git actually added the conflict description into the README.md file.

The end of the file now looks like this:

<<<<<<< HEAD
An example repository for [Codeberg Docs](https://docs.codeberg.org).
=======
An example repository to use with the Codeberg Documentation.
>>>>>>> update-last-sentence-in-readme

The conflict description start with <<<<<<< HEAD. The next line shows you, that the current HEAD (the last commit on the main-branch before we typed in git merge update-last-sentence-in-readme) was:

An example repository for [Codeberg Docs](https://docs.codeberg.org).

The next line ======= seperates the current line from the line proposed in the branch that is to be merged.

An example repository to use with the Codeberg Documentation.

The last line >>>>>>> update-last-sentence-in-readme concludes the conflict description and tells you that the line(s) before are taken from the branch update-last-sentence-in-readme.

Use your editor of choice and change the line to reflect the changes you wish to commit to the repository after resolution of the conflict.

Remove all other lines. The file should be in the form that you want to commit to the main branch.

A possible resolution of this conflict could be:

An example repository to use with the [Codeberg Documentation](https://docs.codeberg.org).

Calling git diff README.md shows the new line was added and the two conflicting lines were removed:

diff --cc README.md
index 616dc84,088249f..0000000
--- a/README.md
+++ b/README.md
@@@ -1,3 -1,3 +1,3 @@@
  ![](https://docs.codeberg.org/assets/images/getting-started/knut.svg)
  
- An example repository for [Codeberg Docs](https://docs.codeberg.org).
 -An example repository to use with the Codeberg Documentation.
++An example repository to use with the [Codeberg Documentation](https://docs.codeberg.org).

You can now mark the conflict to be resolved by calling git add README.md.

If you have more than one conflict in one or more files, repeat the resolution process until all conflicts are resolved.

Make sure not to leave any lines starting with <<<<<<<, ======= and >>>>>>> as Git does no longer know that these are special and will treat these as normal text.

Issuing git commit (without any further comment) will open the default editor and lets you edit a commit-message for the merge commit. Closing the editor will conclude the resolution of the merge conflict.

Note: git log shows you both the original commit that lead to the conflict and the merge commit.

For example (hashes will vary on your system):

commit c10f2c3338979149d7c6fcb815a2072743b5bde6 (HEAD -> main)
Merge: 5e2cebd 7b5bf4f
Author: Knut <knut@...>
Date:   Sat May 21 19:44:43 2022 +0200

    Merge branch 'update-last-sentence-in-readme' into main

commit 7b5bf4f0fe2213ded938bc9de313f4cd3d9043db (update-last-sentence-in-readme)
Author: Knut <knut@...>
Date:   Sat May 21 18:38:16 2022 +0200

    Adjusted last sentence in README

commit 5e2cebd523754b655d1990fb48dbb7b973f07dfa (add-link-to-readme)
Author: Knut <knut@...>
Date:   Sat May 21 18:29:15 2022 +0200

    Added link to Codeberg docs to README
    

Note the line starting with Merge which includes the commit-ids of the two merged commits.

Removed files

Let us create another conflict.

We start again at the main-Branch. If you did not work through the example above, you can jump start the environment for this example with these commands:

git clone git@codeberg.org:knut/examples.git
cd examples

If you still have a checkout from the last example, make sure that you start this example on the main branch git switch main.

Removing a file

Again we create a new branch.

git switch -c remove-README-file

This time we remove the README.md file.

git rm README.md
git commit -m "removed README.md"

We do not merge this branch yet.

Editing the file

First switch back to the main branch.

git switch main

On second branch we add a line to the end of the README.md file.

git switch -c adapt-README-file
echo "You can find this repository in the Gitea Web GUI at https://codeberg.org/knut/examples" >> README.md
git add README.md
git commit -m "added repository url to README.md"

Merging the first branch

Again switch back to the main branch.

git switch main

Merging the first branch does not lead to a conflict, because the main-Branch did not change since the branch "remove-README-file" was created.

git merge remove-README-file

Conflict and resolution

When we try to merge the second branch "adapt-README-file", we get a conflict because the file README.md we are trying to change was removed by our previous merge.

$ git merge adapt-README-file
CONFLICT (modify/delete): README.md deleted in HEAD and modified in adapt-README-file.  Version adapt-README-file of README.md left in tree.
Automatic merge failed; fix conflicts and then commit the result.

A call to git status also shows the conflict:

$ 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/rm <file>..." as appropriate to mark resolution)
	deleted by us:   README.md

no changes added to commit (use "git add" and/or "git commit -a")

You now have two choices:

  • Either to keep the current status and remove the README.md file
  • or to re-introduce the README.md file into the main-branch.

To keep the current status and remove the README.md file, you must tell Git once more to remove it:

git rm README.md

To re-introduce the README.md file simply add it again:

git add README.md

Use git commit if you finished the resolution of all conflicts (in this case it was only one).

Issuing git commit (without any further comment) will open the default editor and lets you edit a commit-message for the merge commit. Closing the editor will conclude the resolution of the merge conflict.

Note: git log shows you both the original commit that lead to the conflict and the merge commit.

Tips

  • Try to avoid using git push -f on the target branch.
  • Ensure that all branches are pushed to a remote repository before trying to resolve a conflict. It makes it easier to start over in case you run into a problem.
  • Search for <<<<<<<, ======= and >>>>>>> in the resolved files, to not leave a conflict description artefact in your files.