我想使用这个工作流:

进行一些改变。 将未分阶段的更改保存到存储中。 用阶段中的东西做一些事情(构建、测试等)。 提交。 恢复未分阶段的更改。

有办法完成第二步吗?

例子:

git init
echo one >file
git add file
git commit
echo two >>file
git add file
echo three >>file
git stash push
test
git commit
git stash pop

Git stash push有一个选项——keep-index,这正是你所需要的。

运行git stash push——keep-index。


git stash save --keep-index

此外,Re:

为什么不在提交更改之后提交它们呢?——心

答:因为你应该总是签入测试过的代码:)这意味着,你只需要用你即将提交的更改来运行测试

当然,作为一名有经验的程序员,您天生就有测试和检查这些更改的冲动——这只是在开玩笑


扩展前面的回答,我有时会有一组复杂的更改,但希望先提交一个单独的更改。例如,我可能发现了一个错误或其他不正确的代码,我想在进行阶段性更改之前修复它。一个可行的方法是:

首先把所有东西都藏起来,但保留阶段性的变化

$ git保存——keep-index[——include-untracked]

现在也将阶段性更改单独保存

$ git保存

为解决问题做出改变;和测试;提交:

$ git add[——interactive][——patch] $ git commit -m"fix…"

现在恢复之前的更改:

$ git隐藏pop

解决任何冲突,并注意如果存在冲突,git将应用而不是删除顶部的隐藏条目。

(…然后提交分阶段的更改,并恢复所有其他更改的存储,然后继续…)


另一个建议,与这个问题有关:

当您使用

$ git stash save -keep-index

你可能希望给stash一个消息,这样当你做一个git隐藏列表时,它会更明显地显示你之前隐藏了什么,特别是当你跟随stash操作进一步保存时。例如

$ git保存保存—keep-index“尚未进行更改”

(尽管实际上它确实包含了其他答案中提到的所有变化)。

例如,上面的语句之后可以立即加上:

$ git保存“功能X的阶段性变化”

但是要注意,你不能使用它

$ git stash apply "stash@{1}" ###所以并不完全符合你的要求

只恢复未分阶段的变化。


这可以通过3个步骤完成:保存阶段性更改,保存所有其他内容,使用阶段性更改恢复索引。基本上就是:

git commit -m 'Save index'
git stash push -u -m 'Unstaged changes and untracked files'
git reset --soft HEAD^

这正是你想要的。


在git 2.7.4版本中,你可以:

git stash save --patch

git会问你是否添加你的更改到stash。 然后你只需回答y或n

你可以恢复工作目录,你总是这样做:

git stash pop

或者,如果你想在stash保存更改:

git stash apply

使用实例添加未分期(未添加到提交)的文件到stash。

git stash -k

如果你想要将新添加的文件(不是阶段性的-不是绿色的)也包含到stash中,请执行以下操作:

git stash -k -u

然后可以提交暂存文件。在此之后,您可以使用命令返回最后存储的文件:

git stash pop

Git没有只存储未分阶段更改的命令。

但是,Git允许您指定要保存哪些文件。

git stash push --message 'Unstaged changes' -- app/controllers/products_controller.rb test/controllers/products_controller_test.rb

如果您只想在这些文件中保存特定的更改,请添加——patch选项。

git stash push --patch --message 'Unstaged changes' -- app/controllers/products_controller.rb test/controllers/products_controller_test.rb

——include-untracked选项允许你隐藏未跟踪的文件。

git stash push --include-untracked --message 'Untracked files' -- app/controllers/widgets_controller.rb test/controllers/widgets_controller_test.rb

运行git help stash(或man git-stash)获取更多信息。

注意:如果您的未分阶段更改相当混乱,@alesguzik的答案可能更简单。


2022:我在“在git中只存储阶段性变化-这可能吗?”中提到,git 2.35(第一季度2022)附带了“git隐藏推送-阶段性”(男人):

此选项仅对推送和保存命令有效。 只保存当前暂存的更改。 这类似于基本的git提交,除了状态提交到stash而不是当前分支。


2019:该命令的现代形式是git stash push[——][<pathspec>…]],因为Git 2.16+ (Git保存已弃用)

你可以将其与通配符表单结合起来,例如:

git stash push --all --keep-index ':(glob)**/*.testextension' 

但这并不适用于Git for Windows,直到Git 2.22(2019年第二季度),见issue 2037,考虑到Git stash已在C中重新实现(而不是shell脚本)。

参见Thomas Gummerer (tummerer)的commit 7db9302(2019年3月11日)。 参见Johannes Schindelin (dscho)的commit 1366c78, commit 7b556aa(2019年3月07日)。 (由Junio C Hamano - gitster -在commit 0ba1ba4中合并,2019年4月22日)

built-in stash: handle :(glob) pathspecs again When passing a list of pathspecs to, say, git add, we need to be careful to use the original form, not the parsed form of the pathspecs. This makes a difference e.g. when calling git stash -- ':(glob)**/*.txt' where the original form includes the :(glob) prefix while the parsed form does not. However, in the built-in git stash, we passed the parsed (i.e. incorrect) form, and git add would fail with the error message: fatal: pathspec '**/*.txt' did not match any files at the stage where git stash drops the changes from the worktree, even if refs/stash has been actually updated successfully.


