33

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?

Flows
  • 3,675
  • 3
  • 28
  • 52
kassak
  • 3,974
  • 1
  • 25
  • 36

4 Answers4

10

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).

ThiefMaster
  • 310,957
  • 84
  • 592
  • 636
  • 4
    You can update other branch with: git fetch origin & git branch mybranch origin/mybranch -f – mnaoumov Dec 09 '13 at 23:55
  • 5
    @mnaoumov Even simpler: `git fetch :` – Nicu Stiurca Mar 16 '19 at 05:33
  • 1
    "Not possible in the current implementation", yes. "Not worth the trouble to implement it properly" - maybe. But a potentially unresolvable conflict is not a good argument for that: in that case the cherry-pick should fail without making changes to working dir or repo state. – peterchen Feb 09 '21 at 09:17
  • "For the same reason you also can't update branches that are not currently checked-out (even if a fast-forward was possible)." This sentence is false: https://stackoverflow.com/a/17722977/86845 – João Portela Dec 14 '21 at 16:31
6

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

lennartcl
  • 578
  • 4
  • 11
  • 2
    Looks like "git cherry-copy" just automates the 3 manual steps outlined by the OP. Thus, it does not contradict @ThiefMaster. I was hoping to cherry-copy a commit to branch "later" **while** compiling the current branch. That didn't go well… – user2394284 Jun 14 '17 at 07:33
1

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…

user2394284
  • 5,520
  • 4
  • 32
  • 38
  • 3
    In that case it is better to use `git worktree` instead of clone. It won't copy whole `.git` – kassak May 22 '18 at 06:32
  • 1
    That's actually a good hack. The inefficiency shouldn't matter for small-ish projects. – leftaroundabout Oct 16 '18 at 08:45
  • 1
    Instead of adding the tmp clone as a remote, you could just push _from_ the clone to its origin – FFD-pushing to a not-checked-out branch on a remote is after all no problem. – leftaroundabout Oct 16 '18 at 08:50
1

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

gitTopLevel=$(git rev-parse --show-toplevel)

# Unique name for the temporary clone.
totalhash=$(tar -c "$gitTopLevel/.git" 2> /dev/null | sha256sum | head -c8)

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

git clone "$gitTopLevel" ${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.)

leftaroundabout
  • 117,950
  • 5
  • 174
  • 319