75

I've read about some tricks with merge in Git: merging public and private branches while while keeping certain files intact in both branches and others and not found a solution.

In my case I'm feeling need to do opposite merge strategy. In parallel development I have to keep some files same across the arbitrary branches. From other side I do not want to do squash or no-commit merge, while difference are significant and could break current state of testing branch.

What I want something like

git checkout testing

git merge config.xml -b development or git merge config\*.xml -b development

I guess this is like git merge-files ... command, but second file delivered from the branch, not from the filesystem. Is it possible? or may be there is a kind of workaround? submodules? attributes?

Thanks

Community
  • 1
  • 1
olegtaranenko
  • 3,722
  • 3
  • 26
  • 33
  • 1
    See also [How to do a partial merge in git?](https://stackoverflow.com/questions/52527195/how-to-do-a-partial-merge-in-git) – Vadzim Jun 08 '20 at 20:26
  • 2
    Cherry picks will create a duplicate commit, and down the road that can cause excess merge conflicts, or worse yet, no conflicts and the wrong code is taken. @Vadzim comment is a link to the correct answer if you want to do true partial merges that will allow your branches to reconcile properly when cherry picked doppelgangers meet each other. This links to a 10 part blog post that you will probably have to read twice before it will make any sense, but well worth the time if you really want to understand git merging. – Brain2000 Jun 15 '20 at 23:25

4 Answers4

68

There are a couple things you can do.

One, you can cherry-pick the changes you want, which applies only a single commit. For example, if there's a change that only touches config.xml, you can cherry-pick it with

$ git cherry-pick $COMMIT_ID_YOU_WANT

You could also just grab config.xml from the development branch:

$ git checkout testing
$ git checkout development -- config.xml

That'll get you the same version of config.xml that exists in the development branch, but note that it won't pull in the history of changes to the file.

mipadi
  • 398,885
  • 90
  • 523
  • 479
  • This is what I'm looking for. Thanks. Only one more wish, it would luxury if I could write git cherry-pick $COMMIT_ID config.xml. Ok, this is a wish to the git forum. – olegtaranenko Nov 30 '10 at 20:38
  • 11
    For the second solution: Would this cause a merge conflict if the testing branch would be merged to the development branch? I have a situation where I want to bring the changes from one feature branch to an other, and I'm not so sure if that's a good idea because when both branches merged back to the master, it could cause a big havoc of conflicts... – progician Mar 28 '12 at 12:34
  • is the -- in git checkout development -- config.xml necessary? – RobinReborn Aug 07 '20 at 17:33
  • @RobinReborn: No, it's only necessary if you also have a branch with the same name as the file, but I always add it by habit. – mipadi Aug 10 '20 at 03:45
23

If you just want to apply changes made by a certain range of commits (this can as well be only a single commit), made to only a subset of files then do:

git diff commit1..commit2 filepattern | git apply --index && git commit

You could also just apply the above pattern excluding git commit, review your staging area to see if all changes are as required and finally commit the staging area manually.

lumpidu
  • 719
  • 6
  • 13
13

Here's a repository with a step-by-step documentation to clarify the dangers of partial merge and show the right way.

https://gitlab.com/bimlas/learning-by-testing-git-partial-merge/tree/doc

TL;DR:

Merge is has to be what it is: union of branches. If you doing a merge commit without merging all the files, and you will try to merge the same branches later, than Git thinks that you merged everything in the first merge commit, thus the earlier commits does not matter, it will skip the unmerged changes before the first merge.

Use checkout to copy files from one branch to another:

git checkout BRANCH -- FILE
git commit -m "Partial merge"
bimlas
  • 2,359
  • 1
  • 21
  • 29
6

It is possible to merge against a file directly picked from the git-tree.
What I suggest is to do something like :
$ git ls-tree development -- config.xml
$ git show <blob-hash> > config.xml.development

Then get the common base :

$ git ls-tree $(git merge-base HEAD development) -- config.xml
$ git show <blob-hash> > config.xml.base

And finally :

$ git merge-file config.xml config.xml.base config.xml.development

I did not test that, though.

With a shell like zsh, you can avoid saving the blob into a temporary file with this :

$ git merge-file config.xml =(git show <base-blob-hash>) =(git show <dev-blob-hash>)

Smar
  • 8,109
  • 3
  • 36
  • 48
Hugues
  • 61
  • 1
  • 1