【问题标题】:How to ignore added hunks in `git stash -p`如何忽略`git stash -p`中添加的帅哥
【发布时间】:2018-05-08 21:26:22
【问题描述】:

想象一下这个场景:

# edit two files
git add -p // add hunks from one file

现在当您运行git stash -p 时,它会再次询问您是否要存储您刚刚通过git add -p 选择的块。有没有办法配置 git 默认忽略这些已经添加的大块?大多数时候,我不想隐藏我已经添加的东西。

【问题讨论】:

  • 您是否考虑过在git stash 之前发出git commit -m WIP?这将通过将暂存的内容转换为功能齐全的提交来解决问题。隐藏后,git reset --soft HEAD^ 应该会让你回到之前的状态。
  • @user4815162342 是的,但是对于一个非常常见的用例来说,这是很多打字工作。似乎我必须在某处添加功能请求......
  • 您是否有理由不能为此创建git alias?这是否有一个根本原因必须是原生的?
  • 我不明白你在什么情况下会提示这个尝试。你能用具体的例子解释你在做什么吗?请考虑以下可能性,无论您处于何种情况,都有比您在此处尝试的方法更好的方法来处理它。如果你能解释一下这里到底发生了什么,那么提供帮助会容易得多。
  • 我认为 git stash -k 会做你想做的事,它会隐藏所有内容并将工作树重置为索引状态,即你所有的 git add [-p]'d 更改。然后你可以git-clang-format那些,提交结果,git stash pop,不是吗? git stash -k; git clang-format; git stash pop?

标签: git git-stash


【解决方案1】:

manpage中有一个类似的例子:

ma​​n git stash:

"Testing partial commits
You can use git stash save --keep-index when you want 
to make two or more commits out of the changes in the 
work tree, and you want to test each change before 
committing:

# ... hack hack hack ...
$ git add --patch foo            # add just first part to the index
$ git stash save --keep-index    # save all other changes to the stash"*

我可以确认:

如果您使用git stash -p(这意味着--keep-index),您仍然会被询问是否应该隐藏索引中已经存在的更改(如您所述)。

因此,联机帮助页似乎令人困惑,其他地方也提到了这一点:https://github.com/progit/progit2/issues/822

总结一下:

--keep-index(或-p,暗示--keep-index)只是保持索引不变。已经暂存的更改仍会插入到存储中。和AFAIK,没有办法做你描述的事情。

或者,更准确地说(再次来自手册页):

With --patch, you can interactively select hunks from 
the diff between HEAD and the working tree to be stashed. 

The stash entry is constructed such that its index state 
is the same as the index state of your repository, and its 
worktree contains only the changes you selected interactively.

替代方案:

至少有 3 种方法可以实现您想要的(或多或少):

  • 不要在 git stash 中使用 -p。存放所有东西(使用--keep-index 和可能的--all,以确保您已安全存放所有东西)。
  • 在存储之前提交分阶段的更改。这样一来,对于要从存储中省略的这些更改,HEAD 和工作树之间就不会有差异。但是,如果你还不确定要提交这个怎么办?您可以随时进行更改并使用--amend 更改现有提交。
  • 取消暂存更改(从索引中删除),然后存储。

