git与重命名的文件合并

res*_*ode 45 git

我有一个大型网站,我正在进入一个新的框架,并在此过程中添加git.当前站点没有任何版本控制.

我开始将网站复制到一个新的git存储库.我创建了一个新的分支,并进行了使其与新框架一起工作所需的所有更改.其中一个步骤是更改所有页面的文件扩展名.

现在,在我一直在处理新站点的时候,已经对旧站点上的文件进行了更改.所以我切换到master并复制了所有这些更改.

问题是当我将分支与新框架合并回主服务器时,在主分支上更改的每个文件都存在冲突.

我不会担心它,但有几百个文件有变化.我曾尝试git rebasegit rebase --merge没有运气.

如何在不处理每个文件的情况下合并这两个分支?

Til*_*gel 59

从git 1.7.4开始,您可以指定合并的重命名阈值git merge -X rename-threshold=25,以便控制25%的相似性已经足以考虑两个文件重命名候选.这取决于具体情况,-X ignore-space-change可以使重命名检测更可靠.

但是,我希望有更多的直接控制,并在最后几天制作相关的脚本.也许它有帮助 - 让我知道.

https://gist.github.com/894374

  • 引用`git help revisions`:"冒号,可选地后跟阶段号(0到3)和冒号,后跟路径(例如:0:README);这在给定的索引中命名blob对象缺少阶段编号(以及跟随它的冒号​​,例如:README)命名阶段0条目.在合并期间,阶段1是共同的祖先,阶段2是目标分支的版本(通常是当前分支)和阶段3是合并分支的版本." 我会看看我是否可以提炼一个简单的示例工作流程.这些往往出现在复杂的合并中,但...... (2认同)
  • 谢谢,这是一个很大的帮助。由于可以在不真正了解阶段编号的情况下使用 git,因此我认为该信息的链接在您的脚本中会很方便。 (2认同)

Jak*_*ski 15

由于重命名检测,应该自动工作.下面是示例会话:

$ git init test
Initialized empty Git repository in /tmp/jnareb/test/.git/
$ cp ~/git/README .    # example file, large enough so that rename detection works
$ git add .
$ git commit -m 'Initial commit'
[master (root-commit) b638320] Initial commit
 1 files changed, 54 insertions(+), 0 deletions(-)
 create mode 100644 README
$ git checkout -b new-feature        
Switched to a new branch 'new-feature'
$ git mv README README.txt
$ git commit -m 'Renamed README to README.txt'
[new-feature ce7b731] Renamed README to README.txt
 1 files changed, 0 insertions(+), 0 deletions(-)
 rename README => README.txt (100%)
$ git checkout master
Switched to branch 'master'
$ sed -e 's/UNIX/Unix/g' README+ && mv -f README+ README
$ git commit -a -m 'README changed'
[master 57b1114] README changed
 1 files changed, 1 insertions(+), 1 deletions(-)
$ git merge new-feature 
Merge made by recursive.
 README => README.txt |    0
 1 files changed, 0 insertions(+), 0 deletions(-)
 rename README => README.txt (100%)

如果您在'new-feature'分支上执行"git merge master"而不是像上面那样在'master'上执行"git merge new-feature",那么您将获得:

$ git merge master
Merge made by recursive.
 README.txt |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

你能说出你在做什么不同吗?

请注意,普通的"git rebase"(和"git pull --rebase")不会重新命名:您需要运行"git rebase -m"或交互式rebase.


Von*_*onC 6

十多年后,随着 Git 2.31(2021 年第一季度)的出现,一种新的合并策略应该会有所帮助:ORT(“表面上递归的双胞胎”)。

\n

它包括关于重命名检测的大量性能优化工作,这超出了简单的rename-threshold.

\n

请参阅Elijah Newren提交的提交 f78cf97提交 07c9a7f提交 bd24aa2提交 da09f65提交 a35df33提交 f384525提交 829514c(2021 年 2 月 14 日)和提交 f15eb7c(2021 年 2 月 3 日)。\n (由Junio C Hamano 合并 -- --提交 12bd175,2021 年 3 月 1 日)newren
gitster

\n

例如:

\n
\n

diffcore-rename:计算源和目标候选者的基本名称

\n

签署人:伊利亚·纽伦

\n
\n
\n