我使用了一个别名,它接受一个字符串作为消息发送到存储条目。

mystash = "!f() { git commit -m hold && git stash push -m \"$1\" && git reset HEAD^; }; f"

哪一个:

提交索引中的所有内容, 将更改的内容存储在工作树中(当然可以添加-u或-a), 将最后一次提交重置回工作尝试(可能需要使用——soft将其保留在索引中)。


没有阶段性变化的隐藏

——keep-index / -k的问题

在Git中只存储工作树(非阶段性更改)比它应该做的要困难得多。接受的答案,以及其他一些答案,将存储非阶段的更改,并按照请求通过——keep-index离开阶段。

然而,不明显的是——keep-index还存储了分阶段的更改。阶段性的更改最终同时存在于阶段和存储中。这很少是人们想要的,因为对隐藏的任何临时更改都可能在稍后弹出隐藏时导致冲突。

别名解决方案

这个别名可以很好地执行工作副本更改:

stash-working = "!f() { \
  git commit --quiet --no-verify -m \"temp for stash-working\" && \
  git stash push \"$@\" && \
  git reset --quiet --soft HEAD~1; }; f"

它临时提交分阶段的更改,从剩余的更改中创建一个隐藏(并允许额外的参数,如——include-untracked和——message作为别名参数传递),然后重置临时提交以获得分阶段的更改。

它类似于@Simon Knapp的答案,但有一些小的区别——它在所采取的临时操作上使用——quiet,它接受任意数量的参数用于stash推送,而不是硬编码-m,它确实在最终重置中添加——soft,以便索引保持它开始时的状态。它还在提交时使用——no-verify来避免来自预提交钩子(HT: @Granfalloner)对工作副本的更改。

关于只存储阶段性更改的相反问题(别名stash-index),请参阅此答案。


To my knowledge, it is currently impossible to save only unstaged changes in the working tree with git stash push, i.e. to save changes from the index state. This command saves all changes in the working tree (staged and unstaged changes), i.e. changes from the HEAD state, even with the option --keep-index which also sets the working tree state to the index state instead of the HEAD state (thereby creating conflicts when restoring the changes from the HEAD state with git stash pop). It would be very convenient if git stash push had an option -U|--unstaged for saving only unstaged changes (to me the option --keep-index is flawed), since it has already an option -S|--staged for saving only staged changes.

所以现在你必须模仿

git stash push --unstaged

git stash pop

使用临时文件:

git diff >unstaged
git restore .

git apply unstaged
rm unstaged

您的用例是在提交部分更改之前进行测试,它已经在参考文档中,但是使用了有缺陷的选项——keep-index,这会产生冲突。下面是带有模拟选项-U|——unstaging的版本:

git init
echo one >file
git add file
git commit
echo two >>file
git add file
echo three >>file
git diff >unstaged
git restore .
test
git commit
git apply unstaged
rm unstaged

想象状态

为了更好地理解存储,我认为在每一步查看工作树、索引和HEAD的状态是很重要的。让我们看看你的用例。

git init

working index HEAD

回显一个>文件

working index HEAD
one

Git添加文件

working index HEAD
one one

git提交

working index HEAD
one one one

回显两个>>文件

working index HEAD
one one one
two

Git添加文件

working index HEAD
one one one
two two

回三>>文件

working index HEAD
one one one
two two
three

愉快

去恢复.

working index HEAD
one one one
two two

test

git提交

working index HEAD
one one one
two two two

Git应用unstaging

罗unstaged

working index HEAD
one one one
two two two
three

这是(在我看来)最好的解决方案,这完全符合OP的要求。它只存储未暂存的、被跟踪的文件——无需不必要的提交或使用——keep-index存储所有更改的文件

它列出了所有未分段的、跟踪的更改(git diff——name-only),将换行符转换为空格(| tr '\n' ' ' '),并使用git stash push存储所有这些文件:

git stash push $(git diff --name-only | tr '\n' ' ')

从Git 2.35+ (Q1 2022)开始,你现在可以在Git stash推送上使用——staging标志(man)来只stage你的索引的变化。

既然你的问题正好相反,我们有两个选择:

像这样反向操作:

git stash push --staged            # Stash staged changes
git stash                          # Stash everything else
git stash pop stash@{1}            # Restore staged changes stash

阶段性的更改是你想要保存的,而不是你想要保留的。现在你可以运行:

git stash push --staged

我从另一个S/O帖子的回答中得到了这个信息。


我对Python程序如何预提交感兴趣。这是代码。 https://github.com/pre-commit/pre-commit/blob/3fe38dff05957f609cf7b97f471b35a8d9e0659a/pre_commit/staged_files_only.py#L50

它在功能上等同于:

git diff-index --ignore-submodules --binary --exit-code --no-color --no-ext-diff $(git write-tree) -- >stash.patch
git checkout -- .

# Do stuff now

git apply stash.patch && rm stash.patch

重新思考:没有必要只将存储数据限制在工作树更改上,但是可以稍后在应用时决定只应用存储的工作树更改。

因此,在储存时间,只要像往常一样做:

git stash [-k|--keep-index]

在申请的时候

git cherry-pick -m2 -n stash

解释:-m2选择对阶段提交的第二个父元素的更改,即存储的索引状态。-n|——no-commit阻止自动提交。stash@{1}将是堆栈中第二个stash的ref…