【讨论】:

    【解决方案2】:

    好的,cmets 需要的是存储尚未添加的所有更改(无论是在git add -p 期间排除,还是尚未添加)。

    这样做的原因是在提交之前对暂存状态应用一些测试/可能的调整。

    这是一个直接的git stash -k,像往常一样存储所有内容,但保留索引状态和相应的工作树,即从工作树中清除我不打算提交的所有内容。

    所以:

    git stash -k
    git clang-format
    git commit
    

    并且存储库现在有四个有趣的快照:原始内容(即存储库)、快照索引、快照工作树和当前索引(、提交和工作树),它是 stash^2 的索引快照和清理应用。请注意,所有三个新快照(即此处的提交)都将存储库作为父级。

    现在您希望您的工作树更改回来,但显然从基础到隐藏索引和工作树的更改与当前索引和工作树中的更改不匹配(以及新提交,这些都匹配),所以当 git 去弹出 stash 会发现冲突:从 stashed base 到 stashed index 的更改与从 stash base 到当前索引的更改不匹配。

    如果 Git 直接提供了你想要的东西,“存储所有工作树更改除了索引中的那些”,你可以使用它,然后存储弹出不会有任何问题,一个直的git stash pop 会这样做。幸运的是,如果 Git 擅长任何事情,它就是合并、组合、拆分以及全面的差异化处理。

    git cherry-pick -nm2 stash
    # cherry-pick updated the index, too. maybe git reset here to unstage that stuff.
    git stash drop
    

    Stash pop 是从 stash base 到 stashed 状态的更改与从 stash base(通常与当前 base 非常相似)到当前状态的更改的合并。您希望将隐藏的工作树更改回您的工作树中,但只有您尚未添加的那些,因为您添加的那些都还在这里,它们现在只是有点不同。

    所以樱桃选择是-n,没有提交,-m2,用于更改的主线是它的第二个父级,即你在存储时所做但未添加的所有差异。

    一个例子可能会有所帮助,

     cd `mktemp -d`
     git init
     printf >file %s\\n 1 2 3 4 5
     git add .;git commit -m1
     printf >file %s\\n 1 2a 3 4 5
     git add .
     printf >file %s\\n 1 2a 3 4a 5
    

    现在您已经有效地git add -p'd 2a 更改,而 4a 更改仅在您的工作树中。

     $ git stash -k
     $ cat file
     1
     2a
     3
     4
     5
     $ sed -i '2s,^,_,' file   # indent the 2a line
     $ git commit -am2
    

    现在,初始提交 :/11 2 3 4 5,你当前的提交、索引和工作树都是 1 _2a 3 4 5,你的隐藏索引是 1 2a 3 4 5,你隐藏的工作树是 1 2a 3 4a 5

    您想要返回的更改是您的隐藏索引和隐藏的工作树之间的差异,这是隐藏提交与其第二个父项的差异。因此,那个樱桃采摘。


    cherry-pick 的其他拼写方式包括

    git cherry-pick -nm1 -Xours stash
    

    它应用所有隐藏的工作树更改,但在发生冲突时采用本地版本(基本上它是发现并丢弃冲突的差异,而不是像 -m2 那样避免它们)和

    git diff stash^2..stash|git apply -3
    

    让自己更轻松的是脚本领域,谈论设置它的最简单方法是作为 git 别名,

    git config --global alias.poptree '!git cherry-pick -nm2 stash; git reset; git stash pop'
    

    你现在有一个git poptree 命令来做你想做的事。


    编辑:作为进一步的补充,假设您在记住隐藏的工作树更改之前已经继续完成了一些工作,cherry-pick 将正确更新工作树和索引,但重置将取消您已经添加的任何更改到新索引。现在你处于核心指挥领域,

    ( index=`git write-tree` &&
      git cherry-pick -nm2 stash &&
      git read-tree $index &&
      git stash drop
    )
    

    我是如何真正实现它的。

    【讨论】:

    • 非常有趣。 +1。出色地使用git cherry-pick
    【解决方案3】:

    当涉及到git stash push(因为不带任何参数调用git stash 等效于git stash push),请考虑添加--keep-index 选项。

    这意味着已经添加到索引中的所有更改都保持不变。

    所以-p (patch) 选项不应该查询那些(已经缓存的)大块。

    注意:--patch 选项暗示--keep-index,因此(用于测试)确保您使用的是可用的最新 Git 版本 (2.17) 并尝试使用 git stash push -p

    如果问题仍然存在,那么,如评论所述,首先进行提交将允许 stash -p 使用干净的索引进行操作。
    git reset --soft @~ 将恢复提交的索引。

    【讨论】:

    • 这不是 OP 要求的,而是 忽略 已经上演的差异。虽然--keep-index 似乎会有所帮助,因为它不会核弹上演的帅哥,但它会将它们包含在存储中,从而导致以后发生冲突。
    • @user4815162342 是的,这就是我在回答中提到的。其中确实包含您自己的评论。
    猜你喜欢
    • 2011-05-02
    • 2017-03-18
    • 2014-03-11
    • 2014-10-09
    • 2023-02-08
    • 1970-01-01
    • 2020-04-03
    • 2015-11-30
    • 2014-11-12
    相关资源
    最近更新 更多