Merge branch 'en/fast-export'
* en/fast-export: fast-export: Document the fact that git-rev-list arguments are accepted Add new fast-export testcases fast-export: Add a --tag-of-filtered-object option for newly dangling tags fast-export: Do parent rewriting to avoid dropping relevant commits fast-export: Make sure we show actual ref names instead of "(null)" fast-export: Omit tags that tag trees fast-export: Set revs.topo_order before calling setup_revisions
This commit is contained in:
commit
feab68cd91
@ -36,6 +36,17 @@ when encountering a signed tag. With 'strip', the tags will be made
|
||||
unsigned, with 'verbatim', they will be silently exported
|
||||
and with 'warn', they will be exported, but you will see a warning.
|
||||
|
||||
--tag-of-filtered-object=(abort|drop|rewrite)::
|
||||
Specify how to handle tags whose tagged objectis filtered out.
|
||||
Since revisions and files to export can be limited by path,
|
||||
tagged objects may be filtered completely.
|
||||
+
|
||||
When asking to 'abort' (which is the default), this program will die
|
||||
when encountering such a tag. With 'drop' it will omit such tags from
|
||||
the output. With 'rewrite', if the tagged object is a commit, it will
|
||||
rewrite the tag to tag an ancestor commit (via parent rewriting; see
|
||||
linkgit:git-rev-list[1])
|
||||
|
||||
-M::
|
||||
-C::
|
||||
Perform move and/or copy detection, as described in the
|
||||
@ -71,6 +82,12 @@ marks the same across runs.
|
||||
allow that. So fake a tagger to be able to fast-import the
|
||||
output.
|
||||
|
||||
[git-rev-list-args...]::
|
||||
A list of arguments, acceptable to 'git-rev-parse' and
|
||||
'git-rev-list', that specifies the specific objects and references
|
||||
to export. For example, `master\~10..master` causes the
|
||||
current master reference to be exported along with all objects
|
||||
added since its 10th ancestor commit.
|
||||
|
||||
EXAMPLES
|
||||
--------
|
||||
|
@ -23,7 +23,8 @@ static const char *fast_export_usage[] = {
|
||||
};
|
||||
|
||||
static int progress;
|
||||
static enum { VERBATIM, WARN, STRIP, ABORT } signed_tag_mode = ABORT;
|
||||
static enum { ABORT, VERBATIM, WARN, STRIP } signed_tag_mode = ABORT;
|
||||
static enum { ERROR, DROP, REWRITE } tag_of_filtered_mode = ABORT;
|
||||
static int fake_missing_tagger;
|
||||
|
||||
static int parse_opt_signed_tag_mode(const struct option *opt,
|
||||
@ -42,6 +43,20 @@ static int parse_opt_signed_tag_mode(const struct option *opt,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int parse_opt_tag_of_filtered_mode(const struct option *opt,
|
||||
const char *arg, int unset)
|
||||
{
|
||||
if (unset || !strcmp(arg, "abort"))
|
||||
tag_of_filtered_mode = ABORT;
|
||||
else if (!strcmp(arg, "drop"))
|
||||
tag_of_filtered_mode = DROP;
|
||||
else if (!strcmp(arg, "rewrite"))
|
||||
tag_of_filtered_mode = REWRITE;
|
||||
else
|
||||
return error("Unknown tag-of-filtered mode: %s", arg);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct decoration idnums;
|
||||
static uint32_t last_idnum;
|
||||
|
||||
@ -289,6 +304,23 @@ static void handle_tag(const char *name, struct tag *tag)
|
||||
char *buf;
|
||||
const char *tagger, *tagger_end, *message;
|
||||
size_t message_size = 0;
|
||||
struct object *tagged;
|
||||
int tagged_mark;
|
||||
struct commit *p;
|
||||
|
||||
/* Trees have no identifer in fast-export output, thus we have no way
|
||||
* to output tags of trees, tags of tags of trees, etc. Simply omit
|
||||
* such tags.
|
||||
*/
|
||||
tagged = tag->tagged;
|
||||
while (tagged->type == OBJ_TAG) {
|
||||
tagged = ((struct tag *)tagged)->tagged;
|
||||
}
|
||||
if (tagged->type == OBJ_TREE) {
|
||||
warning("Omitting tag %s,\nsince tags of trees (or tags of tags of trees, etc.) are not supported.",
|
||||
sha1_to_hex(tag->object.sha1));
|
||||
return;
|
||||
}
|
||||
|
||||
buf = read_sha1_file(tag->object.sha1, &type, &size);
|
||||
if (!buf)
|
||||
@ -333,10 +365,45 @@ static void handle_tag(const char *name, struct tag *tag)
|
||||
}
|
||||
}
|
||||
|
||||
/* handle tag->tagged having been filtered out due to paths specified */
|
||||
tagged = tag->tagged;
|
||||
tagged_mark = get_object_mark(tagged);
|
||||
if (!tagged_mark) {
|
||||
switch(tag_of_filtered_mode) {
|
||||
case ABORT:
|
||||
die ("Tag %s tags unexported object; use "
|
||||
"--tag-of-filtered-object=<mode> to handle it.",
|
||||
sha1_to_hex(tag->object.sha1));
|
||||
case DROP:
|
||||
/* Ignore this tag altogether */
|
||||
return;
|
||||
case REWRITE:
|
||||
if (tagged->type != OBJ_COMMIT) {
|
||||
die ("Tag %s tags unexported %s!",
|
||||
sha1_to_hex(tag->object.sha1),
|
||||
typename(tagged->type));
|
||||
}
|
||||
p = (struct commit *)tagged;
|
||||
for (;;) {
|
||||
if (p->parents && p->parents->next)
|
||||
break;
|
||||
if (p->object.flags & UNINTERESTING)
|
||||
break;
|
||||
if (!(p->object.flags & TREESAME))
|
||||
break;
|
||||
if (!p->parents)
|
||||
die ("Can't find replacement commit for tag %s\n",
|
||||
sha1_to_hex(tag->object.sha1));
|
||||
p = p->parents->item;
|
||||
}
|
||||
tagged_mark = get_object_mark(&p->object);
|
||||
}
|
||||
}
|
||||
|
||||
if (!prefixcmp(name, "refs/tags/"))
|
||||
name += 10;
|
||||
printf("tag %s\nfrom :%d\n%.*s%sdata %d\n%.*s\n",
|
||||
name, get_object_mark(tag->tagged),
|
||||
name, tagged_mark,
|
||||
(int)(tagger_end - tagger), tagger,
|
||||
tagger == tagger_end ? "" : "\n",
|
||||
(int)message_size, (int)message_size, message ? message : "");
|
||||
@ -504,6 +571,9 @@ int cmd_fast_export(int argc, const char **argv, const char *prefix)
|
||||
OPT_CALLBACK(0, "signed-tags", &signed_tag_mode, "mode",
|
||||
"select handling of signed tags",
|
||||
parse_opt_signed_tag_mode),
|
||||
OPT_CALLBACK(0, "tag-of-filtered-object", &tag_of_filtered_mode, "mode",
|
||||
"select handling of tags that tag filtered objects",
|
||||
parse_opt_tag_of_filtered_mode),
|
||||
OPT_STRING(0, "export-marks", &export_filename, "FILE",
|
||||
"Dump marks to this file"),
|
||||
OPT_STRING(0, "import-marks", &import_filename, "FILE",
|
||||
@ -520,6 +590,9 @@ int cmd_fast_export(int argc, const char **argv, const char *prefix)
|
||||
git_config(git_default_config, NULL);
|
||||
|
||||
init_revisions(&revs, prefix);
|
||||
revs.topo_order = 1;
|
||||
revs.show_source = 1;
|
||||
revs.rewrite_parents = 1;
|
||||
argc = setup_revisions(argc, argv, &revs, NULL);
|
||||
argc = parse_options(argc, argv, prefix, options, fast_export_usage, 0);
|
||||
if (argc > 1)
|
||||
@ -530,18 +603,13 @@ int cmd_fast_export(int argc, const char **argv, const char *prefix)
|
||||
|
||||
get_tags_and_duplicates(&revs.pending, &extra_refs);
|
||||
|
||||
revs.topo_order = 1;
|
||||
if (prepare_revision_walk(&revs))
|
||||
die("revision walk setup failed");
|
||||
revs.diffopt.format_callback = show_filemodify;
|
||||
DIFF_OPT_SET(&revs.diffopt, RECURSIVE);
|
||||
while ((commit = get_revision(&revs))) {
|
||||
if (has_unshown_parent(commit)) {
|
||||
struct commit_list *parent = commit->parents;
|
||||
add_object_array(&commit->object, NULL, &commits);
|
||||
for (; parent; parent = parent->next)
|
||||
if (!parent->item->util)
|
||||
parent->item->util = commit->util;
|
||||
}
|
||||
else {
|
||||
handle_commit(commit, &revs);
|
||||
|
@ -262,6 +262,94 @@ test_expect_success 'cope with tagger-less tags' '
|
||||
|
||||
'
|
||||
|
||||
test_expect_success 'setup for limiting exports by PATH' '
|
||||
mkdir limit-by-paths &&
|
||||
cd limit-by-paths &&
|
||||
git init &&
|
||||
echo hi > there &&
|
||||
git add there &&
|
||||
git commit -m "First file" &&
|
||||
echo foo > bar &&
|
||||
git add bar &&
|
||||
git commit -m "Second file" &&
|
||||
git tag -a -m msg mytag &&
|
||||
echo morefoo >> bar &&
|
||||
git add bar &&
|
||||
git commit -m "Change to second file" &&
|
||||
cd ..
|
||||
'
|
||||
|
||||
cat > limit-by-paths/expected << EOF
|
||||
blob
|
||||
mark :1
|
||||
data 3
|
||||
hi
|
||||
|
||||
reset refs/tags/mytag
|
||||
commit refs/tags/mytag
|
||||
mark :2
|
||||
author A U Thor <author@example.com> 1112912713 -0700
|
||||
committer C O Mitter <committer@example.com> 1112912713 -0700
|
||||
data 11
|
||||
First file
|
||||
M 100644 :1 there
|
||||
|
||||
EOF
|
||||
|
||||
test_expect_success 'dropping tag of filtered out object' '
|
||||
cd limit-by-paths &&
|
||||
git fast-export --tag-of-filtered-object=drop mytag -- there > output &&
|
||||
test_cmp output expected &&
|
||||
cd ..
|
||||
'
|
||||
|
||||
cat >> limit-by-paths/expected << EOF
|
||||
tag mytag
|
||||
from :2
|
||||
tagger C O Mitter <committer@example.com> 1112912713 -0700
|
||||
data 4
|
||||
msg
|
||||
|
||||
EOF
|
||||
|
||||
test_expect_success 'rewriting tag of filtered out object' '
|
||||
cd limit-by-paths &&
|
||||
git fast-export --tag-of-filtered-object=rewrite mytag -- there > output &&
|
||||
test_cmp output expected &&
|
||||
cd ..
|
||||
'
|
||||
|
||||
cat > limit-by-paths/expected << EOF
|
||||
blob
|
||||
mark :1
|
||||
data 4
|
||||
foo
|
||||
|
||||
blob
|
||||
mark :2
|
||||
data 3
|
||||
hi
|
||||
|
||||
reset refs/heads/master
|
||||
commit refs/heads/master
|
||||
mark :3
|
||||
author A U Thor <author@example.com> 1112912713 -0700
|
||||
committer C O Mitter <committer@example.com> 1112912713 -0700
|
||||
data 12
|
||||
Second file
|
||||
M 100644 :1 bar
|
||||
M 100644 :2 there
|
||||
|
||||
EOF
|
||||
|
||||
test_expect_failure 'no exact-ref revisions included' '
|
||||
cd limit-by-paths &&
|
||||
git fast-export master~2..master~1 > output &&
|
||||
test_cmp output expected &&
|
||||
cd ..
|
||||
'
|
||||
|
||||
|
||||
test_expect_success 'set-up a few more tags for tag export tests' '
|
||||
git checkout -f master &&
|
||||
HEAD_TREE=`git show -s --pretty=raw HEAD | grep tree | sed "s/tree //"` &&
|
||||
@ -271,8 +359,14 @@ test_expect_success 'set-up a few more tags for tag export tests' '
|
||||
git tag -a tag-obj_tag-obj -m "tagging a tag" tree_tag-obj
|
||||
'
|
||||
|
||||
test_expect_success 'tree_tag' '
|
||||
mkdir result &&
|
||||
(cd result && git init) &&
|
||||
git fast-export tree_tag > fe-stream &&
|
||||
(cd result && git fast-import < ../fe-stream)
|
||||
'
|
||||
|
||||
# NEEDSWORK: not just check return status, but validate the output
|
||||
test_expect_success 'tree_tag' 'git fast-export tree_tag'
|
||||
test_expect_success 'tree_tag-obj' 'git fast-export tree_tag-obj'
|
||||
test_expect_success 'tag-obj_tag' 'git fast-export tag-obj_tag'
|
||||
test_expect_success 'tag-obj_tag-obj' 'git fast-export tag-obj_tag-obj'
|
||||
|
Loading…
Reference in New Issue
Block a user