【问题标题】:How to stash only unstaged changes in Git?如何在 Git 中仅存储未暂存的更改?
【发布时间】:2022-02-22 21:59:58
【问题描述】:

我想使用这个工作流程:

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

有没有办法进行第 2 步?

例子:

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

【问题讨论】:

  • 为什么不在暂存后提交您的更改?
  • IIRC --keepindex 正是这样做的
  • 因为如果构建失败,我不想提交这个。我知道我可以删除提交,但如果可能的话,我想在没有提交的情况下这样做。
  • 谢赫,谢谢。我可以确认这是可行的。哎呀,我查看了linux.die.net/man/1/git-stash 的手册,它已经过时了。 man git stash 好多了。
  • 它是 --keep-index, fwiw。

标签: git git-stash


【解决方案1】:

git stash push 有一个选项 --keep-index 可以满足您的需求。

所以,运行git stash push --keep-index

【讨论】:

  • 是的。我一直使用savegit stash。也许是我的程序员坚持使用 apply/pop 来尊重对称性。 :)
  • 注意:这仍然会隐藏所有您的更改;与常规 git stash save 的唯一区别是它也会在您的工作副本中保留已经分阶段的更改。在上面的工作流程中,这可以正常工作,因为您只是将存储应用到已经有一半存储更改的本地副本之上(git 足够聪明,可以忽略)。但是,如果您在重新应用存储之前编辑代码,则在应用时可能会看到合并冲突。仅供参考。
  • @ytpete 这已经咬了我很多次了。我真的希望 git 有办法只存储你没有保留的东西......我经常提交东西,然后做一个完整的 git stash,知道如果我提交的内容有问题我可以git commit --ammend
  • 由于 peterflynn 描述的问题,此解决方案对我不起作用。这不是一个很好的问题答案,因为它仍然隐藏分阶段的更改。有人有更好的解决方案吗?
  • 文档似乎说 stash save 现在已弃用:“此选项已弃用,有利于 git stash push。它与“stash push”的不同之处在于它不能采用路径规范,并且任何非选项参数形成消息。”
【解决方案2】:

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

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

这将完全符合您的要求。

【讨论】:

  • 注意:-u 还存储未跟踪的文件。
  • 这种方法基本上复制了 git stash save --keep-index 所做的工作,但需要做更多的工作。我没有看到任何优势。
  • @vas 不,该方法不会重复该方法。请参阅 peterflynn 对已接受答案的评论。
  • 非常好,但存储未暂存更改的目的是在提交暂存更改之前测试暂存更改。所以执行你的第三个命令git reset --soft HEAD^是没有意义的。
  • 吐槽,这个功能不存在
【解决方案3】:
git stash save --keep-index

另外,回复:

为什么不在暂存后提交您的更改? - 申

答:因为您应该始终检查已测试的代码 :) 这意味着,您需要仅使用您将要提交的更改来运行测试

除此之外,当然,作为一名经验丰富的程序员,你天生就有测试和审查这些变化的冲动——只是部分在开玩笑

