问题描述
这里的想法是我想(暂时)暂存所有挂起的更改,然后再撤消它,而无需更改工作树中的文件。似乎它应该在 git stash
的域中,但我不知道如何使用该命令实现它。谢谢!
解决方法
编辑:关于your comment:
@phd 当然,这就是我如何获取工作副本+索引状态的初始快照。但挑战在于如何在git add -u
不更改工作副本中的任何文件之后回滚到该状态。
作为参考,此处的 @phd
正在查看涉及 git stash store
结果的 git stash create
的答案。 git stash create
操作首先创建两棵树:一个是 git write-tree
的结果(如下所述),另一个是实际上将索引复制到临时目录的结果索引,运行 git add -u
,然后再次运行 git write-tree
,全部使用临时索引。这两棵树——如果它们有写的话;当您的索引和工作树都“干净”时,git stash create
什么也不做——然后被包装到 the git stash
documentation 和 {{1} 中描述的 I
和 W
提交中} 打印 git stash create
提交的哈希 ID(适用于 W
)。
请注意,您的工作树不会受到这一部分操作的干扰。没有什么可以恢复的。扰乱您的工作树的是git stash store
的git reset
步骤。但是 git stash push
不运行这一步!它只是进行 git stash create
和 I
提交。因此,如果这就是您想要的,W
将为您提供所需的一切。
我的项目有一个预提交钩子,它只检查暂存文件状态......
在这种情况下,为什么不:
- 进行
git stash create
提交(如果您愿意,可以使用W
),然后 - 或者,出于理智考虑,给它一个临时分支名称,然后
- 使用
git stash create
来检查那个分支,或者作为一个分离的 HEAD 提交,然后 - 在添加的工作树上运行预提交挂钩。
如果 linter 的行为真的很好,你也许可以完全跳过添加的工作树,只需将 git worktree add
设置为一个临时文件,你从 GIT_INDEX_FILE
提交中读取树,然后运行 linter使用 W
设置。
[编辑 2:] 如果 linter 真的表现良好——其中很少有人表现得这么好——你应该能够将 GIT_INDEX_FILE
设置为一个临时文件,运行 GIT_INDEX_FILE
,运行 linter,然后删除临时文件。当然,在工作树上运行 linter 可能更容易,而不是在索引上运行。这需要一个灵活的预提交 linter:它可以使用更老、更笨、不支持 Git 的 linter 风格的工作树(完全忽略 Git 的存在); 或使用 Git 索引。总的来说,这会更快、更容易。
[原答案下一行]
我认为我们在这里有一个 XY problem,但只是为了回答这个问题:
- 没有意义,因为只有一个索引;但是
- 可以临时使用临时索引;和
- 你真的可以这样做,只是毫无意义。
Git 使用索引的方式比较复杂,所以这里有很多毛边。你可以在其中任何一个上割伤自己。例如,索引可能在特定条目上设置了假定未更改和/或跳过工作树位,或者可能处于 Git 在冲突合并中间使用的扩展状态(包括cherry-pick、revert 和 rebase 操作) )。但总的来说,索引几乎可以随时使用 git add -u
:
git write-tree
如果索引处于展开、未合并状态,则写树操作失败;否则,即使设置了一些标志位,它也会成功。如果成功,hash=$(git write-tree) || echo "unable to turn index into a tree"
现在包含树对象的哈希 ID。默认情况下,此树对象将在存储库中保留至少 14 天,因此您最多有 14 天的时间创建使用它的提交,或者以其他方式使用标签或其他引用链接到它,这将使其保持活动状态更永久。
将索引写出作为一棵树,您现在可以对索引执行任何您喜欢的操作,包括运行hash
。稍后,您可以使用 git add -u
:
git read-tree
读取树操作可能在各种情况下失败;咨询the documentation。一些标志使某些操作成功或失败,而它们可能分别失败或成功,例如,您也可以先完全清空索引,然后再读入索引。
要使用临时索引,请将环境变量 git read-tree $hash || echo "unable to restore index"
设置为临时索引文件的名称。这个文件要么根本不存在,要么是一个有效的索引文件。空文件(例如由 GIT_INDEX_FILE
制作)是不合适的。但是,您可以使用:
mktemp
在 sh 或 bash 脚本中。 (在您喜欢的任何语言中使用类似的构造。)操作现在将创建一个索引并使用临时文件填充它,因此您现在可以摆弄它,而不会影响真正的索引。运行 Git 命令,未设置 TF=$(mktemp) || exit
rm -f $TF # remove it now
trap "rm -f $TF" 0 1 2 3 15 # arrange to remove it on exit or signal
export GIT_INDEX_FILE=$TF # point Git at this name from here on
以使用实际索引,并使用 GIT_INDEX_FILE
使用临时索引:
GIT_INDEX_FILE=$TF
例如将演示效果。最后一行使用子shell,以便在最后的 git read-tree --empty # create empty $TF index file
echo "temp index contents:"
git ls-files --stage
echo "real index contents:"
(unset GIT_INDEX_FILE; git ls-files --stage)
# back to using the temporary index in $TF
期间取消环境变量的设置,但在主线执行中保留环境变量,无论是在最终注释之后的任何命令。
与往常一样,为任何目的创建的临时对象(包括您可能放入临时索引的任何 blob)都有 14 天的宽限期来转变为真正的提交。之后,git ls-files
可能会删除它们,即使您还没有完成它们。