builtin / rerere.con commit merge-recursive --patience (58a1ece)
   1#include "builtin.h"
   2#include "cache.h"
   3#include "dir.h"
   4#include "parse-options.h"
   5#include "string-list.h"
   6#include "rerere.h"
   7#include "xdiff/xdiff.h"
   8#include "xdiff-interface.h"
   9
  10static const char * const rerere_usage[] = {
  11        "git rerere [clear | status | diff | gc]",
  12        NULL,
  13};
  14
  15/* these values are days */
  16static int cutoff_noresolve = 15;
  17static int cutoff_resolve = 60;
  18
  19static time_t rerere_created_at(const char *name)
  20{
  21        struct stat st;
  22        return stat(rerere_path(name, "preimage"), &st) ? (time_t) 0 : st.st_mtime;
  23}
  24
  25static void unlink_rr_item(const char *name)
  26{
  27        unlink(rerere_path(name, "thisimage"));
  28        unlink(rerere_path(name, "preimage"));
  29        unlink(rerere_path(name, "postimage"));
  30        rmdir(git_path("rr-cache/%s", name));
  31}
  32
  33static int git_rerere_gc_config(const char *var, const char *value, void *cb)
  34{
  35        if (!strcmp(var, "gc.rerereresolved"))
  36                cutoff_resolve = git_config_int(var, value);
  37        else if (!strcmp(var, "gc.rerereunresolved"))
  38                cutoff_noresolve = git_config_int(var, value);
  39        else
  40                return git_default_config(var, value, cb);
  41        return 0;
  42}
  43
  44static void garbage_collect(struct string_list *rr)
  45{
  46        struct string_list to_remove = { NULL, 0, 0, 1 };
  47        DIR *dir;
  48        struct dirent *e;
  49        int i, cutoff;
  50        time_t now = time(NULL), then;
  51
  52        git_config(git_rerere_gc_config, NULL);
  53        dir = opendir(git_path("rr-cache"));
  54        if (!dir)
  55                die_errno("unable to open rr-cache directory");
  56        while ((e = readdir(dir))) {
  57                if (is_dot_or_dotdot(e->d_name))
  58                        continue;
  59                then = rerere_created_at(e->d_name);
  60                if (!then)
  61                        continue;
  62                cutoff = (has_rerere_resolution(e->d_name)
  63                          ? cutoff_resolve : cutoff_noresolve);
  64                if (then < now - cutoff * 86400)
  65                        string_list_append(e->d_name, &to_remove);
  66        }
  67        for (i = 0; i < to_remove.nr; i++)
  68                unlink_rr_item(to_remove.items[i].string);
  69        string_list_clear(&to_remove, 0);
  70}
  71
  72static int outf(void *dummy, mmbuffer_t *ptr, int nbuf)
  73{
  74        int i;
  75        for (i = 0; i < nbuf; i++)
  76                if (write_in_full(1, ptr[i].ptr, ptr[i].size) != ptr[i].size)
  77                        return -1;
  78        return 0;
  79}
  80
  81static int diff_two(const char *file1, const char *label1,
  82                const char *file2, const char *label2)
  83{
  84        xpparam_t xpp;
  85        xdemitconf_t xecfg;
  86        xdemitcb_t ecb;
  87        mmfile_t minus, plus;
  88
  89        if (read_mmfile(&minus, file1) || read_mmfile(&plus, file2))
  90                return 1;
  91
  92        printf("--- a/%s\n+++ b/%s\n", label1, label2);
  93        fflush(stdout);
  94        memset(&xpp, 0, sizeof(xpp));
  95        xpp.flags = 0;
  96        memset(&xecfg, 0, sizeof(xecfg));
  97        xecfg.ctxlen = 3;
  98        ecb.outf = outf;
  99        xdi_diff(&minus, &plus, &xpp, &xecfg, &ecb);
 100
 101        free(minus.ptr);
 102        free(plus.ptr);
 103        return 0;
 104}
 105
 106int cmd_rerere(int argc, const char **argv, const char *prefix)
 107{
 108        struct string_list merge_rr = { NULL, 0, 0, 1 };
 109        int i, fd, autoupdate = -1, flags = 0;
 110
 111        struct option options[] = {
 112                OPT_SET_INT(0, "rerere-autoupdate", &autoupdate,
 113                        "register clean resolutions in index", 1),
 114                OPT_END(),
 115        };
 116
 117        argc = parse_options(argc, argv, prefix, options, rerere_usage, 0);
 118
 119        if (autoupdate == 1)
 120                flags = RERERE_AUTOUPDATE;
 121        if (autoupdate == 0)
 122                flags = RERERE_NOAUTOUPDATE;
 123
 124        if (argc < 1)
 125                return rerere(flags);
 126
 127        if (!strcmp(argv[0], "forget")) {
 128                const char **pathspec = get_pathspec(prefix, argv + 1);
 129                return rerere_forget(pathspec);
 130        }
 131
 132        fd = setup_rerere(&merge_rr, flags);
 133        if (fd < 0)
 134                return 0;
 135
 136        if (!strcmp(argv[0], "clear")) {
 137                for (i = 0; i < merge_rr.nr; i++) {
 138                        const char *name = (const char *)merge_rr.items[i].util;
 139                        if (!has_rerere_resolution(name))
 140                                unlink_rr_item(name);
 141                }
 142                unlink_or_warn(git_path("rr-cache/MERGE_RR"));
 143        } else if (!strcmp(argv[0], "gc"))
 144                garbage_collect(&merge_rr);
 145        else if (!strcmp(argv[0], "status"))
 146                for (i = 0; i < merge_rr.nr; i++)
 147                        printf("%s\n", merge_rr.items[i].string);
 148        else if (!strcmp(argv[0], "diff"))
 149                for (i = 0; i < merge_rr.nr; i++) {
 150                        const char *path = merge_rr.items[i].string;
 151                        const char *name = (const char *)merge_rr.items[i].util;
 152                        diff_two(rerere_path(name, "preimage"), path, path, path);
 153                }
 154        else
 155                usage_with_options(rerere_usage, options);
 156
 157        string_list_clear(&merge_rr, 1);
 158        return 0;
 159}