No, no no, no. You do not have to.
As long as you can find out the <preimage,postimage> pair, iow, the subdirectory used by .git/rr-cache/, you can remove only "postimage" from there and redo your merge. "ls -t1 .git/rr-cache/*/thisimage | head" would be one way to manually find out which one it is.
For example, let's take this merge as an example.
commit 697eb20061dfa00838df32ac24c414dfb4a1f920
Merge: bba637b 46b77a6
Author: Junio C Hamano <gitster@pobox.com>
Merge branch 'jk/1.7.0-status' into jch
You may not have rerere entries for this, so follow me along for a while.
$ git checkout bba637b
$ git merge 46b77a6
This will have a conflict. We are priming your rerere database, so we cheat (notice the last dot ".").
$ git checkout 697eb200 -- .
$ git rerere
Now reset it away, and redo the merge
$ git reset --hard
$ git checkout bba637b
$ git merge 46b77a6
It will autoresolve the way I resolved in 697eb200
Suppose you do not like the resolution; you can do:
$ git checkout --conflict=merge Documentation/git-commit.txt
$ git rerereto force updating "thisimage". The newest one is the entry you are looking for.
$ ls -1t .git/rr-cache/*/thisimage | head -n 1
.git/rr-cache/02aac459b0c777f92a8ca6f1e449e6760d366c20/thisimageI can remove "postimage" from the directory, recreate conflict again, run rerere to remember it anew, resolve and have rerere remember the new resolution.
A tool support to compute the conflict hash would be part of a nice solution.
$ git checkout --conflict=merge Documentation/git-commit.txt
$ git rerere hash
02aac459b0c777f92a8ca6f1e449e6760d366c20 Documentation/git-commit.txt Instead of giving "hash" subcommand and having the user to remove postimage from the directory, the tool can remove it, of course.
$ git checkout --conflict=merge Documentation/git-commit.txt
$ git rerere forget Documentation/git-commit.txt
02aac459b0c777f92a8ca6f1e449e6760d366c20 Documentation/git-commit.txt
$ edit Documentation/git-commit.txt ;# come up with a better resolution
$ git rerere ;# record itThe attached are rough sketch of such "hash/forget" subcommands.
I however think the best user experience would go like this:
* Run "git merge"; rerere replays an earlier resolution.
$ git merge ...
User decides that it is not a desirable one.
* User fixes it and creates a better resolution in the work tree. The
user may fix-up the autoresolution or the user may first do "checkout
--conflict=merge" and resolves the conflict from scratch.
It does not matter how the updated resolution is prepared in the work
tree.
* Then the user tells rerere that "this is the corrected resolution",
perhaps
$ git rerere update Documentation/git-commit.txt
This will
- Internally recompute the original conflicted state, i.e. run
"checkout --conflict=merge Documentation/git-commit.txt" in-core; - feed it to rerere.c::handle_file() to learn the conflict hash;
- read the user's updated resolution from the work tree, and update
"postimage" with it.There is no need to change MERGE_RR at all if you did it the way outlined in the above.
My "hash" would be more-or-less a useless command. It still might be useful as a plumbing command, but it is mostly for debugging.
The "forget" subcommand may be useful, but the real implementation should be the first half of the "update", iow, recreate conflict in-core in order to compute the conflict hash, and drop existing "postimage", without replacing it from the work tree. We should leave it up to the user using "checkout --conflict" to reproduce the conflict in the work tree.
builtin-rerere.c | 4 +++
rerere.c | 58 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
rerere.h | 2 +
3 files changed, 64 insertions(+), 0 deletions(-)
Show changes to 3 files +64 −0
builtin-rerere.c, rerere.c, rerere.h
diff --git a/builtin-rerere.c b/builtin-rerere.c
index 343d6cd..8865313 100644
--- a/builtin-rerere.c
+++ b/builtin-rerere.c
@@ -108,6 +108,10 @@ int cmd_rerere(int argc, const char **argv, const char *prefix)
if (!strcmp(argv[1], "-h"))
usage(git_rerere_usage);
+ else if (!strcmp(argv[1], "hash"))
+ return rerere_report_hash();
+ else if (!strcmp(argv[1], "forget"))
+ return rerere_forget(argv + 2);
fd = setup_rerere(&merge_rr);
if (fd < 0)
diff --git a/rerere.c b/rerere.c
index 29f95f6..4899219 100644
--- a/rerere.c
+++ b/rerere.c
@@ -392,3 +392,61 @@ int rerere(void)
return 0;
return do_plain_rerere(&merge_rr, fd);
}
+
+int rerere_forget(const char **path)
+{
+ struct string_list conflict = { NULL, 0, 0, 1 };
+ int i;
+
+ find_conflict(&conflict);
+
+ /*
+ * Note note note. I am being lazy here. The loop should not
+ * iterate over "path" like this.
+ *
+ * It should instead iterate over conflict entries, using "path"
+ * as pathspec to filter, so that you can say "I am done with
+ * all the conflict in Documentation/ area".
+ */
+ for (i = 0; path[i]; i++) {
+ unsigned char sha1[20];
+ const char *postimage;
+ int ret;
+
+ if (!string_list_has_string(&conflict, path[i])) {
+ error("No such conflicted path %s\n", path[i]);
+ continue;
+ }
+ ret = handle_file(path[i], sha1, NULL);
+ if (ret < 1) {
+ error("No conflict in work tree %s\n", path[i]);
+ continue;
+ }
+ postimage = rerere_path(sha1_to_hex(sha1), "postimage");
+ if (!unlink(postimage))
+ fprintf(stderr, "forgot resolution for %s\n", path[i]);
+ else if (errno == ENOENT)
+ error("no remembered resolution for %s", path[i]);
+ else
+ error("cannot unlink %s: %s", postimage, strerror(errno));
+ }
+ return 0;
+}
+
+int rerere_report_hash(void)
+{
+ struct string_list conflict = { NULL, 0, 0, 1 };
+ int i;
+
+ find_conflict(&conflict);
+ for (i = 0; i < conflict.nr; i++) {
+ const char *path = conflict.items[i].string;
+ unsigned char sha1[20];
+ int ret;
+ ret = handle_file(path, sha1, NULL);
+ if (ret < 1)
+ continue;
+ printf("%s %s\n", sha1_to_hex(sha1), path);
+ }
+ return 0;
+}
diff --git a/rerere.h b/rerere.h
index 13313f3..a10dea9 100644
--- a/rerere.h
+++ b/rerere.h
@@ -7,5 +7,7 @@ extern int setup_rerere(struct string_list *);
extern int rerere(void);
extern const char *rerere_path(const char *hex, const char *file);
extern int has_rerere_resolution(const char *hex);
+extern int rerere_report_hash(void);
+extern int rerere_forget(const char **path);
#endif