在Git 2.30(2021年第一季度)中,将会有一个新的合并策略:ORT(表面上递归的孪生兄弟)。
git merge -s ort
这篇文章来自Elijah Newren:
For now, I'm calling it "Ostensibly Recursive's Twin", or "ort" for short. >
At first, people shouldn't be able to notice any difference between it and the current recursive strategy, other than the fact that I think I can make it a bit faster (especially for big repos).
But it should allow me to fix some (admittedly corner case) bugs that are harder to handle in the current design, and I think that a merge that doesn't touch $GIT_WORK_TREE or $GIT_INDEX_FILE will allow for some fun new features.
That's the hope anyway.
问题:
In the ideal world, we should:
ask unpack_trees() to do "read-tree -m" without "-u";
do all the merge-recursive computations in-core and prepare the
resulting index, while keeping the current index intact;
compare the current in-core index and the resulting in-core index, and notice the paths that need to be added, updated or removed in the working tree, and ensure that there is no loss of information when the change is reflected to the working tree;
E.g. the result wants to create a file where the working tree currently has a directory with non-expendable contents in it, the result wants to remove a file where the working tree file has local modification, etc.;
And then finally
carry out the working tree update to make it match what the resulting in-core index says it should look like.
结果:
参见Elijah Newren (Newren)的commit 14c4586(2020年11月02日),commit fe1a21d(2020年10月29日)和commit 47b1e89, commit 17e5574(2020年10月27日)。
(由Junio C Hamano - gitster -在commit a1f9595中合并,2020年11月18日)
merge-ort:新合并策略的基本API,空实现
署名:以利亚·纽伦
This is the beginning of a new merge strategy.
While there are some API differences, and the implementation has some differences in behavior, it is essentially meant as an eventual drop-in replacement for merge-recursive.c.
However, it is being built to exist side-by-side with merge-recursive so that we have plenty of time to find out how those differences pan out in the real world while people can still fall back to merge-recursive.
(Also, I intend to avoid modifying merge-recursive during this process, to keep it stable.)
The primary difference noticable here is that the updating of the working tree and index is not done simultaneously with the merge algorithm, but is a separate post-processing step.
The new API is designed so that one can do repeated merges (e.g. during a rebase or cherry-pick) and only update the index and working tree one time at the end instead of updating it with every intermediate result.
Also, one can perform a merge between two branches, neither of which match the index or the working tree, without clobbering the index or working tree.
And:
参见Elijah Newren (Newren)的commit 848a856, commit fd15863, commit 23bef2e, commit c8c35f6, commit c12d1f2, commit 727c75b, commit 489c85f, commit ef52778, commit f06481f(2020年10月26日)。
(由Junio C Hamano - gitster -在commit 66c62ea中合并,2020年11月18日)
T6423, t6436:注意改进了对脏文件的ort处理
署名:以利亚·纽伦
The "recursive" backend relies on unpack_trees() to check if unstaged changes would be overwritten by a merge, but unpack_trees() does not understand renames -- and once it returns, it has already written many updates to the working tree and index.
As such, "recursive" had to do a special 4-way merge where it would need to also treat the working copy as an extra source of differences that we had to carefully avoid overwriting and resulting in moving files to new locations to avoid conflicts.
The "ort" backend, by contrast, does the complete merge inmemory, and only updates the index and working copy as a post-processing step.
If there are dirty files in the way, it can simply abort the merge.
T6423:期望改进的冲突标记标签在运动后端
署名:以利亚·纽伦
冲突标记带有表单的额外注释
REF-OR-COMMIT:文件名
以帮助区分内容来自哪里,如果:FILENAME部分对于历史记录的两边都是相同的,则将被省略(因此只有具有内容冲突的重命名才携带注释的那部分)。
然而,由于合并递归的每个代码路径都需要一份所有特殊case-code的副本格式,有些情况下:FILENAME注释被意外地省略了。
T6404, t6423:期望在ort后端改进重命名/删除处理
署名:以利亚·纽伦
When a file is renamed and has content conflicts, merge-recursive does not have some stages for the old filename and some stages for the new filename in the index; instead it copies all the stages corresponding to the old filename over to the corresponding locations for the new filename, so that there are three higher order stages all corresponding to the new filename.
Doing things this way makes it easier for the user to access the different versions and to resolve the conflict (no need to manually 'git rm '(man) the old version as well as 'git add'(man) the new one).
rename/deletes should be handled similarly -- there should be two stages for the renamed file rather than just one.
We do not want to destabilize merge-recursive right now, so instead update relevant tests to have different expectations depending on whether the "recursive" or "ort" merge strategies are in use.
Git 2.30(2021年第一季度),为新的合并策略做准备。
参见Elijah Newren (Newren)的commit 848a856, commit fd15863, commit 23bef2e, commit c8c35f6, commit c12d1f2, commit 727c75b, commit 489c85f, commit ef52778, commit f06481f(2020年10月26日)。
(由Junio C Hamano - gitster -在commit 66c62ea中合并,2020年11月18日)
合并测试:期望在ort中改进目录/文件冲突处理
署名:以利亚·纽伦
merge-recursive.c is built on the idea of running unpack_trees() and then "doing minor touch-ups" to get the result.
Unfortunately, unpack_trees() was run in an update-as-it-goes mode, leading merge-recursive.c to follow suit and end up with an immediate evaluation and fix-it-up-as-you-go design.
Some things like directory/file conflicts are not well representable in the index data structure, and required special extra code to handle.
But then when it was discovered that rename/delete conflicts could also be involved in directory/file conflicts, the special directory/file conflict handling code had to be copied to the rename/delete codepath.
...and then it had to be copied for modify/delete, and for rename/rename(1to2) conflicts, ...and yet it still missed some.
Further, when it was discovered that there were also file/submodule conflicts and submodule/directory conflicts, we needed to copy the special submodule handling code to all the special cases throughout the codebase.
And then it was discovered that our handling of directory/file conflicts was suboptimal because it would create untracked files to store the contents of the conflicting file, which would not be cleaned up if someone were to run a 'git merge --abort'(man) or 'git rebase --abort'(man).
It was also difficult or scary to try to add or remove the index entries corresponding to these files given the directory/file conflict in the index.
But changing merge-recursive.c to handle these correctly was a royal pain because there were so many sites in the code with similar but not identical code for handling directory/file/submodule conflicts that would all need to be updated.
I have worked hard to push all directory/file/submodule conflict handling in merge-ort through a single codepath, and avoid creating untracked files for storing tracked content (it does record things at alternate paths, but makes sure they have higher-order stages in the index).
随着Git 2.31(2021年第一季度)的出现,合并后端“做得正确”开始出现。
例子:
参见Junio C Hamano (gitster)的commit 6d37ca2(2020年11月11日)。
参见Elijah Newren (Newren) commit 89422d2, commit ef2b369, commit 70912f6, commit 6681ce5, commit 9fefce6, commit bb470f4, commit ee4012d, commit a9945bb, commit 8adffaa, commit 6a02dd9, commit 291f29c, commit 98bf984, commit 34e557a, commit 885f006, commit d2bc199, commit 0c0d705, commit c801717, commit e4171b1, commit 231e2dd, commit 5b59c3d(2020年12月13日)。
(由Junio C Hamano—gitster—在commit f9d29da中合并,2021年1月6日)
合并:添加record_conflicted_index_entries()的实现
署名:以利亚·纽伦
After checkout(), the working tree has the appropriate contents, and the index matches the working copy.
That means that all unmodified and cleanly merged files have correct index entries, but conflicted entries need to be updated.
We do this by looping over the conflicted entries, marking the existing index entry for the path with CE_REMOVE, adding new higher order staged for the path at the end of the index (ignoring normal index sort order), and then at the end of the loop removing the CE_REMOVED-marked cache entries and sorting the index.
在Git 2.31 (Q1 2021)中,重命名检测被添加到“ORT”合并策略中。
参见Elijah Newren (Newren)的commit 6fcccbd, commit f1665e6, commit 35e47e3, commit 2e91ddd, commit 53e88a0, commit af1e56c(2020年12月15日)和commit c2d267d, commit 965a7bc, commit f39d05c, commit e1a124e, commit 864075e(2020年12月14日)。
(由Junio C Hamano—gitster—在commit 2856089中合并,2021年1月25日)
例子:
合并:添加正常重命名处理的实现
署名:以利亚·纽伦
Implement handling of normal renames.
This code replaces the following from merge-recurisve.c:
the code relevant to RENAME_NORMAL in process_renames()
the RENAME_NORMAL case of process_entry()
Also, there is some shared code from merge-recursive.c for multiple different rename cases which we will no longer need for this case (or other rename cases):
handle_rename_normal()
setup_rename_conflict_info()
The consolidation of four separate codepaths into one is made possible by a change in design: process_renames() tweaks the conflict_info entries within opt->priv->paths such that process_entry() can then handle all the non-rename conflict types (directory/file, modify/delete, etc.) orthogonally.
This means we're much less likely to miss special implementation of some kind of combination of conflict types (see commits brought in by 66c62ea ("Merge branch 'en/merge-tests'", 2020-11-18, Git v2.30.0-rc0 -- merge listed in batch #6), especially commit ef52778 ("merge tests: expect improved directory/file conflict handling in ort", 2020-10-26, Git v2.30.0-rc0 -- merge listed in batch #6) for more details).
That, together with letting worktree/index updating be handled orthogonally in the merge_switch_to_result() function, dramatically simplifies the code for various special rename cases.
(To be fair, the code for handling normal renames wasn't all that complicated beforehand, but it's still much simpler now.)
并且,在Git 2.31 (Q1 2021)中,oRT合并策略学习了对合并冲突的更多支持。
参见Elijah Newren (Newren)的commit 4ef88fc, commit 4204cd5, commit 70f19c7, commit c73cda7, commit f591c47, commit 62fdec1, commit 991bbdc, commit 5a1a1e8, commit 23366d2, commit 0ccfa4e (01 Jan 2021)。
(由Junio C Hamano—gitster—在commit b65b9ff中合并,2021年2月5日)
合并:添加处理不同类型的文件在同一路径
署名:以利亚·纽伦
Add some handling that explicitly considers collisions of the following types:
file/submodule
file/symlink
submodule/symlink> Leaving them as conflicts at the same path are hard for users to resolve, so move one or both of them aside so that they each get their own path.
Note that in the case of recursive handling (i.e.
call_depth > 0), we can just use the merge base of the two merge bases as the merge result much like we do with modify/delete conflicts, binary files, conflicting submodule values, and so on.