1

I have a master branch 'A' and a feature branch 'B'.

Now a file called 'X' has evolved with some changes in both 'A' and 'B' branches.

How do I create a third branch 'C' ( From Master 'A') where I can get the file 'X', having both the changes from branch 'A' and branch 'B'. And also I don't need other commit changes from 'B'. I need only the change of file 'X' from 'B'.

What I tried?

  • git cherrypick - This didn't work because of file 'X' in branch 'B' has hundreds of commits associated with it. It's pretty hard to cherrypick and also sometimes it might bring changes involved in other files.

  • git checkout C && git checkout 'branch B' -- path_of_X I created a branch 'C' from master branch 'A' and tried to checkout file 'X' from branch 'B'. Now All my changes of file 'X' from 'A' has vanished. Also, the git history for the file 'X' is lost.

  • git checkout C && git merge B --no-commit --no-ff I created a branch 'C' from master branch 'A' and merged branch 'B' completely with --no-commit and -no-ff options. This has brought all the changes from 'B'. Now I tried to discard all changes in 'C' from 'B' except the changes of file 'X'. Looks like there is no way to do a git discard excluding a file/folder.

What is the way to solve this problem? Any help would be much appreciated. Thanks in advance.

athavan kanapuli
  • 462
  • 1
  • 6
  • 19
  • Consider this one line file: "line 1". What are the changes in this file? What haven't we established, so that you can talk about *changes* in the first place? – torek Apr 25 '19 at 01:25
  • Say, in the beginning, it was a one-line file. Now in branch 'A' 2 lines were added and in branch 'B' 3 different lines are added to the same file 'X'. I want to merge this change. I haven't understood your second question. Can you elaborate? – athavan kanapuli Apr 25 '19 at 01:48
  • "in the beginning": exactly right. What is the *beginning* for the file? You said you have a copy in "branch A" and you have a copy in "branch B". Where is your copy of the file in the beginning? – torek Apr 25 '19 at 01:57
  • Ok. The branch 'B' is created from branch 'A'. So the beginning copy of the file is from "branch A" – athavan kanapuli Apr 25 '19 at 02:00
  • If that's true—if the beginning copy is the copy at the tip of branch A—then by definition there are no changes in branch A, because that's the copy of the file in branch A. It's no different than itself. (This is an exercise, by the way. The goal is to get you to realize that there's some third or fourth or more commit(s) that you must think about.) – torek Apr 25 '19 at 02:02
  • Hmm Not really. Say, two developers are working on two different branches B and D which are created from master branch 'A'. Now both have a set of changes in file 'X' and branch D has been merged back with 'A'. So the file 'X' in branch 'A' has some new set of changes compared to the file 'X' in branch 'B'. How do I merge only file 'X' from branch "B" so that i can have all changes of B and D. – athavan kanapuli Apr 25 '19 at 02:07
  • If something "has been merged back to" A, which *commit* has *which version* of the file? Which commit should you be looking at? Or, to put it another way, can you define *branch* here? What, exactly, is a branch? See https://stackoverflow.com/questions/25068543/what-exactly-do-we-mean-by-branch – torek Apr 25 '19 at 02:10

2 Answers2

2

Find the merge-base of C and B.

base=$(git merge-base C B)

Create a temporary branch from $base.

git checkout -b temp $base

Squash merge B to temp.

git merge B --squash
git commit

Cherry-pick the squashed commit to C with -n.

git checkout C
git cherry-pick temp -n
# commit X only
git commit -m 'blah blah' -- path_to_X
# discard the rest introduced changes
git reset --hard
# if you want to add more changes, modify other files and use "git commit --amend" later

Remove the temporary branch.

git branch -D temp
ElpieKay
  • 27,194
  • 6
  • 32
  • 53
  • After following your steps, if I do a "git log X" where X is the filename, I lost my commit history from "branch B". But I could see the changes in X from branch B – athavan kanapuli Apr 25 '19 at 09:24
  • @athavankanapuli The original history of X is preserved in A and B. Use `git log B -- X` and `git log A -- X`. – ElpieKay Apr 25 '19 at 09:30
  • Fine. But when I do a cherry-pick from temp, I get some conflicts and some files are Auto-Merged. The Auto-Merged files have only partial changes from "branch B" – athavan kanapuli Apr 25 '19 at 09:50
  • @athavankanapuli It doesn't matter if you use the option `-n` in `git cherry-pick`. These changes are later discarded by `git reset --hard` and won't be committed in `C`. – ElpieKay Apr 25 '19 at 09:52
-1

Let me provide my way to do git selective merge.

git checkout -p <branch> <path>

A most simple way is to call

git checkout -p <branch> ./