diff -r bcb973abcc0b -r b254f827b7a6 mercurial/localrepo.py --- a/mercurial/localrepo.py Mon Feb 06 15:00:08 2012 -0600 +++ b/mercurial/localrepo.py Mon Feb 06 15:10:01 2012 -0600 @@ -1096,37 +1096,58 @@ # check subrepos subs = [] - removedsubs = set() + commitsubs = set() + newstate = wctx.substate.copy() + # only manage subrepos and .hgsubstate if .hgsub is present if '.hgsub' in wctx: - # only manage subrepos and .hgsubstate if .hgsub is present + # we'll decide whether to track this ourselves, thanks + if '.hgsubstate' in changes[0]: + changes[0].remove('.hgsubstate') + if '.hgsubstate' in changes[2]: + changes[2].remove('.hgsubstate') + + # compare current state to last committed state + # build new substate based on last committed state + oldstate = wctx.p1().substate + for s in sorted(newstate.keys()): + if not match(s): + # ignore working copy, use old state if present + if s in oldstate: + newstate[s] = oldstate[s] + continue + if not force: + raise util.Abort( + _("commit with new subrepo %s excluded") % s) + if wctx.sub(s).dirty(True): + if not self.ui.configbool('ui', 'commitsubrepos'): + raise util.Abort( + _("uncommitted changes in subrepo %s") % s, + hint=_("use --subrepos for recursive commit")) + subs.append(s) + commitsubs.add(s) + else: + bs = wctx.sub(s).basestate() + newstate[s] = (newstate[s][0], bs, newstate[s][2]) + if oldstate.get(s, (None, None, None))[1] != bs: + subs.append(s) + + # check for removed subrepos for p in wctx.parents(): - removedsubs.update(s for s in p.substate if match(s)) - for s in wctx.substate: - removedsubs.discard(s) - if match(s) and wctx.sub(s).dirty(): - subs.append(s) - if (subs or removedsubs): + r = [s for s in p.substate if s not in newstate] + subs += [s for s in r if match(s)] + if subs: if (not match('.hgsub') and '.hgsub' in (wctx.modified() + wctx.added())): raise util.Abort( _("can't commit subrepos without .hgsub")) - if '.hgsubstate' not in changes[0]: - changes[0].insert(0, '.hgsubstate') - if '.hgsubstate' in changes[2]: - changes[2].remove('.hgsubstate') + changes[0].insert(0, '.hgsubstate') + elif '.hgsub' in changes[2]: # clean up .hgsubstate when .hgsub is removed if ('.hgsubstate' in wctx and '.hgsubstate' not in changes[0] + changes[1] + changes[2]): changes[2].insert(0, '.hgsubstate') - if subs and not self.ui.configbool('ui', 'commitsubrepos', False): - changedsubs = [s for s in subs if wctx.sub(s).dirty(True)] - if changedsubs: - raise util.Abort(_("uncommitted changes in subrepo %s") - % changedsubs[0], - hint=_("use --subrepos for recursive commit")) - # make sure all explicit patterns are matched if not force and match.files(): matched = set(changes[0] + changes[1] + changes[2]) @@ -1162,16 +1183,15 @@ cctx._text = editor(self, cctx, subs) edited = (text != cctx._text) - # commit subs - if subs or removedsubs: - state = wctx.substate.copy() - for s in sorted(subs): + # commit subs and write new state + if subs: + for s in sorted(commitsubs): sub = wctx.sub(s) self.ui.status(_('committing subrepository %s\n') % subrepo.subrelpath(sub)) sr = sub.commit(cctx._text, user, date) - state[s] = (state[s][0], sr) - subrepo.writestate(self, state) + newstate[s] = (newstate[s][0], sr) + subrepo.writestate(self, newstate) # Save commit message in case this transaction gets rolled back # (e.g. by a pretxncommit hook). Leave the content alone on