441

The situation:

  • master is at X
  • quickfix1 is at X + 2 commits

Such that:

o-o-X (master HEAD)
     \
      q1a--q1b (quickfix1 HEAD)

Then I started working on quickfix2, but by accident took quickfix1 as the source branch to copy, not the master. Now quickfix2 is at X + 2 commits + 2 relevant commits.

o-o-X (master HEAD)
     \
      q1a--q1b (quickfix1 HEAD)
              \
               q2a--q2b (quickfix2 HEAD)

Now I want to have a branch with quickfix2, but without the 2 commits that belong to quickfix1.

      q2a'--q2b' (quickfix2 HEAD)
     /
o-o-X (master HEAD)
     \ 
      q1a--q1b (quickfix1 HEAD)

I tried to create a patch from a certain revision in quickfix2, but the patch doesn't preserve the commit history. Is there a way to save my commit history, but have a branch without changes in quickfix1?

Robin Green
  • 32,079
  • 16
  • 104
  • 187
Alex Yarmula
  • 10,477
  • 5
  • 33
  • 32
  • Possible duplicate of [Move the most recent commit(s) to a new branch with Git](http://stackoverflow.com/questions/1628563/move-the-most-recent-commits-to-a-new-branch-with-git) – Kevin Dec 28 '16 at 20:02
  • 14
    @Kevin That question only asks about moving commits from one branch to another, this one has the additional requirement of *not* including the commits on `quickfix1`. (Note also the difference in answers.) – Scott Weldon Dec 29 '16 at 19:23

5 Answers5

414

This is a classic case of rebase --onto:

 # let's go to current master (X, where quickfix2 should begin)
 git checkout master

 # replay every commit *after* quickfix1 up to quickfix2 HEAD.
 git rebase --onto master quickfix1 quickfix2 

So you should go from

o-o-X (master HEAD)
     \ 
      q1a--q1b (quickfix1 HEAD)
              \
               q2a--q2b (quickfix2 HEAD)

to:

      q2a'--q2b' (new quickfix2 HEAD)
     /
o-o-X (master HEAD)
     \ 
      q1a--q1b (quickfix1 HEAD)

This is best done on a clean working tree.
See git config --global rebase.autostash true, especially after Git 2.10.

Michael
  • 8,362
  • 6
  • 61
  • 88
VonC
  • 1,262,500
  • 529
  • 4,410
  • 5,250
  • 29
    Beware that these steps will modify quickfix2's history, so if you already shared the branch, use cherry-picking instead (see following answers). – Max Chernyak Jan 09 '13 at 23:42
  • 1
    Just for the records: with SmartGit's log just drag `q2a` onto `X` and select *Rebase 2 commits* from the options of the occurring dialog. – Thomas S. Jul 27 '15 at 07:20
  • 1
    @ThomasS. Interesting. That is a nice GUI implementation of a `git rebase --onto`. – VonC Jul 27 '15 at 07:22
  • 1
    I have to admit, I do silly things like committing on to the wrong branch more often that I really should, the SmartGit log view GUI has saved me so many times with the same situation. – WORMSS Aug 06 '15 at 09:28
  • @WORMSS another interesting GUI: https://www.kickstarter.com/projects/diffplug/git-for-diffplug – VonC Aug 06 '15 at 09:30
  • Careful! If not careful this will overwrite your working directory. I lost work with this command. – Cosine May 29 '17 at 01:03
  • 1
    @Cosine Agreed. I have edited my answer to add the reference to `rebase.autostash` configuration: that will avoid any loss of work in progress in the working tree when doing a rebase. – VonC May 29 '17 at 04:31
178

You can use git cherry-pick to just pick the commit that you want to copy over.

Probably the best way is to create the branch out of master, then in that branch use git cherry-pick on the 2 commits from quickfix2 that you want.

DJ.
  • 6,664
  • 1
  • 33
  • 48
170

The simplest thing you can do is cherry picking a range. It does the same as the rebase --onto but is easier for the eyes :)

git cherry-pick quickfix1..quickfix2
Christoph
  • 26,519
  • 28
  • 95
  • 133
  • 6
    also, it doesn't lose the original commits, IIUC, so seems preferable for "play-it-safes" like me ;) or does `rebase --onto` also preserve the original changes? – akavel Jul 12 '13 at 10:07
  • 6
    both `rebase` and `cherry-pick` give you new SHA keys. That's because each commit is a **unique** snapshot of the repository. – Christoph Sep 18 '13 at 19:00
  • 6
    What @akavel meant is that cherry-pick will keep the original commits in their branch which is true – Mr_and_Mrs_D Mar 31 '14 at 00:12
  • 4
    For whatever it is worth, I tried to `cherry-pick` a range like in this answer and it confused my repo. I had to do individual `cherry-pick`s for each commit. (And maybe it goes without saying, but in case anyone is struggling, you have to `cherry-pick` in the chronological order that your commits were applied.) – carmenism Sep 06 '16 at 13:49
  • 3
    `git checkout` is crucial here. what is your HEAD :) ? – Sławomir Lenart Dec 22 '16 at 14:47
35

I believe it's:

git checkout master
git checkout -b good_quickfix2
git cherry-pick quickfix2^
git cherry-pick quickfix2
Matthew Flaschen
  • 278,309
  • 50
  • 514
  • 539
  • 3
    `cherry-pick` works with commit hashes so, if you just want to grab a commit from somewhere and put it somewhere else this is the way to go. Just make sure you do the `checkout ` of the correct branch first. – John Leidegren Feb 16 '16 at 10:31
-2
// on your branch that holds the commit you want to pass
$ git log
// copy the commit hash found
$ git checkout [branch that will copy the commit]
$ git reset --hard [hash of the commit you want to copy from the other branch]
// remove the [brackets]

Other more useful commands here with explanation: Git Guide

Gopher
  • 11