Git无法检测到重命名

108

一条分支(refactoringBranch)完成了目录的重构,文件被混乱地移动了位置,但是内容得到了保留。

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

git 状态显示大约有一半的文件被识别为更名。但在项目的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% - Alex
1
那是什么外部工具?你是否尝试使用类似于 git diff -M90% --stat master refactoringBranch 这样的命令测试不同的重命名阈值(尝试使用不同的值替代 90%)? - John Bartholomew
这个工具是 php.net/similar_text。在我的合并命令中,我使用了低至15%的阈值。我期望它能够通过。 - Alex
1
让我们在聊天中继续这个讨论:http://chat.stackoverflow.com/rooms/20889/discussion-between-john-bartholomew-and-alex - John Bartholomew
git rm --cached old_file_name;(重命名文件);git add new_file_name 也可以。 - jungyh0218
显示剩余3条评论
11个回答

147

OS X 是区分大小写的,但不敏感。Git 是区分大小写的。如果你只是更改文件名的大小写,那么请将文件名改回原来的样子,然后使用 git mv 进行重命名。


12
解决了我的问题的非常简单的方法。对于那些想知道“git mv oldfilename newfilename”指令的作用,这里提供文档链接:https://www.kernel.org/pub/software/scm/git/docs/git-mv.html。基本上它会自动更新旧文件和新文件的索引。谢谢! - iusting
如果您更改文件夹名称以使其与不同的大小写相同,则会出现“权限被拒绝”的错误。但是,https://dev59.com/oWUq5IYBdhLWcg3wV_Ai#14580217 可以解决这个问题(首先将其更改为不同的中间名称)。 - David Kaufman
5
无需将文件重命名为原来的名称,只需使用git mv oldcase newcase即可。这个命令可以完成重命名操作并使Git记录该变更。 - Ashish Ranjan
1
@AshishRanjan,如果您记不起oldcase怎么办?更好的恢复旧状态的方法是删除文件并使用git将其还原到原始状态(git checkout -- <file_name>),然后重命名(git mv)。 - Dut A.

58

重命名检测:

我猜测由于候选项过多,重命名检测可能会失败。Git源代码有些难以理解,但似乎在某些特定的搜索步骤中使用了一些硬编码的限制 (参见 diffcore-rename.c),以及可配置的最大配对数限制(配置键为diff.renameLimitmerge.renameLimit)。即使您将已配置的限制设置得足够高,这也可能导致检测失败。可配置的限制本身被压缩到[1, 32767]范围内。

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

或者,您可以将更改拆分成具有一些简单文件分组的单独提交,以便每个提交中需要进行重命名检测的候选项较少。

合并:

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


类似的关于Git可配置设置的讨论在此处可找到:(https://dev59.com/4Gsz5IYBdhLWcg3wiIWe) - Shadi

57

以下是一种完美的方法,让Git知道您重命名了文件。

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

然后git会捕捉到这些变更。

享受吧。


6
重命名已完成后是否有方法应用此操作? - Slbox
2
什么是.ts文件,为什么它能够工作?如果你只是指的是git mv file1 file2,那么它并不能在你对文件进行了大量更改时起作用。 - klm123
@Slbox 在重命名已完成之后,您仍然可以将文件恢复到旧的命名,并继续使用两步 git mv 进行操作,例如 git mv final fine,然后再执行 git mv fine FINAL。遗憾的是,在更改名称后添加文件将记录旧文件的删除和新文件的添加,如果有足够的更改,对于计划中的重命名,我看到新的 git CLI(例如 git version 2.42.0.windows.2)可以很好地处理这个问题。@klm123 是的,简单的 git mv file1 file2 对于很多更改并不适用,但通常只适用于仅仅是大小写差异的情况。建议的两步移动在这种情况下是有效的。 - undefined

34

不要使用git status命令,尝试使用git commit --dry-run -a命令,它可以更好地检测重命名。


8
为什么会有负分?这种技术在我的情况下很有效,希望能得到解释。 - BoD
8
你没有做出任何解释。你使用了 --dry-run,这意味着只有“模拟”提交。 这种技术已经被操作员使用(只是没有使用 --dry-run)。 - xZero
使用git 2.8.0可以获得相同的结果。 - Slbox
对我不起作用。我的git版本是2.34.1。我也尝试了https://dev59.com/J3E85IYBdhLWcg3wvGAR#2641227。 - ZeZNiQ

14

9
我之前遇到了类似的问题,我的情况是由于另一次提交更改了重命名操作,而尝试将其重新更改为另一个失败了。直到我意识到有相应的git配置文件。在我的系统中,git config 列出了一个配置为 core.ignorecase=true
通过使用git config core.ignorecase false 将其设置回false来禁用它,对我有效。值得快速检查和尝试,看看是否会导致Git的大小写检测失败。此方法已在git版本2.33.0.windows.2上尝试过。

7

最简单的方法是简单设置

git config core.ignorecase false

然后重新执行添加和提交。

如果您已经更改了大量文件名并且不想手动执行git mv,这将非常有用。

如果您因某种原因不想默认区分大小写,您始终可以将其重写为true


这会导致git添加重命名的文件,但不会导致它删除旧文件!因此,你最终会同时拥有beforeafter两个重命名的文件。 - undefined
是的!这个答案是正确的答案。 - undefined

2
每当我需要重命名/移动文件并忘记明确告诉GIT时,我会使用以下命令。
git add . -A

自动检测已移动的文件


1
此外,Git没有“显式”的方法来告诉它任何东西已经被移动。在合并期间,它应该自动完成这个过程。 - Alex
2
为了明确告诉GIT你将文件重命名/移动,使用git mv {旧路径} {新路径}命令,而不是unix mv命令。 - Sergey Lukin
2
无论哪种情况,git add 都会导致相同的结果(一半被检测到,一半没有)。 - Alex
这对我来说非常有效。谢谢! - Pez

0
✅ macOS
  1. 使用图形用户界面(GUI)并选择要重命名的所有文件
  2. 选择文件 -> 重命名菜单(或者右键单击并重命名) 重命名
  3. 将要更改的文本替换为独特的内容(但是不要使用最终名称!) 独特内容
  4. 使用git add .将所有更改暂存(只是暂存,不要提交)
  5. 此步骤中再次将文件重命名为所需名称的独特内容! 所需名称
  6. 再次使用git add -A将文件重新暂存(不要使用git add .)
  7. 提交并完成!

0

如果您不介意将其拆分为多个提交,则另一种解决方案是将重命名的文件移回其原始名称,提交其更改,然后将它们移动到其新名称并提交该更改,在提交消息中说明为什么这样做。

当然,如果您只有几个未正确识别的重命名文件,则此方法更容易。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接