77

I have a large git project that I, stupidly, imported to eclipse and ran an autoformat on. Now, every file in the project is showing as modified. Rather than commit my formatted files, I would rather revert all the files that I have only been formatted and not had other changes. For instance:

$ git status
# On branch master
# Changes not staged for commit:
#   (use "git add <file>..." to update what will be committed)
#   (use "git checkout -- <file>..." to discard changes in working directory)
#   (commit or discard the untracked or modified content in submodules)

#     modified: dir/file1.cpp
#     modified: dir/file1.h
#     modified: dir/file2.cpp
#     modified: dir/file2.h
#     modified: dir/file3.cpp
#     modified: dir/file3.h
#     modified: dir/file4.cpp
#     modified: dir/file4.h

I know that file2.cpp, file2.h, and file3.cpp have been modified with content (i.e., not just formatted). I want to stash the changes to these three files and then checkout an old revision, so that I can reapply the changes to these files after. I would rather avoid something like:

$ cp file2.cpp ~/tmp
$ git checkout blahblahblah
$ cp ~/tmp/file2.cpp .

If there's an obvious way to do this that doesnt involve stashing, let me know. whatever gets the job done.

2
  • Take a look at the question how can I git stash a specific file? but it also sounds like in your case you could git add the files with changes you want to keep and then git checkout -- . and then unstage the added files at the end if you want to.
    – mikej
    Commented Sep 6, 2012 at 17:20
  • 1
    With the next Git 2.13 (Q2 2017), the actual command would be git stash push -- file2.cpp file2.h file3.cpp. See my answer below
    – VonC
    Commented Mar 22, 2017 at 22:11

5 Answers 5

78

You can add the files with changes you want to keep, then stash the rest of the files and clear the stash:

git add file2.cpp file2.h file3.cpp
git stash --keep-index

At this point, you've stashed your unwanted changes. If you'd like to permanently get rid of them, run:

git stash drop

Now you have file2.cpp, file2.h, and file3.cpp staged for commit. If you then want to stash these files (and not commit them):

git reset
git stash

Now you'll be at your previous commit, with only those three files stashed.

Update:

Git 2.13 and later includes a more direct way to stash specific files with git stash push, as VonC explains in his answer.

2
  • 1
    why not just git stash drop instead of clear and just blow away the ONE stash you dont want?
    – UpAndAdam
    Commented Mar 23, 2018 at 16:19
  • @UpAndAdam Good suggestion. I've updated the answer. Commented Apr 21, 2018 at 4:33
73

I know that file2.cpp, file2.h, and file3.cpp have been modified with content (i.e., not just formatted).
I want to stash the changes to these three files and then checkout an old revision, so that I can reapply the changes to these files after.

With Git 2.13 (Q2 2017), git stash will have officially a way to stash changes for specific files (pathspec) with

git stash push [--] [<pathspec>...]

# Example
git stash push -m "named-stash" -- file2.cpp file2.h
# you can then easily reapply that stash with:
git stash apply stash^{/named-stash}

See commit 9e14090, commit 1ada502, commit df6bba0 (28 Feb 2017), and commit 9ca6326, commit 6f5ccd4, commit f5727e2 (19 Feb 2017) by Thomas Gummerer (tgummerer).
(Merged by Junio C Hamano -- gitster -- in commit 44c3f09, 10 Mar 2017)

As now documented:

For quickly making a snapshot, you can omit "push".
In this mode, non-option arguments are not allowed to prevent a misspelled subcommand from making an unwanted stash.
The two exceptions to this are stash -p which acts as alias for stash push -p and pathspecs, which are allowed after a double hyphen -- for disambiguation.

When pathspec is given to 'git stash push', the new stash records the modified states only for the files that match the pathspec.
The index entries and working tree files are then rolled back to the state in HEAD only for these files, too, leaving files that do not match the pathspec intact.

Note, as pointed out by medmunds in the comments, that git stash would use paths relative to the root folder of the git repo.


And with Git 2.26 (Q2 2020), "git rm" and "git stash" learns the new "--pathspec-from-file" option.

If you have a list of files to stash in filesToStash.txt, then this is enough:

git stash --pathspec-from-file=filesToStash.txt
13
  • 1
    @OmegaMan And... released! github.com/git-for-windows/git/releases/tag/v2.13.0.windows.1
    – VonC
    Commented May 10, 2017 at 9:24
  • 2
    Note that pathspecs for git stash are relative to your git project root -- not the current working directory (like paths listed in git status).
    – medmunds
    Commented May 15, 2017 at 18:21
  • 1
    @Z.Khullah if pathspecs for git stash are relative to the Git project root -- not the current working directory, then it should be git stash push -- dir/file2.cpp dir/file2.h dir/file3.cp
    – VonC
    Commented Jun 13, 2019 at 20:00
  • 1
    @Adam Sure, I have edited the answer to include examples. For a all folder, I would try git stash push -- folder/*
    – VonC
    Commented Sep 26, 2022 at 7:35
  • 1
    @Invariant Yes, but only if the last stash you made was named "named-stash".
    – VonC
    Commented Nov 11, 2022 at 22:10
28

A nice option is using the interactive stash mode.

git stash --patch

It works mostly like the interactive add mode: you are going to be presented with a series of diffs showing the changes you have in your working tree and you have to choose which files (or only certain parts of a file!) you want to stash, the rest will be left intact.

From man git-stash:

With --patch, you can interactively select hunks from the diff between HEAD and the working tree to be stashed. The stash entry is constructed such that its index state is the same as the index state of your repository, and its worktree contains only the changes you selected interactively. The selected changes are then rolled back from your worktree. See the "Interactive Mode" section of git-add(1) to learn how to operate the --patch mode.

In your case, you will be able to see formatting-only hunks and stash them individually, without loosing your meaningful changes.

0
13

You can also use git stash -p. This way you can select which hunks should be added to stash, whole files can be selected as well.

You'll be prompted with a few actions for each hunk:

y - stash this hunk
n - do not stash this hunk
q - quit; do not stash this hunk or any of the remaining ones
a - stash this hunk and all later hunks in the file
d - do not stash this hunk or any of the later hunks in the file
g - select a hunk to go to
/ - search for a hunk matching the given regex
j - leave this hunk undecided, see next undecided hunk
J - leave this hunk undecided, see next hunk
k - leave this hunk undecided, see previous undecided hunk
K - leave this hunk undecided, see previous hunk
s - split the current hunk into smaller hunks
e - manually edit the current hunk
? - print help
4

That's a good use for git diff and git apply IMO:

git diff file2.cpp file2.h file3.cpp > ../my-changes.patch
git checkout ...
git apply ../my-changes.patch

After diff, you can inspect the patch file to make sure that all your changes are there.

Note that you may need to use the --reject option to apply, in case the patch does not apply cleanly. Also see the man page for apply.

Not the answer you're looking for? Browse other questions tagged or ask your own question.