【讨论】:

    【解决方案4】:

    隐藏没有分阶段的更改

    --keep-index / -k 的问题

    在 Git 中仅存储工作树(未暂存的更改)比应有的困难。已接受的答案以及许多其他答案隐藏了未暂存的更改,并按照--keep-index 的要求单独保留了舞台。

    但不明显的是--keep-index隐藏阶段性更改。 分阶段的更改最终会同时出现在 stage 和 stash 中。 这很少是人们想要的,因为对 stash 的任何临时更改都可能在以后弹出 stash 时导致冲突。

    别名解决方案

    这个别名可以很好地暂存只是工作副本更改:

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

    它临时提交暂存的更改,从剩余的更改中创建一个 stash(并允许将额外的参数,如 --include-untracked--message 作为别名参数传递),然后重置临时提交以取回暂存的变化。

    它类似于@Simon Knapp 的answer,但有一些细微差别——它在所采取的临时操作上使用--quiet,它接受任意数量的参数来存储push,而不是硬参数- 编码-m,它确实将--soft 添加到最终重置中,以便索引保持其开始时的状态。它还在提交时使用--no-verify,以避免从预提交挂钩(HT:@Granfalloner)更改工作副本。

    有关仅存储分阶段更改(别名stash-index)的相反问题,请参阅this answer

    【讨论】:

    • 作为对这个sn-p的进一步改进,值得为git commit添加--no-verify选项,否则隐式临时提交可能会因为pre-commit hook而严重混淆工作目录。跨度>
    【解决方案5】:

    git version 2.7.4 你可以这样做:

    git stash save --patch
    

    git 会要求您将更改添加或不添加到存储中。
    然后你只需回答yn

    您可以像往常一样恢复工作目录:

    git stash pop
    

    或者,如果您想将保存的更改保存在存储中:

    git stash apply
    

    【讨论】:

    • 这太棒了。这有点费力,但至少您可以跳过并添加整个文件。
    【解决方案6】:

    要将未标记(未添加到提交)的文件添加到存储,请运行以下命令:

    git stash -k
    

    如果您想将新添加的文件(未暂存 - 不是绿色)也包含到存储中,请执行以下操作:

    git stash -k -u
    

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

    git stash pop
    

    【讨论】:

    • 这正是我所需要的谢谢
    【解决方案7】:

    从 Git 2.35+(2022 年第一季度)开始,您现在可以在 git stash push 上使用 --staged 标志 (man) 来仅暂存索引中的更改

    由于您的问题正好相反,我们有 2 个选择:

    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 帖子上从 this answer 获得了此信息。

    【讨论】:

    【解决方案8】:

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

    首先隐藏所有内容,但保留分阶段的更改

    $ git stash save --keep-index [--include-untracked]

    现在也单独存储分阶段的更改

    $ git stash 保存

    进行更改以进行修复;和测试;提交他们:

    $ git add [--interactive] [--patch]

    $ git commit -m"修复..."

    现在恢复以前阶段性的更改:

    $ git stash pop

    解决任何冲突,并注意如果存在冲突,git 将应用但 不会 删除顶部存储条目。

    (...然后提交暂存的更改,并恢复所有其他更改的存储,然后继续...)

    【讨论】:

      【解决方案9】:

      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's answer 可能更容易。

      【讨论】:

        【解决方案10】:

        另一个提示,与问题相关:

        当您使用

        有效地存储未暂存的更改时

        $ git stash save --keep-index

        您可能希望给 stash 一条消息,这样当您执行 git stash list 时,您之前存储的内容会更加明显,特别是如果您通过进一步保存来执行该 stash 操作。例如

        $ git stash save --keep-index "更改尚未上演"

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

        例如,上面可能紧跟着:

        $ git stash save "功能 X 的阶段性更改"

        但请注意,您不能然后使用

        $ git stash apply "stash@{1}" ### ✘ 并不完全符合您的要求

        只恢复未暂存的更改。

        【讨论】:

          【解决方案11】:

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

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

          其中:

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

          【讨论】:

            【解决方案12】:

            2022:我在“Stashing only staged changes in git - is it possible?”中提到,Git 2.35(2022 年第一季度)带有“git stash push --staged(man)

            >

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

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


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

            您可以将其与通配符形式结合使用,例如:

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

            但这不适用于 Git for Windows,直到 Git 2.22(2019 年第二季度),请参阅 issue 2037,考虑到 git stash has been re-implemented in C(而不是 shell 脚本)

            commit 7db9302(2019 年 3 月 11 日)Thomas Gummerer (tgummerer)
            请参阅 Johannes Schindelin (dscho)commit 1366c78commit 7b556aa(2019 年 3 月 7 日)。
            (由 Junio C Hamano -- gitster -- 合并到 commit 0ba1ba4,2019 年 4 月 22 日)

            内置stash:再次处理:(glob)路径规范

            当将路径规范列表传递给git add 时,我们需要 小心使用原始形式,而不是路径规范的解析形式。

            这会有所不同,例如打电话时

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

            原始表单包含:(glob) 前缀,而解析后的 表格没有。

            但是,在内置 git stash 中,我们传递了已解析(即不正确)的表单,git add 将失败并显示错误消息:

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

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

            【讨论】:

              【解决方案13】:

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

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

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

              【讨论】:

              • 简单而有效!谢谢!
              • 没问题!很高兴我能帮助@GeorgiyBukharov
              • 我刚刚运行了这个,它也隐藏了我未暂存的更改
              • @Anentropic 这正是 OP 所要求的——存储未分级的更改。是不是打错字了?
              • 我想我打错了,它似乎把所有东西都藏起来了,也上演了,但也许我也混淆了
              【解决方案14】:

              据我所知,目前不可能使用git stash push 在工作树中保存未暂存的更改,即保存索引状态的更改。此命令保存工作树中的所有更改(分阶段和未分阶段的更改),即从 HEAD 状态更改,即使使用选项--keep-index 也 将工作树状态设置为索引状态而不是 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
              

              您的用例是在提交部分更改之前进行测试,它已经在reference documentation 中,但有缺陷的选项--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

              working index HEAD

              echo one >file

              working index HEAD
              one

              git add file

              working index HEAD
              one one

              git commit

              working index HEAD
              one one one

              echo two >>file

              working index HEAD
              one one one
              two

              git add file

              working index HEAD
              one one one
              two two

              echo three >>file

              working index HEAD
              one one one
              two two
              three

              git diff >unstaged

              git restore .

              working index HEAD
              one one one
              two two

              test

              git commit

              working index HEAD
              one one one
              two two two

              git apply unstaged

              rm unstaged

              working index HEAD
              one one one
              two two two
              three

              【讨论】:

                猜你喜欢
                • 2016-10-28
                • 2013-04-16
                • 2013-11-30
                相关资源
                最近更新 更多