【问题标题】:git fails to detect renaminggit 无法检测到重命名
【发布时间】:2012-11-28 03:35:33
【问题描述】:

一个分支 (refactoringBranch) 进行了完整的目录重组。文件移动得乱七八糟,但内容被保留了。

我尝试合并: git merge --no-ff -Xrename-threshold=15 -Xpatience -Xignore-space-change refactoringBranch

git status 显示大约一半的文件重命名识别。但在项目中的 10000 个文件中,有一半未被识别为已移动。

一个例子是:

# On branch master
# Changes to be committed:

#   deleted:    404.php
#   new file:   public_html/404.php
    ...
#   deleted:    AnotherFile.php
#   new file:   public_html/AnotherFile.php
    ...
#   renamed:    contracts/css/view.css -> public_html/contracts/css/view.css

建议?


史前史

重构是在 git 之外进行的。我做了以下事情:

  1. 创建了源自masterrefactoringBranch
  2. refactoringBranch 中删除了更改的结构,这意味着我在其他一些目录中进行了更改,然后将它们复制粘贴到我的git 存储库中。
  3. 添加并提交所有内容,然后尝试合并。

这是我的工作流程:

git checkout -b refactoringBranch
cp -R other/place/* ./
git add . -A
git commit -a -m "blabla"
git checkout master
git merge --no-ff -Xrename-threshold=15 -Xpatience -Xignore-space-change refactoringBranch

问题可能出现在git add . -A 步骤上。 因为如果那里的重命名检测是正确的,我会假设合并会完美无缺。

【问题讨论】:

  • 我用外部工具检查过,master 中的404.phprefactoringBranch 上的public_html/404.php 之间的相似性似乎是95.37%
  • 那是什么外部工具?您是否使用 git diff -M90% --stat master refactoringBranch 之类的东西测试了不同的重命名阈值(尝试使用各种值而不是 90%)?
  • 该工具是php.net/similar_text。在我的合并命令中,我使用的阈值低至 15%。我希望它会通过。
  • 该工作流程表明 master 也是您的合并基础。对吗?

标签: git


【解决方案1】:

这是让 git 知道你重命名文件的完美方法。

git mv old-file-name.ts new-file-name.ts

然后 git 会接受这些更改。

享受吧。

【讨论】:

  • 在重命名完成后有什么方法可以应用这个?
  • 什么是 .ts,它为什么起作用?如果您的意思只是 git mv file1 file2 那么如果您对文件进行大量更改,它将不起作用。
【解决方案2】:

您可以考虑改用git mvhttps://www.kernel.org/pub/software/scm/git/docs/git-mv.html

根据我的经验,它要可靠得多。

【讨论】:

    【解决方案3】:

    OS X 可以区分大小写,但不敏感。 Git ​​ 区分大小写。如果您更改了文件名并且唯一的更改是大小写更改,请将文件重命名为原来的名称,然后改用 git mv 重命名。

    【讨论】:

    • 非常简单的解决方案解决了我的问题。对于那些对“git mv oldfilename newfilename”指令的作用感到好奇的人,这里是文档的链接:kernel.org/pub/software/scm/git/docs/git-mv.html。基本上它会自动更新旧文件和新文件的索引。谢谢!
    • 如果您将文件夹名称更改为相同但大小写不同,则会失败并显示“权限被拒绝”。但是,stackoverflow.com/a/14580217/5593532 可以解决这个问题(首先将其更改为不同的中间名称)。
    • 无需“将文件重命名回原来的样子”,只需 git mv oldcase newcase 即可。
    • @AshishRanjan,如果您不记得 oldcase 怎么办?恢复old case的更好方法是删除文件并使用git(git checkout -- <file_name>)恢复到原始状态,然后重命名(git mv
    【解决方案4】:

    代替git status,尝试git commit --dry-run -a,它可以更好地检测重命名。

    【讨论】:

    • 为什么是减分?这种技术在我的情况下效果很好,一个解释会很好。
    • 你什么都没解释。您使用 --dry-run 这意味着仅“模拟”提交。 op 已经使用了这种技术(只是没有 --dry-run)。
    • 与 git 2.8.0 的结果相同。
    【解决方案5】:

    重命名检测:

    我的最佳猜测是重命名检测失败是由于候选者数量众多。 git 源代码在某些地方有点难以理解,但似乎在重命名检测算法的特定搜索步骤中使用了一些硬编码限制(请参阅diffcore-rename.c),以及要查看的最大对数(配置键 diff.renameLimitmerge.renameLimit)。即使您已将配置的限制设置得适当高,这也可能导致检测失败。可配置限制本身被限制在 [1, 32767] 范围内。

    也许您可以通过首先执行重组步骤来解决此问题:使用 git mv 移动文件而不进行任何内容更改,以匹配新布局,将其提交到新分支上,然后用您的最终版本替换它,这应该只有内容更改,没有重命名。 可能更可靠地检测到没有内容更改的重命名。这只有在您所做的重组相当简单的情况下才实用,而且我不确定它是否会解决重命名检测失败。

    或者,也许您可​​以使用一些简单的文件分组将更改拆分为单独的提交,以便在每次提交中进行重命名检测的候选者更少。

    合并:

    不幸的是,通过将新分支建立在 master 之上,您向 git 提供了有关合并的错误信息。无论是否正确检测到重命名,当新创建的分支与 master 合并时,它将覆盖 master 中的所有内容,因为从 git 的角度来看,master 中没有尚未包含在新分支中的更改.

    【讨论】:

    • 在 git 中可配置设置的类似讨论here
    【解决方案6】:

    每当我不得不重命名/移动文件而忘记明确告诉 GIT 时,我都会使用

    git add . -A
    

    自动检测移动的文件

    【讨论】:

    • 此外,git 没有“显式”方法来告诉它任何东西被移动了。它应该在合并期间自动完成。
    • 为了明确告诉 GIT 你重命名/移动文件使用 git mv {old} {new} 而不是 unix mv 命令
    • 在任何一种情况下, git add 都会导致相同的结果(一半检测到,一半未检测到)
    猜你喜欢
    • 2011-08-26
    • 2019-08-12
    • 2011-02-06
    • 1970-01-01
    • 2018-03-30
    • 2011-12-17
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多