git 与包括未跟踪文件在内的工作树的差异
git diff with respect to working tree including untracked files
我有一个旧的提交 A。我现在在提交 B=HEAD!=A,并且想比较我的工作目录的状态,包括未跟踪的文件,与 A.
原因是当前未跟踪的文件是提交 A
的一部分,因此它们不会出现在我想要的 diff 中,因此不会混乱。
作为解决方法,我可以在差异之前手动 git add <all the untracked files>
并在差异之后手动 git reset <all the untracked files>
。但是,有许多未跟踪的文件,我想以最大程度的原子性和鲁棒性的方式来执行此操作,因为我在脚本中执行所有这些操作。
编辑:This question 还涉及针对未跟踪文件的差异。但是,那里的答案需要手动添加和稍后删除未跟踪的文件,我更喜欢一种更自动地执行此操作的解决方案,并且以原子方式在脚本上下文中防止错误发生中断。接受的答案正是这样做的,并且确实与链接问题的答案不同。
你可以看看:
git add --intent-to-add
(与git add -N
相同)
这只会将一个空条目附加到索引,而不是文件本身。使用 diff 命令时会看到差异。
GIT 文档:
--intent-to-add
This is useful for, among other things, showing the unstaged content
of such files with git diff and committing them with git commit -a.> Record only the fact that the path will be added later. An entry for
the path is placed in the index with no content.
正如其他人所建议的,您可以使用 git add -N
将虚拟条目添加到索引中。 运行:
git diff <hash>
然后将给定的与当前工作树进行比较,使用现有索引(现在具有未跟踪文件的条目)来决定将哪个工作树版本与给定的<hash>
(<hash>
可以是提交 ID、树 ID、分支名称或 Git 可以解析为树的任何内容)。但这确实弄乱了索引,正如你所说,你:
would like to do this in a maximally atomic and robust way
诀窍是使用 临时 索引。
这里的初始提交有文件 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
比较。因此,如果我们 运行 它没有参数,我们会将 commit 11b241c
与 index/work-tree 进行比较(因为我们 git add -A
它 mostly在这一点上,我们是比较索引还是工作树并不重要:它们本质上是相同的,取模 .gitignore
指令)。
trap ...
行确保我们删除了临时索引,无论脚本是被 ^C(信号 2,SIGINT)终止,还是网络断开(信号 1,SIGHUP)或 QUIT(信号3, SIGQUIT) or TERMINATE (signal 15, SIGTERM), or just normally exits (0, not a signal, just normal termination).
恼人的是,Git 坚持认为该文件要么根本不存在,要么有一个索引文件签名——空文件是不允许的——所以我们删除了 mktemp
创建的临时文件,所以git add
步骤可以使用正确的签名创建它。
我有一个旧的提交 A。我现在在提交 B=HEAD!=A,并且想比较我的工作目录的状态,包括未跟踪的文件,与 A.
原因是当前未跟踪的文件是提交 A
的一部分,因此它们不会出现在我想要的 diff 中,因此不会混乱。
作为解决方法,我可以在差异之前手动 git add <all the untracked files>
并在差异之后手动 git reset <all the untracked files>
。但是,有许多未跟踪的文件,我想以最大程度的原子性和鲁棒性的方式来执行此操作,因为我在脚本中执行所有这些操作。
编辑:This question 还涉及针对未跟踪文件的差异。但是,那里的答案需要手动添加和稍后删除未跟踪的文件,我更喜欢一种更自动地执行此操作的解决方案,并且以原子方式在脚本上下文中防止错误发生中断。接受的答案正是这样做的,并且确实与链接问题的答案不同。
你可以看看:
git add --intent-to-add
(与git add -N
相同)
这只会将一个空条目附加到索引,而不是文件本身。使用 diff 命令时会看到差异。
GIT 文档:
--intent-to-add
This is useful for, among other things, showing the unstaged content of such files with git diff and committing them with git commit -a.> Record only the fact that the path will be added later. An entry for the path is placed in the index with no content.
正如其他人所建议的,您可以使用 git add -N
将虚拟条目添加到索引中。 运行:
git diff <hash>
然后将给定的与当前工作树进行比较,使用现有索引(现在具有未跟踪文件的条目)来决定将哪个工作树版本与给定的<hash>
(<hash>
可以是提交 ID、树 ID、分支名称或 Git 可以解析为树的任何内容)。但这确实弄乱了索引,正如你所说,你:
would like to do this in a maximally atomic and robust way
诀窍是使用 临时 索引。
这里的初始提交有文件 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
比较。因此,如果我们 运行 它没有参数,我们会将 commit 11b241c
与 index/work-tree 进行比较(因为我们 git add -A
它 mostly在这一点上,我们是比较索引还是工作树并不重要:它们本质上是相同的,取模 .gitignore
指令)。
trap ...
行确保我们删除了临时索引,无论脚本是被 ^C(信号 2,SIGINT)终止,还是网络断开(信号 1,SIGHUP)或 QUIT(信号3, SIGQUIT) or TERMINATE (signal 15, SIGTERM), or just normally exits (0, not a signal, just normal termination).
恼人的是,Git 坚持认为该文件要么根本不存在,要么有一个索引文件签名——空文件是不允许的——所以我们删除了 mktemp
创建的临时文件,所以git add
步骤可以使用正确的签名创建它。