comparison mercurial/patch.py @ 14534:ecc79816d31e

patch: fix patchmeta/hunk synchronization in iterhunks() Synchronizing on bfile does not work on file removal where bfile is /dev/null. We match items on afile or bfile instead. The incorrect code makes iterhunks() to emit patchmeta and hunks separately in some cases. This is currently hidden by applydiff() being too tolerant when processing patchmeta, and will be fixed later.
author Patrick Mezard <pmezard@gmail.com>
date Sun, 05 Jun 2011 22:24:19 +0200
parents aa12e1bbde10
children e597ef52a7c2
comparison
equal deleted inserted replaced
14533:aa12e1bbde10 14534:ecc79816d31e
1120 if state == BFILE and ( 1120 if state == BFILE and (
1121 (not context and x[0] == '@') 1121 (not context and x[0] == '@')
1122 or (context is not False and x.startswith('***************')) 1122 or (context is not False and x.startswith('***************'))
1123 or x.startswith('GIT binary patch')): 1123 or x.startswith('GIT binary patch')):
1124 gp = None 1124 gp = None
1125 if gitpatches and gitpatches[-1][0] == bfile: 1125 if (gitpatches and
1126 gp = gitpatches.pop()[1] 1126 (gitpatches[-1][0] == afile or gitpatches[-1][1] == bfile)):
1127 gp = gitpatches.pop()[2]
1127 if x.startswith('GIT binary patch'): 1128 if x.startswith('GIT binary patch'):
1128 h = binhunk(lr) 1129 h = binhunk(lr)
1129 else: 1130 else:
1130 if context is None and x.startswith('***************'): 1131 if context is None and x.startswith('***************'):
1131 context = True 1132 context = True
1139 m = gitre.match(x) 1140 m = gitre.match(x)
1140 if not m: 1141 if not m:
1141 continue 1142 continue
1142 if gitpatches is None: 1143 if gitpatches is None:
1143 # scan whole input for git metadata 1144 # scan whole input for git metadata
1144 gitpatches = [('b/' + gp.path, gp) for gp 1145 gitpatches = [('a/' + gp.path, 'b/' + gp.path, gp) for gp
1145 in scangitpatch(lr, x)] 1146 in scangitpatch(lr, x)]
1146 yield 'git', [g[1] for g in gitpatches 1147 yield 'git', [g[2] for g in gitpatches
1147 if g[1].op in ('COPY', 'RENAME')] 1148 if g[2].op in ('COPY', 'RENAME')]
1148 gitpatches.reverse() 1149 gitpatches.reverse()
1149 afile = 'a/' + m.group(1) 1150 afile = 'a/' + m.group(1)
1150 bfile = 'b/' + m.group(2) 1151 bfile = 'b/' + m.group(2)
1151 while bfile != gitpatches[-1][0]: 1152 while afile != gitpatches[-1][0] and bfile != gitpatches[-1][1]:
1152 gp = gitpatches.pop()[1] 1153 gp = gitpatches.pop()[2]
1153 yield 'file', ('a/' + gp.path, 'b/' + gp.path, None, gp) 1154 yield 'file', ('a/' + gp.path, 'b/' + gp.path, None, gp)
1154 gp = gitpatches[-1][1] 1155 gp = gitpatches[-1][2]
1155 # copy/rename + modify should modify target, not source 1156 # copy/rename + modify should modify target, not source
1156 if gp.op in ('COPY', 'DELETE', 'RENAME', 'ADD') or gp.mode: 1157 if gp.op in ('COPY', 'DELETE', 'RENAME', 'ADD') or gp.mode:
1157 afile = bfile 1158 afile = bfile
1158 newfile = True 1159 newfile = True
1159 elif x.startswith('---'): 1160 elif x.startswith('---'):
1187 emitfile = True 1188 emitfile = True
1188 state = BFILE 1189 state = BFILE
1189 hunknum = 0 1190 hunknum = 0
1190 1191
1191 while gitpatches: 1192 while gitpatches:
1192 gp = gitpatches.pop()[1] 1193 gp = gitpatches.pop()[2]
1193 yield 'file', ('a/' + gp.path, 'b/' + gp.path, None, gp) 1194 yield 'file', ('a/' + gp.path, 'b/' + gp.path, None, gp)
1194 1195
1195 def applydiff(ui, fp, changed, backend, store, strip=1, eolmode='strict'): 1196 def applydiff(ui, fp, changed, backend, store, strip=1, eolmode='strict'):
1196 """Reads a patch from fp and tries to apply it. 1197 """Reads a patch from fp and tries to apply it.
1197 1198