Skip to content

Commit feab68c

Browse files
committed
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
2 parents d8f7be2 + 8af15d2 commit feab68c

File tree

3 files changed

+187
-8
lines changed

3 files changed

+187
-8
lines changed

Documentation/git-fast-export.txt

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,17 @@ when encountering a signed tag. With 'strip', the tags will be made
3636
unsigned, with 'verbatim', they will be silently exported
3737
and with 'warn', they will be exported, but you will see a warning.
3838

39+
--tag-of-filtered-object=(abort|drop|rewrite)::
40+
Specify how to handle tags whose tagged objectis filtered out.
41+
Since revisions and files to export can be limited by path,
42+
tagged objects may be filtered completely.
43+
+
44+
When asking to 'abort' (which is the default), this program will die
45+
when encountering such a tag. With 'drop' it will omit such tags from
46+
the output. With 'rewrite', if the tagged object is a commit, it will
47+
rewrite the tag to tag an ancestor commit (via parent rewriting; see
48+
linkgit:git-rev-list[1])
49+
3950
-M::
4051
-C::
4152
Perform move and/or copy detection, as described in the
@@ -71,6 +82,12 @@ marks the same across runs.
7182
allow that. So fake a tagger to be able to fast-import the
7283
output.
7384

85+
[git-rev-list-args...]::
86+
A list of arguments, acceptable to 'git-rev-parse' and
87+
'git-rev-list', that specifies the specific objects and references
88+
to export. For example, `master\~10..master` causes the
89+
current master reference to be exported along with all objects
90+
added since its 10th ancestor commit.
7491

7592
EXAMPLES
7693
--------

builtin-fast-export.c

Lines changed: 75 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,8 @@ static const char *fast_export_usage[] = {
2323
};
2424

2525
static int progress;
26-
static enum { VERBATIM, WARN, STRIP, ABORT } signed_tag_mode = ABORT;
26+
static enum { ABORT, VERBATIM, WARN, STRIP } signed_tag_mode = ABORT;
27+
static enum { ERROR, DROP, REWRITE } tag_of_filtered_mode = ABORT;
2728
static int fake_missing_tagger;
2829

2930
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,
4243
return 0;
4344
}
4445

46+
static int parse_opt_tag_of_filtered_mode(const struct option *opt,
47+
const char *arg, int unset)
48+
{
49+
if (unset || !strcmp(arg, "abort"))
50+
tag_of_filtered_mode = ABORT;
51+
else if (!strcmp(arg, "drop"))
52+
tag_of_filtered_mode = DROP;
53+
else if (!strcmp(arg, "rewrite"))
54+
tag_of_filtered_mode = REWRITE;
55+
else
56+
return error("Unknown tag-of-filtered mode: %s", arg);
57+
return 0;
58+
}
59+
4560
static struct decoration idnums;
4661
static uint32_t last_idnum;
4762

@@ -289,6 +304,23 @@ static void handle_tag(const char *name, struct tag *tag)
289304
char *buf;
290305
const char *tagger, *tagger_end, *message;
291306
size_t message_size = 0;
307+
struct object *tagged;
308+
int tagged_mark;
309+
struct commit *p;
310+
311+
/* Trees have no identifer in fast-export output, thus we have no way
312+
* to output tags of trees, tags of tags of trees, etc. Simply omit
313+
* such tags.
314+
*/
315+
tagged = tag->tagged;
316+
while (tagged->type == OBJ_TAG) {
317+
tagged = ((struct tag *)tagged)->tagged;
318+
}
319+
if (tagged->type == OBJ_TREE) {
320+
warning("Omitting tag %s,\nsince tags of trees (or tags of tags of trees, etc.) are not supported.",
321+
sha1_to_hex(tag->object.sha1));
322+
return;
323+
}
292324

293325
buf = read_sha1_file(tag->object.sha1, &type, &size);
294326
if (!buf)
@@ -333,10 +365,45 @@ static void handle_tag(const char *name, struct tag *tag)
333365
}
334366
}
335367

