summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJelmer Vernooij <jelmer@samba.org>2011-11-23 18:48:46 +0100
committerJelmer Vernooij <jelmer@samba.org>2011-11-23 18:48:46 +0100
commit7186c973f844be36efcfa887191593e25def5080 (patch)
tree64eb032ab8def91364fb8b33aa33b1c83ae6de40
parente4e439b7bba4b6e26bfd2cc4904242ea120aace5 (diff)
parent61bee05055314ea1de0788228da7c7c96cd2ef66 (diff)
downloadbzr-fastimport-7186c973f844be36efcfa887191593e25def5080.tar.gz
Merge support for --baseline option to 'bzr export'.
-rw-r--r--NEWS2
-rw-r--r--cmds.py18
-rw-r--r--exporter.py20
-rw-r--r--tests/test_commands.py74
4 files changed, 111 insertions, 3 deletions
diff --git a/NEWS b/NEWS
index 32c469a..2e703a9 100644
--- a/NEWS
+++ b/NEWS
@@ -20,6 +20,8 @@ Features
* New option --dont-squash-empty-commits for 'bzr fast-import-filter'.
(Alex Usov, #877303)
+* Add --baseline option to ``bzr export``. (Andy Grimm, #893382)
+
0.11 2011-08-22
Bug fixes
diff --git a/cmds.py b/cmds.py
index 7e20a1d..157c9b2 100644
--- a/cmds.py
+++ b/cmds.py
@@ -606,6 +606,16 @@ class cmd_fast_export(Command):
unsupported in git with an underscore instead, specify
--rewrite-tag-names.
+ :History truncation:
+
+ When code has been significantly refactored over time (e.g., to separate
+ proprietary code from open source code), it is sometimes convenient to
+ simply truncate the revision history at a certain point. The --baseline
+ option, to be used in conjunction with -r, emits a baseline commit
+ containing the state of the entire source tree at the first requested
+ revision. This allows a user to produce a tree identical to the original
+ without munging multiple exports.
+
:Examples:
To produce data destined for import into Bazaar::
@@ -656,12 +666,16 @@ class cmd_fast_export(Command):
help="Replace characters invalid in git with '_'"
" (plain mode only).",
),
+ Option('baseline',
+ help="Export an 'absolute' baseline commit prior to"
+ "the first relative commit",
+ ),
]
encoding_type = 'exact'
def run(self, source, destination=None, verbose=False,
git_branch="master", checkpoint=10000, marks=None,
import_marks=None, export_marks=None, revision=None,
- plain=True, rewrite_tag_names=False):
+ plain=True, rewrite_tag_names=False, baseline=False):
load_fastimport()
from bzrlib.branch import Branch
from bzrlib.plugins.fastimport import exporter
@@ -676,7 +690,7 @@ class cmd_fast_export(Command):
outf=outf, git_branch=git_branch, checkpoint=checkpoint,
import_marks_file=import_marks, export_marks_file=export_marks,
revision=revision, verbose=verbose, plain_format=plain,
- rewrite_tags=rewrite_tag_names)
+ rewrite_tags=rewrite_tag_names, baseline=baseline)
return exporter.run()
diff --git a/exporter.py b/exporter.py
index e4b5132..2094ff5 100644
--- a/exporter.py
+++ b/exporter.py
@@ -148,7 +148,8 @@ class BzrFastExporter(object):
def __init__(self, source, outf, git_branch=None, checkpoint=-1,
import_marks_file=None, export_marks_file=None, revision=None,
- verbose=False, plain_format=False, rewrite_tags=False):
+ verbose=False, plain_format=False, rewrite_tags=False,
+ baseline=False):
"""Export branch data in fast import format.
:param plain_format: if True, 'classic' fast-import format is
@@ -170,6 +171,7 @@ class BzrFastExporter(object):
self.excluded_revisions = set()
self.plain_format = plain_format
self.rewrite_tags = rewrite_tags
+ self.baseline = baseline
self._multi_author_api_available = hasattr(bzrlib.revision.Revision,
'get_apparent_authors')
self.properties_to_exclude = ['authors', 'author']
@@ -213,6 +215,10 @@ class BzrFastExporter(object):
self.note("Calculating the revisions to exclude ...")
self.excluded_revisions = set([rev_id for rev_id, _, _, _ in
self.branch.iter_merge_sorted_revisions(start_rev_id)])
+ if self.baseline:
+ # needed so the first relative commit knows its parent
+ self.excluded_revisions.remove(start_rev_id)
+ view_revisions.insert(0, start_rev_id)
return list(view_revisions)
def run(self):
@@ -225,6 +231,8 @@ class BzrFastExporter(object):
self._commit_total)
if not self.plain_format:
self.emit_features()
+ if self.baseline:
+ self.emit_baseline(interesting.pop(0), self.git_branch)
for revid in interesting:
self.emit_commit(revid, self.git_branch)
if self.branch.supports_tags():
@@ -302,6 +310,16 @@ class BzrFastExporter(object):
for feature in sorted(commands.FEATURE_NAMES):
self.print_cmd(commands.FeatureCommand(feature))
+ def emit_baseline(self, revid, git_branch):
+ # Emit a full source tree of the first commit's parent
+ git_ref = 'refs/heads/%s' % (git_branch,)
+ revobj = self.branch.repository.get_revision(revid)
+ mark = 1
+ self.revid_to_mark[revid] = mark
+ file_cmds = self._get_filecommands(bzrlib.revision.NULL_REVISION, revid)
+ self.print_cmd(self._get_commit_command(git_ref, mark, revobj,
+ file_cmds))
+
def emit_commit(self, revid, git_branch):
if revid in self.revid_to_mark or revid in self.excluded_revisions:
return
diff --git a/tests/test_commands.py b/tests/test_commands.py
index 5729660..5053416 100644
--- a/tests/test_commands.py
+++ b/tests/test_commands.py
@@ -16,6 +16,7 @@
"""Test the command implementations."""
import os
+import re
import tempfile
import gzip
@@ -58,6 +59,40 @@ class TestSourceStream(tests.TestCase):
self.assertIsNot("bla", stream.read())
+fast_export_baseline_data = """commit refs/heads/master
+mark :1
+committer
+data 15
+add c, remove b
+M 644 inline a
+data 13
+test 1
+test 3
+M 644 inline c
+data 6
+test 4
+commit refs/heads/master
+mark :2
+committer
+data 14
+modify a again
+from :1
+M 644 inline a
+data 20
+test 1
+test 3
+test 5
+commit refs/heads/master
+mark :3
+committer
+data 5
+add d
+from :2
+M 644 inline d
+data 6
+test 6
+"""
+
class TestFastExport(ExternalBase):
def test_empty(self):
@@ -99,6 +134,45 @@ class TestFastExport(ExternalBase):
# "bad Tag" should be exported as bad_Tag
self.assertNotEqual(-1, data.find("reset refs/tags/bad_Tag"))
+ def test_baseline_option(self):
+ tree = self.make_branch_and_tree("bl")
+
+ # Revision 1
+ file('bl/a', 'w').write('test 1')
+ tree.add('a')
+ tree.commit(message='add a')
+
+ # Revision 2
+ file('bl/b', 'w').write('test 2')
+ file('bl/a', 'a').write('\ntest 3')
+ tree.add('b')
+ tree.commit(message='add b, modify a')
+
+ # Revision 3
+ file('bl/c', 'w').write('test 4')
+ tree.add('c')
+ tree.remove('b')
+ tree.commit(message='add c, remove b')
+
+ # Revision 4
+ file('bl/a', 'a').write('\ntest 5')
+ tree.commit(message='modify a again')
+
+ # Revision 5
+ file('bl/d', 'w').write('test 6')
+ tree.add('d')
+ tree.commit(message='add d')
+
+ # This exports the baseline state at Revision 3,
+ # followed by the deltas for 4 and 5
+ data = self.run_bzr("fast-export --baseline -r 3.. bl")[0]
+ data = re.sub('committer.*', 'committer', data)
+ self.assertEquals(fast_export_baseline_data, data)
+
+ # Also confirm that --baseline with no args is identical to full export
+ data1 = self.run_bzr("fast-export --baseline bl")[0]
+ data2 = self.run_bzr("fast-export bl")[0]
+ self.assertEquals(data1, data2)
simple_fast_import_stream = """commit refs/heads/master
mark :1