在 git add -h
命令中,我可以看到以下选项:
-N, --intent-to-add record only the fact that the path will be added later
但我不明白应该在什么情况下使用这个选项。这个选项到底是做什么的,应该如何使用它?
在 git add -h
命令中,我可以看到以下选项:
-N, --intent-to-add record only the fact that the path will be added later
但我不明白应该在什么情况下使用这个选项。这个选项到底是做什么的,应该如何使用它?
Blue112的回答部分正确。 git add --intent-to-add
确实会为工作副本中每个指定的未跟踪文件添加一个空文件到暂存区/索引中,但其中一个主要目的是使您能够使用git diff
来比较尚未添加到Git存储库中的文件,通过将未跟踪的文件与其在暂存区中的空版本进行比较:
$ echo foo > foo.txt
$ git diff foo.txt
$ git add --intent-to-add foo.txt
$ git status
On branch master
Your branch is up-to-date with 'origin/master'.
Changes to be committed:
(use "git reset HEAD <file>..." to unstage)
new file: foo.txt
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git checkout -- <file>..." to discard changes in working directory)
modified: foo.txt
$ git diff --staged foo.txt
diff --git a/foo.txt b/foo.txt
new file mode 100644
index 0000000..e69de29
$ git diff foo.txt
diff --git a/foo.txt b/foo.txt
index e69de29..257cc56 100644
--- a/foo.txt
+++ b/foo.txt
@@ -0,0 +1 @@
+foo
一旦您已经对文件进行了差异比较,您可以通过简单地执行普通的git add
命令将非空版本添加到暂存区/索引中:
$ git add foo.txt
git commit -a
提交未跟踪的文件同样地,由于--intent-to-add
可以通过向暂存区/索引添加空文件来使未跟踪的文件“已知”于Git,因此它还允许您使用git commit --all
或git commit -a
提交这些文件以及已知修改过的文件,否则您将无法执行此操作。
使用commit命令的
-a
[或--all
]选项会自动从所有已知文件(即已在索引中列出的所有文件)中“添加”更改......然后执行实际提交
-N --intent-to-add
Record only the fact that the path will be added later. An entry for the path is placed in the index with no content. This is useful for, among other things, showing the unstaged content of such files with
git diff
and committing them withgit commit -a
.
--intent-to-add
对我来说似乎没有用处。比如我有一个新文件 foo.txt
,里面有 100 行代码。当我运行 git add -N foo.txt
,再运行 git diff foo.txt
,我会看到添加了 100 行代码。(这好像相当于剪切文件的所有内容,添加文件,然后将其粘贴回文件中。)现在当我进行更改——比如添加一行——并再次运行 git diff,我会看到添加了 101 行代码。因此,在舞台上添加一个空文件路径对于查看差异并没有帮助。 - chharveygit diff
时,我喜欢看到我写过的 所有 代码,这样我就可以在提交和打开 PR 之前在一个地方自我审查所有内容。 - Philip-N
选项,则无法对新添加的文件打补丁。 - WloHutest1 test2 test3
,其中test1已经被提交并且被修改过,test2是通过git add
添加的,而test3则是通过git add -N
添加的。当我运行git commit --all
时,这三个文件都会被包含在提交中。因此,我不明白你所说的“启用git commit --all”的意思。 - Olsgaardgit add -N
命令可以让你使用 git commit -a
命令提交一个未被追踪的文件,即使在执行了 git add -N
命令之后,该文件仍然是未被追踪的。否则,你将无法通过 git commit -a
命令提交未被追踪的文件。 - Fab1nuser456814's answer很好地解释了git add -N
的作用。我只是想更详细地解释一下背后发生了什么。
您可以将git视为维护文件更改历史记录,例如创建、修改和删除(我们称之为增量)。这些增量在最近的提交之前都很容易理解,但是当您在项目中工作以准备新的提交时,情况会变得更加复杂。在此情况下,有三种不同类型的增量。
(顺便说一句:大多数人初次接触git时,被教导的是“在git中提交需要两个步骤;首先执行git add
,然后才能执行git commit
”。虽然这是正确的,但它只关注了要提交的更改类型。git add -N
需要理解其他类型的增量。)
通常称为“暂存更改”,如果有任何更改,则会在运行git status
时出现在顶部。如果您的shell支持颜色,则它们将呈绿色。
当您git add
一个文件时,它会被提升到该类别。这些是在不带任何标志的情况下运行git commit
时实际包含的更改。
如果有的话,这些变化会在你运行git status
时出现在第二个位置。如果你的shell支持颜色,它们将会是红色的。
这些是你对git仓库中的文件所做的更改,尚未提交且未移动到#1。当你编辑一个文件并保存后,默认情况下它会出现在此类别中。
为了使文件出现在这个类别中,它必须已经存在于最近的提交中,或者如果在#1中的更改要被提交,则需要添加。否则,它将出现在第三类别中。
(注意:因为你可以选择何时将文件“提升”到第一类别,所以同一个文件可能会同时出现在#1和#2中。例如,我可以看到
modified: abc.txt
在#1中以绿色显示,并且
modified: abc.txt
当文件同时在 #1 和 #2 中出现时,会以红色显示。这种情况可能发生在我将文件提升到 #1 后,稍后又对其进行了一些更改。#1 中的条目引用了我提升文件之前所做的更改差异,例如添加了一行代码,而 #2 中的条目引用了我随后所做的更改差异,例如在顶部添加了注释。如果我更有组织性,我会在将文件提升到 #1 之前先进行所有更改,以完全避免这种情况的出现。
如果存在任何未跟踪的文件,这些差异将在运行 git status
时最后显示出来,并且如果您的shell支持颜色,则会以红色显示。
这些都是不在最新提交中且不在 #1 中的所有文件。虽然从技术上讲,它们是差异,因为添加它们会更改提交,但有可能文件一直存在,只是人们不希望 git 记录有关它的任何信息。(在这种情况下,您应该将该文件添加到.gitignore中,它将停止在 git status
中显示。)
当您创建全新的文件时,它将显示在此类别中。
git add -N
有什么关系呢?git add -N
的目的是使处理 #3 差异变得更加容易。正如上面接受的答案所引用的那样,git diff
让您查看实际准备好的差异。这里有一组与 git diff
一起使用的良好命令。
git diff
只显示#1和#2之间的差异(即#2中的增量)。
git diff --staged
仅显示#1中的增量。
git diff HEAD
仅显示将#1和#2合并后的增量。
请注意,这些命令都没有查看#3。但是,通过运行git add -N
,您基本上执行以下操作:
git add
“文件创建”增量到#1中这会使第二个增量出现在#2中。现在,新文件完全不在#3中,您可以使用git diff
命令进行操作。
至于git commit -a
,它实际上做的是:
git add
#2中的所有内容,以便与#1中的所有内容一起进行暂存git commit
(从#1中获取所有内容,包括刚刚添加的内容,并创建一个实际的提交)如果没有git add -N
,则此命令会忽略#3中的新文件;但是,您可以看到在运行git add -N
后,您的新文件已分布在#1和#2中,并将包含在提交中。
好的,我已经解释了所有我想要解释的内容。如果你想检查自己的理解,可以跟着下面的例子走:
I make a new git repo.
sh-4.1$ cd ~/Desktop
sh-4.1$ mkdir git-demo
sh-4.1$ cd git-demo
sh-4.1$ git init
Initialized empty Git repository in /local/home/Michael/Desktop/git-demo/.git/
git status
shows me this repo is empty.
sh-4.1$ git status
On branch master
Initial commit
nothing to commit (create/copy files and use "git add" to track)
I make some new files.
sh-4.1$ echo "this is the abc file" > abc.txt
sh-4.1$ echo "this is the def file" > def.txt
sh-4.1$ echo "this is the ghi file" > ghi.txt
git status
shows me all the new files are currently in category #3.
sh-4.1$ git status
On branch master
Initial commit
Untracked files:
(use "git add <file>..." to include in what will be committed)
abc.txt
def.txt
ghi.txt
nothing added to commit but untracked files present (use "git add" to track)
git diff
does nothing, since it doesn't operate on #3.
sh-4.1$ git diff
I commit one file, add another one, and add -N
the third one.
sh-4.1$ git add abc.txt && git commit -m "some commit message"
[master (root-commit) 442c173] some commit message
1 file changed, 1 insertion(+)
create mode 100644 abc.txt
sh-4.1$ git add def.txt
sh-4.1$ git add -N ghi.txt
In git status
, abc.txt
no longer shows up, since it has already been committed. def.txt
only shows up in category #1 since the whole file has been added. ghi.txt
shows up in categories #1 and #2.
sh-4.1$ git status
On branch master
Changes to be committed:
(use "git reset HEAD <file>..." to unstage)
new file: def.txt
new file: ghi.txt
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git checkout -- <file>..." to discard changes in working directory)
modified: ghi.txt
By running git diff
, I can show all the deltas listed in #2. The only delta that shows up is that I added a line to ghi.txt
.
sh-4.1$ git diff
diff --git a/ghi.txt b/ghi.txt
index e69de29..8a8dee2 100644
--- a/ghi.txt
+++ b/ghi.txt
@@ -0,0 +1 @@
+this is the ghi file
By running git diff --staged
, I can show all the deltas listed in #1. Three of them show up: creating a new file def.txt
, adding a line in def.txt
, and creating a new file ghi.txt
. Even though there are 2 deltas for def.txt
, the file name itself is only output one time in example 7 above, to avoid clutter.
sh-4.1$ git diff --staged
diff --git a/def.txt b/def.txt
new file mode 100644
index 0000000..48baf27
--- /dev/null
+++ b/def.txt
@@ -0,0 +1 @@
+this is the def file
diff --git a/ghi.txt b/ghi.txt
new file mode 100644
index 0000000..e69de29
git add file && git diff --staged
时,使用git add -N file && git diff
有何意义?我仍然不太明白使用-N
的意义。 - tmillrgit add -N
有时会跳过某些条目。
请查看由Nguyễn Thái Ngọc Duy (pclouds
)于2016年7月16日提交的提交6d6a782, 提交c041d54, 提交378932d, 提交f9e7d9f。
(于2016年7月25日由Junio C Hamano -- gitster
--合并至提交3cc75c1)
如果您有:
a-file
subdir/file1
subdir/file2
subdir/file3
the-last-file
你需要添加-N
参数来添加所有文件...然后subdir
中的文件不会被记录为i-t-a(“打算添加”)条目。
cache-tree.c
:修复有时跳过目录更新的i-t-a条目问题提交 3cf773e(cache-tree
:修复当存在CE_REMOVE
时写入缓存树的问题-2012年12月16日-Git v1.8.1.1)在从索引构建树对象时跳过i-t-a条目。不幸的是,它可能会跳过太多。
如果subdir/file1
是i-t-a,由于此代码中的错误条件,我们仍然认为“subdir
”是i-t-a文件,而没有将“subdir
”写下并跳到最后一个文件。
结果树现在只有两个项目:a-file
和the-last-file
。
subdir
也应该在那里(即使它只记录了两个子条目file2
和file3
)。
git status
在Git 2.17(2018年第二季度,四年后)得到了改进:在工作树中移动路径(因此使其看起来像是“已删除”),然后使用-N
选项添加它(因此使其看起来像是“已添加”),git status
将其检测为重命名,但没有正确报告旧和新的路径名。
请查看 提交 176ea74, 提交 5134ccd, 提交 ea56f97, 提交 98bc94e, 提交 06dba2b, 提交 6de5aaf (2017年12月27日) 由 Nguyễn Thái Ngọc Duy (pclouds
) 提交。
协助者: Igor Djordjevic (boogisha
)。
(由 Junio C Hamano -- gitster
-- 在 提交 12accdc 中合并,于2018年2月27日)。
提醒: ita
或 i-t-a
表示 "intended-to-add",即 -N
的作用。
wt-status.c
: 处理工作树重命名在 425a28e (
diff-lib
: 允许 ita 条目被视为 "尚未存在于索引中" - 2016-10-24, Git 2.11.0-rc0) 之前,索引中从来没有 "新文件",这基本上禁用了重命名检测,因为我们只有在 diff 对中出现新文件时才会检测到重命名。在那个提交之后,一个 i-t-a 条目可以出现在 "
git diff-files
" 中作为新文件。但是wt-status.c
中的 diff 回调函数不处理这种情况,并生成不正确的状态输出。