git/list[1] front-page[2] threads[3] people[4] search[5] about
 

[PATCH 83/83] builtin/am: use apply api in run_apply()

From
Christian Couder <christian.couder@gmail.com>
Date
Apr 24, 2016, 13:39 UTC
Message-ID
<1461505189-16234-4-git-send-email-chriscool@tuxfamily.org>
In-Reply-To
<1461505189-16234-1-git-send-email-chriscool@tuxfamily.org>

This replaces run_apply() implementation with a new one that uses the apply api that has been previously prepared in apply.c and apply.h.

This shoud improve performance a lot in certain cases.

As the previous implementation was creating a new `git apply` process to apply each patch, it could be slow on systems like Windows where it is costly to create new processes.

Also the new `git apply` process had to read the index from disk, and when the process was done the calling process discarded its own index and read back from disk the new index that had been created by the `git apply` process.

This could be very inefficient with big repositories that have big index files, especially when the system decided that it was a good idea to run the `git apply` processes on a different processor core.

Also eliminating index reads enables further performance improvements by using:

`git update-index --split-index`
Signed-off-by: Christian Couder <chriscool@tuxfamily.org>
---
 builtin/am.c | 103 ++++++++++++++++++++++++++++++++++++++++++++++++-----------
 1 file changed, 85 insertions(+), 18 deletions(-)
diff --git a/builtin/am.c b/builtin/am.c
index d003939..85a77d7 100644
--- a/builtin/am.c
+++ b/builtin/am.c
@@ -28,6 +28,7 @@
 #include "rerere.h"
 #include "prompt.h"
 #include "mailinfo.h"
