builtin/add.c: replace run_command() with direct apply_all_patches() call

When the user runs "git add -e", the diff of the working tree changes is written to a temporary file, opened in an editor, and then applied back to the index. The application step is done by spawning a child process running "git apply --recount --cached <file>", which is an unnecessary subprocess since the apply machinery is available as a native C API. Replace the run_command() call with a direct call to apply_all_patches() using an initialized apply_state with the cached and recount options set appropriately. This avoids the overhead of forking a subprocess, keeps the operation within the same process, and makes the intent of the code clearer to the reader. Remove the now-unused includes of "run-command.h" and "strvec.h" since no other code in this file requires them after this change. Signed-off-by: Gatla Vishweshwar Reddy <gatlavishweshwarreddy26@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Gatla Vishweshwar Reddy committed Jul 11, 2026 at 11:36 UTC d0ee845a718a447cacabecf9610d2e1da6d83330
2 files changed +22 -7
builtin/add.c
+12 -7
@@ -13,7 +13,6 @@
13 #include "dir.h"
14 #include "gettext.h"
15 #include "pathspec.h"
16 -#include "run-command.h"
16 #include "object-file.h"
17 #include "odb.h"
18 #include "odb/transaction.h"
@@ -23,9 +22,9 @@
22 #include "diff.h"
23 #include "read-cache.h"
24 #include "revision.h"
26 -#include "strvec.h"
25 #include "submodule.h"
26 #include "add-interactive.h"
27 +#include "apply.h"
28
29 static const char * const builtin_add_usage[] = {
30 N_("git add [<options>] [--] <pathspec>..."),
@@ -187,7 +186,8 @@ static int edit_patch(struct repository *repo,
186 const char *prefix)
187 {
188 char *file = repo_git_path(repo, "ADD_EDIT.patch");
190 - struct child_process child = CHILD_PROCESS_INIT;
189 + struct apply_state state;
190 + const char *apply_argv[2];
191 struct rev_info rev;
192 int out;
193 struct stat st;
@@ -217,11 +217,16 @@ static int edit_patch(struct repository *repo,
217 if (!st.st_size)
218 die(_("empty patch. aborted"));
219
220 - child.git_cmd = 1;
221 - strvec_pushl(&child.args, "apply", "--recount", "--cached", file,
222 - NULL);
223 - if (run_command(&child))
220 + apply_argv[0] = file;
221 + apply_argv[1] = NULL;
222 + if (init_apply_state(&state, repo, NULL))
223 + die(_("could not initialize apply state"));
224 + state.cached = 1;
225 + if (check_apply_state(&state, 0))
226 + die(_("could not check apply state"));
227 + if (apply_all_patches(&state, 1, apply_argv, APPLY_OPT_RECOUNT))
228 die(_("could not apply '%s'"), file);
229 + clear_apply_state(&state);
230
231 unlink(file);
232 free(file);
t/t3702-add-edit.sh
+10
@@ -124,5 +124,15 @@ test_expect_success 'add -e notices editor failure' '
124 test_must_fail env GIT_EDITOR=false git add -e &&
125 test_expect_code 1 git diff --exit-code
126 '
127 +test_expect_success 'add -e works from a subdirectory' '
128 + git reset --hard &&
129 + echo change >>file &&
130 + mkdir -p subdir &&
131 + (
132 + cd subdir &&
133 + GIT_EDITOR=cat git add -e ../file
134 + ) &&
135 + git diff --cached | grep -q "^+change"
136 +'
137
138 test_done