简体   繁体   中英

How to merge individual commits from another branch without side effects (aka without using cherry-pick)?

A client wanted a customized version of our product, so we branched our master branch into a client branch. However, I ended up making important changes on client , and now I'd like to merge them back into master . These comprise approximately 20 commits (out of, say, 200), some adjacent but mostly spread randomly through the branch's commit log.

I know git cherry-pick was designed for this, but I get the impression it does not preserve commit history, and it seems to ignore commit logs, which I'd rather not copy & paste 20 times. I would also like to avoid problems when merging any further master changes back into client , which I'm sure we will need to do as we develop our product and wish to merge those new features and bugfixes into the custom client version.

Is there a way to merge these 20 commits while preserving easy mergeability and retaining original commit messages?

cherry-pick is the right instrument. You could merge the master back (better doing it right after cherry-picking) and if the changes are identical, you will not get any conflicts, everything will be merged back quite easy. Of course, if during cherry-picking you would be resolving conflicts, you may have conflicts too during merging back. But no easy solution here.

Worth to mention that VCS is for versioning during development, client-branching is not the best approach. Better would be using build tools to make different builds for different clients, so one VCS revision should be used for building an application for all clients.

I think kan's answer answers your question, and this would be a comment, but as a comment it winds up too long, and is impossible to format:

I know git cherry-pick was designed for this, but I get the impression it does not preserve commit history

History, in git, is formed by the commit graph. Cherry-picking an existing commit copies the changes made in that commit, making a new commit 1 (usually with a different parent commit ID, different committer time stamp, and quite possibly a different source tree as well). To copy changes, git simply compares that commit against its parent, 2 resulting in a patch, then applies the patch to the current HEAD commit 3 and makes a new commit (appending to the current HEAD ) from the result.

If you want to keep a record of which commit was cherry-picked, the -x flag tells git cherry-pick to add the source commit ID to the log message. This is a bit painful to use (and relies on no one "rewriting history" to remove that commit), but does work for tracking down the original commit.

and it seems to ignore commit logs ...

The default is to copy the log of the copied commit (and then allow you to edit that), so I don't know why you'd say this.


1 If the parent of the cherry-picked commit is also the current ( HEAD ) commit, git cherry-pick --ff will simply adjust the HEAD via fast-forwarding. You could use this yourself, but I think it's mainly intended as a helper for interactive rebase.

2 This assumes a regular (non-root, non-merge) commit. To cherry-pick a merge, which has multiple parents, you must tell git cherry-pick which parent it should use here. When cherry-picking a root commit git now automatically compares with an empty tree so that every file is newly created, which is the right semantic (although I think it's rare to really want to cherry-pick a root commit in the first place).

3 There are nuances here with using -n , which allows you to jam many "cherries" into a single commit. But if you don't use -n , you can ignore these, just like you can ignore --ff if you don't use it.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM