Subject: [PATCH] gc: reject if another gc is running, unless --force is given

From: Nguyễn Thái Ngọc Duy <[email-masked]>
Date: Sat, 3 Aug 2013 11:20:05 +0700

This may happen when `git gc --auto` is run automatically, then the
user, to avoid wait time, switches to a new terminal, keeps working
and `git gc --auto` is started again because the first gc instance has
not clean up the repository.

Signed-off-by: Nguyễn Thái Ngọc Duy <[email-masked]>
---
 I don't know if the kill(pid, 0) trick works on Windows..

 Documentation/git-gc.txt |  6 +++++-
 builtin/gc.c             | 18 ++++++++++++++++++
 2 files changed, 23 insertions(+), 1 deletion(-)

diff --git a/Documentation/git-gc.txt b/Documentation/git-gc.txt
index 2402ed6..e158a3b 100644
--- a/Documentation/git-gc.txt
+++ b/Documentation/git-gc.txt
@@ -9,7 +9,7 @@ git-gc - Cleanup unnecessary files and optimize the local repository
 SYNOPSIS
 --------
 [verse]
-'git gc' [--aggressive] [--auto] [--quiet] [--prune=<date> | --no-prune]
+'git gc' [--aggressive] [--auto] [--quiet] [--prune=<date> | --no-prune] [--force]
 
 DESCRIPTION
 -----------
@@ -72,6 +72,10 @@ automatic consolidation of packs.
 --quiet::
 	Suppress all progress reports.
 
+--force::
+	Force `git gc` to run even if there may be another `git gc`
+	instance running on this repository.
+
 Configuration
 -------------
 
diff --git a/builtin/gc.c b/builtin/gc.c
index 6be6c8d..07c566c 100644
--- a/builtin/gc.c
+++ b/builtin/gc.c
@@ -169,9 +169,11 @@ static int need_to_gc(void)
 
 int cmd_gc(int argc, const char **argv, const char *prefix)
 {
+	FILE *fp;
 	int aggressive = 0;
 	int auto_gc = 0;
 	int quiet = 0;
+	int force = 0;
 
 	struct option builtin_gc_options[] = {
 		OPT__QUIET(&quiet, N_("suppress progress reporting")),
@@ -180,6 +182,7 @@ int cmd_gc(int argc, const char **argv, const char *prefix)
 			PARSE_OPT_OPTARG, NULL, (intptr_t)prune_expire },
 		OPT_BOOLEAN(0, "aggressive", &aggressive, N_("be more thorough (increased runtime)")),
 		OPT_BOOLEAN(0, "auto", &auto_gc, N_("enable auto-gc mode")),
+		OPT_BOOL(0, "force", &force, N_("force running gc even if there may be another gc running")),
 		OPT_END()
 	};
 
@@ -225,6 +228,21 @@ int cmd_gc(int argc, const char **argv, const char *prefix)
 	} else
 		add_repack_all_option();
 
+	if (!force && (fp = fopen(git_path("gc.pid"), "r")) != NULL) {
+		uintmax_t pid;
+		if (fscanf(fp, "%"PRIuMAX, &pid) == 1 && !kill(pid, 0)) {
+			if (auto_gc)
+				return 0; /* be quiet on --auto */
+			die(_("gc is already running"));
+		}
+		fclose(fp);
+	}
+
+	if ((fp = fopen(git_path("gc.pid"), "w")) != NULL) {
+		fprintf(fp, "%"PRIuMAX"\n", (uintmax_t) getpid());
+		fclose(fp);
+	}
+
 	if (pack_refs && run_command_v_opt(pack_refs_cmd.argv, RUN_GIT_CMD))
 		return error(FAILED_RUN, pack_refs_cmd.argv[0]);
 
-- 
1.8.2.83.gc99314b