From: newren@gmail.com
To: git@vger.kernel.org
Cc: Johannes.Schindelin@gmx.de, kusambite@gmail.com,
Elijah Newren <newren@gmail.com>
Subject: [PATCH 5/7] fast-export: Add a --tag-of-filtered-object option for newly dangling tags
Date: Fri, 19 Jun 2009 22:37:01 -0600 [thread overview]
Message-ID: <1245472623-28103-6-git-send-email-newren@gmail.com> (raw)
In-Reply-To: <1245472623-28103-1-git-send-email-newren@gmail.com>
From: Elijah Newren <newren@gmail.com>
When providing a list of paths to limit what is exported, the object that
a tag points to can be filtered out entirely. This new switch allows
the user to specify what should happen to the tag in such a case. The
default action, 'abort' will exit with an error message. With 'drop', the
tag will simply be omitted from the output. With 'rewrite', if the object
tagged was a commit, the tag will be modified to tag an ancestor of the
removed commit.
Signed-off-by: Elijah Newren <newren@gmail.com>
---
I had a hard time coming up with a decent option name. If anyone has a
better suggestion for the name, I'm all ears.
To see a case where this bug is triggered, run
git fast-export --signed-tag=strip v1.6.3.2 -- COPYING
in git.git and note that the tag that is output points to 'mark :0' (a
non-existent mark), which will cause fast-import to crash.
Documentation/git-fast-export.txt | 11 ++++++
builtin-fast-export.c | 64 +++++++++++++++++++++++++++++++++---
revision.c | 10 +-----
revision.h | 8 +++++
4 files changed, 79 insertions(+), 14 deletions(-)
diff --git a/Documentation/git-fast-export.txt b/Documentation/git-fast-export.txt
index 0c9eb56..194abde 100644
--- a/Documentation/git-fast-export.txt
+++ b/Documentation/git-fast-export.txt
@@ -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
diff --git a/builtin-fast-export.c b/builtin-fast-export.c
index b60a97e..917ac05 100644
--- a/builtin-fast-export.c
+++ b/builtin-fast-export.c
@@ -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;
@@ -282,13 +297,14 @@ static void handle_tail(struct object_array *commits, struct rev_info *revs)
}
}
-static void handle_tag(const char *name, struct tag *tag)
+static void handle_tag(const char *name, struct tag *tag, struct rev_info *revs)
{
unsigned long size;
enum object_type type;
char *buf;
const char *tagger, *tagger_end, *message;
size_t message_size = 0;
+ struct commit *commit;
buf = read_sha1_file(tag->object.sha1, &type, &size);
if (!buf)
@@ -333,10 +349,42 @@ static void handle_tag(const char *name, struct tag *tag)
}
}
+ /* handle tag->tagged having been filtered out due to paths specified */
+ struct object * tagged = tag->tagged;
+ int tagged_mark = get_object_mark(tagged);
+ if (!tagged_mark) {
+ switch(tag_of_filtered_mode) {
+ case ABORT:
+ die ("Tag %s tags unexported commit; use "
+ "--tag-of-filtered-object=<mode> to handle it.",
+ sha1_to_hex(tag->object.sha1));
+ case DROP:
+ /* Ignore this tag altogether */
+ return;
+ /* fallthru */
+ case REWRITE:
+ if (tagged->type != OBJ_COMMIT) {
+ die ("Tag %s tags unexported commit; use "
+ "--tag-of-filtered-object=<mode> to handle it.",
+ sha1_to_hex(tag->object.sha1));
+ }
+ commit = (struct commit *)tagged;
+ switch (rewrite_one_commit(revs, &commit)) {
+ case rewrite_one_ok:
+ tagged_mark = get_object_mark(&commit->object);
+ break;
+ case rewrite_one_noparents:
+ case rewrite_one_error:
+ die ("Can't find replacement commit for tag %s\n",
+ sha1_to_hex(tag->object.sha1));
+ }
+ }
+ }
+
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 : "");
@@ -399,7 +447,8 @@ static void get_tags_and_duplicates(struct object_array *pending,
}
}
-static void handle_tags_and_duplicates(struct string_list *extra_refs)
+static void handle_tags_and_duplicates(struct string_list *extra_refs,
+ struct rev_info *revs)
{
struct commit *commit;
int i;
@@ -415,7 +464,7 @@ static void handle_tags_and_duplicates(struct string_list *extra_refs)
/* Ignore this tag altogether */
return;
}
- handle_tag(name, tag);
+ handle_tag(name, tag, revs);
break;
case OBJ_COMMIT:
/* create refs pointing to already seen commits */
@@ -504,6 +553,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",
@@ -551,7 +603,7 @@ int cmd_fast_export(int argc, const char **argv, const char *prefix)
}
}
- handle_tags_and_duplicates(&extra_refs);
+ handle_tags_and_duplicates(&extra_refs, &revs);
if (export_filename)
export_marks(export_filename);
diff --git a/revision.c b/revision.c
index bf58448..5ed2841 100644
--- a/revision.c
+++ b/revision.c
@@ -1601,13 +1601,7 @@ int prepare_revision_walk(struct rev_info *revs)
return 0;
}
-enum rewrite_result {
- rewrite_one_ok,
- rewrite_one_noparents,
- rewrite_one_error,
-};
-
-static enum rewrite_result rewrite_one(struct rev_info *revs, struct commit **pp)
+enum rewrite_result rewrite_one_commit(struct rev_info *revs, struct commit **pp)
{
struct commit_list *cache = NULL;
@@ -1633,7 +1627,7 @@ static int rewrite_parents(struct rev_info *revs, struct commit *commit)
struct commit_list **pp = &commit->parents;
while (*pp) {
struct commit_list *parent = *pp;
- switch (rewrite_one(revs, &parent->item)) {
+ switch (rewrite_one_commit(revs, &parent->item)) {
case rewrite_one_ok:
break;
case rewrite_one_noparents:
diff --git a/revision.h b/revision.h
index 227164c..6bf5b9e 100644
--- a/revision.h
+++ b/revision.h
@@ -158,6 +158,14 @@ extern void add_pending_object(struct rev_info *revs, struct object *obj, const
extern void add_head_to_pending(struct rev_info *);
+enum rewrite_result {
+ rewrite_one_ok,
+ rewrite_one_noparents,
+ rewrite_one_error,
+};
+
+extern enum rewrite_result rewrite_one_commit(struct rev_info *revs, struct commit **pp);
+
enum commit_action {
commit_ignore,
commit_show,
--
1.6.3.2.323.gfb84f
next prev parent reply other threads:[~2009-06-20 4:39 UTC|newest]
Thread overview: 14+ messages / expand[flat|nested] mbox.gz Atom feed top
2009-06-20 4:36 A few fast-export fixups newren
2009-06-20 4:36 ` [PATCH 1/7] fast-export: Omit tags that tag trees newren
2009-06-20 17:31 ` Jeff King
2009-06-20 18:01 ` Elijah Newren
2009-06-20 18:52 ` Jeff King
2009-06-20 4:36 ` [PATCH 2/7] Modify fast-export testcase to check that we correctly omit tags of trees newren
2009-06-21 5:53 ` Stephen Boyd
2009-06-21 6:17 ` Johannes Sixt
2009-06-22 13:12 ` Elijah Newren
2009-06-20 4:36 ` [PATCH 3/7] fast-export: Make sure we show actual ref names instead of "(null)" newren
2009-06-20 4:37 ` [PATCH 4/7] fast-export: Do parent rewriting to avoid dropping relevant commits newren
2009-06-20 4:37 ` newren [this message]
2009-06-20 4:37 ` [PATCH 6/7] Add new fast-export testcases newren
2009-06-20 4:37 ` [PATCH 7/7] fast-export: Document the fact that git-rev-list arguments are accepted newren
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1245472623-28103-6-git-send-email-newren@gmail.com \
--to=newren@gmail.com \
--cc=Johannes.Schindelin@gmx.de \
--cc=git@vger.kernel.org \
--cc=kusambite@gmail.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).