Mercurial > public > mercurial-scm > hg
comparison mercurial/localrepo.py @ 16073:b254f827b7a6
subrepo: rewrite handling of subrepo state at commit (issue2403)
When the contents of .hgsubstate are stale (either because they've
manually been tweaked or partial updates have confused it), we get
confused about whether it actually needs committing.
So instead, we actively consult the parent's substate and compare it
the actual current state when deciding whether it needs committing.
Side effect: lots of "committing subrepo" messages that didn't
correspond with real commits disappear.
This change is fairly invasive for a fairly obscure condition, so it's
kept on the default branch.
author | Matt Mackall <mpm@selenic.com> |
---|---|
date | Mon, 06 Feb 2012 15:10:01 -0600 |
parents | 308406677e9d |
children | 004982e5d782 |
comparison
equal
deleted
inserted
replaced
16072:bcb973abcc0b | 16073:b254f827b7a6 |
---|---|
1094 if force: | 1094 if force: |
1095 changes[0].extend(changes[6]) # mq may commit unchanged files | 1095 changes[0].extend(changes[6]) # mq may commit unchanged files |
1096 | 1096 |
1097 # check subrepos | 1097 # check subrepos |
1098 subs = [] | 1098 subs = [] |
1099 removedsubs = set() | 1099 commitsubs = set() |
1100 newstate = wctx.substate.copy() | |
1101 # only manage subrepos and .hgsubstate if .hgsub is present | |
1100 if '.hgsub' in wctx: | 1102 if '.hgsub' in wctx: |
1101 # only manage subrepos and .hgsubstate if .hgsub is present | 1103 # we'll decide whether to track this ourselves, thanks |
1104 if '.hgsubstate' in changes[0]: | |
1105 changes[0].remove('.hgsubstate') | |
1106 if '.hgsubstate' in changes[2]: | |
1107 changes[2].remove('.hgsubstate') | |
1108 | |
1109 # compare current state to last committed state | |
1110 # build new substate based on last committed state | |
1111 oldstate = wctx.p1().substate | |
1112 for s in sorted(newstate.keys()): | |
1113 if not match(s): | |
1114 # ignore working copy, use old state if present | |
1115 if s in oldstate: | |
1116 newstate[s] = oldstate[s] | |
1117 continue | |
1118 if not force: | |
1119 raise util.Abort( | |
1120 _("commit with new subrepo %s excluded") % s) | |
1121 if wctx.sub(s).dirty(True): | |
1122 if not self.ui.configbool('ui', 'commitsubrepos'): | |
1123 raise util.Abort( | |
1124 _("uncommitted changes in subrepo %s") % s, | |
1125 hint=_("use --subrepos for recursive commit")) | |
1126 subs.append(s) | |
1127 commitsubs.add(s) | |
1128 else: | |
1129 bs = wctx.sub(s).basestate() | |
1130 newstate[s] = (newstate[s][0], bs, newstate[s][2]) | |
1131 if oldstate.get(s, (None, None, None))[1] != bs: | |
1132 subs.append(s) | |
1133 | |
1134 # check for removed subrepos | |
1102 for p in wctx.parents(): | 1135 for p in wctx.parents(): |
1103 removedsubs.update(s for s in p.substate if match(s)) | 1136 r = [s for s in p.substate if s not in newstate] |
1104 for s in wctx.substate: | 1137 subs += [s for s in r if match(s)] |
1105 removedsubs.discard(s) | 1138 if subs: |
1106 if match(s) and wctx.sub(s).dirty(): | |
1107 subs.append(s) | |
1108 if (subs or removedsubs): | |
1109 if (not match('.hgsub') and | 1139 if (not match('.hgsub') and |
1110 '.hgsub' in (wctx.modified() + wctx.added())): | 1140 '.hgsub' in (wctx.modified() + wctx.added())): |
1111 raise util.Abort( | 1141 raise util.Abort( |
1112 _("can't commit subrepos without .hgsub")) | 1142 _("can't commit subrepos without .hgsub")) |
1113 if '.hgsubstate' not in changes[0]: | 1143 changes[0].insert(0, '.hgsubstate') |
1114 changes[0].insert(0, '.hgsubstate') | 1144 |
1115 if '.hgsubstate' in changes[2]: | |
1116 changes[2].remove('.hgsubstate') | |
1117 elif '.hgsub' in changes[2]: | 1145 elif '.hgsub' in changes[2]: |
1118 # clean up .hgsubstate when .hgsub is removed | 1146 # clean up .hgsubstate when .hgsub is removed |
1119 if ('.hgsubstate' in wctx and | 1147 if ('.hgsubstate' in wctx and |
1120 '.hgsubstate' not in changes[0] + changes[1] + changes[2]): | 1148 '.hgsubstate' not in changes[0] + changes[1] + changes[2]): |
1121 changes[2].insert(0, '.hgsubstate') | 1149 changes[2].insert(0, '.hgsubstate') |
1122 | |
1123 if subs and not self.ui.configbool('ui', 'commitsubrepos', False): | |
1124 changedsubs = [s for s in subs if wctx.sub(s).dirty(True)] | |
1125 if changedsubs: | |
1126 raise util.Abort(_("uncommitted changes in subrepo %s") | |
1127 % changedsubs[0], | |
1128 hint=_("use --subrepos for recursive commit")) | |
1129 | 1150 |
1130 # make sure all explicit patterns are matched | 1151 # make sure all explicit patterns are matched |
1131 if not force and match.files(): | 1152 if not force and match.files(): |
1132 matched = set(changes[0] + changes[1] + changes[2]) | 1153 matched = set(changes[0] + changes[1] + changes[2]) |
1133 | 1154 |
1160 cctx = context.workingctx(self, text, user, date, extra, changes) | 1181 cctx = context.workingctx(self, text, user, date, extra, changes) |
1161 if editor: | 1182 if editor: |
1162 cctx._text = editor(self, cctx, subs) | 1183 cctx._text = editor(self, cctx, subs) |
1163 edited = (text != cctx._text) | 1184 edited = (text != cctx._text) |
1164 | 1185 |
1165 # commit subs | 1186 # commit subs and write new state |
1166 if subs or removedsubs: | 1187 if subs: |
1167 state = wctx.substate.copy() | 1188 for s in sorted(commitsubs): |
1168 for s in sorted(subs): | |
1169 sub = wctx.sub(s) | 1189 sub = wctx.sub(s) |
1170 self.ui.status(_('committing subrepository %s\n') % | 1190 self.ui.status(_('committing subrepository %s\n') % |
1171 subrepo.subrelpath(sub)) | 1191 subrepo.subrelpath(sub)) |
1172 sr = sub.commit(cctx._text, user, date) | 1192 sr = sub.commit(cctx._text, user, date) |
1173 state[s] = (state[s][0], sr) | 1193 newstate[s] = (newstate[s][0], sr) |
1174 subrepo.writestate(self, state) | 1194 subrepo.writestate(self, newstate) |
1175 | 1195 |
1176 # Save commit message in case this transaction gets rolled back | 1196 # Save commit message in case this transaction gets rolled back |
1177 # (e.g. by a pretxncommit hook). Leave the content alone on | 1197 # (e.g. by a pretxncommit hook). Leave the content alone on |
1178 # the assumption that the user will use the same editor again. | 1198 # the assumption that the user will use the same editor again. |
1179 msgfn = self.savecommitmessage(cctx._text) | 1199 msgfn = self.savecommitmessage(cctx._text) |