代码之家  ›  专栏  ›  技术社区  ›  sixeyes

文件报告为新建/删除时如何区分更改

  •  0
  • sixeyes  · 技术社区  · 7 年前

    我重命名了两个文件并做了一些更改(在VisualStudio中)。

        On branch master
    Your branch is up to date with 'origin/master'.
    
    Changes to be committed:
      (use "git reset HEAD <file>..." to unstage)
    
        deleted:    Core/Models/Metadata/MetadataModel.cs
        deleted:    Core/Models/Metadata/MetadataModelCollection.cs
        new file:   Core/Models/Metadata/MetadataValueModel.cs
        new file:   Core/Models/Metadata/MetadataValueModelCollection.cs
    

    如果我尝试git diff——staged,它不会显示已删除文件和新文件之间的差异。而是将每个文件中的所有行都列为已删除或已添加。这并不奇怪,因为git没有意识到这是一个更名。

    如何区分MetadataModel.cs和MetadataValueModel.cs? 或者MetadataModelCollection.cs和MetadataValueModelCollection.cs?

    1 回复  |  直到 7 年前
        1
  •  2
  •   torek    7 年前

    TL;博士

    这里有两种选择:要么进行多个提交,在每个步骤中进行较小的更改。或者,使用 --find-renames= percentage -X find-renames=... 对于 git merge 但是 --find-renames=... -M... 对于 git diff ),将相似性阈值从默认值的50%降低。请注意,没有用于执行此操作的旋钮 git status :

    长的

    这从根本上说是一个关于 The Ship of Theseus ,或祖父的斧头悖论。(“这是我祖父的斧头。我父亲换了柄,我换了头,但它是同一把斧头。还是?”

    知道文件“old.name”被(1)重命名为“new.ext”,并且(2)在时间点A和时间点B之间进行了大量更改,因此即使整个名称不同,大部分内容也不同,我们还是应该称它为“同一”文件?嗯,可能是你自己重新命名的,所以当然

    最后一个问题的答案是 ,Git不会知道。简单地说 不记录 这个信息。Git只是制作和使用快照。快照 Core/Models/Metadata/MetadataModel.cs 有一个同名的文件。如果要比较的两个快照都有一个同名文件,Git假定 这两个文件是“相同”的文件,只是有一些更改的内容。如果一个快照包含该文件,而另一个快照不包含该文件,则会更加复杂。

    Git所做的是(尝试) 发现 Core/Models/Metadata/MetadataModel.cs 右侧快照没有,但左侧快照有 Core/Models/Metadata/MetadataValueModel.cs . 例如,这里就是这样。

    在这种情况下,文件可能被重命名(也可能被修改)。如果您要求Git这样做,Git将比较 目录 全部的 位于右侧而非左侧的文件。对于内容足够相似的任何两个文件,Git都会为这对文件分配一个“相似性分数”,Git将其表示为一个百分比,一个介于0%(完全不相似)和100%(完全相同)之间的数字。

    100%相同的案例特别有用,因为它保证工作并且非常快。 2. 所以如果你 档案 根本不改变

    完成中间提交后,您可以对重命名的文件进行七次大规模更改,然后再进行一次提交。当Git比较父提交和子提交时,所有文件都具有相同的属性 ,即使其中一些文件的内容发生了巨大的变化,Git也可以为您提供一个文件到一个文件的差异,以供配对文件使用 改名。(再次参见脚注1。)

    不会 比较第一个快照(重命名前)和最后一个快照(重命名后)时的帮助 后大变革。它只会帮助你重新命名为后重命名,然后作为第二步,后重命名为后大规模更改;或者等效地,一次一个地向后提交,就像Git通常做的那样。所以这对以后的工作没有多大帮助 合并分支

    适用于不适用的情况,包括 时间,什么时候 git diff --find-renames 在基础和提示上提交,而不查看中间的任何提交 降低最小相似度 . 我们在上面所做的是,通过两次提交,利用了快速简单的情况:给定两个名称不同但内容完全相同的文件,Git可以轻松地将它们配对。但给定两个名称不同的文件,并且只有90%的内容相似,Git仍然可以将它们配对。这需要更多的工作。

    在重命名的文件中,很难说这两个文件是相似的。但Git将尝试任何方式,它将尝试所有可能的配对。 3. 最好的匹配,不管是什么,都要选一个, 只要 它符合或超过标准 与您指定的匹配。这一最低标准默认为50%。

    git diff --find-renames=30 30%,以及 git merge -X find-renames=30 在合并期间使用相同的缩减限制。你怎么知道用什么百分比?答案真的很简单 试试看 相似性指数的计算有点奇怪,所以你只需要进行实验,看看什么对你的案例有效。如果您有两个提交哈希ID,则可以运行 git diff --find-renames=25 --name-status --diff-filter=R

    当你跑的时候 git状态 ,就是这样 差异比较 s、 两棵树中的每一棵:

    • HEAD vs指数

    两种比较都启用了重命名检测,并将其设置为50%。没有改变这一点的选项。

    索引和工作树都不是实际的提交,因此您不能完全将它们交给 差异比较 但是 差异比较

    git diff --cached --name-status --find-renames=...  # for HEAD vs index
    git diff --name-status --find-renames=...           # for index vs work-tree
    

    添加 --diff-filter=R

    注意 --find-renames 自Git 2.9以来默认为打开,在早期的Git版本中默认为关闭。使用 --查找重命名 以50%或您提供的数字打开检测。配置设置 diff.renames true , false copies copy 差异比较 git log git show )使用已配置的 差异重命名


    差异比较 打破 配对。也就是说,如果您有两个名称相同但内容完全不同的文件,您可以告诉Git: 此选项在中不可用 ,只在 .

    2. Git通过散列ID存储每个内容,因此检测提交A中名为X的文件与提交B中名为Y的文件100%相同只需查看散列ID即可。如果哈希ID匹配,则文件也匹配。找到了这些100%相同的内容匹配项后,Git现在将A:X与B:Y配对,这两个名称不再位于“要配对的文件”池中。

    请注意,虽然这很快、很容易并且保证可以工作,但如果还有一个B:Z与a:X 100%相同,则无法确定a:X是否将和B:Y或B:Z匹配。在这里,除了名称检测之外,您可能希望启用Git的 复制 检测,这样Git就可以说A:X得到了 抄袭 对于B:Y和B:Z。这里的细节,交互,变得有点复杂。

    事实上,Git尝试的配对数量是有限制的。重命名检测代码有两个文件名队列: 左路无人匹敌 右翼无与伦比 计算上非常昂贵。因此Git有一个名为 renameLimit ,它限制了队列的长度。这个限制最初是100,然后在Git 1.5.6中增加到200,然后在Git 1.5.6中增加到400 Git 1.7.4.2 / 1.7.5 ,但您可以通过将限制配置为,将其设置为“无限” 0 ,如果您愿意的话(尽管Git仍然会在内部将其限制为32767)。

    diff.renameLimit 但不要设定 merge.renameLimit ,两者都使用 差异重命名限制