关于工作树的 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>
然后将给定的工作树与当前的工作树进行比较,使用现有的索引(现在有未跟踪文件的条目)来决定将哪些工作树版本与给定的<hash>
(<hash>
可能是提交 ID、树 ID、分支名称或 Git 可以解析为树的任何内容)。但这确实弄乱了索引,正如你所说,你:
希望以最大程度的原子性和健壮的方式做到这一点
诀窍是使用 临时 索引。
这里的初始提交有文件bar
和foo
;第二次提交删除了文件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 add
s 之前将“真实”索引文件复制到临时文件。这就是 git commit --include <paths>
在内部工作的方式,例如。
非常感谢。正是我想要的。【参考方案2】:
你可以看看:
git add --intent-to-add
(同git add -N
)
这只会将一个空条目附加到索引中,而不是文件本身。使用 diff 命令时会看到差异。
GIT 文档:
--intent-to-add
这对于显示未暂存的内容等非常有用 使用 git diff 处理此类文件并使用 git commit -a 提交它们。> 仅记录稍后将添加路径的事实。一个条目 路径放在索引中,没有内容。
【讨论】:
朝着正确的方向前进,但不像我希望的那样自动和原子。 (需要添加所有未跟踪的文件,记住它们,然后再次重置它们)以上是关于关于工作树的 git diff,包括未跟踪的文件的主要内容,如果未能解决你的问题,请参考以下文章
Git one-liner 添加所有内容(包括未跟踪的文件)并提交 [重复]