How to partially git a cherry pick without destroying a future merger?

I need to bring some corrections that have been made to the develop branch in master . I would like file A be identical in develop and master .

Normally, I would git cherry-pick commits that affect A , but some of these commits also affect B and C files, where B is a file that exists in master , but I don’t know you want to change yet. and C is a file that does not yet exist in master .

When the next release is completed at some point in the future, develop will be merged into master . If I git cherry-pick -n commit I want now, I have to not make changes to B and resolve conflicts for non-existent C before committing. When the real merge from develop to master happens, I will need changes in B and C , but I actually don’t get them, since I was already confused with these changes during cherry-pick , right?

What should I do instead? If I git checkout <latest_commit_hash> A , will this not lead to an unpleasant merge conflict in the future?

+5
source share
3 answers

In general, avoid git cherry-pick if these branches are merged at any time in the future.

It seems to me that git rebase can really help if the development branch is local and not public. If other people saw your changes, and these commits have different parents, you cannot avoid the merge.

Suppose you have n commits after mainline in development, and you have m1, m2, m3 fixed to n, which you want to use with mainline.

if you do:

 git checkout development # go to development branch git rebase -i mainline # reorder all commits in development 

you will get an editor window that shows that you committed to a line. if you put the commits m1, m2, m3 at the beginning of the line and select edit (instead of pick ) git will reorder your commits according to your request (the top commit is the oldest and the bottom one is new) and it will stop before each commit marked as a change.

You can:

 git add file1 git commit # commit only file1 git commit -a # commit the rest git rebase --continue # continue rebasing 

you can reinstall again to move unwanted commits into the change history. if you are happy with your journal (i.e. all your commits that you need in mainline are on top of the changes in mainline and nothing else, so you can combine the fast forward), you select the farthest commit you want from your development branches (SHA) and combine this.

 git checkout mainline git log development # assume acf123 is the last commit you want git merge acf123 # fast forward to the right commit 

see also:

+2
source

With git -cherry-pick there is no good way to avoid a merge conflict that will occur with the theme with the selected changes, merging with the master (where the changes were selected).

I recommend that you perform a cherry capture operation, then do a test merge locally and find that conflicts are something that Git cannot manage without user intervention before worrying about avoiding conflicts.

One of the tricks I usually do to mimic partial cherries is:

 git cherry-pick <commitish> git checkout HEAD~ -- <path of unwanted change in file> git checkout HEAD~ -- <path of unwanted change in file> git checkout HEAD~ -- <path of unwanted change in file> git checkout HEAD~ -- <path of unwanted change in file> git commit -am "squash me" git rebase -i HEAD~~ 

Squash cherry pick and check / return together.

0
source

If I git checkout develop - A, will there also be a cause for an unpleasant merge conflict in the future?

No, that alone will not be. Merge works by comparing each tip to a merge base and then comparing two sets of changes. If both branches make the same changes, no conflict arises.

Other changes in either branch, or too close to lines that have been changed in both branches, may appear as conflicts. A way to prevent this is to provide git with an accurate merge base by writing the merge from the shared content.

 # merging master and develop, but there are common changes and # also changes that conflict only with those common changes. # supply git merge with the common changes as part of the base, # so it will see that it needs to resolve only those other changes # check out the current merge base git checkout $(git merge-base master develop) # make the changes you're merging git checkout develop -- file_A git commit -m "cherrypicking file_A as of develop @ $(git rev-parse develop)" # (for ensuite) base=$(git rev-parse HEAD) # record that both branches have those changes git checkout develop git merge -s ours $base -m "recording common content from previous cherry-picks" git checkout master git merge -s ours $base -m "recording common content from previous cherry-picks" # and now this merge will get an accurate base: git merge develop 

Now: the only effect of a $base merge is to record the common content as an ancestor for both branch tips, giving the merge from develop to master exact base from which other changes can be allowed.

The new commit returns the story in accordance with the practice given in the widely used successful git branching model .


If, in terms of how your team interprets the commits, leaving the original content of this common content recorded only in the text of the commit messages, it is preferable that git get this too. Instead of constantly writing down a pedigree, through checks and merges after assigning the base above, you can also

 echo $(git rev-parse master master~) $base > .git/info/grafts echo $(git rev-parse develop develop~) $base >>.git/info/grafts git checkout master git merge develop # later, whenever you want -- the ancestry above is strictly repo-local rm .git/info/grafts 

The origin recorded in .git/info/grafts is repo-local. Your merge teams will see it, and the result will be correct. The only drawback to this is that the database is not actually recorded. Others will have the same problem as repetition - it is very unlikely if you do not do criss-cross merges , as well as cherries in other industries.

0
source

All Articles