Senger CodeLab πŸš€

How to git reset --hard a subdirectory

September 29, 2026

How to git reset --hard a subdirectory

Version control is crucial for any software development project. Git, a distributed version control system, has become the industry standard, offering powerful tools for managing code changes. One such tool is git reset --hard, which allows you to revert changes to a specific point in history. But what if you only want to reset a specific subdirectory? While Git doesn’t directly support resetting individual directories with --hard, there are effective workarounds to achieve the desired outcome. This article will guide you through the process of resetting a subdirectory to a previous commit, offering practical examples and clear explanations.

Understanding git reset --hard

The git reset --hard command is a powerful tool that completely reverts your working directory and staging area to a specified commit. It discards any uncommitted changes and rewrites the history of the branch. This command is useful when you want to completely undo changes and start fresh from a previous point. However, it’s crucial to understand its implications before using it, as it can lead to data loss if not used cautiously. Always ensure you have backed up any important changes before using this command.

For instance, imagine you’ve made several changes to your project, but they introduce bugs and instability. Instead of manually reverting each change, you can use git reset --hard HEAD~3 to revert to the state of your project three commits ago. This is a quick way to undo a series of changes, but it’s essential to understand that any changes made after the specified commit will be lost.

It’s important to distinguish git reset --hard from other reset options like --soft and --mixed. These options offer more granular control over how the reset affects your working directory and staging area. However, for resetting a subdirectory, we’ll focus on strategies that complement the --hard reset.

Strategies for Resetting a Subdirectory

As mentioned, Git doesn’t directly support resetting a single directory with git reset --hard. However, we can achieve the same outcome using a combination of other Git commands. Here are two common approaches:

Using git checkout

The git checkout command can be used to restore specific files or directories to a previous state. To reset a subdirectory, you can use git checkout <commit> -- <path/to/subdirectory>. This command updates the subdirectory to match the state of the specified commit. This approach is useful for selectively reverting changes within a subdirectory without affecting the rest of the project.

For example, to reset the “docs” subdirectory to the state of the commit with hash a1b2c3d4, you would use the command git checkout a1b2c3d4 -- docs/. This command restores the “docs” directory to how it existed at that specific commit.

This approach provides a more surgical method for reverting changes within a specific directory.

Using git stash and git checkout

Another approach involves using git stash to temporarily store your current changes, checking out the desired commit, copying the subdirectory, and then restoring your stashed changes. This is a more complex approach but offers greater flexibility when working with complex changes.

  1. Stash your current changes: git stash push
  2. Checkout the target commit: git checkout <commit>
  3. Copy the subdirectory: cp -r <path/to/subdirectory> <target/location>
  4. Return to your original branch: git checkout <your_branch>
  5. Replace the subdirectory with the copied version.
  6. Apply your stashed changes: git stash pop (Resolve any merge conflicts if necessary)

Reverting vs. Resetting

It’s important to distinguish between reverting and resetting. Reverting creates a new commit that undoes the changes introduced by a previous commit, while resetting rewrites the branch history to a specific point. Reverting is generally safer as it preserves the history of your changes, while resetting can lead to data loss if not used carefully.

While git revert is generally preferred for undoing changes, the methods described above for resetting a subdirectory effectively achieve a similar outcome by selectively restoring files to a previous state. Choose the method that best suits your needs and always consider the potential impact on your project’s history.

Understanding the difference between these two operations is crucial for effective version control.

Best Practices

When working with git reset, especially the --hard option, it’s essential to follow some best practices:

  • Commit frequently: Regularly committing your changes creates a more granular history, making it easier to pinpoint and revert to specific points in time.
  • Backup important changes: Before using git reset --hard, ensure you have a backup of any uncommitted changes you want to keep. This can be done by creating a new branch or using git stash.

By following these best practices, you can mitigate the risks associated with git reset --hard and maintain a clean and manageable project history.

Here’s a placeholder for an infographic visualizing the process of resetting a subdirectory.

Frequently Asked Questions

Q: Can I reset a subdirectory in Git without losing my uncommitted changes?

A: Yes, by using the git stash and git checkout method described earlier, you can preserve your uncommitted changes while resetting a specific subdirectory.

Successfully managing a Git repository involves understanding and utilizing the various tools available. Resetting a subdirectory, while not a direct feature, can be achieved through the strategies outlined above. By carefully considering the implications of each approach and adhering to best practices, you can maintain a clean and efficient project history while retaining control over your codebase. Check out this resource for more Git tips. Further resources include the official Git documentation [link to official Git docs], Atlassian’s Git tutorials [link to Atlassian Git tutorials], and GitHub’s learning resources [link to GitHub learning resources]. As you become more comfortable with these techniques, you’ll find them invaluable for maintaining a healthy and organized project. Explore related topics such as branching strategies, merging workflows, and advanced Git commands to further enhance your version control skills.

Question & Answer :

UPDATEΒ²: With Git 2.23 (August 2019), there’s a new command git restore that does this, see the accepted answer.

UPDATE: This will work more intuitively as of Git 1.8.3, see my own answer.

Imagine the following use case: I want to get rid of all changes in a specific subdirectory of my Git working tree, leaving all other subdirectories intact.

What is the proper Git command for this operation?

The script below illustrates the problem. Insert the proper command below the How to make files comment – the current command will restore the file a/c/ac which is supposed to be excluded by the sparse checkout. Note that I do not want to explicitly restore a/a and a/b, I only “know” a and want to restore everything below. EDIT: And I also don’t “know” b, or which other directories reside on the same level as a.

#!/bin/sh rm -rf repo; git init repo; cd repo for f in a b; do for g in a b c; do mkdir -p $f/$g touch $f/$g/$f$g git add $f/$g git commit -m "added $f/$g" done done git config core.sparsecheckout true echo a/a > .git/info/sparse-checkout echo a/b >> .git/info/sparse-checkout echo b/a >> .git/info/sparse-checkout git read-tree -m -u HEAD echo "After read-tree:" find * -type f rm a/a/aa rm a/b/ab echo >> b/a/ba echo "After modifying:" find * -type f git status # How to make files a/* reappear without changing b and without recreating a/c? git checkout -- a echo "After checkout:" git status find * -type f 

With Git 2.23 (August 2019), you have the new command git restore (also presented here)

git restore --source=HEAD --staged --worktree -- aDirectory # or, shorter git restore -s@ -SW -- aDirectory 

That would replace both the index and working tree with HEAD content, like an reset --hard would, but for a specific path.


Original answer (2013)

Note (as commented by Dan Fabulich) that:

  • git checkout -- <path> doesn’t do a hard reset: it replaces the working tree contents with the staged contents.
  • git checkout HEAD -- <path> does a hard reset for a path, replacing both the index and the working tree with the version from the HEAD commit.

As answered by Ajedi32, both checkout forms don’t remove files which were deleted in the target revision.
If you have extra files in the working tree which don’t exist in HEAD, a git checkout HEAD -- <path> won’t remove them.

Note: With git checkout --overlay HEAD -- <path> (Git 2.22, Q1 2019), files that appear in the index and working tree, but not in <tree-ish> are removed, to make them match <tree-ish> exactly.

But that checkout can respect a git update-index --skip-worktree (for those directories you want to ignore), as mentioned in “Why do excluded files keep reappearing in my git sparse checkout?”.