Search code examples
gitmergemeld

How to resolve conflicts with git merge without committing unwanted files?


I have a problem resolving a conflict with git merge. When I tried the command git merge branch_1 a conflict with a file appeared. I was able to succesfully resolve it using git mergetool with Meld. The problem is, after I have done it, I tried again to merge but it says that I have to commit my changes to conclude the merge. So before doing that I checked the git status and I found that there is a bunch of files in the staging area that I haven't modified. I guess those files where brought by the failed merge, but now how am I supposed to finish the merge without committing those files? Thanks!


Solution

  • I have a problem resolving a conflict with git merge. When I tried the command git merge branch_1 a conflict with a file appeared.

    This is normal enough. Remember that git merge branch_1 means:

    1. Identify the current commit (the tip of the current branch). I call this L for Left or Local or --ours (I know l does not appear in ours...).
    2. Identify one other commit (the tip of branch_1). I call this R for Right or Remote or otheR or --theirs.
    3. Find, automatically, a third commit. This third commit is the merge base and it's the point where the two branches first come back together:

                   o--L   <-- current_branch (HEAD)
                  /
      ...--o--o--B
                  \
                   o--R   <-- branch_1
      

      Commit B here is the merge base commit.

    4. Make two diffs. One finds out what we changed since the merge base:

      git diff --find-renames B L   # what we did
      

      and the other finds out what they changed since the merge base:

      git diff --find-renames B R   # what they did
      
    5. Combine the two change-sets found with the two git diff commands. Take one copy of each change to each file. Build up, for committing, a new set of files that are like what was in B, except that each line of each file that we changed in B-vs-L is changed, and each line of each file that they changed in B-vs-R is also changed.

    6. If none of these changes conflict, commit the result. Otherwise, stop and complain about the conflicting changes. Leave, ready to be committed, the non-conflicting files. Leave the conflicted files in conflicted state, ready for manual merging or merging using some sort of merge tool.

    I was able to succesfully resolve it using git mergetool with Meld.

    What git mergetool does is find the files left unmerged in step 6. In your case there was just one such file. Then git mergetool runs the tool on each such file, and if the tool claims that you have successfully resolved the conflict, git mergetool will add the file to the set of files ready to commit, thus resolving the conflict.

    [Git] says that I have to commit my changes to conclude the merge. So before doing that I checked the git status and I found that there is a bunch of files in the staging area that I haven't modified. I guess those files where brought by the failed merge,

    Those files were, in fact, successfully merged. (Well, at least Git thinks so. You might want to verify that what Git thinks is good, is really good, because Git is not very smart. :-) ) Note that git diff --cached will compare what's in the index, ready to be commited, vs what's in the current tip of the current branch.

    but now how am I supposed to finish the merge without committing those files?

    Normally you would want to include those staged, ready-to-commit changes in the files you're committing: they came from the B-vs-R changeset, and normally you should keep them.

    If you really shouldn't keep them, note that you can do anything you like to what's in the work-tree, and then git add the modified files to copy them into the index/staging-area so that whatever else you have done is also (or instead) included. You can even extract the version of any file that appears in any other commit, including the tip of your current branch.

    Whatever you put into the index/staging-area will be in the next commit. That's the definition of the index/staging-area. (Note that it doesn't hold changes, it holds files—copies of specific files. It's the act of comparing, with git diff, that shows you changes. Running git status is really running git diff.)