使用git mv进行Anomolies,编辑然后git add

时间:2017-03-24 01:33:51

标签: git

我的repo中有几个文件,我用git mv重命名了它们。在做git status时,我看到了正确的:

On branch lnxkrnl-chg123-just-to-annoy-linus
Your branch is up-to-date with 'origin/lnxkrnl-chg123-just-to-annoy-linus
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)
    renamed:    file1.service -> RobinHood.service
    renamed:    file1.sh -> RobinHood.sh

然后我按照预期编辑这些文件:

On branch lnxkrnl-chg123-just-to-annoy-linus
Your branch is up-to-date with 'origin/lnxkrnl-chg123-just-to-annoy-linus'.
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)
    renamed:    file1.service -> RobinHood.service
    renamed:    file1.sh -> RobinHood.sh
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:   RobinHood.service
    modified:   RobinHood.sh

现在,当我实际添加这些新文件用于登台时,其中一个似乎是智能处理而另一个则没有。我会告诉读者他们如何定义&#34;智能&#34;,足以说他们看起来被区别对待,尽管他们都对他们执行了相同的操作:

On branch lnxkrnl-chg123-just-to-annoy-linus
Your branch is up-to-date with 'origin/lnxkrnl-chg123-just-to-annoy-linus'.
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

    renamed:    file1.service -> RobinHood.service
    new file:   RobinHood.sh
    deleted:    file1.sh

服务文件的提交更改似乎是一个简单的重命名,虽然我确实改变了文件内容(虽然只是一个小的方式,只是在几行上改变了一些文本)。

shell脚本的提交更改(已编辑得更多,添加了许多新行)是删除/新操作。

为什么git在这里有所区别?我认为显示类似的内容会更有意义:

renamed & edited:    file1.service -> RobinHood.service
renamed & edited:    file1.sh -> RobinHood.sh

但是,即使没有这种详细程度,我也希望git以相同的方式处理相同的操作。

我在Ubuntu 16.04下使用的git版本是2.7.4。

1 个答案:

答案 0 :(得分:3)

Git实际上知道文件已重命名。无论您如何暂存和提交重命名,即是否使用git mv,都是如此。 Git所做的事情 - 对于提交的git diff / git show,以及您尚未提交的git status事件都是如此 - guess 。< / p>

当你只做 的事情是重命名一些文件或文件时,Git可以做出非常准确的猜测。也就是说,它每次都会正确。 1 那是因为它猜测的方式环顾四周:“嗯,我有文件A,{ {1}}和B之前。我现在有CAB。我想知道......我知道{{1}我们现在看看D中的内容。哦,嘿,看,C现在的内容正是D之前的内容!我打赌用户重命名为DC!“

但是,如果您开始更改内容,则会变得更难。在您的情况下,Git发现CD已消失。同时,它看到这些文件file1.servicefile1.sh是新的。因此,它将所有已经消失的文件中的 used 与所有新添加的文件中的内容进行比较。它们都不再与完全匹配。但其中一些看起来很可疑相似

因此,Git为每个文件对计算“相似性索引”。碰巧的是,旧的(现在已经消失的)RobinHood.service与旧RobinHood.sh“非常相似”(至少50%)。所以它选择那对称为重命名。

与此同时,RobinHood.servicefile1.service现在是 dis - 相似(低于相同的50%相似度要求),Git决定这些是完全不同的文件。您必须刚删除第一个,然后从头开始创建第二个。

1 好吧,每次几乎。特别是,如果您有两个相同的文件file1.shRobinHood.sh,并将它们重命名为C3PO,Git可能会认为您将R2重命名为{ {1}}和D2C3,或者可能认为您已将R2重命名为POD2重命名为PO。但是,如果R2C3是绝对的,100%,逐位相同,为什么哪个旧的哪个成为新的呢?

D2实际上运行两个 C3 s

这在PO输出中有点复杂,因为git status实际上在内部运行了两个 git diff命令,一个用来比较git status提交到索引,以及将索引与工作树进行比较的索引。在您git status之前,git diff --name-status --find-renames提交版本与索引版本完全匹配。索引版本具有不同的名称,因此Git将这些视为重命名。然后,索引版本具有与工作树版本相同的名称,因此Git假定它们是相同的文件(不需要重命名检测)。只有当您通过HEAD将工作树版本重新复制到索引版本时,才会将这两个阶段“比较HEAD与索引,然后将索引与工作树进行比较”分崩离析。

出于同样的原因,如果您git add自行重命名,然后HEAD修改,您将稍后通过逐步执行每个提交 - 能够恢复,以编程方式,重命名的事实。如果您git add重命名和更改,Git以后不会恢复重命名(因为它现在没有恢复)。