+#include "apply.h"
 
 /**
  * Returns 1 if the file is empty or does not exist, 0 otherwise.
@@ -1522,39 +1523,105 @@ static int parse_mail_rebase(struct am_state *state, const char *mail)
  */
 static int run_apply(const struct am_state *state, const char *index_file)
 {
-	struct child_process cp = CHILD_PROCESS_INIT;
-
-	cp.git_cmd = 1;
-
-	if (index_file)
-		argv_array_pushf(&cp.env_array, "GIT_INDEX_FILE=%s", index_file);
+	struct argv_array apply_paths = ARGV_ARRAY_INIT;
+	struct argv_array apply_opts = ARGV_ARRAY_INIT;
+	struct apply_state apply_state;
+	int save_stdout_fd, save_stderr_fd;
+	int res, opts_left;
+	char *save_index_file;
+
+	struct option am_apply_options[] = {
+		{ OPTION_CALLBACK, 0, "whitespace", &apply_state, N_("action"),
+			N_("detect new or modified lines that have whitespace errors"),
+			0, apply_option_parse_whitespace },
+		{ OPTION_CALLBACK, 0, "ignore-space-change", &apply_state, NULL,
+			N_("ignore changes in whitespace when finding context"),
+			PARSE_OPT_NOARG, apply_option_parse_space_change },
+		{ OPTION_CALLBACK, 0, "ignore-whitespace", &apply_state, NULL,
+			N_("ignore changes in whitespace when finding context"),
+			PARSE_OPT_NOARG, apply_option_parse_space_change },
+		{ OPTION_CALLBACK, 0, "directory", &apply_state, N_("root"),
+			N_("prepend <root> to all filenames"),
+			0, apply_option_parse_directory },
+		{ OPTION_CALLBACK, 0, "exclude", &apply_state, N_("path"),
+			N_("don't apply changes matching the given path"),
+			0, apply_option_parse_exclude },
+		{ OPTION_CALLBACK, 0, "include", &apply_state, N_("path"),
+			N_("apply changes matching the given path"),
+			0, apply_option_parse_include },
+		OPT_INTEGER('C', NULL, &apply_state.p_context,
+				N_("ensure at least <n> lines of context match")),
+		{ OPTION_CALLBACK, 'p', NULL, &apply_state, N_("num"),
+			N_("remove <num> leading slashes from traditional diff paths"),
+			0, apply_option_parse_p },
+		OPT_BOOL(0, "reject", &apply_state.apply_with_reject,
+			N_("leave the rejected hunks in corresponding *.rej files")),
+		OPT_END()
+	};
 
 	/*
 	 * If we are allowed to fall back on 3-way merge, don't give false
 	 * errors during the initial attempt.
 	 */
+
 	if (state->threeway && !index_file) {
-		cp.no_stdout = 1;
-		cp.no_stderr = 1;
+		save_stdout_fd = dup(1);
+		dup_devnull(1);
+		save_stderr_fd = dup(2);
+		dup_devnull(2);
 	}
 
-	argv_array_push(&cp.args, "apply");
+	if (index_file) {
+		save_index_file = get_index_file();
+		set_index_file((char *)index_file);
+	}
 
-	argv_array_pushv(&cp.args, state->git_apply_opts.argv);
+	if (init_apply_state(&apply_state, NULL))
+		die("init_apply_state() failed");
+
+	argv_array_push(&apply_opts, "apply");
+	argv_array_pushv(&apply_opts, state->git_apply_opts.argv);
+
+	opts_left = parse_options(apply_opts.argc, apply_opts.argv,
+				  NULL, am_apply_options, NULL, 0);
+
+	if (opts_left != 0)
+		die("unknown option passed thru to git apply");
 
 	if (index_file)
-		argv_array_push(&cp.args, "--cached");
+		apply_state.cached = 1;
 	else
-		argv_array_push(&cp.args, "--index");
+		apply_state.check_index = 1;
 
-	argv_array_push(&cp.args, am_path(state, "patch"));
+	if (check_apply_state(&apply_state, 0))
+		die("check_apply_state() failed");
 
-	if (run_command(&cp))
-		return -1;
+	argv_array_push(&apply_paths, am_path(state, "patch"));
 
-	/* Reload index as git-apply will have modified it. */
-	discard_cache();
-	read_cache_from(index_file ? index_file : get_index_file());
+	res = apply_all_patches(&apply_state, apply_paths.argc, apply_paths.argv, 0);
+
+	/* Restore stdout and stderr */
+	if (state->threeway && !index_file) {
+		dup2(save_stdout_fd, 1);
+		close(save_stdout_fd);
+		dup2(save_stderr_fd, 2);
+		close(save_stderr_fd);
+	}
+
+	if (index_file)
+		set_index_file(save_index_file);
+
+	argv_array_clear(&apply_paths);
+	argv_array_clear(&apply_opts);
+
+	if (res)
+		return res;
+
+	if (index_file) {
+		/* Reload index as apply_all_patches() will have modified it. */
+		discard_cache();
+		read_cache_from(index_file);
+	}
 
 	return 0;
 }
-- 
2.8.1.300.g5fed0c0
Previous: Christian CouderNext: Johannes Schindelin
Message 10 of 24 in “run-command: make dup_devnull() non static”
  1. 80/83 run-command: make dup_devnull() non staticChristian Couder, Apr 24, 2016
  2. 81/83 apply: roll back index in case of errorChristian Couder, Apr 24, 2016
  3. Johannes SchindelinApr 25, 2016
  4. Johannes SchindelinMay 2, 2016
  5. Eric SunshineMay 2, 2016
  6. Christian CouderMay 3, 2016
  7. 82/83 environment: add set_index_file()Christian Couder, Apr 24, 2016
  8. Junio C HamanoMay 3, 2016
  9. Christian CouderMay 4, 2016
  10. 83/83 builtin/am: use apply api in run_apply()Christian Couder, Apr 24, 2016
  11. Johannes SchindelinApr 25, 2016
  12. Christian CouderMay 5, 2016
  13. Johannes SchindelinApr 25, 2016
  14. Christian CouderMay 5, 2016
  15. Johannes SixtMay 5, 2016
  16. Christian CouderMay 6, 2016
  17. Johannes SchindelinMay 6, 2016
  18. Christian CouderMay 7, 2016
  19. Johannes SchindelinMay 7, 2016
  20. Christian CouderMay 7, 2016
  21. Johannes SchindelinMay 8, 2016
  22. Duy NguyenMay 8, 2016
  23. Johannes SchindelinMay 9, 2016
  24. Junio C HamanoMay 9, 2016

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.