##// 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 This is currently not implemented -- it's an extension point."""
851 This is currently not implemented -- it's an extension point."""
852 return True
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 def manifestmerge(repo, wctx, p2, pa, branchmerge, force, matcher,
955 def manifestmerge(repo, wctx, p2, pa, branchmerge, force, matcher,
855 acceptremote, followcopies, forcefulldiff=False):
956 acceptremote, followcopies, forcefulldiff=False):
856 """
957 """
@@ -1026,6 +1127,9 b' def manifestmerge(repo, wctx, p2, pa, br'
1026 actions[f] = ('dc', (None, f, f, False, pa.node()),
1127 actions[f] = ('dc', (None, f, f, False, pa.node()),
1027 "prompt deleted/changed")
1128 "prompt deleted/changed")
1028
1129
1130 # If we are merging, look for path conflicts.
1131 checkpathconflicts(repo, wctx, p2, actions)
1132
1029 return actions, diverge, renamedelete
1133 return actions, diverge, renamedelete
1030
1134
1031 def _resolvetrivial(repo, wctx, mctx, ancestor, actions):
1135 def _resolvetrivial(repo, wctx, mctx, ancestor, actions):
@@ -103,7 +103,8 b' attack back/test where back symlinks to '
103 back/test
103 back/test
104 #if symlink
104 #if symlink
105 $ hg update -Cr2
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 [255]
108 [255]
108 #else
109 #else
109 ('back' will be a file and cause some other system specific error)
110 ('back' will be a file and cause some other system specific error)
@@ -160,8 +161,12 b' try trivial merge'
160
161
161 $ hg up -qC 1
162 $ hg up -qC 1
162 $ hg merge 2
163 $ hg merge 2
163 abort: path 'a/poisoned' traverses symbolic link 'a'
164 a: path conflict - a file or link has the same name as a directory
164 [255]
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 try rebase onto other revision: cache of audited paths should be discarded,
171 try rebase onto other revision: cache of audited paths should be discarded,
167 and the rebase should fail (issue5628)
172 and the rebase should fail (issue5628)
@@ -169,8 +174,11 b' and the rebase should fail (issue5628)'
169 $ hg up -qC 2
174 $ hg up -qC 2
170 $ hg rebase -s 2 -d 1 --config extensions.rebase=
175 $ hg rebase -s 2 -d 1 --config extensions.rebase=
171 rebasing 2:e73c21d6b244 "file a/poisoned" (tip)
176 rebasing 2:e73c21d6b244 "file a/poisoned" (tip)
172 abort: path 'a/poisoned' traverses symbolic link 'a'
177 a: path conflict - a file or link has the same name as a directory
173 [255]
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 $ ls ../merge-symlink-out
182 $ ls ../merge-symlink-out
175
183
176 $ cd ..
184 $ cd ..
@@ -202,7 +210,8 b' try linear update where symlink already '
202
210
203 $ hg up -qC 0
211 $ hg up -qC 0
204 $ hg up 1
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 [255]
215 [255]
207
216
208 try linear update including symlinked directory and its content: paths are
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 $ hg up -qC null
221 $ hg up -qC null
213 $ hg up 1
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 [255]
225 [255]
216 $ ls ../update-symlink-out
226 $ ls ../update-symlink-out
217
227
@@ -222,7 +232,8 b' a symlink.'
222 $ rm -f a
232 $ rm -f a
223 $ hg up -qC 2
233 $ hg up -qC 2
224 $ hg up 1
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 [255]
237 [255]
227 $ ls ../update-symlink-out
238 $ ls ../update-symlink-out
228
239
@@ -966,8 +966,12 b' and the merge should fail (issue5628)'
966 *** runcommand up -qC 2
966 *** runcommand up -qC 2
967 *** runcommand up -qC 1
967 *** runcommand up -qC 1
968 *** runcommand merge 2
968 *** runcommand merge 2
969 abort: path 'a/poisoned' traverses symbolic link 'a'
969 a: path conflict - a file or link has the same name as a directory
970 [255]
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 $ ls ../merge-symlink-out
975 $ ls ../merge-symlink-out
972
976
973 cache of repo.auditor should be discarded, so matcher would never traverse
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 $ hg bookmark -i
25 $ hg bookmark -i
26 $ hg merge --verbose dir
26 $ hg merge --verbose dir
27 resolving manifests
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 getting a/b
32 getting a/b
29 abort: *: '$TESTTMP/repo/a/b' (glob)
33 1 files updated, 0 files merged, 0 files removed, 1 files unresolved
30 [255]
34 use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
35 [1]
31 $ hg update --clean .
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 Basic update - local directory conflicts with remote file
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