368+
/* handle tag->tagged having been filtered out due to paths specified */
369+
tagged = tag->tagged;
370+
tagged_mark = get_object_mark(tagged);
371+
if (!tagged_mark) {
372+
switch(tag_of_filtered_mode) {
373+
case ABORT:
374+
die ("Tag %s tags unexported object; use "
375+
"--tag-of-filtered-object=<mode> to handle it.",
376+
sha1_to_hex(tag->object.sha1));
377+
case DROP:
378+
/* Ignore this tag altogether */
379+
return;
380+
case REWRITE:
381+
if (tagged->type != OBJ_COMMIT) {
382+
die ("Tag %s tags unexported %s!",
383+
sha1_to_hex(tag->object.sha1),
384+
typename(tagged->type));
385+
}
386+
p = (struct commit *)tagged;
387+
for (;;) {
388+
if (p->parents && p->parents->next)
389+
break;
390+
if (p->object.flags & UNINTERESTING)
391+
break;
392+
if (!(p->object.flags & TREESAME))
393+
break;
394+
if (!p->parents)
395+
die ("Can't find replacement commit for tag %s\n",
396+
sha1_to_hex(tag->object.sha1));
397+
p = p->parents->item;
398+
}
399+
tagged_mark = get_object_mark(&p->object);
400+
}
401+
}
402+
336403
if (!prefixcmp(name, "refs/tags/"))
337404
name += 10;
338405
printf("tag %s\nfrom :%d\n%.*s%sdata %d\n%.*s\n",
339-
name, get_object_mark(tag->tagged),
406+
name, tagged_mark,
340407
(int)(tagger_end - tagger), tagger,
341408
tagger == tagger_end ? "" : "\n",
342409
(int)message_size, (int)message_size, message ? message : "");
@@ -504,6 +571,9 @@ int cmd_fast_export(int argc, const char **argv, const char *prefix)
504571
OPT_CALLBACK(0, "signed-tags", &signed_tag_mode, "mode",
505572
"select handling of signed tags",
506573
parse_opt_signed_tag_mode),
574+
OPT_CALLBACK(0, "tag-of-filtered-object", &tag_of_filtered_mode, "mode",
575+
"select handling of tags that tag filtered objects",
576+
parse_opt_tag_of_filtered_mode),
507577
OPT_STRING(0, "export-marks", &export_filename, "FILE",
508578
"Dump marks to this file"),
509579
OPT_STRING(0, "import-marks", &import_filename, "FILE",
@@ -520,6 +590,9 @@ int cmd_fast_export(int argc, const char **argv, const char *prefix)
520590
git_config(git_default_config, NULL);
521591

522592
init_revisions(&revs, prefix);
593+
revs.topo_order = 1;
594+
revs.show_source = 1;
595+
revs.rewrite_parents = 1;
523596
argc = setup_revisions(argc, argv, &revs, NULL);
524597
argc = parse_options(argc, argv, prefix, options, fast_export_usage, 0);
525598
if (argc > 1)
@@ -530,18 +603,13 @@ int cmd_fast_export(int argc, const char **argv, const char *prefix)
530603

531604
get_tags_and_duplicates(&revs.pending, &extra_refs);
532605

533-
revs.topo_order = 1;
534606
if (prepare_revision_walk(&revs))
535607
die("revision walk setup failed");
536608
revs.diffopt.format_callback = show_filemodify;
537609
DIFF_OPT_SET(&revs.diffopt, RECURSIVE);
538610
while ((commit = get_revision(&revs))) {
539611
if (has_unshown_parent(commit)) {
540-
struct commit_list *parent = commit->parents;
541612
add_object_array(&commit->object, NULL, &commits);
542-
for (; parent; parent = parent->next)
543-
if (!parent->item->util)
544-
parent->item->util = commit->util;
545613
}
546614
else {
547615
handle_commit(commit, &revs);

t/t9301-fast-export.sh

Lines changed: 95 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -262,6 +262,94 @@ test_expect_success 'cope with tagger-less tags' '
262262
263263
'
264264

265+
test_expect_success 'setup for limiting exports by PATH' '
266+
mkdir limit-by-paths &&
267+
cd limit-by-paths &&
268+
git init &&
269+
echo hi > there &&
270+
git add there &&
271+
git commit -m "First file" &&
272+
echo foo > bar &&
273+
git add bar &&
274+
git commit -m "Second file" &&
275+
git tag -a -m msg mytag &&
276+
echo morefoo >> bar &&
277+
git add bar &&
278+
git commit -m "Change to second file" &&
279+
cd ..
280+
'
281+
282+
cat > limit-by-paths/expected << EOF
283+
blob
284+
mark :1
285+
data 3
286+
hi
287+
288+
reset refs/tags/mytag
289+
commit refs/tags/mytag
290+
mark :2
291+
author A U Thor <[email protected]> 1112912713 -0700
292+
committer C O Mitter <[email protected]> 1112912713 -0700
293+
data 11
294+
First file
295+
M 100644 :1 there
296+
297+
EOF
298+
299+
test_expect_success 'dropping tag of filtered out object' '
300+
cd limit-by-paths &&
301+
git fast-export --tag-of-filtered-object=drop mytag -- there > output &&
302+
test_cmp output expected &&
303+
cd ..
304+
'
305+
306+
cat >> limit-by-paths/expected << EOF
307+
tag mytag
308+
from :2
309+
tagger C O Mitter <[email protected]> 1112912713 -0700
310+
data 4
311+
msg
312+
313+
EOF
314+
315+
test_expect_success 'rewriting tag of filtered out object' '
316+
cd limit-by-paths &&
317+
git fast-export --tag-of-filtered-object=rewrite mytag -- there > output &&
318+
test_cmp output expected &&
319+
cd ..
320+
'
321+
322+
cat > limit-by-paths/expected << EOF
323+
blob
324+
mark :1
325+
data 4
326+
foo
327+
328+
blob
329+
mark :2
330+
data 3
331+
hi
332+
333+
reset refs/heads/master
334+
commit refs/heads/master
335+
mark :3
336+
author A U Thor <[email protected]> 1112912713 -0700
337+
committer C O Mitter <[email protected]> 1112912713 -0700
338+
data 12
339+
Second file
340+
M 100644 :1 bar
341+
M 100644 :2 there
342+
343+
EOF
344+
345+
test_expect_failure 'no exact-ref revisions included' '
346+
cd limit-by-paths &&
347+
git fast-export master~2..master~1 > output &&
348+
test_cmp output expected &&
349+
cd ..
350+
'
351+
352+
265353
test_expect_success 'set-up a few more tags for tag export tests' '
266354
git checkout -f master &&
267355
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' '
271359
git tag -a tag-obj_tag-obj -m "tagging a tag" tree_tag-obj
272360
'
273361

362+
test_expect_success 'tree_tag' '
363+
mkdir result &&
364+
(cd result && git init) &&
365+
git fast-export tree_tag > fe-stream &&
366+
(cd result && git fast-import < ../fe-stream)
367+
'
368+
274369
# NEEDSWORK: not just check return status, but validate the output
275-
test_expect_success 'tree_tag' 'git fast-export tree_tag'
276370
test_expect_success 'tree_tag-obj' 'git fast-export tree_tag-obj'
277371
test_expect_success 'tag-obj_tag' 'git fast-export tag-obj_tag'
278372
test_expect_success 'tag-obj_tag-obj' 'git fast-export tag-obj_tag-obj'

0 commit comments

Comments
 (0)