我有一个大型网站,我正在进入一个新的框架,并在此过程中添加git。当前站点没有任何版本控制。
我首先将网站复制到新的git存储库中。我创建了一个新的分支,并进行了使其与新框架一起工作所需的所有更改。其中一个步骤是更改所有页面的文件扩展名。
现在,在我处理新网站的时候,已经对旧网站上的文件进行了更改。所以我切换到master并复制了所有这些更改。
问题是当我将分支与新框架合并回master时,主分支上的每个文件都会发生冲突。
我不会担心它,但有几百个文件有变化。我试过git rebase
和git rebase --merge
没有运气。
如何在不处理每个文件的情况下合并这两个分支?
答案 0 :(得分:59)
从git 1.7.4开始,您可以将合并的重命名阈值指定为git merge -X rename-threshold=25
,以便控制25%的相似性已经足以考虑两个文件重命名候选。根据案例和-X ignore-space-change
,这可能会使重命名检测更可靠。
然而,我希望有更多的直接控制,并在最后几天制作相关的脚本。也许它有所帮助 - 让我知道。
答案 1 :(得分:16)
由于重命名检测,应该可以自动工作。下面是示例会话:
$ 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。
答案 2 :(得分:2)
我想出了一个解决办法。由于文件的重命名是由脚本完成的,因此我能够复制新的.php文件并在合并之前重新运行脚本。由于文件具有相同的名称,因此合并无冲突。
以下是整个过程的步骤。
git init
这是有效的,因为git对使用新名称的文件进行了更改。
答案 3 :(得分:2)
在我重命名检测失败的情况下,我发现在合并解析期间我可以执行以下操作:
假设:
fileA: A modified file that was moved to the new place but is currently in the old place.
destB: The location where fileB was moved to. This could include a new filename.
运行以下命令:
git add fileA
git mv fileA destB
这就是我必须做的一切。然后我承诺并继续坚持。
答案 4 :(得分:1)
十年后,随着 Git 2.31(2021 年第一季度)的推出,新的合并策略应该会有所帮助:ORT(“表面上递归的双胞胎”)。
它在重命名检测方面做了大量的性能优化工作,超越了简单的 rename-threshold
。
参见 commit f78cf97、commit 07c9a7f、commit bd24aa2、commit da09f65、commit a35df33、commit f384525、commit 829514c(2021 年 2 月 14 日) ,以及 commit f15eb7c(2021 年 2 月 3 日)由 Elijah Newren (newren
).
(由 Junio C Hamano -- gitster
-- 于 commit 12bd175 合并,2021 年 3 月 1 日)
例如:
<块引用>diffcore-rename
:计算源和目标候选的基名签字人:Elijah Newren
<块引用>我们希望在剩余的源文件和目标文件中使用唯一的基本名称来帮助通知重命名检测,以便可以首先检查更有可能的配对。
(如果在剩余的已删除和添加的文件中没有其他“src/moduleA/foo.txt
”文件,则 source/module/A/foo.txt
和 foo.txt
很可能相关。)
添加一个尚未使用的新函数,该函数创建 rename_src
内的唯一基名和 rename_dst,
内的另一个以及 rename_src/rename_dst
内显示这些基名的索引的映射。
非唯一的基本名称仍会显示在地图中,但索引无效 (-1)。
此功能的灵感来自这样一个事实:在现实世界的存储库中,文件经常在不更改名称的情况下跨目录移动。
以下是一些示例存储库及其保留基本名称的历史重命名(截至 2020 年初)的百分比:
仅凭这些统计数据并不能证明该领域的优化会有帮助或有多大帮助,因为还有未配对的添加和删除、对我们考虑的基名的限制等,但它确实激发了这个想法在这方面尝试一些东西。
还有:
<块引用>diffcore-rename
:完成find_basename_matches()
签字人:Elijah Newren
<块引用>在现实世界的存储库中,大多数文件重命名不更改文件的基本名称的情况并不少见;即
大多数“重命名”只是将文件移动到不同目录中。
我们可以利用这一点来避免将所有重命名源候选与所有重命名目标候选进行比较,首先将源与具有相同基本名称的目标进行比较。
这意味着我们要添加一组初步的额外比较,但对于每个文件,我们最多只将它与一个其他文件进行比较。
例如,如果有一个include/media/device.h
被删除,一个src/module/media/device.h
被添加,并且之后添加和删除的文件的剩余集合中没有其他device.h
文件精确重命名检测,那么这两个文件将在初步步骤中进行比较。
这个提交实际上还没有使用这个新的优化,它只是添加了一个可以用于此目的的函数。
请注意,与未进行优化相比,此优化可能会给我们带来不同的结果,因为尽管具有相同基名的文件足够相似可以被视为重命名,但可能会在不具有相同基名的文件之间提供更好的匹配。>
我认为这是可以的,原因有四个:
如果前三个原因还不够,请考虑重命名检测已经做了什么。
中断检测不是默认设置,这意味着如果文件具有相同的 _fullname_,
,那么即使它们的相似度为 0%,也将它们视为相关。
事实上,在这种情况下,我们甚至不需要比较文件以查看它们是否相似,更不用说将它们与所有其他文件进行比较以查看它们最相似的内容。
基本上,我们会根据足够的文件名相似度覆盖内容相似度。
如果没有文件名相似性(目前实现为文件名的精确匹配),我们将钟摆摆向相反的方向,并说文件名相似性无关紧要,然后比较完整的 N x M 源和目的地矩阵,找出哪些内容最相似.
这种优化只是添加了另一种形式的文件名相似性比较,但也增加了文件内容相似性检查。
基本上,如果两个文件具有相同的基本名称并且足够相似以被视为重命名,则将它们标记为这样,而不将这两个文件与所有其他重命名候选对象进行比较。
这导致:
<块引用>diffcore-rename
:指导基于基名的不精确重命名检测签字人:Elijah Newren
<块引用>利用在最后两个补丁中添加的新 find_basename_matches()
函数,在我们可以根据基本名称匹配文件的情况下更快地找到重命名。
作为快速提醒(有关更多详细信息,请参阅最后两条提交消息),例如,这意味着如果没有剩余的 'docs/extensions.txt
' 文件在添加和删除的文件中的其他位置,如果相似性检查确认它们相似,则将它们标记为重命名,而无需在其他文件中寻找更好的相似性匹配。
这是一个行为变化,在之前的提交消息中有更详细的介绍。
我们不会将此启发式与中断或复制检测一起使用。
断点检测的意义在于,文件名相似度并不意味着文件内容相似度,我们只想知道文件内容相似度。
复制检测的重点是使用更多资源来检查额外的相似性,虽然这是一种使用更少资源但也可能导致发现的相似性略少的优化。
因此,此优化背后的想法与这两个功能都背道而驰,并且将针对这两个功能关闭。
对于 commit 557ac03 ("docs/config/extensions.txt
: begin performance work; instrument with extensions.txt
calls", 2020-10-28, Git v2.31.0-rc0 -- { {3}} 列在 merge) 中,此更改改进了如下性能:
merge-ort
在 Git 2.32(2021 年第二季度)中,重命名检测返工继续进行。
见batch #8、commit 81afdf7、commit 333899e、commit 1ad69eb、commit b147301、commit b6e3d27、commit cd52e00、{{3} }、commit 0c4fd73、commit ae8cf74(2021 年 2 月 27 日),作者:commit bde8b9f。
(由 commit 37a2514 于 Elijah Newren (newren
) 合并,2021 年 3 月 22 日)
gitster
--:从trace2_region_*
Before After
s ± 0.062 s 13.294 s ± 0.103 s
s ± 0.493 s 187.248 s ± 0.882 s
s ± 0.019 s 5.557 s ± 0.017 s
审核人:Derrick Stolee
签字人:Elijah Newren
dir_rename_guess
有一个映射的映射,特别是它有
dir_rename_counts
我们想要一个简单的映射
dir_rename_counts
基于给定 old_dir => { new_dir => count }
中哪个 old_dir => new_dir
的计数最高。
计算它并将其存储在 new_dir
中。
这是我们猜测当基名不唯一时将文件移动到哪个目录所需的最后一块拼图。
(最后一块commit dd4048d)
<块引用>对于 diffcore-rename
("old_dir
: begin performance work; instrument with dir_rename_guess
calls", 2020-10-28, Git v2.31.0-rc0 -- { {3}} 列在 based on commit 37a2514) 中,此更改改进了如下性能:
merge-ort
仍然使用 Git 2.32(2021 年第二季度),ort 合并后端已通过跳过不相关的重命名进行了优化。
见commit 557ac03、merge、batch #8、commit e4fd06e、commit f89b4f2、commit 174791f、commit 2fd9eda、{{3} }(2021 年 3 月 11 日)作者:commit a68e6ce。
(由 commit beb0614 于 commit 32a56df 合并,2021 年 4 月 8 日)
签字人:Elijah Newren
<块引用>trace2_region_*
将进行一系列设置,然后检查准确的重命名,如果没有更多的源或目标需要匹配,则在不准确的重命名检测之前中止。
然而,有时情况是这样的,要么
Before After
s ± 0.062 s 12.596 s ± 0.061 s
s ± 0.284 s 130.465 s ± 0.259 s
s ± 0.019 s 3.958 s ± 0.010 s
之前调用 diffcore_rename_extended()
甚至某些设置。对于 Elijah Newren (newren
) ("diffcore_rename_extended()
: begin performance work; instrument with diffcore_rename_extended()
calls", 2020-10-28, Git v2.31.0-rc0 -- { {3}} 列在 Junio C Hamano -- gitster
--) 中,此更改改进了如下性能:
merge-ort
这项工作在 Git 2.33(2021 年第 3 季度)中继续进行,其中优化了一系列合并操作中的重复重命名检测。
见commit 1b31224、merge-ort
、commit 557ac03、merge、batch #8、commit 25e65b6、commit cbdca28、{{3} }、commit 86b41b3、commit d509802、commit 19ceb48、commit 64aceb6(2021 年 5 月 20 日)和 commit 2734f2e(2021 年 5 月 4 日)由 commit d29bd6d.< br/>
(由 commit a22099f 于 commit f950026 合并,2021 年 6 月 14 日)
签字人:Elijah Newren
<块引用>当一系列提交的旧基和新基之间有很多重命名时,commit bb80333、commit 15f3e1e 和 Elijah Newren (newren
) 传统上拆分工作的方式导致重新命名- 在移植的每个提交中检测相同的重命名。
为了解决这个问题,最近几次提交一直在创建重命名检测结果的缓存,确定在后续合并操作中何时可以安全地使用这样的缓存,添加辅助函数等。
对于 Junio C Hamano -- gitster
-- ("trace2_region_*
: begin performance work; instrument with Before After
s ± 0.048 s 5.708 s ± 0.111 s
s ± 0.236 s 102.171 s ± 0.440 s
s ± 0.017 s 3.471 s ± 0.015 s
calls", 2020-10-28, Git v2.31.0-rc0 -- { {3}} 列在 commit 169914e) 中,此更改改进了如下性能:
merge-ort
这是一个相当小的改进,但主要是因为之前的优化对于这些特定的测试用例非常有效;此优化仅在其他优化不启动时才会启动。
如果我们取消 basename-guided rename detection 和 skip-inrelevant-renames 优化,那么我们会看到这个系列本身提高了如下性能:
trace2_region_*
由于此优化开始有助于加速先前优化不适用的情况,因此最后的比较表明此缓存重命名优化有可能在不满足其他优化要求的情况下提供显着帮助有效。
答案 5 :(得分:0)
添加@Tilman的回答,使用最近的git重命名选项为-X find-renames=<n>