Show changes to 3 files +102 −60
builtin/rerere.c, rerere.c, rerere.h
diff --git a/builtin/rerere.c b/builtin/rerere.c
index e900e302c3..2c17f02f56 100644
--- a/builtin/rerere.c
+++ b/builtin/rerere.c
@@ -106,11 +106,15 @@ int cmd_rerere(int argc,
rerere_gc(the_repository, &merge_rr,
skip_locked ? RERERE_NOWAIT : 0);
else if (!strcmp(argv[0], "status")) {
- if (setup_rerere(the_repository, &merge_rr,
- flags | RERERE_READONLY) < 0)
+ struct rerere_cache cache;
+
+ if (rerere_cache_setup(&cache, the_repository, &merge_rr,
+ flags | RERERE_READONLY) < 0)
return 0;
for (size_t i = 0; i < merge_rr.nr; i++)
printf("%s\n", merge_rr.items[i].string);
+
+ rerere_cache_release(&cache);
} else if (!strcmp(argv[0], "remaining")) {
rerere_remaining(the_repository, &merge_rr);
for (size_t i = 0; i < merge_rr.nr; i++) {
@@ -123,8 +127,10 @@ int cmd_rerere(int argc,
}
} else if (!strcmp(argv[0], "diff")) {
struct strbuf buf = STRBUF_INIT;
- if (setup_rerere(the_repository, &merge_rr,
- flags | RERERE_READONLY) < 0)
+ struct rerere_cache cache;
+
+ if (rerere_cache_setup(&cache, the_repository, &merge_rr,
+ flags | RERERE_READONLY) < 0)
return 0;
for (size_t i = 0; i < merge_rr.nr; i++) {
const char *path = merge_rr.items[i].string;
@@ -135,6 +141,7 @@ int cmd_rerere(int argc,
rerere_path(the_repository, &buf, id, NULL));
}
+ rerere_cache_release(&cache);
strbuf_release(&buf);
} else
usage_with_options(rerere_usage, options);
diff --git a/rerere.c b/rerere.c
index 23bcb8bc31..e089761208 100644
--- a/rerere.c
+++ b/rerere.c
@@ -21,10 +21,6 @@
#include "odb.h"
#include "strmap.h"
-static struct rerere_cache cache = {
- .dirs = STRMAP_INIT,
-};
-
#define RESOLVED 0
#define PUNTED 1
#define THREE_STAGED 2
@@ -38,17 +34,19 @@ struct rerere_dir {
char name[FLEX_ARRAY];
};
-static void free_rerere_dirs(void)
+void rerere_cache_release(struct rerere_cache *cache)
{
struct hashmap_iter iter;
struct strmap_entry *ent;
- strmap_for_each_entry(&cache.dirs, &iter, ent) {
+ strmap_for_each_entry(&cache->dirs, &iter, ent) {
struct rerere_dir *rr_dir = ent->value;
free(rr_dir->status);
free(rr_dir);
}
- strmap_clear(&cache.dirs, 0);
+ strmap_clear(&cache->dirs, 0);
+
+ rollback_lock_file(&cache->write_lock);
}
static void free_rerere_id(struct string_list_item *item)
@@ -121,13 +119,13 @@ static int is_rr_file(const char *name, const char *filename, int *variant)
return 1;
}
-static void scan_rerere_dir(struct repository *r, struct rerere_dir *rr_dir)
+static void scan_rerere_dir(struct rerere_cache *cache, struct rerere_dir *rr_dir)
{
struct dirent *de;
char *path;
DIR *dir;
- path = repo_git_path(r, "rr-cache/%s", rr_dir->name);
+ path = repo_git_path(cache->repo, "rr-cache/%s", rr_dir->name);
dir = opendir(path);
free(path);
if (!dir)
@@ -146,19 +144,20 @@ static void scan_rerere_dir(struct repository *r, struct rerere_dir *rr_dir)
closedir(dir);
}
-static struct rerere_dir *find_rerere_dir(struct repository *r, const char *hex)
+static struct rerere_dir *find_rerere_dir(struct rerere_cache *cache,
+ const char *hex)
{
struct rerere_dir *rr_dir;
- rr_dir = strmap_get(&cache.dirs, hex);
+ rr_dir = strmap_get(&cache->dirs, hex);
if (!rr_dir) {
FLEX_ALLOC_STR(rr_dir, name, hex);
rr_dir->status = NULL;
rr_dir->status_nr = 0;
rr_dir->status_alloc = 0;
- strmap_put(&cache.dirs, hex, rr_dir);
+ strmap_put(&cache->dirs, hex, rr_dir);
- scan_rerere_dir(r, rr_dir);
+ scan_rerere_dir(cache, rr_dir);
}
return rr_dir;
}
@@ -173,17 +172,18 @@ static int has_rerere_resolution(const struct rerere_id *id)
return ((id->collection->status[variant] & both) == both);
}
-static struct rerere_id *new_rerere_id_hex(struct repository *r, char *hex)
+static struct rerere_id *new_rerere_id_hex(struct rerere_cache *cache,
+ char *hex)
{
struct rerere_id *id = xmalloc(sizeof(*id));
- id->collection = find_rerere_dir(r, hex);
+ id->collection = find_rerere_dir(cache, hex);
id->variant = -1; /* not known yet */
return id;
}
-static struct rerere_id *new_rerere_id(struct repository *r, unsigned char *hash)
+static struct rerere_id *new_rerere_id(struct rerere_cache *cache, unsigned char *hash)
{
- return new_rerere_id_hex(r, hash_to_hex_algop(hash, r->hash_algo));
+ return new_rerere_id_hex(cache, hash_to_hex_algop(hash, cache->repo->hash_algo));
}
/*
@@ -193,10 +193,10 @@ static struct rerere_id *new_rerere_id(struct repository *r, unsigned char *hash
* work on (i.e. what is left by the previous invocation of "git
* rerere" during the current conflict resolution session).
*/
-static void read_rr(struct repository *r, struct string_list *rr)
+static void read_rr(struct rerere_cache *cache, struct string_list *rr)
{
struct strbuf buf = STRBUF_INIT;
- FILE *in = fopen_or_warn(git_path_merge_rr(r), "r");
+ FILE *in = fopen_or_warn(git_path_merge_rr(cache->repo), "r");
if (!in)
return;
@@ -205,11 +205,11 @@ static void read_rr(struct repository *r, struct string_list *rr)
unsigned char hash[GIT_MAX_RAWSZ];
struct rerere_id *id;
int variant;
- const unsigned hexsz = r->hash_algo->hexsz;
+ const unsigned hexsz = cache->repo->hash_algo->hexsz;
/* There has to be the hash, tab, path and then NUL */
if (buf.len < hexsz + 2 ||
- get_hash_hex_algop(buf.buf, hash, r->hash_algo))
+ get_hash_hex_algop(buf.buf, hash, cache->repo->hash_algo))
die(_("corrupt MERGE_RR"));
if (buf.buf[hexsz] != '.') {
@@ -224,7 +224,7 @@ static void read_rr(struct repository *r, struct string_list *rr)
if (*(path++) != '\t')
die(_("corrupt MERGE_RR"));
buf.buf[hexsz] = '\0';
- id = new_rerere_id_hex(r, buf.buf);
+ id = new_rerere_id_hex(cache, buf.buf);
id->variant = variant;
/*
* make sure id->collection->status has enough space
@@ -237,7 +237,8 @@ static void read_rr(struct repository *r, struct string_list *rr)
fclose(in);
}
-static int write_rr(struct string_list *rr, int out_fd)
+static int write_rr(struct rerere_cache *cache,
+ struct string_list *rr, int out_fd)
{
int i;
for (i = 0; i < rr->nr; i++) {
@@ -264,7 +265,7 @@ static int write_rr(struct string_list *rr, int out_fd)
strbuf_release(&buf);
}
- if (commit_lock_file(&cache.write_lock) != 0)
+ if (commit_lock_file(&cache->write_lock) != 0)
die(_("unable to write rerere record"));
return 0;
}
@@ -564,12 +565,15 @@ static int find_conflict(struct repository *r, struct string_list *conflict)
*/
int rerere_remaining(struct repository *r, struct string_list *merge_rr)
{
- int i;
+ struct rerere_cache cache;
+ int ret, i;
- if (setup_rerere(r, merge_rr, RERERE_READONLY))
+ if (rerere_cache_setup(&cache, r, merge_rr, RERERE_READONLY))
return 0;
- if (repo_read_index(r) < 0)
- return error(_("index file corrupt"));
+ if (repo_read_index(r) < 0) {
+ ret = error(_("index file corrupt"));
+ goto out;
+ }
for (i = 0; i < r->index->cache_nr;) {
int conflict_type;
@@ -586,7 +590,12 @@ int rerere_remaining(struct repository *r, struct string_list *merge_rr)
}
}
}
- return 0;
+
+ ret = 0;
+
+out:
+ rerere_cache_release(&cache);
+ return ret;
}
/*
@@ -714,10 +723,11 @@ static void remove_variant(struct repository *r, struct rerere_id *id)
* only have the preimage for that conflict, in which case the result
* needs to be recorded as a resolution in a postimage file.
*/
-static void do_rerere_one_path(struct index_state *istate,
+static void do_rerere_one_path(struct rerere_cache *cache,
struct string_list_item *rr_item,
struct string_list *update)
{
+ struct index_state *istate = cache->repo->index;
const char *path = rr_item->string;
struct rerere_id *id = rr_item->util;
struct rerere_dir *rr_dir = id->collection;
@@ -779,7 +789,7 @@ static void do_rerere_one_path(struct index_state *istate,
if (0 <= id->variant && id->variant != variant)
remove_variant(istate->repo, id);
- if (cache.autoupdate)
+ if (cache->autoupdate)
string_list_insert(update, path);
else
fprintf_ln(stderr,
@@ -810,12 +820,13 @@ static void do_rerere_one_path(struct index_state *istate,
strbuf_release(&buf);
}
-static int do_plain_rerere(struct repository *r,
+static int do_plain_rerere(struct rerere_cache *cache,
struct string_list *rr, int fd)
{
struct string_list conflict = STRING_LIST_INIT_DUP;
struct string_list update = STRING_LIST_INIT_DUP;
struct strbuf buf = STRBUF_INIT;
+ struct repository *r = cache->repo;
int i;
find_conflict(r, &conflict);
@@ -845,7 +856,7 @@ static int do_plain_rerere(struct repository *r,
if (ret < 1)
continue;
- id = new_rerere_id(r, hash);
+ id = new_rerere_id(cache, hash);
string_list_insert(rr, path)->util = id;
/* Ensure that the directory exists. */
@@ -853,7 +864,7 @@ static int do_plain_rerere(struct repository *r,
}
for (i = 0; i < rr->nr; i++)
- do_rerere_one_path(r->index, &rr->items[i], &update);
+ do_rerere_one_path(cache, &rr->items[i], &update);
if (update.nr)
update_paths(r, &update);
@@ -861,7 +872,7 @@ static int do_plain_rerere(struct repository *r,
string_list_clear(&conflict, 0);
string_list_clear(&update, 0);
strbuf_release(&buf);
- return write_rr(rr, fd);
+ return write_rr(cache, rr, fd);
}
static int is_rerere_enabled(struct repository *r)
@@ -894,7 +905,10 @@ static int is_rerere_enabled(struct repository *r)
return r->rerere_cache_enabled;
}
-int setup_rerere(struct repository *r, struct string_list *merge_rr, int flags)
+int rerere_cache_setup(struct rerere_cache *cache,
+ struct repository *r,
+ struct string_list *merge_rr,
+ int flags)
{
int lock_timeout_ms = 1000;
int fd;
@@ -902,11 +916,14 @@ int setup_rerere(struct repository *r, struct string_list *merge_rr, int flags)
if (!is_rerere_enabled(r))
return -1;
- repo_config_get_bool(r, "rerere.autoupdate", &cache.autoupdate);
+ memset(cache, 0, sizeof(*cache));
+ cache->repo = r;
+ strmap_init(&cache->dirs);
+ repo_config_get_bool(r, "rerere.autoupdate", &cache->autoupdate);
repo_config_get_int(r, "rerere.locktimeout", &lock_timeout_ms);
if (flags & (RERERE_AUTOUPDATE|RERERE_NOAUTOUPDATE))
- cache.autoupdate = !!(flags & RERERE_AUTOUPDATE);
+ cache->autoupdate = !!(flags & RERERE_AUTOUPDATE);
if ((flags & RERERE_READONLY) && (flags & RERERE_NOWAIT))
BUG("RERERE_NOWAIT does not apply with RERERE_READONLY");
if (flags & RERERE_READONLY) {
@@ -924,13 +941,13 @@ int setup_rerere(struct repository *r, struct string_list *merge_rr, int flags)
* "git rerere gc" while it prunes rr-cache, so by default
* wait for it instead of dying right away.
*/
- fd = repo_hold_lock_file_for_update_timeout(r, &cache.write_lock,
+ fd = repo_hold_lock_file_for_update_timeout(r, &cache->write_lock,
git_path_merge_rr(r),
lock_flags, lock_timeout_ms);
if (fd < 0)
return -1;
}
- read_rr(r, merge_rr);
+ read_rr(cache, merge_rr);
return fd;
}
@@ -942,13 +959,15 @@ int setup_rerere(struct repository *r, struct string_list *merge_rr, int flags)
int repo_rerere(struct repository *r, int flags)
{
struct string_list merge_rr = STRING_LIST_INIT_DUP;
+ struct rerere_cache cache;
int fd, status;
- fd = setup_rerere(r, &merge_rr, flags);
+ fd = rerere_cache_setup(&cache, r, &merge_rr, flags);
if (fd < 0)
return 0;
- status = do_plain_rerere(r, &merge_rr, fd);
- free_rerere_dirs();
+ status = do_plain_rerere(&cache, &merge_rr, fd);
+
+ rerere_cache_release(&cache);
string_list_clear(&merge_rr, 1);
return status;
}
@@ -1057,10 +1076,11 @@ static int handle_cache(struct index_state *istate,
return has_conflicts;
}
-static int rerere_forget_one_path(struct index_state *istate,
+static int rerere_forget_one_path(struct rerere_cache *cache,
const char *path,
struct string_list *rr)
{
+ struct index_state *istate = cache->repo->index;
const char *filename;
struct rerere_id *id;
unsigned char hash[GIT_MAX_RAWSZ];
@@ -1077,7 +1097,7 @@ static int rerere_forget_one_path(struct index_state *istate,
return error(_("could not parse conflict hunks in '%s'"), path);
/* Nuke the recorded resolution for the conflict */
- id = new_rerere_id(istate->repo, hash);
+ id = new_rerere_id(cache, hash);
for (id->variant = 0;
id->variant < id->collection->status_nr;
@@ -1145,11 +1165,12 @@ int rerere_forget(struct repository *r, struct pathspec *pathspec)
int i, fd, ret;
struct string_list conflict = STRING_LIST_INIT_DUP;
struct string_list merge_rr = STRING_LIST_INIT_DUP;
+ struct rerere_cache cache;
if (repo_read_index(r) < 0)
return error(_("index file corrupt"));
- fd = setup_rerere(r, &merge_rr, RERERE_NOAUTOUPDATE);
+ fd = rerere_cache_setup(&cache, r, &merge_rr, RERERE_NOAUTOUPDATE);
if (fd < 0)
return 0;
@@ -1165,13 +1186,14 @@ int rerere_forget(struct repository *r, struct pathspec *pathspec)
if (!match_pathspec(r->index, pathspec, it->string,
strlen(it->string), 0, NULL, 0))
continue;
- rerere_forget_one_path(r->index, it->string, &merge_rr);
+ rerere_forget_one_path(&cache, it->string, &merge_rr);
}
- ret = write_rr(&merge_rr, fd);
+ ret = write_rr(&cache, &merge_rr, fd);
string_list_clear(&conflict, 0);
string_list_clear(&merge_rr, 1);
+ rerere_cache_release(&cache);
return ret;
}
@@ -1267,6 +1289,10 @@ static int is_rr_cache_dirname(struct repository *r, const char *path)
bool rerere_gc_needed(struct repository *r, size_t limit)
{
+ struct rerere_cache cache = {
+ .repo = r,
+ .dirs = STRMAP_INIT,
+ };
timestamp_t cutoff_resolve, cutoff_noresolve;
struct strbuf buf = STRBUF_INIT;
bool needed = false;
@@ -1292,7 +1318,7 @@ bool rerere_gc_needed(struct repository *r, size_t limit)
!is_rr_cache_dirname(r, e->d_name))
continue;
- id.collection = find_rerere_dir(r, e->d_name);
+ id.collection = find_rerere_dir(&cache, e->d_name);
for (id.variant = 0;
id.variant < id.collection->status_nr;
id.variant++) {
@@ -1310,13 +1336,14 @@ bool rerere_gc_needed(struct repository *r, size_t limit)
out:
if (dir)
closedir(dir);
- free_rerere_dirs();
+ rerere_cache_release(&cache);
strbuf_release(&buf);
return needed;
}
void rerere_gc(struct repository *r, struct string_list *rr, int flags)
{
+ struct rerere_cache cache;
struct string_list to_remove = STRING_LIST_INIT_DUP;
DIR *dir;
struct dirent *e;
@@ -1325,7 +1352,7 @@ void rerere_gc(struct repository *r, struct string_list *rr, int flags)
timestamp_t cutoff_resolve;
struct strbuf buf = STRBUF_INIT;
- if (setup_rerere(r, rr, flags) < 0)
+ if (rerere_cache_setup(&cache, r, rr, flags) < 0)
return;
rerere_gc_cutoffs(r, &cutoff_resolve, &cutoff_noresolve);
@@ -1342,7 +1369,7 @@ void rerere_gc(struct repository *r, struct string_list *rr, int flags)
if (!is_rr_cache_dirname(r, e->d_name))
continue; /* or should we remove e->d_name? */
- rr_dir = find_rerere_dir(r, e->d_name);
+ rr_dir = find_rerere_dir(&cache, e->d_name);
now_empty = 1;
for (id.variant = 0, id.collection = rr_dir;
@@ -1363,7 +1390,7 @@ void rerere_gc(struct repository *r, struct string_list *rr, int flags)
"rr-cache/%s", to_remove.items[i].string));
string_list_clear(&to_remove, 0);
- rollback_lock_file(&cache.write_lock);
+ rerere_cache_release(&cache);
strbuf_release(&buf);
}
@@ -1376,9 +1403,10 @@ void rerere_gc(struct repository *r, struct string_list *rr, int flags)
*/
void rerere_clear(struct repository *r, struct string_list *merge_rr)
{
+ struct rerere_cache cache;
int i;
- if (setup_rerere(r, merge_rr, 0) < 0)
+ if (rerere_cache_setup(&cache, r, merge_rr, 0) < 0)
return;
for (i = 0; i < merge_rr->nr; i++) {
@@ -1393,5 +1421,5 @@ void rerere_clear(struct repository *r, struct string_list *merge_rr)
strbuf_release(&buf);
}
unlink_or_warn(git_path_merge_rr(r));
- rollback_lock_file(&cache.write_lock);
+ rerere_cache_release(&cache);
}
diff --git a/rerere.h b/rerere.h
index 570667d866..d3cbd10e13 100644
--- a/rerere.h
+++ b/rerere.h
@@ -23,6 +23,8 @@ struct repository;
extern void *RERERE_RESOLVED;
struct rerere_cache {
+ struct repository *repo;
+
/* Automatically update cleanly resolved paths to the index. */
int autoupdate;
@@ -37,7 +39,12 @@ struct rerere_id {
int variant;
};
-int setup_rerere(struct repository *,struct string_list *, int);
+int rerere_cache_setup(struct rerere_cache *cache,
+ struct repository *r,
+ struct string_list *merge_rr,
+ int flags);
+void rerere_cache_release(struct rerere_cache *cache);
+
int repo_rerere(struct repository *, int);
/*
* Given the conflict ID and the name of a "file" used for replaying