diff options
-rw-r--r-- | Documentation/config.txt | 5 | ||||
-rw-r--r-- | builtin-rerere.c | 37 | ||||
-rwxr-xr-x | t/t4200-rerere.sh | 10 |
3 files changed, 52 insertions, 0 deletions
diff --git a/Documentation/config.txt b/Documentation/config.txt index 5331b450ea..0c7cf618ed 100644 --- a/Documentation/config.txt +++ b/Documentation/config.txt @@ -650,6 +650,11 @@ gc.rerereunresolved:: kept for this many days when `git rerere gc` is run. The default is 15 days. See linkgit:git-rerere[1]. +rerere.autoupdate:: + When set to true, `git-rerere` updates the index with the + resulting contents after it cleanly resolves conflicts using + previously recorded resolution. Defaults to false. + rerere.enabled:: Activate recording of resolved conflicts, so that identical conflict hunks can be resolved automatically, should they diff --git a/builtin-rerere.c b/builtin-rerere.c index 0eec1f9373..839b26e8e0 100644 --- a/builtin-rerere.c +++ b/builtin-rerere.c @@ -16,6 +16,9 @@ static int cutoff_resolve = 60; /* if rerere_enabled == -1, fall back to detection of .git/rr-cache */ static int rerere_enabled = -1; +/* automatically update cleanly resolved paths to the index */ +static int rerere_autoupdate; + static char *merge_rr_path; static const char *rr_path(const char *name, const char *file) @@ -276,9 +279,36 @@ static int diff_two(const char *file1, const char *label1, return 0; } +static struct lock_file index_lock; + +static int update_paths(struct path_list *update) +{ + int i; + int fd = hold_locked_index(&index_lock, 0); + int status = 0; + + if (fd < 0) + return -1; + + for (i = 0; i < update->nr; i++) { + struct path_list_item *item = &update->items[i]; + if (add_file_to_cache(item->path, ADD_CACHE_IGNORE_ERRORS)) + status = -1; + } + + if (!status && active_cache_changed) { + if (write_cache(fd, active_cache, active_nr) || + commit_locked_index(&index_lock)) + die("Unable to write new index file"); + } else if (fd >= 0) + rollback_lock_file(&index_lock); + return status; +} + static int do_plain_rerere(struct path_list *rr, int fd) { struct path_list conflict = { NULL, 0, 0, 1 }; + struct path_list update = { NULL, 0, 0, 1 }; int i; find_conflict(&conflict); @@ -323,6 +353,8 @@ static int do_plain_rerere(struct path_list *rr, int fd) if (!merge(name, path)) { fprintf(stderr, "Resolved '%s' using " "previous resolution.\n", path); + if (rerere_autoupdate) + path_list_insert(path, &update); goto mark_resolved; } } @@ -338,6 +370,9 @@ static int do_plain_rerere(struct path_list *rr, int fd) rr->items[i].util = NULL; } + if (update.nr) + update_paths(&update); + return write_rr(rr, fd); } @@ -349,6 +384,8 @@ static int git_rerere_config(const char *var, const char *value, void *cb) cutoff_noresolve = git_config_int(var, value); else if (!strcmp(var, "rerere.enabled")) rerere_enabled = git_config_bool(var, value); + else if (!strcmp(var, "rerere.autoupdate")) + rerere_autoupdate = git_config_bool(var, value); else return git_default_config(var, value, cb); return 0; diff --git a/t/t4200-rerere.sh b/t/t4200-rerere.sh index afb3e3d176..a64727d5ad 100755 --- a/t/t4200-rerere.sh +++ b/t/t4200-rerere.sh @@ -193,9 +193,19 @@ test_expect_success 'resolution was recorded properly' ' echo Bello > file3 && git add file3 && git commit -m version2 && + git tag version2 && test_must_fail git merge fifth && test Cello = "$(cat file3)" && test 0 != $(git ls-files -u | wc -l) ' +test_expect_success 'rerere.autoupdate' ' + git config rerere.autoupdate true + git reset --hard && + git checkout version2 && + test_must_fail git merge fifth && + test 0 = $(git ls-files -u | wc -l) + +' + test_done |