23

I have cloned repository and have made some commits:

git clone ...
git add
git commit
git add
git commit
git add 
git commit 

Now I have realized that it will be better to move all my commits to another new branch. What is the best way to do it?

ceth
  • 44,198
  • 62
  • 180
  • 289

3 Answers3

33

Easy, check out your new branch, then move the old branch (let's assume master and 3 commits were made) back:

git checkout -b my_new_branch
git branch -f master HEAD~3
knittl
  • 246,190
  • 53
  • 318
  • 364
  • Neat. I think you may need a `-f`, though: `git branch -f master HEAD~3` – Rob Davis Jun 18 '11 at 18:28
  • @rob: yup, i forgot to put `-f` there – knittl Jun 18 '11 at 18:31
  • 1
    @BrettRyan: Well, you'd have to force the push – but this will alter history. Everyone who has pulled from or cloned your repository will get confused. Only do it, if you really have to. – knittl Mar 06 '13 at 18:52
  • @knittl all I want to do is undo 3 commits for example, they can stay in history and just have all changes undone and committed as a new commit, the commit message should state what caused the undo. – Brett Ryan Mar 07 '13 at 00:57
  • [this answer explaining git-revert](http://stackoverflow.com/a/4114122/140037) explained how I can do what I wanted to do. – Brett Ryan Mar 07 '13 at 01:53
  • @BrettRyan: well, this is another case then. This answer (and question) is how to move the last N commits to another branch (and effectively remove from the current branch). If you want to undo the last N commits (IOW create a commit that has the same tree as HEAD^N), you can do the following: `git reset --soft HEAD^3; git commit -m'undoing the last 3 commits';` – knittl Mar 07 '13 at 14:24
5

knittl's answer works, but there are other ways to do this.

I'm assuming you're on the master when you first cloned this repository the master branch will match the master branch on the repository you've cloned from. This is origin/master. Since your question starts with a clone this is a fair assumption.

So, after you've made your commits on the master branch, you are now ahead of the origin/master branch.

The first thing you do is create a new branch

git branch new_branch

Note: this command just creates a new branch but doesn't switch branches. So master and new_branch now point to the same commit, but you are still on the master branch.

Next thing to do is to set the current branch (which is master) to the state it was before you added commits. This is the same state as origin/master so you issue this command

git reset --hard origin/master

This sets the current branch to the same state as origin/master. The --hard sets the index and the working tree to the initial state. There are other flags, but they don't do what you want here. (Attention: If you had uncommitted changes in your working tree, they are now thrown away. Use git stash in this case before the reset.)

So now you're on master which points the same state as origin/master, all you need to do is switch to the new branch:

git checkout new_branch

Yes, this is a bit longer (3 commands instead of 2), but you don't have to count how many commits you've got to go back, and this will work even if you've branched, merged, and rebased; and I get to explain other ways of doing things in Git.

Community
  • 1
  • 1
Abizern
  • 146,289
  • 39
  • 203
  • 257
  • `reset --hard` will remove all changes from the working tree. you mention »sets index and working tree to initial state«, but i don't think this warning is clear enough for git newcomers. using `git branch` also works after merging, rebasing and other stuff. you can use `git branch -f master origin/master` to re-create the master branch at the origin/master commit (or any other place) – knittl Jun 18 '11 at 18:55
  • @knittl - Actually, no, because you've already got the changes in the `new_branch`. It will reset the working tree for master, but you then checkout `new_branch`. – Abizern Jun 18 '11 at 18:58
  • @abizem: there's only one working tree for a single git repository. it's the same for `new_branch` and `master`. if you do a `git reset --hard` on `master` and then switch back to `new_branch` you will still have a clean working tree — unless you have stashed before and pop your changes after doing the switch-and-reset game between the branches. and i don't see `stash` mentioned in your answer ;) – knittl Jun 18 '11 at 19:00
  • @knittl - when you checkout a branch it sets up the working directory to the state at that commit. If I reset the working directory for the `master` branch it doesn't affect the working directory for `new_branch` (except for untracked files). – Abizern Jun 18 '11 at 19:04
  • 3
    You can use `origin/master` instead of `HEAD~3` in knittl's version, too. – Paŭlo Ebermann Jun 18 '11 at 19:08
  • @abizern: simple testcase: `git init; >foo echo 'bar'; git add foo; git commit -m'initial'; >>foo echo 'bar'; git commit -am'add line'; >>foo echo 'fancy new code'; git branch new_branch; git reset --hard master^; git checkout new_branch; # ⸘whoops, where is my fancy new code gone‽ i thought i had created a new branch o_O *RAGE*` – knittl Jun 18 '11 at 19:09
  • 1
    @Abizern: The problem (which knittl is pointing out) is that any **uncommitted changes in the working tree** are lost by the `reset --hard` (a plain checkout would complain here). This can be avoided by `git stash` before, or using knittl's version, which does not affect the working tree at all. – Paŭlo Ebermann Jun 18 '11 at 19:12
  • I understand that point. Uncommited changes are lost. But look at the situation in the question. Each add is followed by a commit. I'm not disputing the issue of not stashing, but seriously - I just wanted to show another way of doing this,with an example of `git reset`, but I don't want to completely fill up the answer with a load of checks. Is the remote called `origin`? Are there any untracked files which will need to be cleaned with `git clean -dxf`. I don't mind the downvote, (I've got plenty of rep, thanks) I don't mind the disagreement, I mind being told that I'm wrong. – Abizern Jun 18 '11 at 19:24
  • 1
    i did not say your answer was wrong, i said it was lacking a warning about losing uncommitted changes. your comment about different worktrees for different branches was wrong though. add+commit does not mean that every change was committed … – knittl Jun 18 '11 at 19:34
  • @knittl, @Abizern: I added a warning in the text. If you disagree, you can revert my change. – Paŭlo Ebermann Jun 19 '11 at 00:42
  • @Paŭlo Ebermann, @knittl - Thanks for the edit. I've had some perspective on this overnight and can see what you are trying to say. – Abizern Jun 19 '11 at 08:58
2

Create a new branch, then reset the head to origin/master

git branch new_branch
git reset --hard origin/master

Attention: This last command will discard anything which you have in your working copy and not yet committed. Use git stash before if there is anything you want to preserve.

Then checkout your new branch

git checkout new_branch
Paŭlo Ebermann
  • 73,284
  • 20
  • 146
  • 210
Blake Taylor
  • 9,217
  • 5
  • 38
  • 41