diff options
author | Junio C Hamano <gitster@pobox.com> | 2015-06-30 22:40:35 -0700 |
---|---|---|
committer | Junio C Hamano <gitster@pobox.com> | 2015-07-24 16:02:17 -0700 |
commit | cc899eca552a9b93788e6bca34aa0e4d86b251a0 (patch) | |
tree | 2e75fd380fc70467c120de0f3aacd06ab44c2cd4 /rerere.c | |
parent | 4b68c2a0877b18d1fe591dd7aee55aa1158fada0 (diff) | |
download | git-cc899eca552a9b93788e6bca34aa0e4d86b251a0.tar.gz |
rerere: explain the primary codepath
Explain the internals of rerere as in-code comments, while
sprinkling "NEEDSWORK" comment to highlight iffy bits and
questionable assumptions.
This one covers the codepath reached from rerere(), the primary
interface to the subsystem.
Signed-off-by: Junio C Hamano <gitster@pobox.com>
Diffstat (limited to 'rerere.c')
-rw-r--r-- | rerere.c | 95 |
1 files changed, 82 insertions, 13 deletions
@@ -206,6 +206,21 @@ static int is_cmarker(char *buf, int marker_char, int marker_size) return isspace(*buf); } +/* + * Read contents a file with conflicts, normalize the conflicts + * by (1) discarding the common ancestor version in diff3-style, + * (2) reordering our side and their side so that whichever sorts + * alphabetically earlier comes before the other one, while + * computing the "conflict ID", which is just an SHA-1 hash of + * one side of the conflict, NUL, the other side of the conflict, + * and NUL concatenated together. + * + * Return the number of conflict hunks found. + * + * NEEDSWORK: the logic and theory of operation behind this conflict + * normalization may deserve to be documented somewhere, perhaps in + * Documentation/technical/rerere.txt. + */ static int handle_path(unsigned char *sha1, struct rerere_io *io, int marker_size) { git_SHA_CTX ctx; @@ -276,6 +291,10 @@ static int handle_path(unsigned char *sha1, struct rerere_io *io, int marker_siz return hunk_no; } +/* + * Scan the path for conflicts, do the "handle_path()" thing above, and + * return the number of conflict hunks found. + */ static int handle_file(const char *path, unsigned char *sha1, const char *output) { int hunk_no = 0; @@ -515,29 +534,54 @@ int rerere_remaining(struct string_list *merge_rr) return 0; } +/* + * Find the conflict identified by "name"; the change between its + * "preimage" (i.e. a previous contents with conflict markers) and its + * "postimage" (i.e. the corresponding contents with conflicts + * resolved) may apply cleanly to the contents stored in "path", i.e. + * the conflict this time around. + * + * Returns 0 for successful replay of recorded resolution, or non-zero + * for failure. + */ static int merge(const char *name, const char *path) { int ret; mmfile_t cur = {NULL, 0}, base = {NULL, 0}, other = {NULL, 0}; mmbuffer_t result = {NULL, 0}; + /* + * Normalize the conflicts in path and write it out to + * "thisimage" temporary file. + */ if (handle_file(path, NULL, rerere_path(name, "thisimage")) < 0) return 1; if (read_mmfile(&cur, rerere_path(name, "thisimage")) || - read_mmfile(&base, rerere_path(name, "preimage")) || - read_mmfile(&other, rerere_path(name, "postimage"))) { + read_mmfile(&base, rerere_path(name, "preimage")) || + read_mmfile(&other, rerere_path(name, "postimage"))) { ret = 1; goto out; } + + /* + * A three-way merge. Note that this honors user-customizable + * low-level merge driver settings. + */ ret = ll_merge(&result, path, &base, NULL, &cur, "", &other, "", NULL); if (!ret) { FILE *f; + /* + * A successful replay of recorded resolution. + * Mark that "postimage" was used to help gc. + */ if (utime(rerere_path(name, "postimage"), NULL) < 0) warning("failed utime() on %s: %s", rerere_path(name, "postimage"), strerror(errno)); + + /* Update "path" with the resolution */ f = fopen(path, "w"); if (!f) return error("Could not open %s: %s", path, @@ -590,41 +634,61 @@ static int do_plain_rerere(struct string_list *rr, int fd) find_conflict(&conflict); /* - * MERGE_RR records paths with conflicts immediately after merge - * failed. Some of the conflicted paths might have been hand resolved - * in the working tree since then, but the initial run would catch all - * and register their preimages. + * MERGE_RR records paths with conflicts immediately after + * merge failed. Some of the conflicted paths might have been + * hand resolved in the working tree since then, but the + * initial run would catch all and register their preimages. */ - for (i = 0; i < conflict.nr; i++) { const char *path = conflict.items[i].string; if (!string_list_has_string(rr, path)) { unsigned char sha1[20]; char *hex; int ret; + + /* + * Ask handle_file() to scan and assign a + * conflict ID. No need to write anything out + * yet. + */ ret = handle_file(path, sha1, NULL); if (ret < 1) continue; hex = xstrdup(sha1_to_hex(sha1)); string_list_insert(rr, path)->util = hex; + + /* + * If the directory does not exist, create + * it. mkdir_in_gitdir() will fail with + * EEXIST if there already is one. + * + * NEEDSWORK: make sure "gc" does not remove + * preimage without removing the directory. + */ if (mkdir_in_gitdir(git_path("rr-cache/%s", hex))) continue; + + /* + * We are the first to encounter this + * conflict. Ask handle_file() to write the + * normalized contents to the "preimage" file. + */ handle_file(path, NULL, rerere_path(hex, "preimage")); fprintf(stderr, "Recorded preimage for '%s'\n", path); } } /* - * Now some of the paths that had conflicts earlier might have been - * hand resolved. Others may be similar to a conflict already that - * was resolved before. + * Some of the paths that had conflicts earlier might have + * been resolved by the user. Others may be similar to a + * conflict already that was resolved before. */ - for (i = 0; i < rr->nr; i++) { int ret; const char *path = rr->items[i].string; const char *name = (const char *)rr->items[i].util; + /* Is there a recorded resolution we could attempt to apply? */ if (has_rerere_resolution(name)) { if (merge(name, path)) continue; @@ -638,13 +702,13 @@ static int do_plain_rerere(struct string_list *rr, int fd) goto mark_resolved; } - /* Let's see if we have resolved it. */ + /* Let's see if the user has resolved it. */ ret = handle_file(path, NULL, NULL); if (ret) continue; - fprintf(stderr, "Recorded resolution for '%s'.\n", path); copy_file(rerere_path(name, "postimage"), path, 0666); + fprintf(stderr, "Recorded resolution for '%s'.\n", path); mark_resolved: free(rr->items[i].util); rr->items[i].util = NULL; @@ -698,6 +762,11 @@ int setup_rerere(struct string_list *merge_rr, int flags) return fd; } +/* + * The main entry point that is called internally from codepaths that + * perform mergy operations, possibly leaving conflicted index entries + * and working tree files. + */ int rerere(int flags) { struct string_list merge_rr = STRING_LIST_INIT_DUP; |