Skip to main content

Git Restore File Deleted in Previous Commit

Getting back deleted files from previous commit in Git is something that we might have to do once in a while. Once you've committed your work, it's kind of like files have their own safety net. Unless you've gone all out and wiped the whole repository directory (and no remote backup), it's rare to hit a point where you can't restore a deleted file in previous commit.

Now, let's look at a couple of ways to bring back a deleted file. It all depends on how sure you were about deleting that file in the first place!

You deleted a file but did NOT commit

You accidentally deleted a file and right away realized it was a mistake to delete the file. You can execute the following Git command to easily restore the deleted file. This approach will work regardless of whether the deletion was staged or not.

git checkout HEAD <filename>

The git checkout command is used for various purposes in Git, and its behavior can depend on the specific arguments provided. In the context of git checkout HEAD <filename>, it is used to discard changes in the working directory for a specific file and revert it to the state it has in the last commit (HEAD).

Here's a breakdown of the command:

  • git checkout: This is the main command for checking out or switching between different branches, commits, or files in Git.

  • HEAD: This is a reference to the latest commit on the current branch. It represents the current state of the repository.

  • <filename>: Replace this with the actual name of the file you want to revert to the state of the last commit (HEAD).

Putting it all together, git checkout HEAD <filename> is telling Git to take the version of the specified file from the last commit (HEAD) and overwrite the current version of the file in your working directory with that version.

Note: The git checkout command can also be used to switch branches or even specific commits, but when used with a filename and HEAD, as in this case, it's specifically about discarding changes in the working directory for that particular file.

As of Git version 2.23, the git restore command is recommended for this purpose. For example, you can achieve the same result with:

git restore --source=HEAD --staged --worktree <filename>

The git restore command is used to restore files or directories in a Git repository. The syntax you provided, git restore --source=HEAD --staged --worktree <filename>, is used to restore a specific file to the state it has in the last commit (HEAD) and unstage it from the index.

Here's a breakdown of the command:

  • git restore: This is the main command for restoring files in Git.

  • --source=HEAD: This option specifies the source of the restore operation. In this case, it's set to the last commit (HEAD), indicating that you want to restore the file to its state in the most recent commit.

  • --staged: This option tells Git to unstage the changes from the index (staging area). If the file has changes that are currently staged but not committed, this option will unstage those changes.

  • --worktree: This option restores the file in the working directory, meaning it overwrites the current state of the file in your working directory with the version from the specified source (in this case, the last commit).

  • <filename>: Replace this with the actual name of the file you want to restore.

Putting it all together, git restore --source=HEAD --staged --worktree <filename> is instructing Git to take the version of the specified file from the last commit (HEAD), unstage any changes that were in the index, and overwrite the current version of the file in your working directory with that version.

This command is often used as a more modern alternative to certain use cases of the older git checkout command, providing clearer semantics for different use cases.

This makes the intention more explicit and aligns with the evolving best practices in Git.

You deleted a file and committed the deletion. You did NOT push to a remote.

You made a commit deleting a file, but then realized that you do need that file! You can perform a Git reset to go back to the previous commit:

git reset --hard HEAD~1

The command git reset --hard HEAD~1 is used to reset the current branch to the commit immediately before the last commit (HEAD~1). Let's break down each part of the command:

  • git reset: This is the main command for resetting the current branch to a specified state.

  • --hard: This option indicates that both the working directory and the staging area should be reset to match the specified commit. This means any changes in your working directory and staging area after the specified commit will be discarded.

  • HEAD~1: This is a commit reference. HEAD refers to the most recent commit, and ~1 indicates the commit immediately before it. So, HEAD~1 refers to the commit before the last commit.

Putting it all together, git reset --hard HEAD~1 essentially means discarding the last commit along with all changes in the working directory and staging area, reverting the repository to the state of the commit just before the last one.

Caution: Using git reset --hard is a powerful and irreversible operation. It discards changes permanently. Make sure you really want to discard the changes and are aware of the consequences before using this command, especially if you have uncommitted changes you want to keep.

You committed the deletion and did more commits

If you've deleted a file, made a commit, carried on with more work and additional commits, and suddenly realized that deleting the file was a mistake, don't worry! Git's got your back. To pinpoint the correct commit, start by examining the history for the deleted file:

git log -- <filename>

You have the option to either work with the latest commit that still includes the file or the commit where the file was deleted.

In the first case, simply check out the file from that commit. Note you can use git checkout or the newer git restore command to achieve the same result.

git checkout <commit-hash-that-still-has-the-deleted-file> -- <filename>
git restore --source=<commit-hash-that-still-has-the-deleted-file> -- <filename>

In the second case, checkout the file from one commit before that. Note you can use git checkout or the newer git restore command to achieve the same result.

git checkout <commit-hash-which-the-file-was-deleted>~1 -- <filename>
git restore --source=<commit-hash-which-the-file-was-deleted>~1 -- <filename>
  • git restore: This is the main command for restoring files in Git.

  • --source=<commit-hash-which-the-file-was-deleted>~1: The --source option specifies the source of the restore operation. In this case, it's set to the commit before the one where the file was deleted. The ~1 indicates the commit before the specified commit. So, it points to the state of the repository before the file was deleted.

  • -- <filename>: The double dash (--) is used to separate the command options from the filenames. <filename> should be replaced with the actual name of the file you want to restore.

Putting it all together, the command git restore --source=<commit-hash-which-the-file-was-deleted>~1 -- <filename> tells Git to restore the specified file from the commit before the one where it was deleted. It essentially brings back the file to the state it had in the commit just before it was removed.

You deleted a file locally, committed, and pushed to a remote

If your commit or commits have already been pushed to a remote repository, attempting to reset and push again can lead to issues because it essentially rewrites the history of the local repository. In such situations, it's advisable to create a new commit that reverses the changes made in the commit that deleted the file. To achieve this, use the Git Revert command:

git revert --no-commit <commit-hash>

The git revert command in Git is used to create a new commit that undoes the changes made in a previous commit. When you use git revert --no-commit, you are telling Git to apply the changes from the specified commit but not automatically commit them. This gives you the chance to review and possibly modify the changes before making a new commit.

Here's a breakdown of the command:

  • git revert: This is the main command for reversing changes. It creates a new commit that undoes the changes introduced in a specified commit.

  • --no-commit: This option is used to stage the changes in the working directory but doesn't automatically commit them. It allows you to review and modify the changes before committing.

  • <commit-hash>: Replace this with the actual commit hash or reference where you want to revert changes. This could be the commit hash of the commit you want to undo.

Example:

git revert --no-commit abc123

In this example, the changes introduced in the commit with hash "abc123" will be applied to the working directory, but Git will pause before committing them. You can review the changes, make additional modifications if needed, and then manually commit the changes using git commit. This approach provides more flexibility and control over the reversion process.