comparison mercurial/merge.py @ 26768:ac68769a5985

merge.mergestate: only check for merge driver when property is accessed Otherwise 'hg update --clean', 'hg rebase --abort' etc wouldn't work.
author Siddharth Agarwal <sid0@fb.com>
date Thu, 15 Oct 2015 01:04:46 -0700
parents a83110faece1
children 5b00ec4c05cb
comparison
equal deleted inserted replaced
26767:69a121c378ef 26768:ac68769a5985
88 del self.otherctx 88 del self.otherctx
89 if node: 89 if node:
90 self._local = node 90 self._local = node
91 self._other = other 91 self._other = other
92 self._mdstate = 'u' 92 self._mdstate = 'u'
93 self._readmergedriver = None
93 shutil.rmtree(self._repo.join('merge'), True) 94 shutil.rmtree(self._repo.join('merge'), True)
94 self._dirty = False 95 self._dirty = False
95 96
96 def _read(self): 97 def _read(self):
97 """Analyse each record content to restore a serialized state from disk 98 """Analyse each record content to restore a serialized state from disk
103 self._local = None 104 self._local = None
104 self._other = None 105 self._other = None
105 self._mdstate = 'u' 106 self._mdstate = 'u'
106 if 'otherctx' in vars(self): 107 if 'otherctx' in vars(self):
107 del self.otherctx 108 del self.otherctx
109 self._readmergedriver = None
108 records = self._readrecords() 110 records = self._readrecords()
109 for rtype, record in records: 111 for rtype, record in records:
110 if rtype == 'L': 112 if rtype == 'L':
111 self._local = bin(record) 113 self._local = bin(record)
112 elif rtype == 'O': 114 elif rtype == 'O':
116 mdstate = bits[1] 118 mdstate = bits[1]
117 if len(mdstate) != 1 or mdstate not in 'ums': 119 if len(mdstate) != 1 or mdstate not in 'ums':
118 # the merge driver should be idempotent, so just rerun it 120 # the merge driver should be idempotent, so just rerun it
119 mdstate = 'u' 121 mdstate = 'u'
120 122
121 # protect against the following: 123 self._readmergedriver = bits[0]
122 # - A configures a malicious merge driver in their hgrc, then
123 # pauses the merge
124 # - A edits their hgrc to remove references to the merge driver
125 # - A gives a copy of their entire repo, including .hg, to B
126 # - B inspects .hgrc and finds it to be clean
127 # - B then continues the merge and the malicious merge driver
128 # gets invoked
129 if self.mergedriver != bits[0]:
130 raise error.ConfigError(
131 _("merge driver changed since merge started"),
132 hint=_("revert merge driver change or abort merge"))
133 self._mdstate = mdstate 124 self._mdstate = mdstate
134 elif rtype in 'FD': 125 elif rtype in 'FD':
135 bits = record.split('\0') 126 bits = record.split('\0')
136 self._state[bits[0]] = bits[1:] 127 self._state[bits[0]] = bits[1:]
137 elif not rtype.islower(): 128 elif not rtype.islower():
234 raise 225 raise
235 return records 226 return records
236 227
237 @util.propertycache 228 @util.propertycache
238 def mergedriver(self): 229 def mergedriver(self):
239 return self._repo.ui.config('experimental', 'mergedriver') 230 # protect against the following:
231 # - A configures a malicious merge driver in their hgrc, then
232 # pauses the merge
233 # - A edits their hgrc to remove references to the merge driver
234 # - A gives a copy of their entire repo, including .hg, to B
235 # - B inspects .hgrc and finds it to be clean
236 # - B then continues the merge and the malicious merge driver
237 # gets invoked
238 configmergedriver = self._repo.ui.config('experimental', 'mergedriver')
239 if (self._readmergedriver is not None
240 and self._readmergedriver != configmergedriver):
241 raise error.ConfigError(
242 _("merge driver changed since merge started"),
243 hint=_("revert merge driver change or abort merge"))
244
245 return configmergedriver
246
240 @util.propertycache 247 @util.propertycache
241 def otherctx(self): 248 def otherctx(self):
242 return self._repo[self._other] 249 return self._repo[self._other]
243 250
244 def active(self): 251 def active(self):