git fails to detect renaming
一个分支(refactoringBranch)进行了完整的目录重组。文件被乱动,但内容被保留了下来。
我试图合并:江户十一〔一〕号
Git状态显示大约一半的文件重命名识别。但在项目中的10000个文件中,有一半没有被识别为已移动。
一个例子是:
1 2 3 4 5 6 7 8 9 10
| # 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之外进行的。我做了以下工作:
创建了源自master的refactoringBranch。
在refactoringBranch中删除了修改后的结构,这意味着我在其他目录中进行了修改,只需复制粘贴到我的Git存储库中。
添加并提交所有内容,然后尝试合并。
这是我的工作流程:
1 2 3 4 5 6
| 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.php和refactoringBranch上的public_html/404.php之间的相似性似乎是95.37%。
- 那是什么外部工具?您是否用git diff -M90% --stat master refactoringBranch之类的东西测试了不同的重命名阈值(尝试使用不同的值而不是90%)了?
- 工具是php.net/similar_text。在合并命令中,我使用的阈值低至15%。我希望它能通过。
- 该工作流建议master也是合并基础。对吗?
- 对的。我要把refactoringBranch合并成master。我也尝试过使用cx1(9)和其他值。它几乎可以检测到404.php有85个字符的差异,其中一个master的4141个字符和另一个分支的4226个字符的差异。
- 所以你对大师没有任何改变?那么,您希望合并能做什么呢?
- 让我们在聊天中继续讨论
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源代码在某些地方有点难以遵循,但似乎在重命名检测算法的特定搜索步骤中使用了一些硬编码限制(参见diffcore-rename.c)以及要查看的最大对数的可配置限制(配置键diff.renameLimit和merge.renameLimit。这可能会使检测失败,即使您已将配置的限制设置为适当的高。可配置限制本身被限制在范围[132767]。
也许您可以通过执行重组步骤来解决这个问题:先使用git mv移动文件,而不进行任何内容更改,以匹配新布局,在新分支上提交该布局,然后将其替换为最终版本,该版本只应进行内容更改,不应重命名。可以更可靠地检测到没有内容更改的重命名。只有当您所做的重组相当简单时,这才是可行的,而且我不确定它是否能解决重命名检测失败的问题。
或者,您可以使用一些简单的文件分组将更改拆分为单独的提交,这样在每个提交中可以检测重命名的候选项就更少了。
合并:
不幸的是,通过将新的分支建立在master之上,您向git提供了有关合并的错误信息。不管是否正确检测到重命名,当新创建的分支与master合并时,它将覆盖master中的所有内容,因为从git的角度来看,master中没有未包含在新分支中的更改。
用git commit --dry-run -a代替git status,它能更好地检测重命名。
- 为什么是负点?这种方法在我的案例中效果很好,一个解释会很好。
- 你什么都没解释。您使用--dry-run,这意味着只有"模拟"提交。这项技术已经被OP使用(只是没有——干运行)。
您可以考虑使用git mv代替:https://www.kernel.org/pub/software/scm/git/docs/git-mv.html
以我的经验来看,它更可靠。
每当我不得不重命名/移动文件而忘记明确地告诉Git我使用的
自动检测移动的文件
- 此外,Git没有"显式"方法来告诉它移动了任何东西。它应该在合并期间自动执行。
- 为了明确告诉Git重命名/移动文件,请使用git mv old new而不是unix mv命令
- stackoverflow.com/questions/1094269/git‌&8203;-mv的目的是什么
- 在任何一种情况下,git add都会导致相同的结果(一半检测到,一半未检测到)