关于工作树的 git diff,包括未跟踪的文件

Posted

技术标签:

【中文标题】关于工作树的 git diff,包括未跟踪的文件【英文标题】:git diff with respect to working tree including untracked files 【发布时间】:2018-02-22 11:18:30 【问题描述】:

我有一个旧的提交 A。我现在处于提交 B=HEAD!=A,并且想将我的工作目录的状态(包括未跟踪的文件)与 A 进行比较。

原因是当前未跟踪的文件是提交A 的一部分,因此它们不会出现在我想要的差异中,因此也不会混乱。

作为一种解决方法,我可以在差异之前手动 git add <all the untracked files> 并在之后手动 git reset <all the untracked files>。但是,有许多未跟踪的文件,我想以最大程度的原子性和健壮性的方式执行此操作,因为我在脚本中执行所有这些操作。

编辑:This question 还关注未跟踪文件的差异。但是,那里的答案需要手动添加和稍后删除未跟踪的文件,我更喜欢一种更自动且以原子方式执行此操作的解决方案,该解决方案可以防止脚本上下文中的中断发生错误。接受的答案正是这样做的,并且确实与链接问题的答案不同。

【问题讨论】:

Can I use git diff on untracked files?的可能重复 git add -N .; git diff HEAD..HEAD~1 呢? @SajibKhan:实际上,事实证明这是可行的(所以我删除了评论)。但是对于这个特定目的(脚本),有一种更好的方法。 嗯,没关系@torek 【参考方案1】:

正如其他人所建议的,您可以使用git add -N 将虚拟条目添加到索引中。运行:

git diff <hash>

然后将给定的工作树与当前的工作树进行比较,使用现有的索引(现在有未跟踪文件的条目)来决定将哪些工作树版本与给定的&lt;hash&gt;&lt;hash&gt; 可能是提交 ID、树 ID、分支名称或 Git 可以解析为树的任何内容)。但这确实弄乱了索引,正如你所说,你:

希望以最大程度的原子性和健壮的方式做到这一点

诀窍是使用 临时 索引。

这里的初始提交有文件barfoo;第二次提交删除了文件foo。当前工作树有foo 复活和一个新文件,如git status --short 所示。

$ git log --all --decorate --oneline --graph
* 11b241c (HEAD -> master) remove foo
* 8527327 initial
$ git status --short
A  diffscript
A  foo

注意初始提交是8527327,这是我们作为参数传递给diffscript的:

$ ./diffscript 8527327
diff --git a/diffscript b/diffscript
new file mode 100755
index 0000000..8d5c978
--- /dev/null
+++ b/diffscript
@@ -0,0 +1,6 @@
+#! /bin/sh
+export GIT_INDEX_FILE=$(mktemp) || exit
+rm -f $GIT_INDEX_FILE
+trap "rm -f $GIT_INDEX_FILE" 0 1 2 3 15
+git add -A
+git diff $1:-HEAD
index 3ec370c..d319048 100644
--- a/foo
+++ b/foo
@@ -1 +1 @@
-I am a foo
+I was foo, am now resurrected

这个diffscript 默认与HEAD 不同。因此,如果我们在不带参数的情况下运行它,我们会将 commmit 11b241c 与索引/工作树进行比较(因为我们 git add -A大部分与我们比较是与索引还是工作树无关——树,此时:它们本质上是相同的,以 .gitignore 指令为模)。

trap ... 行确保我们删除临时索引,无论脚本是由 ^C(信号 2,SIGINT)还是网络断开(信号 1,SIGHUP)或 QUIT(信号 3,SIGQUIT)终止或 TERMINATE(信号 15,SIGTERM),或只是正常退出(0,不是信号,只是正常终止)。

令人讨厌的是,Git 坚持认为该文件要么根本不存在,要么具有索引文件签名(不允许空文件),因此我们删除了 mktemp 制作的临时文件,以便 git add 步骤可以创建它带有正确的签名。

【讨论】:

我不明白。 diffscript 只是将所有内容添加到索引中,然后将其保留在那里 注意GIT_INDEX_FILE=$(mktemp) || exit这一行。它不使用 the 索引,它使用一些 other 索引,我们在完成后将其删除。 索引保持不变!但是,需要修复错误:export! (我没有正确测试) 啊,对了,我没有意识到GIT_INDEX_FILE有一个功能。但现在我得到“索引文件小于预期” 呃,另一个错误,将修复。顺便说一句,另一种技术是在运行任何git adds 之前将“真实”索引文件复制到临时文件。这就是 git commit --include &lt;paths&gt; 在内部工作的方式,例如。 非常感谢。正是我想要的。【参考方案2】:

你可以看看:

git add --intent-to-add(同git add -N

这只会将一个空条目附加到索引中,而不是文件本身。使用 diff 命令时会看到差异。

GIT 文档:

--intent-to-add

这对于显示未暂存的内容等非常有用 使用 git diff 处理此类文件并使用 git commit -a 提交它们。> 仅记录稍后将添加路径的事实。一个条目 路径放在索引中,没有内容。

【讨论】:

朝着正确的方向前进,但不像我希望的那样自动和原子。 (需要添加所有未跟踪的文件,记住它们,然后再次重置它们)

以上是关于关于工作树的 git diff,包括未跟踪的文件的主要内容,如果未能解决你的问题,请参考以下文章

Git one-liner 添加所有内容(包括未跟踪的文件)并提交 [重复]

git:撤消所有工作目录更改,包括新文件

如何在 Git 上添加未跟踪的文件?

markdown Git重置回提交的原始副本,包括删除未跟踪的文件

git diff 命令

如何从当前 Git 工作树中删除本地(未跟踪)文件