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:

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
