3

I just fall in a very surprising behavior of git, following a standard dev/master development model.

In the past, I accidentally merged a PR A from a contributor to master and used the GitHub online "revert" functionality to add a revert-commit R to fix the falsely placed commit. Then, I merged A to dev.

  • master: ...-1-2-3-A-R
  • dev: ...-1-2-3-4-5-6-A-...

Months later, I released a new version of the software with a merge from dev to master via a simple merge (online PR on GitHub).

  • dev: ...-1-2-3-4-5-6-A-7-8-9 as PR to master

The merger now realized "hey, I already have commit A" and applied all other commits. But now, the changes of A are not on the HEAD of master since it was also reverted by R which was then not replayed again with the merge from dev to master which should have finally added A.

Code-wise it looks like this, while [7-8-9] is the actual delta the merge commit applied to the master branch:

  • master: ...-1-2-3-A-R-[7-8-9]

Here is the actual git history, simplified, as a graph with GitHub's network visualization: GitHub network graph of git commits

or as a text graph (will full set of feature branches)

*   b8f9e33 (HEAD, tag: v1.5.0, mainline/master) Merge pull request #253 from dev
|\  
| *   563da86 Merge pull request #252
| |\  
| | * 562f9b4 ChangeLog for Release 1.5.0
| |/  
| *   b780652 Merge pull request #251
| |\  
| | * 2275d92 Werror: On Travis Only
| * |   3e02c75 Merge pull request #250
| |\ \  
| | |/  
| |/|   
| | * 1674897 update documentation
| | * d31a7f1 Attribute Writing: Create Group if Missing
| | * a047ab5 extent attribute tests (parallel/serial)
| |/  
| * f9ebe2e Fixed indentations
| * 2b2c146 README: Minor Fix line break
| *   9254272 Merge pull request #247
| |\  
| | * 2bb3e90 Throw exception on invalid calls
| * |   c55e4e7 Merge pull request #246
| |\ \  
| | |/  
| |/|   
| | * 419cd57 Implement generateCollectionType in cpp
| |/  
| *   7053e39 Merge pull request #242
| |\  
| * \   32dab56 Merge pull request #243
| |\ \  
| | * | 894e31a Compare agains NULL
| | * | 0cc4cca Compile in debug mode so runtime tests can trigger assertions
| | * | b9e3b14 Move typeid check into assertion
| | * | 47a810a Fix memory leak in generateCollectionType
* | | |   e3f2a88 Merge pull request #241 from revert-234-master
|\ \ \ \  
| * | | | fb8800e Revert "Make filename creation consistent"
|/ / / /  
* | | |   0b6cb96 Merge pull request #234
|\ \ \ \  
| |_|/ /  
|/| | /   
| | |/    
| |/|     
| * | 4f6e7e6 Fix close/finalize order
| * | f36f925 Disallow using Fullname ...
| * | 6f1c0cd Close files on dtor
| * | 936c002 Don't delete test h5-files and honor line length
| * | e43906a Fix tests
| * | a68c7cf Address PR comments
| * | 380e5de Consistent use of fileNameScheme instead of singleFile
| * | c6033bc Make filename creation consistent
|/ /  
* |   467c85e (tag: v1.4.0) Merge pull request #230 from dev

Consequently, merging dev to master now results in "already up-to-date" and merging master to dev proposes to remove A. But... I want A!

Do you know

  • what would be the right workflow to gracefully revert such a merge and apply it later again?
  • how to recover from that situation?

The idea would be to avoid rebases since the repository I am talking about is a mainline repo where people branch from to start developing new features. The only idea I have right now is to do the release-merge to master after such a revert on the command line doing

(master $=) $ git merge dev --strategy=theirs
Ax3l
  • 1,529
  • 12
  • 20
  • for the 2nd question, recovering: I did a `git merge --strategy=ours mainline/master` to get `dev` up-to-date again. I can now merge normally from `dev`->`master` to draft a new release *including* the changes from `A`. – Ax3l Oct 27 '16 at 13:28
  • 1
    Please draw your graph with actual merge arrows, so we can *see* which commits are merged into which branches. Note that branch names point to the *tip* commit of each branch, and commits themselves "point backwards" to their parents. A merge commit points back to *two* previous commits, while regular commits point back to just one previous commit. The merge model site you linked to has the arrows all reversed (which makes sense for humans, but Git insists on doing everything backwards)—it's OK to do that, just make sure you indicate the direction time goes, if you do. – torek Oct 27 '16 at 17:36
  • thank you for the comment! I clarified my question and added a graph. – Ax3l Oct 28 '16 at 07:47
  • Alas, I find GitHub's "network visualizer" worse than useless. As I understand it, it tries to compare your repository vs other forks of your repository. What is needed is to see the inner workings *within* your repository. In this case (no real forks to compare against) GitHub's visualizer *might* be showing something useful, but I've never quite gotten how they choose what to show and what to ignore ... someone with more experience with these might be able to decipher it, maybe. – torek Oct 28 '16 at 08:34
  • Awww, I am sorry for that. I tried gitk and gitg to get a better graph but they could not visualize the merge arrows - can you recommend a tool or git oneliner that creates a meaningful git graph from an existing repo, including pointing correctly to the two parents of a merge commit? Maybe I am overlooking something very simple. – Ax3l Oct 28 '16 at 08:41
  • 1
    I use `git log --graph --oneline --decorate --all` to get a text form. It's pretty crude. I sometimes use `gitk --all` but the `git log` output is much easier to copy for posting purposes, since it's pure text. (The arrows are implied by the fact that the output is topologically sorted.) – torek Oct 28 '16 at 08:46
  • 1
    Looks very much like "un-rever a merge" issue which has been discussed number of times: https://stackoverflow.com/q/31852169/2303202 , http://stackoverflow.com/q/1078146/2303202 , http://stackoverflow.com/q/17805979/2303202 , and some answers were given. – max630 Oct 29 '16 at 15:09
  • Thanks for the links, they are very useful. I am quite aware why it happens now and am looking for a recommended workflow to handle such a situation: revert a revert is one I just learned and not all people seem to recommend; merge with --strategy as above might be an other but more coarse approach. – Ax3l Nov 02 '16 at 12:11

0 Answers0