简体   繁体   中英

Git stash partially staged file

Is there a way to stash partially staged files (created with git add -p ) in a straightforward easy manner? I already know about git stash -p which behaves like add but with stashing, but I already staged the stuff I'd like to save for later.

Maybe there is also a better way of doing what I want. I just want to save a change I made that does not belong to this branch, which I want to apply later in another branch. The changes are not committed yet.

The git stash command makes two commits:

  • One commit holds every file from the index, as if you'd run git commit (except that this commit is not on any branch). (This is the I commit, in the git stash documentation .)

  • The other commit holds every tracked file from your working tree, as if you'd run git add -u and then git commit (except that this commit is also not on any branch, and has multiple parent commits, making Git consider it to be a merge commit, even though it is not the product of git merge ). (This is the W commit. With git stash -p this W commit has different contents, though as usual it still holds every file.)

In some stashes—those made with -a or -u —there is a third commit as well, made before the second commit (perhaps that makes the second commit the third commit?), but we don't need to care about that here.

The first of these two commits—the index one—has the file with your patches in it. You can simply extract the file wholesale from this staged copy, eg, with git show stash^2:path/to/file.ext . You can turn the stashed copy into a diff (patch) against the stash's parent commit, which is the current commit, with git diff :

git diff stash^ stash^2 -- path/to/file.ext

In general, though, if you just want to turn the existing index copy of some file path/to/file.ext into a patch, I'd use git diff --cached -- path/to/file.ext and not bother with git stash at all.

Note that if you do use git stash , it's at apply time that you choose whether to use the I commit ( git stash apply --index ), or to simply throw it away entirely ( git stash apply ). The --keep-index flag, if you use it at stash creation time, means something else: instead of a git reset --hard , Git reads the I commit into your working tree.

[edit] actually, the easiest way is probably:

git commit

One rather simple way, using usual stash commands, would be:

git stash -k     # stash your changes but keep the index
git stash        # stash again (only you index)
git stash pop --index stash@{1}  # restore your repo to how it was

Your top stash will now have your index (and only your index).


Actually, creating a stash (a regular stash) already stores your index in a separate place.

To view this: run git stash , then git log --graph --oneline stash :

$ git stash
$ git log --oneline --graph stash
*   f94915d (refs/stash) WIP on master: 963f4f4 Merge branch 'fork'
|\  
| * f45cef3 index on master: 963f4f4 Merge branch 'fork'
|/  
*   963f4f4 (HEAD -> master) Merge branch 'fork'
...

The commit named "index on..." contains the content of the index you had when running git stash .

You can use that commit as a regular commit; as you can see, it is the second parent of the actual stash ( stash^2 , or f94915d^2 in my example).


git stash has other subcommands, intended for scripting usage.

For example: git stash create will create the commits to be stored in a stash, but simply won't update the reference named stash nor its reflog:

$ git stash create
8bdb3b5accb08a8e16ec88a49682fcbf10d29ccf   # <- you want to do something with this commit

The content of your index would be {thathash}^2 . So another way is:

# will create a banch 'myindex' containing your current index :
$ git branch myindex $(git stash create)^2

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM