1. Overview
Git is a quite popular version control system today.
In this quick tutorial, we’ll explore how to move existing but uncommitted changes to a new branch.
2. Introduction to the Problem
First of all, let’s think about the typical workflow of adding a new feature to a Git managed project:
- Create a new feature branch, say feature, and then switch to that branch
- Implement the feature and commit it to our local repository
- Push to the feature branch to the remote repository and create a pull request
- After other teammate’s review, the new change can be merged into the master or release branch
However, sometimes, we’ve started making changes but forgotten about creating a new feature branch and switching to it. As a result, we may realize that we’re on the wrong branch – for instance, the master branch – when we’re going to commit our changes.
Therefore, we need to create a new feature branch and move the uncommitted work to the new branch. Moreover, the master branch shouldn’t be modified.
An example may explain this scenario quickly. Let’s say we have a Git repository called myRepo:
$ git branch
* master
$ git status
On branch master
nothing to commit, working tree clean
As we can see from the output above, we’re currently on the master branch. Also, the working tree is clean.
Next, let’s make some changes:
$ git status
On branch master
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git restore <file>..." to discard changes in working directory)
modified: Readme.md
Untracked files:
(use "git add <file>..." to include in what will be committed)
a-new-file.txt
no changes added to commit (use "git add" and/or "git commit -a")
As the output above shows, we’ve added a new file, a-new-file.txt, and changed the content of Readme.md. Now, we realize that the work should be committed to a feature branch instead of the master branch.
Next, let’s see how to move the changes to a new branch and keep master unchanged.
3. Using the git checkout Command
The git checkout -b
Next, let’s test the git checkout command on our myRepo project:
$ git branch
* master
$ git co -b feature1
Switched to a new branch 'feature1'
$ git status
On branch feature1
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git restore <file>..." to discard changes in working directory)
modified: Readme.md
Untracked files:
(use "git add <file>..." to include in what will be committed)
a-new-file.txt
no changes added to commit (use "git add" and/or "git commit -a")
As the commands above show, we’ve created the feature1 branch and moved all uncommitted changes from master to feature1. Next, let’s stage and commit the changes:
$ git add . && git commit -m'implemented feature1'
[feature1 2ffc161] implemented feature1
2 files changed, 2 insertions(+)
create mode 100644 a-new-file.txt
$ git log --abbrev-commit feature1
commit 2ffc161 (HEAD -> feature1)
Author: ...
Date: ...
implemented feature1
commit b009ddf (master)
Author: ...
Date: ...
init commit
Now, let’s switch back to the master branch and check if we’ve left it unchanged:
$ git checkout master
Switched to branch 'master'
$ git status
On branch master
nothing to commit, working tree clean
$ git log --abbrev-commit master
commit b009ddf (HEAD -> master)
Author: ...
Date: ...
init commit
There is no local change on the master branch, as we can see in the output. Further, there is no new commit on master, either.
4. Using the git switch Command
As we’ve known, Git’s checkout command is like a Swiss Army knife. The same command can do many different kinds of operations, such as restoring the working tree files, switching branches, creating branches, moving the head, and so on. The usage of the checkout command is pretty overloaded.
Therefore, Git has introduced the git switch command since version 2.23 to clear some of the confusion from the checkout command’s overloaded usage. As its name implies, git switch allows us to switch between branches. Moreover, we can use the -C option to create a new branch and switch to it in one shot. It works pretty much the same as the git checkout -b command.
Next, let’s do the same test as git checkout -b on the myRepo project:
$ git branch
feature1
* master
$ git status
On branch master
Changes not staged for commit:
(use "git add/rm ...)
(use "git restore ...)
deleted: Readme.md
Untracked files:
(use "git add <file>..." to include in what will be committed)
ReadmeNew.md
...
As we can see in the output above, we’re currently on the master branch. This time, we’ve removed the file Readme.md and added a new ReadmeNew.md file.
Next, let’s use the git switch command to move these uncommitted changes to a new branch called feature2:
$ git switch -C feature2
Switched to a new branch 'feature2'
$ git status
On branch feature2
Changes not staged for commit:
(use "git add/rm ...)
(use "git restore ...)
deleted: Readme.md
Untracked files:
(use "git add <file>..." to include in what will be committed)
ReadmeNew.md
...
$ git add . && git commit -m 'feature2 is done'
[feature2 6cd5933] feature2 is done
1 file changed, 0 insertions(+), 0 deletions(-)
rename Readme.md => ReadmeNew.md (100%)
$ git log --abbrev-commit feature2
commit 6cd5933 (HEAD -> feature2)
Author: ...
Date: ...
feature2 is done
commit b009ddf (master)
Author: ...
Date: ...
init commit
As we can see in the output above, git switch -C creates a new branch feature2 and brings us to feature2. Further, all uncommitted changes have been moved from master to the feature2 branch. Then, we’ve committed the changes to the feature2 branch.
Next, let’s switch back to the master branch and check if it’s unmodified:
$ git switch master
Switched to branch 'master'
$ git status
On branch master
nothing to commit, working tree clean
$ ls -1 Readme.md
Readme.md
$ git log --abbrev-commit master
commit b009ddf (HEAD -> master)
Author: ...
Date: ...
init commit
As we’ve seen, on the master branch, all changes to the working tree files we made previously have been restored. For example, the removed file Readme.md has come back. Moreover, the git log command shows no new commit on master.
5. Conclusion
In this article, we’ve addressed a couple of quick ways to move uncommitted changes to a new Git branch. Both commands are pretty straightforward to use:
- git checkout -b <NEW_BRANCH>
- git switch -C <NEW_BRANCH>