##// END OF EJS Templates
merge: check for path conflicts when merging (issue5628)...
Mark Thomas -
r34556:989e884d default
parent child Browse files
Show More
@@ -851,6 +851,107 b' def driverconclude(repo, ms, wctx, label'
851 851 This is currently not implemented -- it's an extension point."""
852 852 return True
853 853
854 def _filesindirs(repo, manifest, dirs):
855 """
856 Generator that yields pairs of all the files in the manifest that are found
857 inside the directories listed in dirs, and which directory they are found
858 in.
859 """
860 for f in manifest:
861 for p in util.finddirs(f):
862 if p in dirs:
863 yield f, p
864 break
865
866 def checkpathconflicts(repo, wctx, mctx, actions):
867 """
868 Check if any actions introduce path conflicts in the repository, updating
869 actions to record or handle the path conflict accordingly.
870 """
871 mf = wctx.manifest()
872
873 # The set of local files that conflict with a remote directory.
874 localconflicts = set()
875
876 # The set of directories that conflict with a remote file, and so may cause
877 # conflicts if they still contain any files after the merge.
878 remoteconflicts = set()
879
880 # The set of directories that appear as both a file and a directory in the
881 # remote manifest. These indicate an invalid remote manifest, which
882 # can't be updated to cleanly.
883 invalidconflicts = set()
884
885 # The set of files deleted by all the actions.
886 deletedfiles = set()
887
888 for f, (m, args, msg) in actions.items():
889 if m in ('c', 'dc', 'm', 'cm'):
890 # This action may create a new local file.
891 if mf.hasdir(f):
892 # The file aliases a local directory. This might be ok if all
893 # the files in the local directory are being deleted. This
894 # will be checked once we know what all the deleted files are.
895 remoteconflicts.add(f)
896 for p in util.finddirs(f):
897 if p in mf:
898 if p in mctx:
899 # The file is in a directory which aliases both a local
900 # and a remote file. This is an internal inconsistency
901 # within the remote manifest.
902 invalidconflicts.add(p)
903 else:
904 # The file is in a directory which aliases a local file.
905 # We will need to rename the local file.
906 localconflicts.add(p)
907 if p in actions and actions[p][0] in ('c', 'dc', 'm', 'cm'):
908 # The file is in a directory which aliases a remote file.
909 # This is an internal inconsistency within the remote
910 # manifest.
911 invalidconflicts.add(p)
912
913 # Track the names of all deleted files.
914 if m == 'r':
915 deletedfiles.add(f)
916 if m == 'm':
917 f1, f2, fa, move, anc = args
918 if move:
919 deletedfiles.add(f1)
920 if m == 'dm':
921 f2, flags = args
922 deletedfiles.add(f2)
923
924 # Rename all local conflicting files that have not been deleted.
925 for p in localconflicts:
926 if p not in deletedfiles:
927 ctxname = str(wctx).rstrip('+')
928 pnew = util.safename(p, ctxname, wctx, set(actions.keys()))
929 actions[pnew] = ('pr', (p,), "local path conflict")
930 actions[p] = ('p', (pnew, 'l'), "path conflict")
931
932 if remoteconflicts:
933 # Check if all files in the conflicting directories have been removed.
934 ctxname = str(mctx).rstrip('+')
935 for f, p in _filesindirs(repo, mf, remoteconflicts):
936 if f not in deletedfiles:
937 m, args, msg = actions[p]
938 pnew = util.safename(p, ctxname, wctx, set(actions.keys()))
939 if m in ('dc', 'm'):
940 # Action was merge, just update target.
941 actions[pnew] = (m, args, msg)
942 else:
943 # Action was create, change to renamed get action.
944 fl = args[0]
945 actions[pnew] = ('dg', (p, fl), "remote path conflict")
946 actions[p] = ('p', (pnew, 'r'), "path conflict")
947 remoteconflicts.remove(p)
948 break
949
950 if invalidconflicts:
951 for p in invalidconflicts:
952 repo.ui.warn(_("%s: is both a file and a directory\n") % p)
953 raise error.Abort(_("destination manifest contains path conflicts"))
954
854 955 def manifestmerge(repo, wctx, p2, pa, branchmerge, force, matcher,
855 956 acceptremote, followcopies, forcefulldiff=False):
856 957 """
@@ -1026,6 +1127,9 b' def manifestmerge(repo, wctx, p2, pa, br'
1026 1127 actions[f] = ('dc', (None, f, f, False, pa.node()),
1027 1128 "prompt deleted/changed")
1028 1129
1130 # If we are merging, look for path conflicts.
1131 checkpathconflicts(repo, wctx, p2, actions)
1132
1029 1133 return actions, diverge, renamedelete
1030 1134
1031 1135 def _resolvetrivial(repo, wctx, mctx, ancestor, actions):
@@ -103,7 +103,8 b' attack back/test where back symlinks to '
103 103 back/test
104 104 #if symlink
105 105 $ hg update -Cr2
106 abort: path 'back/test' traverses symbolic link 'back'
106 back: is both a file and a directory
107 abort: destination manifest contains path conflicts
107 108 [255]
108 109 #else
109 110 ('back' will be a file and cause some other system specific error)
@@ -160,8 +161,12 b' try trivial merge'
160 161
161 162 $ hg up -qC 1
162 163 $ hg merge 2
163 abort: path 'a/poisoned' traverses symbolic link 'a'
164 [255]
164 a: path conflict - a file or link has the same name as a directory
165 the local file has been renamed to a~aa04623eb0c3
166 resolve manually then use 'hg resolve --mark a'
167 1 files updated, 0 files merged, 0 files removed, 1 files unresolved
168 use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
169 [1]
165 170
166 171 try rebase onto other revision: cache of audited paths should be discarded,
167 172 and the rebase should fail (issue5628)
@@ -169,8 +174,11 b' and the rebase should fail (issue5628)'
169 174 $ hg up -qC 2
170 175 $ hg rebase -s 2 -d 1 --config extensions.rebase=
171 176 rebasing 2:e73c21d6b244 "file a/poisoned" (tip)
172 abort: path 'a/poisoned' traverses symbolic link 'a'
173 [255]
177 a: path conflict - a file or link has the same name as a directory
178 the local file has been renamed to a~aa04623eb0c3
179 resolve manually then use 'hg resolve --mark a'
180 unresolved conflicts (see hg resolve, then hg rebase --continue)
181 [1]
174 182 $ ls ../merge-symlink-out
175 183
176 184 $ cd ..
@@ -202,7 +210,8 b' try linear update where symlink already '
202 210
203 211 $ hg up -qC 0
204 212 $ hg up 1
205 abort: path 'a/b' traverses symbolic link 'a'
213 a: is both a file and a directory
214 abort: destination manifest contains path conflicts
206 215 [255]
207 216
208 217 try linear update including symlinked directory and its content: paths are
@@ -211,7 +220,8 b' audited first by calculateupdates(), whe'
211 220
212 221 $ hg up -qC null
213 222 $ hg up 1
214 abort: path 'a/b' traverses symbolic link 'a'
223 a: is both a file and a directory
224 abort: destination manifest contains path conflicts
215 225 [255]
216 226 $ ls ../update-symlink-out
217 227
@@ -222,7 +232,8 b' a symlink.'
222 232 $ rm -f a
223 233 $ hg up -qC 2
224 234 $ hg up 1
225 abort: path 'a/b' traverses symbolic link 'a'
235 a: is both a file and a directory
236 abort: destination manifest contains path conflicts
226 237 [255]
227 238 $ ls ../update-symlink-out
228 239
@@ -966,8 +966,12 b' and the merge should fail (issue5628)'
966 966 *** runcommand up -qC 2
967 967 *** runcommand up -qC 1
968 968 *** runcommand merge 2
969 abort: path 'a/poisoned' traverses symbolic link 'a'
970 [255]
969 a: path conflict - a file or link has the same name as a directory
970 the local file has been renamed to a~aa04623eb0c3
971 resolve manually then use 'hg resolve --mark a'
972 1 files updated, 0 files merged, 0 files removed, 1 files unresolved
973 use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
974 [1]
971 975 $ ls ../merge-symlink-out
972 976
973 977 cache of repo.auditor should be discarded, so matcher would never traverse
@@ -25,11 +25,16 b' Basic merge - local file conflicts with '
25 25 $ hg bookmark -i
26 26 $ hg merge --verbose dir
27 27 resolving manifests
28 a: path conflict - a file or link has the same name as a directory
29 the local file has been renamed to a~853701544ac3
30 resolve manually then use 'hg resolve --mark a'
31 moving a to a~853701544ac3
28 32 getting a/b
29 abort: *: '$TESTTMP/repo/a/b' (glob)
30 [255]
33 1 files updated, 0 files merged, 0 files removed, 1 files unresolved
34 use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
35 [1]
31 36 $ hg update --clean .
32 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
37 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
33 38
34 39 Basic update - local directory conflicts with remote file
35 40
General Comments 0
You need to be logged in to leave comments. Login now