Reputation: 2538
I'm fairly inexperienced with Git outside of the normal committing process.
Right now I'm on the master branch and I have 8 unstaged changes. What I'd like to do is create a new branch with the last commit (i.e without the 8 unstaged changes) but I want to keep the unstaged changes saved so that I can revisit them later.
How would I do this?
Upvotes: 2
Views: 1711
Reputation: 1617
As others have mentioned in answers and comments there are at least three options. There's a fair bit of overlap between them and each has pros and cons:
Branches cost practically nothing so the simplest option, with no real change to your existing workflow, is to create new branches. If you're ever in doubt if you'll want something some day it generally doesn't hurt to commit it to a "work-in-progress" or "experimental" branch.
In your particular scenario I would recommend creating a new branch to save your 8 unstaged changes (let's call them experimental) and another new branch off master for the other work you want to do (let's call it a new feature):
git checkout -b experimental/foo
git add --all
git commit -m 'Trying a new structure for Foo'
git checkout master
git checkout -b feature/bar
I would recommend this approach if you want to save your 8 changes for a while (or if you're not sure how soon you'll come back to them). You can even push the experimental branch to your upstream repository for additional redundancy or to collaborate on it.
Note 1 The last two commands can be combined into one line git checkout -b feature/bar master
. It's cleverer (and arguably more explicit) but I like to keep things simple and always checkout a branch before creating a new branch from it
Note 2 The "experimental/" and "feature/" namespaces are optional but I find them helpful for future me to know what past me was thinking. And write a good commit message, future you will thank past you :)
Another option is to temporarily "stash" the changes and then later re-apply the stashed changes to your master branch (or even some other branch).
In your situation, I would stash the changes (with a descriptive message), create the new feature branch and then, at a later point, you can come back and apply the stashed changes to master:
git stash --include-untracked save 'Trying a new structure for Foo'
git checkout -b feature/bar
...
<make a few changes in feature/bar and commit or discard them>
...
git checkout master
git stash apply
Stashing is a little more complicated but it can be quite flexible. The main difference to creating a branch is that stashes are local only; they can't be pushed upstream. I would only recommend this option if you know you need the extra flexibility stashing provides or if the stash will only be very short lived, basically a quick cut and paste.
Note 1 By default stashing only includes modified files, the --include-untracked
option is important if your changes include any new files. You can also use --all
(like we used with git add
above) but that will also stash ignored files.
Note 2 The above assumes you didn't stash anything else in the meantime. Use git stash list
to check you haven't made other stashes since. Once you're finished with this stash you can use git stash drop
to delete it. git stash pop
let's you apply and drop in a single command.
Note 3 Atlassian has a pretty useful tutorial on how to use git stash if you want to learn more.
Another (slightly) more complicated but flexible option is adding a working tree (from now on I will just use "worktree" to reflect the name of the command). Your worktree is where unstaged changes exist, moving with you as you checkout and move between branches. By default there is only one "main" worktree but you can add one or more "linked" worktrees to let you have multiple branches checked out at the same time and to have different unstaged changes in each worktree.
In the scenario above, I would probably create a new worktree (and branch) based on master and then switch to the new worktree directory. Your unstaged changes will remain in your main worktree and you can go back to work on them simply by changing back to that directory:
git worktree add -b feature/bar ../app-name-bar
cd ../app-name-bar
Because this allows you to have more than one branch checked out at a time, it enables some really nice workflows. For example, you can have two different terminal and/or editor windows/tabs open and look at two branches side by side. This is the solution I would choose for anything except very short term needs for which I'd probably use stashing.
Note 1 Using this option you're also creating a new branch. This is basically a special case of option 1.
Note 2 You can't have the same branch active in two different worktrees. If you need to for some reason you'll need to copy the branch or run the second one detached with --detach
(see this article for more info)
Note 3 The above commands will create a new folder "app-name-bar" at the same level as your current repository. So let's say your app is called "todos", you'd end up with another copy of "todos" in your filesystem called "todos-bar" (although you can call it whatever you like). To keep things organised I prefer to create a containing folder for all my worktree folders. The following steps show how to move and rename your current repository from todos to todos/main so you can have one or more additional linked worktrees living alongside your main worktree:
# Do these steps just once
mv todos/ main/
mkdir todos
mv main todos/
cd todos/main
# Do these steps every time you want to add a worktree...
cd todos/main
git worktree add -b feature/bar ../bar
cd ../bar
# ...and you'll end up with this directory structure
# └─ todos/
# ├─ main/
# | └─ ...
# └─ bar/
# └─ ...
Upvotes: 0
Reputation: 790
You can simply do
git checkout -b newbranch
This will create a new branch from master
, checkout you to newbranch
& you will have your unstaged/uncommited changes as it is.
And if you want to keep the changes while switching between branches but don't want to commit, use git stash
Upvotes: 1
Reputation: 311723
If you haven't committed these new changes, they are invisible to branching, and you can just branch out of master:
$ git branch newbranch
Or, more explicitly:
$ git branch newbranch master
Upvotes: 1