执行 git diff 时删除文件模式是什么意思?

Sta*_*k18 1 git

我已经获取了原点,并且在执行 git diff origin/master 时看到以下内容:

diff --git a/flash/controllers b/flash/controllers
deleted file mode 120000
index 350cadb..0000000
--- a/flash/controllers
+++ /dev/null
@@ -1 +0,0 @@
-/home/testapp/www/homedir/flash/controllers
\ No newline at end of file
Run Code Online (Sandbox Code Playgroud)

我对这意味着什么感到困惑。这是否意味着如果我进行合并,文件将被删除?这很令人困惑,因为我/flash/controllers/在 gitignore 中。

tor*_*rek 5

TL;DR 版本:虽然下面的所有内容都值得了解,但查看合并将做什么的最简单方法是进行合并。只需确保一切都干净(例如git status,没有任何东西可供您签入),然后运行合并并查看它做了什么。如果您不喜欢结果,请使用以下方法之一中止合并(如果它失败并需要帮助)或退出(如果它成功但您只是不喜欢结果):

git merge --abort  # after merge fails and asks you for help
Run Code Online (Sandbox Code Playgroud)

或者:

git reset --hard HEAD^  # after merge succeeds but you don't like the result
Run Code Online (Sandbox Code Playgroud)

Deleted 意味着在比较两个文件树时,比较“左侧”的树有一些东西,而“右侧”的树不再有它。

所述mode标识一个文件对象的类型,并且120000具体地是指“符号链接”。所以这意味着将 versiona与 version进行比较b,曾经有一个以flash/controllersversion命名的符号链接a,而在 version 中b,不再有。

如果你只是运行git diff origin/master,左边的树(树a)是你当前的工作目录(不是特定的提交!),右边的树(树b)是由origin/master(用于git rev-parse origin/master查看实际的 SHA -1 次提交)。如果您命名两个提交,git diff master origin/master例如,左侧的树是由第一个 SHA-1 命名的树(再次git rev-parse用于查看原始 SHA-1),右侧的树是由第二个命名的树.

这是否意味着如果我进行合并,文件将被删除?

也许; 也许不吧。决定文件是否会被合并删除的是合并和正在合并的项目之间的差异。

假设,例如,a上面表示当前分支尖端的树,可能命名为master,并b表示分支尖端的树命名origin/master(这是一个“远程分支”,但它实际上是存储库中的一个分支; 你刚刚从origin)复制了它。

我们不知道的是master和之间的合并基础origin/master。这将是一些提交——我们只是不知道是哪一个。

假设提交图,如果我们把它画出来,看起来像这样:

...-o-o-B-u   <-- HEAD=master
         \
          t   <-- origin/master
Run Code Online (Sandbox Code Playgroud)

在这里,您在master分支上进行了一次提交。我标记了这个u,为us。与此同时,“他们”(无论他们是谁)在他们的分支上进行了一次提交,他们称之为master以及你正在调用的origin/master;我将此提交标记tthem. 共同的起点——你和他们分歧的点——是我在B这里标记的提交。

您可以使用以下git merge-base命令找到此提交的 SHA-1 ID :

git merge-base HEAD origin/master
Run Code Online (Sandbox Code Playgroud)

如果你这样做:

git diff -M --name-status $(git merge-base HEAD origin/master) origin/master
Run Code Online (Sandbox Code Playgroud)

(这假设有一个shorbash风格的命令行),1 git 会告诉你“他们”在他们的 commit 中添加、修改、删除和重命名了哪些文件t。也就是说,这将 commitB与 的提示进行比较origin/master,即 commit t

如果您与B当前分支的提示进行比较,即与HEAD提交进行比较,您将看到在提交中做了什么u

如果你这样做:

git merge origin/master
Run Code Online (Sandbox Code Playgroud)

git 会尝试合并“你做了什么”和“他们做了什么”。 这是符号链接或任何文件发生的事情的关键。一般有三种可能,虽然只有两种可能:

  • 如果符号链接存在于 中B,那么您可能什么也没做,然后他们删除了它。在这种情况下,git merge将删除它:你什么也没做,他们删除了它,结合这些很容易:删除它。

  • 如果符号链接在 中存在B,那么您添加了它,他们可能什么也没做。在这种情况下,git merge将添加(好吧,保留)它。同样,这很容易组合:你添加了,他们什么也没做,两者的组合是“添加”(或者真的,“保持”)。

  • 如果符号链接存在于 中B,但您更改了它,然后他们删除了它,git merge则会声明冲突并让您自己解决这种情况。这对 git 来说并不容易结合,就像如果你和他们都以不同的方式改变它,它不知道该怎么做。2

(我们知道,或者基于原始git diff输出相信无论如何,与提交关联的树HEAD具有符号链接,而与提交关联的树origin/master没有,因此我们不必担心“两者都创建”或“两者都创建”修改”的情况。)

这很令人困惑,因为我/flash/controllers/在 gitignore 中。

但那是flash/controllers/,带有尾部斜线(我认为,无论哪种方式,前导斜线都没有那么重要——尽管忽略规则有时仍然让我感到困惑)。该gitignore文件包括该位:

   •   If the pattern ends with a slash, it is removed for the purpose of
       the following description, but it would only find a match with a
       directory. In other words, foo/ will match a directory foo and
       paths underneath it, but will not match a regular file or a
       symbolic link foo (this is consistent with the way how pathspec
       works in general in Git).
Run Code Online (Sandbox Code Playgroud)

(还有一个问题,如果文件已经被跟踪,将其添加到.gitignore并不会使其不被跟踪。.gitignore内容仅用于防止文件意外跟踪,并避免git status抱怨它们。)


1事实上,获取对合并基的差异有一个特殊的git diff语法,重新利用A...B来自gitrevisions. 为了找到之间的合并基础AB它比较的内容提交B,你可以写git diff A...B。与往常一样,省略一端等同于指定HEAD,因此git diff ...origin/master将合并基(HEADorigin/master)与 进行比较origin/master;和git diff origin/master...比较合并基(同一两次提交的)来HEAD。添加-M以检测重命名,您就可以进行比较git merge

(我在这里故意省略了一些带有“递归定义”虚拟合并基础的额外细节。在两个“同样有效”的合并基础祖先的情况下,git diff将任意选择一个,但git mergerecursive策略将构造一个虚拟合并基础。这些变得有点复杂。)

2对于大多数常规文件,如果您和他们都修改了它们,git 会尝试通过决定哪些更改是独立的(git 保留每个此类更改的一个副本)以及哪些更改是相同的(git 保留这些更改的一个副本)来组合更改以及,而不是放入两个副本)。git在这方面是否以及何时是正确的——具体来说,关于哪些变化是“相同的”,哪些是“不同的”——是另一回事。它通常做得很好,但它只是一个计算机算法,有时会出错,因此您,用户,必须以某种方式检查结果(例如,“它是否仍在构建,它是否通过测试,它看起来是否正常” ,无论你有什么测试),要真正确定它。