0

Here's how we work with git.

Every functionality is developped in a separate branch. And then, every server has it's branch (production = Master, QA=QA)

So everytime a functionality is validated by a developper, we merge it to the QA branch, where our QA specialists make their validations.

Here's a scenario :

Developper number one merges functionality1 in QA on monday (merge1)

Developper number two merges functionality2 in QA on tuesday (merge2)

Developper number three merges functionality3 in QA on wednesday (merge3)

On friday, the QA specialist decides that functionality2 and functionality3 are good, but the we have to fix the functionality1.

So my question is, is it possible in Git, to cancel only the merge1, and keep the others?

Thanks a lot

user
  • 539
  • 1
  • 11
  • 32

1 Answers1

1

Because the QA branch is presumably shared among a number of developers and QA specialists, there would be significant costs to rewriting the history. (Also it would not be easy to do, because the branch consists of merges.)

Instead you could revert the merge of functionality_1. This also has some complications, especially when you've fixed functionality_1 and want to re-introduce it into QA. I'll walk through that procedure momentarily.

But because all methods of doing this (1) have costs as noted above, and (2) also could involve conflict resolution, you might want to consider another option: Is it possible to modify your workflow to minimize or eliminate the need to do this? It would be beyond the scope of this answer to get into all the workflow design considerations involved, but when its feasible to avoid this situation, it saves headaches.

Anyway, to revert the merge, you need an expression that resolves to the merge commit. That could be the merge commit ID, or something like QA~3 assuming the three merges you mentioned are the three most recent commits on the QA branch.

git revert -m1 QA~3

will create a new commit on the QA branch, which "undoes" the changes that the merge introduced into the QA branch. (I'm making certain assumptions when I say that, but they should hold for the workflow you described.)

... M1 -- M2 -- M3 -- !M1 <--(QA)

So that part's simple, but simply merging functionality_1 again will not re-introduce the changes you reverted, because from git's perspective they're already accounted for in QA. When it comes time to re-introduce funcitonality_1, you'll have two options:

(1) revert !M1, and then merge the remainder of functionality_1; if nothing else has since been merged into QA, then simply QA will resolve to !M1 and you could say

git revert QA

Or

(2) "force rebase" functionality_1, re-creating the branch from new commits, and then merge the recreated branch into QA. To do this, you need to be able to identify all changes "reachable from" functionality_1 that were not "reachable from" QA until M1. If you don't want to change the commit topology, you'll need to know the branch point (i.e. the parent of the first commit that introduced such a change). Then you'd say

git rebase -f P functionality_1

where P is an expression that resolves to the parent commit.

This is a history rewrite of the functionality_1 branch, so if you keep the individual branches on the remove, you'll have to force-push it (and everyone else will have to recover from an upstream rebase condition; see the git rebase docs).

But this will make the merge behave as expected.

Mark Adelsberger
  • 42,148
  • 4
  • 35
  • 52
  • Thanks for the answer. You say that merging functionality_1 back will not re-introduce the changes i reverted. Even if i make some modifications in functionality_1? And second question. `git revert -m1 QA~3` it's -m1 OR QA~3 OR i have to specify both in the command line? Thanks a lot – user Aug 03 '18 at 13:29
  • 1
    If you add new commits to functionality_1, a merge will attempt to introduce changes from the new commits into `QA`. It will still skip over any commits that already appear to be accounted for. In the `revert` command `-m1` means "revert the merge commit relative to its 1st parent"; `QA~3` is the example expression that resolves to the `M1` commit. You need both (though remember, `QA~3` is only an example; you need to make sure you use an expression that *really does* resolve to the `M1` commit). – Mark Adelsberger Aug 03 '18 at 14:00