Skip to content

Commit 530ca19

Browse files
newrengitster
authored andcommitted
fast-export: add --reference-excluded-parents option
git filter-branch has a nifty feature allowing you to rewrite, e.g. just the last 8 commits of a linear history git filter-branch $OPTIONS HEAD~8..HEAD If you try the same with git fast-export, you instead get a history of only 8 commits, with HEAD~7 being rewritten into a root commit. There are two alternatives: 1) Don't use the negative revision specification, and when you're filtering the output to make modifications to the last 8 commits, just be careful to not modify any earlier commits somehow. 2) First run 'git fast-export --export-marks=somefile HEAD~8', then run 'git fast-export --import-marks=somefile HEAD~8..HEAD'. Both are more error prone than I'd like (the first for obvious reasons; with the second option I have sometimes accidentally included too many revisions in the first command and then found that the corresponding extra revisions were not exported by the second command and thus were not modified as I expected). Also, both are poor from a performance perspective. Add a new --reference-excluded-parents option which will cause fast-export to refer to commits outside the specified rev-list-args range by their sha1sum. Such a stream will only be useful in a repository which already contains the necessary commits (much like the restriction imposed when using --no-data). Note from Peff: I think we might be able to do a little more optimization here. If we're exporting HEAD^..HEAD and there's an object in HEAD^ which is unchanged in HEAD, I think we'd still print it (because it would not be marked SHOWN), but we could omit it (by walking the tree of the boundary commits and marking them shown). I don't think it's a blocker for what you're doing here, but just a possible future optimization. Signed-off-by: Elijah Newren <[email protected]> Acked-by: Jeff King <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent fdf31b6 commit 530ca19

File tree

3 files changed

+58
-12
lines changed

3 files changed

+58
-12
lines changed

Documentation/git-fast-export.txt

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,18 @@ marks the same across runs.
110110
the shape of the history and stored tree. See the section on
111111
`ANONYMIZING` below.
112112

113+
--reference-excluded-parents::
114+
By default, running a command such as `git fast-export
115+
master~5..master` will not include the commit master{tilde}5
116+
and will make master{tilde}4 no longer have master{tilde}5 as
117+
a parent (though both the old master{tilde}4 and new
118+
master{tilde}4 will have all the same files). Use
119+
--reference-excluded-parents to instead have the the stream
120+
refer to commits in the excluded range of history by their
121+
sha1sum. Note that the resulting stream can only be used by a
122+
repository which already contains the necessary parent
123+
commits.
124+
113125
--refspec::
114126
Apply the specified refspec to each ref exported. Multiple of them can
115127
be specified.
@@ -119,8 +131,9 @@ marks the same across runs.
119131
'git rev-list', that specifies the specific objects and references
120132
to export. For example, `master~10..master` causes the
121133
current master reference to be exported along with all objects
122-
added since its 10th ancestor commit and all files common to
123-
master{tilde}9 and master{tilde}10.
134+
added since its 10th ancestor commit and (unless the
135+
--reference-excluded-parents option is specified) all files
136+
common to master{tilde}9 and master{tilde}10.
124137

125138
EXAMPLES
126139
--------

builtin/fast-export.c

Lines changed: 32 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ static int fake_missing_tagger;
3737
static int use_done_feature;
3838
static int no_data;
3939
static int full_tree;
40+
static int reference_excluded_commits;
4041
static struct string_list extra_refs = STRING_LIST_INIT_NODUP;
4142
static struct string_list tag_refs = STRING_LIST_INIT_NODUP;
4243
static struct refspec refspecs = REFSPEC_INIT_FETCH;
@@ -597,7 +598,8 @@ static void handle_commit(struct commit *commit, struct rev_info *rev,
597598
message += 2;
598599

599600
if (commit->parents &&
600-
get_object_mark(&commit->parents->item->object) != 0 &&
601+
(get_object_mark(&commit->parents->item->object) != 0 ||
602+
reference_excluded_commits) &&
601603
!full_tree) {
602604
parse_commit_or_die(commit->parents->item);
603605
diff_tree_oid(get_commit_tree_oid(commit->parents->item),
@@ -645,13 +647,21 @@ static void handle_commit(struct commit *commit, struct rev_info *rev,
645647
unuse_commit_buffer(commit, commit_buffer);
646648

647649
for (i = 0, p = commit->parents; p; p = p->next) {
648-
int mark = get_object_mark(&p->item->object);
649-
if (!mark)
650+
struct object *obj = &p->item->object;
651+
int mark = get_object_mark(obj);
652+
653+
if (!mark && !reference_excluded_commits)
650654
continue;
651655
if (i == 0)
652-
printf("from :%d\n", mark);
656+
printf("from ");
657+
else
658+
printf("merge ");
659+
if (mark)
660+
printf(":%d\n", mark);
653661
else
654-
printf("merge :%d\n", mark);
662+
printf("%s\n", oid_to_hex(anonymize ?
663+
anonymize_oid(&obj->oid) :
664+
&obj->oid));
655665
i++;
656666
}
657667

@@ -932,13 +942,22 @@ static void handle_tags_and_duplicates(struct string_list *extras)
932942
/*
933943
* Getting here means we have a commit which
934944
* was excluded by a negative refspec (e.g.
935-
* fast-export ^master master). If the user
945+
* fast-export ^master master). If we are
946+
* referencing excluded commits, set the ref
947+
* to the exact commit. Otherwise, the user
936948
* wants the branch exported but every commit
937-
* in its history to be deleted, that sounds
938-
* like a ref deletion to me.
949+
* in its history to be deleted, which basically
950+
* just means deletion of the ref.
939951
*/
940-
printf("reset %s\nfrom %s\n\n",
941-
name, oid_to_hex(&null_oid));
952+
if (!reference_excluded_commits) {
953+
/* delete the ref */
954+
printf("reset %s\nfrom %s\n\n",
955+
name, oid_to_hex(&null_oid));
956+
continue;
957+
}
958+
/* set ref to commit using oid, not mark */
959+
printf("reset %s\nfrom %s\n\n", name,
960+
oid_to_hex(&commit->object.oid));
942961
continue;
943962
}
944963

@@ -1075,6 +1094,9 @@ int cmd_fast_export(int argc, const char **argv, const char *prefix)
10751094
OPT_STRING_LIST(0, "refspec", &refspecs_list, N_("refspec"),
10761095
N_("Apply refspec to exported refs")),
10771096
OPT_BOOL(0, "anonymize", &anonymize, N_("anonymize output")),
1097+
OPT_BOOL(0, "reference-excluded-parents",
1098+
&reference_excluded_commits, N_("Reference parents which are not in fast-export stream by object id")),
1099+
10781100
OPT_END()
10791101
};
10801102

t/t9350-fast-export.sh

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,17 @@ test_expect_success 'fast-export master~2..master' '
6666
6767
'
6868

69+
test_expect_success 'fast-export --reference-excluded-parents master~2..master' '
70+
71+
git fast-export --reference-excluded-parents master~2..master >actual &&
72+
grep commit.refs/heads/master actual >commit-count &&
73+
test_line_count = 2 commit-count &&
74+
sed "s/master/rewrite/" actual |
75+
(cd new &&
76+
git fast-import &&
77+
test $MASTER = $(git rev-parse --verify refs/heads/rewrite))
78+
'
79+
6980
test_expect_success 'iso-8859-1' '
7081
7182
git config i18n.commitencoding ISO8859-1 &&

0 commit comments

Comments
 (0)