After a Git merge conflict, a lot of files I didn't touch become changes to be committed

旧时模样 提交于 2019-11-26 20:32:24

问题


So I'm working in a branch, make some changes, and run git merge master. I get a merge conflict on one of the files I modified (which I know how to deal with), but for some reason, a bunch of files I did not touch (but which got updated in master) suddenly enter my list of "Changes to be committed".

Why is this? And how do I fix this? I don't want any of these not-by-me changes to get committed.


回答1:


When you attempt a merge, all files that can be automatically merged (e.g. where you don't have any changes in your local branch but which have been modified on the source branch), are automatically merged and staged. Files which could not be automatically merged are updated in your working area with conflict markers and you have to fix them.

Git always assembles new commits in the staging area before committing them. The merge does the same thing. A new commit with all the changes from the source branch is created in the staging area. In case of a conflict, this process of updating the staging area is interrupted and control is given to you. That's why this happens. Once you commit, a "merge commit" will get created in the repository that has both the source and target branches as parents.

As for " I don't want any of these not-by-me changes to get committed.", why did you do a merge at all if you don't want any changes?




回答2:


I think the problem with this GIT way of doing things is that after the commit, a "push" will be performed. The "push" will include all committed files - including files that the "pusher" didn't touch. This makes tracking changed very complicated.




回答3:


The reason this happened is because you most likely did the opposite of what you were intending to do.

Let's suppose your working branch is called topic-branch.

Instead of doing:

$ git merge master

you could have done:

$ git checkout master
$ git merge topic-branch

In English, instead of merging the master branch into topic-branch you could have merged topic-branch into master.

To understand why this achieves the desired result we can examine the statement made in a previous answer:

When you attempt a merge, all files that can be automatically merged (e.g. where you don't have any changes in your local branch but which have been modified on the source branch), are automatically merged and staged.

The problem you are having is simply merge trying to do its job. The files aren't changed in your topic branch, but they are on the branch you are merging into it. If you look at this in the opposite direction of merging the topic-branch into master the problem goes away because it only considers the files you've modified.

Conceptually, here is what merge is doing (more here):

Let the current head be called current, and the head to be merged called merge.

  1. Identify the common ancestor of current and merge. Call it ancestor-commit.
  2. Deal with the easy cases. If the ancestor-commit equals merge, then do nothing. If ancestor-commit equals current, then do a fast forward merge.
  3. Otherwise, determine the changes between the ancestor-commit and merge.
  4. Attempt to merge those changes into the files in current.
  5. If there were no conflicts, create a new commit, with two parents, current and merge. Set current (and HEAD) to point to this new commit, and update the working files for the project accordingly.
  6. If there was a conflict, insert appropriate conflict markers and inform the user. No commit is created.



回答4:


I encountered the same problem myself, and came up with an intermediate solution. Need to find a better one down the road.

First to address the question posed by @NoufalIbrahim: As for " I don't want any of these not-by-me changes to get committed.", why did you do a merge at all if you don't want any changes?

You have misunderstood @grautur intention. The changes are needed, but not as part of a new commit. For example, 1 file was added locally, 100 files came from merge. The new commit should have 1 changed file and not 101 changed file. This is especially important if an automatic merge is not possible, but a pull request is initiated and someone has to review the commit. You want the reviewer to review 1 file, not 101 files.

What I am currently doing is this: let's say we have branch 'master' and 'feature'. 'feature' is created from 'master' and I only make changes to files in 'feature'. When new changes are pulled into 'master', git merge master inside 'feature' will introduce new files (and these are staged automatically in VSCode, which is the IDE I use).

What I do next is unstage all of these files. Basically ignore them. Only add and commit files that I change. Push 'feature' to origin/remote repo, create pull request. When request is accepted and commit is merged to the main branch, delete 'feature' locally and remotely. Pull changes to 'master' local and create a new branch to work on new feature. This new branch will not have a bunch of unstaged files.

There could a git command to tell the git to ignore a bunch of files without using .gitignore. Doing further research into this.




回答5:


Where I find this pop up is if I:

1) create, and work on a branch (b1)

---m
    \
     b1

---m
    \
      ---b1

2) create a new branch (b2) from b1, during which time someone else makes changes to completely unrelated code in master

----------------m
    \
      ---b1
          \
           b2

3) go back and make some changes to b1, and then pull b1 into master.

----------------m
    \          /
      -------b1
          \
            --b2

If I then try to pull from master into b2, I'll get a conflict because of the changes made to b1 after creating b2. If I fix the conflict, the resulting commit will include all changes that have occurred on master since the branch of b1, as if I had performed them. (git blame seems to be able to tell the original author though)

In this scenario, if I instead first pull from b1 into b2, and sort out the merge there, then I can then pull from master without issue, and the pulled-in irrelevant commits won't show up as changes I've made.

git merge --abort is your friend, if you're in the middle of a merge full of commits you didn't make.




回答6:


A way to reproduce the issue

is using a word file to cause the merge failure. Here's how to reproduce the issue:
create a repo a:

mkdir a
cd a
git init

create a/alpha.docx and save it, then continue with

git add alpha.docx
git commit -m "initial alpha commit"

Create a repo b that has a as remote:

cd ..
mkdir b
cd b
git clone ../a

Modify a/alpha.docx and save it, then continue with

cd ../a
touch beta                        # create some file
git commit -am "modified alpha"

Open b/alpha.docx in word and start typing something. Do not save it. This marks the file as busy.

cd ../b
git pull

This will create the file b/beta, and then abort the merge with this error:

remote: Counting objects: 3, done.
remote: Compressing objects: 100% (3/3), done.
remote: Total 3 (delta 1), reused 0 (delta 0)
Unpacking objects: 100% (3/3), done.
From /cygdrive/c/tmp2/b/../a
   a797c43..5c6796e  master     -> origin/master
Updating a797c43..5c6796e
error: unable to unlink old 'alpha.docx': Device or resource busy

If you now try to pull again, after closing word and discarding your local changes, this happens:

$ git pull
Updating a797c43..5c6796e
error: The following untracked working tree files would be overwritten by merge:
        beta
Please move or remove them before you merge.
Aborting

How to deal with this

Way 1

git reset --hard HEAD
git clean -f -d
git pull

as suggested here

Way 2

git add -A
git stash
git pull
git stash drop  # optional

Why this is

I don't know. Feel encouraged to edit this section if you know it.
I, personally, would have expected git to remove all the new files when aborting the merge. To quote Noufal Ibrahim's answer above:

A new commit with all the changes from the source branch is created in the staging area. In case of a conflict, this process of updating the staging area is interrupted and control is given to you. That's why this happens.



来源:https://stackoverflow.com/questions/9189867/after-a-git-merge-conflict-a-lot-of-files-i-didnt-touch-become-changes-to-be-c

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!