将Git中的更改暂存,同时保留工作目录中的更改

269

是否有一个git stash命令可以将您的更改存储,但同时保留它们在工作目录中?因此,基本上是一步完成 git stash; git stash apply 的操作吗?


1
同样的问题:https://dev59.com/lG015IYBdhLWcg3w6QLA - Mariusz Pawelski
这个回答解决了你的问题吗?Git命令可以保存一个stash但不修改工作树吗? - Mariusz Pawelski
2
@MariuszPawelski 不是的,那个问题比我的更具体。对于我的问题,答案很简单,就是“不行”。谢谢你提供的链接,它可能对某些人甚至我自己在以后的某个时候有所帮助。 - Michael Dorst
1
要明确的是,我的问题不同,因为我没有要求文件保持不变。我只是在寻找替代 git stash && git stash apply 的方法。您会注意到,那个问题的答案与我的相当不同。 - Michael Dorst
啊,没错,你的问题有点不太具体。但我提出这个问题是因为它的答案也能满足你的要求。这样这个问题就会在侧边栏中出现为“相关问题”,可能对某些人有帮助。 - Mariusz Pawelski
5个回答

262

值得一提的是,另一种做法是先暂存你想要保留的更改,然后使用 --keep-index 参数来暂存所有更改:

$ git add modified-file.txt
$ git stash push --keep-index

以上命令将隐藏所有更改,但会保留文件在您的工作目录中。

来自官方Linux内核Git文档git stash 或者 git-scm:

如果使用--keep-index选项,则所有已添加到索引的更改都将被保留不变。


13
这是我见过的关于 --keep-index 最简单明了的解释。在文档中那种措辞方式下,我并没有完全理解它的含义。 - 40detectives
2
如果你想在暂存之前将所有内容都添加到暂存区,只需执行 git add --all 命令即可。 - mfaani
4
我执行了git stash push --keep-index -m "message",但它仍然清空了工作目录!然后我又清空了工作目录的更改,因为我以为我已经修改并保存了旧文件,然后应用了stash,结果发现并不是所有我之前有的文件都在stash中,而且现在都消失了! - Mark Jeronimus
1
可能是因为文件没有使用git add进行暂存。 - VishnuVS

91

git stash 然后 git stash applygit stash && git stash apply)将会把文件存储并立即应用。所以最终你将会在存储中拥有你的更改,同时也会在工作目录中。

如果想要一步到位,可以创建一个别名。只需将以下内容放入~/.gitconfig

[alias]
    sta = "!git stash && git stash apply"
这种方法的缺点是所有文件都会被储藏并重新创建。这意味着相关文件的时间戳将会改变。(在我执行了git sta之前打开文件的话,这会导致Emacs发出警告并要求保存文件,并且如果你正在使用make或类似工具,可能会导致不必要的重建。)

这种方法的缺点是所有文件都会被暂存和重新创建。这意味着相关文件的时间戳将会被更改。(如果在执行git sta之前已经打开了文件,这会导致Emacs警告我在保存文件时进行更改,并且如果您正在使用make或类似工具,则可能会导致不必要的重建。)


3
好的,我会尽力进行翻译。以下是需要翻译的内容:也就是说,“git stash; git stash apply”和“git stash && git stash apply”之间有什么区别呢? - Michael Dorst
3
@anthropomorphic git config --global alias.sta "!git stash && git stash apply" 就可以了。 - user456814
为什么在“git”命令前面有一个感叹号(!)?Bash告诉我“-bash:!git:找不到命令。” - Jay Sidri
1
@JaySidri,bang表示它实际上是外部命令,而不是git本身的参数。根据文档所述:“正如您可以看到的那样,Git只是用您为其设置的别名替换新命令。但是,也许您想运行一个外部命令,而不是Git子命令。在这种情况下,您需要使用!字符来启动该命令。” - madhead
显示剩余4条评论

29

您可以使用git stash create创建一个暂存提交,然后使用git stash store将其保存到暂存区中:


git stash store $(git stash create) -m "Stash commit message"

这可以保存到 git 别名中,以使其更方便:

git config --global alias.stash-keep '!git stash store $(git stash create)'

git stash-keep -m "Stash commit message"

请注意,这并不做git stash push所做的所有事情。例如,它不会将分支名称附加到提交中,例如“stash@{0}:On myBranch:Stash commit message”。


1
太喜欢这个了!不过有一个错误需要更正:man git-stash-m <message> 必须在提交哈希之前。除非在最新的 Git 中有所改变。 - tanius
3
这个答案实际上完全符合OP的要求! - jasongregori
我在使用这个别名时遇到了麻烦,最终我选择了 save = "!f() { git stash store $(git stash create); }; f" 这个命令,它起作用了。 - jasongregori
1
这应该是被接受的答案,因为顶部的其他解决方案不干净 - 会弄乱(可能昂贵的)索引状态和/或时间戳。注意:您可以使用“git cherry-pick -m2 stash”从仅索引应用更改到工作树。 - kxr
1
是的,这实际上是我使用的 git GUI 客户端的副作用,它显示了另一条消息。最终,我不得不设置“两个”才能使 git stash list 正确显示它。 - Jannes
显示剩余2条评论

15

这是一个小的增强,实际应用中可能会经常使用。

$ git add modified-file.txt  
(OR $ git add .    ---- for all modified file)
$ git stash save --keep-index "Your Comment"

3
注意:如果文件已修改但未添加到提交中,则不会起作用(例如,没有使用“git add”命令)。 - alex_1948511

3
有一个诀窍可能会对你有帮助,不是什么隐藏的东西,但FWIW。
git commit -m "Your already staged content (May be empty)"   #(Commit index)
git add -A                    #(stage remaining 'unstaged' contents)
git commit -m "My works so far (Unstaged)"       #(Working directory)
git tag stash                 #(mark the commit with 'stash' tag)
git reset HEAD^                   #(1st reset (--mixed): Unstaged)
git reset --soft HEAD^        #(2nd reset (--soft): Staged (Skip if your index was empty))

现在你有一个标记为stash的提交,无法执行git stash pop,但你可以从创建的“stash”标签中执行其他操作,比如创建补丁或重置文件等,你的工作目录文件也会保持不变。


如果你更喜欢储存在分行中:
current_branch=`git branch --show-current`
git checkout -b stash         #(create and switch to new branch 'stash')
git commit -m "Your already staged content (May be empty)"   #(Commit index)
git add -A                    #(stage remaining 'unstaged' contents)
git commit -m "My works so far (Unstaged)"         #(Working directory)
git reset HEAD^                   #(1st reset (--mixed): Unstaged)
git reset --soft $current_branch               #(2nd reset (--soft): Staged)
git checkout $current_branch        #(Now go back to where you've left with your working dir and staged status intact)

1
"工作目录完好无损" 不,您将失去任何已暂存的更改,它们将在此后变为未暂存状态。 - mattalxndr
谢谢,虽然 "working dir intact" 是正确的,但如果您想保留暂存状态,也可以使用 reset 命令的 --soft 选项。我已经更新了我的答案。 - KenIchi
保留分阶段的更改,添加在分支中存储选项 --> 我更喜欢这个选项,因为创建新分支不会影响主分支的 reflog。 - KenIchi

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接