]> git.ipfire.org Git - thirdparty/git.git/blame - Documentation/technical/directory-rename-detection.txt
Merge branch 'jc/do-not-just-explain-but-update-your-patch'
[thirdparty/git.git] / Documentation / technical / directory-rename-detection.txt
CommitLineData
4d34dffb
EN
1Directory rename detection
2==========================
3
4Rename detection logic in diffcore-rename that checks for renames of
5individual files is aggregated and analyzed in merge-recursive for cases
6where combinations of renames indicate that a full directory has been
7renamed.
8
9Scope of abilities
10------------------
11
12It is perhaps easiest to start with an example:
13
14 * When all of x/a, x/b and x/c have moved to z/a, z/b and z/c, it is
15 likely that x/d added in the meantime would also want to move to z/d by
16 taking the hint that the entire directory 'x' moved to 'z'.
17
18More interesting possibilities exist, though, such as:
19
20 * one side of history renames x -> z, and the other renames some file to
b9718d0c
EN
21 x/e, causing the need for the merge to do a transitive rename so that
22 the rename ends up at z/e.
4d34dffb 23
64eca306
JNA
24 * one side of history renames x -> z, but also renames all files within x.
25 For example, x/a -> z/alpha, x/b -> z/bravo, etc.
4d34dffb
EN
26
27 * both 'x' and 'y' being merged into a single directory 'z', with a
28 directory rename being detected for both x->z and y->z.
29
30 * not all files in a directory being renamed to the same location;
31 i.e. perhaps most the files in 'x' are now found under 'z', but a few
32 are found under 'w'.
33
34 * a directory being renamed, which also contained a subdirectory that was
35 renamed to some entirely different location. (And perhaps the inner
36 directory itself contained inner directories that were renamed to yet
37 other locations).
38
b9718d0c 39 * combinations of the above; see t/t6423-merge-rename-directories.sh for
4d34dffb
EN
40 various interesting cases.
41
42Limitations -- applicability of directory renames
43-------------------------------------------------
44
45In order to prevent edge and corner cases resulting in either conflicts
46that cannot be represented in the index or which might be too complex for
47users to try to understand and resolve, a couple basic rules limit when
48directory rename detection applies:
49
50 1) If a given directory still exists on both sides of a merge, we do
51 not consider it to have been renamed.
52
53 2) If a subset of to-be-renamed files have a file or directory in the
54 way (or would be in the way of each other), "turn off" the directory
55 rename for those specific sub-paths and report the conflict to the
56 user.
57
58 3) If the other side of history did a directory rename to a path that
59 your side of history renamed away, then ignore that particular
60 rename from the other side of history for any implicit directory
61 renames (but warn the user).
62
63Limitations -- detailed rules and testcases
64-------------------------------------------
65
b9718d0c 66t/t6423-merge-rename-directories.sh contains extensive tests and commentary
4d34dffb
EN
67which generate and explore the rules listed above. It also lists a few
68additional rules:
69
70 a) If renames split a directory into two or more others, the directory
71 with the most renames, "wins".
72
8536821d 73 b) Only apply implicit directory renames to directories if the other side
4d34dffb
EN
74 of history is the one doing the renaming.
75
c64432aa
EN
76 c) Do not perform directory rename detection for directories which had no
77 new paths added to them.
78
4d34dffb
EN
79Limitations -- support in different commands
80--------------------------------------------
81
82Directory rename detection is supported by 'merge' and 'cherry-pick'.
83Other git commands which users might be surprised to see limited or no
84directory rename detection support in:
85
86 * diff
87
88 Folks have requested in the past that `git diff` detect directory
89 renames and somehow simplify its output. It is not clear whether this
90 would be desirable or how the output should be simplified, so this was
91 simply not implemented. Further, to implement this, directory rename
92 detection logic would need to move from merge-recursive to
93 diffcore-rename.
0661e49a
EN
94
95 * am
96
97 git-am tries to avoid a full three way merge, instead calling
98 git-apply. That prevents us from detecting renames at all, which may
99 defeat the directory rename detection. There is a fallback, though; if
100 the initial git-apply fails and the user has specified the -3 option,
101 git-am will fall back to a three way merge. However, git-am lacks the
102 necessary information to do a "real" three way merge. Instead, it has
103 to use build_fake_ancestor() to get a merge base that is missing files
104 whose rename may have been important to detect for directory rename
105 detection to function.
106
107 * rebase
108
109 Since am-based rebases work by first generating a bunch of patches
110 (which no longer record what the original commits were and thus don't
111 have the necessary info from which we can find a real merge-base), and
112 then calling git-am, this implies that am-based rebases will not always
113 successfully detect directory renames either (see the 'am' section
114 above). merged-based rebases (rebase -m) and cherry-pick-based rebases
115 (rebase -i) are not affected by this shortcoming, and fully support
116 directory rename detection.