如何在Git中只隐藏未分期的更改?

我想使用这个工作流:

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

有办法完成第二步吗?

例子:

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
84495 次浏览

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 list时,它会更明显地显示你之前存储了什么,特别是当你在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 version 2.7.4你可以做:

git stash save --patch
git将询问你是否将更改添加到stash中 然后你只需回答yn

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

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:我在&;__abc1 &;中提到,Git 2.35 (Q1 2022)带有&;__abc2 &;(man):

此选项仅对推送和保存命令有效。

仅保存当前暂存的更改。
这类似于基本的git commit,除了状态被提交到stash而不是当前分支


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

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

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

但这并不适用于Windows Git,直到Git 2.22 (Q2 2019),参见发行2037,考虑git stash已在C中重新实现(而不是shell脚本)

参见提交7 db9302 (11 Mar 2019) by Thomas Gummerer (tgummerer)
参见提交1366年c78提交7 b556aa (07 Mar 2019) by 约翰内斯·辛德林(dscho)
(由Junio C Hamano—gitster提交0 ba1ba4中合并,22 Apr 2019)

内置的stash:再次处理:(glob)路径specs

当传递一个路径规格列表给,比如说git add时,我们需要 小心使用原始形式,而不是路径规格的解析形式

这很重要,比如打电话的时候

git stash -- ':(glob)**/*.txt'

,其中原始形式包括:(glob)前缀,而解析

然而,在内置的git stash中,我们传递了解析后的(即不正确的)表单,而git add将失败并返回错误消息:

fatal: pathspec '**/*.txt' did not match any files

git stash从工作树中删除更改的阶段,即使refs/stash实际上已经成功更新。

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

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,并且它接受存储push的任意数量的参数,而不是硬编码-m,并且它确实将--soft添加到最终重置中,以便索引保持它开始时的状态。它还在提交时使用--no-verify,以避免通过提交前钩子(HT: @Granfalloner)对工作副本进行更改。

关于只存储阶段性变化(别名stash-index)的相反问题,请参阅这个答案

据我所知,目前不可能用git stash push在工作树中保存只有的未分阶段更改,即保存从索引状态的更改。该命令保存工作树中的所有更改(分阶段和非分阶段更改),即更改--keep-index0,即使使用选项--keep-index1将工作树状态设置为索引状态而不是HEAD状态(因此在用git stash pop从HEAD状态恢复更改时产生冲突)。如果git stash push有一个选项-U|--unstaged,只保存非阶段性更改(对我来说,选项--keep-index是有缺陷的),这将是非常方便的,因为它已经有一个选项-S|--staged,只保存阶段性更改。

所以现在你必须模仿

git stash push --unstaged


git stash pop

使用临时文件:

git diff >unstaged
git restore .


git apply unstaged
rm unstaged

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

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

工作 指数

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

工作 指数
一个 一个 一个
两个 两个 两个
三个

这是(在我看来)最好的解决方案,这完全符合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 push上使用--staged标志(男人。)来只进行在你的索引中的更改。

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

  1. 像这样反向操作:
git stash push --staged            # Stash staged changes
git stash                          # Stash everything else
git stash pop stash@{1}            # Restore staged changes stash
  1. 阶段性的更改是你想要保存的,而不是你想要保留的。现在你可以运行:
git stash push --staged

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

我对Python程序pre-commit是如何做到这一点感兴趣。这是代码。 https://github.com/pre-commit/pre-commit/blob/3fe38dff05957f609cf7b97f471b35a8d9e0659a/pre_commit/staged_files_only.py#L50 < / p >

它在功能上等同于:

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}将是堆栈中第二个藏物的ref…