[PATCH] convert: keep track of files created in filtered-out revisions

Yury Sulsky yury.sulsky at gmail.com
Sun Nov 27 07:51:14 CST 2011


This patch makes the semantics of --includerevs and --excluderevs much
nicer. Previously, if you created (or deleted) a file in a skipped
revision and didn't modify it subsequently, the file would not exist
(or still exist) in the destination repo. Now we just keep track of
these files when using  --includerevs or --excluderevs.

Yury

On Sun, Nov 27, 2011 at 8:41 AM, Yury Sulsky <yury.sulsky at gmail.com> wrote:
> # HG changeset patch
> # User Yury Sulsky <yury.sulsky at gmail.com>
> # Date 1322370781 18000
> # Branch stable
> # Node ID e86bc97a0a38b9497342b69a0eda9cce3b1c5d58
> # Parent  2d5e44d732e5207a683300f12207ef147b0e4e67
> convert: keep track of files created in filtered-out revisions
>
> diff -r 2d5e44d732e5 -r e86bc97a0a38 hgext/convert/filtermap.py
> --- a/hgext/convert/filtermap.py        Sat Nov 26 15:51:10 2011 -0500
> +++ b/hgext/convert/filtermap.py        Sun Nov 27 00:13:01 2011 -0500
> @@ -23,7 +23,7 @@
>         """Return True if we want to keep this revision"""
>         return True
>
> -    def __init__(self, ui, baseconverter):
> +    def __init__(self, ui, baseconverter, trackchanges):
>         super(filtermap_base, self).__init__(ui)
>         self.base = baseconverter
>         self.commits = {}
> @@ -38,6 +38,8 @@
>         self.origparents = {}
>         self.children = {}
>         self.seenchildren = {}
> +        self.skippedchanges = {}
> +        self.trackingchanges = trackchanges
>
>     def before(self):
>         self.base.before()
> @@ -51,7 +53,7 @@
>         # To avoid calling getcommit for every revision that has already
>         # been converted, we rebuild only the parentmap, delaying the
>         # rebuild of wantedancestors until we need it (i.e. until a
> -        # merge).
> +        # merge or if we are tracking changes).
>         #
>         # We assume the order argument lists the revisions in
>         # topological order, so that we can infer which revisions were
> @@ -83,6 +85,7 @@
>         self.parentmap.clear()
>         self.wantedancestors.clear()
>         self.seenchildren.clear()
> +        self.skippedchanges.clear()
>         for rev, wanted, arg in self.convertedorder:
>             if rev not in self.origparents:
>                 self.origparents[rev] = self.getcommit(rev).parents
> @@ -124,12 +127,41 @@
>                 del self.wantedancestors[r]
>                 del self.parentmap[r]
>                 del self.seenchildren[r]
> +                if self.trackingchanges:
> +                    del self.skippedchanges[r]
>                 if self._rebuilt:
>                     del self.children[r]
>
> +    def _trackedchanges(self, rev, parents):
> +        changes = self.base.getchanges(rev)
> +        if not self.trackingchanges or not parents:
> +            return changes
> +
> +        files, copies = set(), {}
> +        # The case of a convergent copy takes care of itself because
> +        # the destination file should be present in the merge node's
> +        # list of changed files
> +        for p in parents:
> +            pf, pc = self.skippedchanges[p]
> +            copies.update(pc)
> +            files.update([(f, rev) for (f, prev) in pf])
> +
> +        cf, cc = changes
> +        copies.update(cc); files.update(cf)
> +
> +        for dest in copies:
> +            if dest in files:
> +                del copies[dest]
> +
> +        return files, copies
> +
> +
>     def mark_not_wanted(self, rev, p):
>         # Mark rev as not interesting and update data structures.
>
> +        if self.trackingchanges:
> +            self.skippedchanges[rev] = self._trackedchanges(rev, p and [p])
> +
>         if p is None:
>             # A root revision. Use SKIPREV to indicate that it doesn't
>             # map to any revision in the restricted graph.  Put SKIPREV
> @@ -145,6 +177,9 @@
>     def mark_wanted(self, rev, parents):
>         # Mark rev ss wanted and update data structures.
>
> +        if self.trackingchanges:
> +            self.skippedchanges[rev] = [], {}
> +
>         # rev will be in the restricted graph, so children of rev in
>         # the original graph should still have rev as a parent in the
>         # restricted graph.
> @@ -158,9 +193,10 @@
>         wrev.add(rev)
>         self.wantedancestors[rev] = wrev
>
> +
>     def getchanges(self, rev):
>         parents = self.commits[rev].parents
> -        if len(parents) > 1:
> +        if len(parents) > 1 or self.trackingchanges:
>             self.rebuild()
>
>         # To decide whether we're interested in rev we:
> @@ -197,6 +233,7 @@
>         self.origparents[rev] = parents
>
>         closed = False
> +
>         if 'close' in self.commits[rev].extra:
>             # A branch closing revision is only useful if one of its
>             # parents belong to the branch being closed
> @@ -221,9 +258,18 @@
>         # Rewrite the parents of the commit object
>         self.commits[rev].parents = mparents
>         self.mark_wanted(rev, parents)
> +
> +        changes = self._trackedchanges(rev, parents)
> +        self._discard(*parents)
>         self.convertedorder.append((rev, True, None))
> -        self._discard(*parents)
> -        return self.base.getchanges(rev)
> +
> +        if not mparents:
> +            # If this is a root node, flatten copies.
> +            files, copies = changes
> +            files = set(files)
> +            files.update([(dest, rev) for dest in copies.keys()])
> +            changes = files, {}
> +        return changes
>
>     def getfile(self, name, rev):
>         return self.base.getfile(name, rev)
> @@ -256,7 +302,11 @@
>
>  class filtermap_source(filtermap_base):
>     def __init__(self, ui, base, inrevs = None, outrevs = None, filemap = None):
> -        super(filtermap_source, self).__init__(ui, base)
> +        # If we filter by revisions (not by files), we need to track
> +        # files that have been created or copied in the revisions we've
> +        # filtered out.
> +        trackchanges = inrevs is not None or outrevs is not None
> +        super(filtermap_source, self).__init__(ui, base, trackchanges)
>         if inrevs:
>             self.inrevs = self.parserevset(inrevs)
>         else:
> diff -r 2d5e44d732e5 -r e86bc97a0a38 tests/test-convert-pickrevs.t
> --- /dev/null   Thu Jan 01 00:00:00 1970 +0000
> +++ b/tests/test-convert-pickrevs.t     Sun Nov 27 00:13:01 2011 -0500
> @@ -0,0 +1,207 @@
> +
> +  $ HGMERGE=true; export HGMERGE
> +  $ echo '[extensions]' >> $HGRCPATH
> +  $ echo 'graphlog =' >> $HGRCPATH
> +  $ echo 'convert =' >> $HGRCPATH
> +  $ glog()
> +  > {
> +  >     hg glog --template '{rev} "{desc}" files: {files}\n' "$@"
> +  > }
> +  $ hg init source
> +  $ cd source
> +  $ echo foo > foo
> +  $ echo baz > baz
> +  $ mkdir -p dir/subdir
> +  $ echo dir/file >> dir/file
> +  $ echo dir/file2 >> dir/file2
> +  $ echo dir/file3 >> dir/file3 # to be corrupted in rev 0
> +  $ echo dir/subdir/file3 >> dir/subdir/file3
> +  $ echo dir/subdir/file4 >> dir/subdir/file4
> +  $ hg ci -d '0 0' -qAm '0: add foo baz dir/'
> +  $ echo bar > bar
> +  $ echo quux > quux
> +  $ echo dir/file4 >> dir/file4 # to be corrupted in rev 1
> +  $ hg copy foo copied
> +  $ hg ci -d '1 0' -qAm '1: add bar quux; copy foo to copied'
> +  $ echo >> foo
> +  $ hg ci -d '2 0' -m '2: change foo'
> +  $ hg up -qC 1
> +  $ echo >> bar
> +  $ echo >> quux
> +  $ hg ci -d '3 0' -m '3: change bar quux'
> +  created new head
> +  $ hg up -qC 2
> +  $ hg merge -qr 3
> +  $ echo >> bar
> +  $ echo >> baz
> +  $ hg ci -d '4 0' -m '4: first merge; change bar baz'
> +  $ echo >> bar
> +  $ echo 1 >> baz
> +  $ echo >> quux
> +  $ hg ci -d '5 0' -m '5: change bar baz quux'
> +  $ hg up -qC 4
> +  $ echo >> foo
> +  $ echo 2 >> baz
> +  $ hg ci -d '6 0' -m '6: change foo baz'
> +  created new head
> +  $ hg up -qC 5
> +  $ hg merge -qr 6
> +  $ echo >> bar
> +  $ hg ci -d '7 0' -m '7: second merge; change bar'
> +  $ echo >> foo
> +  $ hg ci -m '8: change foo'
> +  $ glog
> +  @  8 "8: change foo" files: foo
> +  |
> +  o    7 "7: second merge; change bar" files: bar baz
> +  |\
> +  | o  6 "6: change foo baz" files: baz foo
> +  | |
> +  o |  5 "5: change bar baz quux" files: bar baz quux
> +  |/
> +  o    4 "4: first merge; change bar baz" files: bar baz
> +  |\
> +  | o  3 "3: change bar quux" files: bar quux
> +  | |
> +  o |  2 "2: change foo" files: foo
> +  |/
> +  o  1 "1: add bar quux; copy foo to copied" files: bar copied dir/file4 quux
> +  |
> +  o  0 "0: add foo baz dir/" files: baz dir/file dir/file2 dir/file3 dir/subdir/file3 dir/subdir/file4 foo
> +
> +  $ cd ..
> +  $ cat >>include.revs <<EOF
> +  > 1
> +  > 6
> +  > 8
> +  > EOF
> +  $ hg convert --includerevs include.revs source dest1
> +  initializing destination dest1 repository
> +  scanning source...
> +  sorting...
> +  converting...
> +  8 0: add foo baz dir/
> +  7 1: add bar quux; copy foo to copied
> +  6 2: change foo
> +  5 3: change bar quux
> +  4 4: first merge; change bar baz
> +  3 5: change bar baz quux
> +  2 6: change foo baz
> +  1 7: second merge; change bar
> +  0 8: change foo
> +  $ hg glog -R dest1 --debug
> +  o  changeset:   2:aae4e6787d5247344e528cf6683402253c5f81d3
> +  |  tag:         tip
> +  |  parent:      1:15e417a5c00afbafbf451ac3b909e9b09a5d6c37
> +  |  parent:      -1:0000000000000000000000000000000000000000
> +  |  manifest:    2:3bd158bd8138cde9385fde4ed930f3376bf5881e
> +  |  user:        test
> +  |  date:        Thu Jan 01 00:00:00 1970 +0000
> +  |  files:       bar baz foo
> +  |  extra:       branch=default
> +  |  description:
> +  |  8: change foo
> +  |
> +  |
> +  o  changeset:   1:15e417a5c00afbafbf451ac3b909e9b09a5d6c37
> +  |  parent:      0:505780bbef8a0939a7ebb81b3972241566f73e81
> +  |  parent:      -1:0000000000000000000000000000000000000000
> +  |  manifest:    1:4e1b63e06f1509fa11224e55f7e3b311d9549c95
> +  |  user:        test
> +  |  date:        Thu Jan 01 00:00:06 1970 +0000
> +  |  files:       bar baz foo quux
> +  |  extra:       branch=default
> +  |  description:
> +  |  6: change foo baz
> +  |
> +  |
> +  o  changeset:   0:505780bbef8a0939a7ebb81b3972241566f73e81
> +     parent:      -1:0000000000000000000000000000000000000000
> +     parent:      -1:0000000000000000000000000000000000000000
> +     manifest:    0:32cf238e6cc88a093c3d1d6e0f1ccab71423e3a1
> +     user:        test
> +     date:        Thu Jan 01 00:00:01 1970 +0000
> +     files+:      bar baz copied dir/file dir/file2 dir/file3 dir/file4 dir/subdir/file3 dir/subdir/file4 foo quux
> +     extra:       branch=default
> +     description:
> +     1: add bar quux; copy foo to copied
> +
> +
> +  $ hg up -R dest1; ls dest1
> +  11 files updated, 0 files merged, 0 files removed, 0 files unresolved
> +  bar
> +  baz
> +  copied
> +  dir
> +  foo
> +  quux
> +
> +  $ cat >>exclude.revs <<EOF
> +  > 0
> +  > 2
> +  > 3
> +  > 4
> +  > 5
> +  > 7
> +  > EOF
> +  $ hg convert --excluderevs exclude.revs source dest2
> +  initializing destination dest2 repository
> +  scanning source...
> +  sorting...
> +  converting...
> +  8 0: add foo baz dir/
> +  7 1: add bar quux; copy foo to copied
> +  6 2: change foo
> +  5 3: change bar quux
> +  4 4: first merge; change bar baz
> +  3 5: change bar baz quux
> +  2 6: change foo baz
> +  1 7: second merge; change bar
> +  0 8: change foo
> +  $ hg glog -R dest1 --debug
> +  @  changeset:   2:aae4e6787d5247344e528cf6683402253c5f81d3
> +  |  tag:         tip
> +  |  parent:      1:15e417a5c00afbafbf451ac3b909e9b09a5d6c37
> +  |  parent:      -1:0000000000000000000000000000000000000000
> +  |  manifest:    2:3bd158bd8138cde9385fde4ed930f3376bf5881e
> +  |  user:        test
> +  |  date:        Thu Jan 01 00:00:00 1970 +0000
> +  |  files:       bar baz foo
> +  |  extra:       branch=default
> +  |  description:
> +  |  8: change foo
> +  |
> +  |
> +  o  changeset:   1:15e417a5c00afbafbf451ac3b909e9b09a5d6c37
> +  |  parent:      0:505780bbef8a0939a7ebb81b3972241566f73e81
> +  |  parent:      -1:0000000000000000000000000000000000000000
> +  |  manifest:    1:4e1b63e06f1509fa11224e55f7e3b311d9549c95
> +  |  user:        test
> +  |  date:        Thu Jan 01 00:00:06 1970 +0000
> +  |  files:       bar baz foo quux
> +  |  extra:       branch=default
> +  |  description:
> +  |  6: change foo baz
> +  |
> +  |
> +  o  changeset:   0:505780bbef8a0939a7ebb81b3972241566f73e81
> +     parent:      -1:0000000000000000000000000000000000000000
> +     parent:      -1:0000000000000000000000000000000000000000
> +     manifest:    0:32cf238e6cc88a093c3d1d6e0f1ccab71423e3a1
> +     user:        test
> +     date:        Thu Jan 01 00:00:01 1970 +0000
> +     files+:      bar baz copied dir/file dir/file2 dir/file3 dir/file4 dir/subdir/file3 dir/subdir/file4 foo quux
> +     extra:       branch=default
> +     description:
> +     1: add bar quux; copy foo to copied
> +
> +
> +  $ hg up -R dest2; ls dest2
> +  11 files updated, 0 files merged, 0 files removed, 0 files unresolved
> +  bar
> +  baz
> +  copied
> +  dir
> +  foo
> +  quux
> +
>


More information about the Mercurial-devel mailing list