@matheusbsbs / matheus-bagliano / commits / 3cb22b8efe
Fork 0

Per-ref reflog expiry configuration

In addition to gc.reflogexpireunreachable and gc.reflogexpire, this lets you set gc.<pattern>.reflogexpireunreachable and gc.<pattern>.reflogexpire variables. When "git reflog expire" expires reflog entry for $ref, the expiry timers are taken from the first <pattern> that matches $ref (and if there isn't the global default value is used). For example, you could: [gc "refs/stash"] reflogexpire = never reflogexpireunreachable = never [gc "refs/remotes/*"] reflogexpire = 7 days reflogexpireunreachable = 3 days [gc] reflogexpire = 90 days reflogexpireunreachable = 30 days Signed-off-by: Junio C Hamano <gitster@pobox.com>

Junio C Hamano committed Jun 15, 2008 at 23:48 UTC 3cb22b8efe2cab60dc0ef5e265c414bd826d83ef
1 file changed +126 -19
builtin-reflog.c
+126 -19
@@ -269,7 +269,9 @@ static int expire_reflog(const char *ref, const unsigned char *sha1, int unused,
269 int status = 0;
270
271 memset(&cb, 0, sizeof(cb));
272 - /* we take the lock for the ref itself to prevent it from
272 +
273 + /*
274 + * we take the lock for the ref itself to prevent it from
275 * getting updated.
276 */
277 lock = lock_any_ref_for_update(ref, sha1, 0);
@@ -331,21 +333,119 @@ static int collect_reflog(const char *ref, const unsigned char *sha1, int unused
333 return 0;
334 }
335
334 -static int reflog_expire_config(const char *var, const char *value, void *cb)
336 +static struct reflog_expire_cfg {
337 + struct reflog_expire_cfg *next;
338 + unsigned long expire_total;
339 + unsigned long expire_unreachable;
340 + size_t len;
341 + char pattern[FLEX_ARRAY];
342 +} *reflog_expire_cfg, **reflog_expire_cfg_tail;
343 +
344 +static struct reflog_expire_cfg *find_cfg_ent(const char *pattern, size_t len)
345 {
336 - if (!strcmp(var, "gc.reflogexpire")) {
337 - if (!value)
338 - config_error_nonbool(var);
339 - default_reflog_expire = approxidate(value);
346 + struct reflog_expire_cfg *ent;
347 +
348 + if (!reflog_expire_cfg_tail)
349 + reflog_expire_cfg_tail = &reflog_expire_cfg;
350 +
351 + for (ent = reflog_expire_cfg; ent; ent = ent->next)
352 + if (ent->len == len &&
353 + !memcmp(ent->pattern, pattern, len))
354 + return ent;
355 +
356 + ent = xcalloc(1, (sizeof(*ent) + len));
357 + memcpy(ent->pattern, pattern, len);
358 + ent->len = len;
359 + *reflog_expire_cfg_tail = ent;
360 + reflog_expire_cfg_tail = &(ent->next);
361 + return ent;
362 +}
363 +
364 +static int parse_expire_cfg_value(const char *var, const char *value, unsigned long *expire)
365 +{
366 + if (!value)
367 + return config_error_nonbool(var);
368 + if (!strcmp(value, "never") || !strcmp(value, "false")) {
369 + *expire = 0;
370 return 0;
371 }
342 - if (!strcmp(var, "gc.reflogexpireunreachable")) {
343 - if (!value)
344 - config_error_nonbool(var);
345 - default_reflog_expire_unreachable = approxidate(value);
372 + *expire = approxidate(value);
373 + return 0;
374 +}
375 +
376 +/* expiry timer slot */
377 +#define EXPIRE_TOTAL 01
378 +#define EXPIRE_UNREACH 02
379 +
380 +static int reflog_expire_config(const char *var, const char *value, void *cb)
381 +{
382 + const char *lastdot = strrchr(var, '.');
383 + unsigned long expire;
384 + int slot;
385 + struct reflog_expire_cfg *ent;
386 +
387 + if (!lastdot || prefixcmp(var, "gc."))
388 + return git_default_config(var, value, cb);
389 +
390 + if (!strcmp(lastdot, ".reflogexpire")) {
391 + slot = EXPIRE_TOTAL;
392 + if (parse_expire_cfg_value(var, value, &expire))
393 + return -1;
394 + } else if (!strcmp(lastdot, ".reflogexpireunreachable")) {
395 + slot = EXPIRE_UNREACH;
396 + if (parse_expire_cfg_value(var, value, &expire))
397 + return -1;
398 + } else
399 + return git_default_config(var, value, cb);
400 +
401 + if (lastdot == var + 2) {
402 + switch (slot) {
403 + case EXPIRE_TOTAL:
404 + default_reflog_expire = expire;
405 + break;
406 + case EXPIRE_UNREACH:
407 + default_reflog_expire_unreachable = expire;
408 + break;
409 + }
410 return 0;
411 }
348 - return git_default_config(var, value, cb);
412 +
413 + ent = find_cfg_ent(var + 3, lastdot - (var+3));
414 + if (!ent)
415 + return -1;
416 + switch (slot) {
417 + case EXPIRE_TOTAL:
418 + ent->expire_total = expire;
419 + break;
420 + case EXPIRE_UNREACH:
421 + ent->expire_unreachable = expire;
422 + break;
423 + }
424 + return 0;
425 +}
426 +
427 +static void set_reflog_expiry_param(struct cmd_reflog_expire_cb *cb, int slot, const char *ref)
428 +{
429 + struct reflog_expire_cfg *ent;
430 +
431 + if (slot == (EXPIRE_TOTAL|EXPIRE_UNREACH))
432 + return; /* both given explicitly -- nothing to tweak */
433 +
434 + for (ent = reflog_expire_cfg; ent; ent = ent->next) {
435 + if (!fnmatch(ent->pattern, ref, 0)) {
436 + if (!(slot & EXPIRE_TOTAL))
437 + cb->expire_total = ent->expire_total;
438 + if (!(slot & EXPIRE_UNREACH))
439 + cb->expire_unreachable = ent->expire_unreachable;
440 + return;
441 + }
442 + }
443 +
444 + /* Nothing matched -- use the default value */
445 + if (!(slot & EXPIRE_TOTAL))
446 + cb->expire_total = default_reflog_expire;
447 + if (!(slot & EXPIRE_UNREACH))
448 + cb->expire_unreachable = default_reflog_expire_unreachable;
449 }
450
451 static int cmd_reflog_expire(int argc, const char **argv, const char *prefix)
@@ -353,6 +453,7 @@ static int cmd_reflog_expire(int argc, const char **argv, const char *prefix)
453 struct cmd_reflog_expire_cb cb;
454 unsigned long now = time(NULL);
455 int i, status, do_all;
456 + int explicit_expiry = 0;
457
458 git_config(reflog_expire_config, NULL);
459
@@ -367,20 +468,18 @@ static int cmd_reflog_expire(int argc, const char **argv, const char *prefix)
468 cb.expire_total = default_reflog_expire;
469 cb.expire_unreachable = default_reflog_expire_unreachable;
470
370 - /*
371 - * We can trust the commits and objects reachable from refs
372 - * even in older repository. We cannot trust what's reachable
373 - * from reflog if the repository was pruned with older git.
374 - */
375 -
471 for (i = 1; i < argc; i++) {
472 const char *arg = argv[i];
473 if (!strcmp(arg, "--dry-run") || !strcmp(arg, "-n"))
474 cb.dry_run = 1;
380 - else if (!prefixcmp(arg, "--expire="))
475 + else if (!prefixcmp(arg, "--expire=")) {
476 cb.expire_total = approxidate(arg + 9);
382 - else if (!prefixcmp(arg, "--expire-unreachable="))
477 + explicit_expiry |= EXPIRE_TOTAL;
478 + }
479 + else if (!prefixcmp(arg, "--expire-unreachable=")) {
480 cb.expire_unreachable = approxidate(arg + 21);
481 + explicit_expiry |= EXPIRE_UNREACH;
482 + }
483 else if (!strcmp(arg, "--stale-fix"))
484 cb.stalefix = 1;
485 else if (!strcmp(arg, "--rewrite"))
@@ -400,6 +499,12 @@ static int cmd_reflog_expire(int argc, const char **argv, const char *prefix)
499 else
500 break;
501 }
502 +
503 + /*
504 + * We can trust the commits and objects reachable from refs
505 + * even in older repository. We cannot trust what's reachable
506 + * from reflog if the repository was pruned with older git.
507 + */
508 if (cb.stalefix) {
509 init_revisions(&cb.revs, prefix);
510 if (cb.verbose)
@@ -417,6 +522,7 @@ static int cmd_reflog_expire(int argc, const char **argv, const char *prefix)
522 for_each_reflog(collect_reflog, &collected);
523 for (i = 0; i < collected.nr; i++) {
524 struct collected_reflog *e = collected.e[i];
525 + set_reflog_expiry_param(&cb, explicit_expiry, e->reflog);
526 status |= expire_reflog(e->reflog, e->sha1, 0, &cb);
527 free(e);
528 }
@@ -430,6 +536,7 @@ static int cmd_reflog_expire(int argc, const char **argv, const char *prefix)
536 status |= error("%s points nowhere!", ref);
537 continue;
538 }
539 + set_reflog_expiry_param(&cb, explicit_expiry, ref);
540 status |= expire_reflog(ref, sha1, 0, &cb);
541 }
542 return status;