Re: [PATCH RFC 10/11] add-patch: add support for in-memory index patching
- From
D. Ben Knoble <ben.knoble@gmail.com>
- Date
- Aug 20, 2025, 21:15 UTC
- Message-ID
- <CALnO6CAPugqDC8sGO1Si=5Wk-pz52BF84Ai7ZQjwb3vLMs6A=A@mail.gmail.com>
- In-Reply-To
- <20250819-b4-pks-history-builtin-v1-10-9b77c32688fe@pks.im>
On Wed, Aug 20, 2025 at 4:17 AM Patrick Steinhardt <ps@pks.im> wrote:
Show 34 quoted lines
>
> 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@pks.im>
> ---
> 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.
Show 81 quoted lines
>
> 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?
Show 30 quoted lines
> + 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