Re: [PATCH RFC 10/11] add-patch: add support for in-memory index patching

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Wed, Aug 20, 2025 at 4:17 AM Patrick Steinhardt <ps@xxxxxx> wrote:
>
> With `run_add_p()` callers have the ability to apply changes from a
> specific revision to a repository's index. This infra supports several
> different modes, like for example applying changes to the index,
> worktree or both.
>
> One feature that is missing though is the ability to apply changes to an
> in-memory index different from the repository's index. Add a new
> function `run_add_p_index()` to plug this gap.
>
> This new function will be used in a subsequent commit.
>
> Signed-off-by: Patrick Steinhardt <ps@xxxxxx>
> ---
>  add-patch.c | 111 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
>  add-patch.h |   8 +++++
>  2 files changed, 116 insertions(+), 3 deletions(-)
>
> diff --git a/add-patch.c b/add-patch.c
> index 1bcbc91de9..adef20c02b 100644
> --- a/add-patch.c
> +++ b/add-patch.c
> @@ -1849,9 +1853,12 @@ static int patch_update_file(struct add_p_state *s,
>                                          NULL, 0, NULL, 0))
>                                 error(_("'git apply' failed"));
>                 }
> -               if (repo_read_index(s->r) >= 0)
> +               read_index_from(s->index, s->index_file, s->r->gitdir);
> +               if (read_index_from(s->index, s->index_file, s->r->gitdir) >= 0 &&
> +                   s->index == s->r->index) {
>                         repo_refresh_and_write_index(s->r, REFRESH_QUIET, 0,
>                                                      1, NULL, NULL, NULL);
> +               }
>         }

Is this call to read_index_from duplicated? I don't see anything that
indicates that would be desirable here.

>
>         putchar('\n');
> @@ -1864,6 +1871,8 @@ int run_add_p(struct repository *r, enum add_p_mode mode,
>  {
>         struct add_p_state s = {
>                 .r = r,
> +               .index = r->index,
> +               .index_file = r->index_file,
>                 .answer = STRBUF_INIT,
>                 .buf = STRBUF_INIT,
>                 .plain = STRBUF_INIT,
> @@ -1922,3 +1931,99 @@ int run_add_p(struct repository *r, enum add_p_mode mode,
>         add_p_state_clear(&s);
>         return 0;
>  }
> +
> +int run_add_p_index(struct repository *r,
> +                   struct index_state *index,
> +                   const char *index_file,
> +                   struct interactive_options *opts,
> +                   const char *revision,
> +                   const struct pathspec *ps)
> +{
> +       struct patch_mode mode = {
> +               .apply_args = { "--cached", NULL },
> +               .apply_check_args = { "--cached", NULL },
> +               .prompt_mode = {
> +                       N_("Stage mode change [y,n,q,a,d%s,?]? "),
> +                       N_("Stage deletion [y,n,q,a,d%s,?]? "),
> +                       N_("Stage addition [y,n,q,a,d%s,?]? "),
> +                       N_("Stage this hunk [y,n,q,a,d%s,?]? ")
> +               },
> +               .edit_hunk_hint = N_("If the patch applies cleanly, the edited hunk "
> +                                    "will immediately be marked for staging."),
> +               .help_patch_text =
> +                       N_("y - stage this hunk\n"
> +                          "n - do not stage this hunk\n"
> +                          "q - quit; do not stage this hunk or any of the remaining "
> +                               "ones\n"
> +                          "a - stage this hunk and all later hunks in the file\n"
> +                          "d - do not stage this hunk or any of the later hunks in "
> +                               "the file\n"),
> +               .index_only = 1,
> +       };
> +       struct add_p_state s = {
> +               .r = r,
> +               .index = index,
> +               .index_file = index_file,
> +               .answer = STRBUF_INIT,
> +               .buf = STRBUF_INIT,
> +               .plain = STRBUF_INIT,
> +               .colored = STRBUF_INIT,
> +               .mode = &mode,
> +               .revision = revision,
> +       };
> +       struct strbuf parent_revision = STRBUF_INIT;
> +       char parent_tree_oid[GIT_MAX_HEXSZ + 1];
> +       size_t binary_count = 0;
> +       struct commit *commit;
> +       int ret;
> +
> +       commit = lookup_commit_reference_by_name(revision);
> +       if (!commit) {
> +               err(&s, _("Revision does not refer to a commit"));
> +               ret = -1;
> +               goto out;
> +       }
> +
> +       if (commit->parents)
> +               oid_to_hex_r(parent_tree_oid, get_commit_tree_oid(commit->parents->item));
> +       else
> +               oid_to_hex_r(parent_tree_oid, r->hash_algo->empty_tree);
> +
> +       strbuf_addf(&parent_revision, "%s~", revision);
> +       mode.diff_cmd[0] = "diff-tree";
> +       mode.diff_cmd[1] = "-r";
> +       mode.diff_cmd[2] = parent_tree_oid;
> +
> +       interactive_config_init(&s.cfg, r, opts);
> +
> +       if (parse_diff(&s, ps) < 0) {

I noticed run_add_p() calls discard_index() right before parse_diff()
[but it also reads/refreshes the index there]. Sounds like that's not
something we need for in-memory indices?

> +               ret = -1;
> +               goto out;
> +       }
> +
> +       for (size_t i = 0; i < s.file_diff_nr; i++) {
> +               if (s.file_diff[i].binary && !s.file_diff[i].hunk_nr)
> +                       binary_count++;
> +               else if (patch_update_file(&s, s.file_diff + i))
> +                       break;
> +       }
> +
> +       if (s.file_diff_nr == 0) {
> +               err(&s, _("No changes."));
> +               ret = -1;
> +               goto out;
> +       }
> +
> +       if (binary_count == s.file_diff_nr) {
> +               err(&s, _("Only binary files changed."));
> +               ret = -1;
> +               goto out;
> +       }
> +
> +       ret = 0;
> +
> +out:
> +       strbuf_release(&parent_revision);
> +       add_p_state_clear(&s);
> +       return ret;
> +}

This single call to add_p_state_clear() is probably easier to follow
than the original in run_add_p(). Nice.

-- 
D. Ben Knoble





[Index of Archives]     [Linux Kernel Development]     [Gcc Help]     [IETF Annouce]     [DCCP]     [Netdev]     [Networking]     [Security]     [V4L]     [Bugtraq]     [Yosemite]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux SCSI]     [Fedora Users]

  Powered by Linux