git reset --soft HEAD~
git reset HEAD <file>will do the job.
Your modifications will be kept and the file will once again show up in the modified, but not yet staged set.
git reset is a versatile command with many configurations. It can be used to remove committed snapshots, although it’s more often used to undo changes in the staging area and the working directory. In either case, it should only be used to undolocal changes—you should never reset snapshots that have been shared with other developers.
git reset <file>
Remove the specified file from the staging area, but leave the working directory unchanged. This unstages a file without overwriting any changes.
Reset the staging area to match the most recent commit, but leave the working directory unchanged. This unstages all files without overwriting any changes, giving you the opportunity to re-build the staged snapshot from scratch.
git reset --hard
Reset the staging area and the working directory to match the most recent commit. In addition to unstaging changes, the
--hard flag tells Git to overwrite all changes in the working directory, too. Put another way: this obliterates all uncommitted changes, so make sure you really want to throw away your local developments before using it.
git reset <commit>
Move the current branch tip backward to
<commit>, reset the staging area to match, but leave the working directory alone. All changes made since
<commit> will reside in the working directory, which lets you re-commit the project history using cleaner, more atomic snapshots.
git reset --hard <commit>
Move the current branch tip backward to
<commit> and reset both the staging area and the working directory to match. This obliterates not only the uncommitted changes, but all commits after
<commit>, as well.
All of the above invocations are used to remove changes from a repository. Without the
git reset is a way to clean up a repository by unstaging changes or uncommitting a series of snapshots and re-building them from scratch. The
--hard flag comes in handy when an experiment has gone horribly wrong and you need a clean slate to work with.
Whereas reverting is designed to safely undo a public commit,
git reset is designed to undo local changes. Because of their distinct goals, the two commands are implemented differently: resetting completely removes a changeset, whereas revertingmaintains the original changeset and uses a new commit to apply the undo.
You should never use
git reset <commit> when any snapshots after<commit> have been pushed to a public repository. After publishing a commit, you have to assume that other developers are reliant upon it.
Removing a commit that other team members have continued developing poses serious problems for collaboration. When they try to sync up with your repository, it will look like a chunk of the project history abruptly disappeared. The sequence below demonstrates what happens when you try to reset a public commit. The
origin/master branch is the central repository’s version of your local
As soon as you add new commits after the reset, Git will think that your local history has diverged from
origin/master, and the merge commit required to synchronize your repositories is likely to confuse and frustrate your team.
The point is, make sure that you’re using
git reset <commit> on a local experiment that went wrong—not on published changes. If you need to fix a public commit, the
git revert command was designed specifically for this purpose.
git reset command is frequently encountered while preparing the staged snapshot. The next example assumes you have two files called
main.py that you’ve already added to the repository.
# Edit both hello.py and main.py # Stage everything in the current directory git add . # Realize that the changes in hello.py and main.py # should be committed in different snapshots # Unstage main.py git reset main.py # Commit only hello.py git commit -m "Make some changes to hello.py" # Commit main.py in a separate snapshot git add main.py git commit -m "Edit main.py"
As you can see,
git reset helps you keep your commits highly-focused by letting you unstage changes that aren’t related to the next commit.
The next example shows a more advanced use case. It demonstrates what happens when you’ve been working on a new experiment for a while, but decide to completely throw it away after committing a few snapshots.
# Create a new file called `foo.py` and add some code to it # Commit it to the project history git add foo.py git commit -m "Start developing a crazy feature" # Edit `foo.py` again and change some other tracked files, too # Commit another snapshot git commit -a -m "Continue my crazy feature" # Decide to scrap the feature and remove the associated commits git reset --hard HEAD~2
git reset HEAD~2 command moves the current branch backward by two commits, effectively removing the two snapshots we just created from the project history. Remember that this kind of reset should only be used on unpublished commits. Never perform the above operation if you’ve already pushed your commits to a shared repository.
Rebasing is the process of moving a branch to a new base commit. The general process can be visualized as the following:
From a content perspective, rebasing really is just moving a branch from one commit to another. But internally, Git accomplishes this by creating new commits and applying them to the specified base—it’s literally rewriting your project history. It’s very important to understand that, even though the branch looks the same, it’s composed of entirely new commits.
git rebase <base>
Rebase the current branch onto <base>, which can be any kind of commit reference (an ID, a branch name, a tag, or a relative reference to
The primary reason for rebasing is to maintain a linear project history. For example, consider a situation where the master branch has progressed since you started working on a feature:
You have two options for integrating your feature into the
masterbranch: merging directly or rebasing and then merging. The former option results in a 3-way merge and a merge commit, while the latter results in a fast-forward merge and a perfectly linear history. The following diagram demonstrates how rebasing onto
master facilitates a fast-forward merge.
Rebasing is a common way to integrate upstream changes into your local repository. Pulling in upstream changes with
git merge results in a superfluous merge commit every time you want to see how the project has progressed. On the other hand, rebasing is like saying, “I want to base my changes on what everybody has already done.”
As we’ve discussed with
git commit --amend and
git reset, you should never rebase commits that have been pushed to a public repository. The rebase would replace the old commits with new ones, and it would look like that part of your project history abruptly vanished.