854

Sometimes it happens that I make some changes in my working directory, and I realize that these changes should be committed in a branch different to the current one. This usually happens when I want to try out new things or do some testing and I forget to create a new branch beforehand, but I don't want to commit dirty code to the master branch.

So, how can I make that uncommitted changes (or changes stored in the index) be committed to a different branch than the current one?

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Auron
  • 13,626
  • 15
  • 47
  • 54

3 Answers3

1355

The other answers suggesting checking out the other branch, then committing to it, only work if the checkout is possible given the local modifications. If not, you're in the most common use case for git stash:

git stash
git checkout other-branch
git stash pop

The first stash hides away your changes (basically making a temporary commit), and the subsequent stash pop re-applies them. This lets Git use its merge capabilities.

If, when you try to pop the stash, you run into merge conflicts... the next steps depend on what those conflicts are. If all the stashed changes indeed belong on that other branch, you're simply going to have to sort through them - it's a consequence of having made your changes on the wrong branch.

On the other hand, if you've really messed up, and your work tree has a mix of changes for the two branches, and the conflicts are just in the ones you want to commit back on the original branch, you can save some work. As usual, there are a lot of ways to do this. Here's one, starting from after you pop and see the conflicts:

# Unstage everything (warning: this leaves files with conflicts in your tree)
git reset

# Add the things you *do* want to commit here
git add -p     # or maybe git add -i
git commit

# The stash still exists; pop only throws it away if it applied cleanly
git checkout original-branch
git stash pop

# Add the changes meant for this branch
git add -p
git commit

# And throw away the rest
git reset --hard

Alternatively, if you realize ahead of the time that this is going to happen, simply commit the things that belong on the current branch. You can always come back and amend that commit:

git add -p
git commit
git stash
git checkout other-branch
git stash pop

