merge(third_party/git): Merge squashed git subtree at v2.23.0
Merge commit '1b593e1ea4
' as 'third_party/git'
This commit is contained in:
commit
7ef0d62730
3629 changed files with 1139935 additions and 0 deletions
115
third_party/git/Documentation/technical/directory-rename-detection.txt
vendored
Normal file
115
third_party/git/Documentation/technical/directory-rename-detection.txt
vendored
Normal file
|
@ -0,0 +1,115 @@
|
|||
Directory rename detection
|
||||
==========================
|
||||
|
||||
Rename detection logic in diffcore-rename that checks for renames of
|
||||
individual files is aggregated and analyzed in merge-recursive for cases
|
||||
where combinations of renames indicate that a full directory has been
|
||||
renamed.
|
||||
|
||||
Scope of abilities
|
||||
------------------
|
||||
|
||||
It is perhaps easiest to start with an example:
|
||||
|
||||
* When all of x/a, x/b and x/c have moved to z/a, z/b and z/c, it is
|
||||
likely that x/d added in the meantime would also want to move to z/d by
|
||||
taking the hint that the entire directory 'x' moved to 'z'.
|
||||
|
||||
More interesting possibilities exist, though, such as:
|
||||
|
||||
* one side of history renames x -> z, and the other renames some file to
|
||||
x/e, causing the need for the merge to do a transitive rename.
|
||||
|
||||
* one side of history renames x -> z, but also renames all files within x.
|
||||
For example, x/a -> z/alpha, x/b -> z/bravo, etc.
|
||||
|
||||
* both 'x' and 'y' being merged into a single directory 'z', with a
|
||||
directory rename being detected for both x->z and y->z.
|
||||
|
||||
* not all files in a directory being renamed to the same location;
|
||||
i.e. perhaps most the files in 'x' are now found under 'z', but a few
|
||||
are found under 'w'.
|
||||
|
||||
* a directory being renamed, which also contained a subdirectory that was
|
||||
renamed to some entirely different location. (And perhaps the inner
|
||||
directory itself contained inner directories that were renamed to yet
|
||||
other locations).
|
||||
|
||||
* combinations of the above; see t/t6043-merge-rename-directories.sh for
|
||||
various interesting cases.
|
||||
|
||||
Limitations -- applicability of directory renames
|
||||
-------------------------------------------------
|
||||
|
||||
In order to prevent edge and corner cases resulting in either conflicts
|
||||
that cannot be represented in the index or which might be too complex for
|
||||
users to try to understand and resolve, a couple basic rules limit when
|
||||
directory rename detection applies:
|
||||
|
||||
1) If a given directory still exists on both sides of a merge, we do
|
||||
not consider it to have been renamed.
|
||||
|
||||
2) If a subset of to-be-renamed files have a file or directory in the
|
||||
way (or would be in the way of each other), "turn off" the directory
|
||||
rename for those specific sub-paths and report the conflict to the
|
||||
user.
|
||||
|
||||
3) If the other side of history did a directory rename to a path that
|
||||
your side of history renamed away, then ignore that particular
|
||||
rename from the other side of history for any implicit directory
|
||||
renames (but warn the user).
|
||||
|
||||
Limitations -- detailed rules and testcases
|
||||
-------------------------------------------
|
||||
|
||||
t/t6043-merge-rename-directories.sh contains extensive tests and commentary
|
||||
which generate and explore the rules listed above. It also lists a few
|
||||
additional rules:
|
||||
|
||||
a) If renames split a directory into two or more others, the directory
|
||||
with the most renames, "wins".
|
||||
|
||||
b) Avoid directory-rename-detection for a path, if that path is the
|
||||
source of a rename on either side of a merge.
|
||||
|
||||
c) Only apply implicit directory renames to directories if the other side
|
||||
of history is the one doing the renaming.
|
||||
|
||||
Limitations -- support in different commands
|
||||
--------------------------------------------
|
||||
|
||||
Directory rename detection is supported by 'merge' and 'cherry-pick'.
|
||||
Other git commands which users might be surprised to see limited or no
|
||||
directory rename detection support in:
|
||||
|
||||
* diff
|
||||
|
||||
Folks have requested in the past that `git diff` detect directory
|
||||
renames and somehow simplify its output. It is not clear whether this
|
||||
would be desirable or how the output should be simplified, so this was
|
||||
simply not implemented. Further, to implement this, directory rename
|
||||
detection logic would need to move from merge-recursive to
|
||||
diffcore-rename.
|
||||
|
||||
* am
|
||||
|
||||
git-am tries to avoid a full three way merge, instead calling
|
||||
git-apply. That prevents us from detecting renames at all, which may
|
||||
defeat the directory rename detection. There is a fallback, though; if
|
||||
the initial git-apply fails and the user has specified the -3 option,
|
||||
git-am will fall back to a three way merge. However, git-am lacks the
|
||||
necessary information to do a "real" three way merge. Instead, it has
|
||||
to use build_fake_ancestor() to get a merge base that is missing files
|
||||
whose rename may have been important to detect for directory rename
|
||||
detection to function.
|
||||
|
||||
* rebase
|
||||
|
||||
Since am-based rebases work by first generating a bunch of patches
|
||||
(which no longer record what the original commits were and thus don't
|
||||
have the necessary info from which we can find a real merge-base), and
|
||||
then calling git-am, this implies that am-based rebases will not always
|
||||
successfully detect directory renames either (see the 'am' section
|
||||
above). merged-based rebases (rebase -m) and cherry-pick-based rebases
|
||||
(rebase -i) are not affected by this shortcoming, and fully support
|
||||
directory rename detection.
|
Loading…
Add table
Add a link
Reference in a new issue