30

Say I'm working on a feature in a branch oldFeature. I've done commits A and B1 and sent it for the code review. In B1 I changed some existing files but also added newfile.txt.

In the meantime I started working in a branch newFeature, forked from oldFeature (HEAD == B1). I've added C, D, E.

Meanwhile, I got code review results and had to amend B1, changing newfile.txt, and also changing some existing files. After the fixes, it became B2.

So to illustrate it:

newFeature   oldFeature
A             A
B1            B2 [B1 with some fixes]
C
D
E

Now I'm in newFeature and I want to rebase newFeature to have B2 instead of B1. When I simply do the rebase, I have rebase a conflict due to newfile.txt being added in both parts of the rebase.

I want to keep the version from oldFeature (B2).

I can't move B1 to the HEAD, because C, D, E depend on it.

I know I can do the following workaround:

Then I'll have a situation like this:

newFeature   oldFeature
A             A
B2            B2
BX
C
D
E

where BX is more or less B2\B1 on the files that existed in A. Now I can do interactive rebase and remove BX.

However my workaround is kind of convoluted. Is there a simpler way to do it? By simpler I mean, that I either have

newFeature   oldFeature
A             A
B2            B2
B2\B1
C
D
E

without any rebase conflicts, and then I can get rid of that B2\B1 commit, or to replace them automatically so I get

newFeature   oldFeature
A             A
B2            B2
C
D
E

Using Git 1.8.0.

Community
  • 1
  • 1
jakub.g
  • 38,512
  • 12
  • 92
  • 130
  • you've perfectly described the same problem I had, thanks ^^ – jirislav Jan 09 '18 at 11:29
  • because `git checkout --theirs` throws an error **fatal: '--ours/--theirs' cannot be used with switching branches**, i find this oneliner to checkout all changes using **theirs** policy and add them to git: `git status | grep modified | awk '{$1=$2=$3=""}1' | xargs -I {} sh -c 'git checkout --theirs {}; git add {}'` quite useful :) – jirislav Jan 09 '18 at 11:58

2 Answers2

30

You could do a rebase interactive:

git checkout new_feature
git rebase --interactive old_feature

and drop B1: you simply delete the line with B1:

# If you remove a line here THAT COMMIT WILL BE LOST
ScottyBlades
  • 12,189
  • 5
  • 77
  • 85
VonC
  • 1,262,500
  • 529
  • 4,410
  • 5,250
2

I made a small script in case you don't want to do an interactive rebase :

COMMIT_HASH_TO_REPLACE=$1
NEW_COMMIT_HASH=$2
GIT_SEQUENCE_EDITOR="sed -i -re 's/^pick $COMMIT_HASH_TO_REPLACE/pick $NEW_COMMIT_HASH/'" git rebase -i --reapply-cherry-picks $COMMIT_HASH_TO_REPLACE~

It is a little bit faster, because you just need to run this small command if you want to replace c6e9cdb4 by 558332c :

replace c6e9cdb4 558332c
Jack'
  • 1,722
  • 1
  • 19
  • 27