And of course, remember that this all took a bit of work, and avoid it next time, perhaps by putting your current branch name in your prompt by adding $(__git_ps1) to your PS1 environment variable in your bashrc file. (See for example the Git in Bash documentation.)

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Cascabel
  • 479,068
  • 72
  • 370
  • 318
  • When you said: `Checking out the branch and then committing would only work if the checkout is possible given the local modifications`. What do you mean? Would you mind giving/discussing one simple example when that would fail? – Amelio Vazquez-Reina Apr 11 '13 at 15:04
  • 8
    @user815423426 If you have uncommitted changes, you can check out another branch if and only if the set of files you've changed and the set of files which differ between the two branches are disjoint. That is, if you've modified file A, you can check out another branch only if file A is the same in both branches. – Cascabel Apr 11 '13 at 15:06
  • Thanks! When you said `A` is the same in both branches, you mean `A` before my changes (i.e. `A` in the HEAD of each branch). Correct? – Amelio Vazquez-Reina Apr 11 '13 at 15:12
  • In case you need to commit only part of changes you can do git stash; git checkout other_branch; git stash pop; git add -i; git commit; git stash; git checkout first_branch; git stash pop. Or instead of returning to first branch you may checkout to a third one... This is a way to spread your edits among several branches. – Dmitry Vyal Aug 27 '13 at 07:11
  • 2
    This answer works very poorly if there are other changes in the working tree, which can't be cleanly unstashed onto the branch where I need to commit a change. – Alex D Oct 10 '13 at 15:22
  • 1
    @Alex If you can't unstash cleanly that's an unavoidable merge conflict, a consequence of making changes based on the wrong branch. Git can't magically resolve them for you. – Cascabel Oct 10 '13 at 15:40
  • @Jefromi, yes, I understand. But I wish there was another way to commit selected changes only onto a different branch. – Alex D Oct 11 '13 at 14:33
  • @AlexD You can always commit selected changes, with `git add -p` (or `git add -i`); that's a completely separate thing. But given that the situation in this question occurs most often when people simply don't realize which branch they're on, generally if there are conflicts the only thing to do is work through them; all the changes have to get committed. But for the case where you really don't need to bring all the changes to the other branch, I added to the answer. – Cascabel Oct 12 '13 at 14:38
  • ...and then you find that the commit you have so carefully staged has been obliterated; you're now back to all-your-changes-are-unstaged. Big gotcha. Is there really no better way to commit a staged change to a new branch?... – Roman Starkov Apr 20 '14 at 15:46
  • @romkyns I don't really understand what you're trying to ask, so you might want to post another question. (Maybe you're trying to ask for `git stash --keep-index`?) – Cascabel Apr 20 '14 at 16:18
  • this is not only useful if you have made a mistake but also when you symlinked your dropbox into your git-repo and someone made unwanted changes. For example out graphics team for a minecraft mod just couldn't figure out how to use git so we made a dropbox and symlinked it into our local repo so their changes would be reflected instantly in the build. – WorldSEnder Jul 19 '14 at 21:42
  • Git stash is VERY dangerous to a newbie. This answer lost me a lot of progress. It's unclear that git stash is not a snapshot but really a temporary commit. Especially with your answer. – sybog64 Mar 05 '22 at 13:18
  • 4
    @sybog64 `git` is VERY dangerous to a newbie, unfortunately. All of it. It's so easy to end up with stuff getting lost or wiped out in hard-to-retrieve or impossible-to-retrieve ways until you give up on doing anything without understanding out. It's a perfect example of software thoroughly permeated with leaky abstractions, and really almost everything in git is shorthand, not abstraction. Point being: every `git` answer really needs a generic warning, and it's hard to provide more specific warnings for any single answer since there are usually multiple pitfalls you can maneuver/stumble into. – mtraceur May 29 '22 at 22:09
  • @mtraceur Not true, it's actually very hard to lose any data, due to pretty much every action ending up in `reflog`. So you can always do a `git reflog` and then `git checkout `, where `` is a hash before your mess-up. But @sybog64 is not incorrect in that `git stash clear` is dangerous. – DarkNeuron Jul 18 '23 at 09:50
  • @DarkNeuron I think you've forgotten the experience of not being nearly as fluent at Git as you are now, or maybe you just had a really efficient Git learning experience. To a typical Git newbie I've dealt with, `reflog` *doesn't exist* (they've never heard of it, they have no idea what to do with it to recover anything, they wouldn't know what to start asking to find it). Also, I can't remember if when I wrote this comment I was counting `reflog` in the hard-to-retrieve (for a newbie, obviously you or I could do it in seconds) or if I had other data-destroying mistakes in mind. – mtraceur Jul 18 '23 at 18:17
91

You can just create a new branch and switch onto it. Commit your changes then:

git branch dirty
git checkout dirty
// And your commit follows ...

Alternatively, you can also checkout an existing branch (just git checkout <name>). But only, if there are no collisions (the base of all edited files is the same as in your current branch). Otherwise you will get a message.

Note that in the case of switching to existing divergent branch you can use -m option to tell git to try to merge changes, i.e. git checkout -m <name>

Alec
  • 8,529
  • 8
  • 37
  • 63
tanascius
  • 53,078
  • 22
  • 114
  • 136
  • 14
    Note that in the case of switching to **existing** ***divergent*** branch you can use `-m` option to tell git to try to merge changes, i.e. `git checkout -m ` – Jakub Narębski Jun 01 '10 at 08:40
  • 2
    @Jefromi's answer is better in pretty much every case I think. – Alexander Bird Jun 04 '11 at 14:09
  • 9
    Shorter version: `git checkout -b dirty` – user1338062 Mar 04 '13 at 07:03
  • What do you mean by `"the base of all edited files is the same as in your current branch"` ? When would `git checkout ` be a problem if you have uncommitted changes? – Amelio Vazquez-Reina Apr 11 '13 at 14:58
  • 3
    @user815423426: If you edit a file, but do not commit it, you won't be able to checkout a branch, where the file is not committed (or was deleted, previously). Git will abort: *error: Your local changes to the following files would be overwritten by checkout: ...* – tanascius Apr 12 '13 at 11:59
  • 2
    This really is the better answer for when you're committing to a new branch. `stash` erases what you've staged; this approach does not. – Roman Starkov Apr 20 '14 at 15:47
35
  1. git checkout my_other_branch
  2. git add my_file my_other_file
  3. git commit -m

And provide your commit message.

Hank Gay
  • 70,339
  • 36
  • 160
  • 222
  • 1
    you may want to write what *co* and *ci* is ... though one can guess it (checkout, commit) ^^ – tanascius May 31 '10 at 15:30
  • 5
    @tanascius Good suggestion, and done. I've been using the aliases so long I forget they aren't the default. – Hank Gay Jun 01 '10 at 10:55