21 sidedata as sidedatamod, |
21 sidedata as sidedatamod, |
22 ) |
22 ) |
23 |
23 |
24 |
24 |
25 class ChangingFiles(object): |
25 class ChangingFiles(object): |
26 """A class recording the changes made to a file by a revision |
26 """A class recording the changes made to a file by a changeset |
|
27 |
|
28 Actions performed on files are gathered into 3 sets: |
|
29 |
|
30 - added: files actively added in the changeset. |
|
31 - removed: files removed in the revision |
|
32 - touched: files affected by the merge |
|
33 |
|
34 and copies information is held by 2 mappings |
|
35 |
|
36 - copied_from_p1: {"<new-name>": "<source-name-in-p1>"} mapping for copies |
|
37 - copied_from_p2: {"<new-name>": "<source-name-in-p2>"} mapping for copies |
|
38 |
|
39 See their inline help for details. |
27 """ |
40 """ |
28 |
41 |
29 def __init__( |
42 def __init__( |
30 self, touched=(), added=(), removed=(), p1_copies=(), p2_copies=(), |
43 self, touched=(), added=(), removed=(), p1_copies=(), p2_copies=(), |
31 ): |
44 ): |
37 self._p1_copies = dict(p1_copies) |
50 self._p1_copies = dict(p1_copies) |
38 self._p2_copies = dict(p2_copies) |
51 self._p2_copies = dict(p2_copies) |
39 |
52 |
40 @property |
53 @property |
41 def added(self): |
54 def added(self): |
|
55 """files actively added in the changeset |
|
56 |
|
57 Any file present in that revision that was absent in all the changeset's |
|
58 parents. |
|
59 |
|
60 In case of merge, this means a file absent in one of the parents but |
|
61 existing in the other will *not* be contained in this set. (They were |
|
62 added by an ancestor) |
|
63 """ |
42 return frozenset(self._added) |
64 return frozenset(self._added) |
43 |
65 |
44 def mark_added(self, filename): |
66 def mark_added(self, filename): |
45 self._added.add(filename) |
67 self._added.add(filename) |
46 self._touched.add(filename) |
68 self._touched.add(filename) |
49 for f in filenames: |
71 for f in filenames: |
50 self.mark_added(f) |
72 self.mark_added(f) |
51 |
73 |
52 @property |
74 @property |
53 def removed(self): |
75 def removed(self): |
|
76 """files actively removed by the changeset |
|
77 |
|
78 In case of merge this will only contain the set of files removing "new" |
|
79 content. For any file absent in the current changeset: |
|
80 |
|
81 a) If the file exists in both parents, it is clearly "actively" removed |
|
82 by this changeset. |
|
83 |
|
84 b) If a file exists in only one parent and in none of the common |
|
85 ancestors, then the file was newly added in one of the merged branches |
|
86 and then got "actively" removed. |
|
87 |
|
88 c) If a file exists in only one parent and at least one of the common |
|
89 ancestors using the same filenode, then the file was unchanged on one |
|
90 side and deleted on the other side. The merge "passively" propagated |
|
91 that deletion, but didn't "actively" remove the file. In this case the |
|
92 file is *not* included in the `removed` set. |
|
93 |
|
94 d) If a file exists in only one parent and at least one of the common |
|
95 ancestors using a different filenode, then the file was changed on one |
|
96 side and removed on the other side. The merge process "actively" |
|
97 decided to drop the new change and delete the file. Unlike in the |
|
98 previous case, (c), the file included in the `removed` set. |
|
99 |
|
100 Summary table for merge: |
|
101 |
|
102 case | exists in parents | exists in gca || removed |
|
103 (a) | both | * || yes |
|
104 (b) | one | none || yes |
|
105 (c) | one | same filenode || no |
|
106 (d) | one | new filenode || yes |
|
107 """ |
54 return frozenset(self._removed) |
108 return frozenset(self._removed) |
55 |
109 |
56 def mark_removed(self, filename): |
110 def mark_removed(self, filename): |
57 self._removed.add(filename) |
111 self._removed.add(filename) |
58 self._touched.add(filename) |
112 self._touched.add(filename) |