James Bowes | 6757ada | 2007-03-13 21:58:22 -0400 | [diff] [blame] | 1 | /* |
| 2 | * git gc builtin command |
| 3 | * |
| 4 | * Cleanup unreachable files and optimize the repository. |
| 5 | * |
| 6 | * Copyright (c) 2007 James Bowes |
| 7 | * |
| 8 | * Based on git-gc.sh, which is |
| 9 | * |
| 10 | * Copyright (c) 2006 Shawn O. Pearce |
| 11 | */ |
| 12 | |
Peter Hagervall | baffc0e | 2007-07-15 01:14:45 +0200 | [diff] [blame] | 13 | #include "builtin.h" |
Brandon Williams | b2141fc | 2017-06-14 11:07:36 -0700 | [diff] [blame] | 14 | #include "config.h" |
Michael Haggerty | ebebeae | 2015-08-10 11:47:49 +0200 | [diff] [blame] | 15 | #include "tempfile.h" |
Michael Haggerty | 697cc8e | 2014-10-01 12:28:42 +0200 | [diff] [blame] | 16 | #include "lockfile.h" |
James Bowes | 44c637c | 2007-11-01 21:02:27 -0400 | [diff] [blame] | 17 | #include "parse-options.h" |
James Bowes | 6757ada | 2007-03-13 21:58:22 -0400 | [diff] [blame] | 18 | #include "run-command.h" |
Jonathan Nieder | 4c5baf0 | 2013-10-16 16:11:46 -0700 | [diff] [blame] | 19 | #include "sigchain.h" |
Jeff King | 234587f | 2012-04-18 14:10:19 -0700 | [diff] [blame] | 20 | #include "argv-array.h" |
Nguyễn Thái Ngọc Duy | eab3296 | 2013-12-05 20:02:54 +0700 | [diff] [blame] | 21 | #include "commit.h" |
Jonathan Tan | 0abe14f | 2017-08-18 15:20:26 -0700 | [diff] [blame] | 22 | #include "packfile.h" |
James Bowes | 6757ada | 2007-03-13 21:58:22 -0400 | [diff] [blame] | 23 | |
| 24 | #define FAILED_RUN "failed to run %s" |
| 25 | |
James Bowes | 44c637c | 2007-11-01 21:02:27 -0400 | [diff] [blame] | 26 | static const char * const builtin_gc_usage[] = { |
Alex Henrie | 9c9b4f2 | 2015-01-13 00:44:47 -0700 | [diff] [blame] | 27 | N_("git gc [<options>]"), |
James Bowes | 44c637c | 2007-11-01 21:02:27 -0400 | [diff] [blame] | 28 | NULL |
| 29 | }; |
James Bowes | 6757ada | 2007-03-13 21:58:22 -0400 | [diff] [blame] | 30 | |
Linus Torvalds | 5675239 | 2007-05-24 11:41:39 -0700 | [diff] [blame] | 31 | static int pack_refs = 1; |
Nguyễn Thái Ngọc Duy | 62aad18 | 2014-05-25 07:38:29 +0700 | [diff] [blame] | 32 | static int prune_reflogs = 1; |
Jeff King | 07e7dbf | 2016-08-11 12:13:09 -0400 | [diff] [blame] | 33 | static int aggressive_depth = 50; |
Johannes Schindelin | 1c192f3 | 2007-12-06 12:03:38 +0000 | [diff] [blame] | 34 | static int aggressive_window = 250; |
Junio C Hamano | 2c3c439 | 2007-09-05 13:01:37 -0700 | [diff] [blame] | 35 | static int gc_auto_threshold = 6700; |
Junio C Hamano | 9706397 | 2008-03-23 00:04:48 -0700 | [diff] [blame] | 36 | static int gc_auto_pack_limit = 50; |
Nguyễn Thái Ngọc Duy | 9f673f9 | 2014-02-08 14:08:52 +0700 | [diff] [blame] | 37 | static int detach_auto = 1; |
Johannes Schindelin | dddbad7 | 2017-04-26 21:29:31 +0200 | [diff] [blame] | 38 | static timestamp_t gc_log_expire_time; |
David Turner | a831c06 | 2017-02-10 16:28:22 -0500 | [diff] [blame] | 39 | static const char *gc_log_expire = "1.day.ago"; |
David Bryson | d3154b4 | 2008-09-30 13:28:58 -0700 | [diff] [blame] | 40 | static const char *prune_expire = "2.weeks.ago"; |
Nguyễn Thái Ngọc Duy | e3df33b | 2014-11-30 15:24:53 +0700 | [diff] [blame] | 41 | static const char *prune_worktrees_expire = "3.months.ago"; |
James Bowes | 6757ada | 2007-03-13 21:58:22 -0400 | [diff] [blame] | 42 | |
Jeff King | 234587f | 2012-04-18 14:10:19 -0700 | [diff] [blame] | 43 | static struct argv_array pack_refs_cmd = ARGV_ARRAY_INIT; |
| 44 | static struct argv_array reflog = ARGV_ARRAY_INIT; |
| 45 | static struct argv_array repack = ARGV_ARRAY_INIT; |
| 46 | static struct argv_array prune = ARGV_ARRAY_INIT; |
Nguyễn Thái Ngọc Duy | e3df33b | 2014-11-30 15:24:53 +0700 | [diff] [blame] | 47 | static struct argv_array prune_worktrees = ARGV_ARRAY_INIT; |
Jeff King | 234587f | 2012-04-18 14:10:19 -0700 | [diff] [blame] | 48 | static struct argv_array rerere = ARGV_ARRAY_INIT; |
James Bowes | 6757ada | 2007-03-13 21:58:22 -0400 | [diff] [blame] | 49 | |
Jeff King | 076aa2c | 2017-09-05 08:15:08 -0400 | [diff] [blame] | 50 | static struct tempfile *pidfile; |
Nguyễn Thái Ngọc Duy | 329e6e8 | 2015-09-19 12:13:23 +0700 | [diff] [blame] | 51 | static struct lock_file log_lock; |
Jonathan Nieder | 4c5baf0 | 2013-10-16 16:11:46 -0700 | [diff] [blame] | 52 | |
Doug Kelly | 478f34d | 2015-11-03 21:05:08 -0600 | [diff] [blame] | 53 | static struct string_list pack_garbage = STRING_LIST_INIT_DUP; |
| 54 | |
| 55 | static void clean_pack_garbage(void) |
| 56 | { |
| 57 | int i; |
| 58 | for (i = 0; i < pack_garbage.nr; i++) |
| 59 | unlink_or_warn(pack_garbage.items[i].string); |
| 60 | string_list_clear(&pack_garbage, 0); |
| 61 | } |
| 62 | |
| 63 | static void report_pack_garbage(unsigned seen_bits, const char *path) |
| 64 | { |
| 65 | if (seen_bits == PACKDIR_FILE_IDX) |
| 66 | string_list_append(&pack_garbage, path); |
| 67 | } |
| 68 | |
Nguyễn Thái Ngọc Duy | 329e6e8 | 2015-09-19 12:13:23 +0700 | [diff] [blame] | 69 | static void process_log_file(void) |
| 70 | { |
| 71 | struct stat st; |
David Turner | a831c06 | 2017-02-10 16:28:22 -0500 | [diff] [blame] | 72 | if (fstat(get_lock_file_fd(&log_lock), &st)) { |
| 73 | /* |
| 74 | * Perhaps there was an i/o error or another |
| 75 | * unlikely situation. Try to make a note of |
| 76 | * this in gc.log along with any existing |
| 77 | * messages. |
| 78 | */ |
| 79 | int saved_errno = errno; |
| 80 | fprintf(stderr, _("Failed to fstat %s: %s"), |
Jeff King | 076aa2c | 2017-09-05 08:15:08 -0400 | [diff] [blame] | 81 | get_tempfile_path(log_lock.tempfile), |
David Turner | a831c06 | 2017-02-10 16:28:22 -0500 | [diff] [blame] | 82 | strerror(saved_errno)); |
| 83 | fflush(stderr); |
Nguyễn Thái Ngọc Duy | 329e6e8 | 2015-09-19 12:13:23 +0700 | [diff] [blame] | 84 | commit_lock_file(&log_lock); |
David Turner | a831c06 | 2017-02-10 16:28:22 -0500 | [diff] [blame] | 85 | errno = saved_errno; |
| 86 | } else if (st.st_size) { |
| 87 | /* There was some error recorded in the lock file */ |
| 88 | commit_lock_file(&log_lock); |
| 89 | } else { |
| 90 | /* No error, clean up any old gc.log */ |
| 91 | unlink(git_path("gc.log")); |
Nguyễn Thái Ngọc Duy | 329e6e8 | 2015-09-19 12:13:23 +0700 | [diff] [blame] | 92 | rollback_lock_file(&log_lock); |
David Turner | a831c06 | 2017-02-10 16:28:22 -0500 | [diff] [blame] | 93 | } |
Nguyễn Thái Ngọc Duy | 329e6e8 | 2015-09-19 12:13:23 +0700 | [diff] [blame] | 94 | } |
| 95 | |
| 96 | static void process_log_file_at_exit(void) |
| 97 | { |
| 98 | fflush(stderr); |
| 99 | process_log_file(); |
| 100 | } |
| 101 | |
| 102 | static void process_log_file_on_signal(int signo) |
| 103 | { |
| 104 | process_log_file(); |
| 105 | sigchain_pop(signo); |
| 106 | raise(signo); |
| 107 | } |
| 108 | |
Tanay Abhra | 5801d3b | 2014-08-07 09:21:22 -0700 | [diff] [blame] | 109 | static void gc_config(void) |
James Bowes | 6757ada | 2007-03-13 21:58:22 -0400 | [diff] [blame] | 110 | { |
Tanay Abhra | 5801d3b | 2014-08-07 09:21:22 -0700 | [diff] [blame] | 111 | const char *value; |
| 112 | |
| 113 | if (!git_config_get_value("gc.packrefs", &value)) { |
Miklos Vajna | c5e5a2c | 2008-02-08 15:26:18 +0100 | [diff] [blame] | 114 | if (value && !strcmp(value, "notbare")) |
James Bowes | 6757ada | 2007-03-13 21:58:22 -0400 | [diff] [blame] | 115 | pack_refs = -1; |
| 116 | else |
Tanay Abhra | 5801d3b | 2014-08-07 09:21:22 -0700 | [diff] [blame] | 117 | pack_refs = git_config_bool("gc.packrefs", value); |
James Bowes | 6757ada | 2007-03-13 21:58:22 -0400 | [diff] [blame] | 118 | } |
Tanay Abhra | 5801d3b | 2014-08-07 09:21:22 -0700 | [diff] [blame] | 119 | |
| 120 | git_config_get_int("gc.aggressivewindow", &aggressive_window); |
| 121 | git_config_get_int("gc.aggressivedepth", &aggressive_depth); |
| 122 | git_config_get_int("gc.auto", &gc_auto_threshold); |
| 123 | git_config_get_int("gc.autopacklimit", &gc_auto_pack_limit); |
| 124 | git_config_get_bool("gc.autodetach", &detach_auto); |
Christian Couder | 77d6797 | 2017-02-27 19:00:13 +0100 | [diff] [blame] | 125 | git_config_get_expiry("gc.pruneexpire", &prune_expire); |
| 126 | git_config_get_expiry("gc.worktreepruneexpire", &prune_worktrees_expire); |
Junio C Hamano | 94c9b5a | 2017-03-17 13:50:23 -0700 | [diff] [blame] | 127 | git_config_get_expiry("gc.logexpiry", &gc_log_expire); |
David Turner | a831c06 | 2017-02-10 16:28:22 -0500 | [diff] [blame] | 128 | |
Tanay Abhra | 5801d3b | 2014-08-07 09:21:22 -0700 | [diff] [blame] | 129 | git_config(git_default_config, NULL); |
James Bowes | 6757ada | 2007-03-13 21:58:22 -0400 | [diff] [blame] | 130 | } |
| 131 | |
Junio C Hamano | a087cc9 | 2007-09-17 00:44:17 -0700 | [diff] [blame] | 132 | static int too_many_loose_objects(void) |
Junio C Hamano | 2c3c439 | 2007-09-05 13:01:37 -0700 | [diff] [blame] | 133 | { |
| 134 | /* |
| 135 | * Quickly check if a "gc" is needed, by estimating how |
| 136 | * many loose objects there are. Because SHA-1 is evenly |
| 137 | * distributed, we can check only one and get a reasonable |
| 138 | * estimate. |
| 139 | */ |
Junio C Hamano | 2c3c439 | 2007-09-05 13:01:37 -0700 | [diff] [blame] | 140 | DIR *dir; |
| 141 | struct dirent *ent; |
| 142 | int auto_threshold; |
| 143 | int num_loose = 0; |
| 144 | int needed = 0; |
| 145 | |
Junio C Hamano | 1781550 | 2007-09-17 00:55:13 -0700 | [diff] [blame] | 146 | if (gc_auto_threshold <= 0) |
| 147 | return 0; |
| 148 | |
Jeff King | 07af889 | 2017-03-28 15:47:03 -0400 | [diff] [blame] | 149 | dir = opendir(git_path("objects/17")); |
Junio C Hamano | 2c3c439 | 2007-09-05 13:01:37 -0700 | [diff] [blame] | 150 | if (!dir) |
| 151 | return 0; |
| 152 | |
René Scharfe | 42c78a2 | 2017-07-08 12:35:35 +0200 | [diff] [blame] | 153 | auto_threshold = DIV_ROUND_UP(gc_auto_threshold, 256); |
Junio C Hamano | 2c3c439 | 2007-09-05 13:01:37 -0700 | [diff] [blame] | 154 | while ((ent = readdir(dir)) != NULL) { |
| 155 | if (strspn(ent->d_name, "0123456789abcdef") != 38 || |
| 156 | ent->d_name[38] != '\0') |
| 157 | continue; |
| 158 | if (++num_loose > auto_threshold) { |
| 159 | needed = 1; |
| 160 | break; |
| 161 | } |
| 162 | } |
| 163 | closedir(dir); |
| 164 | return needed; |
| 165 | } |
| 166 | |
Junio C Hamano | 1781550 | 2007-09-17 00:55:13 -0700 | [diff] [blame] | 167 | static int too_many_packs(void) |
| 168 | { |
| 169 | struct packed_git *p; |
| 170 | int cnt; |
| 171 | |
| 172 | if (gc_auto_pack_limit <= 0) |
| 173 | return 0; |
| 174 | |
| 175 | prepare_packed_git(); |
| 176 | for (cnt = 0, p = packed_git; p; p = p->next) { |
Junio C Hamano | 1781550 | 2007-09-17 00:55:13 -0700 | [diff] [blame] | 177 | if (!p->pack_local) |
| 178 | continue; |
Brandon Casey | 01af249 | 2008-11-12 11:59:07 -0600 | [diff] [blame] | 179 | if (p->pack_keep) |
Junio C Hamano | 1781550 | 2007-09-17 00:55:13 -0700 | [diff] [blame] | 180 | continue; |
| 181 | /* |
| 182 | * Perhaps check the size of the pack and count only |
| 183 | * very small ones here? |
| 184 | */ |
| 185 | cnt++; |
| 186 | } |
Eric Wong | 5f4e3bf | 2016-06-25 06:46:47 +0000 | [diff] [blame] | 187 | return gc_auto_pack_limit < cnt; |
Junio C Hamano | 1781550 | 2007-09-17 00:55:13 -0700 | [diff] [blame] | 188 | } |
| 189 | |
Jeff King | 7e52f56 | 2012-04-07 06:30:09 -0400 | [diff] [blame] | 190 | static void add_repack_all_option(void) |
| 191 | { |
| 192 | if (prune_expire && !strcmp(prune_expire, "now")) |
Jeff King | 234587f | 2012-04-18 14:10:19 -0700 | [diff] [blame] | 193 | argv_array_push(&repack, "-a"); |
Jeff King | 7e52f56 | 2012-04-07 06:30:09 -0400 | [diff] [blame] | 194 | else { |
Jeff King | 234587f | 2012-04-18 14:10:19 -0700 | [diff] [blame] | 195 | argv_array_push(&repack, "-A"); |
| 196 | if (prune_expire) |
| 197 | argv_array_pushf(&repack, "--unpack-unreachable=%s", prune_expire); |
Jeff King | 7e52f56 | 2012-04-07 06:30:09 -0400 | [diff] [blame] | 198 | } |
| 199 | } |
| 200 | |
David Turner | bdf56de | 2016-12-28 17:45:41 -0500 | [diff] [blame] | 201 | static void add_repack_incremental_option(void) |
| 202 | { |
| 203 | argv_array_push(&repack, "--no-write-bitmap-index"); |
| 204 | } |
| 205 | |
Junio C Hamano | a087cc9 | 2007-09-17 00:44:17 -0700 | [diff] [blame] | 206 | static int need_to_gc(void) |
| 207 | { |
| 208 | /* |
Brandon Casey | b14d255 | 2008-03-19 16:53:20 -0500 | [diff] [blame] | 209 | * Setting gc.auto to 0 or negative can disable the |
| 210 | * automatic gc. |
Junio C Hamano | a087cc9 | 2007-09-17 00:44:17 -0700 | [diff] [blame] | 211 | */ |
Brandon Casey | b14d255 | 2008-03-19 16:53:20 -0500 | [diff] [blame] | 212 | if (gc_auto_threshold <= 0) |
Junio C Hamano | a087cc9 | 2007-09-17 00:44:17 -0700 | [diff] [blame] | 213 | return 0; |
| 214 | |
Junio C Hamano | 1781550 | 2007-09-17 00:55:13 -0700 | [diff] [blame] | 215 | /* |
| 216 | * If there are too many loose objects, but not too many |
| 217 | * packs, we run "repack -d -l". If there are too many packs, |
| 218 | * we run "repack -A -d -l". Otherwise we tell the caller |
| 219 | * there is no need. |
| 220 | */ |
Junio C Hamano | 1781550 | 2007-09-17 00:55:13 -0700 | [diff] [blame] | 221 | if (too_many_packs()) |
Jeff King | 7e52f56 | 2012-04-07 06:30:09 -0400 | [diff] [blame] | 222 | add_repack_all_option(); |
David Turner | bdf56de | 2016-12-28 17:45:41 -0500 | [diff] [blame] | 223 | else if (too_many_loose_objects()) |
| 224 | add_repack_incremental_option(); |
| 225 | else |
Junio C Hamano | 1781550 | 2007-09-17 00:55:13 -0700 | [diff] [blame] | 226 | return 0; |
Miklos Vajna | bde3054 | 2008-04-02 21:34:38 +0200 | [diff] [blame] | 227 | |
Benoit Pierre | 15048f8 | 2014-03-18 11:00:53 +0100 | [diff] [blame] | 228 | if (run_hook_le(NULL, "pre-auto-gc", NULL)) |
Miklos Vajna | bde3054 | 2008-04-02 21:34:38 +0200 | [diff] [blame] | 229 | return 0; |
Junio C Hamano | 95143f9 | 2007-09-17 00:48:39 -0700 | [diff] [blame] | 230 | return 1; |
Junio C Hamano | a087cc9 | 2007-09-17 00:44:17 -0700 | [diff] [blame] | 231 | } |
| 232 | |
Nguyễn Thái Ngọc Duy | 64a99eb | 2013-08-08 18:05:38 +0700 | [diff] [blame] | 233 | /* return NULL on success, else hostname running the gc */ |
| 234 | static const char *lock_repo_for_gc(int force, pid_t* ret_pid) |
| 235 | { |
| 236 | static struct lock_file lock; |
René Scharfe | da25bdb | 2017-04-18 17:57:42 -0400 | [diff] [blame] | 237 | char my_host[HOST_NAME_MAX + 1]; |
Nguyễn Thái Ngọc Duy | 64a99eb | 2013-08-08 18:05:38 +0700 | [diff] [blame] | 238 | struct strbuf sb = STRBUF_INIT; |
| 239 | struct stat st; |
| 240 | uintmax_t pid; |
| 241 | FILE *fp; |
Elia Pinto | 4f1c0b2 | 2014-01-29 08:59:37 -0800 | [diff] [blame] | 242 | int fd; |
Michael Haggerty | 00539ce | 2015-08-10 11:47:48 +0200 | [diff] [blame] | 243 | char *pidfile_path; |
Nguyễn Thái Ngọc Duy | 64a99eb | 2013-08-08 18:05:38 +0700 | [diff] [blame] | 244 | |
Jeff King | 076aa2c | 2017-09-05 08:15:08 -0400 | [diff] [blame] | 245 | if (is_tempfile_active(pidfile)) |
Jonathan Nieder | 4c5baf0 | 2013-10-16 16:11:46 -0700 | [diff] [blame] | 246 | /* already locked */ |
| 247 | return NULL; |
| 248 | |
David Turner | 5781a9a | 2017-04-18 17:57:43 -0400 | [diff] [blame] | 249 | if (xgethostname(my_host, sizeof(my_host))) |
Jeff King | 5096d49 | 2015-09-24 17:06:08 -0400 | [diff] [blame] | 250 | xsnprintf(my_host, sizeof(my_host), "unknown"); |
Nguyễn Thái Ngọc Duy | 64a99eb | 2013-08-08 18:05:38 +0700 | [diff] [blame] | 251 | |
Michael Haggerty | 00539ce | 2015-08-10 11:47:48 +0200 | [diff] [blame] | 252 | pidfile_path = git_pathdup("gc.pid"); |
| 253 | fd = hold_lock_file_for_update(&lock, pidfile_path, |
Nguyễn Thái Ngọc Duy | 64a99eb | 2013-08-08 18:05:38 +0700 | [diff] [blame] | 254 | LOCK_DIE_ON_ERROR); |
| 255 | if (!force) { |
René Scharfe | da25bdb | 2017-04-18 17:57:42 -0400 | [diff] [blame] | 256 | static char locking_host[HOST_NAME_MAX + 1]; |
| 257 | static char *scan_fmt; |
Elia Pinto | 4f1c0b2 | 2014-01-29 08:59:37 -0800 | [diff] [blame] | 258 | int should_exit; |
René Scharfe | da25bdb | 2017-04-18 17:57:42 -0400 | [diff] [blame] | 259 | |
| 260 | if (!scan_fmt) |
Junio C Hamano | afe2fab | 2017-09-17 12:16:55 +0900 | [diff] [blame] | 261 | scan_fmt = xstrfmt("%s %%%ds", "%"SCNuMAX, HOST_NAME_MAX); |
Michael Haggerty | 00539ce | 2015-08-10 11:47:48 +0200 | [diff] [blame] | 262 | fp = fopen(pidfile_path, "r"); |
Nguyễn Thái Ngọc Duy | 64a99eb | 2013-08-08 18:05:38 +0700 | [diff] [blame] | 263 | memset(locking_host, 0, sizeof(locking_host)); |
| 264 | should_exit = |
| 265 | fp != NULL && |
| 266 | !fstat(fileno(fp), &st) && |
| 267 | /* |
| 268 | * 12 hour limit is very generous as gc should |
| 269 | * never take that long. On the other hand we |
| 270 | * don't really need a strict limit here, |
| 271 | * running gc --auto one day late is not a big |
| 272 | * problem. --force can be used in manual gc |
| 273 | * after the user verifies that no gc is |
| 274 | * running. |
| 275 | */ |
| 276 | time(NULL) - st.st_mtime <= 12 * 3600 && |
René Scharfe | da25bdb | 2017-04-18 17:57:42 -0400 | [diff] [blame] | 277 | fscanf(fp, scan_fmt, &pid, locking_host) == 2 && |
Nguyễn Thái Ngọc Duy | 64a99eb | 2013-08-08 18:05:38 +0700 | [diff] [blame] | 278 | /* be gentle to concurrent "gc" on remote hosts */ |
Kyle J. McKay | ed7eda8 | 2013-12-31 04:07:39 -0800 | [diff] [blame] | 279 | (strcmp(locking_host, my_host) || !kill(pid, 0) || errno == EPERM); |
Nguyễn Thái Ngọc Duy | 64a99eb | 2013-08-08 18:05:38 +0700 | [diff] [blame] | 280 | if (fp != NULL) |
| 281 | fclose(fp); |
| 282 | if (should_exit) { |
| 283 | if (fd >= 0) |
| 284 | rollback_lock_file(&lock); |
| 285 | *ret_pid = pid; |
Michael Haggerty | 00539ce | 2015-08-10 11:47:48 +0200 | [diff] [blame] | 286 | free(pidfile_path); |
Nguyễn Thái Ngọc Duy | 64a99eb | 2013-08-08 18:05:38 +0700 | [diff] [blame] | 287 | return locking_host; |
| 288 | } |
| 289 | } |
| 290 | |
| 291 | strbuf_addf(&sb, "%"PRIuMAX" %s", |
| 292 | (uintmax_t) getpid(), my_host); |
| 293 | write_in_full(fd, sb.buf, sb.len); |
| 294 | strbuf_release(&sb); |
| 295 | commit_lock_file(&lock); |
Jeff King | 076aa2c | 2017-09-05 08:15:08 -0400 | [diff] [blame] | 296 | pidfile = register_tempfile(pidfile_path); |
Michael Haggerty | ebebeae | 2015-08-10 11:47:49 +0200 | [diff] [blame] | 297 | free(pidfile_path); |
Nguyễn Thái Ngọc Duy | 64a99eb | 2013-08-08 18:05:38 +0700 | [diff] [blame] | 298 | return NULL; |
| 299 | } |
| 300 | |
Nguyễn Thái Ngọc Duy | 329e6e8 | 2015-09-19 12:13:23 +0700 | [diff] [blame] | 301 | static int report_last_gc_error(void) |
| 302 | { |
| 303 | struct strbuf sb = STRBUF_INIT; |
David Turner | a831c06 | 2017-02-10 16:28:22 -0500 | [diff] [blame] | 304 | int ret = 0; |
| 305 | struct stat st; |
| 306 | char *gc_log_path = git_pathdup("gc.log"); |
Nguyễn Thái Ngọc Duy | 329e6e8 | 2015-09-19 12:13:23 +0700 | [diff] [blame] | 307 | |
David Turner | a831c06 | 2017-02-10 16:28:22 -0500 | [diff] [blame] | 308 | if (stat(gc_log_path, &st)) { |
| 309 | if (errno == ENOENT) |
| 310 | goto done; |
| 311 | |
| 312 | ret = error_errno(_("Can't stat %s"), gc_log_path); |
| 313 | goto done; |
| 314 | } |
| 315 | |
| 316 | if (st.st_mtime < gc_log_expire_time) |
| 317 | goto done; |
| 318 | |
| 319 | ret = strbuf_read_file(&sb, gc_log_path, 0); |
Nguyễn Thái Ngọc Duy | 329e6e8 | 2015-09-19 12:13:23 +0700 | [diff] [blame] | 320 | if (ret > 0) |
David Turner | a831c06 | 2017-02-10 16:28:22 -0500 | [diff] [blame] | 321 | ret = error(_("The last gc run reported the following. " |
Nguyễn Thái Ngọc Duy | 329e6e8 | 2015-09-19 12:13:23 +0700 | [diff] [blame] | 322 | "Please correct the root cause\n" |
| 323 | "and remove %s.\n" |
| 324 | "Automatic cleanup will not be performed " |
| 325 | "until the file is removed.\n\n" |
| 326 | "%s"), |
David Turner | a831c06 | 2017-02-10 16:28:22 -0500 | [diff] [blame] | 327 | gc_log_path, sb.buf); |
Nguyễn Thái Ngọc Duy | 329e6e8 | 2015-09-19 12:13:23 +0700 | [diff] [blame] | 328 | strbuf_release(&sb); |
David Turner | a831c06 | 2017-02-10 16:28:22 -0500 | [diff] [blame] | 329 | done: |
| 330 | free(gc_log_path); |
| 331 | return ret; |
Nguyễn Thái Ngọc Duy | 329e6e8 | 2015-09-19 12:13:23 +0700 | [diff] [blame] | 332 | } |
| 333 | |
Nguyễn Thái Ngọc Duy | 62aad18 | 2014-05-25 07:38:29 +0700 | [diff] [blame] | 334 | static int gc_before_repack(void) |
| 335 | { |
| 336 | if (pack_refs && run_command_v_opt(pack_refs_cmd.argv, RUN_GIT_CMD)) |
| 337 | return error(FAILED_RUN, pack_refs_cmd.argv[0]); |
| 338 | |
| 339 | if (prune_reflogs && run_command_v_opt(reflog.argv, RUN_GIT_CMD)) |
| 340 | return error(FAILED_RUN, reflog.argv[0]); |
| 341 | |
| 342 | pack_refs = 0; |
| 343 | prune_reflogs = 0; |
| 344 | return 0; |
| 345 | } |
| 346 | |
James Bowes | 6757ada | 2007-03-13 21:58:22 -0400 | [diff] [blame] | 347 | int cmd_gc(int argc, const char **argv, const char *prefix) |
| 348 | { |
James Bowes | 44c637c | 2007-11-01 21:02:27 -0400 | [diff] [blame] | 349 | int aggressive = 0; |
Junio C Hamano | 2c3c439 | 2007-09-05 13:01:37 -0700 | [diff] [blame] | 350 | int auto_gc = 0; |
Frank Lichtenheld | a0c14cb | 2008-02-29 22:53:39 +0100 | [diff] [blame] | 351 | int quiet = 0; |
Nguyễn Thái Ngọc Duy | 64a99eb | 2013-08-08 18:05:38 +0700 | [diff] [blame] | 352 | int force = 0; |
| 353 | const char *name; |
| 354 | pid_t pid; |
Nguyễn Thái Ngọc Duy | 329e6e8 | 2015-09-19 12:13:23 +0700 | [diff] [blame] | 355 | int daemonized = 0; |
James Bowes | 6757ada | 2007-03-13 21:58:22 -0400 | [diff] [blame] | 356 | |
James Bowes | 44c637c | 2007-11-01 21:02:27 -0400 | [diff] [blame] | 357 | struct option builtin_gc_options[] = { |
Nguyễn Thái Ngọc Duy | 6705c16 | 2012-08-20 19:32:14 +0700 | [diff] [blame] | 358 | OPT__QUIET(&quiet, N_("suppress progress reporting")), |
| 359 | { OPTION_STRING, 0, "prune", &prune_expire, N_("date"), |
| 360 | N_("prune unreferenced objects"), |
Johannes Schindelin | 58e9d9d | 2009-02-14 23:10:10 +0100 | [diff] [blame] | 361 | PARSE_OPT_OPTARG, NULL, (intptr_t)prune_expire }, |
Stefan Beller | d5d09d4 | 2013-08-03 13:51:19 +0200 | [diff] [blame] | 362 | OPT_BOOL(0, "aggressive", &aggressive, N_("be more thorough (increased runtime)")), |
| 363 | OPT_BOOL(0, "auto", &auto_gc, N_("enable auto-gc mode")), |
Nguyễn Thái Ngọc Duy | 64a99eb | 2013-08-08 18:05:38 +0700 | [diff] [blame] | 364 | OPT_BOOL(0, "force", &force, N_("force running gc even if there may be another gc running")), |
James Bowes | 44c637c | 2007-11-01 21:02:27 -0400 | [diff] [blame] | 365 | OPT_END() |
| 366 | }; |
| 367 | |
Nguyễn Thái Ngọc Duy | 0c8151b | 2010-10-22 01:47:19 -0500 | [diff] [blame] | 368 | if (argc == 2 && !strcmp(argv[1], "-h")) |
| 369 | usage_with_options(builtin_gc_usage, builtin_gc_options); |
| 370 | |
Jeff King | 234587f | 2012-04-18 14:10:19 -0700 | [diff] [blame] | 371 | argv_array_pushl(&pack_refs_cmd, "pack-refs", "--all", "--prune", NULL); |
| 372 | argv_array_pushl(&reflog, "reflog", "expire", "--all", NULL); |
| 373 | argv_array_pushl(&repack, "repack", "-d", "-l", NULL); |
Nguyễn Thái Ngọc Duy | 2cfe2a7 | 2014-11-30 15:24:51 +0700 | [diff] [blame] | 374 | argv_array_pushl(&prune, "prune", "--expire", NULL); |
Nguyễn Thái Ngọc Duy | df0b6cf | 2015-06-29 19:51:18 +0700 | [diff] [blame] | 375 | argv_array_pushl(&prune_worktrees, "worktree", "prune", "--expire", NULL); |
Jeff King | 234587f | 2012-04-18 14:10:19 -0700 | [diff] [blame] | 376 | argv_array_pushl(&rerere, "rerere", "gc", NULL); |
| 377 | |
David Turner | a831c06 | 2017-02-10 16:28:22 -0500 | [diff] [blame] | 378 | /* default expiry time, overwritten in gc_config */ |
Tanay Abhra | 5801d3b | 2014-08-07 09:21:22 -0700 | [diff] [blame] | 379 | gc_config(); |
David Turner | a831c06 | 2017-02-10 16:28:22 -0500 | [diff] [blame] | 380 | if (parse_expiry_date(gc_log_expire, &gc_log_expire_time)) |
| 381 | die(_("Failed to parse gc.logexpiry value %s"), gc_log_expire); |
James Bowes | 6757ada | 2007-03-13 21:58:22 -0400 | [diff] [blame] | 382 | |
| 383 | if (pack_refs < 0) |
| 384 | pack_refs = !is_bare_repository(); |
| 385 | |
Stephen Boyd | 3778292 | 2009-05-23 11:53:12 -0700 | [diff] [blame] | 386 | argc = parse_options(argc, argv, prefix, builtin_gc_options, |
| 387 | builtin_gc_usage, 0); |
James Bowes | 44c637c | 2007-11-01 21:02:27 -0400 | [diff] [blame] | 388 | if (argc > 0) |
| 389 | usage_with_options(builtin_gc_usage, builtin_gc_options); |
| 390 | |
| 391 | if (aggressive) { |
Jeff King | 234587f | 2012-04-18 14:10:19 -0700 | [diff] [blame] | 392 | argv_array_push(&repack, "-f"); |
Nguyễn Thái Ngọc Duy | 125f814 | 2014-03-16 20:35:03 +0700 | [diff] [blame] | 393 | if (aggressive_depth > 0) |
| 394 | argv_array_pushf(&repack, "--depth=%d", aggressive_depth); |
Jeff King | 234587f | 2012-04-18 14:10:19 -0700 | [diff] [blame] | 395 | if (aggressive_window > 0) |
| 396 | argv_array_pushf(&repack, "--window=%d", aggressive_window); |
James Bowes | 6757ada | 2007-03-13 21:58:22 -0400 | [diff] [blame] | 397 | } |
Frank Lichtenheld | a0c14cb | 2008-02-29 22:53:39 +0100 | [diff] [blame] | 398 | if (quiet) |
Jeff King | 234587f | 2012-04-18 14:10:19 -0700 | [diff] [blame] | 399 | argv_array_push(&repack, "-q"); |
James Bowes | 6757ada | 2007-03-13 21:58:22 -0400 | [diff] [blame] | 400 | |
Junio C Hamano | 2c3c439 | 2007-09-05 13:01:37 -0700 | [diff] [blame] | 401 | if (auto_gc) { |
| 402 | /* |
| 403 | * Auto-gc should be least intrusive as possible. |
| 404 | */ |
Junio C Hamano | 2c3c439 | 2007-09-05 13:01:37 -0700 | [diff] [blame] | 405 | if (!need_to_gc()) |
| 406 | return 0; |
Nguyễn Thái Ngọc Duy | 9f673f9 | 2014-02-08 14:08:52 +0700 | [diff] [blame] | 407 | if (!quiet) { |
| 408 | if (detach_auto) |
| 409 | fprintf(stderr, _("Auto packing the repository in background for optimum performance.\n")); |
| 410 | else |
| 411 | fprintf(stderr, _("Auto packing the repository for optimum performance.\n")); |
| 412 | fprintf(stderr, _("See \"git help gc\" for manual housekeeping.\n")); |
| 413 | } |
Nguyễn Thái Ngọc Duy | 62aad18 | 2014-05-25 07:38:29 +0700 | [diff] [blame] | 414 | if (detach_auto) { |
Nguyễn Thái Ngọc Duy | 329e6e8 | 2015-09-19 12:13:23 +0700 | [diff] [blame] | 415 | if (report_last_gc_error()) |
| 416 | return -1; |
| 417 | |
Jeff King | c45af94 | 2017-07-11 05:06:35 -0400 | [diff] [blame] | 418 | if (lock_repo_for_gc(force, &pid)) |
| 419 | return 0; |
Nguyễn Thái Ngọc Duy | 62aad18 | 2014-05-25 07:38:29 +0700 | [diff] [blame] | 420 | if (gc_before_repack()) |
| 421 | return -1; |
Jeff King | c45af94 | 2017-07-11 05:06:35 -0400 | [diff] [blame] | 422 | delete_tempfile(&pidfile); |
| 423 | |
Nguyễn Thái Ngọc Duy | 9f673f9 | 2014-02-08 14:08:52 +0700 | [diff] [blame] | 424 | /* |
| 425 | * failure to daemonize is ok, we'll continue |
| 426 | * in foreground |
| 427 | */ |
Nguyễn Thái Ngọc Duy | 329e6e8 | 2015-09-19 12:13:23 +0700 | [diff] [blame] | 428 | daemonized = !daemonize(); |
Nguyễn Thái Ngọc Duy | 62aad18 | 2014-05-25 07:38:29 +0700 | [diff] [blame] | 429 | } |
Brandon Casey | a37cce3 | 2008-05-09 23:01:56 -0500 | [diff] [blame] | 430 | } else |
Jeff King | 7e52f56 | 2012-04-07 06:30:09 -0400 | [diff] [blame] | 431 | add_repack_all_option(); |
Junio C Hamano | 2c3c439 | 2007-09-05 13:01:37 -0700 | [diff] [blame] | 432 | |
Nguyễn Thái Ngọc Duy | 64a99eb | 2013-08-08 18:05:38 +0700 | [diff] [blame] | 433 | name = lock_repo_for_gc(force, &pid); |
| 434 | if (name) { |
| 435 | if (auto_gc) |
| 436 | return 0; /* be quiet on --auto */ |
| 437 | die(_("gc is already running on machine '%s' pid %"PRIuMAX" (use --force if not)"), |
| 438 | name, (uintmax_t)pid); |
| 439 | } |
| 440 | |
Nguyễn Thái Ngọc Duy | 329e6e8 | 2015-09-19 12:13:23 +0700 | [diff] [blame] | 441 | if (daemonized) { |
| 442 | hold_lock_file_for_update(&log_lock, |
| 443 | git_path("gc.log"), |
| 444 | LOCK_DIE_ON_ERROR); |
Junio C Hamano | 076c827 | 2015-10-15 15:43:32 -0700 | [diff] [blame] | 445 | dup2(get_lock_file_fd(&log_lock), 2); |
Nguyễn Thái Ngọc Duy | 329e6e8 | 2015-09-19 12:13:23 +0700 | [diff] [blame] | 446 | sigchain_push_common(process_log_file_on_signal); |
| 447 | atexit(process_log_file_at_exit); |
| 448 | } |
| 449 | |
Nguyễn Thái Ngọc Duy | 62aad18 | 2014-05-25 07:38:29 +0700 | [diff] [blame] | 450 | if (gc_before_repack()) |
| 451 | return -1; |
James Bowes | 6757ada | 2007-03-13 21:58:22 -0400 | [diff] [blame] | 452 | |
Jeff King | 067fbd4 | 2015-06-23 06:54:11 -0400 | [diff] [blame] | 453 | if (!repository_format_precious_objects) { |
| 454 | if (run_command_v_opt(repack.argv, RUN_GIT_CMD)) |
| 455 | return error(FAILED_RUN, repack.argv[0]); |
James Bowes | 6757ada | 2007-03-13 21:58:22 -0400 | [diff] [blame] | 456 | |
Jeff King | 067fbd4 | 2015-06-23 06:54:11 -0400 | [diff] [blame] | 457 | if (prune_expire) { |
| 458 | argv_array_push(&prune, prune_expire); |
| 459 | if (quiet) |
| 460 | argv_array_push(&prune, "--no-progress"); |
| 461 | if (run_command_v_opt(prune.argv, RUN_GIT_CMD)) |
| 462 | return error(FAILED_RUN, prune.argv[0]); |
| 463 | } |
Johannes Schindelin | 58e9d9d | 2009-02-14 23:10:10 +0100 | [diff] [blame] | 464 | } |
James Bowes | 6757ada | 2007-03-13 21:58:22 -0400 | [diff] [blame] | 465 | |
Nguyễn Thái Ngọc Duy | e3df33b | 2014-11-30 15:24:53 +0700 | [diff] [blame] | 466 | if (prune_worktrees_expire) { |
| 467 | argv_array_push(&prune_worktrees, prune_worktrees_expire); |
| 468 | if (run_command_v_opt(prune_worktrees.argv, RUN_GIT_CMD)) |
| 469 | return error(FAILED_RUN, prune_worktrees.argv[0]); |
| 470 | } |
| 471 | |
Jeff King | 234587f | 2012-04-18 14:10:19 -0700 | [diff] [blame] | 472 | if (run_command_v_opt(rerere.argv, RUN_GIT_CMD)) |
| 473 | return error(FAILED_RUN, rerere.argv[0]); |
James Bowes | 6757ada | 2007-03-13 21:58:22 -0400 | [diff] [blame] | 474 | |
Doug Kelly | 478f34d | 2015-11-03 21:05:08 -0600 | [diff] [blame] | 475 | report_garbage = report_pack_garbage; |
| 476 | reprepare_packed_git(); |
| 477 | if (pack_garbage.nr > 0) |
| 478 | clean_pack_garbage(); |
| 479 | |
Junio C Hamano | a087cc9 | 2007-09-17 00:44:17 -0700 | [diff] [blame] | 480 | if (auto_gc && too_many_loose_objects()) |
Ævar Arnfjörð Bjarmason | fea6128 | 2011-02-22 23:42:24 +0000 | [diff] [blame] | 481 | warning(_("There are too many unreachable loose objects; " |
| 482 | "run 'git prune' to remove them.")); |
Junio C Hamano | a087cc9 | 2007-09-17 00:44:17 -0700 | [diff] [blame] | 483 | |
David Turner | a831c06 | 2017-02-10 16:28:22 -0500 | [diff] [blame] | 484 | if (!daemonized) |
| 485 | unlink(git_path("gc.log")); |
| 486 | |
James Bowes | 6757ada | 2007-03-13 21:58:22 -0400 | [diff] [blame] | 487 | return 0; |
| 488 | } |