8

I've two branches: development, and bug_fixes, and I accidentally merged development branch in bug_fixes two to three weeks ago, and have been working on bug_fixes since then, and I've pushed the changes in bug_fixes.

Now, I need to un-merge the development branch. I want a pure bug_fixes branch with no commits form development branch. By googling, I've come up with the following scenarios:

1) Revert the commit that merged development branch in bug_fixes branch, but it partially did the job. The commits from development branch can still be seen in bug_fixes branch, something that isn't required.

2) Rebase, and delete the commit that did the merging, but it still has the same issue described in point 1. bug_fixes branch still contains the commits from development branch.

Is there a way I can delete the merging commit, and all those commits that came in bug_fixes branch form development branch, would be deleted as well? Or, it isn't possible?

Arslan Ali
  • 17,418
  • 8
  • 58
  • 76
  • 1
    why not you create an another third `branch future` and use `cherrypick` to do your work. – Gupta Apr 18 '16 at 16:14
  • Read here how to "cancel" the commits you want. http://stackoverflow.com/questions/34519665/how-to-move-head-back-to-a-previous-location/34519716#34519716 – CodeWizard Apr 19 '16 at 05:36

4 Answers4

5

IF you know which commits are coming from the development branch (in addition of the merge commit), you can do a git rebase -i (interactive rebase) from the last good commit of bug fixes:

 b--b--(B)--M--d--b--d--b--b (bugfix)
           /
    d--d--d  (devel)

git checkout bugfix
git rebase -i (B)
# drop M, d, and d

 b--b--(B)--b'--b'--b' (bugfix)

    d--d--d  (devel)

The more complex alternative would be a git filter-branch, but hopefully, the interactive rebase is enough.

In the OP's case, the full command was:

git rebase -p -i (b)

-p allows to preserve the merge commit.

Community
  • 1
  • 1
VonC
  • 1,262,500
  • 529
  • 4,410
  • 5,250
  • Here is the thing: I can see commits from **development** branch into **bug_fixes** branch, way behind the merging commit. It's not like that I'd have to remove only commits after the merging commit; there are commits from **development** branch that exist in **bug_fixes** way before it hits merging commit. It's like whole history in **bug_fixes** has been re-written. – Arslan Ali Apr 13 '16 at 11:25
  • @ArslanAli then check your `git reflog` (https://git-scm.com/docs/git-reflog) to see if you can detect why bug_fixes would have been rewritten. – VonC Apr 13 '16 at 11:33
  • I'd definitely have a look at that branch through `git reflog`. One more thing: I can't see my merging commit in `git rebase`. – Arslan Ali Apr 13 '16 at 12:45
  • @ArslanAli did you do a `git rebase -i` with the right commit (the one *before* the merge commit)? – VonC Apr 13 '16 at 13:42
  • Yes, I exactly did it the way you are saying in comment. – Arslan Ali Apr 13 '16 at 14:35
  • @ArslanAli Just for testing: `git rebase -p -i (B)` (with `-p` for "preserve merge", just to see if that includes the merge commit in the list of commits to edit (and, in your case, to drop) – VonC Apr 13 '16 at 15:36
  • Why not use `git rebase -i` to go back to the point where there's no commit from development branch and `drop` every commit from development leaving `pick` only bugfix commits ? wouldn't it work ? – Acemad Apr 15 '16 at 20:39
  • @Acemad That was the idea behind `git rebase -i (B)` with `(B)` being "the point where there's no commit from development branch". – VonC Apr 15 '16 at 21:03
  • @VonC Yeah, and it should normally do the job ! but the OP said in the first comment that there are commits way before the merge commit ! so why not take `(B)` even further not just immediately before merge, that's what i'm saying. – Acemad Apr 15 '16 at 21:41
  • Re @ArslanAli earlier comment: Does a merge commit ever show up in `rebase -i`? For example, when you do: `git clone https://github.com/githubtraining/example-branches.git && cd example-branches/`, `git checkout topic2` then `git rebase -i master` the merge commit `ca60ac7` never shows up in the rebase todo list (`git --version # 2.5.0`) – jaimedash Apr 16 '16 at 23:09
  • @VonC Please post this thing `git rebase -p -i (b)` in your answer, as it worked for me. – Arslan Ali Apr 20 '16 at 01:33
  • @ArslanAli I have edited the answer. (You can edit it too if you see anything missing) – VonC Apr 20 '16 at 06:27
4

I would try the following approach:

First of all, make a list of the commits in both branches:

git checkout development
git log --oneline > log-devel.txt

git checkout bug_fixing
git log --oneline > log-bugfixing.txt

Second, identify in each branch the id of the last commit before executing the merge. Let's name these commits devel-0 and bugfixing-0 Then, take your branches to the status they were before the accidental merge:

git checkout development
git reset --hard <devel-0-hash>

git checkout bug_fixing
git reset --hard <bugfixin-0-hash>

At this point you have two clean but outdated git branches. Now, you should take from log-devel.txt and log-bugfixing.txt all the commits that are not included in the current branches, and add them to the corresponding branch. In order to add a commit with id abc0123 to your branch development you can use cherry pick:

git checkout development
git cherry-pick `abc0123`

Take into account that the commits should better be added to the clean branches in the same order they were added to the bug fixing branch, in order to minimize the number of conflicts appearing.

Bustikiller
  • 2,423
  • 2
  • 16
  • 34
  • Here's the issue: I can't just `cherry-pick` the commits, as `bug_fixes` branch includes commits from `development` branch way behind the merging commit. So where should I start? – Arslan Ali Apr 20 '16 at 01:35
1

you need to know your latest commit message for bug_fixes before merge, if you know the sha hash then evne better.

now first you need to find the sha hash using the command

$ git reflog

the output is something like

1fb5738 HEAD@{10}: commit...

4d47df6 HEAD@{11}: commit...

5f32c4b HEAD@{12}: merge...

428f91d HEAD@{13}: checkout...

5f32c4b HEAD@{14}: checkout...

the first part is the sha hash. In this case the state before merge has hash value 428f91d

so now, in bug_fixes branch we reset to this hash value

git reset --hard 428f91d

now it is undone

Community
  • 1
  • 1
krazedkrish
  • 638
  • 3
  • 10
0

Let me describe the scenario with an example below

Bug Fix branch: Revision 10

Merged Dev Branch: Revision 11

Multiple changes after merge: Revision 12 - Revision 15

-

Now there are 2 steps that needs to be done(Easy method Without git native commands)

  1. Go back to Revision 10

    Clone Latest code to a folder called "latest"

    Clone Revision 10 to a folder called "rev10"

    Remove all the content(except .git folder) from latest folder

    Copy all the content(except .git folder) from rev10 folder to latest folder

    Checking the latest folder content

Now the Bug fix branch will be having the content equal to Revision 10 without any developer branch changes

  1. Optional - Merging Revision 12 - Revision 15 to bug_fix branch

    As we have revert back to the old revision the latest commits to bugfix branch is also gone This revisions needs to be manually merged one by one back to bug fix branch