There are some things you (or your manager) need to understand about revert
.
First, it doesn't delete commits. It creates a new commit that undoes changes from one or more old commits.
Second, if you want to revert a merge commit, you need to also specify which of the merge's parents you want to revert to. This matters because your "5th" commit is a merge.
Lastly, if you do revert a merge, it will be hard to re-introduce the undone changes later. The documentation states that you are telling git that you will never want the reverted side of the merge.
So what you have after your push is
x --- x --- x --- A --- B --- C --- D --- M
\ /
o --- o --- o --- o --- O
The x
s are commits you (and the remote) had before you started work.
The o
s and O
are commits that appeared on the remote while you were "off line".
A
through D
are your commits.
M
is the merge created by git when you pull
ed. This merge considers D
to be parent 1, and O
to be parent 2.
Now if you say
git revert -m 1 <SHA-of-M>
this says "revert M
to D
". That would effectively undo all the o
commits as well as O
. On the other hand,
git revert -m 2 <SHA-of-M>
this says "revert M
to O
". That would effectively undo A
, B
, C
, and D
.
But again, this does not delete commits. It also does not remove commits from branch history. The result would be
x --- x --- x --- A --- B --- C --- D --- M --- W
\ /
o --- o --- o --- o --- O
where the TREE
(content) at W
matches either the TREE
at D
or the TREE
at O
(depending on which -m
option you specified).
And to reiterate: not only are all the commits from one side of the merge effectively undone, but it isn't so easy to re-do them because git considers them "accounted for" by M
.
If you (or your manager) are trying to remove "unnecessary commits" from history, then you have to do a history rewrite. There are several ways to do that; revert
isn't one of them. Any history rewrite affecting commits that have been pushed has costs associated with it. The view that merge commits are "ugly" or "unnecessary" is a matter of opinion; I question whether the cost is justified in most circumstances. But editorializing aside:
One procedure that would work (assuming your local master
is still at M
):
1) Create a temporary branch and move it to O
git checkout master
git checkout -b o_master
git reset --hard HEAD^2
2) Move master
to D
git checkout master
git reset --hard HEAD^
3) Use rebase
to create a linear history
git rebase o_master master
git branch -d o_master
You may have to resolve some conflicts during the rebase; see the git rebase docs.
This gives the appearance of moving the commits around so you have
x --- x --- x -- o --- o --- o --- o --- O --- A' --- B' --- C' --- D'
You have some new commits (A'
through D'
); each is a replacement for one of your original commits (A
through D
). The code states at A'
, B'
, and C'
are untested and may not compile or may malfunction, which could affect future debugging efforts; so you should probably test them. The code state at D'
should be equivalent to what you had at M
before (so presumably it is tested), but this is not 100% guaranteed (for various reasons, but especially if there were conflicts to resolve) so it's best to validate (either test D'
as well, or at least diff D'
against the original M
).
Next you would do a "force push".
git push -f
At this point, you have rewritten the remote history. While you still have not deleted any commits, you have removed some old commits from the master
ref. This means that all of your coworkers must update, and any work they've done (based on M
) must be rebased to D'
. See "recovering from upstream rebase" in the git rebase docs for more details about this issue.
Technically all of the old commits still exist, but they aren't visible by default because you've taken them out of your refs' history. If you need them physically deleted, that's yet another multi-step procedure.