问题
The scenario
A long existing bug was spotted out and the problematic commit was found by bisec. So the bug fixer created a branch (say branch A), just for all the tags and releases after this point can merge this branch to fix the bug. A was then merged to master. Everything is fine.
Later on, Another developer that works on branch B merged the branch to master. After this point, we found that the bug was back.
The merge commit for B to master shows that it uses B's version and so it effectively reverts the bug fix.
The commit history
The following is ordered by time, earlier on top.
- Commit
c1-- the branching point ofBandmaster - Commit
c2-- A commit inmaster, parent:c1 - Commit
c3-- A bug fix commit that branch inA - Commit
c4-- MergeAtomaster, parent:c2andc3 - Commit
c5-- A commit inB, parent:c1 - Commit
c6-- MergeBtomaster. parent:c5andc4
Or look at the picture below (earlier on bottom)
The facts confirmed
c3changes only one filef1- both
c2andc5does not changef1at all c6's comment includes a conflict list, butf1is not includedc6revertsf1to theBversion- Commits that have the bug:
c1,c2andc5(all expected),c6as well (unexpected).
Software versions
Commit c3 and c4 was using git 1.9.4.msysgit.0, others was 1.9.5.msysgit.0.
The push was using SourceTree 1.6.14.0.
Question
What causes the problem? How to avoid this? Since the change on f1 is more recent, I can't see any reason that git should use an older version without marking a conflict.
Further analysis and claims guided from answers
- The merge of
Bandmastercannot be a fast forward sincec2is conflicting withc5, as we can see in the conflict list. - The work done in
c2andc5are on a quite different part of the project (say, the bug is apply to desktop version only but those work is for web version) and people worked for those commits usually never expect that they should test the bugc3fixes. - Although the detail of the project was removed, the graph and the scenario exactly represents something that happened in the real world. The graph is a screenshot from the real project repository.
回答1:
Let's see, in principle, when merging B to master (after the bug has been fixed), and if the file with the bugfix was not touched in any of B's commits, git should do a fast-forward merge and keep the newer, already fixed file. If the file was modified, it will try to do an automatic merge, and if a conflict appears and it would force you to use some merge tool like kdiff3 or meld to solve the conflict prior to letting you merge.
If you are sure that the file was never touched in all of B's history, this is kind of strange, indeed, as it should keep the one from master.
Anyway, to avoid this sort of stuff, I prefer to do always a rebase prior to merging, if the branch is a private branch. That is, rebase B to the master's head, to be sure it contains last bugfixes, and to be sure it works correctly with those bugfixes (maybe by fixing a bug, somebody broke something that would affect B's functionality). After testing everything, using the last bugfixes and my code, I'd merge B to master.
If B is a public branch, instead of a rebase, you may want to merge master onto B, test it, and then merge B back to master.
These tricks are very well explained on this post:
http://blog.sourcetreeapp.com/2012/08/21/merge-or-rebase/
Follow this guy's rules and you'll probably never suffer git-madness anymore :)
回答2:
I think this is what might actually happened:
- The merger tries to merge his local commits with the repository
- He starts the merge and resolved the conflicts
- For some reason, his local copy of the bug file was updated
- In addition of the staged files, he saw a single file in the "unstaged" list
- he added this file to stage (since this is manual the conflict list in comments didn't change)
- Commit. Duang! a broken file being committed.
来源:https://stackoverflow.com/questions/29979599/git-reverts-commit-unexpectedly-after-merge