diff --git a/mercurial/localrepo.py b/mercurial/localrepo.py --- a/mercurial/localrepo.py +++ b/mercurial/localrepo.py @@ -949,6 +949,7 @@ class localrepository(repo.repository): # commit subs if subs or removedsubs: + pstate = subrepo.substate(self['.']) state = wctx.substate.copy() for s in sorted(subs): sub = wctx.sub(s) @@ -956,7 +957,19 @@ class localrepository(repo.repository): subrepo.subrelpath(sub)) sr = sub.commit(cctx._text, user, date) state[s] = (state[s][0], sr) - subrepo.writestate(self, state) + + changed = False + if len(pstate) != len(state): + changed = True + if not changed: + for newstate in state: + if state[newstate][1] != pstate[newstate]: + changed = True + if changed: + subrepo.writestate(self, state) + elif (changes[0] == ['.hgsubstate'] and changes[1] == [] and + changes[2] == []): + return None # Save commit message in case this transaction gets rolled back # (e.g. by a pretxncommit hook). Leave the content alone on diff --git a/mercurial/subrepo.py b/mercurial/subrepo.py --- a/mercurial/subrepo.py +++ b/mercurial/subrepo.py @@ -13,6 +13,19 @@ hg = None nullstate = ('', '', 'empty') + +def substate(ctx): + rev = {} + if '.hgsubstate' in ctx: + try: + for l in ctx['.hgsubstate'].data().splitlines(): + revision, path = l.split(" ", 1) + rev[path] = revision + except IOError as err: + if err.errno != errno.ENOENT: + raise + return rev + def state(ctx, ui): """return a state dict, mapping subrepo paths configured in .hgsub to tuple: (source from .hgsub, revision from .hgsubstate, kind @@ -39,15 +52,7 @@ def state(ctx, ui): for path, src in ui.configitems('subpaths'): p.set('subpaths', path, src, ui.configsource('subpaths', path)) - rev = {} - if '.hgsubstate' in ctx: - try: - for l in ctx['.hgsubstate'].data().splitlines(): - revision, path = l.split(" ", 1) - rev[path] = revision - except IOError, err: - if err.errno != errno.ENOENT: - raise + rev = substate(ctx) state = {} for path, src in p[''].items(): diff --git a/tests/test-subrepo-empty-commit.t b/tests/test-subrepo-empty-commit.t new file mode 100644 --- /dev/null +++ b/tests/test-subrepo-empty-commit.t @@ -0,0 +1,64 @@ + $ hg init + $ hg init sub + $ echo 'sub = sub' > .hgsub + $ hg add .hgsub + $ echo c1 > f1 + $ echo c2 > sub/f2 + $ hg add -S + adding f1 + adding sub/f2 + $ hg commit -m0 + committing subrepository sub + +Make .hgsubstate dirty: + + $ echo '0000000000000000000000000000000000000000 sub' > .hgsubstate + $ hg diff --nodates + diff -r 853ea21970bb .hgsubstate + --- a/.hgsubstate + +++ b/.hgsubstate + @@ -1,1 +1,1 @@ + -5bbc614a5b06ad7f3bf7c2463d74b005324f34c1 sub + +0000000000000000000000000000000000000000 sub + +trying to do an empty commit: + + $ hg commit -m1 + committing subrepository sub + nothing changed + [1] + +an okay update of .hgsubstate + $ cd sub + $ echo c3 > f2 + $ hg commit -m "Sub commit" + $ cd .. + $ hg commit -m "Updated sub" + committing subrepository sub + +deleting again: + $ echo '' > .hgsub + $ hg commit -m2 + $ cat .hgsub + + $ cat .hgsubstate + +an okay commit, but with a dirty .hgsubstate + $ echo 'sub = sub' > .hgsub + $ hg commit -m3 + committing subrepository sub + $ echo '0000000000000000000000000000000000000000 sub' > .hgsubstate + $ hg diff --nodates + diff -r 41e1dee3d5d9 .hgsubstate + --- a/.hgsubstate + +++ b/.hgsubstate + @@ -1,1 +1,1 @@ + -fe0229ee9a0a38b43163c756bb51b94228b118e7 sub + +0000000000000000000000000000000000000000 sub + $ echo c4 > f3 + $ hg add f3 + $ hg status + M .hgsubstate + A f3 + $ hg commit -m4 + committing subrepository sub