From: Junio C Hamano Date: Fri, 19 Oct 2018 04:34:02 +0000 (+0900) Subject: Merge branch 'nd/the-index' X-Git-Tag: v2.20.0-rc0~164 X-Git-Url: https://git.lorimer.id.au/gitweb.git/diff_plain/11877b9ebec87175a9cc55676311ef2d98585cca?ds=inline;hp=-c Merge branch 'nd/the-index' Various codepaths in the core-ish part learn to work on an arbitrary in-core index structure, not necessarily the default instance "the_index". * nd/the-index: (23 commits) revision.c: reduce implicit dependency the_repository revision.c: remove implicit dependency on the_index ws.c: remove implicit dependency on the_index tree-diff.c: remove implicit dependency on the_index submodule.c: remove implicit dependency on the_index line-range.c: remove implicit dependency on the_index userdiff.c: remove implicit dependency on the_index rerere.c: remove implicit dependency on the_index sha1-file.c: remove implicit dependency on the_index patch-ids.c: remove implicit dependency on the_index merge.c: remove implicit dependency on the_index merge-blobs.c: remove implicit dependency on the_index ll-merge.c: remove implicit dependency on the_index diff-lib.c: remove implicit dependency on the_index read-cache.c: remove implicit dependency on the_index diff.c: remove implicit dependency on the_index grep.c: remove implicit dependency on the_index diff.c: remove the_index dependency in textconv() functions blame.c: rename "repo" argument to "r" combine-diff.c: remove implicit dependency on the_index ... --- 11877b9ebec87175a9cc55676311ef2d98585cca diff --combined archive.c index c1870105eb,994495af05..9d16b7fadf --- a/archive.c +++ b/archive.c @@@ -110,8 -110,7 +110,8 @@@ static const struct attr_check *get_arc static struct attr_check *check; if (!check) check = attr_check_initl("export-ignore", "export-subst", NULL); - return git_check_attr(istate, path, check) ? NULL : check; + git_check_attr(istate, path, check); + return check; } static int check_attr_export_ignore(const struct attr_check *check) @@@ -392,7 -391,7 +392,7 @@@ static void parse_treeish_arg(const cha if (get_oid(name, &oid)) die("Not a valid object name"); - commit = lookup_commit_reference_gently(the_repository, &oid, 1); + commit = lookup_commit_reference_gently(ar_args->repo, &oid, 1); if (commit) { commit_sha1 = commit->object.oid.hash; archive_time = commit->date; diff --combined bisect.c index e8b17cf7e1,6ae5e5b49e..487675c672 --- a/bisect.c +++ b/bisect.c @@@ -13,8 -13,6 +13,8 @@@ #include "sha1-array.h" #include "argv-array.h" #include "commit-slab.h" +#include "commit-reach.h" +#include "object-store.h" static struct oid_array good_revs; static struct oid_array skipped_revs; @@@ -122,14 -120,14 +122,14 @@@ static inline int halfway(struct commit } } -#if !DEBUG_BISECT -#define show_list(a,b,c,d) do { ; } while (0) -#else static void show_list(const char *debug, int counted, int nr, struct commit_list *list) { struct commit_list *p; + if (!DEBUG_BISECT) + return; + fprintf(stderr, "%s (%d/%d)\n", debug, counted, nr); for (p = list; p; p = p->next) { @@@ -147,7 -145,7 +147,7 @@@ (flags & TREESAME) ? ' ' : 'T', (flags & UNINTERESTING) ? 'U' : ' ', (flags & COUNTED) ? 'C' : ' '); - if (commit->util) + if (*commit_weight_at(&commit_weight, p->item)) fprintf(stderr, "%3d", weight(p)); else fprintf(stderr, "---"); @@@ -162,6 -160,7 +162,6 @@@ fprintf(stderr, "\n"); } } -#endif /* DEBUG_BISECT */ static struct commit_list *best_bisection(struct commit_list *list, int nr) { @@@ -596,7 -595,7 +596,7 @@@ static struct commit_list *skip_away(st for (i = 0; cur; cur = cur->next, i++) { if (i == index) { - if (oidcmp(&cur->item->object.oid, current_bad_oid)) + if (!oideq(&cur->item->object.oid, current_bad_oid)) return cur; if (previous) return previous; @@@ -633,7 -632,7 +633,7 @@@ static void bisect_rev_setup(struct rev struct argv_array rev_argv = ARGV_ARRAY_INIT; int i; - init_revisions(revs, prefix); + repo_init_revisions(the_repository, revs, prefix); revs->abbrev = 0; revs->commit_format = CMIT_FMT_UNSPECIFIED; @@@ -808,7 -807,7 +808,7 @@@ static void check_merge_bases(int rev_n for (; result; result = result->next) { const struct object_id *mb = &result->item->object.oid; - if (!oidcmp(mb, current_bad_oid)) { + if (oideq(mb, current_bad_oid)) { handle_bad_merge_base(); } else if (0 <= oid_array_lookup(&good_revs, mb)) { continue; @@@ -890,7 -889,7 +890,7 @@@ static void show_diff_tree(const char * struct rev_info opt; /* diff-tree init */ - init_revisions(&opt, prefix); + repo_init_revisions(the_repository, &opt, prefix); git_config(git_diff_basic_config, NULL); /* no "diff" UI options */ opt.abbrev = 0; opt.diff = 1; @@@ -989,7 -988,7 +989,7 @@@ int bisect_next_all(const char *prefix bisect_rev = &revs.commits->item->object.oid; - if (!oidcmp(bisect_rev, current_bad_oid)) { + if (oideq(bisect_rev, current_bad_oid)) { exit_if_skipped_commits(tried, current_bad_oid); printf("%s is the first %s commit\n", oid_to_hex(bisect_rev), term_bad); diff --combined blame.c index d5f7b7237c,c229a10c0e..d84c937780 --- a/blame.c +++ b/blame.c @@@ -90,7 -90,7 +90,7 @@@ static struct blame_origin *get_origin( - static void verify_working_tree_path(struct repository *repo, + static void verify_working_tree_path(struct repository *r, struct commit *work_tree, const char *path) { struct commit_list *parents; @@@ -102,15 -102,15 +102,15 @@@ unsigned mode; if (!get_tree_entry(commit_oid, path, &blob_oid, &mode) && - oid_object_info(repo, &blob_oid, NULL) == OBJ_BLOB) + oid_object_info(r, &blob_oid, NULL) == OBJ_BLOB) return; } - pos = index_name_pos(repo->index, path, strlen(path)); + pos = index_name_pos(r->index, path, strlen(path)); if (pos >= 0) ; /* path is in the index */ - else if (-1 - pos < repo->index->cache_nr && - !strcmp(repo->index->cache[-1 - pos]->name, path)) + else if (-1 - pos < r->index->cache_nr && + !strcmp(r->index->cache[-1 - pos]->name, path)) ; /* path is in the index, unmerged */ else die("no such path '%s' in HEAD", path); @@@ -166,7 -166,7 +166,7 @@@ static void set_commit_buffer_from_strb * Prepare a dummy commit that represents the work tree (or staged) item. * Note that annotating work tree item never works in the reverse. */ - static struct commit *fake_working_tree_commit(struct repository *repo, + static struct commit *fake_working_tree_commit(struct repository *r, struct diff_options *opt, const char *path, const char *contents_from) @@@ -183,7 -183,7 +183,7 @@@ unsigned mode; struct strbuf msg = STRBUF_INIT; - read_index(repo->index); + read_index(r->index); time(&now); commit = alloc_commit_node(the_repository); commit->object.parsed = 1; @@@ -195,7 -195,7 +195,7 @@@ parent_tail = append_parent(parent_tail, &head_oid); append_merge_parents(parent_tail); - verify_working_tree_path(repo, commit, path); + verify_working_tree_path(r, commit, path); origin = make_origin(commit, path); @@@ -234,7 -234,7 +234,7 @@@ switch (st.st_mode & S_IFMT) { case S_IFREG: if (opt->flags.allow_textconv && - textconv_object(read_from, mode, &null_oid, 0, &buf_ptr, &buf_len)) + textconv_object(r, read_from, mode, &null_oid, 0, &buf_ptr, &buf_len)) strbuf_attach(&buf, buf_ptr, buf_len, buf_len + 1); else if (strbuf_read_file(&buf, read_from, st.st_size) != st.st_size) die_errno("cannot open or read '%s'", read_from); @@@ -253,7 -253,7 +253,7 @@@ if (strbuf_read(&buf, 0, 0) < 0) die_errno("failed to read from stdin"); } - convert_to_git(repo->index, path, buf.buf, buf.len, &buf, 0); + convert_to_git(r->index, path, buf.buf, buf.len, &buf, 0); origin->file.ptr = buf.buf; origin->file.size = buf.len; pretend_object_file(buf.buf, buf.len, OBJ_BLOB, &origin->blob_oid); @@@ -264,28 -264,28 +264,28 @@@ * bits; we are not going to write this index out -- we just * want to run "diff-index --cached". */ - discard_index(repo->index); - read_index(repo->index); + discard_index(r->index); + read_index(r->index); len = strlen(path); if (!mode) { - int pos = index_name_pos(repo->index, path, len); + int pos = index_name_pos(r->index, path, len); if (0 <= pos) - mode = repo->index->cache[pos]->ce_mode; + mode = r->index->cache[pos]->ce_mode; else /* Let's not bother reading from HEAD tree */ mode = S_IFREG | 0644; } - ce = make_empty_cache_entry(repo->index, len); + ce = make_empty_cache_entry(r->index, len); oidcpy(&ce->oid, &origin->blob_oid); memcpy(ce->name, path, len); ce->ce_flags = create_ce_flags(0); ce->ce_namelen = len; ce->ce_mode = create_ce_mode(mode); - add_index_entry(repo->index, ce, + add_index_entry(r->index, ce, ADD_CACHE_OK_TO_ADD | ADD_CACHE_OK_TO_REPLACE); - cache_tree_invalidate_path(repo->index, path); + cache_tree_invalidate_path(r->index, path); return commit; } @@@ -318,7 -318,8 +318,8 @@@ static void fill_origin_blob(struct dif (*num_read_blob)++; if (opt->flags.allow_textconv && - textconv_object(o->path, o->mode, &o->blob_oid, 1, &file->ptr, &file_size)) + textconv_object(opt->repo, o->path, o->mode, + &o->blob_oid, 1, &file->ptr, &file_size)) ; else file->ptr = read_object_file(&o->blob_oid, &type, @@@ -520,14 -521,14 +521,14 @@@ static void queue_blames(struct blame_s * * This also fills origin->mode for corresponding tree path. */ - static int fill_blob_sha1_and_mode(struct repository *repo, + static int fill_blob_sha1_and_mode(struct repository *r, struct blame_origin *origin) { if (!is_null_oid(&origin->blob_oid)) return 0; if (get_tree_entry(&origin->commit->object.oid, origin->path, &origin->blob_oid, &origin->mode)) goto error_out; - if (oid_object_info(repo, &origin->blob_oid, NULL) != OBJ_BLOB) + if (oid_object_info(r, &origin->blob_oid, NULL) != OBJ_BLOB) goto error_out; return 0; error_out: @@@ -540,8 -541,9 +541,9 @@@ * We have an origin -- check if the same path exists in the * parent and return an origin structure to represent it. */ - static struct blame_origin *find_origin(struct commit *parent, - struct blame_origin *origin) + static struct blame_origin *find_origin(struct repository *r, + struct commit *parent, + struct blame_origin *origin) { struct blame_origin *porigin; struct diff_options diff_opts; @@@ -561,7 -563,7 +563,7 @@@ * and origin first. Most of the time they are the * same and diff-tree is fairly efficient about this. */ - diff_setup(&diff_opts); + repo_diff_setup(r, &diff_opts); diff_opts.flags.recursive = 1; diff_opts.detect_rename = 0; diff_opts.output_format = DIFF_FORMAT_NO_OUTPUT; @@@ -628,14 -630,15 +630,15 @@@ * We have an origin -- find the path that corresponds to it in its * parent and return an origin structure to represent it. */ - static struct blame_origin *find_rename(struct commit *parent, - struct blame_origin *origin) + static struct blame_origin *find_rename(struct repository *r, + struct commit *parent, + struct blame_origin *origin) { struct blame_origin *porigin = NULL; struct diff_options diff_opts; int i; - diff_setup(&diff_opts); + repo_diff_setup(r, &diff_opts); diff_opts.flags.recursive = 1; diff_opts.detect_rename = DIFF_DETECT_RENAME; diff_opts.output_format = DIFF_FORMAT_NO_OUTPUT; @@@ -1259,7 -1262,7 +1262,7 @@@ static void find_copy_in_parent(struct if (!unblamed) return; /* nothing remains for this target */ - diff_setup(&diff_opts); + repo_diff_setup(sb->repo, &diff_opts); diff_opts.flags.recursive = 1; diff_opts.output_format = DIFF_FORMAT_NO_OUTPUT; @@@ -1441,7 -1444,7 +1444,7 @@@ static void pass_blame(struct blame_sco * common cases, then we look for renames in the second pass. */ for (pass = 0; pass < 2 - sb->no_whole_file_rename; pass++) { - struct blame_origin *(*find)(struct commit *, struct blame_origin *); + struct blame_origin *(*find)(struct repository *, struct commit *, struct blame_origin *); find = pass ? find_rename : find_origin; for (i = 0, sg = first_scapegoat(revs, commit, sb->reverse); @@@ -1454,17 -1457,17 +1457,17 @@@ continue; if (parse_commit(p)) continue; - porigin = find(p, origin); + porigin = find(sb->repo, p, origin); if (!porigin) continue; - if (!oidcmp(&porigin->blob_oid, &origin->blob_oid)) { + if (oideq(&porigin->blob_oid, &origin->blob_oid)) { pass_whole_blame(sb, origin, porigin); blame_origin_decref(porigin); goto finish; } for (j = same = 0; j < i; j++) if (sg_origin[j] && - !oidcmp(&sg_origin[j]->blob_oid, &porigin->blob_oid)) { + oideq(&sg_origin[j]->blob_oid, &porigin->blob_oid)) { same = 1; break; } @@@ -1832,7 -1835,7 +1835,7 @@@ void setup_scoreboard(struct blame_scor sb->revs->children.name = "children"; while (c->parents && - oidcmp(&c->object.oid, &sb->final->object.oid)) { + !oideq(&c->object.oid, &sb->final->object.oid)) { struct commit_list *l = xcalloc(1, sizeof(*l)); l->item = c; @@@ -1842,7 -1845,7 +1845,7 @@@ c = c->parents->item; } - if (oidcmp(&c->object.oid, &sb->final->object.oid)) + if (!oideq(&c->object.oid, &sb->final->object.oid)) die(_("--reverse --first-parent together require range along first-parent chain")); } @@@ -1857,7 -1860,7 +1860,7 @@@ die(_("no such path %s in %s"), path, final_commit_name); if (sb->revs->diffopt.flags.allow_textconv && - textconv_object(path, o->mode, &o->blob_oid, 1, (char **) &sb->final_buf, + textconv_object(sb->repo, path, o->mode, &o->blob_oid, 1, (char **) &sb->final_buf, &sb->final_buf_size)) ; else diff --combined builtin/add.c index 0b64bcdebe,f94b614c1c..ad49806ebf --- a/builtin/add.c +++ b/builtin/add.c @@@ -110,7 -110,7 +110,7 @@@ int add_files_to_cache(const char *pref memset(&data, 0, sizeof(data)); data.flags = flags; - init_revisions(&rev, prefix); + repo_init_revisions(the_repository, &rev, prefix); setup_revisions(0, NULL, &rev, NULL); if (pathspec) copy_pathspec(&rev.prune_data, pathspec); @@@ -232,7 -232,7 +232,7 @@@ static int edit_patch(int argc, const c if (read_cache() < 0) die(_("Could not read the index")); - init_revisions(&rev, prefix); + repo_init_revisions(the_repository, &rev, prefix); rev.diffopt.context = 7; argc = setup_revisions(argc, argv, &rev, NULL); @@@ -454,7 -454,7 +454,7 @@@ int cmd_add(int argc, const char **argv * Check the "pathspec '%s' did not match any files" block * below before enabling new magic. */ - parse_pathspec(&pathspec, 0, + parse_pathspec(&pathspec, PATHSPEC_ATTR, PATHSPEC_PREFER_FULL | PATHSPEC_SYMLINK_LEADING_PATH, prefix, argv); diff --combined builtin/am.c index 5e643e2a3e,601570dbef..d79f092a96 --- a/builtin/am.c +++ b/builtin/am.c @@@ -1244,10 -1244,6 +1244,10 @@@ static int parse_mail(struct am_state * fclose(mi.input); fclose(mi.output); + if (mi.format_flowed) + warning(_("Patch sent with format=flowed; " + "space at the end of lines might be lost.")); + /* Extract message and author information */ fp = xfopen(am_path(state, "info"), "r"); while (!strbuf_getline_lf(&sb, fp)) { @@@ -1376,7 -1372,7 +1376,7 @@@ static void write_commit_patch(const st FILE *fp; fp = xfopen(am_path(state, "patch"), "w"); - init_revisions(&rev_info, NULL); + repo_init_revisions(the_repository, &rev_info, NULL); rev_info.diff = 1; rev_info.abbrev = 0; rev_info.disable_stdin = 1; @@@ -1411,7 -1407,7 +1411,7 @@@ static void write_index_patch(const str the_repository->hash_algo->empty_tree); fp = xfopen(am_path(state, "patch"), "w"); - init_revisions(&rev_info, NULL); + repo_init_revisions(the_repository, &rev_info, NULL); rev_info.diff = 1; rev_info.disable_stdin = 1; rev_info.no_commit_id = 1; @@@ -1569,7 -1565,7 +1569,7 @@@ static int fall_back_threeway(const str struct rev_info rev_info; const char *diff_filter_str = "--diff-filter=AM"; - init_revisions(&rev_info, NULL); + repo_init_revisions(the_repository, &rev_info, NULL); rev_info.diffopt.output_format = DIFF_FORMAT_NAME_STATUS; diff_opt_parse(&rev_info.diffopt, &diff_filter_str, 1, rev_info.prefix); add_pending_oid(&rev_info, "HEAD", &our_tree, 0); @@@ -1608,7 -1604,7 +1608,7 @@@ o.verbosity = 0; if (merge_recursive_generic(&o, &our_tree, &their_tree, 1, bases, &result)) { - rerere(state->allow_rerere_autoupdate); + repo_rerere(the_repository, state->allow_rerere_autoupdate); free(their_tree_name); return error(_("Failed to merge in the changes.")); } @@@ -1903,7 -1899,7 +1903,7 @@@ static void am_resolve(struct am_state goto next; } - rerere(0); + repo_rerere(the_repository, 0); do_commit(state); @@@ -2082,7 -2078,7 +2082,7 @@@ static int safe_to_abort(const struct a if (get_oid("HEAD", &head)) oidclr(&head); - if (!oidcmp(&head, &abort_safety)) + if (oideq(&head, &abort_safety)) return 1; warning(_("You seem to have moved HEAD since the last 'am' failure.\n" diff --combined builtin/checkout.c index 902c06702c,ae28478ff8..acdafc6e4c --- a/builtin/checkout.c +++ b/builtin/checkout.c @@@ -25,8 -25,6 +25,8 @@@ #include "submodule.h" #include "advice.h" +static int checkout_optimize_new_branch; + static const char * const checkout_usage[] = { N_("git checkout [] "), N_("git checkout [] [] -- ..."), @@@ -44,10 -42,6 +44,10 @@@ struct checkout_opts int ignore_skipworktree; int ignore_other_worktrees; int show_progress; + /* + * If new checkout options are added, skip_merge_working_tree + * should be updated accordingly. + */ const char *new_branch; const char *new_branch_force; @@@ -102,7 -96,7 +102,7 @@@ static int update_some(const struct obj if (pos >= 0) { struct cache_entry *old = active_cache[pos]; if (ce->ce_mode == old->ce_mode && - !oidcmp(&ce->oid, &old->oid)) { + oideq(&ce->oid, &old->oid)) { old->ce_flags |= CE_UPDATE; discard_cache_entry(ce); return 0; @@@ -214,7 -208,8 +214,8 @@@ static int checkout_merged(int pos, con * merge.renormalize set, too */ status = ll_merge(&result_buf, path, &ancestor, "base", - &ours, "ours", &theirs, "theirs", NULL); + &ours, "ours", &theirs, "theirs", + state->istate, NULL); free(ancestor.ptr); free(ours.ptr); free(theirs.ptr); @@@ -397,7 -392,7 +398,7 @@@ static void show_local_changes(struct o { struct rev_info rev; /* I think we want full paths, even if we're in a subdirectory. */ - init_revisions(&rev, NULL); + repo_init_revisions(the_repository, &rev, NULL); rev.diffopt.flags = opts->flags; rev.diffopt.output_format |= DIFF_FORMAT_NAME_STATUS; diff_setup_done(&rev.diffopt); @@@ -478,99 -473,6 +479,99 @@@ static void setup_branch_path(struct br branch->path = strbuf_detach(&buf, NULL); } +/* + * Skip merging the trees, updating the index and working directory if and + * only if we are creating a new branch via "git checkout -b ." + */ +static int skip_merge_working_tree(const struct checkout_opts *opts, + const struct branch_info *old_branch_info, + const struct branch_info *new_branch_info) +{ + /* + * Do the merge if sparse checkout is on and the user has not opted in + * to the optimized behavior + */ + if (core_apply_sparse_checkout && !checkout_optimize_new_branch) + return 0; + + /* + * We must do the merge if we are actually moving to a new commit. + */ + if (!old_branch_info->commit || !new_branch_info->commit || + !oideq(&old_branch_info->commit->object.oid, + &new_branch_info->commit->object.oid)) + return 0; + + /* + * opts->patch_mode cannot be used with switching branches so is + * not tested here + */ + + /* + * opts->quiet only impacts output so doesn't require a merge + */ + + /* + * Honor the explicit request for a three-way merge or to throw away + * local changes + */ + if (opts->merge || opts->force) + return 0; + + /* + * --detach is documented as "updating the index and the files in the + * working tree" but this optimization skips those steps so fall through + * to the regular code path. + */ + if (opts->force_detach) + return 0; + + /* + * opts->writeout_stage cannot be used with switching branches so is + * not tested here + */ + + /* + * Honor the explicit ignore requests + */ + if (!opts->overwrite_ignore || opts->ignore_skipworktree || + opts->ignore_other_worktrees) + return 0; + + /* + * opts->show_progress only impacts output so doesn't require a merge + */ + + /* + * If we aren't creating a new branch any changes or updates will + * happen in the existing branch. Since that could only be updating + * the index and working directory, we don't want to skip those steps + * or we've defeated any purpose in running the command. + */ + if (!opts->new_branch) + return 0; + + /* + * new_branch_force is defined to "create/reset and checkout a branch" + * so needs to go through the merge to do the reset + */ + if (opts->new_branch_force) + return 0; + + /* + * A new orphaned branch requrires the index and the working tree to be + * adjusted to + */ + if (opts->new_orphan_branch) + return 0; + + /* + * Remaining variables are not checkout options but used to track state + */ + + return 1; +} + static int merge_working_tree(const struct checkout_opts *opts, struct branch_info *old_branch_info, struct branch_info *new_branch_info, @@@ -899,7 -801,7 +900,7 @@@ static void orphaned_commit_warning(str struct rev_info revs; struct object *object = &old_commit->object; - init_revisions(&revs, NULL); + repo_init_revisions(the_repository, &revs, NULL); setup_revisions(0, NULL, &revs, NULL); object->flags &= ~UNINTERESTING; @@@ -945,19 -847,10 +946,19 @@@ static int switch_branches(const struc parse_commit_or_die(new_branch_info->commit); } - ret = merge_working_tree(opts, &old_branch_info, new_branch_info, &writeout_error); - if (ret) { - free(path_to_free); - return ret; + /* optimize the "checkout -b path */ + if (skip_merge_working_tree(opts, &old_branch_info, new_branch_info)) { + if (!checkout_optimize_new_branch && !opts->quiet) { + if (read_cache_preload(NULL) < 0) + return error(_("index file corrupt")); + show_local_changes(&new_branch_info->commit->object, &opts->diff_options); + } + } else { + ret = merge_working_tree(opts, &old_branch_info, new_branch_info, &writeout_error); + if (ret) { + free(path_to_free); + return ret; + } } if (!opts->quiet && !old_branch_info.path && old_branch_info.commit && new_branch_info->commit != old_branch_info.commit) @@@ -972,11 -865,6 +973,11 @@@ static int git_checkout_config(const char *var, const char *value, void *cb) { + if (!strcmp(var, "checkout.optimizenewbranch")) { + checkout_optimize_new_branch = git_config_bool(var, value); + return 0; + } + if (!strcmp(var, "diff.ignoresubmodules")) { struct checkout_opts *opts = cb; handle_ignore_submodules_arg(&opts->diff_options, value); diff --combined builtin/commit.c index 1d5292e4d8,9d8ce6cb3b..79d557fb2b --- a/builtin/commit.c +++ b/builtin/commit.c @@@ -33,8 -33,6 +33,8 @@@ #include "sequencer.h" #include "mailmap.h" #include "help.h" +#include "commit-reach.h" +#include "commit-graph.h" static const char * const builtin_commit_usage[] = { N_("git commit [] [--] ..."), @@@ -874,7 -872,6 +874,7 @@@ static int prepare_to_commit(const cha s->use_color = 0; commitable = run_status(s->fp, index_file, prefix, 1, s); s->use_color = saved_color_setting; + string_list_clear(&s->change, 1); } else { struct object_id oid; const char *parent = "HEAD"; @@@ -983,7 -980,7 +983,7 @@@ static const char *find_author_by_nickn const char *av[20]; int ac = 0; - init_revisions(&revs, NULL); + repo_init_revisions(the_repository, &revs, NULL); strbuf_addf(&buf, "--author=%s", name); av[++ac] = "--all"; av[++ac] = "-i"; @@@ -1654,10 -1651,7 +1654,10 @@@ int cmd_commit(int argc, const char **a "new_index file. Check that disk is not full and quota is\n" "not exceeded, and then \"git reset HEAD\" to recover.")); + if (git_env_bool(GIT_TEST_COMMIT_GRAPH, 0)) + write_commit_graph_reachable(get_object_directory(), 0, 0); + - rerere(0); + repo_rerere(the_repository, 0); run_command_v_opt(argv_gc_auto, RUN_GIT_CMD); run_commit_hook(use_editor, get_index_file(), "post-commit", NULL); if (amend && !no_post_rewrite) { diff --combined builtin/describe.c index 22c0541da5,1fde0563fe..c48c34e866 --- a/builtin/describe.c +++ b/builtin/describe.c @@@ -62,7 -62,7 +62,7 @@@ static const char *prio_names[] = N_("head"), N_("lightweight"), N_("annotated"), }; -static int commit_name_cmp(const void *unused_cmp_data, +static int commit_name_neq(const void *unused_cmp_data, const void *entry, const void *entry_or_key, const void *peeled) @@@ -70,7 -70,7 +70,7 @@@ const struct commit_name *cn1 = entry; const struct commit_name *cn2 = entry_or_key; - return oidcmp(&cn1->peeled, peeled ? peeled : &cn2->peeled); + return !oideq(&cn1->peeled, peeled ? peeled : &cn2->peeled); } static inline struct commit_name *find_commit_name(const struct object_id *peeled) @@@ -190,7 -190,7 +190,7 @@@ static int get_name(const char *path, c /* Is it annotated? */ if (!peel_ref(path, &peeled)) { - is_annotated = !!oidcmp(oid, &peeled); + is_annotated = !oideq(oid, &peeled); } else { oidcpy(&peeled, oid); is_annotated = 0; @@@ -469,7 -469,7 +469,7 @@@ static void process_object(struct objec { struct process_commit_data *pcd = data; - if (!oidcmp(&pcd->looking_for, &obj->oid) && !pcd->dst->len) { + if (oideq(&pcd->looking_for, &obj->oid) && !pcd->dst->len) { reset_revision_walk(); describe_commit(&pcd->current_commit, pcd->dst); strbuf_addf(pcd->dst, ":%s", path); @@@ -488,7 -488,7 +488,7 @@@ static void describe_blob(struct object "--objects", "--in-commit-order", "--reverse", "HEAD", NULL); - init_revisions(&revs, NULL); + repo_init_revisions(the_repository, &revs, NULL); if (setup_revisions(args.argc, args.argv, &revs, NULL) > 1) BUG("setup_revisions could not handle all args?"); @@@ -596,7 -596,7 +596,7 @@@ int cmd_describe(int argc, const char * return cmd_name_rev(args.argc, args.argv, prefix); } - hashmap_init(&names, commit_name_cmp, NULL, 0); + hashmap_init(&names, commit_name_neq, NULL, 0); for_each_rawref(get_name, NULL); if (!hashmap_get_size(&names) && !always) die(_("No names found, cannot describe anything.")); @@@ -636,7 -636,7 +636,7 @@@ if (0 <= fd) update_index_if_able(&the_index, &index_lock); - init_revisions(&revs, prefix); + repo_init_revisions(the_repository, &revs, prefix); argv_array_pushv(&args, diff_index_args); if (setup_revisions(args.argc, args.argv, &revs, NULL) != 1) BUG("malformed internal diff-index command line"); diff --combined builtin/diff.c index b3a8ba488f,43bb71c1e0..f0393bba23 --- a/builtin/diff.c +++ b/builtin/diff.c @@@ -41,7 -41,7 +41,7 @@@ static void stuff_change(struct diff_op struct diff_filespec *one, *two; if (!is_null_oid(old_oid) && !is_null_oid(new_oid) && - !oidcmp(old_oid, new_oid) && (old_mode == new_mode)) + oideq(old_oid, new_oid) && (old_mode == new_mode)) return; if (opt->flags.reverse_diff) { @@@ -318,7 -318,7 +318,7 @@@ int cmd_diff(int argc, const char **arg git_config(git_diff_ui_config, NULL); precompose_argv(argc, argv); - init_revisions(&rev, prefix); + repo_init_revisions(the_repository, &rev, prefix); if (no_index && argc != i + 2) { if (no_index == DIFF_NO_INDEX_IMPLICIT) { @@@ -339,7 -339,7 +339,7 @@@ } if (no_index) /* If this is a no-index diff, just run it and exit there. */ - diff_no_index(&rev, argc, argv); + diff_no_index(the_repository, &rev, argc, argv); /* Otherwise, we are doing the usual "git" diff */ rev.diffopt.skip_stat_unmatch = !!diff_auto_refresh_index; diff --combined builtin/difftool.c index b41a9199ff,e7023e3adf..544b0e8639 --- a/builtin/difftool.c +++ b/builtin/difftool.c @@@ -112,11 -112,11 +112,11 @@@ static int use_wt_file(const char *work int fd = open(buf.buf, O_RDONLY); if (fd >= 0 && - !index_fd(&wt_oid, fd, &st, OBJ_BLOB, name, 0)) { + !index_fd(&the_index, &wt_oid, fd, &st, OBJ_BLOB, name, 0)) { if (is_null_oid(oid)) { oidcpy(oid, &wt_oid); use = 1; - } else if (!oidcmp(oid, &wt_oid)) + } else if (oideq(oid, &wt_oid)) use = 1; } } @@@ -438,7 -438,7 +438,7 @@@ static int run_dir_diff(const char *ext strbuf_reset(&buf); strbuf_addf(&buf, "Subproject commit %s", oid_to_hex(&roid)); - if (!oidcmp(&loid, &roid)) + if (oideq(&loid, &roid)) strbuf_addstr(&buf, "-dirty"); add_left_or_right(&submodules, dst_path, buf.buf, 1); continue; diff --combined builtin/fast-export.c index 74f3bf5c96,9bd4a95a47..456797c12a --- a/builtin/fast-export.c +++ b/builtin/fast-export.c @@@ -384,7 -384,7 +384,7 @@@ static void show_filemodify(struct diff string_list_insert(changed, spec->path); putchar('\n'); - if (!oidcmp(&ospec->oid, &spec->oid) && + if (oideq(&ospec->oid, &spec->oid) && ospec->mode == spec->mode) break; } @@@ -1033,7 -1033,7 +1033,7 @@@ int cmd_fast_export(int argc, const cha /* we handle encodings */ git_config(git_default_config, NULL); - init_revisions(&revs, prefix); + repo_init_revisions(the_repository, &revs, prefix); init_revision_sources(&revision_sources); revs.topo_order = 1; revs.sources = &revision_sources; diff --combined builtin/fmt-merge-msg.c index 59a40342b6,1adc84ed87..a4615587fd --- a/builtin/fmt-merge-msg.c +++ b/builtin/fmt-merge-msg.c @@@ -12,7 -12,6 +12,7 @@@ #include "fmt-merge-msg.h" #include "gpg-interface.h" #include "repository.h" +#include "commit-reach.h" static const char * const fmt_merge_msg_usage[] = { N_("git fmt-merge-msg [-m ] [--log[=] | --no-log] [--file ]"), @@@ -79,9 -78,9 +79,9 @@@ static struct merge_parent *find_merge_ { int i; for (i = 0; i < table->nr; i++) { - if (given && oidcmp(&table->item[i].given, given)) + if (given && !oideq(&table->item[i].given, given)) continue; - if (commit && oidcmp(&table->item[i].commit, commit)) + if (commit && !oideq(&table->item[i].commit, commit)) continue; return &table->item[i]; } @@@ -583,7 -582,7 +583,7 @@@ static void find_merge_parents(struct m while (parents) { struct commit *cmit = pop_commit(&parents); for (i = 0; i < result->nr; i++) - if (!oidcmp(&result->item[i].commit, &cmit->object.oid)) + if (oideq(&result->item[i].commit, &cmit->object.oid)) result->item[i].used = 1; } @@@ -643,7 -642,7 +643,7 @@@ int fmt_merge_msg(struct strbuf *in, st struct rev_info rev; head = lookup_commit_or_die(&head_oid, "HEAD"); - init_revisions(&rev, NULL); + repo_init_revisions(the_repository, &rev, NULL); rev.commit_format = CMIT_FMT_ONELINE; rev.ignore_merges = 1; rev.limited = 1; diff --combined builtin/log.c index 1dbb9d829b,717d20e115..061d4fd864 --- a/builtin/log.c +++ b/builtin/log.c @@@ -31,9 -31,6 +31,9 @@@ #include "progress.h" #include "commit-slab.h" #include "repository.h" +#include "commit-reach.h" +#include "interdiff.h" +#include "range-diff.h" #define MAIL_DEFAULT_WRAP 72 @@@ -118,7 -115,7 +118,7 @@@ static int log_line_range_callback(cons static void init_log_defaults(void) { - init_grep_defaults(); + init_grep_defaults(the_repository); init_diff_ui_defaults(); decoration_style = auto_decoration_style(); @@@ -470,7 -467,7 +470,7 @@@ int cmd_whatchanged(int argc, const cha init_log_defaults(); git_config(git_log_config, NULL); - init_revisions(&rev, prefix); + repo_init_revisions(the_repository, &rev, prefix); rev.diff = 1; rev.simplify_history = 0; memset(&opt, 0, sizeof(opt)); @@@ -510,7 -507,8 +510,8 @@@ static int show_blob_object(const struc &oidc, &obj_context)) die(_("Not a valid object name %s"), obj_name); if (!obj_context.path || - !textconv_object(obj_context.path, obj_context.mode, &oidc, 1, &buf, &size)) { + !textconv_object(the_repository, obj_context.path, + obj_context.mode, &oidc, 1, &buf, &size)) { free(obj_context.path); return stream_blob_to_fd(1, oid, NULL, 0); } @@@ -587,7 -585,7 +588,7 @@@ int cmd_show(int argc, const char **arg git_config(git_log_config, NULL); memset(&match_all, 0, sizeof(match_all)); - init_revisions(&rev, prefix); + repo_init_revisions(the_repository, &rev, prefix); rev.diff = 1; rev.always_show_header = 1; rev.no_walk = REVISION_WALK_NO_WALK_SORTED; @@@ -667,7 -665,7 +668,7 @@@ int cmd_log_reflog(int argc, const cha init_log_defaults(); git_config(git_log_config, NULL); - init_revisions(&rev, prefix); + repo_init_revisions(the_repository, &rev, prefix); init_reflog_walk(&rev.reflog_info); rev.verbose_header = 1; memset(&opt, 0, sizeof(opt)); @@@ -706,7 -704,7 +707,7 @@@ int cmd_log(int argc, const char **argv init_log_defaults(); git_config(git_log_config, NULL); - init_revisions(&rev, prefix); + repo_init_revisions(the_repository, &rev, prefix); rev.always_show_header = 1; memset(&opt, 0, sizeof(opt)); opt.def = "HEAD"; @@@ -916,10 -914,10 +917,10 @@@ static void get_patch_ids(struct rev_in if ((flags1 & UNINTERESTING) == (flags2 & UNINTERESTING)) die(_("Not a range.")); - init_patch_ids(ids); + init_patch_ids(the_repository, ids); /* given a range a..b get all patch ids for b..a */ - init_revisions(&check_rev, rev->prefix); + repo_init_revisions(the_repository, &check_rev, rev->prefix); check_rev.max_parents = 1; o1->flags ^= UNINTERESTING; o2->flags ^= UNINTERESTING; @@@ -995,32 -993,12 +996,32 @@@ static char *find_branch_name(struct re tip_oid = &rev->cmdline.rev[positive].item->oid; if (dwim_ref(ref, strlen(ref), &branch_oid, &full_ref) && skip_prefix(full_ref, "refs/heads/", &v) && - !oidcmp(tip_oid, &branch_oid)) + oideq(tip_oid, &branch_oid)) branch = xstrdup(v); free(full_ref); return branch; } +static void show_diffstat(struct rev_info *rev, + struct commit *origin, struct commit *head) +{ + struct diff_options opts; + + memcpy(&opts, &rev->diffopt, sizeof(opts)); + opts.output_format = DIFF_FORMAT_SUMMARY | DIFF_FORMAT_DIFFSTAT; + opts.stat_width = MAIL_DEFAULT_WRAP; + + diff_setup_done(&opts); + + diff_tree_oid(get_commit_tree_oid(origin), + get_commit_tree_oid(head), + "", &opts); + diffcore_std(&opts); + diff_flush(&opts); + + fprintf(rev->diffopt.file, "\n"); +} + static void make_cover_letter(struct rev_info *rev, int use_stdout, struct commit *origin, int nr, struct commit **list, @@@ -1034,6 -1012,7 +1035,6 @@@ struct strbuf sb = STRBUF_INIT; int i; const char *encoding = "UTF-8"; - struct diff_options opts; int need_8bit_cte = 0; struct pretty_print_context pp = {0}; struct commit *head = list[0]; @@@ -1083,20 -1062,25 +1084,20 @@@ shortlog_output(&log); - /* - * We can only do diffstat with a unique reference point - */ - if (!origin) - return; - - memcpy(&opts, &rev->diffopt, sizeof(opts)); - opts.output_format = DIFF_FORMAT_SUMMARY | DIFF_FORMAT_DIFFSTAT; - opts.stat_width = MAIL_DEFAULT_WRAP; + /* We can only do diffstat with a unique reference point */ + if (origin) + show_diffstat(rev, origin, head); - diff_setup_done(&opts); - - diff_tree_oid(get_commit_tree_oid(origin), - get_commit_tree_oid(head), - "", &opts); - diffcore_std(&opts); - diff_flush(&opts); + if (rev->idiff_oid1) { + fprintf_ln(rev->diffopt.file, "%s", rev->idiff_title); + show_interdiff(rev, 0); + } - fprintf(rev->diffopt.file, "\n"); + if (rev->rdiff1) { + fprintf_ln(rev->diffopt.file, "%s", rev->rdiff_title); + show_range_diff(rev->rdiff1, rev->rdiff2, + rev->creation_factor, 1, &rev->diffopt); + } } static const char *clean_message_id(const char *msg_id) @@@ -1377,13 -1361,13 +1378,13 @@@ static void prepare_bases(struct base_t return; init_commit_base(&commit_base); - diff_setup(&diffopt); + repo_diff_setup(the_repository, &diffopt); diffopt.flags.recursive = 1; diff_setup_done(&diffopt); oidcpy(&bases->base_commit, &base->object.oid); - init_revisions(&revs, NULL); + repo_init_revisions(the_repository, &revs, NULL); revs.max_parents = 1; revs.topo_order = 1; for (i = 0; i < total; i++) { @@@ -1436,36 -1420,6 +1437,36 @@@ static void print_bases(struct base_tre oidclr(&bases->base_commit); } +static const char *diff_title(struct strbuf *sb, int reroll_count, + const char *generic, const char *rerolled) +{ + if (reroll_count <= 0) + strbuf_addstr(sb, generic); + else /* RFC may be v0, so allow -v1 to diff against v0 */ + strbuf_addf(sb, rerolled, reroll_count - 1); + return sb->buf; +} + +static void infer_range_diff_ranges(struct strbuf *r1, + struct strbuf *r2, + const char *prev, + struct commit *origin, + struct commit *head) +{ + const char *head_oid = oid_to_hex(&head->object.oid); + + if (!strstr(prev, "..")) { + strbuf_addf(r1, "%s..%s", head_oid, prev); + strbuf_addf(r2, "%s..%s", prev, head_oid); + } else if (!origin) { + die(_("failed to infer range-diff ranges")); + } else { + strbuf_addstr(r1, prev); + strbuf_addf(r2, "%s..%s", + oid_to_hex(&origin->object.oid), head_oid); + } +} + int cmd_format_patch(int argc, const char **argv, const char *prefix) { struct commit *commit; @@@ -1493,13 -1447,6 +1494,13 @@@ struct base_tree_info bases; int show_progress = 0; struct progress *progress = NULL; + struct oid_array idiff_prev = OID_ARRAY_INIT; + struct strbuf idiff_title = STRBUF_INIT; + const char *rdiff_prev = NULL; + struct strbuf rdiff1 = STRBUF_INIT; + struct strbuf rdiff2 = STRBUF_INIT; + struct strbuf rdiff_title = STRBUF_INIT; + int creation_factor = -1; const struct option builtin_format_patch_options[] = { { OPTION_CALLBACK, 'n', "numbered", &numbered, NULL, @@@ -1573,13 -1520,6 +1574,13 @@@ OPT__QUIET(&quiet, N_("don't print the patch filenames")), OPT_BOOL(0, "progress", &show_progress, N_("show progress while generating patches")), + OPT_CALLBACK(0, "interdiff", &idiff_prev, N_("rev"), + N_("show changes against in cover letter or single patch"), + parse_opt_object_name), + OPT_STRING(0, "range-diff", &rdiff_prev, N_("refspec"), + N_("show changes against in cover letter or single patch")), + OPT_INTEGER(0, "creation-factor", &creation_factor, + N_("percentage by which creation is weighted")), OPT_END() }; @@@ -1588,7 -1528,7 +1589,7 @@@ extra_cc.strdup_strings = 1; init_log_defaults(); git_config(git_format_config, NULL); - init_revisions(&rev, prefix); + repo_init_revisions(the_repository, &rev, prefix); rev.commit_format = CMIT_FMT_EMAIL; rev.expand_tabs_in_log_default = 0; rev.verbose_header = 1; @@@ -1764,8 -1704,8 +1765,8 @@@ /* Don't say anything if head and upstream are the same. */ if (rev.pending.nr == 2) { struct object_array_entry *o = rev.pending.objects; - if (oidcmp(&o[0].item->oid, &o[1].item->oid) == 0) - return 0; + if (oideq(&o[0].item->oid, &o[1].item->oid)) + goto done; } get_patch_ids(&rev, &ids); } @@@ -1789,7 -1729,7 +1790,7 @@@ } if (nr == 0) /* nothing to do */ - return 0; + goto done; total = nr; if (cover_letter == -1) { if (config_cover_letter == COVER_AUTO) @@@ -1802,35 -1742,6 +1803,35 @@@ if (numbered) rev.total = total + start_number - 1; + if (idiff_prev.nr) { + if (!cover_letter && total != 1) + die(_("--interdiff requires --cover-letter or single patch")); + rev.idiff_oid1 = &idiff_prev.oid[idiff_prev.nr - 1]; + rev.idiff_oid2 = get_commit_tree_oid(list[0]); + rev.idiff_title = diff_title(&idiff_title, reroll_count, + _("Interdiff:"), + _("Interdiff against v%d:")); + } + + if (creation_factor < 0) + creation_factor = RANGE_DIFF_CREATION_FACTOR_DEFAULT; + else if (!rdiff_prev) + die(_("--creation-factor requires --range-diff")); + + if (rdiff_prev) { + if (!cover_letter && total != 1) + die(_("--range-diff requires --cover-letter or single patch")); + + infer_range_diff_ranges(&rdiff1, &rdiff2, rdiff_prev, + origin, list[0]); + rev.rdiff1 = rdiff1.buf; + rev.rdiff2 = rdiff2.buf; + rev.creation_factor = creation_factor; + rev.rdiff_title = diff_title(&rdiff_title, reroll_count, + _("Range-diff:"), + _("Range-diff against v%d:")); + } + if (!signature) { ; /* --no-signature inhibits all signatures */ } else if (signature && signature != git_version_string) { @@@ -1868,9 -1779,6 +1869,9 @@@ print_signature(rev.diffopt.file); total++; start_number--; + /* interdiff/range-diff in cover-letter; omit from patches */ + rev.idiff_oid1 = NULL; + rev.rdiff1 = NULL; } rev.add_signoff = do_signoff; @@@ -1951,13 -1859,6 +1952,13 @@@ string_list_clear(&extra_hdr, 0); if (ignore_if_in_upstream) free_patch_ids(&ids); + +done: + oid_array_clear(&idiff_prev); + strbuf_release(&idiff_title); + strbuf_release(&rdiff1); + strbuf_release(&rdiff2); + strbuf_release(&rdiff_title); return 0; } @@@ -2038,7 -1939,7 +2039,7 @@@ int cmd_cherry(int argc, const char **a } } - init_revisions(&revs, prefix); + repo_init_revisions(the_repository, &revs, prefix); revs.max_parents = 1; if (add_pending_commit(head, &revs, 0)) @@@ -2049,7 -1950,7 +2050,7 @@@ /* Don't say anything if head and upstream are the same. */ if (revs.pending.nr == 2) { struct object_array_entry *o = revs.pending.objects; - if (oidcmp(&o[0].item->oid, &o[1].item->oid) == 0) + if (oideq(&o[0].item->oid, &o[1].item->oid)) return 0; } diff --combined builtin/merge-tree.c index 8cea8a74f2,f32941fdab..8fc108d305 --- a/builtin/merge-tree.c +++ b/builtin/merge-tree.c @@@ -76,7 -76,7 +76,7 @@@ static void *result(struct merge_list * their = NULL; if (entry) their = entry->blob; - return merge_blobs(path, base, our, their, size); + return merge_blobs(&the_index, path, base, our, their, size); } static void *origin(struct merge_list *entry, unsigned long *size) @@@ -155,7 -155,7 +155,7 @@@ static int same_entry(struct name_entr { return a->oid && b->oid && - !oidcmp(a->oid, b->oid) && + oideq(a->oid, b->oid) && a->mode == b->mode; } diff --combined builtin/merge.c index e331ca6d48,a493f8d866..4aa6071598 --- a/builtin/merge.c +++ b/builtin/merge.c @@@ -36,7 -36,6 +36,7 @@@ #include "packfile.h" #include "tag.h" #include "alias.h" +#include "commit-reach.h" #define DEFAULT_TWOHEAD (1<<0) #define DEFAULT_OCTOPUS (1<<1) @@@ -390,7 -389,7 +390,7 @@@ static void squash_message(struct commi printf(_("Squash commit -- not updating HEAD\n")); - init_revisions(&rev, NULL); + repo_init_revisions(the_repository, &rev, NULL); rev.ignore_merges = 1; rev.commit_format = CMIT_FMT_MEDIUM; @@@ -453,7 -452,7 +453,7 @@@ static void finish(struct commit *head_ } if (new_head && show_diffstat) { struct diff_options opts; - diff_setup(&opts); + repo_diff_setup(the_repository, &opts); opts.stat_width = -1; /* use full terminal width */ opts.stat_graph_width = -1; /* respect statGraphWidth config */ opts.output_format |= @@@ -729,8 -728,9 +729,9 @@@ static int try_merge_strategy(const cha die(_("unable to write %s"), get_index_file()); return clean ? 0 : 1; } else { - return try_merge_command(strategy, xopts_nr, xopts, - common, head_arg, remoteheads); + return try_merge_command(the_repository, + strategy, xopts_nr, xopts, + common, head_arg, remoteheads); } } @@@ -899,7 -899,7 +900,7 @@@ static int suggest_conflicts(void fputs(msgbuf.buf, fp); strbuf_release(&msgbuf); fclose(fp); - rerere(allow_rerere_auto); + repo_rerere(the_repository, allow_rerere_auto); printf(_("Automatic merge failed; " "fix conflicts and then commit the result.\n")); return 1; @@@ -911,7 -911,7 +912,7 @@@ static int evaluate_result(void struct rev_info rev; /* Check how many files differ. */ - init_revisions(&rev, ""); + repo_init_revisions(the_repository, &rev, ""); setup_revisions(0, NULL, &rev, NULL); rev.diffopt.output_format |= DIFF_FORMAT_CALLBACK; @@@ -1190,7 -1190,7 +1191,7 @@@ static int merging_a_throwaway_tag(stru tag_ref = xstrfmt("refs/tags/%s", ((struct tag *)merge_remote_util(commit)->obj)->tag); if (!read_ref(tag_ref, &oid) && - !oidcmp(&oid, &merge_remote_util(commit)->obj->oid)) + oideq(&oid, &merge_remote_util(commit)->obj->oid)) is_throwaway_tag = 0; else is_throwaway_tag = 1; @@@ -1449,7 -1449,7 +1450,7 @@@ int cmd_merge(int argc, const char **ar goto done; } else if (fast_forward != FF_NO && !remoteheads->next && !common->next && - !oidcmp(&common->item->object.oid, &head_commit->object.oid)) { + oideq(&common->item->object.oid, &head_commit->object.oid)) { /* Again the most common case of merging one remote. */ struct strbuf msg = STRBUF_INIT; struct commit *commit; @@@ -1471,7 -1471,8 +1472,8 @@@ goto done; } - if (checkout_fast_forward(&head_commit->object.oid, + if (checkout_fast_forward(the_repository, + &head_commit->object.oid, &commit->object.oid, overwrite_ignore)) { ret = 1; @@@ -1522,7 -1523,7 +1524,7 @@@ * HEAD^^" would be missed. */ common_one = get_merge_bases(head_commit, j->item); - if (oidcmp(&common_one->item->object.oid, &j->item->object.oid)) { + if (!oideq(&common_one->item->object.oid, &j->item->object.oid)) { up_to_date = 0; break; } diff --combined builtin/pack-objects.c index c6370f2716,3383ba43d0..b059b86aee --- a/builtin/pack-objects.c +++ b/builtin/pack-objects.c @@@ -24,7 -24,6 +24,7 @@@ #include "streaming.h" #include "thread-utils.h" #include "pack-bitmap.h" +#include "delta-islands.h" #include "reachable.h" #include "sha1-array.h" #include "argv-array.h" @@@ -32,7 -31,6 +32,7 @@@ #include "packfile.h" #include "object-store.h" #include "dir.h" +#include "midx.h" #define IN_PACK(obj) oe_in_pack(&to_pack, obj) #define SIZE(obj) oe_size(&to_pack, obj) @@@ -42,7 -40,6 +42,7 @@@ #define DELTA_CHILD(obj) oe_delta_child(&to_pack, obj) #define DELTA_SIBLING(obj) oe_delta_sibling(&to_pack, obj) #define SET_DELTA(obj, val) oe_set_delta(&to_pack, obj, val) +#define SET_DELTA_EXT(obj, oid) oe_set_delta_ext(&to_pack, obj, oid) #define SET_DELTA_SIZE(obj, val) oe_set_delta_size(&to_pack, obj, val) #define SET_DELTA_CHILD(obj, val) oe_set_delta_child(&to_pack, obj, val) #define SET_DELTA_SIBLING(obj, val) oe_set_delta_sibling(&to_pack, obj, val) @@@ -62,8 -59,6 +62,8 @@@ static struct packing_data to_pack static struct pack_idx_entry **written_list; static uint32_t nr_result, nr_written, nr_seen; +static struct bitmap_index *bitmap_git; +static uint32_t write_layer; static int non_empty; static int reuse_delta = 1, reuse_object = 1; @@@ -84,7 -79,6 +84,7 @@@ static unsigned long pack_size_limit static int depth = 50; static int delta_search_threads; static int pack_to_stdout; +static int thin; static int num_preferred_base; static struct progress *progress_state; @@@ -99,8 -93,6 +99,8 @@@ static uint16_t write_bitmap_options static int exclude_promisor_objects; +static int use_delta_islands; + static unsigned long delta_cache_size = 0; static unsigned long max_delta_cache_size = DEFAULT_DELTA_CACHE_SIZE; static unsigned long cache_max_small_delta_size = 1000; @@@ -620,7 -612,7 +620,7 @@@ static inline void add_to_write_order(s unsigned int *endp, struct object_entry *e) { - if (e->filled) + if (e->filled || oe_layer(&to_pack, e) != write_layer) return; wo[(*endp)++] = e; e->filled = 1; @@@ -680,15 -672,48 +680,15 @@@ static void add_family_to_write_order(s add_descendants_to_write_order(wo, endp, root); } -static struct object_entry **compute_write_order(void) +static void compute_layer_order(struct object_entry **wo, unsigned int *wo_end) { - unsigned int i, wo_end, last_untagged; - - struct object_entry **wo; + unsigned int i, last_untagged; struct object_entry *objects = to_pack.objects; for (i = 0; i < to_pack.nr_objects; i++) { - objects[i].tagged = 0; - objects[i].filled = 0; - SET_DELTA_CHILD(&objects[i], NULL); - SET_DELTA_SIBLING(&objects[i], NULL); - } - - /* - * Fully connect delta_child/delta_sibling network. - * Make sure delta_sibling is sorted in the original - * recency order. - */ - for (i = to_pack.nr_objects; i > 0;) { - struct object_entry *e = &objects[--i]; - if (!DELTA(e)) - continue; - /* Mark me as the first child */ - e->delta_sibling_idx = DELTA(e)->delta_child_idx; - SET_DELTA_CHILD(DELTA(e), e); - } - - /* - * Mark objects that are at the tip of tags. - */ - for_each_tag_ref(mark_tagged, NULL); - - /* - * Give the objects in the original recency order until - * we see a tagged tip. - */ - ALLOC_ARRAY(wo, to_pack.nr_objects); - for (i = wo_end = 0; i < to_pack.nr_objects; i++) { if (objects[i].tagged) break; - add_to_write_order(wo, &wo_end, &objects[i]); + add_to_write_order(wo, wo_end, &objects[i]); } last_untagged = i; @@@ -697,7 -722,7 +697,7 @@@ */ for (; i < to_pack.nr_objects; i++) { if (objects[i].tagged) - add_to_write_order(wo, &wo_end, &objects[i]); + add_to_write_order(wo, wo_end, &objects[i]); } /* @@@ -707,7 -732,7 +707,7 @@@ if (oe_type(&objects[i]) != OBJ_COMMIT && oe_type(&objects[i]) != OBJ_TAG) continue; - add_to_write_order(wo, &wo_end, &objects[i]); + add_to_write_order(wo, wo_end, &objects[i]); } /* @@@ -716,61 -741,17 +716,61 @@@ for (i = last_untagged; i < to_pack.nr_objects; i++) { if (oe_type(&objects[i]) != OBJ_TREE) continue; - add_to_write_order(wo, &wo_end, &objects[i]); + add_to_write_order(wo, wo_end, &objects[i]); } /* * Finally all the rest in really tight order */ for (i = last_untagged; i < to_pack.nr_objects; i++) { - if (!objects[i].filled) - add_family_to_write_order(wo, &wo_end, &objects[i]); + if (!objects[i].filled && oe_layer(&to_pack, &objects[i]) == write_layer) + add_family_to_write_order(wo, wo_end, &objects[i]); + } +} + +static struct object_entry **compute_write_order(void) +{ + uint32_t max_layers = 1; + unsigned int i, wo_end; + + struct object_entry **wo; + struct object_entry *objects = to_pack.objects; + + for (i = 0; i < to_pack.nr_objects; i++) { + objects[i].tagged = 0; + objects[i].filled = 0; + SET_DELTA_CHILD(&objects[i], NULL); + SET_DELTA_SIBLING(&objects[i], NULL); + } + + /* + * Fully connect delta_child/delta_sibling network. + * Make sure delta_sibling is sorted in the original + * recency order. + */ + for (i = to_pack.nr_objects; i > 0;) { + struct object_entry *e = &objects[--i]; + if (!DELTA(e)) + continue; + /* Mark me as the first child */ + e->delta_sibling_idx = DELTA(e)->delta_child_idx; + SET_DELTA_CHILD(DELTA(e), e); } + /* + * Mark objects that are at the tip of tags. + */ + for_each_tag_ref(mark_tagged, NULL); + + if (use_delta_islands) + max_layers = compute_pack_layers(&to_pack); + + ALLOC_ARRAY(wo, to_pack.nr_objects); + wo_end = 0; + + for (; write_layer < max_layers; ++write_layer) + compute_layer_order(wo, &wo_end); + if (wo_end != to_pack.nr_objects) die(_("ordered %u objects, expected %"PRIu32), wo_end, to_pack.nr_objects); @@@ -970,7 -951,8 +970,7 @@@ static int no_try_delta(const char *pat if (!check) check = attr_check_initl("delta", NULL); - if (git_check_attr(&the_index, path, check)) - return 0; + git_check_attr(&the_index, path, check); if (ATTR_FALSE(check->items[0].value)) return 1; return 0; @@@ -1058,7 -1040,6 +1058,7 @@@ static int want_object_in_pack(const st { int want; struct list_head *pos; + struct multi_pack_index *m; if (!exclude && local && has_loose_object_nonlocal(oid)) return 0; @@@ -1073,32 -1054,6 +1073,32 @@@ if (want != -1) return want; } + + for (m = get_multi_pack_index(the_repository); m; m = m->next) { + struct pack_entry e; + if (fill_midx_entry(oid, &e, m)) { + struct packed_git *p = e.p; + off_t offset; + + if (p == *found_pack) + offset = *found_offset; + else + offset = find_pack_entry_one(oid->hash, p); + + if (offset) { + if (!*found_pack) { + if (!is_pack_valid(p)) + continue; + *found_offset = offset; + *found_pack = p; + } + want = want_found_object(exclude, p); + if (want != -1) + return want; + } + } + } + list_for_each(pos, get_packed_git_mru(the_repository)) { struct packed_git *p = list_entry(pos, struct packed_git, mru); off_t offset; @@@ -1247,7 -1202,7 +1247,7 @@@ static struct pbase_tree_cache *pbase_t */ for (neigh = 0; neigh < 8; neigh++) { ent = pbase_tree_cache[my_ix]; - if (ent && !oidcmp(&ent->oid, oid)) { + if (ent && oideq(&ent->oid, oid)) { ent->ref++; return ent; } @@@ -1429,7 -1384,7 +1429,7 @@@ static void add_preferred_base(struct o return; for (it = pbase_tree; it; it = it->next) { - if (!oidcmp(&it->pcache.oid, &tree_oid)) { + if (oideq(&it->pcache.oid, &tree_oid)) { free(data); return; } @@@ -1469,57 -1424,6 +1469,57 @@@ static void cleanup_preferred_base(void done_pbase_paths_num = done_pbase_paths_alloc = 0; } +/* + * Return 1 iff the object specified by "delta" can be sent + * literally as a delta against the base in "base_sha1". If + * so, then *base_out will point to the entry in our packing + * list, or NULL if we must use the external-base list. + * + * Depth value does not matter - find_deltas() will + * never consider reused delta as the base object to + * deltify other objects against, in order to avoid + * circular deltas. + */ +static int can_reuse_delta(const unsigned char *base_sha1, + struct object_entry *delta, + struct object_entry **base_out) +{ + struct object_entry *base; + + if (!base_sha1) + return 0; + + /* + * First see if we're already sending the base (or it's explicitly in + * our "excluded" list). + */ + base = packlist_find(&to_pack, base_sha1, NULL); + if (base) { + if (!in_same_island(&delta->idx.oid, &base->idx.oid)) + return 0; + *base_out = base; + return 1; + } + + /* + * Otherwise, reachability bitmaps may tell us if the receiver has it, + * even if it was buried too deep in history to make it into the + * packing list. + */ + if (thin && bitmap_has_sha1_in_uninteresting(bitmap_git, base_sha1)) { + if (use_delta_islands) { + struct object_id base_oid; + hashcpy(base_oid.hash, base_sha1); + if (!in_same_island(&delta->idx.oid, &base_oid)) + return 0; + } + *base_out = NULL; + return 1; + } + + return 0; +} + static void check_object(struct object_entry *entry) { unsigned long canonical_size; @@@ -1606,19 -1510,23 +1606,19 @@@ break; } - if (base_ref && (base_entry = packlist_find(&to_pack, base_ref, NULL))) { - /* - * If base_ref was set above that means we wish to - * reuse delta data, and we even found that base - * in the list of objects we want to pack. Goodie! - * - * Depth value does not matter - find_deltas() will - * never consider reused delta as the base object to - * deltify other objects against, in order to avoid - * circular deltas. - */ + if (can_reuse_delta(base_ref, entry, &base_entry)) { oe_set_type(entry, entry->in_pack_type); SET_SIZE(entry, in_pack_size); /* delta size */ - SET_DELTA(entry, base_entry); SET_DELTA_SIZE(entry, in_pack_size); - entry->delta_sibling_idx = base_entry->delta_child_idx; - SET_DELTA_CHILD(base_entry, entry); + + if (base_entry) { + SET_DELTA(entry, base_entry); + entry->delta_sibling_idx = base_entry->delta_child_idx; + SET_DELTA_CHILD(base_entry, entry); + } else { + SET_DELTA_EXT(entry, base_ref); + } + unuse_pack(&w_curs); return; } @@@ -1918,11 -1826,6 +1918,11 @@@ static int type_size_sort(const void *_ return -1; if (a->preferred_base < b->preferred_base) return 1; + if (use_delta_islands) { + int island_cmp = island_delta_cmp(&a->idx.oid, &b->idx.oid); + if (island_cmp) + return island_cmp; + } if (a_size > b_size) return -1; if (a_size < b_size) @@@ -2083,9 -1986,6 +2083,9 @@@ static int try_delta(struct unpacked *t if (trg_size < src_size / 32) return 0; + if (!in_same_island(&trg->entry->idx.oid, &src->entry->idx.oid)) + return 0; + /* Load data if not already done */ if (!trg->data) { read_lock(); @@@ -2628,9 -2528,6 +2628,9 @@@ static void prepare_pack(int window, in uint32_t i, nr_deltas; unsigned n; + if (use_delta_islands) + resolve_tree_islands(progress, &to_pack); + get_object_details(); /* @@@ -2794,9 -2691,6 +2794,9 @@@ static void show_commit(struct commit * if (write_bitmap_index) index_commit_for_bitmap(commit); + + if (use_delta_islands) + propagate_island_marks(commit); } static void show_object(struct object *obj, const char *name, void *data) @@@ -2804,19 -2698,6 +2804,19 @@@ add_preferred_base_object(name); add_object_entry(&obj->oid, obj->type, name, 0); obj->flags |= OBJECT_ADDED; + + if (use_delta_islands) { + const char *p; + unsigned depth = 0; + struct object_entry *ent; + + for (p = strchr(name, '/'); p; p = strchr(p + 1, '/')) + depth++; + + ent = packlist_find(&to_pack, obj->oid.hash, NULL); + if (ent && depth > oe_tree_depth(&to_pack, ent)) + oe_set_tree_depth(&to_pack, ent, depth); + } } static void show_object__ma_allow_any(struct object *obj, const char *name, void *data) @@@ -2925,7 -2806,7 +2925,7 @@@ static void add_objects_in_unpacked_pac memset(&in_pack, 0, sizeof(in_pack)); - for (p = get_packed_git(the_repository); p; p = p->next) { + for (p = get_all_packs(the_repository); p; p = p->next) { struct object_id oid; struct object *o; @@@ -2989,7 -2870,7 +2989,7 @@@ static int has_sha1_pack_kept_or_nonloc struct packed_git *p; p = (last_found != (void *)1) ? last_found : - get_packed_git(the_repository); + get_all_packs(the_repository); while (p) { if ((!p->pack_local || p->pack_keep || @@@ -2999,7 -2880,7 +2999,7 @@@ return 1; } if (p == last_found) - p = get_packed_git(the_repository); + p = get_all_packs(the_repository); else p = p->next; if (p == last_found) @@@ -3035,7 -2916,7 +3035,7 @@@ static void loosen_unused_packed_object uint32_t i; struct object_id oid; - for (p = get_packed_git(the_repository); p; p = p->next) { + for (p = get_all_packs(the_repository); p; p = p->next) { if (!p->pack_local || p->pack_keep || p->pack_keep_in_core) continue; @@@ -3070,6 -2951,7 +3070,6 @@@ static int pack_options_allow_reuse(voi static int get_object_list_from_bitmap(struct rev_info *revs) { - struct bitmap_index *bitmap_git; if (!(bitmap_git = prepare_bitmap_walk(revs))) return -1; @@@ -3085,6 -2967,7 +3085,6 @@@ } traverse_bitmap_commit_list(bitmap_git, &add_object_entry_from_bitmap); - free_bitmap_index(bitmap_git); return 0; } @@@ -3106,7 -2989,7 +3106,7 @@@ static void get_object_list(int ac, con char line[1000]; int flags = 0; - init_revisions(&revs, NULL); + repo_init_revisions(the_repository, &revs, NULL); save_commit_buffer = 0; setup_revisions(ac, av, &revs, NULL); @@@ -3142,9 -3025,6 +3142,9 @@@ if (use_bitmap_index && !get_object_list_from_bitmap(&revs)) return; + if (use_delta_islands) + load_delta_islands(); + if (prepare_revision_walk(&revs)) die(_("revision walk setup failed")); mark_edges_uninteresting(&revs, show_edge); @@@ -3183,7 -3063,7 +3183,7 @@@ static void add_extra_kept_packs(const if (!names->nr) return; - for (p = get_packed_git(the_repository); p; p = p->next) { + for (p = get_all_packs(the_repository); p; p = p->next) { const char *name = basename(p->pack_name); int i; @@@ -3235,6 -3115,7 +3235,6 @@@ static int option_parse_unpack_unreacha int cmd_pack_objects(int argc, const char **argv, const char *prefix) { int use_internal_rev_list = 0; - int thin = 0; int shallow = 0; int all_progress_implied = 0; struct argv_array rp = ARGV_ARRAY_INIT; @@@ -3323,8 -3204,6 +3323,8 @@@ option_parse_missing_action }, OPT_BOOL(0, "exclude-promisor-objects", &exclude_promisor_objects, N_("do not pack objects in promisor packfiles")), + OPT_BOOL(0, "delta-islands", &use_delta_islands, + N_("respect islands during delta compression")), OPT_END(), }; @@@ -3451,16 -3330,13 +3451,16 @@@ if (pack_to_stdout || !rev_list_all) write_bitmap_index = 0; + if (use_delta_islands) + argv_array_push(&rp, "--topo-order"); + if (progress && all_progress_implied) progress = 2; add_extra_kept_packs(&keep_pack_list); if (ignore_packed_keep_on_disk) { struct packed_git *p; - for (p = get_packed_git(the_repository); p; p = p->next) + for (p = get_all_packs(the_repository); p; p = p->next) if (p->pack_local && p->pack_keep) break; if (!p) /* no keep-able packs found */ @@@ -3473,7 -3349,7 +3473,7 @@@ * it also covers non-local objects */ struct packed_git *p; - for (p = get_packed_git(the_repository); p; p = p->next) { + for (p = get_all_packs(the_repository); p; p = p->next) { if (!p->pack_local) { have_non_local_packs = 1; break; diff --combined builtin/pull.c index b2055d1dd6,9c455984d1..798ecf7faf --- a/builtin/pull.c +++ b/builtin/pull.c @@@ -22,7 -22,6 +22,7 @@@ #include "tempfile.h" #include "lockfile.h" #include "wt-status.h" +#include "commit-reach.h" enum rebase_type { REBASE_INVALID = -1, @@@ -563,7 -562,9 +563,9 @@@ static int pull_into_void(const struct * index/worktree changes that the user already made on the unborn * branch. */ - if (checkout_fast_forward(the_hash_algo->empty_tree, merge_head, 0)) + if (checkout_fast_forward(the_repository, + the_hash_algo->empty_tree, + merge_head, 0)) return 1; if (update_ref("initial pull", "HEAD", merge_head, curr_head, 0, UPDATE_REFS_DIE_ON_ERR)) @@@ -800,7 -801,7 +802,7 @@@ static int run_rebase(const struct obje struct argv_array args = ARGV_ARRAY_INIT; if (!get_octopus_merge_base(&oct_merge_base, curr_head, merge_head, fork_point)) - if (!is_null_oid(fork_point) && !oidcmp(&oct_merge_base, fork_point)) + if (!is_null_oid(fork_point) && oideq(&oct_merge_base, fork_point)) fork_point = NULL; argv_array_push(&args, "rebase"); @@@ -903,7 -904,7 +905,7 @@@ int cmd_pull(int argc, const char **arg oidclr(&curr_head); if (!is_null_oid(&orig_head) && !is_null_oid(&curr_head) && - oidcmp(&orig_head, &curr_head)) { + !oideq(&orig_head, &curr_head)) { /* * The fetch involved updating the current branch. * @@@ -916,7 -917,8 +918,8 @@@ "fast-forwarding your working tree from\n" "commit %s."), oid_to_hex(&orig_head)); - if (checkout_fast_forward(&orig_head, &curr_head, 0)) + if (checkout_fast_forward(the_repository, &orig_head, + &curr_head, 0)) die(_("Cannot fast-forward your working tree.\n" "After making sure that you saved anything precious from\n" "$ git diff %s\n" @@@ -942,7 -944,7 +945,7 @@@ int ret = 0; if ((recurse_submodules == RECURSE_SUBMODULES_ON || recurse_submodules == RECURSE_SUBMODULES_ON_DEMAND) && - submodule_touches_in_range(&rebase_fork_point, &curr_head)) + submodule_touches_in_range(&the_index, &rebase_fork_point, &curr_head)) die(_("cannot rebase with locally recorded submodule modifications")); if (!autostash) { struct commit_list *list = NULL; diff --combined builtin/range-diff.c index 96af537493,1c477c4dc5..f01a0be851 --- a/builtin/range-diff.c +++ b/builtin/range-diff.c @@@ -11,9 -11,14 +11,9 @@@ N_("git range-diff [] < NULL }; -static struct strbuf *output_prefix_cb(struct diff_options *opt, void *data) -{ - return data; -} - int cmd_range_diff(int argc, const char **argv, const char *prefix) { - int creation_factor = 60; + int creation_factor = RANGE_DIFF_CREATION_FACTOR_DEFAULT; struct diff_options diffopt = { NULL }; int simple_color = -1; struct option options[] = { @@@ -24,11 -29,17 +24,11 @@@ OPT_END() }; int i, j, res = 0; - struct strbuf four_spaces = STRBUF_INIT; struct strbuf range1 = STRBUF_INIT, range2 = STRBUF_INIT; git_config(git_diff_ui_config, NULL); - diff_setup(&diffopt); + repo_diff_setup(the_repository, &diffopt); - diffopt.output_format = DIFF_FORMAT_PATCH; - diffopt.flags.suppress_diff_headers = 1; - diffopt.output_prefix = output_prefix_cb; - strbuf_addstr(&four_spaces, " "); - diffopt.output_prefix_data = &four_spaces; argc = parse_options(argc, argv, NULL, options, builtin_range_diff_usage, PARSE_OPT_KEEP_UNKNOWN | @@@ -52,9 -63,12 +52,9 @@@ options + ARRAY_SIZE(options) - 1, /* OPT_END */ builtin_range_diff_usage, 0); - if (simple_color < 1) { - if (!simple_color) - /* force color when --dual-color was used */ - diffopt.use_color = 1; - diffopt.flags.dual_color_diffed_diffs = 1; - } + /* force color when --dual-color was used */ + if (!simple_color) + diffopt.use_color = 1; if (argc == 2) { if (!strstr(argv[0], "..")) @@@ -92,10 -106,11 +92,10 @@@ } res = show_range_diff(range1.buf, range2.buf, creation_factor, - &diffopt); + simple_color < 1, &diffopt); strbuf_release(&range1); strbuf_release(&range2); - strbuf_release(&four_spaces); return res; } diff --combined builtin/replace.c index 30a661ea0c,e0b16ad44b..a58b9c6d13 --- a/builtin/replace.c +++ b/builtin/replace.c @@@ -39,8 -39,7 +39,8 @@@ struct show_data enum replace_format format; }; -static int show_reference(const char *refname, const struct object_id *oid, +static int show_reference(struct repository *r, const char *refname, + const struct object_id *oid, int flag, void *cb_data) { struct show_data *data = cb_data; @@@ -57,8 -56,9 +57,8 @@@ if (get_oid(refname, &object)) return error(_("failed to resolve '%s' as a valid ref"), refname); - obj_type = oid_object_info(the_repository, &object, - NULL); - repl_type = oid_object_info(the_repository, oid, NULL); + obj_type = oid_object_info(r, &object, NULL); + repl_type = oid_object_info(r, oid, NULL); printf("%s (%s) -> %s (%s)\n", refname, type_name(obj_type), oid_to_hex(oid), type_name(repl_type)); @@@ -295,7 -295,7 +295,7 @@@ static int import_object(struct object_ close(fd); return -1; } - if (index_fd(oid, fd, &st, type, NULL, flags) < 0) + if (index_fd(&the_index, oid, fd, &st, type, NULL, flags) < 0) return error(_("unable to write object to database")); /* index_fd close()s fd for us */ } @@@ -343,7 -343,7 +343,7 @@@ static int edit_and_replace(const char } free(tmpfile); - if (!oidcmp(&old_oid, &new_oid)) + if (oideq(&old_oid, &new_oid)) return error(_("new object is the same as the old one: '%s'"), oid_to_hex(&old_oid)); return replace_object_oid(object_ref, &old_oid, "replacement", &new_oid, force); @@@ -414,7 -414,7 +414,7 @@@ static int check_one_mergetag(struct co if (get_oid(mergetag_data->argv[i], &oid) < 0) return error(_("not a valid object name: '%s'"), mergetag_data->argv[i]); - if (!oidcmp(&tag->tagged->oid, &oid)) + if (oideq(&tag->tagged->oid, &oid)) return 0; /* found */ } @@@ -474,7 -474,7 +474,7 @@@ static int create_graft(int argc, cons strbuf_release(&buf); - if (!oidcmp(&old_oid, &new_oid)) { + if (oideq(&old_oid, &new_oid)) { if (gentle) { warning(_("graft for '%s' unnecessary"), oid_to_hex(&old_oid)); return 0; diff --combined builtin/rerere.c index 5ed941b91f,1ca271b711..e89ccbc524 --- a/builtin/rerere.c +++ b/builtin/rerere.c @@@ -70,15 -70,15 +70,15 @@@ int cmd_rerere(int argc, const char **a flags = RERERE_NOAUTOUPDATE; if (argc < 1) - return rerere(flags); + return repo_rerere(the_repository, flags); if (!strcmp(argv[0], "forget")) { struct pathspec pathspec; if (argc < 2) - warning("'git rerere forget' without paths is deprecated"); + warning(_("'git rerere forget' without paths is deprecated")); parse_pathspec(&pathspec, 0, PATHSPEC_PREFER_CWD, prefix, argv + 1); - return rerere_forget(&pathspec); + return rerere_forget(the_repository, &pathspec); } if (!strcmp(argv[0], "clear")) { @@@ -91,7 -91,7 +91,7 @@@ for (i = 0; i < merge_rr.nr; i++) printf("%s\n", merge_rr.items[i].string); } else if (!strcmp(argv[0], "remaining")) { - rerere_remaining(&merge_rr); + rerere_remaining(the_repository, &merge_rr); for (i = 0; i < merge_rr.nr; i++) { if (merge_rr.items[i].util != RERERE_RESOLVED) printf("%s\n", merge_rr.items[i].string); @@@ -107,7 -107,7 +107,7 @@@ const char *path = merge_rr.items[i].string; const struct rerere_id *id = merge_rr.items[i].util; if (diff_two(rerere_path(id, "preimage"), path, path, path)) - die("unable to generate diff for %s", rerere_path(id, NULL)); + die(_("unable to generate diff for '%s'"), rerere_path(id, NULL)); } } else usage_with_options(rerere_usage, options); diff --combined builtin/rev-list.c index ed0ea7dc5b,c60504891a..cc1b70522f --- a/builtin/rev-list.c +++ b/builtin/rev-list.c @@@ -370,7 -370,7 +370,7 @@@ int cmd_rev_list(int argc, const char * usage(rev_list_usage); git_config(git_default_config, NULL); - init_revisions(&revs, prefix); + repo_init_revisions(the_repository, &revs, prefix); revs.abbrev = DEFAULT_ABBREV; revs.commit_format = CMIT_FMT_UNSPECIFIED; @@@ -493,7 -493,7 +493,7 @@@ if ((!revs.commits && reflog_walk_empty(revs.reflog_info) && (!(revs.tag_objects || revs.tree_objects || revs.blob_objects) && !revs.pending.nr) && - !revs.rev_input_given) || + !revs.rev_input_given && !revs.read_from_stdin) || revs.diff) usage(rev_list_usage); diff --combined builtin/submodule--helper.c index 247881189f,063cc0b6b6..80474c3ff5 --- a/builtin/submodule--helper.c +++ b/builtin/submodule--helper.c @@@ -792,7 -792,7 +792,7 @@@ static void status_submodule(const cha path, NULL); git_config(git_diff_basic_config, NULL); - init_revisions(&rev, prefix); + repo_init_revisions(the_repository, &rev, prefix); rev.abbrev = 0; diff_files_args.argc = setup_revisions(diff_files_args.argc, diff_files_args.argv, @@@ -1233,7 -1233,6 +1233,7 @@@ static int clone_submodule(const char * if (gitdir && *gitdir) argv_array_pushl(&cp.args, "--separate-git-dir", gitdir, NULL); + argv_array_push(&cp.args, "--"); argv_array_push(&cp.args, url); argv_array_push(&cp.args, path); @@@ -1444,72 -1443,6 +1444,72 @@@ static int module_clone(int argc, cons return 0; } +static void determine_submodule_update_strategy(struct repository *r, + int just_cloned, + const char *path, + const char *update, + struct submodule_update_strategy *out) +{ + const struct submodule *sub = submodule_from_path(r, &null_oid, path); + char *key; + const char *val; + + key = xstrfmt("submodule.%s.update", sub->name); + + if (update) { + trace_printf("parsing update"); + if (parse_submodule_update_strategy(update, out) < 0) + die(_("Invalid update mode '%s' for submodule path '%s'"), + update, path); + } else if (!repo_config_get_string_const(r, key, &val)) { + if (parse_submodule_update_strategy(val, out) < 0) + die(_("Invalid update mode '%s' configured for submodule path '%s'"), + val, path); + } else if (sub->update_strategy.type != SM_UPDATE_UNSPECIFIED) { + trace_printf("loaded thing"); + out->type = sub->update_strategy.type; + out->command = sub->update_strategy.command; + } else + out->type = SM_UPDATE_CHECKOUT; + + if (just_cloned && + (out->type == SM_UPDATE_MERGE || + out->type == SM_UPDATE_REBASE || + out->type == SM_UPDATE_NONE)) + out->type = SM_UPDATE_CHECKOUT; + + free(key); +} + +static int module_update_module_mode(int argc, const char **argv, const char *prefix) +{ + const char *path, *update = NULL; + int just_cloned; + struct submodule_update_strategy update_strategy = { .type = SM_UPDATE_CHECKOUT }; + + if (argc < 3 || argc > 4) + die("submodule--helper update-module-clone expects []"); + + just_cloned = git_config_int("just_cloned", argv[1]); + path = argv[2]; + + if (argc == 4) + update = argv[3]; + + determine_submodule_update_strategy(the_repository, + just_cloned, path, update, + &update_strategy); + fputs(submodule_strategy_to_string(&update_strategy), stdout); + + return 0; +} + +struct update_clone_data { + const struct submodule *sub; + struct object_id oid; + unsigned just_cloned; +}; + struct submodule_update_clone { /* index into 'list', the list of submodules to look into for cloning */ int current; @@@ -1529,9 -1462,8 +1529,9 @@@ const char *recursive_prefix; const char *prefix; - /* Machine-readable status lines to be consumed by git-submodule.sh */ - struct string_list projectlines; + /* to be consumed by git-submodule.sh */ + struct update_clone_data *update_clone; + int update_clone_nr; int update_clone_alloc; /* If we want to stop as fast as possible and return an error */ unsigned quickstop : 1; @@@ -1539,13 -1471,11 +1539,13 @@@ /* failed clones to be retried again */ const struct cache_entry **failed_clones; int failed_clones_nr, failed_clones_alloc; + + int max_jobs; }; #define SUBMODULE_UPDATE_CLONE_INIT {0, MODULE_LIST_INIT, 0, \ SUBMODULE_UPDATE_STRATEGY_INIT, 0, 0, -1, STRING_LIST_INIT_DUP, 0, \ NULL, NULL, NULL, \ - STRING_LIST_INIT_DUP, 0, NULL, 0, 0} + NULL, 0, 0, 0, NULL, 0, 0, 0} static void next_submodule_warn_missing(struct submodule_update_clone *suc, @@@ -1639,12 -1569,11 +1639,12 @@@ static int prepare_to_clone_next_submod strbuf_addf(&sb, "%s/.git", ce->name); needs_cloning = !file_exists(sb.buf); - strbuf_reset(&sb); - strbuf_addf(&sb, "%06o %s %d %d\t%s\n", ce->ce_mode, - oid_to_hex(&ce->oid), ce_stage(ce), - needs_cloning, ce->name); - string_list_append(&suc->projectlines, sb.buf); + ALLOC_GROW(suc->update_clone, suc->update_clone_nr + 1, + suc->update_clone_alloc); + oidcpy(&suc->update_clone[suc->update_clone_nr].oid, &ce->oid); + suc->update_clone[suc->update_clone_nr].just_cloned = needs_cloning; + suc->update_clone[suc->update_clone_nr].sub = sub; + suc->update_clone_nr++; if (!needs_cloning) goto cleanup; @@@ -1785,44 -1714,11 +1785,44 @@@ static int git_update_clone_config(cons return 0; } +static void update_submodule(struct update_clone_data *ucd) +{ + fprintf(stdout, "dummy %s %d\t%s\n", + oid_to_hex(&ucd->oid), + ucd->just_cloned, + ucd->sub->path); +} + +static int update_submodules(struct submodule_update_clone *suc) +{ + int i; + + run_processes_parallel(suc->max_jobs, + update_clone_get_next_task, + update_clone_start_failure, + update_clone_task_finished, + suc); + + /* + * We saved the output and put it out all at once now. + * That means: + * - the listener does not have to interleave their (checkout) + * work with our fetching. The writes involved in a + * checkout involve more straightforward sequential I/O. + * - the listener can avoid doing any work if fetching failed. + */ + if (suc->quickstop) + return 1; + + for (i = 0; i < suc->update_clone_nr; i++) + update_submodule(&suc->update_clone[i]); + + return 0; +} + static int update_clone(int argc, const char **argv, const char *prefix) { const char *update = NULL; - int max_jobs = 1; - struct string_list_item *item; struct pathspec pathspec; struct submodule_update_clone suc = SUBMODULE_UPDATE_CLONE_INIT; @@@ -1844,7 -1740,7 +1844,7 @@@ OPT_STRING(0, "depth", &suc.depth, "", N_("Create a shallow clone truncated to the " "specified number of revisions")), - OPT_INTEGER('j', "jobs", &max_jobs, + OPT_INTEGER('j', "jobs", &suc.max_jobs, N_("parallel jobs")), OPT_BOOL(0, "recommend-shallow", &suc.recommend_shallow, N_("whether the initial clone should follow the shallow recommendation")), @@@ -1860,8 -1756,8 +1860,8 @@@ }; suc.prefix = prefix; - update_clone_config_from_gitmodules(&max_jobs); - git_config(git_update_clone_config, &max_jobs); + update_clone_config_from_gitmodules(&suc.max_jobs); + git_config(git_update_clone_config, &suc.max_jobs); argc = parse_options(argc, argv, prefix, module_update_clone_options, git_submodule_helper_usage, 0); @@@ -1876,7 -1772,27 +1876,7 @@@ if (pathspec.nr) suc.warn_if_uninitialized = 1; - run_processes_parallel(max_jobs, - update_clone_get_next_task, - update_clone_start_failure, - update_clone_task_finished, - &suc); - - /* - * We saved the output and put it out all at once now. - * That means: - * - the listener does not have to interleave their (checkout) - * work with our fetching. The writes involved in a - * checkout involve more straightforward sequential I/O. - * - the listener can avoid doing any work if fetching failed. - */ - if (suc.quickstop) - return 1; - - for_each_string_list_item(item, &suc.projectlines) - fprintf(stdout, "%s", item->string); - - return 0; + return update_submodules(&suc); } static int resolve_relative_path(int argc, const char **argv, const char *prefix) @@@ -2022,45 -1938,6 +2022,45 @@@ static int push_check(int argc, const c return 0; } +static int ensure_core_worktree(int argc, const char **argv, const char *prefix) +{ + const struct submodule *sub; + const char *path; + char *cw; + struct repository subrepo; + + if (argc != 2) + BUG("submodule--helper connect-gitdir-workingtree "); + + path = argv[1]; + + sub = submodule_from_path(the_repository, &null_oid, path); + if (!sub) + BUG("We could get the submodule handle before?"); + + if (repo_submodule_init(&subrepo, the_repository, path)) + die(_("could not get a repository handle for submodule '%s'"), path); + + if (!repo_config_get_string(&subrepo, "core.worktree", &cw)) { + char *cfg_file, *abs_path; + const char *rel_path; + struct strbuf sb = STRBUF_INIT; + + cfg_file = repo_git_path(&subrepo, "config"); + + abs_path = absolute_pathdup(path); + rel_path = relative_path(abs_path, subrepo.gitdir, &sb); + + git_config_set_in_file(cfg_file, "core.worktree", rel_path); + + free(cfg_file); + free(abs_path); + strbuf_release(&sb); + } + + return 0; +} + static int absorb_git_dirs(int argc, const char **argv, const char *prefix) { int i; @@@ -2138,9 -2015,7 +2138,9 @@@ static struct cmd_struct commands[] = {"list", module_list, 0}, {"name", module_name, 0}, {"clone", module_clone, 0}, + {"update-module-mode", module_update_module_mode, 0}, {"update-clone", update_clone, 0}, + {"ensure-core-worktree", ensure_core_worktree, 0}, {"relative-path", resolve_relative_path, 0}, {"resolve-relative-url", resolve_relative_url, 0}, {"resolve-relative-url-test", resolve_relative_url_test, 0}, diff --combined builtin/update-index.c index e7fab78b3b,3086212fdb..07c10bcb7d --- a/builtin/update-index.c +++ b/builtin/update-index.c @@@ -282,7 -282,7 +282,7 @@@ static int add_one_path(const struct ca fill_stat_cache_info(ce, st); ce->ce_mode = ce_mode_from_stat(old, st->st_mode); - if (index_path(&ce->oid, path, st, + if (index_path(&the_index, &ce->oid, path, st, info_only ? 0 : HASH_WRITE_OBJECT)) { discard_cache_entry(ce); return -1; @@@ -669,7 -669,7 +669,7 @@@ static int unresolve_one(const char *pa ret = -1; goto free_return; } - if (!oidcmp(&ce_2->oid, &ce_3->oid) && + if (oideq(&ce_2->oid, &ce_3->oid) && ce_2->ce_mode == ce_3->ce_mode) { fprintf(stderr, "%s: identical in both, skipping.\n", path); @@@ -754,7 -754,7 +754,7 @@@ static int do_reupdate(int ac, const ch old = read_one_ent(NULL, &head_oid, ce->name, ce_namelen(ce), 0); if (old && ce->ce_mode == old->ce_mode && - !oidcmp(&ce->oid, &old->oid)) { + oideq(&ce->oid, &old->oid)) { discard_cache_entry(old); continue; /* unchanged */ } diff --combined bundle.c index 14f2cfc248,a5a71d059e..1ef584b93b --- a/bundle.c +++ b/bundle.c @@@ -140,7 -140,7 +140,7 @@@ int verify_bundle(struct bundle_header int i, ret = 0, req_nr; const char *message = _("Repository lacks these prerequisite commits:"); - init_revisions(&revs, NULL); + repo_init_revisions(the_repository, &revs, NULL); for (i = 0; i < p->nr; i++) { struct ref_list_entry *e = p->list + i; struct object *o = parse_object(the_repository, &e->oid); @@@ -369,7 -369,7 +369,7 @@@ static int write_bundle_refs(int bundle * commit that is referenced by the tag, and not the tag * itself. */ - if (oidcmp(&oid, &e->item->oid)) { + if (!oideq(&oid, &e->item->oid)) { /* * Is this the positive end of a range expressed * in terms of a tag (e.g. v2.0 from the range @@@ -441,7 -441,7 +441,7 @@@ int create_bundle(struct bundle_header /* init revs to list objects for pack-objects later */ save_commit_buffer = 0; - init_revisions(&revs, NULL); + repo_init_revisions(the_repository, &revs, NULL); /* write prerequisites */ if (compute_and_write_prerequisites(bundle_fd, &revs, argc, argv)) diff --combined cache.h index d508f3d4f8,eb0f7d5470..1d749abf69 --- a/cache.h +++ b/cache.h @@@ -703,7 -703,7 +703,7 @@@ extern int unmerged_index(const struct * provided, the space-separated list of files that differ will be appended * to it. */ - extern int index_has_changes(const struct index_state *istate, + extern int index_has_changes(struct index_state *istate, struct tree *tree, struct strbuf *sb); @@@ -787,8 -787,8 +787,8 @@@ extern int ie_modified(struct index_sta #define HASH_WRITE_OBJECT 1 #define HASH_FORMAT_CHECK 2 #define HASH_RENORMALIZE 4 - extern int index_fd(struct object_id *oid, int fd, struct stat *st, enum object_type type, const char *path, unsigned flags); - extern int index_path(struct object_id *oid, const char *path, struct stat *st, unsigned flags); + extern int index_fd(struct index_state *istate, struct object_id *oid, int fd, struct stat *st, enum object_type type, const char *path, unsigned flags); + extern int index_path(struct index_state *istate, struct object_id *oid, const char *path, struct stat *st, unsigned flags); /* * Record to sd the data from st that we use to check whether a file @@@ -1041,24 -1041,14 +1041,24 @@@ static inline int oidcmp(const struct o return hashcmp(oid1->hash, oid2->hash); } +static inline int hasheq(const unsigned char *sha1, const unsigned char *sha2) +{ + return !hashcmp(sha1, sha2); +} + +static inline int oideq(const struct object_id *oid1, const struct object_id *oid2) +{ + return hasheq(oid1->hash, oid2->hash); +} + static inline int is_null_sha1(const unsigned char *sha1) { - return !hashcmp(sha1, null_sha1); + return hasheq(sha1, null_sha1); } static inline int is_null_oid(const struct object_id *oid) { - return !hashcmp(oid->hash, null_sha1); + return hasheq(oid->hash, null_sha1); } static inline void hashcpy(unsigned char *sha_dst, const unsigned char *sha_src) @@@ -1095,22 -1085,22 +1095,22 @@@ static inline void oidread(struct objec static inline int is_empty_blob_sha1(const unsigned char *sha1) { - return !hashcmp(sha1, the_hash_algo->empty_blob->hash); + return hasheq(sha1, the_hash_algo->empty_blob->hash); } static inline int is_empty_blob_oid(const struct object_id *oid) { - return !oidcmp(oid, the_hash_algo->empty_blob); + return oideq(oid, the_hash_algo->empty_blob); } static inline int is_empty_tree_sha1(const unsigned char *sha1) { - return !hashcmp(sha1, the_hash_algo->empty_tree->hash); + return hasheq(sha1, the_hash_algo->empty_tree->hash); } static inline int is_empty_tree_oid(const struct object_id *oid) { - return !oidcmp(oid, the_hash_algo->empty_tree); + return oideq(oid, the_hash_algo->empty_tree); } const char *empty_tree_oid_hex(void); @@@ -1528,7 -1518,6 +1528,7 @@@ struct checkout unsigned force:1, quiet:1, not_new:1, + clone:1, refresh_cache:1; }; #define CHECKOUT_INIT { NULL, "" } @@@ -1705,7 -1694,7 +1705,7 @@@ void shift_tree_by(const struct object_ /* All WS_* -- when extended, adapt diff.c emit_symbol */ #define WS_RULE_MASK 07777 extern unsigned whitespace_rule_cfg; - extern unsigned whitespace_rule(const char *); + extern unsigned whitespace_rule(struct index_state *, const char *); extern unsigned parse_whitespace_rule(const char *); extern unsigned ws_check(const char *line, int len, unsigned ws_rule); extern void ws_check_emit(const char *line, int len, unsigned ws_rule, FILE *stream, const char *set, const char *reset, const char *ws); @@@ -1727,10 -1716,12 +1727,12 @@@ extern struct startup_info *startup_inf /* merge.c */ struct commit_list; - int try_merge_command(const char *strategy, size_t xopts_nr, + int try_merge_command(struct repository *r, + const char *strategy, size_t xopts_nr, const char **xopts, struct commit_list *common, const char *head_arg, struct commit_list *remotes); - int checkout_fast_forward(const struct object_id *from, + int checkout_fast_forward(struct repository *r, + const struct object_id *from, const struct object_id *to, int overwrite_ignore); diff --combined combine-diff.c index 0fed4ca529,41ab5b01de..10155e0ec8 --- a/combine-diff.c +++ b/combine-diff.c @@@ -285,7 -285,8 +285,8 @@@ static struct lline *coalesce_lines(str return base; } - static char *grab_blob(const struct object_id *oid, unsigned int mode, + static char *grab_blob(struct repository *r, + const struct object_id *oid, unsigned int mode, unsigned long *size, struct userdiff_driver *textconv, const char *path) { @@@ -304,7 -305,7 +305,7 @@@ } else if (textconv) { struct diff_filespec *df = alloc_filespec(path); fill_filespec(df, oid, 1, mode); - *size = fill_textconv(textconv, df, &blob); + *size = fill_textconv(r, textconv, df, &blob); free_filespec(df); } else { blob = read_object_file(oid, &type, size); @@@ -389,7 -390,8 +390,8 @@@ static void consume_line(void *state_, } } - static void combine_diff(const struct object_id *parent, unsigned int mode, + static void combine_diff(struct repository *r, + const struct object_id *parent, unsigned int mode, mmfile_t *result_file, struct sline *sline, unsigned int cnt, int n, int num_parent, int result_deleted, @@@ -407,7 -409,7 +409,7 @@@ if (result_deleted) return; /* result deleted */ - parent_file.ptr = grab_blob(parent, mode, &sz, textconv, path); + parent_file.ptr = grab_blob(r, parent, mode, &sz, textconv, path); parent_file.size = sz; memset(&xpp, 0, sizeof(xpp)); xpp.flags = flags; @@@ -985,7 -987,7 +987,7 @@@ static void show_patch_diff(struct comb const char *line_prefix = diff_line_prefix(opt); context = opt->context; - userdiff = userdiff_find_by_path(elem->path); + userdiff = userdiff_find_by_path(opt->repo->index, elem->path); if (!userdiff) userdiff = userdiff_find_by_name("default"); if (opt->flags.allow_textconv) @@@ -993,7 -995,7 +995,7 @@@ /* Read the result of merge first */ if (!working_tree_file) - result = grab_blob(&elem->oid, elem->mode, &result_size, + result = grab_blob(opt->repo, &elem->oid, elem->mode, &result_size, textconv, elem->path); else { /* Used by diff-tree to read from the working tree */ @@@ -1016,15 -1018,16 +1018,16 @@@ } else if (S_ISDIR(st.st_mode)) { struct object_id oid; if (resolve_gitlink_ref(elem->path, "HEAD", &oid) < 0) - result = grab_blob(&elem->oid, elem->mode, - &result_size, NULL, NULL); + result = grab_blob(opt->repo, &elem->oid, + elem->mode, &result_size, + NULL, NULL); else - result = grab_blob(&oid, elem->mode, + result = grab_blob(opt->repo, &oid, elem->mode, &result_size, NULL, NULL); } else if (textconv) { struct diff_filespec *df = alloc_filespec(elem->path); fill_filespec(df, &null_oid, 0, st.st_mode); - result_size = fill_textconv(textconv, df, &result); + result_size = fill_textconv(opt->repo, textconv, df, &result); free_filespec(df); } else if (0 <= (fd = open(elem->path, O_RDONLY))) { size_t len = xsize_t(st.st_size); @@@ -1054,7 -1057,8 +1057,8 @@@ if (is_file) { struct strbuf buf = STRBUF_INIT; - if (convert_to_git(&the_index, elem->path, result, len, &buf, global_conv_flags_eol)) { + if (convert_to_git(rev->diffopt.repo->index, + elem->path, result, len, &buf, global_conv_flags_eol)) { free(result); result = strbuf_detach(&buf, &len); result_size = len; @@@ -1089,7 -1093,8 +1093,8 @@@ for (i = 0; !is_binary && i < num_parent; i++) { char *buf; unsigned long size; - buf = grab_blob(&elem->parent[i].oid, + buf = grab_blob(opt->repo, + &elem->parent[i].oid, elem->parent[i].mode, &size, NULL, NULL); if (buffer_is_binary(buf, size)) @@@ -1138,14 -1143,15 +1143,15 @@@ for (i = 0; i < num_parent; i++) { int j; for (j = 0; j < i; j++) { - if (!oidcmp(&elem->parent[i].oid, - &elem->parent[j].oid)) { + if (oideq(&elem->parent[i].oid, + &elem->parent[j].oid)) { reuse_combine_diff(sline, cnt, i, j); break; } } if (i <= j) - combine_diff(&elem->parent[i].oid, + combine_diff(opt->repo, + &elem->parent[i].oid, elem->parent[i].mode, &result_file, sline, cnt, i, num_parent, result_deleted, diff --combined diff-lib.c index 30bf9a2399,9a3b798cb5..83fce51518 --- a/diff-lib.c +++ b/diff-lib.c @@@ -70,7 -70,7 +70,7 @@@ static int match_stat_with_submodule(st struct stat *st, unsigned ce_option, unsigned *dirty_submodule) { - int changed = ce_match_stat(ce, st, ce_option); + int changed = ie_match_stat(diffopt->repo->index, ce, st, ce_option); if (S_ISGITLINK(ce->ce_mode)) { struct diff_flags orig_flags = diffopt->flags; if (!diffopt->flags.override_submodule_config) @@@ -93,15 -93,16 +93,16 @@@ int run_diff_files(struct rev_info *rev unsigned ce_option = ((option & DIFF_RACY_IS_MODIFIED) ? CE_MATCH_RACY_IS_DIRTY : 0); uint64_t start = getnanotime(); + struct index_state *istate = revs->diffopt.repo->index; diff_set_mnemonic_prefix(&revs->diffopt, "i/", "w/"); if (diff_unmerged_stage < 0) diff_unmerged_stage = 2; - entries = active_nr; + entries = istate->cache_nr; for (i = 0; i < entries; i++) { unsigned int oldmode, newmode; - struct cache_entry *ce = active_cache[i]; + struct cache_entry *ce = istate->cache[i]; int changed; unsigned dirty_submodule = 0; const struct object_id *old_oid, *new_oid; @@@ -109,7 -110,7 +110,7 @@@ if (diff_can_quit_early(&revs->diffopt)) break; - if (!ce_path_match(&the_index, ce, &revs->prune_data, NULL)) + if (!ce_path_match(istate, ce, &revs->prune_data, NULL)) continue; if (ce_stage(ce)) { @@@ -145,7 -146,7 +146,7 @@@ dpath->mode = wt_mode; while (i < entries) { - struct cache_entry *nce = active_cache[i]; + struct cache_entry *nce = istate->cache[i]; int stage; if (strcmp(ce->name, nce->name)) @@@ -342,7 -343,7 +343,7 @@@ static int show_modified(struct rev_inf } if (revs->combine_merges && !cached && - (oidcmp(oid, &old_entry->oid) || oidcmp(&old_entry->oid, &new_entry->oid))) { + (!oideq(oid, &old_entry->oid) || !oideq(&old_entry->oid, &new_entry->oid))) { struct combine_diff_path *p; int pathlen = ce_namelen(new_entry); @@@ -366,7 -367,7 +367,7 @@@ } oldmode = old_entry->ce_mode; - if (mode == oldmode && !oidcmp(oid, &old_entry->oid) && !dirty_submodule && + if (mode == oldmode && oideq(oid, &old_entry->oid) && !dirty_submodule && !revs->diffopt.flags.find_copies_harder) return 0; @@@ -474,7 -475,9 +475,9 @@@ static int oneway_diff(const struct cac if (tree == o->df_conflict_entry) tree = NULL; - if (ce_path_match(&the_index, idx ? idx : tree, &revs->prune_data, NULL)) { + if (ce_path_match(revs->diffopt.repo->index, + idx ? idx : tree, + &revs->prune_data, NULL)) { do_oneway_diff(o, idx, tree); if (diff_can_quit_early(&revs->diffopt)) { o->exiting_early = 1; @@@ -506,7 -509,7 +509,7 @@@ static int diff_cache(struct rev_info * opts.merge = 1; opts.fn = oneway_diff; opts.unpack_data = revs; - opts.src_index = &the_index; + opts.src_index = revs->diffopt.repo->index; opts.dst_index = NULL; opts.pathspec = &revs->diffopt.pathspec; opts.pathspec->recursive = 1; @@@ -518,11 -521,11 +521,11 @@@ int run_diff_index(struct rev_info *revs, int cached) { struct object_array_entry *ent; - uint64_t start = getnanotime(); if (revs->pending.nr != 1) BUG("run_diff_index must be passed exactly one tree"); + trace_performance_enter(); ent = revs->pending.objects; if (diff_cache(revs, &ent->item->oid, ent->name, cached)) exit(128); @@@ -531,7 -534,7 +534,7 @@@ diffcore_fix_diff_index(&revs->diffopt); diffcore_std(&revs->diffopt); diff_flush(&revs->diffopt); - trace_performance_since(start, "diff-index"); + trace_performance_leave("diff-index"); return 0; } @@@ -539,7 -542,7 +542,7 @@@ int do_diff_cache(const struct object_i { struct rev_info revs; - init_revisions(&revs, NULL); + repo_init_revisions(the_repository, &revs, NULL); copy_pathspec(&revs.prune_data, &opt->pathspec); revs.diffopt = *opt; @@@ -554,7 -557,7 +557,7 @@@ int index_differs_from(const char *def struct rev_info rev; struct setup_revision_opt opt; - init_revisions(&rev, NULL); + repo_init_revisions(the_repository, &rev, NULL); memset(&opt, 0, sizeof(opt)); opt.def = def; setup_revisions(0, NULL, &rev, &opt); diff --combined diff.c index f0c7557b40,c5b5e7ac41..42ba9e48d7 --- a/diff.c +++ b/diff.c @@@ -554,14 -554,15 +554,15 @@@ static int count_lines(const char *data return count; } - static int fill_mmfile(mmfile_t *mf, struct diff_filespec *one) + static int fill_mmfile(struct repository *r, mmfile_t *mf, + struct diff_filespec *one) { if (!DIFF_FILE_VALID(one)) { mf->ptr = (char *)""; /* does not matter */ mf->size = 0; return 0; } - else if (diff_populate_filespec(one, 0)) + else if (diff_populate_filespec(r, one, 0)) return -1; mf->ptr = one->data; @@@ -570,11 -571,12 +571,12 @@@ } /* like fill_mmfile, but only for size, so we can avoid retrieving blob */ - static unsigned long diff_filespec_size(struct diff_filespec *one) + static unsigned long diff_filespec_size(struct repository *r, + struct diff_filespec *one) { if (!DIFF_FILE_VALID(one)) return 0; - diff_populate_filespec(one, CHECK_SIZE_ONLY); + diff_populate_filespec(r, one, CHECK_SIZE_ONLY); return one->size; } @@@ -624,54 -626,42 +626,54 @@@ static void check_blank_at_eof(mmfile_ } static void emit_line_0(struct diff_options *o, - const char *set, unsigned reverse, const char *reset, + const char *set_sign, const char *set, unsigned reverse, const char *reset, int first, const char *line, int len) { int has_trailing_newline, has_trailing_carriage_return; - int nofirst; + int needs_reset = 0; /* at the end of the line */ FILE *file = o->file; - if (first) - fputs(diff_line_prefix(o), file); - else if (!len) - return; + fputs(diff_line_prefix(o), file); - if (len == 0) { - has_trailing_newline = (first == '\n'); - has_trailing_carriage_return = (!has_trailing_newline && - (first == '\r')); - nofirst = has_trailing_newline || has_trailing_carriage_return; - } else { - has_trailing_newline = (len > 0 && line[len-1] == '\n'); - if (has_trailing_newline) - len--; - has_trailing_carriage_return = (len > 0 && line[len-1] == '\r'); - if (has_trailing_carriage_return) - len--; - nofirst = 0; + has_trailing_newline = (len > 0 && line[len-1] == '\n'); + if (has_trailing_newline) + len--; + + has_trailing_carriage_return = (len > 0 && line[len-1] == '\r'); + if (has_trailing_carriage_return) + len--; + + if (!len && !first) + goto end_of_line; + + if (reverse && want_color(o->use_color)) { + fputs(GIT_COLOR_REVERSE, file); + needs_reset = 1; } - if (len || !nofirst) { - if (reverse && want_color(o->use_color)) - fputs(GIT_COLOR_REVERSE, file); + if (set_sign) { + fputs(set_sign, file); + needs_reset = 1; + } + + if (first) + fputc(first, file); + + if (!len) + goto end_of_line; + + if (set) { + if (set_sign && set != set_sign) + fputs(reset, file); fputs(set, file); - if (first && !nofirst) - fputc(first, file); - fwrite(line, len, 1, file); - fputs(reset, file); + needs_reset = 1; } + fwrite(line, len, 1, file); + needs_reset = 1; /* 'line' may contain color codes. */ + +end_of_line: + if (needs_reset) + fputs(reset, file); if (has_trailing_carriage_return) fputc('\r', file); if (has_trailing_newline) @@@ -681,7 -671,7 +683,7 @@@ static void emit_line(struct diff_options *o, const char *set, const char *reset, const char *line, int len) { - emit_line_0(o, set, 0, reset, line[0], line+1, len-1); + emit_line_0(o, set, NULL, 0, reset, 0, line, len); } enum diff_symbol { @@@ -980,13 -970,8 +982,13 @@@ static void pmb_advance_or_null_multi_m /* Carry the white space delta forward */ pmb[i]->next_line->wsd = pmb[i]->wsd; pmb[i] = pmb[i]->next_line; - } else + } else { + if (pmb[i]->wsd) { + free(pmb[i]->wsd->string); + FREE_AND_NULL(pmb[i]->wsd); + } pmb[i] = NULL; + } } } @@@ -1007,6 -992,10 +1009,6 @@@ static int shrink_potential_moved_block if (lp < pmb_nr && rp > -1 && lp < rp) { pmb[lp] = pmb[rp]; - if (pmb[rp]->wsd) { - free(pmb[rp]->wsd->string); - FREE_AND_NULL(pmb[rp]->wsd); - } pmb[rp] = NULL; rp--; lp++; @@@ -1200,9 -1189,9 +1202,9 @@@ static void dim_moved_lines(struct diff } static void emit_line_ws_markup(struct diff_options *o, - const char *set, const char *reset, - const char *line, int len, - const char *set_sign, char sign, + const char *set_sign, const char *set, + const char *reset, + char sign, const char *line, int len, unsigned ws_rule, int blank_at_eof) { const char *ws = NULL; @@@ -1214,15 -1203,18 +1216,15 @@@ } if (!ws && !set_sign) - emit_line_0(o, set, 0, reset, sign, line, len); + emit_line_0(o, set, NULL, 0, reset, sign, line, len); else if (!ws) { - /* Emit just the prefix, then the rest. */ - emit_line_0(o, set_sign ? set_sign : set, !!set_sign, reset, - sign, "", 0); - emit_line_0(o, set, 0, reset, 0, line, len); + emit_line_0(o, set_sign, set, !!set_sign, reset, sign, line, len); } else if (blank_at_eof) /* Blank line at EOF - paint '+' as well */ - emit_line_0(o, ws, 0, reset, sign, line, len); + emit_line_0(o, ws, NULL, 0, reset, sign, line, len); else { /* Emit just the prefix, then the rest. */ - emit_line_0(o, set_sign ? set_sign : set, !!set_sign, reset, + emit_line_0(o, set_sign ? set_sign : set, NULL, !!set_sign, reset, sign, "", 0); ws_check_emit(line, len, ws_rule, o->file, set, reset, ws); @@@ -1246,7 -1238,7 +1248,7 @@@ static void emit_diff_symbol_from_struc context = diff_get_color_opt(o, DIFF_CONTEXT); reset = diff_get_color_opt(o, DIFF_RESET); putc('\n', o->file); - emit_line_0(o, context, 0, reset, '\\', + emit_line_0(o, context, NULL, 0, reset, '\\', nneof, strlen(nneof)); break; case DIFF_SYMBOL_SUBMODULE_HEADER: @@@ -1284,9 -1276,7 +1286,9 @@@ else if (c == '-') set = diff_get_color_opt(o, DIFF_FILE_OLD); } - emit_line_ws_markup(o, set, reset, line, len, set_sign, ' ', + emit_line_ws_markup(o, set_sign, set, reset, + o->output_indicators[OUTPUT_INDICATOR_CONTEXT], + line, len, flags & (DIFF_SYMBOL_CONTENT_WS_MASK), 0); break; case DIFF_SYMBOL_PLUS: @@@ -1329,9 -1319,7 +1331,9 @@@ set = diff_get_color_opt(o, DIFF_CONTEXT_BOLD); flags &= ~DIFF_SYMBOL_CONTENT_WS_MASK; } - emit_line_ws_markup(o, set, reset, line, len, set_sign, '+', + emit_line_ws_markup(o, set_sign, set, reset, + o->output_indicators[OUTPUT_INDICATOR_NEW], + line, len, flags & DIFF_SYMBOL_CONTENT_WS_MASK, flags & DIFF_SYMBOL_CONTENT_BLANK_LINE_EOF); break; @@@ -1374,9 -1362,7 +1376,9 @@@ else set = diff_get_color_opt(o, DIFF_CONTEXT_DIM); } - emit_line_ws_markup(o, set, reset, line, len, set_sign, '-', + emit_line_ws_markup(o, set_sign, set, reset, + o->output_indicators[OUTPUT_INDICATOR_OLD], + line, len, flags & DIFF_SYMBOL_CONTENT_WS_MASK, 0); break; case DIFF_SYMBOL_WORDS_PORCELAIN: @@@ -1714,12 -1700,12 +1716,12 @@@ static void emit_rewrite_diff(const cha quote_two_c_style(&a_name, a_prefix, name_a, 0); quote_two_c_style(&b_name, b_prefix, name_b, 0); - size_one = fill_textconv(textconv_one, one, &data_one); - size_two = fill_textconv(textconv_two, two, &data_two); + size_one = fill_textconv(o->repo, textconv_one, one, &data_one); + size_two = fill_textconv(o->repo, textconv_two, two, &data_two); memset(&ecbdata, 0, sizeof(ecbdata)); ecbdata.color_diff = want_color(o->use_color); - ecbdata.ws_rule = whitespace_rule(name_b); + ecbdata.ws_rule = whitespace_rule(o->repo->index, name_b); ecbdata.opt = o; if (ecbdata.ws_rule & WS_BLANK_AT_EOF) { mmfile_t mf1, mf2; @@@ -2107,23 -2093,25 +2109,25 @@@ static void diff_words_flush(struct emi } } - static void diff_filespec_load_driver(struct diff_filespec *one) + static void diff_filespec_load_driver(struct diff_filespec *one, + struct index_state *istate) { /* Use already-loaded driver */ if (one->driver) return; if (S_ISREG(one->mode)) - one->driver = userdiff_find_by_path(one->path); + one->driver = userdiff_find_by_path(istate, one->path); /* Fallback to default settings */ if (!one->driver) one->driver = userdiff_find_by_name("default"); } - static const char *userdiff_word_regex(struct diff_filespec *one) + static const char *userdiff_word_regex(struct diff_filespec *one, + struct index_state *istate) { - diff_filespec_load_driver(one); + diff_filespec_load_driver(one, istate); return one->driver->word_regex; } @@@ -2146,9 -2134,9 +2150,9 @@@ static void init_diff_words_data(struc xcalloc(1, sizeof(struct emitted_diff_symbols)); if (!o->word_regex) - o->word_regex = userdiff_word_regex(one); + o->word_regex = userdiff_word_regex(one, o->repo->index); if (!o->word_regex) - o->word_regex = userdiff_word_regex(two); + o->word_regex = userdiff_word_regex(two, o->repo->index); if (!o->word_regex) o->word_regex = diff_word_regex_cfg; if (o->word_regex) { @@@ -2949,11 -2937,16 +2953,11 @@@ static void show_dirstat(struct diff_op struct diff_filepair *p = q->queue[i]; const char *name; unsigned long copied, added, damage; - int content_changed; name = p->two->path ? p->two->path : p->one->path; - if (p->one->oid_valid && p->two->oid_valid) - content_changed = oidcmp(&p->one->oid, &p->two->oid); - else - content_changed = 1; - - if (!content_changed) { + if (p->one->oid_valid && p->two->oid_valid && + oideq(&p->one->oid, &p->two->oid)) { /* * The SHA1 has not changed, so pre-/post-content is * identical. We can therefore skip looking at the @@@ -2976,18 -2969,19 +2980,19 @@@ } if (DIFF_FILE_VALID(p->one) && DIFF_FILE_VALID(p->two)) { - diff_populate_filespec(p->one, 0); - diff_populate_filespec(p->two, 0); - diffcore_count_changes(p->one, p->two, NULL, NULL, + diff_populate_filespec(options->repo, p->one, 0); + diff_populate_filespec(options->repo, p->two, 0); + diffcore_count_changes(options->repo, + p->one, p->two, NULL, NULL, &copied, &added); diff_free_filespec_data(p->one); diff_free_filespec_data(p->two); } else if (DIFF_FILE_VALID(p->one)) { - diff_populate_filespec(p->one, CHECK_SIZE_ONLY); + diff_populate_filespec(options->repo, p->one, CHECK_SIZE_ONLY); copied = added = 0; diff_free_filespec_data(p->one); } else if (DIFF_FILE_VALID(p->two)) { - diff_populate_filespec(p->two, CHECK_SIZE_ONLY); + diff_populate_filespec(options->repo, p->two, CHECK_SIZE_ONLY); copied = 0; added = p->two->size; diff_free_filespec_data(p->two); @@@ -3000,7 -2994,7 +3005,7 @@@ * made to the preimage. * If the resulting damage is zero, we know that * diffcore_count_changes() considers the two entries to - * be identical, but since content_changed is true, we + * be identical, but since the oid changed, we * know that there must have been _some_ kind of change, * so we force all entries to have damage > 0. */ @@@ -3261,15 -3255,16 +3266,16 @@@ static void emit_binary_diff(struct dif emit_binary_diff_body(o, two, one); } - int diff_filespec_is_binary(struct diff_filespec *one) + int diff_filespec_is_binary(struct repository *r, + struct diff_filespec *one) { if (one->is_binary == -1) { - diff_filespec_load_driver(one); + diff_filespec_load_driver(one, r->index); if (one->driver->binary != -1) one->is_binary = one->driver->binary; else { if (!one->data && DIFF_FILE_VALID(one)) - diff_populate_filespec(one, CHECK_BINARY); + diff_populate_filespec(r, one, CHECK_BINARY); if (one->is_binary == -1 && one->data) one->is_binary = buffer_is_binary(one->data, one->size); @@@ -3280,9 -3275,10 +3286,10 @@@ return one->is_binary; } - static const struct userdiff_funcname *diff_funcname_pattern(struct diff_filespec *one) + static const struct userdiff_funcname * + diff_funcname_pattern(struct diff_options *o, struct diff_filespec *one) { - diff_filespec_load_driver(one); + diff_filespec_load_driver(one, o->repo->index); return one->driver->funcname.pattern ? &one->driver->funcname : NULL; } @@@ -3294,12 -3290,13 +3301,13 @@@ void diff_set_mnemonic_prefix(struct di options->b_prefix = b; } - struct userdiff_driver *get_textconv(struct diff_filespec *one) + struct userdiff_driver *get_textconv(struct index_state *istate, + struct diff_filespec *one) { if (!DIFF_FILE_VALID(one)) return NULL; - diff_filespec_load_driver(one); + diff_filespec_load_driver(one, istate); return userdiff_get_textconv(one->driver); } @@@ -3349,8 -3346,8 +3357,8 @@@ static void builtin_diff(const char *na } if (o->flags.allow_textconv) { - textconv_one = get_textconv(one); - textconv_two = get_textconv(two); + textconv_one = get_textconv(o->repo->index, one); + textconv_two = get_textconv(o->repo->index, two); } /* Never use a non-valid filename anywhere if at all possible */ @@@ -3391,13 -3388,13 +3399,13 @@@ if ((one->mode ^ two->mode) & S_IFMT) goto free_ab_and_return; if (complete_rewrite && - (textconv_one || !diff_filespec_is_binary(one)) && - (textconv_two || !diff_filespec_is_binary(two))) { + (textconv_one || !diff_filespec_is_binary(o->repo, one)) && + (textconv_two || !diff_filespec_is_binary(o->repo, two))) { emit_diff_symbol(o, DIFF_SYMBOL_HEADER, header.buf, header.len, 0); strbuf_reset(&header); emit_rewrite_diff(name_a, name_b, one, two, - textconv_one, textconv_two, o); + textconv_one, textconv_two, o); o->found_changes = 1; goto free_ab_and_return; } @@@ -3409,13 -3406,13 +3417,13 @@@ strbuf_reset(&header); goto free_ab_and_return; } else if (!o->flags.text && - ( (!textconv_one && diff_filespec_is_binary(one)) || - (!textconv_two && diff_filespec_is_binary(two)) )) { + ( (!textconv_one && diff_filespec_is_binary(o->repo, one)) || + (!textconv_two && diff_filespec_is_binary(o->repo, two)) )) { struct strbuf sb = STRBUF_INIT; if (!one->data && !two->data && S_ISREG(one->mode) && S_ISREG(two->mode) && !o->flags.binary) { - if (!oidcmp(&one->oid, &two->oid)) { + if (oideq(&one->oid, &two->oid)) { if (must_show_header) emit_diff_symbol(o, DIFF_SYMBOL_HEADER, header.buf, header.len, @@@ -3431,7 -3428,8 +3439,8 @@@ strbuf_release(&sb); goto free_ab_and_return; } - if (fill_mmfile(&mf1, one) < 0 || fill_mmfile(&mf2, two) < 0) + if (fill_mmfile(o->repo, &mf1, one) < 0 || + fill_mmfile(o->repo, &mf2, two) < 0) die("unable to read files to diff"); /* Quite common confusing case */ if (mf1.size == mf2.size && @@@ -3468,12 -3466,12 +3477,12 @@@ strbuf_reset(&header); } - mf1.size = fill_textconv(textconv_one, one, &mf1.ptr); - mf2.size = fill_textconv(textconv_two, two, &mf2.ptr); + mf1.size = fill_textconv(o->repo, textconv_one, one, &mf1.ptr); + mf2.size = fill_textconv(o->repo, textconv_two, two, &mf2.ptr); - pe = diff_funcname_pattern(one); + pe = diff_funcname_pattern(o, one); if (!pe) - pe = diff_funcname_pattern(two); + pe = diff_funcname_pattern(o, two); memset(&xpp, 0, sizeof(xpp)); memset(&xecfg, 0, sizeof(xecfg)); @@@ -3482,7 -3480,7 +3491,7 @@@ lbl[0] = NULL; ecbdata.label_path = lbl; ecbdata.color_diff = want_color(o->use_color); - ecbdata.ws_rule = whitespace_rule(name_b); + ecbdata.ws_rule = whitespace_rule(o->repo->index, name_b); if (ecbdata.ws_rule & WS_BLANK_AT_EOF) check_blank_at_eof(&mf1, &mf2, &ecbdata); ecbdata.opt = o; @@@ -3580,22 -3578,23 +3589,23 @@@ static void builtin_diffstat(const cha return; } - same_contents = !oidcmp(&one->oid, &two->oid); + same_contents = oideq(&one->oid, &two->oid); - if (diff_filespec_is_binary(one) || diff_filespec_is_binary(two)) { + if (diff_filespec_is_binary(o->repo, one) || + diff_filespec_is_binary(o->repo, two)) { data->is_binary = 1; if (same_contents) { data->added = 0; data->deleted = 0; } else { - data->added = diff_filespec_size(two); - data->deleted = diff_filespec_size(one); + data->added = diff_filespec_size(o->repo, two); + data->deleted = diff_filespec_size(o->repo, one); } } else if (complete_rewrite) { - diff_populate_filespec(one, 0); - diff_populate_filespec(two, 0); + diff_populate_filespec(o->repo, one, 0); + diff_populate_filespec(o->repo, two, 0); data->deleted = count_lines(one->data, one->size); data->added = count_lines(two->data, two->size); } @@@ -3605,7 -3604,8 +3615,8 @@@ xpparam_t xpp; xdemitconf_t xecfg; - if (fill_mmfile(&mf1, one) < 0 || fill_mmfile(&mf2, two) < 0) + if (fill_mmfile(o->repo, &mf1, one) < 0 || + fill_mmfile(o->repo, &mf2, two) < 0) die("unable to read files to diff"); memset(&xpp, 0, sizeof(xpp)); @@@ -3640,10 -3640,11 +3651,11 @@@ static void builtin_checkdiff(const cha data.filename = name_b ? name_b : name_a; data.lineno = 0; data.o = o; - data.ws_rule = whitespace_rule(attr_path); - data.conflict_marker_size = ll_merge_marker_size(attr_path); + data.ws_rule = whitespace_rule(o->repo->index, attr_path); + data.conflict_marker_size = ll_merge_marker_size(o->repo->index, attr_path); - if (fill_mmfile(&mf1, one) < 0 || fill_mmfile(&mf2, two) < 0) + if (fill_mmfile(o->repo, &mf1, one) < 0 || + fill_mmfile(o->repo, &mf2, two) < 0) die("unable to read files to diff"); /* @@@ -3652,7 -3653,7 +3664,7 @@@ * introduced changes, and as long as the "new" side is text, we * can and should check what it introduces. */ - if (diff_filespec_is_binary(two)) + if (diff_filespec_is_binary(o->repo, two)) goto free_and_return; else { /* Crazy xdl interfaces.. */ @@@ -3725,7 -3726,10 +3737,10 @@@ void fill_filespec(struct diff_filespe * the work tree has that object contents, return true, so that * prepare_temp_file() does not have to inflate and extract. */ - static int reuse_worktree_file(const char *name, const struct object_id *oid, int want_file) + static int reuse_worktree_file(struct index_state *istate, + const char *name, + const struct object_id *oid, + int want_file) { const struct cache_entry *ce; struct stat st; @@@ -3744,7 -3748,7 +3759,7 @@@ * by diff-cache --cached, which does read the cache before * calling us. */ - if (!active_cache) + if (!istate->cache) return 0; /* We want to avoid the working directory if our caller @@@ -3763,20 -3767,20 +3778,20 @@@ * Similarly, if we'd have to convert the file contents anyway, that * makes the optimization not worthwhile. */ - if (!want_file && would_convert_to_git(&the_index, name)) + if (!want_file && would_convert_to_git(istate, name)) return 0; len = strlen(name); - pos = cache_name_pos(name, len); + pos = index_name_pos(istate, name, len); if (pos < 0) return 0; - ce = active_cache[pos]; + ce = istate->cache[pos]; /* * This is not the sha1 we are looking for, or * unreusable because it is not a regular file. */ - if (oidcmp(oid, &ce->oid) || !S_ISREG(ce->ce_mode)) + if (!oideq(oid, &ce->oid) || !S_ISREG(ce->ce_mode)) return 0; /* @@@ -3790,7 -3794,7 +3805,7 @@@ * If ce matches the file in the work tree, we can reuse it. */ if (ce_uptodate(ce) || - (!lstat(name, &st) && !ce_match_stat(ce, &st, 0))) + (!lstat(name, &st) && !ie_match_stat(istate, ce, &st, 0))) return 1; return 0; @@@ -3823,7 -3827,9 +3838,9 @@@ static int diff_populate_gitlink(struc * grab the data for the blob (or file) for our own in-core comparison. * diff_filespec has data and size fields for this purpose. */ - int diff_populate_filespec(struct diff_filespec *s, unsigned int flags) + int diff_populate_filespec(struct repository *r, + struct diff_filespec *s, + unsigned int flags) { int size_only = flags & CHECK_SIZE_ONLY; int err = 0; @@@ -3850,7 -3856,7 +3867,7 @@@ return diff_populate_gitlink(s, size_only); if (!s->oid_valid || - reuse_worktree_file(s->path, &s->oid, 0)) { + reuse_worktree_file(r->index, s->path, &s->oid, 0)) { struct strbuf buf = STRBUF_INIT; struct stat st; int fd; @@@ -3883,7 -3889,7 +3900,7 @@@ * point if the path requires us to run the content * conversion. */ - if (size_only && !would_convert_to_git(&the_index, s->path)) + if (size_only && !would_convert_to_git(r->index, s->path)) return 0; /* @@@ -3910,7 -3916,7 +3927,7 @@@ /* * Convert from working tree format to canonical git format */ - if (convert_to_git(&the_index, s->path, s->data, s->size, &buf, conv_flags)) { + if (convert_to_git(r->index, s->path, s->data, s->size, &buf, conv_flags)) { size_t size = 0; munmap(s->data, s->size); s->should_munmap = 0; @@@ -3922,8 -3928,7 +3939,7 @@@ else { enum object_type type; if (size_only || (flags & CHECK_BINARY)) { - type = oid_object_info(the_repository, &s->oid, - &s->size); + type = oid_object_info(r, &s->oid, &s->size); if (type < 0) die("unable to read %s", oid_to_hex(&s->oid)); @@@ -3961,7 -3966,8 +3977,8 @@@ void diff_free_filespec_data(struct dif FREE_AND_NULL(s->cnt_data); } - static void prep_temp_blob(const char *path, struct diff_tempfile *temp, + static void prep_temp_blob(struct index_state *istate, + const char *path, struct diff_tempfile *temp, void *blob, unsigned long size, const struct object_id *oid, @@@ -3979,7 -3985,7 +3996,7 @@@ temp->tempfile = mks_tempfile_ts(tempfile.buf, strlen(base) + 1); if (!temp->tempfile) die_errno("unable to create temp-file"); - if (convert_to_working_tree(&the_index, path, + if (convert_to_working_tree(istate, path, (const char *)blob, (size_t)size, &buf)) { blob = buf.buf; size = buf.len; @@@ -3995,8 -4001,9 +4012,9 @@@ free(path_dup); } - static struct diff_tempfile *prepare_temp_file(const char *name, - struct diff_filespec *one) + static struct diff_tempfile *prepare_temp_file(struct repository *r, + const char *name, + struct diff_filespec *one) { struct diff_tempfile *temp = claim_diff_tempfile(); @@@ -4013,7 -4020,7 +4031,7 @@@ if (!S_ISGITLINK(one->mode) && (!one->oid_valid || - reuse_worktree_file(name, &one->oid, 1))) { + reuse_worktree_file(r->index, name, &one->oid, 1))) { struct stat st; if (lstat(name, &st) < 0) { if (errno == ENOENT) @@@ -4024,7 -4031,7 +4042,7 @@@ struct strbuf sb = STRBUF_INIT; if (strbuf_readlink(&sb, name, st.st_size) < 0) die_errno("readlink(%s)", name); - prep_temp_blob(name, temp, sb.buf, sb.len, + prep_temp_blob(r->index, name, temp, sb.buf, sb.len, (one->oid_valid ? &one->oid : &null_oid), (one->oid_valid ? @@@ -4049,19 -4056,21 +4067,21 @@@ return temp; } else { - if (diff_populate_filespec(one, 0)) + if (diff_populate_filespec(r, one, 0)) die("cannot read data blob for %s", one->path); - prep_temp_blob(name, temp, one->data, one->size, + prep_temp_blob(r->index, name, temp, + one->data, one->size, &one->oid, one->mode); } return temp; } - static void add_external_diff_name(struct argv_array *argv, + static void add_external_diff_name(struct repository *r, + struct argv_array *argv, const char *name, struct diff_filespec *df) { - struct diff_tempfile *temp = prepare_temp_file(name, df); + struct diff_tempfile *temp = prepare_temp_file(r, name, df); argv_array_push(argv, temp->name); argv_array_push(argv, temp->hex); argv_array_push(argv, temp->mode); @@@ -4090,11 -4099,11 +4110,11 @@@ static void run_external_diff(const cha argv_array_push(&argv, name); if (one && two) { - add_external_diff_name(&argv, name, one); + add_external_diff_name(o->repo, &argv, name, one); if (!other) - add_external_diff_name(&argv, name, two); + add_external_diff_name(o->repo, &argv, name, two); else { - add_external_diff_name(&argv, other, two); + add_external_diff_name(o->repo, &argv, other, two); argv_array_push(&argv, other); argv_array_push(&argv, xfrm_msg); } @@@ -4181,14 -4190,16 +4201,16 @@@ static void fill_metainfo(struct strbu default: *must_show_header = 0; } - if (one && two && oidcmp(&one->oid, &two->oid)) { + if (one && two && !oideq(&one->oid, &two->oid)) { const unsigned hexsz = the_hash_algo->hexsz; int abbrev = o->flags.full_index ? hexsz : DEFAULT_ABBREV; if (o->flags.binary) { mmfile_t mf; - if ((!fill_mmfile(&mf, one) && diff_filespec_is_binary(one)) || - (!fill_mmfile(&mf, two) && diff_filespec_is_binary(two))) + if ((!fill_mmfile(o->repo, &mf, one) && + diff_filespec_is_binary(o->repo, one)) || + (!fill_mmfile(o->repo, &mf, two) && + diff_filespec_is_binary(o->repo, two))) abbrev = hexsz; } strbuf_addf(msg, "%s%sindex %s..%s", line_prefix, set, @@@ -4216,7 -4227,9 +4238,9 @@@ static void run_diff_cmd(const char *pg if (o->flags.allow_external) { - struct userdiff_driver *drv = userdiff_find_by_path(attr_path); + struct userdiff_driver *drv; + + drv = userdiff_find_by_path(o->repo->index, attr_path); if (drv && drv->external) pgm = drv->external; } @@@ -4245,7 -4258,7 +4269,7 @@@ fprintf(o->file, "* Unmerged path %s\n", name); } - static void diff_fill_oid_info(struct diff_filespec *one) + static void diff_fill_oid_info(struct diff_filespec *one, struct index_state *istate) { if (DIFF_FILE_VALID(one)) { if (!one->oid_valid) { @@@ -4256,7 -4269,7 +4280,7 @@@ } if (lstat(one->path, &st) < 0) die_errno("stat '%s'", one->path); - if (index_path(&one->oid, one->path, &st, 0)) + if (index_path(istate, &one->oid, one->path, &st, 0)) die("cannot hash %s", one->path); } } @@@ -4304,8 -4317,8 +4328,8 @@@ static void run_diff(struct diff_filepa return; } - diff_fill_oid_info(one); - diff_fill_oid_info(two); + diff_fill_oid_info(one, o->repo->index); + diff_fill_oid_info(two, o->repo->index); if (!pgm && DIFF_FILE_VALID(one) && DIFF_FILE_VALID(two) && @@@ -4316,7 -4329,8 +4340,8 @@@ */ struct diff_filespec *null = alloc_filespec(two->path); run_diff_cmd(NULL, name, other, attr_path, - one, null, &msg, o, p); + one, null, &msg, + o, p); free(null); strbuf_release(&msg); @@@ -4340,7 -4354,8 +4365,8 @@@ static void run_diffstat(struct diff_fi if (DIFF_PAIR_UNMERGED(p)) { /* unmerged */ - builtin_diffstat(p->one->path, NULL, NULL, NULL, diffstat, o, p); + builtin_diffstat(p->one->path, NULL, NULL, NULL, + diffstat, o, p); return; } @@@ -4350,10 -4365,11 +4376,11 @@@ if (o->prefix_length) strip_prefix(o->prefix_length, &name, &other); - diff_fill_oid_info(p->one); - diff_fill_oid_info(p->two); + diff_fill_oid_info(p->one, o->repo->index); + diff_fill_oid_info(p->two, o->repo->index); - builtin_diffstat(name, other, p->one, p->two, diffstat, o, p); + builtin_diffstat(name, other, p->one, p->two, + diffstat, o, p); } static void run_checkdiff(struct diff_filepair *p, struct diff_options *o) @@@ -4374,21 -4390,19 +4401,22 @@@ if (o->prefix_length) strip_prefix(o->prefix_length, &name, &other); - diff_fill_oid_info(p->one); - diff_fill_oid_info(p->two); + diff_fill_oid_info(p->one, o->repo->index); + diff_fill_oid_info(p->two, o->repo->index); builtin_checkdiff(name, other, attr_path, p->one, p->two, o); } - void diff_setup(struct diff_options *options) + void repo_diff_setup(struct repository *r, struct diff_options *options) { memcpy(options, &default_diff_options, sizeof(*options)); options->file = stdout; + options->repo = r; + options->output_indicators[OUTPUT_INDICATOR_NEW] = '+'; + options->output_indicators[OUTPUT_INDICATOR_OLD] = '-'; + options->output_indicators[OUTPUT_INDICATOR_CONTEXT] = ' '; options->abbrev = DEFAULT_ABBREV; options->line_termination = '\n'; options->break_opt = -1; @@@ -4866,12 -4880,6 +4894,12 @@@ int diff_opt_parse(struct diff_options options->output_format |= DIFF_FORMAT_DIFFSTAT; } else if (!strcmp(arg, "--no-compact-summary")) options->flags.stat_with_summary = 0; + else if (skip_prefix(arg, "--output-indicator-new=", &arg)) + options->output_indicators[OUTPUT_INDICATOR_NEW] = arg[0]; + else if (skip_prefix(arg, "--output-indicator-old=", &arg)) + options->output_indicators[OUTPUT_INDICATOR_OLD] = arg[0]; + else if (skip_prefix(arg, "--output-indicator-context=", &arg)) + options->output_indicators[OUTPUT_INDICATOR_CONTEXT] = arg[0]; /* renames options */ else if (starts_with(arg, "-B") || @@@ -5343,7 -5351,7 +5371,7 @@@ int diff_unmodified_pair(struct diff_fi * dealing with a change. */ if (one->oid_valid && two->oid_valid && - !oidcmp(&one->oid, &two->oid) && + oideq(&one->oid, &two->oid) && !one->dirty_submodule && !two->dirty_submodule) return 1; /* no change */ if (!one->oid_valid && !two->oid_valid) @@@ -5477,7 -5485,7 +5505,7 @@@ static void diff_resolve_rename_copy(vo else p->status = DIFF_STATUS_RENAMED; } - else if (oidcmp(&p->one->oid, &p->two->oid) || + else if (!oideq(&p->one->oid, &p->two->oid) || p->one->mode != p->two->mode || p->one->dirty_submodule || p->two->dirty_submodule || @@@ -5683,8 -5691,8 +5711,8 @@@ static int diff_get_patch_id(struct dif if (DIFF_PAIR_UNMERGED(p)) continue; - diff_fill_oid_info(p->one); - diff_fill_oid_info(p->two); + diff_fill_oid_info(p->one, options->repo->index); + diff_fill_oid_info(p->two, options->repo->index); len1 = remove_space(p->one->path, strlen(p->one->path)); len2 = remove_space(p->two->path, strlen(p->two->path)); @@@ -5716,12 -5724,12 +5744,12 @@@ if (diff_header_only) continue; - if (fill_mmfile(&mf1, p->one) < 0 || - fill_mmfile(&mf2, p->two) < 0) + if (fill_mmfile(options->repo, &mf1, p->one) < 0 || + fill_mmfile(options->repo, &mf2, p->two) < 0) return error("unable to read files to diff"); - if (diff_filespec_is_binary(p->one) || - diff_filespec_is_binary(p->two)) { + if (diff_filespec_is_binary(options->repo, p->one) || + diff_filespec_is_binary(options->repo, p->two)) { git_SHA1_Update(&ctx, oid_to_hex(&p->one->oid), GIT_SHA1_HEXSZ); git_SHA1_Update(&ctx, oid_to_hex(&p->two->oid), @@@ -6024,19 -6032,21 +6052,21 @@@ static void diffcore_apply_filter(struc } /* Check whether two filespecs with the same mode and size are identical */ - static int diff_filespec_is_identical(struct diff_filespec *one, + static int diff_filespec_is_identical(struct repository *r, + struct diff_filespec *one, struct diff_filespec *two) { if (S_ISGITLINK(one->mode)) return 0; - if (diff_populate_filespec(one, 0)) + if (diff_populate_filespec(r, one, 0)) return 0; - if (diff_populate_filespec(two, 0)) + if (diff_populate_filespec(r, two, 0)) return 0; return !memcmp(one->data, two->data, one->size); } - static int diff_filespec_check_stat_unmatch(struct diff_filepair *p) + static int diff_filespec_check_stat_unmatch(struct repository *r, + struct diff_filepair *p) { if (p->done_skip_stat_unmatch) return p->skip_stat_unmatch_result; @@@ -6060,10 -6070,10 +6090,10 @@@ !DIFF_FILE_VALID(p->two) || (p->one->oid_valid && p->two->oid_valid) || (p->one->mode != p->two->mode) || - diff_populate_filespec(p->one, CHECK_SIZE_ONLY) || - diff_populate_filespec(p->two, CHECK_SIZE_ONLY) || + diff_populate_filespec(r, p->one, CHECK_SIZE_ONLY) || + diff_populate_filespec(r, p->two, CHECK_SIZE_ONLY) || (p->one->size != p->two->size) || - !diff_filespec_is_identical(p->one, p->two)) /* (2) */ + !diff_filespec_is_identical(r, p->one, p->two)) /* (2) */ p->skip_stat_unmatch_result = 1; return p->skip_stat_unmatch_result; } @@@ -6078,7 -6088,7 +6108,7 @@@ static void diffcore_skip_stat_unmatch( for (i = 0; i < q->nr; i++) { struct diff_filepair *p = q->queue[i]; - if (diff_filespec_check_stat_unmatch(p)) + if (diff_filespec_check_stat_unmatch(diffopt->repo, p)) diff_q(&outq, p); else { /* @@@ -6120,7 -6130,8 +6150,8 @@@ void diffcore_std(struct diff_options * if (!options->found_follow) { /* See try_to_follow_renames() in tree-diff.c */ if (options->break_opt != -1) - diffcore_break(options->break_opt); + diffcore_break(options->repo, + options->break_opt); if (options->detect_rename) diffcore_rename(options); if (options->break_opt != -1) @@@ -6271,7 -6282,7 +6302,7 @@@ void diff_change(struct diff_options *o return; if (options->flags.quick && options->skip_stat_unmatch && - !diff_filespec_check_stat_unmatch(p)) + !diff_filespec_check_stat_unmatch(options->repo, p)) return; options->flags.has_changes = 1; @@@ -6293,8 -6304,10 +6324,10 @@@ struct diff_filepair *diff_unmerge(stru return pair; } - static char *run_textconv(const char *pgm, struct diff_filespec *spec, - size_t *outsize) + static char *run_textconv(struct repository *r, + const char *pgm, + struct diff_filespec *spec, + size_t *outsize) { struct diff_tempfile *temp; const char *argv[3]; @@@ -6303,7 -6316,7 +6336,7 @@@ struct strbuf buf = STRBUF_INIT; int err = 0; - temp = prepare_temp_file(spec->path, spec); + temp = prepare_temp_file(r, spec->path, spec); *arg++ = pgm; *arg++ = temp->name; *arg = NULL; @@@ -6330,7 -6343,8 +6363,8 @@@ return strbuf_detach(&buf, outsize); } - size_t fill_textconv(struct userdiff_driver *driver, + size_t fill_textconv(struct repository *r, + struct userdiff_driver *driver, struct diff_filespec *df, char **outbuf) { @@@ -6341,7 -6355,7 +6375,7 @@@ *outbuf = ""; return 0; } - if (diff_populate_filespec(df, 0)) + if (diff_populate_filespec(r, df, 0)) die("unable to read files to diff"); *outbuf = df->data; return df->size; @@@ -6358,7 -6372,7 +6392,7 @@@ return size; } - *outbuf = run_textconv(driver->textconv, df, &size); + *outbuf = run_textconv(r, driver->textconv, df, &size); if (!*outbuf) die("unable to read files to diff"); @@@ -6378,7 -6392,8 +6412,8 @@@ return size; } - int textconv_object(const char *path, + int textconv_object(struct repository *r, + const char *path, unsigned mode, const struct object_id *oid, int oid_valid, @@@ -6390,13 -6405,13 +6425,13 @@@ df = alloc_filespec(path); fill_filespec(df, oid, oid_valid, mode); - textconv = get_textconv(df); + textconv = get_textconv(r->index, df); if (!textconv) { free_filespec(df); return 0; } - *buf_size = fill_textconv(textconv, df, buf); + *buf_size = fill_textconv(r, textconv, df, buf); free_filespec(df); return 1; } diff --combined diff.h index a30cc35ec3,af26196224..ce5e8a8183 --- a/diff.h +++ b/diff.h @@@ -18,6 -18,7 +18,7 @@@ struct userdiff_driver struct oid_array; struct commit; struct combine_diff_path; + struct repository; typedef int (*pathchange_fn_t)(struct diff_options *options, struct combine_diff_path *path); @@@ -194,11 -195,6 +195,11 @@@ struct diff_options FILE *file; int close_file; +#define OUTPUT_INDICATOR_NEW 0 +#define OUTPUT_INDICATOR_OLD 1 +#define OUTPUT_INDICATOR_CONTEXT 2 + char output_indicators[3]; + struct pathspec pathspec; pathchange_fn_t pathchange; change_fn_t change; @@@ -225,6 -221,8 +226,8 @@@ /* XDF_WHITESPACE_FLAGS regarding block detection are set at 2, 3, 4 */ #define COLOR_MOVED_WS_ALLOW_INDENTATION_CHANGE (1<<5) int color_moved_ws_handling; + + struct repository *repo; }; void diff_emit_submodule_del(struct diff_options *o, const char *line); @@@ -338,7 -336,10 +341,10 @@@ int git_diff_basic_config(const char *v int git_diff_heuristic_config(const char *var, const char *value, void *cb); void init_diff_ui_defaults(void); int git_diff_ui_config(const char *var, const char *value, void *cb); - void diff_setup(struct diff_options *); + #ifndef NO_THE_REPOSITORY_COMPATIBILITY_MACROS + #define diff_setup(diffopts) repo_diff_setup(the_repository, diffopts) + #endif + void repo_diff_setup(struct repository *, struct diff_options *); int diff_opt_parse(struct diff_options *, const char **, int, const char *); void diff_setup_done(struct diff_options *); int git_config_rename(const char *var, const char *value); @@@ -428,7 -429,7 +434,7 @@@ int diff_flush_patch_id(struct diff_opt int diff_result_code(struct diff_options *, int); - void diff_no_index(struct rev_info *, int, const char **); + void diff_no_index(struct repository *, struct rev_info *, int, const char **); int index_differs_from(const char *def, const struct diff_flags *flags, int ita_invisible_in_index); @@@ -444,7 -445,8 +450,8 @@@ * struct. If it is non-NULL, then "outbuf" points to a newly allocated buffer * that should be freed by the caller. */ - size_t fill_textconv(struct userdiff_driver *driver, + size_t fill_textconv(struct repository *r, + struct userdiff_driver *driver, struct diff_filespec *df, char **outbuf); @@@ -453,14 -455,19 +460,19 @@@ * and only if it has textconv enabled (otherwise return NULL). The result * can be passed to fill_textconv(). */ - struct userdiff_driver *get_textconv(struct diff_filespec *one); + struct userdiff_driver *get_textconv(struct index_state *istate, + struct diff_filespec *one); /* * Prepare diff_filespec and convert it using diff textconv API * if the textconv driver exists. * Return 1 if the conversion succeeds, 0 otherwise. */ - int textconv_object(const char *path, unsigned mode, const struct object_id *oid, int oid_valid, char **buf, unsigned long *buf_size); + int textconv_object(struct repository *repo, + const char *path, + unsigned mode, + const struct object_id *oid, int oid_valid, + char **buf, unsigned long *buf_size); int parse_rename_score(const char **cp_p); diff --combined diffcore-break.c index e11fcfdb39,b580d92154..875aefd3fe --- a/diffcore-break.c +++ b/diffcore-break.c @@@ -5,7 -5,8 +5,8 @@@ #include "diff.h" #include "diffcore.h" - static int should_break(struct diff_filespec *src, + static int should_break(struct repository *r, + struct diff_filespec *src, struct diff_filespec *dst, int break_score, int *merge_score_p) @@@ -58,10 -59,11 +59,11 @@@ } if (src->oid_valid && dst->oid_valid && - !oidcmp(&src->oid, &dst->oid)) + oideq(&src->oid, &dst->oid)) return 0; /* they are the same */ - if (diff_populate_filespec(src, 0) || diff_populate_filespec(dst, 0)) + if (diff_populate_filespec(r, src, 0) || + diff_populate_filespec(r, dst, 0)) return 0; /* error but caught downstream */ max_size = ((src->size > dst->size) ? src->size : dst->size); @@@ -71,7 -73,7 +73,7 @@@ if (!src->size) return 0; /* we do not let empty files get renamed */ - if (diffcore_count_changes(src, dst, + if (diffcore_count_changes(r, src, dst, &src->cnt_data, &dst->cnt_data, &src_copied, &literal_added)) return 0; @@@ -114,7 -116,7 +116,7 @@@ return 1; } - void diffcore_break(int break_score) + void diffcore_break(struct repository *r, int break_score) { struct diff_queue_struct *q = &diff_queued_diff; struct diff_queue_struct outq; @@@ -178,7 -180,7 +180,7 @@@ object_type(p->one->mode) == OBJ_BLOB && object_type(p->two->mode) == OBJ_BLOB && !strcmp(p->one->path, p->two->path)) { - if (should_break(p->one, p->two, + if (should_break(r, p->one, p->two, break_score, &score)) { /* Split this into delete and create */ struct diff_filespec *null_one, *null_two; diff --combined diffcore-rename.c index daddd9b28a,f85758b233..07bd34b631 --- a/diffcore-rename.c +++ b/diffcore-rename.c @@@ -128,7 -128,8 +128,8 @@@ struct diff_score short name_score; }; - static int estimate_similarity(struct diff_filespec *src, + static int estimate_similarity(struct repository *r, + struct diff_filespec *src, struct diff_filespec *dst, int minimum_score) { @@@ -165,10 -166,10 +166,10 @@@ * say whether the size is valid or not!) */ if (!src->cnt_data && - diff_populate_filespec(src, CHECK_SIZE_ONLY)) + diff_populate_filespec(r, src, CHECK_SIZE_ONLY)) return 0; if (!dst->cnt_data && - diff_populate_filespec(dst, CHECK_SIZE_ONLY)) + diff_populate_filespec(r, dst, CHECK_SIZE_ONLY)) return 0; max_size = ((src->size > dst->size) ? src->size : dst->size); @@@ -186,12 -187,12 +187,12 @@@ if (max_size * (MAX_SCORE-minimum_score) < delta_size * MAX_SCORE) return 0; - if (!src->cnt_data && diff_populate_filespec(src, 0)) + if (!src->cnt_data && diff_populate_filespec(r, src, 0)) return 0; - if (!dst->cnt_data && diff_populate_filespec(dst, 0)) + if (!dst->cnt_data && diff_populate_filespec(r, dst, 0)) return 0; - if (diffcore_count_changes(src, dst, + if (diffcore_count_changes(r, src, dst, &src->cnt_data, &dst->cnt_data, &src_copied, &literal_added)) return 0; @@@ -256,10 -257,11 +257,11 @@@ struct file_similarity struct diff_filespec *filespec; }; - static unsigned int hash_filespec(struct diff_filespec *filespec) + static unsigned int hash_filespec(struct repository *r, + struct diff_filespec *filespec) { if (!filespec->oid_valid) { - if (diff_populate_filespec(filespec, 0)) + if (diff_populate_filespec(r, filespec, 0)) return 0; hash_object_file(filespec->data, filespec->size, "blob", &filespec->oid); @@@ -280,13 -282,15 +282,15 @@@ static int find_identical_files(struct /* * Find the best source match for specified destination. */ - p = hashmap_get_from_hash(srcs, hash_filespec(target), NULL); + p = hashmap_get_from_hash(srcs, + hash_filespec(options->repo, target), + NULL); for (; p; p = hashmap_get_next(srcs, p)) { int score; struct diff_filespec *source = p->filespec; /* False hash collision? */ - if (oidcmp(&source->oid, &target->oid)) + if (!oideq(&source->oid, &target->oid)) continue; /* Non-regular files? If so, the modes must match! */ if (!S_ISREG(source->mode) || !S_ISREG(target->mode)) { @@@ -316,14 -320,16 +320,16 @@@ return renames; } - static void insert_file_table(struct hashmap *table, int index, struct diff_filespec *filespec) + static void insert_file_table(struct repository *r, + struct hashmap *table, int index, + struct diff_filespec *filespec) { struct file_similarity *entry = xmalloc(sizeof(*entry)); entry->index = index; entry->filespec = filespec; - hashmap_entry_init(entry, hash_filespec(filespec)); + hashmap_entry_init(entry, hash_filespec(r, filespec)); hashmap_add(table, entry); } @@@ -344,7 -350,9 +350,9 @@@ static int find_exact_renames(struct di */ hashmap_init(&file_table, NULL, NULL, rename_src_nr); for (i = rename_src_nr-1; i >= 0; i--) - insert_file_table(&file_table, i, rename_src[i].p->one); + insert_file_table(options->repo, + &file_table, i, + rename_src[i].p->one); /* Walk the destinations and find best source match */ for (i = 0; i < rename_dst_nr; i++) @@@ -557,7 -565,8 +565,8 @@@ void diffcore_rename(struct diff_option diff_unmodified_pair(rename_src[j].p)) continue; - this_src.score = estimate_similarity(one, two, + this_src.score = estimate_similarity(options->repo, + one, two, minimum_score); this_src.name_score = basename_same(one, two); this_src.dst = i; diff --combined http-push.c index 1bbb0cdb6d,df504ab6a3..d1f52cbdf6 --- a/http-push.c +++ b/http-push.c @@@ -14,7 -14,7 +14,7 @@@ #include "argv-array.h" #include "packfile.h" #include "object-store.h" - +#include "commit-reach.h" #ifdef EXPAT_NEEDS_XMLPARSE_H #include @@@ -1859,7 -1859,7 +1859,7 @@@ int cmd_main(int argc, const char **arg continue; } - if (!oidcmp(&ref->old_oid, &ref->peer_ref->new_oid)) { + if (oideq(&ref->old_oid, &ref->peer_ref->new_oid)) { if (push_verbosely) fprintf(stderr, "'%s': up-to-date\n", ref->name); if (helper_status) @@@ -1925,7 -1925,7 +1925,7 @@@ if (!push_all && !is_null_oid(&ref->old_oid)) argv_array_pushf(&commit_argv, "^%s", oid_to_hex(&ref->old_oid)); - init_revisions(&revs, setup_git_directory()); + repo_init_revisions(the_repository, &revs, setup_git_directory()); setup_revisions(commit_argv.argc, commit_argv.argv, &revs, NULL); revs.edge_hint = 0; /* just in case */ diff --combined ll-merge.c index 1936fee9e1,c339ef8ae8..3c8fb917e9 --- a/ll-merge.c +++ b/ll-merge.c @@@ -336,10 -336,10 +336,10 @@@ static const struct ll_merge_driver *fi return &ll_merge_drv[LL_TEXT_MERGE]; } - static void normalize_file(mmfile_t *mm, const char *path) + static void normalize_file(mmfile_t *mm, const char *path, struct index_state *istate) { struct strbuf strbuf = STRBUF_INIT; - if (renormalize_buffer(&the_index, path, mm->ptr, mm->size, &strbuf)) { + if (renormalize_buffer(istate, path, mm->ptr, mm->size, &strbuf)) { free(mm->ptr); mm->size = strbuf.len; mm->ptr = strbuf_detach(&strbuf, NULL); @@@ -351,6 -351,7 +351,7 @@@ int ll_merge(mmbuffer_t *result_buf mmfile_t *ancestor, const char *ancestor_label, mmfile_t *ours, const char *our_label, mmfile_t *theirs, const char *their_label, + struct index_state *istate, const struct ll_merge_options *opts) { static struct attr_check *check; @@@ -363,20 -364,21 +364,20 @@@ opts = &default_opts; if (opts->renormalize) { - normalize_file(ancestor, path); - normalize_file(ours, path); - normalize_file(theirs, path); + normalize_file(ancestor, path, istate); + normalize_file(ours, path, istate); + normalize_file(theirs, path, istate); } if (!check) check = attr_check_initl("merge", "conflict-marker-size", NULL); - git_check_attr(&the_index, path, check); - if (!git_check_attr(istate, path, check)) { - ll_driver_name = check->items[0].value; - if (check->items[1].value) { - marker_size = atoi(check->items[1].value); - if (marker_size <= 0) - marker_size = DEFAULT_CONFLICT_MARKER_SIZE; - } ++ git_check_attr(istate, path, check); + ll_driver_name = check->items[0].value; + if (check->items[1].value) { + marker_size = atoi(check->items[1].value); + if (marker_size <= 0) + marker_size = DEFAULT_CONFLICT_MARKER_SIZE; } driver = find_ll_merge_driver(ll_driver_name); @@@ -390,15 -392,14 +391,15 @@@ opts, marker_size); } - int ll_merge_marker_size(const char *path) + int ll_merge_marker_size(struct index_state *istate, const char *path) { static struct attr_check *check; int marker_size = DEFAULT_CONFLICT_MARKER_SIZE; if (!check) check = attr_check_initl("conflict-marker-size", NULL); - git_check_attr(&the_index, path, check); - if (!git_check_attr(istate, path, check) && check->items[0].value) { ++ git_check_attr(istate, path, check); + if (check->items[0].value) { marker_size = atoi(check->items[0].value); if (marker_size <= 0) marker_size = DEFAULT_CONFLICT_MARKER_SIZE; diff --combined merge-recursive.c index 0684dab779,82e9f1d24a..c0fb83d285 --- a/merge-recursive.c +++ b/merge-recursive.c @@@ -27,7 -27,6 +27,7 @@@ #include "dir.h" #include "submodule.h" #include "revision.h" +#include "commit-reach.h" struct path_hashmap_entry { struct hashmap_entry e; @@@ -157,7 -156,7 +157,7 @@@ static struct tree *shift_tree_object(s shift_tree_by(&one->object.oid, &two->object.oid, &shifted, subtree_shift); } - if (!oidcmp(&two->object.oid, &shifted)) + if (oideq(&two->object.oid, &shifted)) return two; return lookup_tree(the_repository, &shifted); } @@@ -180,7 -179,7 +180,7 @@@ static int oid_eq(const struct object_i { if (!a && !b) return 2; - return a && b && oidcmp(a, b) == 0; + return a && b && oideq(a, b); } enum rename_type { @@@ -1084,7 -1083,8 +1084,8 @@@ static int merge_3way(struct merge_opti read_mmblob(&src2, &b->oid); merge_status = ll_merge(result_buf, a->path, &orig, base_name, - &src1, name1, &src2, name2, &ll_opts); + &src1, name1, &src2, name2, + &the_index, &ll_opts); free(base_name); free(name1); @@@ -1115,7 -1115,7 +1116,7 @@@ static int find_first_merges(struct obj /* get all revisions that merge commit a */ xsnprintf(merged_revision, sizeof(merged_revision), "^%s", oid_to_hex(&a->object.oid)); - init_revisions(&revs, NULL); + repo_init_revisions(the_repository, &revs, NULL); rev_opts.submodule = path; /* FIXME: can't handle linked worktrees in submodules yet */ revs.single_worktree = path != NULL; @@@ -1274,14 -1274,14 +1275,14 @@@ static int merge_submodule(struct merge return 0; } -static int merge_file_1(struct merge_options *o, - const struct diff_filespec *one, - const struct diff_filespec *a, - const struct diff_filespec *b, - const char *filename, - const char *branch1, - const char *branch2, - struct merge_file_info *result) +static int merge_mode_and_contents(struct merge_options *o, + const struct diff_filespec *one, + const struct diff_filespec *a, + const struct diff_filespec *b, + const char *filename, + const char *branch1, + const char *branch2, + struct merge_file_info *result) { result->merge = 0; result->clean = 1; @@@ -1366,6 -1366,56 +1367,6 @@@ return 0; } -static int merge_file_special_markers(struct merge_options *o, - const struct diff_filespec *one, - const struct diff_filespec *a, - const struct diff_filespec *b, - const char *target_filename, - const char *branch1, - const char *filename1, - const char *branch2, - const char *filename2, - struct merge_file_info *mfi) -{ - char *side1 = NULL; - char *side2 = NULL; - int ret; - - if (filename1) - side1 = xstrfmt("%s:%s", branch1, filename1); - if (filename2) - side2 = xstrfmt("%s:%s", branch2, filename2); - - ret = merge_file_1(o, one, a, b, target_filename, - side1 ? side1 : branch1, - side2 ? side2 : branch2, mfi); - - free(side1); - free(side2); - return ret; -} - -static int merge_file_one(struct merge_options *o, - const char *path, - const struct object_id *o_oid, int o_mode, - const struct object_id *a_oid, int a_mode, - const struct object_id *b_oid, int b_mode, - const char *branch1, - const char *branch2, - struct merge_file_info *mfi) -{ - struct diff_filespec one, a, b; - - one.path = a.path = b.path = (char *)path; - oidcpy(&one.oid, o_oid); - one.mode = o_mode; - oidcpy(&a.oid, a_oid); - a.mode = a_mode; - oidcpy(&b.oid, b_oid); - b.mode = b_mode; - return merge_file_1(o, &one, &a, &b, path, branch1, branch2, mfi); -} - static int handle_rename_via_dir(struct merge_options *o, struct diff_filepair *pair, const char *rename_branch, @@@ -1609,8 -1659,11 +1610,8 @@@ static int handle_rename_rename_1to2(st struct merge_file_info mfi; struct diff_filespec other; struct diff_filespec *add; - if (merge_file_one(o, one->path, - &one->oid, one->mode, - &a->oid, a->mode, - &b->oid, b->mode, - ci->branch1, ci->branch2, &mfi)) + if (merge_mode_and_contents(o, one, a, b, one->path, + ci->branch1, ci->branch2, &mfi)) return -1; /* @@@ -1676,10 -1729,14 +1677,10 @@@ static int handle_rename_rename_2to1(st path_side_1_desc = xstrfmt("%s (was %s)", path, a->path); path_side_2_desc = xstrfmt("%s (was %s)", path, b->path); - if (merge_file_special_markers(o, a, c1, &ci->ren1_other, - path_side_1_desc, - o->branch1, c1->path, - o->branch2, ci->ren1_other.path, &mfi_c1) || - merge_file_special_markers(o, b, &ci->ren2_other, c2, - path_side_2_desc, - o->branch1, ci->ren2_other.path, - o->branch2, c2->path, &mfi_c2)) + if (merge_mode_and_contents(o, a, c1, &ci->ren1_other, path_side_1_desc, + o->branch1, o->branch2, &mfi_c1) || + merge_mode_and_contents(o, b, &ci->ren2_other, c2, path_side_2_desc, + o->branch1, o->branch2, &mfi_c2)) return -1; free(path_side_1_desc); free(path_side_2_desc); @@@ -1756,7 -1813,7 +1757,7 @@@ static struct diff_queue_struct *get_di struct diff_queue_struct *ret; struct diff_options opts; - diff_setup(&opts); + repo_diff_setup(the_repository, &opts); opts.flags.recursive = 1; opts.flags.rename_empty = 0; opts.detect_rename = merge_detect_rename(o); @@@ -2183,7 -2240,7 +2184,7 @@@ static struct dir_rename_entry *check_d { char *temp = xstrdup(path); char *end; - struct dir_rename_entry *entry = NULL;; + struct dir_rename_entry *entry = NULL; while ((end = strrchr(temp, '/'))) { *end = '\0'; @@@ -2709,23 -2766,12 +2710,23 @@@ static int process_renames(struct merge ren1_dst, branch2); if (o->call_depth) { struct merge_file_info mfi; - if (merge_file_one(o, ren1_dst, &null_oid, 0, - &ren1->pair->two->oid, - ren1->pair->two->mode, - &dst_other.oid, - dst_other.mode, - branch1, branch2, &mfi)) { + struct diff_filespec one, a, b; + + oidcpy(&one.oid, &null_oid); + one.mode = 0; + one.path = ren1->pair->two->path; + + oidcpy(&a.oid, &ren1->pair->two->oid); + a.mode = ren1->pair->two->mode; + a.path = one.path; + + oidcpy(&b.oid, &dst_other.oid); + b.mode = dst_other.mode; + b.path = one.path; + + if (merge_mode_and_contents(o, &one, &a, &b, ren1_dst, + branch1, branch2, + &mfi)) { clean_merge = -1; goto cleanup_and_return; } @@@ -2975,13 -3021,13 +2976,13 @@@ static int handle_modify_delete(struct _("modify"), _("modified")); } -static int merge_content(struct merge_options *o, - const char *path, - int is_dirty, - struct object_id *o_oid, int o_mode, - struct object_id *a_oid, int a_mode, - struct object_id *b_oid, int b_mode, - struct rename_conflict_info *rename_conflict_info) +static int handle_content_merge(struct merge_options *o, + const char *path, + int is_dirty, + struct object_id *o_oid, int o_mode, + struct object_id *a_oid, int a_mode, + struct object_id *b_oid, int b_mode, + struct rename_conflict_info *rename_conflict_info) { const char *reason = _("content"); const char *path1 = NULL, *path2 = NULL; @@@ -3013,16 -3059,14 +3014,16 @@@ path2 = (rename_conflict_info->pair2 || o->branch2 == rename_conflict_info->branch1) ? pair1->two->path : pair1->one->path; + one.path = pair1->one->path; + a.path = (char *)path1; + b.path = (char *)path2; if (dir_in_way(path, !o->call_depth, S_ISGITLINK(pair1->two->mode))) df_conflict_remains = 1; } - if (merge_file_special_markers(o, &one, &a, &b, path, - o->branch1, path1, - o->branch2, path2, &mfi)) + if (merge_mode_and_contents(o, &one, &a, &b, path, + o->branch1, o->branch2, &mfi)) return -1; /* @@@ -3113,9 -3157,9 +3114,9 @@@ static int handle_rename_normal(struct struct rename_conflict_info *ci) { /* Merge the content and write it out */ - return merge_content(o, path, was_dirty(o, path), - o_oid, o_mode, a_oid, a_mode, b_oid, b_mode, - ci); + return handle_content_merge(o, path, was_dirty(o, path), + o_oid, o_mode, a_oid, a_mode, b_oid, b_mode, + ci); } /* Per entry merge function */ @@@ -3239,11 -3283,9 +3240,11 @@@ static int process_entry(struct merge_o /* Case C: Added in both (check for same permissions) and */ /* case D: Modified in both, but differently. */ int is_dirty = 0; /* unpack_trees would have bailed if dirty */ - clean_merge = merge_content(o, path, is_dirty, - o_oid, o_mode, a_oid, a_mode, b_oid, b_mode, - NULL); + clean_merge = handle_content_merge(o, path, is_dirty, + o_oid, o_mode, + a_oid, a_mode, + b_oid, b_mode, + NULL); } else if (!o_oid && !a_oid && !b_oid) { /* * this entry was deleted altogether. a_mode == 0 means diff --combined notes-merge.c index 5764e2b0ef,13dd9ba158..bd05d50b05 --- a/notes-merge.c +++ b/notes-merge.c @@@ -12,7 -12,6 +12,7 @@@ #include "notes-merge.h" #include "strbuf.h" #include "notes-utils.h" +#include "commit-reach.h" struct notes_merge_pair { struct object_id obj, base, local, remote; @@@ -127,7 -126,7 +127,7 @@@ static struct notes_merge_pair *diff_tr trace_printf("\tdiff_tree_remote(base = %.7s, remote = %.7s)\n", oid_to_hex(base), oid_to_hex(remote)); - diff_setup(&opt); + repo_diff_setup(the_repository, &opt); opt.flags.recursive = 1; opt.output_format = DIFF_FORMAT_NO_OUTPUT; diff_setup_done(&opt); @@@ -152,7 -151,7 +152,7 @@@ mp = find_notes_merge_pair_pos(changes, len, &obj, 1, &occupied); if (occupied) { /* We've found an addition/deletion pair */ - assert(!oidcmp(&mp->obj, &obj)); + assert(oideq(&mp->obj, &obj)); if (is_null_oid(&p->one->oid)) { /* addition */ assert(is_null_oid(&mp->remote)); oidcpy(&mp->remote, &p->two->oid); @@@ -190,7 -189,7 +190,7 @@@ static void diff_tree_local(struct note trace_printf("\tdiff_tree_local(len = %i, base = %.7s, local = %.7s)\n", len, oid_to_hex(base), oid_to_hex(local)); - diff_setup(&opt); + repo_diff_setup(the_repository, &opt); opt.flags.recursive = 1; opt.output_format = DIFF_FORMAT_NO_OUTPUT; diff_setup_done(&opt); @@@ -219,7 -218,7 +219,7 @@@ continue; } - assert(!oidcmp(&mp->obj, &obj)); + assert(oideq(&mp->obj, &obj)); if (is_null_oid(&p->two->oid)) { /* deletion */ /* * Either this is a true deletion (1), or it is part @@@ -230,7 -229,7 +230,7 @@@ * (3) mp->local is uninitialized; set it to null_sha1 * (will be overwritten by following addition) */ - if (!oidcmp(&mp->local, &uninitialized)) + if (oideq(&mp->local, &uninitialized)) oidclr(&mp->local); } else if (is_null_oid(&p->one->oid)) { /* addition */ /* @@@ -242,7 -241,7 +242,7 @@@ * (3) mp->local is null_sha1; set to p->two->sha1 */ assert(is_null_oid(&mp->local) || - !oidcmp(&mp->local, &uninitialized)); + oideq(&mp->local, &uninitialized)); oidcpy(&mp->local, &p->two->oid); } else { /* modification */ /* @@@ -250,8 -249,8 +250,8 @@@ * match mp->base, and mp->local shall be uninitialized. * Set mp->local to p->two->sha1. */ - assert(!oidcmp(&p->one->oid, &mp->base)); - assert(!oidcmp(&mp->local, &uninitialized)); + assert(oideq(&p->one->oid, &mp->base)); + assert(oideq(&mp->local, &uninitialized)); oidcpy(&mp->local, &p->two->oid); } trace_printf("\t\tStored local change for %s: %.7s -> %.7s\n", @@@ -349,7 -348,8 +349,8 @@@ static int ll_merge_in_worktree(struct read_mmblob(&remote, &p->remote); status = ll_merge(&result_buf, oid_to_hex(&p->obj), &base, NULL, - &local, o->local_ref, &remote, o->remote_ref, NULL); + &local, o->local_ref, &remote, o->remote_ref, + &the_index, NULL); free(base.ptr); free(local.ptr); @@@ -481,14 -481,14 +482,14 @@@ static int merge_changes(struct notes_m oid_to_hex(&p->local), oid_to_hex(&p->remote)); - if (!oidcmp(&p->base, &p->remote)) { + if (oideq(&p->base, &p->remote)) { /* no remote change; nothing to do */ trace_printf("\t\t\tskipping (no remote change)\n"); - } else if (!oidcmp(&p->local, &p->remote)) { + } else if (oideq(&p->local, &p->remote)) { /* same change in local and remote; nothing to do */ trace_printf("\t\t\tskipping (local == remote)\n"); - } else if (!oidcmp(&p->local, &uninitialized) || - !oidcmp(&p->local, &p->base)) { + } else if (oideq(&p->local, &uninitialized) || + oideq(&p->local, &p->base)) { /* no local change; adopt remote change */ trace_printf("\t\t\tno local change, adopted remote\n"); if (add_note(t, &p->obj, &p->remote, @@@ -622,14 -622,14 +623,14 @@@ int notes_merge(struct notes_merge_opti oid_to_hex(&local->object.oid), oid_to_hex(base_oid)); - if (!oidcmp(&remote->object.oid, base_oid)) { + if (oideq(&remote->object.oid, base_oid)) { /* Already merged; result == local commit */ if (o->verbosity >= 2) printf("Already up to date!\n"); oidcpy(result_oid, &local->object.oid); goto found_result; } - if (!oidcmp(&local->object.oid, base_oid)) { + if (oideq(&local->object.oid, base_oid)) { /* Fast-forward; result == remote commit */ if (o->verbosity >= 2) printf("Fast-forward\n"); @@@ -710,7 -710,7 +711,7 @@@ int notes_merge_commit(struct notes_mer /* write file as blob, and add to partial_tree */ if (stat(path.buf, &st)) die_errno("Failed to stat '%s'", path.buf); - if (index_path(&blob_oid, path.buf, &st, HASH_WRITE_OBJECT)) + if (index_path(&the_index, &blob_oid, path.buf, &st, HASH_WRITE_OBJECT)) die("Failed to write blob object from '%s'", path.buf); if (add_note(partial_tree, &obj_oid, &blob_oid, NULL)) die("Failed to add resolved note '%s' to notes tree", diff --combined pack-bitmap-write.c index fc82f37a02,198fd13097..f2fd9d81ef --- a/pack-bitmap-write.c +++ b/pack-bitmap-write.c @@@ -11,7 -11,6 +11,7 @@@ #include "pack-bitmap.h" #include "sha1-lookup.h" #include "pack-objects.h" +#include "commit-reach.h" struct bitmapped_commit { struct commit *commit; @@@ -262,7 -261,7 +262,7 @@@ void bitmap_writer_build(struct packing if (writer.show_progress) writer.progress = start_progress("Building bitmaps", writer.selected_nr); - init_revisions(&revs, NULL); + repo_init_revisions(the_repository, &revs, NULL); revs.tag_objects = 1; revs.tree_objects = 1; revs.blob_objects = 1; diff --combined patch-ids.c index 960ea24054,7da86047d9..c262e1be9c --- a/patch-ids.c +++ b/patch-ids.c @@@ -28,14 -28,14 +28,14 @@@ int commit_patch_id(struct commit *comm /* * When we cannot load the full patch-id for both commits for whatever * reason, the function returns -1 (i.e. return error(...)). Despite - * the "cmp" in the name of this function, the caller only cares about + * the "neq" in the name of this function, the caller only cares about * the return value being zero (a and b are equivalent) or non-zero (a * and b are different), and returning non-zero would keep both in the * result, even if they actually were equivalent, in order to err on * the side of safety. The actual value being negative does not have * any significance; only that it is non-zero matters. */ -static int patch_id_cmp(const void *cmpfn_data, +static int patch_id_neq(const void *cmpfn_data, const void *entry, const void *entry_or_key, const void *unused_keydata) @@@ -53,17 -53,17 +53,17 @@@ commit_patch_id(b->commit, opt, &b->patch_id, 0)) return error("Could not get patch ID for %s", oid_to_hex(&b->commit->object.oid)); - return oidcmp(&a->patch_id, &b->patch_id); + return !oideq(&a->patch_id, &b->patch_id); } - int init_patch_ids(struct patch_ids *ids) + int init_patch_ids(struct repository *r, struct patch_ids *ids) { memset(ids, 0, sizeof(*ids)); - diff_setup(&ids->diffopts); + repo_diff_setup(r, &ids->diffopts); ids->diffopts.detect_rename = 0; ids->diffopts.flags.recursive = 1; diff_setup_done(&ids->diffopts); - hashmap_init(&ids->patches, patch_id_cmp, &ids->diffopts, 256); + hashmap_init(&ids->patches, patch_id_neq, &ids->diffopts, 256); return 0; } diff --combined read-cache.c index 8d04d78a58,b707edd044..01859b7703 --- a/read-cache.c +++ b/read-cache.c @@@ -205,15 -205,17 +205,17 @@@ void fill_stat_cache_info(struct cache_ } } - static int ce_compare_data(const struct cache_entry *ce, struct stat *st) + static int ce_compare_data(struct index_state *istate, + const struct cache_entry *ce, + struct stat *st) { int match = -1; int fd = git_open_cloexec(ce->name, O_RDONLY); if (fd >= 0) { struct object_id oid; - if (!index_fd(&oid, fd, st, OBJ_BLOB, ce->name, 0)) + if (!index_fd(istate, &oid, fd, st, OBJ_BLOB, ce->name, 0)) - match = oidcmp(&oid, &ce->oid); + match = !oideq(&oid, &ce->oid); /* index_fd() closed the file descriptor already */ } return match; @@@ -254,14 -256,16 +256,16 @@@ static int ce_compare_gitlink(const str */ if (resolve_gitlink_ref(ce->name, "HEAD", &oid) < 0) return 0; - return oidcmp(&oid, &ce->oid); + return !oideq(&oid, &ce->oid); } - static int ce_modified_check_fs(const struct cache_entry *ce, struct stat *st) + static int ce_modified_check_fs(struct index_state *istate, + const struct cache_entry *ce, + struct stat *st) { switch (st->st_mode & S_IFMT) { case S_IFREG: - if (ce_compare_data(ce, st)) + if (ce_compare_data(istate, ce, st)) return DATA_CHANGED; break; case S_IFLNK: @@@ -407,7 -411,7 +411,7 @@@ int ie_match_stat(struct index_state *i if (assume_racy_is_modified) changed |= DATA_CHANGED; else - changed |= ce_modified_check_fs(ce, st); + changed |= ce_modified_check_fs(istate, ce, st); } return changed; @@@ -447,7 -451,7 +451,7 @@@ int ie_modified(struct index_state *ist (S_ISGITLINK(ce->ce_mode) || ce->ce_stat_data.sd_size != 0)) return changed; - changed_fs = ce_modified_check_fs(ce, st); + changed_fs = ce_modified_check_fs(istate, ce, st); if (changed_fs) return changed | changed_fs; return 0; @@@ -753,7 -757,7 +757,7 @@@ int add_to_index(struct index_state *is } } if (!intent_only) { - if (index_path(&ce->oid, path, st, newflags)) { + if (index_path(istate, &ce->oid, path, st, newflags)) { discard_cache_entry(ce); return error("unable to index file %s", path); } @@@ -767,7 -771,7 +771,7 @@@ /* It was suspected to be racily clean, but it turns out to be Ok */ was_same = (alias && !ce_stage(alias) && - !oidcmp(&alias->oid, &ce->oid) && + oideq(&alias->oid, &ce->oid) && ce->ce_mode == alias->ce_mode); if (pretend) @@@ -823,7 -827,7 +827,7 @@@ struct cache_entry *make_cache_entry(st ce->ce_namelen = len; ce->ce_mode = create_ce_mode(mode); - ret = refresh_cache_entry(&the_index, ce, refresh_options); + ret = refresh_cache_entry(istate, ce, refresh_options); if (ret != ce) discard_cache_entry(ce); return ret; @@@ -1476,8 -1480,8 +1480,8 @@@ int refresh_index(struct index_state *i const char *typechange_fmt; const char *added_fmt; const char *unmerged_fmt; - uint64_t start = getnanotime(); + trace_performance_enter(); modified_fmt = (in_porcelain ? "M\t%s\n" : "%s: needs update\n"); deleted_fmt = (in_porcelain ? "D\t%s\n" : "%s: needs update\n"); typechange_fmt = (in_porcelain ? "T\t%s\n" : "%s needs update\n"); @@@ -1493,7 -1497,7 +1497,7 @@@ if (ignore_submodules && S_ISGITLINK(ce->ce_mode)) continue; - if (pathspec && !ce_path_match(&the_index, ce, pathspec, seen)) + if (pathspec && !ce_path_match(istate, ce, pathspec, seen)) filtered = 1; if (ce_stage(ce)) { @@@ -1547,7 -1551,7 +1551,7 @@@ replace_index_entry(istate, i, new_entry); } - trace_performance_since(start, "refresh index"); + trace_performance_leave("refresh index"); return has_errors; } @@@ -1668,7 -1672,7 +1672,7 @@@ static int verify_hdr(struct cache_head the_hash_algo->init_fn(&c); the_hash_algo->update_fn(&c, hdr, size - the_hash_algo->rawsz); the_hash_algo->final_fn(hash, &c); - if (hashcmp(hash, (unsigned char *)hdr + size - the_hash_algo->rawsz)) + if (!hasheq(hash, (unsigned char *)hdr + size - the_hash_algo->rawsz)) return error("bad index file sha1 signature"); return 0; } @@@ -2002,6 -2006,7 +2006,6 @@@ static void freshen_shared_index(const int read_index_from(struct index_state *istate, const char *path, const char *gitdir) { - uint64_t start = getnanotime(); struct split_index *split_index; int ret; char *base_oid_hex; @@@ -2011,9 -2016,8 +2015,9 @@@ if (istate->initialized) return istate->cache_nr; + trace_performance_enter(); ret = do_read_index(istate, path, 0); - trace_performance_since(start, "read cache %s", path); + trace_performance_leave("read cache %s", path); split_index = istate->split_index; if (!split_index || is_null_oid(&split_index->base_oid)) { @@@ -2021,7 -2025,6 +2025,7 @@@ return ret; } + trace_performance_enter(); if (split_index->base) discard_index(split_index->base); else @@@ -2030,7 -2033,7 +2034,7 @@@ base_oid_hex = oid_to_hex(&split_index->base_oid); base_path = xstrfmt("%s/sharedindex.%s", gitdir, base_oid_hex); ret = do_read_index(split_index->base, base_path, 1); - if (oidcmp(&split_index->base_oid, &split_index->base->oid)) + if (!oideq(&split_index->base_oid, &split_index->base->oid)) die("broken index, expect %s in %s, got %s", base_oid_hex, base_path, oid_to_hex(&split_index->base->oid)); @@@ -2038,8 -2041,8 +2042,8 @@@ freshen_shared_index(base_path, 0); merge_base_index(istate); post_read_index_from(istate); - trace_performance_since(start, "read cache %s", base_path); free(base_path); + trace_performance_leave("read cache %s", base_path); return ret; } @@@ -2123,7 -2126,7 +2127,7 @@@ int unmerged_index(const struct index_s return 0; } - int index_has_changes(const struct index_state *istate, + int index_has_changes(struct index_state *istate, struct tree *tree, struct strbuf *sb) { @@@ -2138,7 -2141,7 +2142,7 @@@ if (tree || !get_oid_tree("HEAD", &cmp)) { struct diff_options opt; - diff_setup(&opt); + repo_diff_setup(the_repository, &opt); opt.flags.exit_with_status = 1; if (!sb) opt.flags.quick = 1; @@@ -2231,7 -2234,8 +2235,8 @@@ static int ce_flush(git_hash_ctx *conte return (write_in_full(fd, write_buffer, left) < 0) ? -1 : 0; } - static void ce_smudge_racily_clean_entry(struct cache_entry *ce) + static void ce_smudge_racily_clean_entry(struct index_state *istate, + struct cache_entry *ce) { /* * The only thing we care about in this function is to smudge the @@@ -2250,7 -2254,7 +2255,7 @@@ return; if (ce_match_stat_basic(ce, &st)) return; - if (ce_modified_check_fs(ce, &st)) { + if (ce_modified_check_fs(istate, ce, &st)) { /* This is "racily clean"; smudge it. Note that this * is a tricky code. At first glance, it may appear * that it can break with this sequence: @@@ -2396,7 -2400,7 +2401,7 @@@ static int verify_index_from(const stru if (n != the_hash_algo->rawsz) goto out; - if (hashcmp(istate->oid.hash, hash)) + if (!hasheq(istate->oid.hash, hash)) goto out; close(fd); @@@ -2495,7 -2499,7 +2500,7 @@@ static int do_write_index(struct index_ if (ce->ce_flags & CE_REMOVE) continue; if (!ce_uptodate(ce) && is_racy_timestamp(istate, ce)) - ce_smudge_racily_clean_entry(ce); + ce_smudge_racily_clean_entry(istate, ce); if (is_null_oid(&ce->oid)) { static const char msg[] = "cache entry has null sha1: %s"; static int allow = -1; @@@ -2744,9 -2748,6 +2749,9 @@@ int write_locked_index(struct index_sta int new_shared_index, ret; struct split_index *si = istate->split_index; + if (git_env_bool("GIT_TEST_CHECK_CACHE_TREE", 0)) + cache_tree_verify(istate); + if ((flags & SKIP_IF_UNCHANGED) && !istate->cache_changed) { if (flags & COMMIT_LOCK) rollback_lock_file(lock); @@@ -2943,8 -2944,6 +2948,8 @@@ void move_index_extensions(struct index { dst->untracked = src->untracked; src->untracked = NULL; + dst->cache_tree = src->cache_tree; + src->cache_tree = NULL; } struct cache_entry *dup_cache_entry(const struct cache_entry *ce, diff --combined ref-filter.c index e1bcb4ca8a,f081a290cb..2a05619211 --- a/ref-filter.c +++ b/ref-filter.c @@@ -19,7 -19,6 +19,7 @@@ #include "wt-status.h" #include "commit-slab.h" #include "commit-graph.h" +#include "commit-reach.h" static struct ref_msg { const char *gone; @@@ -264,8 -263,6 +264,8 @@@ static int trailers_atom_parser(const s struct string_list params = STRING_LIST_INIT_DUP; int i; + atom->u.contents.trailer_opts.no_divider = 1; + if (arg) { string_list_split(¶ms, arg, ',', -1); for (i = 0; i < params.nr; i++) { @@@ -1676,6 -1673,144 +1676,6 @@@ static int get_ref_atom_value(struct re return 0; } -/* - * Unknown has to be "0" here, because that's the default value for - * contains_cache slab entries that have not yet been assigned. - */ -enum contains_result { - CONTAINS_UNKNOWN = 0, - CONTAINS_NO, - CONTAINS_YES -}; - -define_commit_slab(contains_cache, enum contains_result); - -struct ref_filter_cbdata { - struct ref_array *array; - struct ref_filter *filter; - struct contains_cache contains_cache; - struct contains_cache no_contains_cache; -}; - -/* - * Mimicking the real stack, this stack lives on the heap, avoiding stack - * overflows. - * - * At each recursion step, the stack items points to the commits whose - * ancestors are to be inspected. - */ -struct contains_stack { - int nr, alloc; - struct contains_stack_entry { - struct commit *commit; - struct commit_list *parents; - } *contains_stack; -}; - -static int in_commit_list(const struct commit_list *want, struct commit *c) -{ - for (; want; want = want->next) - if (!oidcmp(&want->item->object.oid, &c->object.oid)) - return 1; - return 0; -} - -/* - * Test whether the candidate is contained in the list. - * Do not recurse to find out, though, but return -1 if inconclusive. - */ -static enum contains_result contains_test(struct commit *candidate, - const struct commit_list *want, - struct contains_cache *cache, - uint32_t cutoff) -{ - enum contains_result *cached = contains_cache_at(cache, candidate); - - /* If we already have the answer cached, return that. */ - if (*cached) - return *cached; - - /* or are we it? */ - if (in_commit_list(want, candidate)) { - *cached = CONTAINS_YES; - return CONTAINS_YES; - } - - /* Otherwise, we don't know; prepare to recurse */ - parse_commit_or_die(candidate); - - if (candidate->generation < cutoff) - return CONTAINS_NO; - - return CONTAINS_UNKNOWN; -} - -static void push_to_contains_stack(struct commit *candidate, struct contains_stack *contains_stack) -{ - ALLOC_GROW(contains_stack->contains_stack, contains_stack->nr + 1, contains_stack->alloc); - contains_stack->contains_stack[contains_stack->nr].commit = candidate; - contains_stack->contains_stack[contains_stack->nr++].parents = candidate->parents; -} - -static enum contains_result contains_tag_algo(struct commit *candidate, - const struct commit_list *want, - struct contains_cache *cache) -{ - struct contains_stack contains_stack = { 0, 0, NULL }; - enum contains_result result; - uint32_t cutoff = GENERATION_NUMBER_INFINITY; - const struct commit_list *p; - - for (p = want; p; p = p->next) { - struct commit *c = p->item; - load_commit_graph_info(the_repository, c); - if (c->generation < cutoff) - cutoff = c->generation; - } - - result = contains_test(candidate, want, cache, cutoff); - if (result != CONTAINS_UNKNOWN) - return result; - - push_to_contains_stack(candidate, &contains_stack); - while (contains_stack.nr) { - struct contains_stack_entry *entry = &contains_stack.contains_stack[contains_stack.nr - 1]; - struct commit *commit = entry->commit; - struct commit_list *parents = entry->parents; - - if (!parents) { - *contains_cache_at(cache, commit) = CONTAINS_NO; - contains_stack.nr--; - } - /* - * If we just popped the stack, parents->item has been marked, - * therefore contains_test will return a meaningful yes/no. - */ - else switch (contains_test(parents->item, want, cache, cutoff)) { - case CONTAINS_YES: - *contains_cache_at(cache, commit) = CONTAINS_YES; - contains_stack.nr--; - break; - case CONTAINS_NO: - entry->parents = parents->next; - break; - case CONTAINS_UNKNOWN: - push_to_contains_stack(parents->item, &contains_stack); - break; - } - } - free(contains_stack.contains_stack); - return contains_test(candidate, want, cache, cutoff); -} - -static int commit_contains(struct ref_filter *filter, struct commit *commit, - struct commit_list *list, struct contains_cache *cache) -{ - if (filter->with_commit_tag_algo) - return contains_tag_algo(commit, list, cache) == CONTAINS_YES; - return is_descendant_of(commit, list); -} - /* * Return 1 if the refname matches one of the patterns, otherwise 0. * A pattern can be a literal prefix (e.g. a refname "refs/heads/master" @@@ -1911,13 -2046,6 +1911,13 @@@ static int filter_ref_kind(struct ref_f return ref_kind_from_refname(refname); } +struct ref_filter_cbdata { + struct ref_array *array; + struct ref_filter *filter; + struct contains_cache contains_cache; + struct contains_cache no_contains_cache; +}; + /* * A call-back given to for_each_ref(). Filter refs and keep them for * later object processing. @@@ -2010,7 -2138,7 +2010,7 @@@ static void do_merge_filter(struct ref_ struct ref_array *array = ref_cbdata->array; struct commit **to_clear = xcalloc(sizeof(struct commit *), array->nr); - init_revisions(&revs, NULL); + repo_init_revisions(the_repository, &revs, NULL); for (i = 0; i < array->nr; i++) { struct ref_array_item *item = array->items[i]; diff --combined remote.c index 682f2a01f9,348417f0a7..81f4f01b00 --- a/remote.c +++ b/remote.c @@@ -12,7 -12,6 +12,7 @@@ #include "string-list.h" #include "mergesort.h" #include "argv-array.h" +#include "commit-reach.h" enum map_direction { FROM_SRC, FROM_DST }; @@@ -1389,7 -1388,7 +1389,7 @@@ void set_ref_status_for_push(struct re ref->deletion = is_null_oid(&ref->new_oid); if (!ref->deletion && - !oidcmp(&ref->old_oid, &ref->new_oid)) { + oideq(&ref->old_oid, &ref->new_oid)) { ref->status = REF_STATUS_UPTODATE; continue; } @@@ -1404,7 -1403,7 +1404,7 @@@ * branch. */ if (ref->expect_old_sha1) { - if (oidcmp(&ref->old_oid, &ref->old_oid_expect)) + if (!oideq(&ref->old_oid, &ref->old_oid_expect)) reject_reason = REF_STATUS_REJECT_STALE; else /* If the ref isn't stale then force the update. */ @@@ -1792,6 -1791,55 +1792,6 @@@ int resolve_remote_symref(struct ref *r return 1; } -static void unmark_and_free(struct commit_list *list, unsigned int mark) -{ - while (list) { - struct commit *commit = pop_commit(&list); - commit->object.flags &= ~mark; - } -} - -int ref_newer(const struct object_id *new_oid, const struct object_id *old_oid) -{ - struct object *o; - struct commit *old_commit, *new_commit; - struct commit_list *list, *used; - int found = 0; - - /* - * Both new_commit and old_commit must be commit-ish and new_commit is descendant of - * old_commit. Otherwise we require --force. - */ - o = deref_tag(the_repository, parse_object(the_repository, old_oid), - NULL, 0); - if (!o || o->type != OBJ_COMMIT) - return 0; - old_commit = (struct commit *) o; - - o = deref_tag(the_repository, parse_object(the_repository, new_oid), - NULL, 0); - if (!o || o->type != OBJ_COMMIT) - return 0; - new_commit = (struct commit *) o; - - if (parse_commit(new_commit) < 0) - return 0; - - used = list = NULL; - commit_list_insert(new_commit, &list); - while (list) { - new_commit = pop_most_recent_commit(&list, TMP_MARK); - commit_list_insert(new_commit, &used); - if (new_commit == old_commit) { - found = 1; - break; - } - } - unmark_and_free(list, TMP_MARK); - unmark_and_free(used, TMP_MARK); - return found; -} - /* * Lookup the upstream branch for the given branch and if present, optionally * compute the commit ahead/behind values for the pair. @@@ -1855,7 -1903,7 +1855,7 @@@ int stat_tracking_info(struct branch *b oid_to_hex(&theirs->object.oid)); argv_array_push(&argv, "--"); - init_revisions(&revs, NULL); + repo_init_revisions(the_repository, &revs, NULL); setup_revisions(argv.argc, argv.argv, &revs, NULL); if (prepare_revision_walk(&revs)) die("revision walk setup failed"); @@@ -2001,7 -2049,7 +2001,7 @@@ struct ref *guess_remote_head(const str /* If refs/heads/master could be right, it is. */ if (!all) { r = find_ref_by_name(refs, "refs/heads/master"); - if (r && !oidcmp(&r->old_oid, &head->old_oid)) + if (r && oideq(&r->old_oid, &head->old_oid)) return copy_ref(r); } @@@ -2009,7 -2057,7 +2009,7 @@@ for (r = refs; r; r = r->next) { if (r != head && starts_with(r->name, "refs/heads/") && - !oidcmp(&r->old_oid, &head->old_oid)) { + oideq(&r->old_oid, &head->old_oid)) { *tail = copy_ref(r); tail = &((*tail)->next); if (!all) diff --combined rerere.c index 7aa149e849,8d4ac8426b..887e26d45b --- a/rerere.c +++ b/rerere.c @@@ -213,7 -213,7 +213,7 @@@ static void read_rr(struct string_list /* There has to be the hash, tab, path and then NUL */ if (buf.len < 42 || get_sha1_hex(buf.buf, sha1)) - die("corrupt MERGE_RR"); + die(_("corrupt MERGE_RR")); if (buf.buf[40] != '.') { variant = 0; @@@ -222,10 -222,10 +222,10 @@@ errno = 0; variant = strtol(buf.buf + 41, &path, 10); if (errno) - die("corrupt MERGE_RR"); + die(_("corrupt MERGE_RR")); } if (*(path++) != '\t') - die("corrupt MERGE_RR"); + die(_("corrupt MERGE_RR")); buf.buf[40] = '\0'; id = new_rerere_id_hex(buf.buf); id->variant = variant; @@@ -260,12 -260,12 +260,12 @@@ static int write_rr(struct string_list rr->items[i].string, 0); if (write_in_full(out_fd, buf.buf, buf.len) < 0) - die("unable to write rerere record"); + die(_("unable to write rerere record")); strbuf_release(&buf); } if (commit_lock_file(&write_lock) != 0) - die("unable to write rerere record"); + die(_("unable to write rerere record")); return 0; } @@@ -303,6 -303,38 +303,6 @@@ static void rerere_io_putstr(const cha ferr_puts(str, io->output, &io->wrerror); } -/* - * Write a conflict marker to io->output (if defined). - */ -static void rerere_io_putconflict(int ch, int size, struct rerere_io *io) -{ - char buf[64]; - - while (size) { - if (size <= sizeof(buf) - 2) { - memset(buf, ch, size); - buf[size] = '\n'; - buf[size + 1] = '\0'; - size = 0; - } else { - int sz = sizeof(buf) - 1; - - /* - * Make sure we will not write everything out - * in this round by leaving at least 1 byte - * for the next round, giving the next round - * a chance to add the terminating LF. Yuck. - */ - if (size <= sz) - sz -= (sz - size) + 1; - memset(buf, ch, sz); - buf[sz] = '\0'; - size -= sz; - } - rerere_io_putstr(buf, io); - } -} - static void rerere_io_putmem(const char *mem, size_t sz, struct rerere_io *io) { if (io->output) @@@ -353,154 -385,135 +353,155 @@@ static int is_cmarker(char *buf, int ma 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) +static void rerere_strbuf_putconflict(struct strbuf *buf, int ch, size_t size) +{ + strbuf_addchars(buf, ch, size); + strbuf_addch(buf, '\n'); +} + +static int handle_conflict(struct strbuf *out, struct rerere_io *io, + int marker_size, git_SHA_CTX *ctx) { - git_SHA_CTX ctx; - int hunk_no = 0; enum { - RR_CONTEXT = 0, RR_SIDE_1, RR_SIDE_2, RR_ORIGINAL - } hunk = RR_CONTEXT; + RR_SIDE_1 = 0, RR_SIDE_2, RR_ORIGINAL + } hunk = RR_SIDE_1; struct strbuf one = STRBUF_INIT, two = STRBUF_INIT; - struct strbuf buf = STRBUF_INIT; - - if (sha1) - git_SHA1_Init(&ctx); + struct strbuf buf = STRBUF_INIT, conflict = STRBUF_INIT; + int has_conflicts = -1; while (!io->getline(&buf, io)) { if (is_cmarker(buf.buf, '<', marker_size)) { - if (hunk != RR_CONTEXT) - goto bad; - hunk = RR_SIDE_1; + if (handle_conflict(&conflict, io, marker_size, NULL) < 0) + break; + if (hunk == RR_SIDE_1) + strbuf_addbuf(&one, &conflict); + else + strbuf_addbuf(&two, &conflict); + strbuf_release(&conflict); } else if (is_cmarker(buf.buf, '|', marker_size)) { if (hunk != RR_SIDE_1) - goto bad; + break; hunk = RR_ORIGINAL; } else if (is_cmarker(buf.buf, '=', marker_size)) { if (hunk != RR_SIDE_1 && hunk != RR_ORIGINAL) - goto bad; + break; hunk = RR_SIDE_2; } else if (is_cmarker(buf.buf, '>', marker_size)) { if (hunk != RR_SIDE_2) - goto bad; + break; if (strbuf_cmp(&one, &two) > 0) strbuf_swap(&one, &two); - hunk_no++; - hunk = RR_CONTEXT; - rerere_io_putconflict('<', marker_size, io); - rerere_io_putmem(one.buf, one.len, io); - rerere_io_putconflict('=', marker_size, io); - rerere_io_putmem(two.buf, two.len, io); - rerere_io_putconflict('>', marker_size, io); - if (sha1) { - git_SHA1_Update(&ctx, one.buf ? one.buf : "", + has_conflicts = 1; + rerere_strbuf_putconflict(out, '<', marker_size); + strbuf_addbuf(out, &one); + rerere_strbuf_putconflict(out, '=', marker_size); + strbuf_addbuf(out, &two); + rerere_strbuf_putconflict(out, '>', marker_size); + if (ctx) { + git_SHA1_Update(ctx, one.buf ? one.buf : "", one.len + 1); - git_SHA1_Update(&ctx, two.buf ? two.buf : "", + git_SHA1_Update(ctx, two.buf ? two.buf : "", two.len + 1); } - strbuf_reset(&one); - strbuf_reset(&two); + break; } else if (hunk == RR_SIDE_1) strbuf_addbuf(&one, &buf); else if (hunk == RR_ORIGINAL) ; /* discard */ else if (hunk == RR_SIDE_2) strbuf_addbuf(&two, &buf); - else - rerere_io_putstr(buf.buf, io); - continue; - bad: - hunk = 99; /* force error exit */ - break; } strbuf_release(&one); strbuf_release(&two); strbuf_release(&buf); + return has_conflicts; +} + +/* + * 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 1 if conflict hunks are found, 0 if there are no conflict + * hunks and -1 if an error occured. + */ +static int handle_path(unsigned char *sha1, struct rerere_io *io, int marker_size) +{ + git_SHA_CTX ctx; + struct strbuf buf = STRBUF_INIT, out = STRBUF_INIT; + int has_conflicts = 0; + if (sha1) + git_SHA1_Init(&ctx); + + while (!io->getline(&buf, io)) { + if (is_cmarker(buf.buf, '<', marker_size)) { + has_conflicts = handle_conflict(&out, io, marker_size, + sha1 ? &ctx : NULL); + if (has_conflicts < 0) + break; + rerere_io_putmem(out.buf, out.len, io); + strbuf_reset(&out); + } else + rerere_io_putstr(buf.buf, io); + } + strbuf_release(&buf); + strbuf_release(&out); + if (sha1) git_SHA1_Final(sha1, &ctx); - if (hunk != RR_CONTEXT) - return -1; - return hunk_no; + + return has_conflicts; } /* * 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) + static int handle_file(struct index_state *istate, const char *path, + unsigned char *sha1, const char *output) { - int hunk_no = 0; + int has_conflicts = 0; struct rerere_io_file io; - int marker_size = ll_merge_marker_size(path); + int marker_size = ll_merge_marker_size(istate, path); memset(&io, 0, sizeof(io)); io.io.getline = rerere_file_getline; io.input = fopen(path, "r"); io.io.wrerror = 0; if (!io.input) - return error_errno("Could not open %s", path); + return error_errno(_("could not open '%s'"), path); if (output) { io.io.output = fopen(output, "w"); if (!io.io.output) { - error_errno("Could not write %s", output); + error_errno(_("could not write '%s'"), output); fclose(io.input); return -1; } } - hunk_no = handle_path(sha1, (struct rerere_io *)&io, marker_size); + has_conflicts = handle_path(sha1, (struct rerere_io *)&io, marker_size); fclose(io.input); if (io.io.wrerror) - error("There were errors while writing %s (%s)", + error(_("there were errors while writing '%s' (%s)"), path, strerror(io.io.wrerror)); if (io.io.output && fclose(io.io.output)) - io.io.wrerror = error_errno("Failed to flush %s", path); + io.io.wrerror = error_errno(_("failed to flush '%s'"), path); - if (hunk_no < 0) { + if (has_conflicts < 0) { if (output) unlink_or_warn(output); - return error("Could not parse conflict hunks in %s", path); + return error(_("could not parse conflict hunks in '%s'"), path); } if (io.io.wrerror) return -1; - return hunk_no; + return has_conflicts; } /* @@@ -511,9 -524,9 +512,9 @@@ * stages we have already looked at in this invocation of this * function. */ - static int check_one_conflict(int i, int *type) + static int check_one_conflict(struct index_state *istate, int i, int *type) { - const struct cache_entry *e = active_cache[i]; + const struct cache_entry *e = istate->cache[i]; if (!ce_stage(e)) { *type = RESOLVED; @@@ -521,13 -534,13 +522,13 @@@ } *type = PUNTED; - while (i < active_nr && ce_stage(active_cache[i]) == 1) - while (ce_stage(istate->cache[i]) == 1) ++ while (i < istate->cache_nr && ce_stage(istate->cache[i]) == 1) i++; /* Only handle regular files with both stages #2 and #3 */ - if (i + 1 < active_nr) { - const struct cache_entry *e2 = active_cache[i]; - const struct cache_entry *e3 = active_cache[i + 1]; + if (i + 1 < istate->cache_nr) { + const struct cache_entry *e2 = istate->cache[i]; + const struct cache_entry *e3 = istate->cache[i + 1]; if (ce_stage(e2) == 2 && ce_stage(e3) == 3 && ce_same_name(e, e3) && @@@ -537,7 -550,7 +538,7 @@@ } /* Skip the entries with the same name */ - while (i < active_nr && ce_same_name(e, active_cache[i])) + while (i < istate->cache_nr && ce_same_name(e, istate->cache[i])) i++; return i; } @@@ -553,16 -566,17 +554,17 @@@ * are identical to the previous round, might want to be handled, * though. */ - static int find_conflict(struct string_list *conflict) + static int find_conflict(struct repository *r, struct string_list *conflict) { int i; - if (read_cache() < 0) + + if (read_index(r->index) < 0) - return error("Could not read index"); + return error(_("index file corrupt")); - for (i = 0; i < active_nr;) { + for (i = 0; i < r->index->cache_nr;) { int conflict_type; - const struct cache_entry *e = active_cache[i]; - i = check_one_conflict(i, &conflict_type); + const struct cache_entry *e = r->index->cache[i]; + i = check_one_conflict(r->index, i, &conflict_type); if (conflict_type == THREE_STAGED) string_list_insert(conflict, (const char *)e->name); } @@@ -584,18 -598,19 +586,19 @@@ * NEEDSWORK: we may want to fix the caller that implements "rerere * remaining" to do this without abusing merge_rr. */ - int rerere_remaining(struct string_list *merge_rr) + int rerere_remaining(struct repository *r, struct string_list *merge_rr) { int i; + if (setup_rerere(merge_rr, RERERE_READONLY)) return 0; - if (read_cache() < 0) + if (read_index(r->index) < 0) - return error("Could not read index"); + return error(_("index file corrupt")); - for (i = 0; i < active_nr;) { + for (i = 0; i < r->index->cache_nr;) { int conflict_type; - const struct cache_entry *e = active_cache[i]; - i = check_one_conflict(i, &conflict_type); + const struct cache_entry *e = r->index->cache[i]; + i = check_one_conflict(r->index, i, &conflict_type); if (conflict_type == PUNTED) string_list_insert(merge_rr, (const char *)e->name); else if (conflict_type == RESOLVED) { @@@ -615,7 -630,8 +618,8 @@@ * if that recorded conflict resolves cleanly what we * got in the "cur". */ - static int try_merge(const struct rerere_id *id, const char *path, + static int try_merge(struct index_state *istate, + const struct rerere_id *id, const char *path, mmfile_t *cur, mmbuffer_t *result) { int ret; @@@ -629,7 -645,8 +633,8 @@@ * 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); + ret = ll_merge(result, path, &base, NULL, cur, "", &other, "", + istate, NULL); free(base.ptr); free(other.ptr); @@@ -647,7 -664,7 +652,7 @@@ * Returns 0 for successful replay of recorded resolution, or non-zero * for failure. */ - static int merge(const struct rerere_id *id, const char *path) + static int merge(struct index_state *istate, const struct rerere_id *id, const char *path) { FILE *f; int ret; @@@ -658,13 -675,13 +663,13 @@@ * Normalize the conflicts in path and write it out to * "thisimage" temporary file. */ - if ((handle_file(path, NULL, rerere_path(id, "thisimage")) < 0) || + if ((handle_file(istate, path, NULL, rerere_path(id, "thisimage")) < 0) || read_mmfile(&cur, rerere_path(id, "thisimage"))) { ret = 1; goto out; } - ret = try_merge(id, path, &cur, &result); + ret = try_merge(istate, id, path, &cur, &result); if (ret) goto out; @@@ -673,17 -690,17 +678,17 @@@ * Mark that "postimage" was used to help gc. */ if (utime(rerere_path(id, "postimage"), NULL) < 0) - warning_errno("failed utime() on %s", + warning_errno(_("failed utime() on '%s'"), rerere_path(id, "postimage")); /* Update "path" with the resolution */ f = fopen(path, "w"); if (!f) - return error_errno("Could not open %s", path); + return error_errno(_("could not open '%s'"), path); if (fwrite(result.ptr, result.size, 1, f) != 1) - error_errno("Could not write %s", path); + error_errno(_("could not write '%s'"), path); if (fclose(f)) - return error_errno("Writing %s failed", path); + return error_errno(_("writing '%s' failed"), path); out: free(cur.ptr); @@@ -692,7 -709,7 +697,7 @@@ return ret; } - static void update_paths(struct string_list *update) + static void update_paths(struct repository *r, struct string_list *update) { struct lock_file index_lock = LOCK_INIT; int i; @@@ -701,15 -718,15 +706,15 @@@ for (i = 0; i < update->nr; i++) { struct string_list_item *item = &update->items[i]; - if (add_file_to_cache(item->string, 0)) + if (add_file_to_index(r->index, item->string, 0)) exit(128); - fprintf(stderr, "Staged '%s' using previous resolution.\n", + fprintf_ln(stderr, _("Staged '%s' using previous resolution."), item->string); } - if (write_locked_index(&the_index, &index_lock, + if (write_locked_index(r->index, &index_lock, COMMIT_LOCK | SKIP_IF_UNCHANGED)) - die("Unable to write new index file"); + die(_("unable to write new index file")); } static void remove_variant(struct rerere_id *id) @@@ -726,7 -743,8 +731,8 @@@ * 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 string_list_item *rr_item, + static void do_rerere_one_path(struct index_state *istate, + struct string_list_item *rr_item, struct string_list *update) { const char *path = rr_item->string; @@@ -738,10 -756,10 +744,10 @@@ /* Has the user resolved it already? */ if (variant >= 0) { - if (!handle_file(path, NULL, NULL)) { + if (!handle_file(istate, path, NULL, NULL)) { copy_file(rerere_path(id, "postimage"), path, 0666); id->collection->status[variant] |= RR_HAS_POSTIMAGE; - fprintf(stderr, "Recorded resolution for '%s'.\n", path); + fprintf_ln(stderr, _("Recorded resolution for '%s'."), path); free_rerere_id(rr_item); rr_item->util = NULL; return; @@@ -762,7 -780,7 +768,7 @@@ continue; vid.variant = variant; - if (merge(&vid, path)) + if (merge(istate, &vid, path)) continue; /* failed to replay */ /* @@@ -775,9 -793,9 +781,9 @@@ if (rerere_autoupdate) string_list_insert(update, path); else - fprintf(stderr, - "Resolved '%s' using previous resolution.\n", - path); + fprintf_ln(stderr, + _("Resolved '%s' using previous resolution."), + path); free_rerere_id(rr_item); rr_item->util = NULL; return; @@@ -787,24 -805,25 +793,25 @@@ assign_variant(id); variant = id->variant; - handle_file(path, NULL, rerere_path(id, "preimage")); + handle_file(istate, path, NULL, rerere_path(id, "preimage")); if (id->collection->status[variant] & RR_HAS_POSTIMAGE) { const char *path = rerere_path(id, "postimage"); if (unlink(path)) - die_errno("cannot unlink stray '%s'", path); + die_errno(_("cannot unlink stray '%s'"), path); id->collection->status[variant] &= ~RR_HAS_POSTIMAGE; } id->collection->status[variant] |= RR_HAS_PREIMAGE; - fprintf(stderr, "Recorded preimage for '%s'\n", path); + fprintf_ln(stderr, _("Recorded preimage for '%s'"), path); } - static int do_plain_rerere(struct string_list *rr, int fd) + static int do_plain_rerere(struct repository *r, + struct string_list *rr, int fd) { struct string_list conflict = STRING_LIST_INIT_DUP; struct string_list update = STRING_LIST_INIT_DUP; int i; - find_conflict(&conflict); + find_conflict(r, &conflict); /* * MERGE_RR records paths with conflicts immediately after @@@ -818,16 -837,15 +825,16 @@@ const char *path = conflict.items[i].string; int ret; - if (string_list_has_string(rr, path)) - continue; - /* * Ask handle_file() to scan and assign a * conflict ID. No need to write anything out * yet. */ - ret = handle_file(path, sha1, NULL); + ret = handle_file(r->index, path, sha1, NULL); + if (ret != 0 && string_list_has_string(rr, path)) { + remove_variant(string_list_lookup(rr, path)->util); + string_list_remove(rr, path, 1); + } if (ret < 1) continue; @@@ -839,10 -857,10 +846,10 @@@ } for (i = 0; i < rr->nr; i++) - do_rerere_one_path(&rr->items[i], &update); + do_rerere_one_path(r->index, &rr->items[i], &update); if (update.nr) - update_paths(&update); + update_paths(r, &update); return write_rr(rr, fd); } @@@ -868,7 -886,7 +875,7 @@@ static int is_rerere_enabled(void return rr_cache_exists; if (!rr_cache_exists && mkdir_in_gitdir(git_path_rr_cache())) - die("Could not create directory %s", git_path_rr_cache()); + die(_("could not create directory '%s'"), git_path_rr_cache()); return 1; } @@@ -897,7 -915,7 +904,7 @@@ int setup_rerere(struct string_list *me * perform mergy operations, possibly leaving conflicted index entries * and working tree files. */ - int rerere(int flags) + int repo_rerere(struct repository *r, int flags) { struct string_list merge_rr = STRING_LIST_INIT_DUP; int fd, status; @@@ -905,7 -923,7 +912,7 @@@ fd = setup_rerere(&merge_rr, flags); if (fd < 0) return 0; - status = do_plain_rerere(&merge_rr, fd); + status = do_plain_rerere(r, &merge_rr, fd); free_rerere_dirs(); return status; } @@@ -942,29 -960,30 +949,30 @@@ static int rerere_mem_getline(struct st return 0; } - static int handle_cache(const char *path, unsigned char *sha1, const char *output) + static int handle_cache(struct index_state *istate, const char *path, + unsigned char *sha1, const char *output) { mmfile_t mmfile[3] = {{NULL}}; mmbuffer_t result = {NULL, 0}; const struct cache_entry *ce; - int pos, len, i, hunk_no; + int pos, len, i, has_conflicts; struct rerere_io_mem io; - int marker_size = ll_merge_marker_size(path); + int marker_size = ll_merge_marker_size(istate, path); /* * Reproduce the conflicted merge in-core */ len = strlen(path); - pos = cache_name_pos(path, len); + pos = index_name_pos(istate, path, len); if (0 <= pos) return -1; pos = -pos - 1; - while (pos < active_nr) { + while (pos < istate->cache_nr) { enum object_type type; unsigned long size; - ce = active_cache[pos++]; + ce = istate->cache[pos++]; if (ce_namelen(ce) != len || memcmp(ce->name, path, len)) break; i = ce_stage(ce) - 1; @@@ -984,7 -1003,8 +992,8 @@@ */ ll_merge(&result, path, &mmfile[0], NULL, &mmfile[1], "ours", - &mmfile[2], "theirs", NULL); + &mmfile[2], "theirs", + istate, NULL); for (i = 0; i < 3; i++) free(mmfile[i].ptr); @@@ -1001,14 -1021,16 +1010,16 @@@ * Grab the conflict ID and optionally write the original * contents with conflict markers out. */ - hunk_no = handle_path(sha1, (struct rerere_io *)&io, marker_size); + has_conflicts = handle_path(sha1, (struct rerere_io *)&io, marker_size); strbuf_release(&io.input); if (io.io.output) fclose(io.io.output); - return hunk_no; + return has_conflicts; } - static int rerere_forget_one_path(const char *path, struct string_list *rr) + static int rerere_forget_one_path(struct index_state *istate, + const char *path, + struct string_list *rr) { const char *filename; struct rerere_id *id; @@@ -1020,9 -1042,9 +1031,9 @@@ * Recreate the original conflict from the stages in the * index and compute the conflict ID */ - ret = handle_cache(path, sha1, NULL); + ret = handle_cache(istate, path, sha1, NULL); if (ret < 1) - return error("Could not parse conflict hunks in '%s'", path); + return error(_("could not parse conflict hunks in '%s'"), path); /* Nuke the recorded resolution for the conflict */ id = new_rerere_id(sha1); @@@ -1037,13 -1059,13 +1048,13 @@@ if (!has_rerere_resolution(id)) continue; - handle_cache(path, sha1, rerere_path(id, "thisimage")); + handle_cache(istate, path, sha1, rerere_path(id, "thisimage")); if (read_mmfile(&cur, rerere_path(id, "thisimage"))) { free(cur.ptr); - error("Failed to update conflicted state in '%s'", path); + error(_("failed to update conflicted state in '%s'"), path); goto fail_exit; } - cleanly_resolved = !try_merge(id, path, &cur, &result); + cleanly_resolved = !try_merge(istate, id, path, &cur, &result); free(result.ptr); free(cur.ptr); if (cleanly_resolved) @@@ -1051,16 -1073,16 +1062,16 @@@ } if (id->collection->status_nr <= id->variant) { - error("no remembered resolution for '%s'", path); + error(_("no remembered resolution for '%s'"), path); goto fail_exit; } filename = rerere_path(id, "postimage"); if (unlink(filename)) { if (errno == ENOENT) - error("no remembered resolution for %s", path); + error(_("no remembered resolution for '%s'"), path); else - error_errno("cannot unlink %s", filename); + error_errno(_("cannot unlink '%s'"), filename); goto fail_exit; } @@@ -1069,8 -1091,8 +1080,8 @@@ * conflict in the working tree, run us again to record * the postimage. */ - handle_cache(path, sha1, rerere_path(id, "preimage")); + handle_cache(istate, path, sha1, rerere_path(id, "preimage")); - fprintf(stderr, "Updated preimage for '%s'\n", path); + fprintf_ln(stderr, _("Updated preimage for '%s'"), path); /* * And remember that we can record resolution for this @@@ -1079,7 -1101,7 +1090,7 @@@ item = string_list_insert(rr, path); free_rerere_id(item); item->util = id; - fprintf(stderr, "Forgot resolution for %s\n", path); + fprintf(stderr, _("Forgot resolution for '%s'\n"), path); return 0; fail_exit: @@@ -1087,14 -1109,14 +1098,14 @@@ return -1; } - int rerere_forget(struct pathspec *pathspec) + int rerere_forget(struct repository *r, struct pathspec *pathspec) { int i, fd; struct string_list conflict = STRING_LIST_INIT_DUP; struct string_list merge_rr = STRING_LIST_INIT_DUP; - if (read_cache() < 0) + if (read_index(r->index) < 0) - return error("Could not read index"); + return error(_("index file corrupt")); fd = setup_rerere(&merge_rr, RERERE_NOAUTOUPDATE); if (fd < 0) @@@ -1105,14 -1127,14 +1116,14 @@@ * recover the original conflicted state and then * find the conflicted paths. */ - unmerge_cache(pathspec); - find_conflict(&conflict); + unmerge_index(r->index, pathspec); + find_conflict(r, &conflict); for (i = 0; i < conflict.nr; i++) { struct string_list_item *it = &conflict.items[i]; - if (!match_pathspec(&the_index, pathspec, it->string, + if (!match_pathspec(r->index, pathspec, it->string, strlen(it->string), 0, NULL, 0)) continue; - rerere_forget_one_path(it->string, &merge_rr); + rerere_forget_one_path(r->index, it->string, &merge_rr); } return write_rr(&merge_rr, fd); } @@@ -1182,7 -1204,7 +1193,7 @@@ void rerere_gc(struct string_list *rr git_config(git_default_config, NULL); dir = opendir(git_path("rr-cache")); if (!dir) - die_errno("unable to open rr-cache directory"); + die_errno(_("unable to open rr-cache directory")); /* Collect stale conflict IDs ... */ while ((e = readdir(dir))) { struct rerere_dir *rr_dir; diff --combined revision.c index e18bd530e4,28366eaccf..b5108b75ab --- a/revision.c +++ b/revision.c @@@ -24,7 -24,6 +24,7 @@@ #include "packfile.h" #include "worktree.h" #include "argv-array.h" +#include "commit-reach.h" volatile show_early_output_fn_t show_early_output; @@@ -52,7 -51,8 +52,8 @@@ static void mark_blob_uninteresting(str blob->object.flags |= UNINTERESTING; } - static void mark_tree_contents_uninteresting(struct tree *tree) + static void mark_tree_contents_uninteresting(struct repository *r, + struct tree *tree) { struct tree_desc desc; struct name_entry entry; @@@ -64,10 -64,10 +65,10 @@@ while (tree_entry(&desc, &entry)) { switch (object_type(entry.mode)) { case OBJ_TREE: - mark_tree_uninteresting(lookup_tree(the_repository, entry.oid)); + mark_tree_uninteresting(r, lookup_tree(r, entry.oid)); break; case OBJ_BLOB: - mark_blob_uninteresting(lookup_blob(the_repository, entry.oid)); + mark_blob_uninteresting(lookup_blob(r, entry.oid)); break; default: /* Subproject commit - not in this repository */ @@@ -82,7 -82,7 +83,7 @@@ free_tree_buffer(tree); } - void mark_tree_uninteresting(struct tree *tree) + void mark_tree_uninteresting(struct repository *r, struct tree *tree) { struct object *obj; @@@ -93,7 -93,7 +94,7 @@@ if (obj->flags & UNINTERESTING) return; obj->flags |= UNINTERESTING; - mark_tree_contents_uninteresting(tree); + mark_tree_contents_uninteresting(r, tree); } struct commit_stack { @@@ -199,7 -199,7 +200,7 @@@ void add_head_to_pending(struct rev_inf struct object *obj; if (get_oid("HEAD", &oid)) return; - obj = parse_object(the_repository, &oid); + obj = parse_object(revs->repo, &oid); if (!obj) return; add_pending_object(revs, obj, "HEAD"); @@@ -211,7 -211,7 +212,7 @@@ static struct object *get_reference(str { struct object *object; - object = parse_object(the_repository, oid); + object = parse_object(revs->repo, oid); if (!object) { if (revs->ignore_missing) return object; @@@ -248,7 -248,7 +249,7 @@@ static struct commit *handle_commit(str add_pending_object(revs, object, tag->tag); if (!tag->tagged) die("bad tag"); - object = parse_object(the_repository, &tag->tagged->oid); + object = parse_object(revs->repo, &tag->tagged->oid); if (!object) { if (revs->ignore_missing_links || (flags & UNINTERESTING)) return NULL; @@@ -298,7 -298,7 +299,7 @@@ if (!revs->tree_objects) return NULL; if (flags & UNINTERESTING) { - mark_tree_contents_uninteresting(tree); + mark_tree_contents_uninteresting(revs->repo, tree); return NULL; } add_pending_object_with_path(revs, object, name, mode, path); @@@ -878,7 -878,7 +879,7 @@@ static void cherry_pick_list(struct com return; left_first = left_count < right_count; - init_patch_ids(&ids); + init_patch_ids(revs->repo, &ids); ids.diffopts.pathspec = revs->diffopt.pathspec; /* Compute patch-ids for one side */ @@@ -1254,7 -1254,7 +1255,7 @@@ static void handle_one_reflog_commit(st { struct all_refs_cb *cb = cb_data; if (!is_null_oid(oid)) { - struct object *o = parse_object(the_repository, oid); + struct object *o = parse_object(cb->all_revs->repo, oid); if (o) { o->flags |= cb->all_flags; /* ??? CMDLINEFLAGS ??? */ @@@ -1313,7 -1313,7 +1314,7 @@@ void add_reflogs_to_pending(struct rev_ cb.all_revs = revs; cb.all_flags = flags; - cb.refs = get_main_ref_store(the_repository); + cb.refs = get_main_ref_store(revs->repo); for_each_reflog(handle_one_reflog, &cb); if (!revs->single_worktree) @@@ -1327,7 -1327,7 +1328,7 @@@ static void add_cache_tree(struct cache int i; if (it->entry_count >= 0) { - struct tree *tree = lookup_tree(the_repository, &it->oid); + struct tree *tree = lookup_tree(revs->repo, &it->oid); add_pending_object_with_path(revs, &tree->object, "", 040000, path->buf); } @@@ -1353,7 -1353,7 +1354,7 @@@ static void do_add_index_objects_to_pen if (S_ISGITLINK(ce->ce_mode)) continue; - blob = lookup_blob(the_repository, &ce->oid); + blob = lookup_blob(revs->repo, &ce->oid); if (!blob) die("unable to add index blob to traversal"); add_pending_object_with_path(revs, &blob->object, "", @@@ -1371,8 -1371,8 +1372,8 @@@ void add_index_objects_to_pending(struc { struct worktree **worktrees, **p; - read_cache(); - do_add_index_objects_to_pending(revs, &the_index); + read_index(revs->repo->index); + do_add_index_objects_to_pending(revs, revs->repo->index); if (revs->single_worktree) return; @@@ -1440,10 -1440,13 +1441,13 @@@ static int add_parents_only(struct rev_ return 1; } - void init_revisions(struct rev_info *revs, const char *prefix) + void repo_init_revisions(struct repository *r, + struct rev_info *revs, + const char *prefix) { memset(revs, 0, sizeof(*revs)); + revs->repo = r; revs->abbrev = DEFAULT_ABBREV; revs->ignore_merges = 1; revs->simplify_history = 1; @@@ -1465,11 -1468,11 +1469,11 @@@ revs->commit_format = CMIT_FMT_DEFAULT; revs->expand_tabs_in_log_default = 8; - init_grep_defaults(); - grep_init(&revs->grep_filter, prefix); + init_grep_defaults(revs->repo); + grep_init(&revs->grep_filter, revs->repo, prefix); revs->grep_filter.status_only = 1; - diff_setup(&revs->diffopt); + repo_diff_setup(revs->repo, &revs->diffopt); if (prefix && !revs->diffopt.prefix) { revs->diffopt.prefix = prefix; revs->diffopt.prefix_length = strlen(prefix); @@@ -1497,6 -1500,7 +1501,7 @@@ static void prepare_show_merge(struct r struct object_id oid; const char **prune = NULL; int i, prune_num = 1; /* counting terminating NULL */ + struct index_state *istate = revs->repo->index; if (get_oid("HEAD", &oid)) die("--merge without HEAD?"); @@@ -1512,20 -1516,20 +1517,20 @@@ free_commit_list(bases); head->object.flags |= SYMMETRIC_LEFT; - if (!active_nr) - read_cache(); - for (i = 0; i < active_nr; i++) { - const struct cache_entry *ce = active_cache[i]; + if (!istate->cache_nr) + read_index(istate); + for (i = 0; i < istate->cache_nr; i++) { + const struct cache_entry *ce = istate->cache[i]; if (!ce_stage(ce)) continue; - if (ce_path_match(&the_index, ce, &revs->prune_data, NULL)) { + if (ce_path_match(istate, ce, &revs->prune_data, NULL)) { prune_num++; REALLOC_ARRAY(prune, prune_num); prune[prune_num-2] = ce->name; prune[prune_num-1] = NULL; } - while ((i+1 < active_nr) && - ce_same_name(ce, active_cache[i+1])) + while ((i+1 < istate->cache_nr) && + ce_same_name(ce, istate->cache[i+1])) i++; } clear_pathspec(&revs->prune_data); @@@ -1582,8 -1586,8 +1587,8 @@@ static int handle_dotdot_1(const char * *dotdot = '\0'; } - a_obj = parse_object(the_repository, &a_oid); - b_obj = parse_object(the_repository, &b_oid); + a_obj = parse_object(revs->repo, &a_oid); + b_obj = parse_object(revs->repo, &b_oid); if (!a_obj || !b_obj) return dotdot_missing(arg, dotdot, revs, symmetric); @@@ -1596,8 -1600,8 +1601,8 @@@ struct commit *a, *b; struct commit_list *exclude; - a = lookup_commit_reference(the_repository, &a_obj->oid); - b = lookup_commit_reference(the_repository, &b_obj->oid); + a = lookup_commit_reference(revs->repo, &a_obj->oid); + b = lookup_commit_reference(revs->repo, &b_obj->oid); if (!a || !b) return dotdot_missing(arg, dotdot, revs, symmetric); @@@ -2205,7 -2209,7 +2210,7 @@@ static int handle_revision_pseudo_opt(c BUG("--single-worktree cannot be used together with submodule"); refs = get_submodule_ref_store(submodule); } else - refs = get_main_ref_store(the_repository); + refs = get_main_ref_store(revs->repo); /* * NOTE! @@@ -2319,7 -2323,7 +2324,7 @@@ static void NORETURN diagnose_missing_d */ int setup_revisions(int argc, const char **argv, struct rev_info *revs, struct setup_revision_opt *opt) { - int i, flags, left, seen_dashdash, read_from_stdin, got_rev_arg = 0, revarg_opt; + int i, flags, left, seen_dashdash, got_rev_arg = 0, revarg_opt; struct argv_array prune_data = ARGV_ARRAY_INIT; const char *submodule = NULL; @@@ -2349,6 -2353,7 +2354,6 @@@ revarg_opt = opt ? opt->revarg_opt : 0; if (seen_dashdash) revarg_opt |= REVARG_CANNOT_BE_FILENAME; - read_from_stdin = 0; for (left = i = 1; i < argc; i++) { const char *arg = argv[i]; if (*arg == '-') { @@@ -2367,7 -2372,7 +2372,7 @@@ argv[left++] = arg; continue; } - if (read_from_stdin++) + if (revs->read_from_stdin++) die("--stdin given twice?"); read_revisions_from_stdin(revs, &prune_data); continue; @@@ -2885,9 -2890,10 +2890,10 @@@ void reset_revision_walk(void static int mark_uninteresting(const struct object_id *oid, struct packed_git *pack, uint32_t pos, - void *unused) + void *cb) { - struct object *o = parse_object(the_repository, oid); + struct rev_info *revs = cb; + struct object *o = parse_object(revs->repo, oid); o->flags |= UNINTERESTING | SEEN; return 0; } @@@ -2920,7 -2926,7 +2926,7 @@@ int prepare_revision_walk(struct rev_in revs->treesame.name = "treesame"; if (revs->exclude_promisor_objects) { - for_each_packed_object(mark_uninteresting, NULL, + for_each_packed_object(mark_uninteresting, revs, FOR_EACH_OBJECT_PROMISOR_ONLY); } @@@ -3238,7 -3244,7 +3244,7 @@@ static void track_linear(struct rev_inf struct commit_list *p; for (p = revs->previous_parents; p; p = p->next) if (p->item == NULL || /* first commit */ - !oidcmp(&p->item->object.oid, &commit->object.oid)) + oideq(&p->item->object.oid, &commit->object.oid)) break; revs->linear = p != NULL; } diff --combined revision.h index 2b30ac270d,7e62a65bad..bc30a3023e --- a/revision.h +++ b/revision.h @@@ -28,8 -28,9 +28,9 @@@ #define DECORATE_SHORT_REFS 1 #define DECORATE_FULL_REFS 2 - struct rev_info; struct log_info; + struct repository; + struct rev_info; struct string_list; struct saved_parents; define_shared_commit_slab(revision_sources, char *); @@@ -60,6 -61,7 +61,7 @@@ struct rev_info /* Starting list */ struct commit_list *commits; struct object_array pending; + struct repository *repo; /* Parents of shown commits */ struct object_array boundary_commits; @@@ -82,11 -84,6 +84,11 @@@ */ int rev_input_given; + /* + * Whether we read from stdin due to the --stdin option. + */ + int read_from_stdin; + /* topo-sort */ enum rev_sort_order sort_order; @@@ -219,17 -216,6 +221,17 @@@ /* notes-specific options: which refs to show */ struct display_notes_opt notes_opt; + /* interdiff */ + const struct object_id *idiff_oid1; + const struct object_id *idiff_oid2; + const char *idiff_title; + + /* range-diff */ + const char *rdiff1; + const char *rdiff2; + int creation_factor; + const char *rdiff_title; + /* commit counts */ int count_left; int count_right; @@@ -264,12 -250,17 +266,17 @@@ extern volatile show_early_output_fn_t struct setup_revision_opt { const char *def; void (*tweak)(struct rev_info *, struct setup_revision_opt *); - const char *submodule; + const char *submodule; /* TODO: drop this and use rev_info->repo */ int assume_dashdash; unsigned revarg_opt; }; - void init_revisions(struct rev_info *revs, const char *prefix); + #ifndef NO_THE_REPOSITORY_COMPATIBILITY_MACROS + #define init_revisions(revs, prefix) repo_init_revisions(the_repository, revs, prefix) + #endif + void repo_init_revisions(struct repository *r, + struct rev_info *revs, + const char *prefix); int setup_revisions(int argc, const char **argv, struct rev_info *revs, struct setup_revision_opt *); void parse_revision_opt(struct rev_info *revs, struct parse_opt_ctx_t *ctx, @@@ -289,7 -280,7 +296,7 @@@ void put_revision_mark(const struct rev const struct commit *commit); void mark_parents_uninteresting(struct commit *commit); - void mark_tree_uninteresting(struct tree *tree); + void mark_tree_uninteresting(struct repository *r, struct tree *tree); void show_object_with_name(FILE *, struct object *, const char *); diff --combined sequencer.c index 6387c9ee6e,da4e727cc3..83f17721d4 --- a/sequencer.c +++ b/sequencer.c @@@ -30,7 -30,6 +30,7 @@@ #include "oidset.h" #include "commit-slab.h" #include "alias.h" +#include "commit-reach.h" #define GIT_REFLOG_ACTION "GIT_REFLOG_ACTION" @@@ -226,16 -225,13 +226,16 @@@ static const char *get_todo_path(const * Returns 3 when sob exists within conforming footer as last entry */ static int has_conforming_footer(struct strbuf *sb, struct strbuf *sob, - int ignore_footer) + size_t ignore_footer) { + struct process_trailer_options opts = PROCESS_TRAILER_OPTIONS_INIT; struct trailer_info info; - int i; + size_t i; int found_sob = 0, found_sob_last = 0; - trailer_info_get(&info, sb->buf); + opts.no_divider = 1; + + trailer_info_get(&info, sb->buf, &opts); if (info.trailer_start == info.trailer_end) return 0; @@@ -474,8 -470,8 +474,8 @@@ static int fast_forward_to(const struc struct strbuf sb = STRBUF_INIT; struct strbuf err = STRBUF_INIT; - read_cache(); - if (checkout_fast_forward(from, to, 1)) + read_index(&the_index); + if (checkout_fast_forward(the_repository, from, to, 1)) return -1; /* the callee should have complained already */ strbuf_addf(&sb, _("%s: fast-forward"), _(action_name(opts))); @@@ -614,7 -610,7 +614,7 @@@ static int is_index_unchanged(void if (!(cache_tree_oid = get_cache_tree_oid())) return -1; - return !oidcmp(cache_tree_oid, get_commit_tree_oid(head_commit)); + return oideq(cache_tree_oid, get_commit_tree_oid(head_commit)); } static int write_author_script(const char *message) @@@ -903,7 -899,7 +903,7 @@@ static int run_git_commit(const char *d if ((flags & ALLOW_EMPTY)) argv_array_push(&cmd.args, "--allow-empty"); - if (opts->allow_empty_message) + if (!(flags & EDIT_MSG)) argv_array_push(&cmd.args, "--allow-empty-message"); if (cmd.err == -1) { @@@ -1176,7 -1172,7 +1176,7 @@@ void print_commit_summary(const char *p strbuf_release(&author_ident); strbuf_release(&committer_ident); - init_revisions(&rev, prefix); + repo_init_revisions(the_repository, &rev, prefix); setup_revisions(0, NULL, &rev, NULL); rev.diff = 1; @@@ -1221,7 -1217,7 +1221,7 @@@ static int parse_head(struct commit **h current_head = lookup_commit_reference(the_repository, &oid); if (!current_head) return error(_("could not parse HEAD")); - if (oidcmp(&oid, ¤t_head->object.oid)) { + if (!oideq(&oid, ¤t_head->object.oid)) { warning(_("HEAD %s is not a commit!"), oid_to_hex(&oid)); } @@@ -1291,9 -1287,9 +1291,9 @@@ static int try_to_commit(struct strbuf goto out; } - if (!(flags & ALLOW_EMPTY) && !oidcmp(current_head ? - get_commit_tree_oid(current_head) : - the_hash_algo->empty_tree, &tree)) { + if (!(flags & ALLOW_EMPTY) && oideq(current_head ? + get_commit_tree_oid(current_head) : + the_hash_algo->empty_tree, &tree)) { res = 1; /* run 'git commit' to display error message */ goto out; } @@@ -1317,7 -1313,7 +1317,7 @@@ if (cleanup != COMMIT_MSG_CLEANUP_NONE) strbuf_stripspace(msg, cleanup == COMMIT_MSG_CLEANUP_ALL); - if (!opts->allow_empty_message && message_is_empty(msg, cleanup)) { + if ((flags & EDIT_MSG) && message_is_empty(msg, cleanup)) { res = 1; /* run 'git commit' to display error message */ goto out; } @@@ -1398,7 -1394,7 +1398,7 @@@ static int is_original_commit_empty(str ptree_oid = the_hash_algo->empty_tree; /* commit is root */ } - return !oidcmp(ptree_oid, get_commit_tree_oid(commit)); + return oideq(ptree_oid, get_commit_tree_oid(commit)); } /* @@@ -1678,7 -1674,7 +1678,7 @@@ static int do_pick_commit(enum todo_com unborn = get_oid("HEAD", &head); /* Do we want to generate a root commit? */ if (is_pick_or_similar(command) && opts->have_squash_onto && - !oidcmp(&head, &opts->squash_onto)) { + oideq(&head, &opts->squash_onto)) { if (is_fixup(command)) return error(_("cannot fixup root commit")); flags |= CREATE_ROOT_COMMIT; @@@ -1721,7 -1717,7 +1721,7 @@@ oid_to_hex(&commit->object.oid)); if (opts->allow_ff && !is_fixup(command) && - ((parent && !oidcmp(&parent->object.oid, &head)) || + ((parent && oideq(&parent->object.oid, &head)) || (!parent && unborn))) { if (is_rebase_i(opts)) write_author_script(msg.message); @@@ -1831,7 -1827,7 +1831,7 @@@ commit_list_insert(base, &common); commit_list_insert(next, &remotes); - res |= try_merge_command(opts->strategy, + res |= try_merge_command(the_repository, opts->strategy, opts->xopts_nr, (const char **)opts->xopts, common, oid_to_hex(&head), remotes); free_commit_list(common); @@@ -1860,7 -1856,7 +1860,7 @@@ : _("could not apply %s... %s"), short_commit_name(commit), msg.subject); print_advice(res == 1, opts); - rerere(opts->allow_rerere_auto); + repo_rerere(the_repository, opts->allow_rerere_auto); goto leave; } @@@ -2426,7 -2422,7 +2426,7 @@@ static int rollback_is_safe(void if (get_oid("HEAD", &actual_head)) oidclr(&actual_head); - return !oidcmp(&actual_head, &expected_head); + return oideq(&actual_head, &expected_head); } static int reset_for_rollback(const struct object_id *oid) @@@ -2599,7 -2595,7 +2599,7 @@@ static int make_patch(struct commit *co strbuf_addf(&buf, "%s/patch", get_dir(opts)); memset(&log_tree_opt, 0, sizeof(log_tree_opt)); - init_revisions(&log_tree_opt, NULL); + repo_init_revisions(the_repository, &log_tree_opt, NULL); log_tree_opt.abbrev = 0; log_tree_opt.diff = 1; log_tree_opt.diffopt.output_format = DIFF_FORMAT_PATCH; @@@ -2987,7 -2983,7 +2987,7 @@@ static int do_merge(struct commit *comm } if (opts->have_squash_onto && - !oidcmp(&head_commit->object.oid, &opts->squash_onto)) { + oideq(&head_commit->object.oid, &opts->squash_onto)) { /* * When the user tells us to "merge" something into a * "[new root]", let's simply fast-forward to the merge head. @@@ -3056,8 -3052,8 +3056,8 @@@ * commit, we cannot fast-forward. */ can_fast_forward = opts->allow_ff && commit && commit->parents && - !oidcmp(&commit->parents->item->object.oid, - &head_commit->object.oid); + oideq(&commit->parents->item->object.oid, + &head_commit->object.oid); /* * If any merge head is different from the original one, we cannot @@@ -3067,7 -3063,7 +3067,7 @@@ struct commit_list *p = commit->parents->next; for (j = to_merge; j && p; j = j->next, p = p->next) - if (oidcmp(&j->item->object.oid, + if (!oideq(&j->item->object.oid, &p->item->object.oid)) { can_fast_forward = 0; break; @@@ -3135,8 -3131,8 +3135,8 @@@ write_message("no-ff", 5, git_path_merge_mode(the_repository), 0); bases = get_merge_bases(head_commit, merge_commit); - if (bases && !oidcmp(&merge_commit->object.oid, - &bases->item->object.oid)) { + if (bases && oideq(&merge_commit->object.oid, + &bases->item->object.oid)) { ret = 0; /* skip merging an ancestor of HEAD */ goto leave_merge; @@@ -3179,7 -3175,7 +3179,7 @@@ rollback_lock_file(&lock); if (ret) - rerere(opts->allow_rerere_auto); + repo_rerere(the_repository, opts->allow_rerere_auto); else /* * In case of problems, we now want to return a positive @@@ -3382,9 -3378,9 +3382,9 @@@ static int pick_commits(struct todo_lis */ if (item->command == TODO_REWORD && !get_oid("HEAD", &oid) && - (!oidcmp(&item->commit->object.oid, &oid) || + (oideq(&item->commit->object.oid, &oid) || (opts->have_squash_onto && - !oidcmp(&opts->squash_onto, &oid)))) + oideq(&opts->squash_onto, &oid)))) to_amend = 1; return res | error_with_patch(item->commit, @@@ -3510,7 -3506,7 +3510,7 @@@ cleanup_head_ref struct object_id orig, head; memset(&log_tree_opt, 0, sizeof(log_tree_opt)); - init_revisions(&log_tree_opt, NULL); + repo_init_revisions(the_repository, &log_tree_opt, NULL); log_tree_opt.diff = 1; log_tree_opt.diffopt.output_format = DIFF_FORMAT_DIFFSTAT; @@@ -3599,7 -3595,7 +3599,7 @@@ static int commit_staged_changes(struc if (get_oid_hex(rev.buf, &to_amend)) return error(_("invalid contents: '%s'"), rebase_path_amend()); - if (!is_clean && oidcmp(&head, &to_amend)) + if (!is_clean && !oideq(&head, &to_amend)) return error(_("\nYou have uncommitted changes in your " "working tree. Please, commit them\n" "first and then run 'git rebase " @@@ -3611,20 -3607,9 +3611,20 @@@ * the commit message and if there was a squash, let the user * edit it. */ - if (is_clean && !oidcmp(&head, &to_amend) && - opts->current_fixup_count > 0 && - file_exists(rebase_path_stopped_sha())) { + if (!is_clean || !opts->current_fixup_count) + ; /* this is not the final fixup */ + else if (!oideq(&head, &to_amend) || + !file_exists(rebase_path_stopped_sha())) { + /* was a final fixup or squash done manually? */ + if (!is_fixup(peek_command(todo_list, 0))) { + unlink(rebase_path_fixup_msg()); + unlink(rebase_path_squash_msg()); + unlink(rebase_path_current_fixups()); + strbuf_reset(&opts->current_fixups); + opts->current_fixup_count = 0; + } + } else { + /* we are in a fixup/squash chain */ const char *p = opts->current_fixups.buf; int len = opts->current_fixups.len; @@@ -3843,7 -3828,7 +3843,7 @@@ int sequencer_pick_revisions(struct rep return res; } -void append_signoff(struct strbuf *msgbuf, int ignore_footer, unsigned flag) +void append_signoff(struct strbuf *msgbuf, size_t ignore_footer, unsigned flag) { unsigned no_dup_sob = flag & APPEND_SIGNOFF_DEDUP; struct strbuf sob = STRBUF_INIT; @@@ -4146,7 -4131,9 +4146,7 @@@ static int make_script_with_merges(stru struct object_id *oid = &parent->item->object.oid; if (!oidset_contains(&interesting, oid)) continue; - if (!oidset_contains(&child_seen, oid)) - oidset_insert(&child_seen, oid); - else + if (oidset_insert(&child_seen, oid)) label_oid(oid, "branch-point", &state); } @@@ -4254,7 -4241,7 +4254,7 @@@ int sequencer_make_script(FILE *out, in const char *insn = flags & TODO_LIST_ABBREVIATE_CMDS ? "p" : "pick"; int rebase_merges = flags & TODO_LIST_REBASE_MERGES; - init_revisions(&revs, NULL); + repo_init_revisions(the_repository, &revs, NULL); revs.verbose_header = 1; if (!rebase_merges) revs.max_parents = 1; @@@ -4587,7 -4574,7 +4587,7 @@@ int skip_unnecessary_picks(void if (item->commit->parents->next) break; /* merge commit */ parent_oid = &item->commit->parents->item->object.oid; - if (hashcmp(parent_oid->hash, oid->hash)) + if (!oideq(parent_oid, oid)) break; oid = &item->commit->object.oid; } diff --combined sha1-file.c index a4367b8f04,308d5e20e2..dd0b6aa873 --- a/sha1-file.c +++ b/sha1-file.c @@@ -149,10 -149,10 +149,10 @@@ static struct cached_object *find_cache struct cached_object *co = cached_objects; for (i = 0; i < cached_object_nr; i++, co++) { - if (!oidcmp(&co->oid, oid)) + if (oideq(&co->oid, oid)) return co; } - if (!oidcmp(oid, the_hash_algo->empty_tree)) + if (oideq(oid, the_hash_algo->empty_tree)) return &empty_tree; return NULL; } @@@ -825,7 -825,7 +825,7 @@@ int check_object_signature(const struc if (map) { hash_object_file(map, size, type, &real_oid); - return oidcmp(oid, &real_oid) ? -1 : 0; + return !oideq(oid, &real_oid) ? -1 : 0; } st = open_istream(oid, &obj_type, &size, NULL); @@@ -852,7 -852,7 +852,7 @@@ } the_hash_algo->final_fn(real_oid.hash, &c); close_istream(st); - return oidcmp(oid, &real_oid) ? -1 : 0; + return !oideq(oid, &real_oid) ? -1 : 0; } int git_open_cloexec(const char *name, int flags) @@@ -1317,7 -1317,7 +1317,7 @@@ int oid_object_info_extended(struct rep * TODO Pass a repository struct through fetch_object, * such that arbitrary repositories work. */ - fetch_object(repository_format_partial_clone, real->hash); + fetch_objects(repository_format_partial_clone, real, 1); already_retried = 1; continue; } @@@ -1671,7 -1671,7 +1671,7 @@@ static int write_loose_object(const str die(_("deflateEnd on object %s failed (%d)"), oid_to_hex(oid), ret); the_hash_algo->final_fn(parano_oid.hash, &c); - if (oidcmp(oid, ¶no_oid) != 0) + if (!oideq(oid, ¶no_oid)) die(_("confused by unstable object source data for %s"), oid_to_hex(oid)); @@@ -1813,7 -1813,8 +1813,8 @@@ static void check_tag(const void *buf, die(_("corrupt tag")); } - static int index_mem(struct object_id *oid, void *buf, size_t size, + static int index_mem(struct index_state *istate, + struct object_id *oid, void *buf, size_t size, enum object_type type, const char *path, unsigned flags) { @@@ -1828,7 -1829,7 +1829,7 @@@ */ if ((type == OBJ_BLOB) && path) { struct strbuf nbuf = STRBUF_INIT; - if (convert_to_git(&the_index, path, buf, size, &nbuf, + if (convert_to_git(istate, path, buf, size, &nbuf, get_conv_flags(flags))) { buf = strbuf_detach(&nbuf, &size); re_allocated = 1; @@@ -1852,17 -1853,20 +1853,20 @@@ return ret; } - static int index_stream_convert_blob(struct object_id *oid, int fd, - const char *path, unsigned flags) + static int index_stream_convert_blob(struct index_state *istate, + struct object_id *oid, + int fd, + const char *path, + unsigned flags) { int ret; const int write_object = flags & HASH_WRITE_OBJECT; struct strbuf sbuf = STRBUF_INIT; assert(path); - assert(would_convert_to_git_filter_fd(&the_index, path)); + assert(would_convert_to_git_filter_fd(istate, path)); - convert_to_git_filter_fd(&the_index, path, fd, &sbuf, + convert_to_git_filter_fd(istate, path, fd, &sbuf, get_conv_flags(flags)); if (write_object) @@@ -1875,14 -1879,15 +1879,15 @@@ return ret; } - static int index_pipe(struct object_id *oid, int fd, enum object_type type, + static int index_pipe(struct index_state *istate, struct object_id *oid, + int fd, enum object_type type, const char *path, unsigned flags) { struct strbuf sbuf = STRBUF_INIT; int ret; if (strbuf_read(&sbuf, fd, 4096) >= 0) - ret = index_mem(oid, sbuf.buf, sbuf.len, type, path, flags); + ret = index_mem(istate, oid, sbuf.buf, sbuf.len, type, path, flags); else ret = -1; strbuf_release(&sbuf); @@@ -1891,14 -1896,15 +1896,15 @@@ #define SMALL_FILE_SIZE (32*1024) - static int index_core(struct object_id *oid, int fd, size_t size, + static int index_core(struct index_state *istate, + struct object_id *oid, int fd, size_t size, enum object_type type, const char *path, unsigned flags) { int ret; if (!size) { - ret = index_mem(oid, "", size, type, path, flags); + ret = index_mem(istate, oid, "", size, type, path, flags); } else if (size <= SMALL_FILE_SIZE) { char *buf = xmalloc(size); ssize_t read_result = read_in_full(fd, buf, size); @@@ -1909,11 -1915,11 +1915,11 @@@ ret = error(_("short read while indexing %s"), path ? path : ""); else - ret = index_mem(oid, buf, size, type, path, flags); + ret = index_mem(istate, oid, buf, size, type, path, flags); free(buf); } else { void *buf = xmmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0); - ret = index_mem(oid, buf, size, type, path, flags); + ret = index_mem(istate, oid, buf, size, type, path, flags); munmap(buf, size); } return ret; @@@ -1941,7 -1947,8 +1947,8 @@@ static int index_stream(struct object_i return index_bulk_checkin(oid, fd, size, type, path, flags); } - int index_fd(struct object_id *oid, int fd, struct stat *st, + int index_fd(struct index_state *istate, struct object_id *oid, + int fd, struct stat *st, enum object_type type, const char *path, unsigned flags) { int ret; @@@ -1950,14 -1957,14 +1957,14 @@@ * Call xsize_t() only when needed to avoid potentially unnecessary * die() for large files. */ - if (type == OBJ_BLOB && path && would_convert_to_git_filter_fd(&the_index, path)) - ret = index_stream_convert_blob(oid, fd, path, flags); + if (type == OBJ_BLOB && path && would_convert_to_git_filter_fd(istate, path)) + ret = index_stream_convert_blob(istate, oid, fd, path, flags); else if (!S_ISREG(st->st_mode)) - ret = index_pipe(oid, fd, type, path, flags); + ret = index_pipe(istate, oid, fd, type, path, flags); else if (st->st_size <= big_file_threshold || type != OBJ_BLOB || - (path && would_convert_to_git(&the_index, path))) - ret = index_core(oid, fd, xsize_t(st->st_size), type, path, - flags); + (path && would_convert_to_git(istate, path))) + ret = index_core(istate, oid, fd, xsize_t(st->st_size), + type, path, flags); else ret = index_stream(oid, fd, xsize_t(st->st_size), type, path, flags); @@@ -1965,7 -1972,8 +1972,8 @@@ return ret; } - int index_path(struct object_id *oid, const char *path, struct stat *st, unsigned flags) + int index_path(struct index_state *istate, struct object_id *oid, + const char *path, struct stat *st, unsigned flags) { int fd; struct strbuf sb = STRBUF_INIT; @@@ -1976,7 -1984,7 +1984,7 @@@ fd = open(path, O_RDONLY); if (fd < 0) return error_errno("open(\"%s\")", path); - if (index_fd(oid, fd, st, OBJ_BLOB, path, flags) < 0) + if (index_fd(istate, oid, fd, st, OBJ_BLOB, path, flags) < 0) return error(_("%s: failed to insert into database"), path); break; @@@ -2213,7 -2221,7 +2221,7 @@@ static int check_stream_sha1(git_zstrea } the_hash_algo->final_fn(real_sha1, &c); - if (hashcmp(expected_sha1, real_sha1)) { + if (!hasheq(expected_sha1, real_sha1)) { error(_("sha1 mismatch for %s (expected %s)"), path, sha1_to_hex(expected_sha1)); return -1; diff --combined shallow.c index 99fd2d1ba0,e656ce8b9c..732e18d54f --- a/shallow.c +++ b/shallow.c @@@ -16,7 -16,6 +16,7 @@@ #include "list-objects.h" #include "commit-slab.h" #include "repository.h" +#include "commit-reach.h" void set_alternate_shallow_file(struct repository *r, const char *path, int override) { @@@ -185,7 -184,7 +185,7 @@@ struct commit_list *get_shallow_commits is_repository_shallow(the_repository); /* make sure shallows are read */ - init_revisions(&revs, NULL); + repo_init_revisions(the_repository, &revs, NULL); save_commit_buffer = 0; setup_revisions(ac, av, &revs, NULL); diff --combined submodule.c index b53cb6e9c4,442229bb49..25c6e5d5b9 --- a/submodule.c +++ b/submodule.c @@@ -22,7 -22,6 +22,7 @@@ #include "worktree.h" #include "parse-options.h" #include "object-store.h" +#include "commit-reach.h" static int config_update_recurse_submodules = RECURSE_SUBMODULES_OFF; static struct string_list changed_submodule_names = STRING_LIST_INIT_DUP; @@@ -66,7 -65,8 +66,7 @@@ int is_staging_gitmodules_ok(struct ind if ((pos >= 0) && (pos < istate->cache_nr)) { struct stat st; if (lstat(GITMODULES_FILE, &st) == 0 && - ie_match_stat(istate, istate->cache[pos], &st, - CE_MATCH_IGNORE_FSMONITOR) & DATA_CHANGED) + ie_match_stat(istate, istate->cache[pos], &st, 0) & DATA_CHANGED) return 0; } @@@ -428,7 -428,7 +428,7 @@@ static int prepare_submodule_summary(st { struct commit_list *list; - init_revisions(rev, NULL); + repo_init_revisions(the_repository, rev, NULL); setup_revisions(0, NULL, rev, NULL); rev->left_right = 1; rev->first_parent_only = 1; @@@ -536,7 -536,7 +536,7 @@@ static void show_submodule_header(struc fast_backward = 1; } - if (!oidcmp(one, two)) { + if (oideq(one, two)) { strbuf_release(&sb); return; } @@@ -766,13 -766,14 +766,14 @@@ static void collect_changed_submodules_ * have a corresponding 'struct oid_array' (in the 'util' field) which lists * what the submodule pointers were updated to during the change. */ - static void collect_changed_submodules(struct string_list *changed, + static void collect_changed_submodules(struct index_state *istate, + struct string_list *changed, struct argv_array *argv) { struct rev_info rev; const struct commit *commit; - init_revisions(&rev, NULL); + repo_init_revisions(the_repository, &rev, NULL); setup_revisions(argv->argc, argv->argv, &rev, NULL); if (prepare_revision_walk(&rev)) die("revision walk setup failed"); @@@ -783,7 -784,7 +784,7 @@@ data.changed = changed; data.commit_oid = &commit->object.oid; - init_revisions(&diff_rev, NULL); + repo_init_revisions(the_repository, &diff_rev, NULL); diff_rev.diffopt.output_format |= DIFF_FORMAT_CALLBACK; diff_rev.diffopt.format_callback = collect_changed_submodules_cb; diff_rev.diffopt.format_callback_data = &data; @@@ -930,8 -931,10 +931,10 @@@ static int submodule_needs_pushing(cons return 0; } - int find_unpushed_submodules(struct oid_array *commits, - const char *remotes_name, struct string_list *needs_pushing) + int find_unpushed_submodules(struct index_state *istate, + struct oid_array *commits, + const char *remotes_name, + struct string_list *needs_pushing) { struct string_list submodules = STRING_LIST_INIT_DUP; struct string_list_item *name; @@@ -943,7 -946,7 +946,7 @@@ argv_array_push(&argv, "--not"); argv_array_pushf(&argv, "--remotes=%s", remotes_name); - collect_changed_submodules(&submodules, &argv); + collect_changed_submodules(istate, &submodules, &argv); for_each_string_list_item(name, &submodules) { struct oid_array *commits = name->util; @@@ -1044,7 -1047,8 +1047,8 @@@ static void submodule_push_check(const die("process for submodule '%s' failed", path); } - int push_unpushed_submodules(struct oid_array *commits, + int push_unpushed_submodules(struct index_state *istate, + struct oid_array *commits, const struct remote *remote, const struct refspec *rs, const struct string_list *push_options, @@@ -1053,7 -1057,8 +1057,8 @@@ int i, ret = 1; struct string_list needs_pushing = STRING_LIST_INIT_DUP; - if (!find_unpushed_submodules(commits, remote->name, &needs_pushing)) + if (!find_unpushed_submodules(istate, commits, + remote->name, &needs_pushing)) return 1; /* @@@ -1110,7 -1115,7 +1115,7 @@@ void check_for_new_submodule_commits(st oid_array_append(&ref_tips_after_fetch, oid); } - static void calculate_changed_submodule_paths(void) + static void calculate_changed_submodule_paths(struct index_state *istate) { struct argv_array argv = ARGV_ARRAY_INIT; struct string_list changed_submodules = STRING_LIST_INIT_DUP; @@@ -1131,7 -1136,7 +1136,7 @@@ * Collect all submodules (whether checked out or not) for which new * commits have been recorded upstream in "changed_submodule_names". */ - collect_changed_submodules(&changed_submodules, &argv); + collect_changed_submodules(istate, &changed_submodules, &argv); for_each_string_list_item(name, &changed_submodules) { struct oid_array *commits = name->util; @@@ -1158,7 -1163,8 +1163,8 @@@ initialized_fetch_ref_tips = 0; } - int submodule_touches_in_range(struct object_id *excl_oid, + int submodule_touches_in_range(struct index_state *istate, + struct object_id *excl_oid, struct object_id *incl_oid) { struct string_list subs = STRING_LIST_INIT_DUP; @@@ -1176,7 -1182,7 +1182,7 @@@ argv_array_push(&args, oid_to_hex(excl_oid)); } - collect_changed_submodules(&subs, &args); + collect_changed_submodules(istate, &subs, &args); ret = subs.nr; argv_array_clear(&args); @@@ -1346,7 -1352,7 +1352,7 @@@ int fetch_populated_submodules(struct r argv_array_push(&spf.args, "--recurse-submodules-default"); /* default value, "--submodule-prefix" and its value are added later */ - calculate_changed_submodule_paths(); + calculate_changed_submodule_paths(r->index); run_processes_parallel(max_parallel_jobs, get_next_submodule, fetch_start_failure, diff --combined transport.c index 1c76d64aba,cb40a23d45..dd7bd3436c --- a/transport.c +++ b/transport.c @@@ -1139,7 -1139,8 +1139,8 @@@ int transport_push(struct transport *tr oid_array_append(&commits, &ref->new_oid); - if (!push_unpushed_submodules(&commits, + if (!push_unpushed_submodules(&the_index, + &commits, transport->remote, rs, transport->push_options, @@@ -1163,8 -1164,10 +1164,10 @@@ oid_array_append(&commits, &ref->new_oid); - if (find_unpushed_submodules(&commits, transport->remote->name, - &needs_pushing)) { + if (find_unpushed_submodules(&the_index, + &commits, + transport->remote->name, + &needs_pushing)) { oid_array_clear(&commits); die_with_unpushed_submodules(&needs_pushing); } @@@ -1228,7 -1231,7 +1231,7 @@@ int transport_fetch_refs(struct transpo nr_refs++; if (rm->peer_ref && !is_null_oid(&rm->old_oid) && - !oidcmp(&rm->peer_ref->old_oid, &rm->old_oid)) + oideq(&rm->peer_ref->old_oid, &rm->old_oid)) continue; ALLOC_GROW(heads, nr_heads + 1, nr_alloc); heads[nr_heads++] = rm; diff --combined tree-diff.c index 425668e1e0,16b28ff6d6..0e54324610 --- a/tree-diff.c +++ b/tree-diff.c @@@ -491,7 -491,7 +491,7 @@@ static struct combine_diff_path *ll_dif continue; /* diff(t,pi) != ø */ - if (oidcmp(t.entry.oid, tp[i].entry.oid) || + if (!oideq(t.entry.oid, tp[i].entry.oid) || (t.entry.mode != tp[i].entry.mode)) continue; @@@ -605,7 -605,7 +605,7 @@@ static void try_to_follow_renames(cons choice = q->queue[0]; q->nr = 0; - diff_setup(&diff_opts); + repo_diff_setup(opt->repo, &diff_opts); diff_opts.flags.recursive = 1; diff_opts.flags.find_copies_harder = 1; diff_opts.output_format = DIFF_FORMAT_NO_OUTPUT; diff --combined userdiff.c index f565f6731d,c913232396..46d34cc2a4 --- a/userdiff.c +++ b/userdiff.c @@@ -270,7 -270,8 +270,8 @@@ struct userdiff_driver *userdiff_find_b return userdiff_find_by_namelen(name, len); } - struct userdiff_driver *userdiff_find_by_path(const char *path) + struct userdiff_driver *userdiff_find_by_path(struct index_state *istate, + const char *path) { static struct attr_check *check; @@@ -278,7 -279,8 +279,7 @@@ check = attr_check_initl("diff", NULL); if (!path) return NULL; - git_check_attr(&the_index, path, check); - if (git_check_attr(istate, path, check)) - return NULL; ++ git_check_attr(istate, path, check); if (ATTR_TRUE(check->items[0].value)) return &driver_true; diff --combined ws.c index a64ab51e09,55349b4c5d..6e69877f25 --- a/ws.c +++ b/ws.c @@@ -3,7 -3,6 +3,6 @@@ * * Copyright (c) 2007 Junio C Hamano */ - #include "cache.h" #include "attr.h" @@@ -71,34 -70,38 +70,34 @@@ unsigned parse_whitespace_rule(const ch return rule; } - unsigned whitespace_rule(const char *pathname) + unsigned whitespace_rule(struct index_state *istate, const char *pathname) { static struct attr_check *attr_whitespace_rule; + const char *value; if (!attr_whitespace_rule) attr_whitespace_rule = attr_check_initl("whitespace", NULL); - git_check_attr(&the_index, pathname, attr_whitespace_rule); - if (!git_check_attr(istate, pathname, attr_whitespace_rule)) { - const char *value; - - value = attr_whitespace_rule->items[0].value; - if (ATTR_TRUE(value)) { - /* true (whitespace) */ - unsigned all_rule = ws_tab_width(whitespace_rule_cfg); - int i; - for (i = 0; i < ARRAY_SIZE(whitespace_rule_names); i++) - if (!whitespace_rule_names[i].loosens_error && - !whitespace_rule_names[i].exclude_default) - all_rule |= whitespace_rule_names[i].rule_bits; - return all_rule; - } else if (ATTR_FALSE(value)) { - /* false (-whitespace) */ - return ws_tab_width(whitespace_rule_cfg); - } else if (ATTR_UNSET(value)) { - /* reset to default (!whitespace) */ - return whitespace_rule_cfg; - } else { - /* string */ - return parse_whitespace_rule(value); - } - } else { ++ git_check_attr(istate, pathname, attr_whitespace_rule); + value = attr_whitespace_rule->items[0].value; + if (ATTR_TRUE(value)) { + /* true (whitespace) */ + unsigned all_rule = ws_tab_width(whitespace_rule_cfg); + int i; + for (i = 0; i < ARRAY_SIZE(whitespace_rule_names); i++) + if (!whitespace_rule_names[i].loosens_error && + !whitespace_rule_names[i].exclude_default) + all_rule |= whitespace_rule_names[i].rule_bits; + return all_rule; + } else if (ATTR_FALSE(value)) { + /* false (-whitespace) */ + return ws_tab_width(whitespace_rule_cfg); + } else if (ATTR_UNSET(value)) { + /* reset to default (!whitespace) */ return whitespace_rule_cfg; + } else { + /* string */ + return parse_whitespace_rule(value); } } diff --combined wt-status.c index 1c8746d0ea,2f743941d5..87042d4568 --- a/wt-status.c +++ b/wt-status.c @@@ -453,8 -453,8 +453,8 @@@ static void wt_status_collect_changed_c d->worktree_status = p->status; if (S_ISGITLINK(p->two->mode)) { d->dirty_submodule = p->two->dirty_submodule; - d->new_submodule_commits = !!oidcmp(&p->one->oid, - &p->two->oid); + d->new_submodule_commits = !oideq(&p->one->oid, + &p->two->oid); if (s->status_format == STATUS_FORMAT_SHORT) d->worktree_status = short_submodule_status(d); } @@@ -582,7 -582,7 +582,7 @@@ static void wt_status_collect_changes_w { struct rev_info rev; - init_revisions(&rev, NULL); + repo_init_revisions(the_repository, &rev, NULL); setup_revisions(0, NULL, &rev, NULL); rev.diffopt.output_format |= DIFF_FORMAT_CALLBACK; rev.diffopt.flags.dirty_submodules = 1; @@@ -607,7 -607,7 +607,7 @@@ static void wt_status_collect_changes_i struct rev_info rev; struct setup_revision_opt opt; - init_revisions(&rev, NULL); + repo_init_revisions(the_repository, &rev, NULL); memset(&opt, 0, sizeof(opt)); opt.def = s->is_initial ? empty_tree_oid_hex() : s->reference; setup_revisions(0, NULL, &rev, &opt); @@@ -982,7 -982,7 +982,7 @@@ static void wt_longstatus_print_verbose int dirty_submodules; const char *c = color(WT_STATUS_HEADER, s); - init_revisions(&rev, NULL); + repo_init_revisions(the_repository, &rev, NULL); rev.diffopt.flags.allow_textconv = 1; rev.diffopt.ita_invisible_in_index = 1; @@@ -1487,10 -1487,10 +1487,10 @@@ static void wt_status_get_detached_from if (dwim_ref(cb.buf.buf, cb.buf.len, &oid, &ref) == 1 && /* sha1 is a commit? match without further lookup */ - (!oidcmp(&cb.noid, &oid) || + (oideq(&cb.noid, &oid) || /* perhaps sha1 is a tag, try to dereference to a commit */ ((commit = lookup_commit_reference_gently(the_repository, &oid, 1)) != NULL && - !oidcmp(&cb.noid, &commit->object.oid)))) { + oideq(&cb.noid, &commit->object.oid)))) { const char *from = ref; if (!skip_prefix(from, "refs/tags/", &from)) skip_prefix(from, "refs/remotes/", &from); @@@ -1500,7 -1500,7 +1500,7 @@@ xstrdup(find_unique_abbrev(&cb.noid, DEFAULT_ABBREV)); oidcpy(&state->detached_oid, &cb.noid); state->detached_at = !get_oid("HEAD", &oid) && - !oidcmp(&oid, &state->detached_oid); + oideq(&oid, &state->detached_oid); free(ref); strbuf_release(&cb.buf); @@@ -2314,7 -2314,7 +2314,7 @@@ int has_unstaged_changes(int ignore_sub struct rev_info rev_info; int result; - init_revisions(&rev_info, NULL); + repo_init_revisions(the_repository, &rev_info, NULL); if (ignore_submodules) { rev_info.diffopt.flags.ignore_submodules = 1; rev_info.diffopt.flags.override_submodule_config = 1; @@@ -2336,7 -2336,7 +2336,7 @@@ int has_uncommitted_changes(int ignore_ if (is_cache_unborn()) return 0; - init_revisions(&rev_info, NULL); + repo_init_revisions(the_repository, &rev_info, NULL); if (ignore_submodules) rev_info.diffopt.flags.ignore_submodules = 1; rev_info.diffopt.flags.quick = 1;