git cherry-pick to another branch

2019-01-26 04:06发布

问题:

I wonder if there is the way to copy one commit to another branch without checking out that branch.

For example, I have two branches: master and parallel_version.

I'm on parallel_version branch and I found a bug in file common for these branches.

I've fixed it and committed. How to duplicate this commit to another branch, assuming I'm using git-svn?

Normally I would do:

$ git checkout master
$ git cherry-pick parallel_version
$ git checkout parallel_version

Is there better way of doing that?

回答1:

That's not possible - simply imagine what would happen if there was a conflict that couldn't be resolved automatically. For the same reason you also can't update branches that are not currently checked-out (even if a fast-forward was possible).



回答2:

https://github.com/lennartcl/gitl provides "git cherry-copy" and "git cherry-move" scripts that do this and handle most of the corner cases.



回答3:

Crazy idea (based on mnaoumov's comment) if you really want to avoid touching the checked out files (say you don't want to disturb your build system) … that's what I want anyway.

  1. Clone the whole git repo to a temporary directory.
  2. Do the work in the clone.
  3. Add the clone as a remote.
  4. git fetch clone && git branch mybranch clone/mybranch -f
  5. Clean up.

This would be a thing to automate. If you have filesystem snapshots, cloning the whole repo is cheap – perhaps not so crazy after all…



回答4:

Here's a small script that creates a temporary clone of the repository, as suggested by user2394284:

/usr/bin/git-tmp-clone or ~/bin/git-tmp-clone

#!/bin/bash

# Unique name for the temporary clone.
totalhash=$(tar -c $(git rev-parse --show-toplevel)/.git | sha256sum | head -c8)

tmprepo="/tmp/$(basename $(pwd))_${totalhash}"

git clone . ${tmprepo}

# Start an interactive shell in the clone. Pass any
# arguments as initial commands to be executed.
/bin/bash --init-file <(echo "cd ${tmprepo}; $@")

# Clean up the clone.
rm -rf ${tmprepo} && echo "Deleted ${tmprepo}"

(This script is less than robust, but it seems to work for me on Ubuntu.)

You can use this to cherry-pick e.g. the last commit on the current brach to another branch, by running

git-tmp-clone "git checkout TARGET_BRANCH
            && git cherry-pick $(git rev-parse --short @)
            && git push origin HEAD"

(Note that in this example, the rev-parse is evaluated in the origin repository before the clone is created! That's why it points to the most recent commit. Adapt as needed.)