我们希望在剩余的源文件和目标文件中使用唯一的基本名称来帮助通知重命名检测,以便可以首先检查更可能的配对。
\n(如果剩余的已删除和添加的文件中没有其他 \' \' 文件,src/moduleA/foo.txt则可能相关。)source/module/A/foo.txtfoo.txt

\n

添加一个尚未使用的新函数,该函数创建一个映射,其中包含唯一的基本名称rename_src和另一个内部的rename_dst,映射,以及rename_src/rename_dst这些基本名称显示的索引。

\n

非唯一的基本名称仍然显示在地图中,但具有无效索引 (-1)。

\n

此功能的灵感来自于以下事实:在现实世界的存储库中,文件通常会在不更改名称的情况下跨目录移动。

\n

以下是一些示例存储库及其保留基本名称的历史重命名(截至 2020 年初)的百分比:

\n
    \n
  • linux:76%
  • \n
  • 海湾合作委员会:64%
  • \n
  • 壁虎:79%
  • \n
  • 网络套件:89%
  • \n
\n

这些统计数据本身并不能证明该领域的优化会有帮助或有多大帮助,因为还有不成对的添加和删除、对我们考虑的基名的限制等,但它确实激发了尝试的想法这个区域的东西。

\n
\n

和:

\n
\n

diffcore-rename: 完全的find_basename_matches()

\n

签署人:伊利亚·纽伦

\n
\n
\n

在现实世界的存储库中,大多数文件重命名不更改文件的基本名称的情况并不少见;IE

\n

大多数“重命名”只是将文件移动到不同的目录中。

\n

我们可以利用这一点来避免将所有重命名源候选者与所有重命名目标候选者进行比较,方法是首先将源与具有相同基名的目标进行比较。

\n
    \n
  • 如果具有相同基本名称的两个文件足够相似,我们会记录重命名;\n-如果不是,我们会将这些文件包含在更详尽的矩阵比较中。
  • \n
\n

这意味着我们正在添加一组初步的附加比较,但对于每个文件,我们最多仅将其与另一个文件进行比较。

\n

例如,如果有一个include/media/device.h被删除的文件和一个被添加的文件,并且在精确重命名检测后剩余的添加和删除文件组中src/module/media/device.h没有其他文件,则在预备步骤中将比较这两个文件。device.h

\n

此提交尚未实际采用这种新的优化,它只是添加了一个可用于此目的的函数。

\n

请注意,此优化可能会给我们带来与没有优化时不同的结果,因为尽管具有相同基名的文件足够相似以被视为重命名,但没有相同基名的文件之间可能存在更好的匹配。

\n

我认为这没有问题,原因有四个:

\n
    \n
  • (1) 如果确实发生过,很容易向用户解释发生了什么(甚至让他们直观地弄清楚),
  • \n
  • (2) 下一个补丁将显示它提供了如此大的性能提升,值得权衡,并且
  • \n
  • (3) 尽管具有唯一的匹配基名,但其他文件不太可能成为更好的匹配项。
    \n原因(4)需要一整段才能解释...
  • \n
\n

如果前三个原因还不够,请考虑重命名检测已经执行的操作。
\n中断检测不是默认设置,这意味着如果文件具有相同的内容_fullname_,,那么即使它们的相似度为 0%,它们也会被视为相关。
事实上,在这种情况下,我们甚至懒得比较这些文件以查看它们是否相似,更不用说将它们与所有其他文件进行比较以查看它们最相似的内容。

\n

基本上,我们根据足够的文件名相似度覆盖内容相似度
\n如果没有文件名相似性(当前实现为文件名的精确匹配),我们就会向相反方向摆动,并说文件名相似性是无关紧要的,并比较源和目标的完整 N x M 矩阵,以找出最相似的内容。
\n此优化只是添加了另一种形式的文件名相似性比较,但还通过文件内容相似性检查对其进行了增强。
\n基本上,如果两个文件具有相同的基本名称并且足够相似以被视为重命名,则将它们标记为这样,而不将这两个文件与所有其他重命名候选者进行比较。

\n
\n

这导致:

\n
\n

diffcore-rename:指导基于基本名称的不精确重命名检测

\n

签署人:伊利亚·纽伦

\n
\n
\n

利用find_basename_matches()最后两个补丁中添加的新功能,在我们可以根据基本名称匹配文件的情况下更快地找到重命名。

\n

作为快速提醒(请参阅最后两条提交消息以了解更多详细信息),这意味着,docs/extensions.txt如果添加和删除的文件中的其他位置docs/config/extensions.txt没有剩余的“\”文件,并且相似性检查确认,则 和 被认为可能重命名extensions.txt它们相似,然后将它们标记为重命名,而不在其他文件之间寻找更好的相似性匹配。

\n

这是一种行为变化,前面的提交消息中更详细地介绍了这一点。

\n

我们不会将这种启发式与中断或复制检测一起使用。

\n

中断检测的要点是文件名相似并不意味着文件内容相似,我们只想知道文件内容相似。

\n

复制检测的要点是使用更多的资源来检查额外的相似性,虽然这是一种使用更少资源的优化,但也可能导致发现的相似性略少。

\n

因此,这种优化背后的想法与这两个功能背道而驰,并且将针对这两个功能关闭。

\n

对于提交 557ac03中提到的测试用例(“ merge-ort:开始性能工作;使用调用进行检测trace2_region_*”,2020-10-28,Git v2.31.0-rc0 -批量 #8中列出的合并),此更改提高了性能,如下所示:

\n
Before                  After\n s \xc2\xb1  0.062 s    13.294 s \xc2\xb1  0.103 s\n s \xc2\xb1  0.493 s   187.248 s \xc2\xb1  0.882 s\n s \xc2\xb1  0.019 s     5.557 s \xc2\xb1  0.017 s\n
Run Code Online (Sandbox Code Playgroud)\n
\n
\n

在 Git 2.32(2021 年第 2 季度)中,重命名检测返工仍在继续。

\n

请参阅提交 81afdf7提交 333899e、提交1ad69eb、提交b147301提交 b6e3d27提交 cd52e00提交 0c4fd73提交 ae8cf74提交 bde8b9f提交 37a2514(2021 年 2 月 27 日),作者:Elijah Newren ( newren)
\n (由Junio C Hamano 合并 -- gitster--dd4048d 提交,2021 年 3 月 22 日)

\n
\n

diffcore-rename:计算dir_rename_guessdir_rename_counts

\n

审阅者:Derrick Stolee
\n签署者:Elijah Newren

\n
\n
\n

dir_rename_counts有一个映射的映射,特别是,它有

\n
old_dir => { new_dir => count }\n
Run Code Online (Sandbox Code Playgroud)\n

我们想要一个简单的映射

\n
old_dir => new_dir\n
Run Code Online (Sandbox Code Playgroud)\n

基于new_dir给定 的最高计数old_dir
\n计算这个并将其存储在dir_rename_guess.

\n

这是我们猜测当基名不唯一时哪些目录文件已移动到的最后一个难题。

\n
\n

基于提交 37a2514 的最终作品)

\n
\n

对于提交 557ac03中提到的测试用例(“ merge-ort:开始性能工作;使用调用进行检测trace2_region_*”,2020-10-28,Git v2.31.0-rc0 -批量 #8中列出的合并),此更改提高了性能,如下所示:

\n
Before                  After\n s \xc2\xb1  0.062 s    12.596 s \xc2\xb1  0.061 s\n s \xc2\xb1  0.284 s   130.465 s \xc2\xb1  0.259 s\n s \xc2\xb1  0.019 s     3.958 s \xc2\xb1  0.010 s\n
Run Code Online (Sandbox Code Playgroud)\n
\n
\n

仍然使用 Git 2.32(2021 年第 2 季度),ort 合并后端已通过跳过不相关的重命名进行了优化。

\n

请参阅提交 e4fd06e提交 f89b4f2提交 174791f提交 2fd9eda提交 a68e6ce提交 beb0614提交 32a56df提交 9799889(2021 年 3 月 11 日),作者:Elijah Newren ( newren)
\n (由Junio C Hamano 合并 -- gitster--提交 1b31224,2021 年 4 月 8 日)

\n
\n

merge-ort:如果可能的话完全跳过重命名检测

\n

签署人:伊利亚·纽伦

\n
\n
\n

diffcore_rename_extended()将进行一系列设置,然后检查精确的重命名,如果没有更多的源或目标需要匹配,则在不精确的重命名检测之前中止。
\n然而,有时会出现这样的情况:

\n
    \n
  • 我们从没有任何来源或目的地开始
  • \n
  • 我们从没有相关来源开始> 在这两种情况中的第一种情况下,设置和精确的重命名检测将非常便宜,因为有 0 个文件要操作。
    \n在第二种情况下,很可能有数千个文件,但没有一个源文件是相关的。\n在我们确定不需要重命名检测之前,
    请避免调用diffcore_rename_extended()甚至某些设置。diffcore_rename_extended()
  • \n
\n

对于提交 557ac03中提到的测试用例(“ merge-ort:开始性能工作;使用调用进行检测trace2_region_*”,2020-10-28,Git v2.31.0-rc0 -批量 #8中列出的合并),此更改提高了性能,如下所示:

\n
Before                  After\n s \xc2\xb1  0.048 s     5.708 s \xc2\xb1  0.111 s\n s \xc2\xb1  0.236 s   102.171 s \xc2\xb1  0.440 s\n s \xc2\xb1  0.017 s     3.471 s \xc2\xb1  0.015 s\n
Run Code Online (Sandbox Code Playgroud)\n
\n
\n

这项工作在 Git 2.33(2021 年第 3 季度)中继续进行,其中优化了一系列合并操作中的重复重命名检测。

\n

请参阅提交 25e65b6提交 cbdca28提交 86b41b3提交 d509802提交 19ceb48提交 64aceb6、提交2734f2e 、提交 d29bd6d、提交a22099f 、提交f950026 提交caba91c提交 bb80333(5 月 20 日) 2021 年),并提交 15f3e1e (2021 年 5 月 4日)作者:伊利亚·纽伦 (Elijah Newren newren)
\n (由Junio C Hamano 合并 -- gitster--提交 169914e中,2021 年 6 月 14 日)

\n
\n

merge-ort, diffcore-rename:尽可能使用缓存的重命名

\n

签署人:伊利亚·纽伦

\n
\n
\n

当一系列提交的旧基础和新基础之间存在许多重命名时sequencer.c,传统上分割工作的merge-recursive.c方式diffcore-rename.c会导致在移植的每个提交时重新检测相同的重命名。
\n为了解决这个问题,最近几次提交一直在创建重命名检测结果的缓存,确定在后续合并操作中何时可以安全地使用此类缓存,添加辅助函数等等。

\n

对于提交 557ac03中提到的测试用例(“ merge-ort:开始性能工作;使用调用进行检测trace2_region_*”,2020-10-28,Git v2.31.0-rc0 -批量 #8中列出的合并),此更改提高了性能,如下所示:

\n
Before                  After\n s \xc2\xb1  0.129 s     5.622 s \xc2\xb1  0.059 s\n s \xc2\xb1  0.158 s    10.127 s \xc2\xb1  0.073 s\nms \xc2\xb1  6.1  ms   500.3  ms \xc2\xb1  3.8  ms\n
Run Code Online (Sandbox Code Playgroud)\n

这是一个相当小的改进,但主要是因为之前的优化对于这些特定的测试用例非常有效;此优化仅在其他优化不生效时才会生效。
\n如果我们取消基本名称引导的重命名检测和跳过无关重命名优化,那么我们会看到该系列本身改进了性能,如下所示:

\n
Before Basename Series   After Just This Series\n  13.815 s \xc2\xb1  0.062 s      5.697 s \xc2\xb1  0.080 s\n1799.937 s \xc2\xb1  0.493 s    205.709 s \xc2\xb1  0.457 s\n
Run Code Online (Sandbox Code Playgroud)\n

由于此优化有助于加速先前优化不适用的情况,因此最后的比较表明,此缓存重命名优化有可能在不满足其他优化生效要求的情况下提供显着帮助。

\n
\n
\n

使用 Git 2.33(2021 年第 3 季度),对“”进行了更多修复和优化merge -sort

\n

请参阅Elijah Newren ( )的提交 ef68c3d提交 356da0f提交 61bf449提交 5a3743d(2021 年 6 月 8 日)。\n (由Junio C Hamano 合并 -- --提交 89efac8,2021 年 7 月 16 日)newren
gitster

\n
\n

merge-ortstring_list_df_name_compare用更快的替代品替换

\n

签署人:Elijah Newren
\n审阅人:Derrick Stolee

\n
\n
\n

以在比较字符串时不需要找出字符串长度的方式重写比较函数。
\n在此过程中,针对我们的具体情况调整代码——例如,不需要处理各种模式。
\n在大型重命名情况下,这些更改的组合将“plist 特殊排序”花费的时间减少了约 25%。

\n

对于提交 557ac03中提到的测试用例(“ merge-ort:开始性能工作;使用调用进行检测trace2_region_*”,2020-10-28,Git v2.31.0-rc0 -批量 #8中列出的合并),此更改提高了性能,如下所示:

\n
Before                  After\n s \xc2\xb1  0.059 s     5.235 s \xc2\xb1  0.042 s\n s \xc2\xb1  0.073 s     9.419 s \xc2\xb1  0.107 s\nms \xc2\xb1  3.8  ms   480.1  ms \xc2\xb1  3.9  ms\n
Run Code Online (Sandbox Code Playgroud)\n
\n

并且,仍然使用 git 2.33:

\n

请参阅Elijah Newren提交的提交 2bff554提交 1aedd03提交 d331dd3提交 c75c423(2021 年 6 月 22 日)和提交 78cfdd0(2021 年 6 月 15 日)。\n (由Junio C Hamano 合并 -- --提交 fdbcdfc中,2021 年 7 月 16 日)newren
gitster

\n
\n


res*_*ode 2

我想出了一个解决办法。由于文件的重命名是通过脚本完成的,因此我能够复制新的 .php 文件并在合并之前重新运行脚本。由于文件具有相同的名称,因此合并不会发生冲突。

以下是整个过程的步骤。

  1. 创建 git 存储库git init
  2. 将现有文件复制到
  3. 犯罪
  4. 运行脚本来重命名文件
  5. 犯罪
  6. 创建一个分支但不签出它
  7. 进行修复并随时提交更改
  8. 签出您在步骤 6 中创建的分支
  9. 复制文件的新版本
  10. 运行脚本来重命名文件(这应该替换第一次运行时的文件)
  11. 犯罪
  12. 结帐大师
  13. 合并分支到master

这是有效的,因为 git 已对具有新名称的文件进行了更改。