git 隐藏跟踪但新文件

git stash tracked but new files

$ git init
$ git commit -m 'initial commit needed to stash' --allow-empty
$ touch test
$ git add --intent-to-add test  # aka -N
$ git stash
error: Entry 'test' not uptodate. Cannot merge.
Cannot save the current worktree state

它不是未跟踪的,所以 --include-untracked 没有影响。有什么方法可以隐藏已添加但从未提交的文件吗?

Is there any way to stash an added but never committed file?

只有当它真正被添加时,即索引中有一个实际版本。那么 git stash 就可以了。

过去,Git 中的 --intent-to-add 标志存在一些错误。据说它们现在都已修复,可以安全使用,但我建议避免使用它,除非它正在做一些特别重要的事情 and/or 今天对你有用。它在内部所做的是创建一个带有标志集的索引实体,如果/根据需要,每个处理索引的 Git 命令都应该对该实体进行特殊处理:

$ git add --intent-to-add test
$ git ls-files --stage --debug
100644 e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 0   test
  ctime: 0:0
  mtime: 0:0
  dev: 0    ino: 0
  uid: 0    gid: 0
  size: 0   flags: 20004000

这里的哈希ID,e69de29bb2d1d6434b8b29ae775ad8c2e48c5391,是一个空文件的哈希:

$ git hash-object -t blob --stdin < /dev/null
e69de29bb2d1d6434b8b29ae775ad8c2e48c5391

flags: 20004000 显示来自 cache.hCE_INTENT_TO_ADD 标志:

/*
 * Extended on-disk flags
 */
#define CE_INTENT_TO_ADD     (1 << 29)
#define CE_SKIP_WORKTREE     (1 << 30)

git stash 所做的是进行两个(有时是三个)不在 any 分支上的提交,然后——实际上——运行 git reset --hard 将您的索引和工作树设置回如果您没有开始使用索引和工作树时的状态。1 这两个提交持有索引(暂存区)状态,作为一个普通的提交/快照,以及你的工作树状态,作为另一个提交/快照。第三次提交(如果存在)包含所有未跟踪的文件,可能包括被忽略的文件。 None 这些提交中的 git ls-files --debug 显示的这些扩展标志有任何空间,因此根本无法保留 CE_INTENT_TO_ADD 标志。

也许 git stash 可以假装它根本没有设置来尝试处理该标志(这样它会写入一个空的 test 文件,然后完全删除索引条目)。这基本上是一致的:毕竟,该文件是作为一个空文件进行跟踪的。它只有这种特殊的 "intent to add" 状态,加上全零缓存信息,因为它不作为文件系统文件存在。当然,您会在此过程中失去特殊的 "intent to add" 身份。因此最终结果与您只是添加空文件一样。


1这曾经正是它所做的,但后来 git stash 被幻想允许使用 pathspec 参数。之后的几个 Git 版本,这种 git stash 偶尔会丢失数据。这里的所有错误都已修复——我认为——但总的来说我不建议进行这种基于路径规范的隐藏。事实上,我建议完全避免使用 git stash,除非是为了一些非常短期的目的。毕竟,Stashes 只是提交,以后没有很多好的方法可以再次找到它们。进行真正的提交,确实有很好的方法可以在以后再次找到它们。