Johannes Schindelin <johannes.schinde...@gmx.de> writes:

> This option is intended to help with the transition away from the
> now-deprecated graft file.
>
> Signed-off-by: Johannes Schindelin <johannes.schinde...@gmx.de>
> ---
>  Documentation/git-replace.txt | 11 +++++--
>  builtin/replace.c             | 59 ++++++++++++++++++++++++++++++++++-
>  2 files changed, 66 insertions(+), 4 deletions(-)

I expected you to remove convert-grafts-to-replace-refs.sh from the
contrib/ section in the same patch, actually.  FWIW, I think it is a
much better approach to give the first-class UI for transition like
this patch does than "go fish for a good way to transition yourself,
we may have something useful in contrib/", which is what we had so
far.

> diff --git a/Documentation/git-replace.txt b/Documentation/git-replace.txt
> ...
> @@ -87,9 +88,13 @@ OPTIONS
>       content as <commit> except that its parents will be
>       [<parent>...] instead of <commit>'s parents. A replacement ref
>       is then created to replace <commit> with the newly created
> -     commit. See contrib/convert-grafts-to-replace-refs.sh for an
> -     example script based on this option that can convert grafts to
> -     replace refs.
> +     commit. Use `--convert-graft-file` to convert a
> +     `$GIT_DIR/info/grafts` file use replace refs instead.
> +

Nice.

> diff --git a/builtin/replace.c b/builtin/replace.c
> index 43264f0998e..4cdc00a96df 100644
> --- a/builtin/replace.c
> +++ b/builtin/replace.c
> @@ -20,6 +20,7 @@ static const char * const git_replace_usage[] = {
>       N_("git replace [-f] <object> <replacement>"),
>       N_("git replace [-f] --edit <object>"),
>       N_("git replace [-f] --graft <commit> [<parent>...]"),
> +     N_("git replace [-f] --convert-graft-file"),
>       N_("git replace -d <object>..."),
>       N_("git replace [--format=<format>] [-l [<pattern>]]"),
>       NULL
> @@ -423,6 +424,53 @@ static int create_graft(int argc, const char **argv, int 
> force)
>       return replace_object_oid(old_ref, &old_oid, "replacement", &new_oid, 
> force);
>  }
>  
> +static int convert_graft_file(int force)
> +{
> +     const char *graft_file = get_graft_file();
> +     FILE *fp = fopen_or_warn(graft_file, "r");
> +     struct strbuf buf = STRBUF_INIT, err = STRBUF_INIT;
> +     struct argv_array args = ARGV_ARRAY_INIT;
> +
> +     if (!fp)
> +             return -1;

Returning silently is fine as fopen_or_warn() would have said
something already.  Good.

> +     while (strbuf_getline(&buf, fp) != EOF) {
> +             int i = 0, j;
> +
> +             while (i != buf.len) {
> +                     char save;
> +
> +                     for (j = i; j < buf.len && !isspace(buf.buf[j]); j++)
> +                             ; /* look further */
> +                     save = buf.buf[j];
> +                     buf.buf[j] = '\0';
> +                     argv_array_push(&args, buf.buf + i);
> +                     buf.buf[j] = save;

It's a shame that we do not have a helper that splits the contents
of a strbuf at SP and shove the result into an argv_array(). [*1*]

*1* There is one that splits into an array of strbuf but the point
of splitting is often that these split pieces are the final thing we
want, and placing them in separate strbuf (whose strength is that
contents are easily manipulatable) is pointless.

> +
> +                     while (j < buf.len && isspace(buf.buf[j]))
> +                             j++;
> +                     i = j;

One difference I notice while comparing this with what is done by
contrib/convert-grafts-to-replace-refs.sh is that this does not
skip a line that begins with # or SP.  I offhand do not know what
the point of skipping a line that begins with a SP, but I suspect
that skipping a line that begins with "#" is a desirable thing to
do, because commit.c::read_graft_line() does know that such a line
is a valid comment.

> +             }
> +
> +             if (create_graft(args.argc, args.argv, force))
> +                     strbuf_addf(&err, "\n\t%s", buf.buf);
> +
> +             argv_array_clear(&args);
> +             strbuf_reset(&buf);

Strictly speaking, this reset is redundant, as getline() will always
stuff the line into a fresh buffer (and after the loop there
correctly is a release).

> +     }
> +
> +     strbuf_release(&buf);
> +     argv_array_clear(&args);
> +
> +     if (!err.len)
> +             return unlink_or_warn(graft_file);
> +     warning(_("could not convert the following graft(s):\n%s"), err.buf);
> +     strbuf_release(&err);

commit.c::read_graft_file() seems to ignore a broken graft line and
salvages other lines, and this one follows suit, which is good.

The remaining die() I pointed out in 1/2 can safely be turned into
return error() for this caller (I didn't check for existing callers,
though) and would automatically do the right thing.  The real
consumer of the graft file, commit.c::read_graft_line(), shows an
error when oid cannot be parsed, and the above code, when
create_graft() is updated to return an error instead of dying, would
append the problematic record to buf.buf in the code above.

Looking basically-good modulo minor nits.

Reply via email to