diff --git a/mercurial/revset.py b/mercurial/revset.py --- a/mercurial/revset.py +++ b/mercurial/revset.py @@ -1755,6 +1755,49 @@ def sort(repo, subset, x): l.sort() return baseset([e[-1] for e in l]) +def subrepo(repo, subset, x): + """``subrepo([pattern])`` + Changesets that add, modify or remove the given subrepo. If no subrepo + pattern is named, any subrepo changes are returned. + """ + # i18n: "subrepo" is a keyword + args = getargs(x, 0, 1, _('subrepo takes at most one argument')) + if len(args) != 0: + pat = getstring(args[0], _("subrepo requires a pattern")) + + m = matchmod.exact(repo.root, repo.root, ['.hgsubstate']) + + def submatches(names): + k, p, m = _stringmatcher(pat) + for name in names: + if m(name): + yield name + + def matches(x): + c = repo[x] + s = repo.status(c.p1().node(), c.node(), match=m) + + if len(args) == 0: + return s.added or s.modified or s.removed + + if s.added: + return util.any(submatches(c.substate.keys())) + + if s.modified: + subs = set(c.p1().substate.keys()) + subs.update(c.substate.keys()) + + for path in submatches(subs): + if c.p1().substate.get(path) != c.substate.get(path): + return True + + if s.removed: + return util.any(submatches(c.p1().substate.keys())) + + return False + + return subset.filter(matches) + def _stringmatcher(pattern): """ accepts a string, possibly starting with 're:' or 'literal:' prefix. @@ -1952,6 +1995,7 @@ symbols = { "roots": roots, "sort": sort, "secret": secret, + "subrepo": subrepo, "matching": matching, "tag": tag, "tagged": tagged, diff --git a/tests/test-subrepo-deep-nested-change.t b/tests/test-subrepo-deep-nested-change.t --- a/tests/test-subrepo-deep-nested-change.t +++ b/tests/test-subrepo-deep-nested-change.t @@ -458,4 +458,85 @@ Test a directory commit with a changed l R a.dat R foo/bar/abc + + $ echo foo > main + $ hg ci -m "mod parent only" + $ hg init sub3 + $ echo "sub3 = sub3" >> .hgsub + $ echo xyz > sub3/a.txt + $ hg add sub3/a.txt + $ hg ci -Sm "add sub3" + committing subrepository sub3 + $ cat .hgsub | grep -v sub3 > .hgsub1 + $ mv .hgsub1 .hgsub + $ hg ci -m "remove sub3" + + $ hg log -r "subrepo()" --style compact + 0 7f491f53a367 1970-01-01 00:00 +0000 test + main import + + 1 ffe6649062fe 1970-01-01 00:00 +0000 test + deep nested modif should trigger a commit + + 2 9bb10eebee29 1970-01-01 00:00 +0000 test + add test.txt + + 3 7c64f035294f 1970-01-01 00:00 +0000 test + add large files + + 4 f734a59e2e35 1970-01-01 00:00 +0000 test + forget testing + + 11 9685a22af5db 1970-01-01 00:00 +0000 test + add sub3 + + 12[tip] 2e0485b475b9 1970-01-01 00:00 +0000 test + remove sub3 + + $ hg log -r "subrepo('sub3')" --style compact + 11 9685a22af5db 1970-01-01 00:00 +0000 test + add sub3 + + 12[tip] 2e0485b475b9 1970-01-01 00:00 +0000 test + remove sub3 + + $ hg log -r "subrepo('bogus')" --style compact + + +Test .hgsubstate in the R state + + $ hg rm .hgsub .hgsubstate + $ hg ci -m 'trash subrepo tracking' + + $ hg log -r "subrepo('re:sub\d+')" --style compact + 0 7f491f53a367 1970-01-01 00:00 +0000 test + main import + + 1 ffe6649062fe 1970-01-01 00:00 +0000 test + deep nested modif should trigger a commit + + 2 9bb10eebee29 1970-01-01 00:00 +0000 test + add test.txt + + 3 7c64f035294f 1970-01-01 00:00 +0000 test + add large files + + 4 f734a59e2e35 1970-01-01 00:00 +0000 test + forget testing + + 11 9685a22af5db 1970-01-01 00:00 +0000 test + add sub3 + + 12 2e0485b475b9 1970-01-01 00:00 +0000 test + remove sub3 + + 13[tip] a68b2c361653 1970-01-01 00:00 +0000 test + trash subrepo tracking + + +Restore the trashed subrepo tracking + + $ hg rollback -q + $ hg update -Cq . + $ cd ..