]> git.ipfire.org Git - thirdparty/git.git/commitdiff
Merge branches 'bw/ls-files-sans-the-index' and 'bw/config-h' into bw/repo-object
authorJunio C Hamano <gitster@pobox.com>
Wed, 21 Jun 2017 22:20:44 +0000 (15:20 -0700)
committerJunio C Hamano <gitster@pobox.com>
Sat, 24 Jun 2017 01:24:00 +0000 (18:24 -0700)
* bw/ls-files-sans-the-index:
  ls-files: factor out tag calculation
  ls-files: factor out debug info into a function
  ls-files: convert show_files to take an index
  ls-files: convert show_ce_entry to take an index
  ls-files: convert prune_cache to take an index
  ls-files: convert ce_excluded to take an index
  ls-files: convert show_ru_info to take an index
  ls-files: convert show_other_files to take an index
  ls-files: convert show_killed_files to take an index
  ls-files: convert write_eolinfo to take an index
  ls-files: convert overlay_tree_on_cache to take an index
  tree: convert read_tree to take an index parameter
  convert: convert renormalize_buffer to take an index
  convert: convert convert_to_git to take an index
  convert: convert convert_to_git_filter_fd to take an index
  convert: convert crlf_to_git to take an index
  convert: convert get_cached_convert_stats_ascii to take an index

* bw/config-h:
  config: don't implicitly use gitdir or commondir
  config: respect commondir
  setup: teach discover_git_directory to respect the commondir
  config: don't include config.h by default
  config: remove git_config_iter
  config: create config.h
  alias: use the early config machinery to expand aliases
  t7006: demonstrate a problem with aliases in subdirectories
  t1308: relax the test verifying that empty alias values are disallowed
  help: use early config when autocorrecting aliases
  config: report correct line number upon error
  discover_git_directory(): avoid setting invalid git_dir

102 files changed:
1  2  3 
apply.c
archive-tar.c
archive-zip.c
archive.c
attr.c
bisect.c
blame.c
branch.c
builtin/add.c
builtin/am.c
builtin/blame.c
builtin/branch.c
builtin/cat-file.c
builtin/check-ignore.c
builtin/checkout.c
builtin/clean.c
builtin/clone.c
builtin/commit-tree.c
builtin/commit.c
builtin/config.c
builtin/describe.c
builtin/diff-files.c
builtin/diff-index.c
builtin/diff-tree.c
builtin/diff.c
builtin/difftool.c
builtin/fast-export.c
builtin/fetch.c
builtin/fmt-merge-msg.c
builtin/fsck.c
builtin/gc.c
builtin/grep.c
builtin/index-pack.c
builtin/log.c
builtin/ls-files.c
builtin/ls-tree.c
builtin/merge-base.c
builtin/merge.c
builtin/name-rev.c
builtin/notes.c
builtin/pack-objects.c
builtin/pull.c
builtin/push.c
builtin/read-tree.c
builtin/receive-pack.c
builtin/reflog.c
builtin/remote.c
builtin/repack.c
builtin/replace.c
builtin/reset.c
builtin/rev-list.c
builtin/rev-parse.c
builtin/rm.c
builtin/show-branch.c
builtin/submodule--helper.c
builtin/tag.c
builtin/unpack-objects.c
builtin/update-index.c
builtin/verify-commit.c
builtin/worktree.c
cache.h
combine-diff.c
config.c
connect.c
convert.c
credential-cache--daemon.c
diff.c
dir.c
environment.c
fast-import.c
fetch-pack.c
git.c
grep.c
help.c
http-backend.c
ident.c
ll-merge.c
log-tree.c
mailinfo.c
merge-recursive.c
notes-utils.c
notes.c
parse-options.c
pathspec.c
pretty.c
read-cache.c
refs.c
refs/files-backend.c
remote.c
rerere.c
sequencer.c
setup.c
sha1_file.c
sha1_name.c
submodule.c
t/t1300-repo-config.sh
t/t1308-config-set.sh
transport.c
unpack-trees.c
upload-pack.c
wrapper.c
xdiff-interface.c

diff --cc apply.c
Simple merge
diff --cc archive-tar.c
Simple merge
diff --cc archive-zip.c
Simple merge
diff --cc archive.c
Simple merge
diff --cc attr.c
Simple merge
diff --cc bisect.c
Simple merge
diff --cc blame.c
index 194b58e96066f9620005f64a57ca9ecc618c86f4,a6f3d72df8fbc45a14214029491d5c06a73cefa5,0000000000000000000000000000000000000000..6d57ab9715665a8bc6a2ba02015342ad851b6d2f
mode 100644,100644,000000..100644
--- /dev/null
+++ b/blame.c
@@@@ -1,1863 -1,1863 -1,0 +1,1863 @@@@
-       convert_to_git(path, buf.buf, buf.len, &buf, 0);
  +#include "cache.h"
  +#include "refs.h"
  +#include "cache-tree.h"
  +#include "mergesort.h"
  +#include "diff.h"
  +#include "diffcore.h"
  +#include "tag.h"
  +#include "blame.h"
  +
  +void blame_origin_decref(struct blame_origin *o)
  +{
  +     if (o && --o->refcnt <= 0) {
  +             struct blame_origin *p, *l = NULL;
  +             if (o->previous)
  +                     blame_origin_decref(o->previous);
  +             free(o->file.ptr);
  +             /* Should be present exactly once in commit chain */
  +             for (p = o->commit->util; p; l = p, p = p->next) {
  +                     if (p == o) {
  +                             if (l)
  +                                     l->next = p->next;
  +                             else
  +                                     o->commit->util = p->next;
  +                             free(o);
  +                             return;
  +                     }
  +             }
  +             die("internal error in blame_origin_decref");
  +     }
  +}
  +
  +/*
  + * Given a commit and a path in it, create a new origin structure.
  + * The callers that add blame to the scoreboard should use
  + * get_origin() to obtain shared, refcounted copy instead of calling
  + * this function directly.
  + */
  +static struct blame_origin *make_origin(struct commit *commit, const char *path)
  +{
  +     struct blame_origin *o;
  +     FLEX_ALLOC_STR(o, path, path);
  +     o->commit = commit;
  +     o->refcnt = 1;
  +     o->next = commit->util;
  +     commit->util = o;
  +     return o;
  +}
  +
  +/*
  + * Locate an existing origin or create a new one.
  + * This moves the origin to front position in the commit util list.
  + */
  +static struct blame_origin *get_origin(struct commit *commit, const char *path)
  +{
  +     struct blame_origin *o, *l;
  +
  +     for (o = commit->util, l = NULL; o; l = o, o = o->next) {
  +             if (!strcmp(o->path, path)) {
  +                     /* bump to front */
  +                     if (l) {
  +                             l->next = o->next;
  +                             o->next = commit->util;
  +                             commit->util = o;
  +                     }
  +                     return blame_origin_incref(o);
  +             }
  +     }
  +     return make_origin(commit, path);
  +}
  +
  +
  +
  +static void verify_working_tree_path(struct commit *work_tree, const char *path)
  +{
  +     struct commit_list *parents;
  +     int pos;
  +
  +     for (parents = work_tree->parents; parents; parents = parents->next) {
  +             const struct object_id *commit_oid = &parents->item->object.oid;
  +             struct object_id blob_oid;
  +             unsigned mode;
  +
  +             if (!get_tree_entry(commit_oid->hash, path, blob_oid.hash, &mode) &&
  +                 sha1_object_info(blob_oid.hash, NULL) == OBJ_BLOB)
  +                     return;
  +     }
  +
  +     pos = cache_name_pos(path, strlen(path));
  +     if (pos >= 0)
  +             ; /* path is in the index */
  +     else if (-1 - pos < active_nr &&
  +              !strcmp(active_cache[-1 - pos]->name, path))
  +             ; /* path is in the index, unmerged */
  +     else
  +             die("no such path '%s' in HEAD", path);
  +}
  +
  +static struct commit_list **append_parent(struct commit_list **tail, const struct object_id *oid)
  +{
  +     struct commit *parent;
  +
  +     parent = lookup_commit_reference(oid);
  +     if (!parent)
  +             die("no such commit %s", oid_to_hex(oid));
  +     return &commit_list_insert(parent, tail)->next;
  +}
  +
  +static void append_merge_parents(struct commit_list **tail)
  +{
  +     int merge_head;
  +     struct strbuf line = STRBUF_INIT;
  +
  +     merge_head = open(git_path_merge_head(), O_RDONLY);
  +     if (merge_head < 0) {
  +             if (errno == ENOENT)
  +                     return;
  +             die("cannot open '%s' for reading", git_path_merge_head());
  +     }
  +
  +     while (!strbuf_getwholeline_fd(&line, merge_head, '\n')) {
  +             struct object_id oid;
  +             if (line.len < GIT_SHA1_HEXSZ || get_oid_hex(line.buf, &oid))
  +                     die("unknown line in '%s': %s", git_path_merge_head(), line.buf);
  +             tail = append_parent(tail, &oid);
  +     }
  +     close(merge_head);
  +     strbuf_release(&line);
  +}
  +
  +/*
  + * This isn't as simple as passing sb->buf and sb->len, because we
  + * want to transfer ownership of the buffer to the commit (so we
  + * must use detach).
  + */
  +static void set_commit_buffer_from_strbuf(struct commit *c, struct strbuf *sb)
  +{
  +     size_t len;
  +     void *buf = strbuf_detach(sb, &len);
  +     set_commit_buffer(c, buf, len);
  +}
  +
  +/*
  + * 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 diff_options *opt,
  +                                            const char *path,
  +                                            const char *contents_from)
  +{
  +     struct commit *commit;
  +     struct blame_origin *origin;
  +     struct commit_list **parent_tail, *parent;
  +     struct object_id head_oid;
  +     struct strbuf buf = STRBUF_INIT;
  +     const char *ident;
  +     time_t now;
  +     int size, len;
  +     struct cache_entry *ce;
  +     unsigned mode;
  +     struct strbuf msg = STRBUF_INIT;
  +
  +     read_cache();
  +     time(&now);
  +     commit = alloc_commit_node();
  +     commit->object.parsed = 1;
  +     commit->date = now;
  +     parent_tail = &commit->parents;
  +
  +     if (!resolve_ref_unsafe("HEAD", RESOLVE_REF_READING, head_oid.hash, NULL))
  +             die("no such ref: HEAD");
  +
  +     parent_tail = append_parent(parent_tail, &head_oid);
  +     append_merge_parents(parent_tail);
  +     verify_working_tree_path(commit, path);
  +
  +     origin = make_origin(commit, path);
  +
  +     ident = fmt_ident("Not Committed Yet", "not.committed.yet", NULL, 0);
  +     strbuf_addstr(&msg, "tree 0000000000000000000000000000000000000000\n");
  +     for (parent = commit->parents; parent; parent = parent->next)
  +             strbuf_addf(&msg, "parent %s\n",
  +                         oid_to_hex(&parent->item->object.oid));
  +     strbuf_addf(&msg,
  +                 "author %s\n"
  +                 "committer %s\n\n"
  +                 "Version of %s from %s\n",
  +                 ident, ident, path,
  +                 (!contents_from ? path :
  +                  (!strcmp(contents_from, "-") ? "standard input" : contents_from)));
  +     set_commit_buffer_from_strbuf(commit, &msg);
  +
  +     if (!contents_from || strcmp("-", contents_from)) {
  +             struct stat st;
  +             const char *read_from;
  +             char *buf_ptr;
  +             unsigned long buf_len;
  +
  +             if (contents_from) {
  +                     if (stat(contents_from, &st) < 0)
  +                             die_errno("Cannot stat '%s'", contents_from);
  +                     read_from = contents_from;
  +             }
  +             else {
  +                     if (lstat(path, &st) < 0)
  +                             die_errno("Cannot lstat '%s'", path);
  +                     read_from = path;
  +             }
  +             mode = canon_mode(st.st_mode);
  +
  +             switch (st.st_mode & S_IFMT) {
  +             case S_IFREG:
  +                     if (DIFF_OPT_TST(opt, ALLOW_TEXTCONV) &&
  +                         textconv_object(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);
  +                     break;
  +             case S_IFLNK:
  +                     if (strbuf_readlink(&buf, read_from, st.st_size) < 0)
  +                             die_errno("cannot readlink '%s'", read_from);
  +                     break;
  +             default:
  +                     die("unsupported file type %s", read_from);
  +             }
  +     }
  +     else {
  +             /* Reading from stdin */
  +             mode = 0;
  +             if (strbuf_read(&buf, 0, 0) < 0)
  +                     die_errno("failed to read from stdin");
  +     }
 -              diff_tree_sha1(parent->tree->object.oid.hash,
 -                             origin->commit->tree->object.oid.hash,
 -                             "", &diff_opts);
+ +     convert_to_git(&the_index, path, buf.buf, buf.len, &buf, 0);
  +     origin->file.ptr = buf.buf;
  +     origin->file.size = buf.len;
  +     pretend_sha1_file(buf.buf, buf.len, OBJ_BLOB, origin->blob_oid.hash);
  +
  +     /*
  +      * Read the current index, replace the path entry with
  +      * origin->blob_sha1 without mucking with its mode or type
  +      * bits; we are not going to write this index out -- we just
  +      * want to run "diff-index --cached".
  +      */
  +     discard_cache();
  +     read_cache();
  +
  +     len = strlen(path);
  +     if (!mode) {
  +             int pos = cache_name_pos(path, len);
  +             if (0 <= pos)
  +                     mode = active_cache[pos]->ce_mode;
  +             else
  +                     /* Let's not bother reading from HEAD tree */
  +                     mode = S_IFREG | 0644;
  +     }
  +     size = cache_entry_size(len);
  +     ce = xcalloc(1, size);
  +     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_cache_entry(ce, ADD_CACHE_OK_TO_ADD|ADD_CACHE_OK_TO_REPLACE);
  +
  +     cache_tree_invalidate_path(&the_index, path);
  +
  +     return commit;
  +}
  +
  +
  +
  +static int diff_hunks(mmfile_t *file_a, mmfile_t *file_b,
  +                   xdl_emit_hunk_consume_func_t hunk_func, void *cb_data, int xdl_opts)
  +{
  +     xpparam_t xpp = {0};
  +     xdemitconf_t xecfg = {0};
  +     xdemitcb_t ecb = {NULL};
  +
  +     xpp.flags = xdl_opts;
  +     xecfg.hunk_func = hunk_func;
  +     ecb.priv = cb_data;
  +     return xdi_diff(file_a, file_b, &xpp, &xecfg, &ecb);
  +}
  +
  +/*
  + * Given an origin, prepare mmfile_t structure to be used by the
  + * diff machinery
  + */
  +static void fill_origin_blob(struct diff_options *opt,
  +                          struct blame_origin *o, mmfile_t *file, int *num_read_blob)
  +{
  +     if (!o->file.ptr) {
  +             enum object_type type;
  +             unsigned long file_size;
  +
  +             (*num_read_blob)++;
  +             if (DIFF_OPT_TST(opt, ALLOW_TEXTCONV) &&
  +                 textconv_object(o->path, o->mode, &o->blob_oid, 1, &file->ptr, &file_size))
  +                     ;
  +             else
  +                     file->ptr = read_sha1_file(o->blob_oid.hash, &type,
  +                                                &file_size);
  +             file->size = file_size;
  +
  +             if (!file->ptr)
  +                     die("Cannot read blob %s for path %s",
  +                         oid_to_hex(&o->blob_oid),
  +                         o->path);
  +             o->file = *file;
  +     }
  +     else
  +             *file = o->file;
  +}
  +
  +static void drop_origin_blob(struct blame_origin *o)
  +{
  +     if (o->file.ptr) {
  +             free(o->file.ptr);
  +             o->file.ptr = NULL;
  +     }
  +}
  +
  +/*
  + * Any merge of blames happens on lists of blames that arrived via
  + * different parents in a single suspect.  In this case, we want to
  + * sort according to the suspect line numbers as opposed to the final
  + * image line numbers.  The function body is somewhat longish because
  + * it avoids unnecessary writes.
  + */
  +
  +static struct blame_entry *blame_merge(struct blame_entry *list1,
  +                                    struct blame_entry *list2)
  +{
  +     struct blame_entry *p1 = list1, *p2 = list2,
  +             **tail = &list1;
  +
  +     if (!p1)
  +             return p2;
  +     if (!p2)
  +             return p1;
  +
  +     if (p1->s_lno <= p2->s_lno) {
  +             do {
  +                     tail = &p1->next;
  +                     if ((p1 = *tail) == NULL) {
  +                             *tail = p2;
  +                             return list1;
  +                     }
  +             } while (p1->s_lno <= p2->s_lno);
  +     }
  +     for (;;) {
  +             *tail = p2;
  +             do {
  +                     tail = &p2->next;
  +                     if ((p2 = *tail) == NULL)  {
  +                             *tail = p1;
  +                             return list1;
  +                     }
  +             } while (p1->s_lno > p2->s_lno);
  +             *tail = p1;
  +             do {
  +                     tail = &p1->next;
  +                     if ((p1 = *tail) == NULL) {
  +                             *tail = p2;
  +                             return list1;
  +                     }
  +             } while (p1->s_lno <= p2->s_lno);
  +     }
  +}
  +
  +static void *get_next_blame(const void *p)
  +{
  +     return ((struct blame_entry *)p)->next;
  +}
  +
  +static void set_next_blame(void *p1, void *p2)
  +{
  +     ((struct blame_entry *)p1)->next = p2;
  +}
  +
  +/*
  + * Final image line numbers are all different, so we don't need a
  + * three-way comparison here.
  + */
  +
  +static int compare_blame_final(const void *p1, const void *p2)
  +{
  +     return ((struct blame_entry *)p1)->lno > ((struct blame_entry *)p2)->lno
  +             ? 1 : -1;
  +}
  +
  +static int compare_blame_suspect(const void *p1, const void *p2)
  +{
  +     const struct blame_entry *s1 = p1, *s2 = p2;
  +     /*
  +      * to allow for collating suspects, we sort according to the
  +      * respective pointer value as the primary sorting criterion.
  +      * The actual relation is pretty unimportant as long as it
  +      * establishes a total order.  Comparing as integers gives us
  +      * that.
  +      */
  +     if (s1->suspect != s2->suspect)
  +             return (intptr_t)s1->suspect > (intptr_t)s2->suspect ? 1 : -1;
  +     if (s1->s_lno == s2->s_lno)
  +             return 0;
  +     return s1->s_lno > s2->s_lno ? 1 : -1;
  +}
  +
  +void blame_sort_final(struct blame_scoreboard *sb)
  +{
  +     sb->ent = llist_mergesort(sb->ent, get_next_blame, set_next_blame,
  +                               compare_blame_final);
  +}
  +
  +static int compare_commits_by_reverse_commit_date(const void *a,
  +                                               const void *b,
  +                                               void *c)
  +{
  +     return -compare_commits_by_commit_date(a, b, c);
  +}
  +
  +/*
  + * For debugging -- origin is refcounted, and this asserts that
  + * we do not underflow.
  + */
  +static void sanity_check_refcnt(struct blame_scoreboard *sb)
  +{
  +     int baa = 0;
  +     struct blame_entry *ent;
  +
  +     for (ent = sb->ent; ent; ent = ent->next) {
  +             /* Nobody should have zero or negative refcnt */
  +             if (ent->suspect->refcnt <= 0) {
  +                     fprintf(stderr, "%s in %s has negative refcnt %d\n",
  +                             ent->suspect->path,
  +                             oid_to_hex(&ent->suspect->commit->object.oid),
  +                             ent->suspect->refcnt);
  +                     baa = 1;
  +             }
  +     }
  +     if (baa)
  +             sb->on_sanity_fail(sb, baa);
  +}
  +
  +/*
  + * If two blame entries that are next to each other came from
  + * contiguous lines in the same origin (i.e. <commit, path> pair),
  + * merge them together.
  + */
  +void blame_coalesce(struct blame_scoreboard *sb)
  +{
  +     struct blame_entry *ent, *next;
  +
  +     for (ent = sb->ent; ent && (next = ent->next); ent = next) {
  +             if (ent->suspect == next->suspect &&
  +                 ent->s_lno + ent->num_lines == next->s_lno) {
  +                     ent->num_lines += next->num_lines;
  +                     ent->next = next->next;
  +                     blame_origin_decref(next->suspect);
  +                     free(next);
  +                     ent->score = 0;
  +                     next = ent; /* again */
  +             }
  +     }
  +
  +     if (sb->debug) /* sanity */
  +             sanity_check_refcnt(sb);
  +}
  +
  +/*
  + * Merge the given sorted list of blames into a preexisting origin.
  + * If there were no previous blames to that commit, it is entered into
  + * the commit priority queue of the score board.
  + */
  +
  +static void queue_blames(struct blame_scoreboard *sb, struct blame_origin *porigin,
  +                      struct blame_entry *sorted)
  +{
  +     if (porigin->suspects)
  +             porigin->suspects = blame_merge(porigin->suspects, sorted);
  +     else {
  +             struct blame_origin *o;
  +             for (o = porigin->commit->util; o; o = o->next) {
  +                     if (o->suspects) {
  +                             porigin->suspects = sorted;
  +                             return;
  +                     }
  +             }
  +             porigin->suspects = sorted;
  +             prio_queue_put(&sb->commits, porigin->commit);
  +     }
  +}
  +
  +/*
  + * Fill the blob_sha1 field of an origin if it hasn't, so that later
  + * call to fill_origin_blob() can use it to locate the data.  blob_sha1
  + * for an origin is also used to pass the blame for the entire file to
  + * the parent to detect the case where a child's blob is identical to
  + * that of its parent's.
  + *
  + * This also fills origin->mode for corresponding tree path.
  + */
  +static int fill_blob_sha1_and_mode(struct blame_origin *origin)
  +{
  +     if (!is_null_oid(&origin->blob_oid))
  +             return 0;
  +     if (get_tree_entry(origin->commit->object.oid.hash,
  +                        origin->path,
  +                        origin->blob_oid.hash, &origin->mode))
  +             goto error_out;
  +     if (sha1_object_info(origin->blob_oid.hash, NULL) != OBJ_BLOB)
  +             goto error_out;
  +     return 0;
  + error_out:
  +     oidclr(&origin->blob_oid);
  +     origin->mode = S_IFINVALID;
  +     return -1;
  +}
  +
  +/*
  + * 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)
  +{
  +     struct blame_origin *porigin;
  +     struct diff_options diff_opts;
  +     const char *paths[2];
  +
  +     /* First check any existing origins */
  +     for (porigin = parent->util; porigin; porigin = porigin->next)
  +             if (!strcmp(porigin->path, origin->path)) {
  +                     /*
  +                      * The same path between origin and its parent
  +                      * without renaming -- the most common case.
  +                      */
  +                     return blame_origin_incref (porigin);
  +             }
  +
  +     /* See if the origin->path is different between parent
  +      * and origin first.  Most of the time they are the
  +      * same and diff-tree is fairly efficient about this.
  +      */
  +     diff_setup(&diff_opts);
  +     DIFF_OPT_SET(&diff_opts, RECURSIVE);
  +     diff_opts.detect_rename = 0;
  +     diff_opts.output_format = DIFF_FORMAT_NO_OUTPUT;
  +     paths[0] = origin->path;
  +     paths[1] = NULL;
  +
  +     parse_pathspec(&diff_opts.pathspec,
  +                    PATHSPEC_ALL_MAGIC & ~PATHSPEC_LITERAL,
  +                    PATHSPEC_LITERAL_PATH, "", paths);
  +     diff_setup_done(&diff_opts);
  +
  +     if (is_null_oid(&origin->commit->object.oid))
  +             do_diff_cache(&parent->tree->object.oid, &diff_opts);
  +     else
 -              diff_tree_sha1(parent->tree->object.oid.hash,
 -                             origin->commit->tree->object.oid.hash,
 -                             "", &diff_opts);
 ++             diff_tree_oid(&parent->tree->object.oid,
 ++                           &origin->commit->tree->object.oid,
 ++                           "", &diff_opts);
  +     diffcore_std(&diff_opts);
  +
  +     if (!diff_queued_diff.nr) {
  +             /* The path is the same as parent */
  +             porigin = get_origin(parent, origin->path);
  +             oidcpy(&porigin->blob_oid, &origin->blob_oid);
  +             porigin->mode = origin->mode;
  +     } else {
  +             /*
  +              * Since origin->path is a pathspec, if the parent
  +              * commit had it as a directory, we will see a whole
  +              * bunch of deletion of files in the directory that we
  +              * do not care about.
  +              */
  +             int i;
  +             struct diff_filepair *p = NULL;
  +             for (i = 0; i < diff_queued_diff.nr; i++) {
  +                     const char *name;
  +                     p = diff_queued_diff.queue[i];
  +                     name = p->one->path ? p->one->path : p->two->path;
  +                     if (!strcmp(name, origin->path))
  +                             break;
  +             }
  +             if (!p)
  +                     die("internal error in blame::find_origin");
  +             switch (p->status) {
  +             default:
  +                     die("internal error in blame::find_origin (%c)",
  +                         p->status);
  +             case 'M':
  +                     porigin = get_origin(parent, origin->path);
  +                     oidcpy(&porigin->blob_oid, &p->one->oid);
  +                     porigin->mode = p->one->mode;
  +                     break;
  +             case 'A':
  +             case 'T':
  +                     /* Did not exist in parent, or type changed */
  +                     break;
  +             }
  +     }
  +     diff_flush(&diff_opts);
  +     clear_pathspec(&diff_opts.pathspec);
  +     return porigin;
  +}
  +
  +/*
  + * 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)
  +{
  +     struct blame_origin *porigin = NULL;
  +     struct diff_options diff_opts;
  +     int i;
  +
  +     diff_setup(&diff_opts);
  +     DIFF_OPT_SET(&diff_opts, RECURSIVE);
  +     diff_opts.detect_rename = DIFF_DETECT_RENAME;
  +     diff_opts.output_format = DIFF_FORMAT_NO_OUTPUT;
  +     diff_opts.single_follow = origin->path;
  +     diff_setup_done(&diff_opts);
  +
  +     if (is_null_oid(&origin->commit->object.oid))
  +             do_diff_cache(&parent->tree->object.oid, &diff_opts);
  +     else
 -       * force diff_tree_sha1() to feed all filepairs to diff_queue,
 ++             diff_tree_oid(&parent->tree->object.oid,
 ++                           &origin->commit->tree->object.oid,
 ++                           "", &diff_opts);
  +     diffcore_std(&diff_opts);
  +
  +     for (i = 0; i < diff_queued_diff.nr; i++) {
  +             struct diff_filepair *p = diff_queued_diff.queue[i];
  +             if ((p->status == 'R' || p->status == 'C') &&
  +                 !strcmp(p->two->path, origin->path)) {
  +                     porigin = get_origin(parent, p->one->path);
  +                     oidcpy(&porigin->blob_oid, &p->one->oid);
  +                     porigin->mode = p->one->mode;
  +                     break;
  +             }
  +     }
  +     diff_flush(&diff_opts);
  +     clear_pathspec(&diff_opts.pathspec);
  +     return porigin;
  +}
  +
  +/*
  + * Append a new blame entry to a given output queue.
  + */
  +static void add_blame_entry(struct blame_entry ***queue,
  +                         const struct blame_entry *src)
  +{
  +     struct blame_entry *e = xmalloc(sizeof(*e));
  +     memcpy(e, src, sizeof(*e));
  +     blame_origin_incref(e->suspect);
  +
  +     e->next = **queue;
  +     **queue = e;
  +     *queue = &e->next;
  +}
  +
  +/*
  + * src typically is on-stack; we want to copy the information in it to
  + * a malloced blame_entry that gets added to the given queue.  The
  + * origin of dst loses a refcnt.
  + */
  +static void dup_entry(struct blame_entry ***queue,
  +                   struct blame_entry *dst, struct blame_entry *src)
  +{
  +     blame_origin_incref(src->suspect);
  +     blame_origin_decref(dst->suspect);
  +     memcpy(dst, src, sizeof(*src));
  +     dst->next = **queue;
  +     **queue = dst;
  +     *queue = &dst->next;
  +}
  +
  +const char *blame_nth_line(struct blame_scoreboard *sb, long lno)
  +{
  +     return sb->final_buf + sb->lineno[lno];
  +}
  +
  +/*
  + * It is known that lines between tlno to same came from parent, and e
  + * has an overlap with that range.  it also is known that parent's
  + * line plno corresponds to e's line tlno.
  + *
  + *                <---- e ----->
  + *                   <------>
  + *                   <------------>
  + *             <------------>
  + *             <------------------>
  + *
  + * Split e into potentially three parts; before this chunk, the chunk
  + * to be blamed for the parent, and after that portion.
  + */
  +static void split_overlap(struct blame_entry *split,
  +                       struct blame_entry *e,
  +                       int tlno, int plno, int same,
  +                       struct blame_origin *parent)
  +{
  +     int chunk_end_lno;
  +     memset(split, 0, sizeof(struct blame_entry [3]));
  +
  +     if (e->s_lno < tlno) {
  +             /* there is a pre-chunk part not blamed on parent */
  +             split[0].suspect = blame_origin_incref(e->suspect);
  +             split[0].lno = e->lno;
  +             split[0].s_lno = e->s_lno;
  +             split[0].num_lines = tlno - e->s_lno;
  +             split[1].lno = e->lno + tlno - e->s_lno;
  +             split[1].s_lno = plno;
  +     }
  +     else {
  +             split[1].lno = e->lno;
  +             split[1].s_lno = plno + (e->s_lno - tlno);
  +     }
  +
  +     if (same < e->s_lno + e->num_lines) {
  +             /* there is a post-chunk part not blamed on parent */
  +             split[2].suspect = blame_origin_incref(e->suspect);
  +             split[2].lno = e->lno + (same - e->s_lno);
  +             split[2].s_lno = e->s_lno + (same - e->s_lno);
  +             split[2].num_lines = e->s_lno + e->num_lines - same;
  +             chunk_end_lno = split[2].lno;
  +     }
  +     else
  +             chunk_end_lno = e->lno + e->num_lines;
  +     split[1].num_lines = chunk_end_lno - split[1].lno;
  +
  +     /*
  +      * if it turns out there is nothing to blame the parent for,
  +      * forget about the splitting.  !split[1].suspect signals this.
  +      */
  +     if (split[1].num_lines < 1)
  +             return;
  +     split[1].suspect = blame_origin_incref(parent);
  +}
  +
  +/*
  + * split_overlap() divided an existing blame e into up to three parts
  + * in split.  Any assigned blame is moved to queue to
  + * reflect the split.
  + */
  +static void split_blame(struct blame_entry ***blamed,
  +                     struct blame_entry ***unblamed,
  +                     struct blame_entry *split,
  +                     struct blame_entry *e)
  +{
  +     if (split[0].suspect && split[2].suspect) {
  +             /* The first part (reuse storage for the existing entry e) */
  +             dup_entry(unblamed, e, &split[0]);
  +
  +             /* The last part -- me */
  +             add_blame_entry(unblamed, &split[2]);
  +
  +             /* ... and the middle part -- parent */
  +             add_blame_entry(blamed, &split[1]);
  +     }
  +     else if (!split[0].suspect && !split[2].suspect)
  +             /*
  +              * The parent covers the entire area; reuse storage for
  +              * e and replace it with the parent.
  +              */
  +             dup_entry(blamed, e, &split[1]);
  +     else if (split[0].suspect) {
  +             /* me and then parent */
  +             dup_entry(unblamed, e, &split[0]);
  +             add_blame_entry(blamed, &split[1]);
  +     }
  +     else {
  +             /* parent and then me */
  +             dup_entry(blamed, e, &split[1]);
  +             add_blame_entry(unblamed, &split[2]);
  +     }
  +}
  +
  +/*
  + * After splitting the blame, the origins used by the
  + * on-stack blame_entry should lose one refcnt each.
  + */
  +static void decref_split(struct blame_entry *split)
  +{
  +     int i;
  +
  +     for (i = 0; i < 3; i++)
  +             blame_origin_decref(split[i].suspect);
  +}
  +
  +/*
  + * reverse_blame reverses the list given in head, appending tail.
  + * That allows us to build lists in reverse order, then reverse them
  + * afterwards.  This can be faster than building the list in proper
  + * order right away.  The reason is that building in proper order
  + * requires writing a link in the _previous_ element, while building
  + * in reverse order just requires placing the list head into the
  + * _current_ element.
  + */
  +
  +static struct blame_entry *reverse_blame(struct blame_entry *head,
  +                                      struct blame_entry *tail)
  +{
  +     while (head) {
  +             struct blame_entry *next = head->next;
  +             head->next = tail;
  +             tail = head;
  +             head = next;
  +     }
  +     return tail;
  +}
  +
  +/*
  + * Process one hunk from the patch between the current suspect for
  + * blame_entry e and its parent.  This first blames any unfinished
  + * entries before the chunk (which is where target and parent start
  + * differing) on the parent, and then splits blame entries at the
  + * start and at the end of the difference region.  Since use of -M and
  + * -C options may lead to overlapping/duplicate source line number
  + * ranges, all we can rely on from sorting/merging is the order of the
  + * first suspect line number.
  + */
  +static void blame_chunk(struct blame_entry ***dstq, struct blame_entry ***srcq,
  +                     int tlno, int offset, int same,
  +                     struct blame_origin *parent)
  +{
  +     struct blame_entry *e = **srcq;
  +     struct blame_entry *samep = NULL, *diffp = NULL;
  +
  +     while (e && e->s_lno < tlno) {
  +             struct blame_entry *next = e->next;
  +             /*
  +              * current record starts before differing portion.  If
  +              * it reaches into it, we need to split it up and
  +              * examine the second part separately.
  +              */
  +             if (e->s_lno + e->num_lines > tlno) {
  +                     /* Move second half to a new record */
  +                     int len = tlno - e->s_lno;
  +                     struct blame_entry *n = xcalloc(1, sizeof (struct blame_entry));
  +                     n->suspect = e->suspect;
  +                     n->lno = e->lno + len;
  +                     n->s_lno = e->s_lno + len;
  +                     n->num_lines = e->num_lines - len;
  +                     e->num_lines = len;
  +                     e->score = 0;
  +                     /* Push new record to diffp */
  +                     n->next = diffp;
  +                     diffp = n;
  +             } else
  +                     blame_origin_decref(e->suspect);
  +             /* Pass blame for everything before the differing
  +              * chunk to the parent */
  +             e->suspect = blame_origin_incref(parent);
  +             e->s_lno += offset;
  +             e->next = samep;
  +             samep = e;
  +             e = next;
  +     }
  +     /*
  +      * As we don't know how much of a common stretch after this
  +      * diff will occur, the currently blamed parts are all that we
  +      * can assign to the parent for now.
  +      */
  +
  +     if (samep) {
  +             **dstq = reverse_blame(samep, **dstq);
  +             *dstq = &samep->next;
  +     }
  +     /*
  +      * Prepend the split off portions: everything after e starts
  +      * after the blameable portion.
  +      */
  +     e = reverse_blame(diffp, e);
  +
  +     /*
  +      * Now retain records on the target while parts are different
  +      * from the parent.
  +      */
  +     samep = NULL;
  +     diffp = NULL;
  +     while (e && e->s_lno < same) {
  +             struct blame_entry *next = e->next;
  +
  +             /*
  +              * If current record extends into sameness, need to split.
  +              */
  +             if (e->s_lno + e->num_lines > same) {
  +                     /*
  +                      * Move second half to a new record to be
  +                      * processed by later chunks
  +                      */
  +                     int len = same - e->s_lno;
  +                     struct blame_entry *n = xcalloc(1, sizeof (struct blame_entry));
  +                     n->suspect = blame_origin_incref(e->suspect);
  +                     n->lno = e->lno + len;
  +                     n->s_lno = e->s_lno + len;
  +                     n->num_lines = e->num_lines - len;
  +                     e->num_lines = len;
  +                     e->score = 0;
  +                     /* Push new record to samep */
  +                     n->next = samep;
  +                     samep = n;
  +             }
  +             e->next = diffp;
  +             diffp = e;
  +             e = next;
  +     }
  +     **srcq = reverse_blame(diffp, reverse_blame(samep, e));
  +     /* Move across elements that are in the unblamable portion */
  +     if (diffp)
  +             *srcq = &diffp->next;
  +}
  +
  +struct blame_chunk_cb_data {
  +     struct blame_origin *parent;
  +     long offset;
  +     struct blame_entry **dstq;
  +     struct blame_entry **srcq;
  +};
  +
  +/* diff chunks are from parent to target */
  +static int blame_chunk_cb(long start_a, long count_a,
  +                       long start_b, long count_b, void *data)
  +{
  +     struct blame_chunk_cb_data *d = data;
  +     if (start_a - start_b != d->offset)
  +             die("internal error in blame::blame_chunk_cb");
  +     blame_chunk(&d->dstq, &d->srcq, start_b, start_a - start_b,
  +                 start_b + count_b, d->parent);
  +     d->offset = start_a + count_a - (start_b + count_b);
  +     return 0;
  +}
  +
  +/*
  + * We are looking at the origin 'target' and aiming to pass blame
  + * for the lines it is suspected to its parent.  Run diff to find
  + * which lines came from parent and pass blame for them.
  + */
  +static void pass_blame_to_parent(struct blame_scoreboard *sb,
  +                              struct blame_origin *target,
  +                              struct blame_origin *parent)
  +{
  +     mmfile_t file_p, file_o;
  +     struct blame_chunk_cb_data d;
  +     struct blame_entry *newdest = NULL;
  +
  +     if (!target->suspects)
  +             return; /* nothing remains for this target */
  +
  +     d.parent = parent;
  +     d.offset = 0;
  +     d.dstq = &newdest; d.srcq = &target->suspects;
  +
  +     fill_origin_blob(&sb->revs->diffopt, parent, &file_p, &sb->num_read_blob);
  +     fill_origin_blob(&sb->revs->diffopt, target, &file_o, &sb->num_read_blob);
  +     sb->num_get_patch++;
  +
  +     if (diff_hunks(&file_p, &file_o, blame_chunk_cb, &d, sb->xdl_opts))
  +             die("unable to generate diff (%s -> %s)",
  +                 oid_to_hex(&parent->commit->object.oid),
  +                 oid_to_hex(&target->commit->object.oid));
  +     /* The rest are the same as the parent */
  +     blame_chunk(&d.dstq, &d.srcq, INT_MAX, d.offset, INT_MAX, parent);
  +     *d.dstq = NULL;
  +     queue_blames(sb, parent, newdest);
  +
  +     return;
  +}
  +
  +/*
  + * The lines in blame_entry after splitting blames many times can become
  + * very small and trivial, and at some point it becomes pointless to
  + * blame the parents.  E.g. "\t\t}\n\t}\n\n" appears everywhere in any
  + * ordinary C program, and it is not worth to say it was copied from
  + * totally unrelated file in the parent.
  + *
  + * Compute how trivial the lines in the blame_entry are.
  + */
  +unsigned blame_entry_score(struct blame_scoreboard *sb, struct blame_entry *e)
  +{
  +     unsigned score;
  +     const char *cp, *ep;
  +
  +     if (e->score)
  +             return e->score;
  +
  +     score = 1;
  +     cp = blame_nth_line(sb, e->lno);
  +     ep = blame_nth_line(sb, e->lno + e->num_lines);
  +     while (cp < ep) {
  +             unsigned ch = *((unsigned char *)cp);
  +             if (isalnum(ch))
  +                     score++;
  +             cp++;
  +     }
  +     e->score = score;
  +     return score;
  +}
  +
  +/*
  + * best_so_far[] and this[] are both a split of an existing blame_entry
  + * that passes blame to the parent.  Maintain best_so_far the best split
  + * so far, by comparing this and best_so_far and copying this into
  + * bst_so_far as needed.
  + */
  +static void copy_split_if_better(struct blame_scoreboard *sb,
  +                              struct blame_entry *best_so_far,
  +                              struct blame_entry *this)
  +{
  +     int i;
  +
  +     if (!this[1].suspect)
  +             return;
  +     if (best_so_far[1].suspect) {
  +             if (blame_entry_score(sb, &this[1]) < blame_entry_score(sb, &best_so_far[1]))
  +                     return;
  +     }
  +
  +     for (i = 0; i < 3; i++)
  +             blame_origin_incref(this[i].suspect);
  +     decref_split(best_so_far);
  +     memcpy(best_so_far, this, sizeof(struct blame_entry [3]));
  +}
  +
  +/*
  + * We are looking at a part of the final image represented by
  + * ent (tlno and same are offset by ent->s_lno).
  + * tlno is where we are looking at in the final image.
  + * up to (but not including) same match preimage.
  + * plno is where we are looking at in the preimage.
  + *
  + * <-------------- final image ---------------------->
  + *       <------ent------>
  + *         ^tlno ^same
  + *    <---------preimage----->
  + *         ^plno
  + *
  + * All line numbers are 0-based.
  + */
  +static void handle_split(struct blame_scoreboard *sb,
  +                      struct blame_entry *ent,
  +                      int tlno, int plno, int same,
  +                      struct blame_origin *parent,
  +                      struct blame_entry *split)
  +{
  +     if (ent->num_lines <= tlno)
  +             return;
  +     if (tlno < same) {
  +             struct blame_entry this[3];
  +             tlno += ent->s_lno;
  +             same += ent->s_lno;
  +             split_overlap(this, ent, tlno, plno, same, parent);
  +             copy_split_if_better(sb, split, this);
  +             decref_split(this);
  +     }
  +}
  +
  +struct handle_split_cb_data {
  +     struct blame_scoreboard *sb;
  +     struct blame_entry *ent;
  +     struct blame_origin *parent;
  +     struct blame_entry *split;
  +     long plno;
  +     long tlno;
  +};
  +
  +static int handle_split_cb(long start_a, long count_a,
  +                        long start_b, long count_b, void *data)
  +{
  +     struct handle_split_cb_data *d = data;
  +     handle_split(d->sb, d->ent, d->tlno, d->plno, start_b, d->parent,
  +                  d->split);
  +     d->plno = start_a + count_a;
  +     d->tlno = start_b + count_b;
  +     return 0;
  +}
  +
  +/*
  + * Find the lines from parent that are the same as ent so that
  + * we can pass blames to it.  file_p has the blob contents for
  + * the parent.
  + */
  +static void find_copy_in_blob(struct blame_scoreboard *sb,
  +                           struct blame_entry *ent,
  +                           struct blame_origin *parent,
  +                           struct blame_entry *split,
  +                           mmfile_t *file_p)
  +{
  +     const char *cp;
  +     mmfile_t file_o;
  +     struct handle_split_cb_data d;
  +
  +     memset(&d, 0, sizeof(d));
  +     d.sb = sb; d.ent = ent; d.parent = parent; d.split = split;
  +     /*
  +      * Prepare mmfile that contains only the lines in ent.
  +      */
  +     cp = blame_nth_line(sb, ent->lno);
  +     file_o.ptr = (char *) cp;
  +     file_o.size = blame_nth_line(sb, ent->lno + ent->num_lines) - cp;
  +
  +     /*
  +      * file_o is a part of final image we are annotating.
  +      * file_p partially may match that image.
  +      */
  +     memset(split, 0, sizeof(struct blame_entry [3]));
  +     if (diff_hunks(file_p, &file_o, handle_split_cb, &d, sb->xdl_opts))
  +             die("unable to generate diff (%s)",
  +                 oid_to_hex(&parent->commit->object.oid));
  +     /* remainder, if any, all match the preimage */
  +     handle_split(sb, ent, d.tlno, d.plno, ent->num_lines, parent, split);
  +}
  +
  +/* Move all blame entries from list *source that have a score smaller
  + * than score_min to the front of list *small.
  + * Returns a pointer to the link pointing to the old head of the small list.
  + */
  +
  +static struct blame_entry **filter_small(struct blame_scoreboard *sb,
  +                                      struct blame_entry **small,
  +                                      struct blame_entry **source,
  +                                      unsigned score_min)
  +{
  +     struct blame_entry *p = *source;
  +     struct blame_entry *oldsmall = *small;
  +     while (p) {
  +             if (blame_entry_score(sb, p) <= score_min) {
  +                     *small = p;
  +                     small = &p->next;
  +                     p = *small;
  +             } else {
  +                     *source = p;
  +                     source = &p->next;
  +                     p = *source;
  +             }
  +     }
  +     *small = oldsmall;
  +     *source = NULL;
  +     return small;
  +}
  +
  +/*
  + * See if lines currently target is suspected for can be attributed to
  + * parent.
  + */
  +static void find_move_in_parent(struct blame_scoreboard *sb,
  +                             struct blame_entry ***blamed,
  +                             struct blame_entry **toosmall,
  +                             struct blame_origin *target,
  +                             struct blame_origin *parent)
  +{
  +     struct blame_entry *e, split[3];
  +     struct blame_entry *unblamed = target->suspects;
  +     struct blame_entry *leftover = NULL;
  +     mmfile_t file_p;
  +
  +     if (!unblamed)
  +             return; /* nothing remains for this target */
  +
  +     fill_origin_blob(&sb->revs->diffopt, parent, &file_p, &sb->num_read_blob);
  +     if (!file_p.ptr)
  +             return;
  +
  +     /* At each iteration, unblamed has a NULL-terminated list of
  +      * entries that have not yet been tested for blame.  leftover
  +      * contains the reversed list of entries that have been tested
  +      * without being assignable to the parent.
  +      */
  +     do {
  +             struct blame_entry **unblamedtail = &unblamed;
  +             struct blame_entry *next;
  +             for (e = unblamed; e; e = next) {
  +                     next = e->next;
  +                     find_copy_in_blob(sb, e, parent, split, &file_p);
  +                     if (split[1].suspect &&
  +                         sb->move_score < blame_entry_score(sb, &split[1])) {
  +                             split_blame(blamed, &unblamedtail, split, e);
  +                     } else {
  +                             e->next = leftover;
  +                             leftover = e;
  +                     }
  +                     decref_split(split);
  +             }
  +             *unblamedtail = NULL;
  +             toosmall = filter_small(sb, toosmall, &unblamed, sb->move_score);
  +     } while (unblamed);
  +     target->suspects = reverse_blame(leftover, NULL);
  +}
  +
  +struct blame_list {
  +     struct blame_entry *ent;
  +     struct blame_entry split[3];
  +};
  +
  +/*
  + * Count the number of entries the target is suspected for,
  + * and prepare a list of entry and the best split.
  + */
  +static struct blame_list *setup_blame_list(struct blame_entry *unblamed,
  +                                        int *num_ents_p)
  +{
  +     struct blame_entry *e;
  +     int num_ents, i;
  +     struct blame_list *blame_list = NULL;
  +
  +     for (e = unblamed, num_ents = 0; e; e = e->next)
  +             num_ents++;
  +     if (num_ents) {
  +             blame_list = xcalloc(num_ents, sizeof(struct blame_list));
  +             for (e = unblamed, i = 0; e; e = e->next)
  +                     blame_list[i++].ent = e;
  +     }
  +     *num_ents_p = num_ents;
  +     return blame_list;
  +}
  +
  +/*
  + * For lines target is suspected for, see if we can find code movement
  + * across file boundary from the parent commit.  porigin is the path
  + * in the parent we already tried.
  + */
  +static void find_copy_in_parent(struct blame_scoreboard *sb,
  +                             struct blame_entry ***blamed,
  +                             struct blame_entry **toosmall,
  +                             struct blame_origin *target,
  +                             struct commit *parent,
  +                             struct blame_origin *porigin,
  +                             int opt)
  +{
  +     struct diff_options diff_opts;
  +     int i, j;
  +     struct blame_list *blame_list;
  +     int num_ents;
  +     struct blame_entry *unblamed = target->suspects;
  +     struct blame_entry *leftover = NULL;
  +
  +     if (!unblamed)
  +             return; /* nothing remains for this target */
  +
  +     diff_setup(&diff_opts);
  +     DIFF_OPT_SET(&diff_opts, RECURSIVE);
  +     diff_opts.output_format = DIFF_FORMAT_NO_OUTPUT;
  +
  +     diff_setup_done(&diff_opts);
  +
  +     /* Try "find copies harder" on new path if requested;
  +      * we do not want to use diffcore_rename() actually to
  +      * match things up; find_copies_harder is set only to
 -              diff_tree_sha1(parent->tree->object.oid.hash,
 -                             target->commit->tree->object.oid.hash,
 -                             "", &diff_opts);
 ++      * force diff_tree_oid() to feed all filepairs to diff_queue,
  +      * and this code needs to be after diff_setup_done(), which
  +      * usually makes find-copies-harder imply copy detection.
  +      */
  +     if ((opt & PICKAXE_BLAME_COPY_HARDEST)
  +         || ((opt & PICKAXE_BLAME_COPY_HARDER)
  +             && (!porigin || strcmp(target->path, porigin->path))))
  +             DIFF_OPT_SET(&diff_opts, FIND_COPIES_HARDER);
  +
  +     if (is_null_oid(&target->commit->object.oid))
  +             do_diff_cache(&parent->tree->object.oid, &diff_opts);
  +     else
 ++             diff_tree_oid(&parent->tree->object.oid,
 ++                           &target->commit->tree->object.oid,
 ++                           "", &diff_opts);
  +
  +     if (!DIFF_OPT_TST(&diff_opts, FIND_COPIES_HARDER))
  +             diffcore_std(&diff_opts);
  +
  +     do {
  +             struct blame_entry **unblamedtail = &unblamed;
  +             blame_list = setup_blame_list(unblamed, &num_ents);
  +
  +             for (i = 0; i < diff_queued_diff.nr; i++) {
  +                     struct diff_filepair *p = diff_queued_diff.queue[i];
  +                     struct blame_origin *norigin;
  +                     mmfile_t file_p;
  +                     struct blame_entry this[3];
  +
  +                     if (!DIFF_FILE_VALID(p->one))
  +                             continue; /* does not exist in parent */
  +                     if (S_ISGITLINK(p->one->mode))
  +                             continue; /* ignore git links */
  +                     if (porigin && !strcmp(p->one->path, porigin->path))
  +                             /* find_move already dealt with this path */
  +                             continue;
  +
  +                     norigin = get_origin(parent, p->one->path);
  +                     oidcpy(&norigin->blob_oid, &p->one->oid);
  +                     norigin->mode = p->one->mode;
  +                     fill_origin_blob(&sb->revs->diffopt, norigin, &file_p, &sb->num_read_blob);
  +                     if (!file_p.ptr)
  +                             continue;
  +
  +                     for (j = 0; j < num_ents; j++) {
  +                             find_copy_in_blob(sb, blame_list[j].ent,
  +                                               norigin, this, &file_p);
  +                             copy_split_if_better(sb, blame_list[j].split,
  +                                                  this);
  +                             decref_split(this);
  +                     }
  +                     blame_origin_decref(norigin);
  +             }
  +
  +             for (j = 0; j < num_ents; j++) {
  +                     struct blame_entry *split = blame_list[j].split;
  +                     if (split[1].suspect &&
  +                         sb->copy_score < blame_entry_score(sb, &split[1])) {
  +                             split_blame(blamed, &unblamedtail, split,
  +                                         blame_list[j].ent);
  +                     } else {
  +                             blame_list[j].ent->next = leftover;
  +                             leftover = blame_list[j].ent;
  +                     }
  +                     decref_split(split);
  +             }
  +             free(blame_list);
  +             *unblamedtail = NULL;
  +             toosmall = filter_small(sb, toosmall, &unblamed, sb->copy_score);
  +     } while (unblamed);
  +     target->suspects = reverse_blame(leftover, NULL);
  +     diff_flush(&diff_opts);
  +     clear_pathspec(&diff_opts.pathspec);
  +}
  +
  +/*
  + * The blobs of origin and porigin exactly match, so everything
  + * origin is suspected for can be blamed on the parent.
  + */
  +static void pass_whole_blame(struct blame_scoreboard *sb,
  +                          struct blame_origin *origin, struct blame_origin *porigin)
  +{
  +     struct blame_entry *e, *suspects;
  +
  +     if (!porigin->file.ptr && origin->file.ptr) {
  +             /* Steal its file */
  +             porigin->file = origin->file;
  +             origin->file.ptr = NULL;
  +     }
  +     suspects = origin->suspects;
  +     origin->suspects = NULL;
  +     for (e = suspects; e; e = e->next) {
  +             blame_origin_incref(porigin);
  +             blame_origin_decref(e->suspect);
  +             e->suspect = porigin;
  +     }
  +     queue_blames(sb, porigin, suspects);
  +}
  +
  +/*
  + * We pass blame from the current commit to its parents.  We keep saying
  + * "parent" (and "porigin"), but what we mean is to find scapegoat to
  + * exonerate ourselves.
  + */
  +static struct commit_list *first_scapegoat(struct rev_info *revs, struct commit *commit,
  +                                     int reverse)
  +{
  +     if (!reverse) {
  +             if (revs->first_parent_only &&
  +                 commit->parents &&
  +                 commit->parents->next) {
  +                     free_commit_list(commit->parents->next);
  +                     commit->parents->next = NULL;
  +             }
  +             return commit->parents;
  +     }
  +     return lookup_decoration(&revs->children, &commit->object);
  +}
  +
  +static int num_scapegoats(struct rev_info *revs, struct commit *commit, int reverse)
  +{
  +     struct commit_list *l = first_scapegoat(revs, commit, reverse);
  +     return commit_list_count(l);
  +}
  +
  +/* Distribute collected unsorted blames to the respected sorted lists
  + * in the various origins.
  + */
  +static void distribute_blame(struct blame_scoreboard *sb, struct blame_entry *blamed)
  +{
  +     blamed = llist_mergesort(blamed, get_next_blame, set_next_blame,
  +                              compare_blame_suspect);
  +     while (blamed)
  +     {
  +             struct blame_origin *porigin = blamed->suspect;
  +             struct blame_entry *suspects = NULL;
  +             do {
  +                     struct blame_entry *next = blamed->next;
  +                     blamed->next = suspects;
  +                     suspects = blamed;
  +                     blamed = next;
  +             } while (blamed && blamed->suspect == porigin);
  +             suspects = reverse_blame(suspects, NULL);
  +             queue_blames(sb, porigin, suspects);
  +     }
  +}
  +
  +#define MAXSG 16
  +
  +static void pass_blame(struct blame_scoreboard *sb, struct blame_origin *origin, int opt)
  +{
  +     struct rev_info *revs = sb->revs;
  +     int i, pass, num_sg;
  +     struct commit *commit = origin->commit;
  +     struct commit_list *sg;
  +     struct blame_origin *sg_buf[MAXSG];
  +     struct blame_origin *porigin, **sg_origin = sg_buf;
  +     struct blame_entry *toosmall = NULL;
  +     struct blame_entry *blames, **blametail = &blames;
  +
  +     num_sg = num_scapegoats(revs, commit, sb->reverse);
  +     if (!num_sg)
  +             goto finish;
  +     else if (num_sg < ARRAY_SIZE(sg_buf))
  +             memset(sg_buf, 0, sizeof(sg_buf));
  +     else
  +             sg_origin = xcalloc(num_sg, sizeof(*sg_origin));
  +
  +     /*
  +      * The first pass looks for unrenamed path to optimize for
  +      * 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 *);
  +             find = pass ? find_rename : find_origin;
  +
  +             for (i = 0, sg = first_scapegoat(revs, commit, sb->reverse);
  +                  i < num_sg && sg;
  +                  sg = sg->next, i++) {
  +                     struct commit *p = sg->item;
  +                     int j, same;
  +
  +                     if (sg_origin[i])
  +                             continue;
  +                     if (parse_commit(p))
  +                             continue;
  +                     porigin = find(p, origin);
  +                     if (!porigin)
  +                             continue;
  +                     if (!oidcmp(&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)) {
  +                                     same = 1;
  +                                     break;
  +                             }
  +                     if (!same)
  +                             sg_origin[i] = porigin;
  +                     else
  +                             blame_origin_decref(porigin);
  +             }
  +     }
  +
  +     sb->num_commits++;
  +     for (i = 0, sg = first_scapegoat(revs, commit, sb->reverse);
  +          i < num_sg && sg;
  +          sg = sg->next, i++) {
  +             struct blame_origin *porigin = sg_origin[i];
  +             if (!porigin)
  +                     continue;
  +             if (!origin->previous) {
  +                     blame_origin_incref(porigin);
  +                     origin->previous = porigin;
  +             }
  +             pass_blame_to_parent(sb, origin, porigin);
  +             if (!origin->suspects)
  +                     goto finish;
  +     }
  +
  +     /*
  +      * Optionally find moves in parents' files.
  +      */
  +     if (opt & PICKAXE_BLAME_MOVE) {
  +             filter_small(sb, &toosmall, &origin->suspects, sb->move_score);
  +             if (origin->suspects) {
  +                     for (i = 0, sg = first_scapegoat(revs, commit, sb->reverse);
  +                          i < num_sg && sg;
  +                          sg = sg->next, i++) {
  +                             struct blame_origin *porigin = sg_origin[i];
  +                             if (!porigin)
  +                                     continue;
  +                             find_move_in_parent(sb, &blametail, &toosmall, origin, porigin);
  +                             if (!origin->suspects)
  +                                     break;
  +                     }
  +             }
  +     }
  +
  +     /*
  +      * Optionally find copies from parents' files.
  +      */
  +     if (opt & PICKAXE_BLAME_COPY) {
  +             if (sb->copy_score > sb->move_score)
  +                     filter_small(sb, &toosmall, &origin->suspects, sb->copy_score);
  +             else if (sb->copy_score < sb->move_score) {
  +                     origin->suspects = blame_merge(origin->suspects, toosmall);
  +                     toosmall = NULL;
  +                     filter_small(sb, &toosmall, &origin->suspects, sb->copy_score);
  +             }
  +             if (!origin->suspects)
  +                     goto finish;
  +
  +             for (i = 0, sg = first_scapegoat(revs, commit, sb->reverse);
  +                  i < num_sg && sg;
  +                  sg = sg->next, i++) {
  +                     struct blame_origin *porigin = sg_origin[i];
  +                     find_copy_in_parent(sb, &blametail, &toosmall,
  +                                         origin, sg->item, porigin, opt);
  +                     if (!origin->suspects)
  +                             goto finish;
  +             }
  +     }
  +
  +finish:
  +     *blametail = NULL;
  +     distribute_blame(sb, blames);
  +     /*
  +      * prepend toosmall to origin->suspects
  +      *
  +      * There is no point in sorting: this ends up on a big
  +      * unsorted list in the caller anyway.
  +      */
  +     if (toosmall) {
  +             struct blame_entry **tail = &toosmall;
  +             while (*tail)
  +                     tail = &(*tail)->next;
  +             *tail = origin->suspects;
  +             origin->suspects = toosmall;
  +     }
  +     for (i = 0; i < num_sg; i++) {
  +             if (sg_origin[i]) {
  +                     drop_origin_blob(sg_origin[i]);
  +                     blame_origin_decref(sg_origin[i]);
  +             }
  +     }
  +     drop_origin_blob(origin);
  +     if (sg_buf != sg_origin)
  +             free(sg_origin);
  +}
  +
  +/*
  + * The main loop -- while we have blobs with lines whose true origin
  + * is still unknown, pick one blob, and allow its lines to pass blames
  + * to its parents. */
  +void assign_blame(struct blame_scoreboard *sb, int opt)
  +{
  +     struct rev_info *revs = sb->revs;
  +     struct commit *commit = prio_queue_get(&sb->commits);
  +
  +     while (commit) {
  +             struct blame_entry *ent;
  +             struct blame_origin *suspect = commit->util;
  +
  +             /* find one suspect to break down */
  +             while (suspect && !suspect->suspects)
  +                     suspect = suspect->next;
  +
  +             if (!suspect) {
  +                     commit = prio_queue_get(&sb->commits);
  +                     continue;
  +             }
  +
  +             assert(commit == suspect->commit);
  +
  +             /*
  +              * We will use this suspect later in the loop,
  +              * so hold onto it in the meantime.
  +              */
  +             blame_origin_incref(suspect);
  +             parse_commit(commit);
  +             if (sb->reverse ||
  +                 (!(commit->object.flags & UNINTERESTING) &&
  +                  !(revs->max_age != -1 && commit->date < revs->max_age)))
  +                     pass_blame(sb, suspect, opt);
  +             else {
  +                     commit->object.flags |= UNINTERESTING;
  +                     if (commit->object.parsed)
  +                             mark_parents_uninteresting(commit);
  +             }
  +             /* treat root commit as boundary */
  +             if (!commit->parents && !sb->show_root)
  +                     commit->object.flags |= UNINTERESTING;
  +
  +             /* Take responsibility for the remaining entries */
  +             ent = suspect->suspects;
  +             if (ent) {
  +                     suspect->guilty = 1;
  +                     for (;;) {
  +                             struct blame_entry *next = ent->next;
  +                             if (sb->found_guilty_entry)
  +                                     sb->found_guilty_entry(ent, sb->found_guilty_entry_data);
  +                             if (next) {
  +                                     ent = next;
  +                                     continue;
  +                             }
  +                             ent->next = sb->ent;
  +                             sb->ent = suspect->suspects;
  +                             suspect->suspects = NULL;
  +                             break;
  +                     }
  +             }
  +             blame_origin_decref(suspect);
  +
  +             if (sb->debug) /* sanity */
  +                     sanity_check_refcnt(sb);
  +     }
  +}
  +
  +static const char *get_next_line(const char *start, const char *end)
  +{
  +     const char *nl = memchr(start, '\n', end - start);
  +     return nl ? nl + 1 : end;
  +}
  +
  +/*
  + * To allow quick access to the contents of nth line in the
  + * final image, prepare an index in the scoreboard.
  + */
  +static int prepare_lines(struct blame_scoreboard *sb)
  +{
  +     const char *buf = sb->final_buf;
  +     unsigned long len = sb->final_buf_size;
  +     const char *end = buf + len;
  +     const char *p;
  +     int *lineno;
  +     int num = 0;
  +
  +     for (p = buf; p < end; p = get_next_line(p, end))
  +             num++;
  +
  +     ALLOC_ARRAY(sb->lineno, num + 1);
  +     lineno = sb->lineno;
  +
  +     for (p = buf; p < end; p = get_next_line(p, end))
  +             *lineno++ = p - buf;
  +
  +     *lineno = len;
  +
  +     sb->num_lines = num;
  +     return sb->num_lines;
  +}
  +
  +static struct commit *find_single_final(struct rev_info *revs,
  +                                     const char **name_p)
  +{
  +     int i;
  +     struct commit *found = NULL;
  +     const char *name = NULL;
  +
  +     for (i = 0; i < revs->pending.nr; i++) {
  +             struct object *obj = revs->pending.objects[i].item;
  +             if (obj->flags & UNINTERESTING)
  +                     continue;
  +             obj = deref_tag(obj, NULL, 0);
  +             if (obj->type != OBJ_COMMIT)
  +                     die("Non commit %s?", revs->pending.objects[i].name);
  +             if (found)
  +                     die("More than one commit to dig from %s and %s?",
  +                         revs->pending.objects[i].name, name);
  +             found = (struct commit *)obj;
  +             name = revs->pending.objects[i].name;
  +     }
  +     if (name_p)
  +             *name_p = name;
  +     return found;
  +}
  +
  +static struct commit *dwim_reverse_initial(struct rev_info *revs,
  +                                        const char **name_p)
  +{
  +     /*
  +      * DWIM "git blame --reverse ONE -- PATH" as
  +      * "git blame --reverse ONE..HEAD -- PATH" but only do so
  +      * when it makes sense.
  +      */
  +     struct object *obj;
  +     struct commit *head_commit;
  +     struct object_id head_oid;
  +
  +     if (revs->pending.nr != 1)
  +             return NULL;
  +
  +     /* Is that sole rev a committish? */
  +     obj = revs->pending.objects[0].item;
  +     obj = deref_tag(obj, NULL, 0);
  +     if (obj->type != OBJ_COMMIT)
  +             return NULL;
  +
  +     /* Do we have HEAD? */
  +     if (!resolve_ref_unsafe("HEAD", RESOLVE_REF_READING, head_oid.hash, NULL))
  +             return NULL;
  +     head_commit = lookup_commit_reference_gently(&head_oid, 1);
  +     if (!head_commit)
  +             return NULL;
  +
  +     /* Turn "ONE" into "ONE..HEAD" then */
  +     obj->flags |= UNINTERESTING;
  +     add_pending_object(revs, &head_commit->object, "HEAD");
  +
  +     if (name_p)
  +             *name_p = revs->pending.objects[0].name;
  +     return (struct commit *)obj;
  +}
  +
  +static struct commit *find_single_initial(struct rev_info *revs,
  +                                       const char **name_p)
  +{
  +     int i;
  +     struct commit *found = NULL;
  +     const char *name = NULL;
  +
  +     /*
  +      * There must be one and only one negative commit, and it must be
  +      * the boundary.
  +      */
  +     for (i = 0; i < revs->pending.nr; i++) {
  +             struct object *obj = revs->pending.objects[i].item;
  +             if (!(obj->flags & UNINTERESTING))
  +                     continue;
  +             obj = deref_tag(obj, NULL, 0);
  +             if (obj->type != OBJ_COMMIT)
  +                     die("Non commit %s?", revs->pending.objects[i].name);
  +             if (found)
  +                     die("More than one commit to dig up from, %s and %s?",
  +                         revs->pending.objects[i].name, name);
  +             found = (struct commit *) obj;
  +             name = revs->pending.objects[i].name;
  +     }
  +
  +     if (!name)
  +             found = dwim_reverse_initial(revs, &name);
  +     if (!name)
  +             die("No commit to dig up from?");
  +
  +     if (name_p)
  +             *name_p = name;
  +     return found;
  +}
  +
  +void init_scoreboard(struct blame_scoreboard *sb)
  +{
  +     memset(sb, 0, sizeof(struct blame_scoreboard));
  +     sb->move_score = BLAME_DEFAULT_MOVE_SCORE;
  +     sb->copy_score = BLAME_DEFAULT_COPY_SCORE;
  +}
  +
  +void setup_scoreboard(struct blame_scoreboard *sb, const char *path, struct blame_origin **orig)
  +{
  +     const char *final_commit_name = NULL;
  +     struct blame_origin *o;
  +     struct commit *final_commit = NULL;
  +     enum object_type type;
  +
  +     if (sb->reverse && sb->contents_from)
  +             die(_("--contents and --reverse do not blend well."));
  +
  +     if (!sb->reverse) {
  +             sb->final = find_single_final(sb->revs, &final_commit_name);
  +             sb->commits.compare = compare_commits_by_commit_date;
  +     } else {
  +             sb->final = find_single_initial(sb->revs, &final_commit_name);
  +             sb->commits.compare = compare_commits_by_reverse_commit_date;
  +     }
  +
  +     if (sb->final && sb->contents_from)
  +             die(_("cannot use --contents with final commit object name"));
  +
  +     if (sb->reverse && sb->revs->first_parent_only)
  +             sb->revs->children.name = NULL;
  +
  +     if (!sb->final) {
  +             /*
  +              * "--not A B -- path" without anything positive;
  +              * do not default to HEAD, but use the working tree
  +              * or "--contents".
  +              */
  +             setup_work_tree();
  +             sb->final = fake_working_tree_commit(&sb->revs->diffopt,
  +                                                  path, sb->contents_from);
  +             add_pending_object(sb->revs, &(sb->final->object), ":");
  +     }
  +
  +     if (sb->reverse && sb->revs->first_parent_only) {
  +             final_commit = find_single_final(sb->revs, NULL);
  +             if (!final_commit)
  +                     die(_("--reverse and --first-parent together require specified latest commit"));
  +     }
  +
  +     /*
  +      * If we have bottom, this will mark the ancestors of the
  +      * bottom commits we would reach while traversing as
  +      * uninteresting.
  +      */
  +     if (prepare_revision_walk(sb->revs))
  +             die(_("revision walk setup failed"));
  +
  +     if (sb->reverse && sb->revs->first_parent_only) {
  +             struct commit *c = final_commit;
  +
  +             sb->revs->children.name = "children";
  +             while (c->parents &&
  +                    oidcmp(&c->object.oid, &sb->final->object.oid)) {
  +                     struct commit_list *l = xcalloc(1, sizeof(*l));
  +
  +                     l->item = c;
  +                     if (add_decoration(&sb->revs->children,
  +                                        &c->parents->item->object, l))
  +                             die("BUG: not unique item in first-parent chain");
  +                     c = c->parents->item;
  +             }
  +
  +             if (oidcmp(&c->object.oid, &sb->final->object.oid))
  +                     die(_("--reverse --first-parent together require range along first-parent chain"));
  +     }
  +
  +     if (is_null_oid(&sb->final->object.oid)) {
  +             o = sb->final->util;
  +             sb->final_buf = xmemdupz(o->file.ptr, o->file.size);
  +             sb->final_buf_size = o->file.size;
  +     }
  +     else {
  +             o = get_origin(sb->final, path);
  +             if (fill_blob_sha1_and_mode(o))
  +                     die(_("no such path %s in %s"), path, final_commit_name);
  +
  +             if (DIFF_OPT_TST(&sb->revs->diffopt, ALLOW_TEXTCONV) &&
  +                 textconv_object(path, o->mode, &o->blob_oid, 1, (char **) &sb->final_buf,
  +                                 &sb->final_buf_size))
  +                     ;
  +             else
  +                     sb->final_buf = read_sha1_file(o->blob_oid.hash, &type,
  +                                                    &sb->final_buf_size);
  +
  +             if (!sb->final_buf)
  +                     die(_("cannot read blob %s for path %s"),
  +                         oid_to_hex(&o->blob_oid),
  +                         path);
  +     }
  +     sb->num_read_blob++;
  +     prepare_lines(sb);
  +
  +     if (orig)
  +             *orig = o;
  +}
  +
  +
  +
  +struct blame_entry *blame_entry_prepend(struct blame_entry *head,
  +                                     long start, long end,
  +                                     struct blame_origin *o)
  +{
  +     struct blame_entry *new_head = xcalloc(1, sizeof(struct blame_entry));
  +     new_head->lno = start;
  +     new_head->num_lines = end - start;
  +     new_head->suspect = o;
  +     new_head->s_lno = start;
  +     new_head->next = head;
  +     blame_origin_incref(o);
  +     return new_head;
  +}
diff --cc branch.c
Simple merge
diff --cc builtin/add.c
Simple merge
diff --cc builtin/am.c
Simple merge
diff --cc builtin/blame.c
index 749ad7f05b657ba34534a4ae6601dd5d85649b36,d7a2df3b47439c5564a716402e815e0da4f0d8a9,1a7371808ad4615052e92b792149ad7f84845776..bda1a787265e6d44d2ec0bec1e4dee5bf8de9c3b
    */
   
   #include "cache.h"
  -#include "refs.h"
++ #include "config.h"
   #include "builtin.h"
  -#include "blob.h"
   #include "commit.h"
  -#include "tag.h"
  -#include "tree-walk.h"
   #include "diff.h"
  -#include "diffcore.h"
   #include "revision.h"
   #include "quote.h"
  -#include "xdiff-interface.h"
  -#include "cache-tree.h"
   #include "string-list.h"
   #include "mailmap.h"
  -#include "mergesort.h"
   #include "parse-options.h"
   #include "prio-queue.h"
   #include "utf8.h"
Simple merge
index 4bffd7a2d8eee2ea251afef70f63f646f184a339,4bffd7a2d8eee2ea251afef70f63f646f184a339,12451205cf8929c25c57f6a2d7f7a1a0a5f11fa4..7efbc4019ac59a16ae4f147889e6f489dac1e661
@@@@ -4,8 -4,8 -4,8 +4,9 @@@@
    * Copyright (C) Linus Torvalds, 2005
    */
   #include "cache.h"
++ #include "config.h"
   #include "builtin.h"
  +#include "diff.h"
   #include "parse-options.h"
   #include "userdiff.h"
   #include "streaming.h"
Simple merge
Simple merge
diff --cc builtin/clean.c
Simple merge
diff --cc builtin/clone.c
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
index c97069a714e42a1737b5dfa223fe39c26ad9aa67,a572da9d5152ddf541f71e1aaf8abdb3c98f8ffe,29d3e4f416746eda53c9d599d4adf92966ffff09..17bf84d18f802d3f223e7408fee644b94878b35f
@@@@ -20,12 -20,9 -21,9 +21,12 @@@@ int cmd_diff_files(int argc, const cha
        int result;
        unsigned options = 0;
   
 ++     if (argc == 2 && !strcmp(argv[1], "-h"))
 ++             usage(diff_files_usage);
 ++
  +     git_config(git_diff_basic_config, NULL); /* no "diff" UI options */
        init_revisions(&rev, prefix);
        gitmodules_config();
  -     git_config(git_diff_basic_config, NULL); /* no "diff" UI options */
        rev.abbrev = 0;
        precompose_argv(argc, argv);
   
index d59bf6cf5f8da394251532765f27a044c14a572d,f084826a293f96870d0cf6be05e3e346672fc5dc,e3d418361c7db8b4206019898d4373f31169652f..185e6f9b582fdcf15072038b570463a0cfb1bbf2
@@@@ -17,12 -17,9 -18,9 +18,12 @@@@ int cmd_diff_index(int argc, const cha
        int i;
        int result;
   
 ++     if (argc == 2 && !strcmp(argv[1], "-h"))
 ++             usage(diff_cache_usage);
 ++
  +     git_config(git_diff_basic_config, NULL); /* no "diff" UI options */
        init_revisions(&rev, prefix);
        gitmodules_config();
  -     git_config(git_diff_basic_config, NULL); /* no "diff" UI options */
        rev.abbrev = 0;
        precompose_argv(argc, argv);
   
index 7e15d01f36396fdc6b630eb43a5f36d462fb78e6,e401112045023e990537a4ffe25c19487b31a30b,c81063d534f87a0d6d6ee768fab2253144674279..31d2cb410738d335d9f6431d6901ea1c0f8b67ff
@@@@ -7,9 -7,9 -8,9 +8,9 @@@@
   
   static struct rev_info log_tree_opt;
   
 --static int diff_tree_commit_sha1(const struct object_id *oid)
 ++static int diff_tree_commit_oid(const struct object_id *oid)
   {
  -     struct commit *commit = lookup_commit_reference(oid->hash);
  +     struct commit *commit = lookup_commit_reference(oid);
        if (!commit)
                return -1;
        return log_tree_commit(&log_tree_opt, commit);
@@@@ -104,12 -105,9 -106,9 +105,12 @@@@ int cmd_diff_tree(int argc, const char 
        struct setup_revision_opt s_r_opt;
        int read_stdin = 0;
   
 ++     if (argc == 2 && !strcmp(argv[1], "-h"))
 ++             usage(diff_tree_usage);
 ++
  +     git_config(git_diff_basic_config, NULL); /* no "diff" UI options */
        init_revisions(opt, prefix);
        gitmodules_config();
  -     git_config(git_diff_basic_config, NULL); /* no "diff" UI options */
        opt->abbrev = 0;
        opt->diff = 1;
        opt->disable_stdin = 1;
diff --cc builtin/diff.c
index d9152c21bf5a8aa41778f838b4d804ac698bdc2b,0c8f86e40da6537d57f5ed6ca0ecdd005e29c8f5,1ce40c63b23cdec6f0f9c22bbce351acdf3effed..7cde6abbcf7651af8313bd3d70eb1944e72c9cb3
@@@@ -50,14 -50,14 -52,14 +51,14 @@@@ static void stuff_change(struct diff_op
        }
   
        if (opt->prefix &&
  -         (strncmp(old_name, opt->prefix, opt->prefix_length) ||
  -          strncmp(new_name, opt->prefix, opt->prefix_length)))
  +         (strncmp(old_path, opt->prefix, opt->prefix_length) ||
  +          strncmp(new_path, opt->prefix, opt->prefix_length)))
                return;
   
  -     one = alloc_filespec(old_name);
  -     two = alloc_filespec(new_name);
  -     fill_filespec(one, old_oid->hash, old_oid_valid, old_mode);
  -     fill_filespec(two, new_oid->hash, new_oid_valid, new_mode);
  +     one = alloc_filespec(old_path);
  +     two = alloc_filespec(new_path);
 -      fill_filespec(one, old_oid->hash, old_oid_valid, old_mode);
 -      fill_filespec(two, new_oid->hash, new_oid_valid, new_mode);
 ++     fill_filespec(one, old_oid, old_oid_valid, old_mode);
 ++     fill_filespec(two, new_oid, new_oid_valid, new_mode);
   
        diff_queue(&diff_queued_diff, one, two);
   }
Simple merge
Simple merge
diff --cc builtin/fetch.c
Simple merge
Simple merge
diff --cc builtin/fsck.c
Simple merge
diff --cc builtin/gc.c
Simple merge
diff --cc builtin/grep.c
index 3e4b9600e86b661c99f4b936dfa574029ac4fbba,7df9c253eebb3053693769d14efe0551393dfd4d,3df9e08f0368024dd067d5897bf46c83a7cbfdfc..f61a9d938b44424414812c57eecc309bd563f4b3
@@@@ -290,22 -289,19 -290,8 +291,22 @@@@ static int grep_cmd_config(const char *
                if (num_threads < 0)
                        die(_("invalid number of threads specified (%d) for %s"),
                            num_threads, var);
  +#ifdef NO_PTHREADS
  +             else if (num_threads && num_threads != 1) {
  +                     /*
  +                      * TRANSLATORS: %s is the configuration
  +                      * variable for tweaking threads, currently
  +                      * grep.threads
  +                      */
  +                     warning(_("no threads support, ignoring %s"), var);
  +                     num_threads = 0;
  +             }
  +#endif
        }
   
 ++     if (!strcmp(var, "submodule.recurse"))
 ++             recurse_submodules = git_config_bool(var, value);
 ++
        return st;
   }
   
@@@@ -1243,11 -1241,9 -1227,7 +1244,11 @@@@ int cmd_grep(int argc, const char **arg
                num_threads = GREP_NUM_THREADS_DEFAULT;
        else if (num_threads < 0)
                die(_("invalid number of threads specified (%d)"), num_threads);
 ++     if (num_threads == 1)
 ++             num_threads = 0;
   #else
  +     if (num_threads)
  +             warning(_("no threads support, ignoring --threads"));
        num_threads = 0;
   #endif
   
Simple merge
diff --cc builtin/log.c
Simple merge
index b376afc3124c3240f4f249ccc206efa0b064675e,cdc1cfdd26a95c54cc23717ce53c20a9d1607c90,975101078071dc48c09024830c4a621e3891cefb..b12d0bb61240890b3145baa8f051c83005b97dbe
@@@@ -319,13 -336,14 -320,13 +337,14 @@@@ static void show_ru_info(const struct i
        }
   }
   
- -static int ce_excluded(struct dir_struct *dir, const struct cache_entry *ce)
+ +static int ce_excluded(struct dir_struct *dir, struct index_state *istate,
+ +                    const struct cache_entry *ce)
   {
        int dtype = ce_to_dtype(ce);
-       return is_excluded(dir, &the_index, ce->name, &dtype);
  -     return is_excluded(dir, ce->name, &dtype);
+ +     return is_excluded(dir, istate, ce->name, &dtype);
   }
   
- -static void show_files(struct dir_struct *dir)
+ +static void show_files(struct index_state *istate, struct dir_struct *dir)
   {
        int i;
   
        if (show_others || show_killed) {
                if (!show_others)
                        dir->flags |= DIR_COLLECT_KILLED_ONLY;
-               fill_directory(dir, &the_index, &pathspec);
  -             fill_directory(dir, &pathspec);
+ +             fill_directory(dir, istate, &pathspec);
                if (show_others)
- -                     show_other_files(dir);
+ +                     show_other_files(istate, dir);
                if (show_killed)
- -                     show_killed_files(dir);
+ +                     show_killed_files(istate, dir);
        }
        if (show_cached || show_stage) {
- -             for (i = 0; i < active_nr; i++) {
- -                     const struct cache_entry *ce = active_cache[i];
+ +             for (i = 0; i < istate->cache_nr; i++) {
+ +                     const struct cache_entry *ce = istate->cache[i];
                        if ((dir->flags & DIR_SHOW_IGNORED) &&
- -                         !ce_excluded(dir, ce))
+ +                         !ce_excluded(dir, istate, ce))
                                continue;
                        if (show_unmerged && !ce_stage(ce))
                                continue;
@@@@ -398,28 -417,28 -399,9 +418,28 @@@@ static void prune_index(struct index_st
                }
                last = next;
        }
- -     memmove(active_cache, active_cache + pos,
+ +     memmove(istate->cache, istate->cache + pos,
                (last - pos) * sizeof(struct cache_entry *));
- -     active_nr = last - pos;
+ +     istate->cache_nr = last - pos;
  +}
  +
  +static int get_common_prefix_len(const char *common_prefix)
  +{
  +     int common_prefix_len;
  +
  +     if (!common_prefix)
  +             return 0;
  +
  +     common_prefix_len = strlen(common_prefix);
  +
  +     /*
  +      * If the prefix has a trailing slash, strip it so that submodules wont
  +      * be pruned from the index.
  +      */
  +     if (common_prefix[common_prefix_len - 1] == '/')
  +             common_prefix_len--;
  +
  +     return common_prefix_len;
   }
   
   /*
    * that were given from the command line.  We are not
    * going to write this index out.
    */
- -void overlay_tree_on_cache(const char *tree_name, const char *prefix)
+ +void overlay_tree_on_index(struct index_state *istate,
+ +                        const char *tree_name, const char *prefix)
   {
        struct tree *tree;
  -     unsigned char sha1[20];
  +     struct object_id oid;
        struct pathspec pathspec;
        struct cache_entry *last_stage0 = NULL;
        int i;
@@@@ -655,9 -675,9 -638,7 +676,9 @@@@ int cmd_ls_files(int argc, const char *
                max_prefix = NULL;
        else
                max_prefix = common_prefix(&pathspec);
  -     max_prefix_len = max_prefix ? strlen(max_prefix) : 0;
  +     max_prefix_len = get_common_prefix_len(max_prefix);
  +
-       prune_cache(max_prefix, max_prefix_len);
+ +     prune_index(&the_index, max_prefix, max_prefix_len);
   
        /* Treat unmatching pathspec elements as errors */
        if (pathspec.nr && error_unmatch)
Simple merge
Simple merge
diff --cc builtin/merge.c
Simple merge
Simple merge
diff --cc builtin/notes.c
Simple merge
Simple merge
diff --cc builtin/pull.c
Simple merge
diff --cc builtin/push.c
Simple merge
index 5bfd4c9f76d84c177b72a8ed97d3418d111583e9,78d3193659e06b4969324153689f219f1cd1c1b3,0a85b6d938806986da06e83afeaa55a6930eca34..d5f618d086365520fcf36ed8db110ba701ba37d3
   static int nr_trees;
   static int read_empty;
   static struct tree *trees[MAX_UNPACK_TREES];
 --static int recurse_submodules = RECURSE_SUBMODULES_DEFAULT;
   
  -static int list_tree(unsigned char *sha1)
  +static int list_tree(struct object_id *oid)
   {
        struct tree *tree;
   
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
diff --cc builtin/reset.c
index 45001e5200cb4c5aaf0ad316cf1622f9495d851d,430602d102133d125009e8c8068ce5547c24cab7,fdd5e5e003484b97a9915540642c34943abb1423..7aeaea2737991f021eb788708c1710305abb4b08
   #include "parse-options.h"
   #include "unpack-trees.h"
   #include "cache-tree.h"
  +#include "submodule.h"
  +#include "submodule-config.h"
   
 - static int recurse_submodules = RECURSE_SUBMODULES_DEFAULT;
 - 
 - static int option_parse_recurse_submodules(const struct option *opt,
 -                                         const char *arg, int unset)
 - {
 -      if (unset) {
 -              recurse_submodules = RECURSE_SUBMODULES_OFF;
 -              return 0;
 -      }
 -      if (arg)
 -              recurse_submodules =
 -                      parse_update_recurse_submodules_arg(opt->long_name,
 -                                                          arg);
 -      else
 -              recurse_submodules = RECURSE_SUBMODULES_ON;
 - 
 -      return 0;
 - }
 - 
   static const char * const git_reset_usage[] = {
        N_("git reset [--mixed | --soft | --hard | --merge | --keep] [-q] [<commit>]"),
        N_("git reset [-q] [<tree-ish>] [--] <paths>..."),
@@@@ -292,9 -303,9 -284,6 +293,9 @@@@ int cmd_reset(int argc, const char **ar
                                N_("reset HEAD, index and working tree"), MERGE),
                OPT_SET_INT(0, "keep", &reset_type,
                                N_("reset HEAD but keep local changes"), KEEP),
 -              { OPTION_CALLBACK, 0, "recurse-submodules", &recurse_submodules,
 ++             { OPTION_CALLBACK, 0, "recurse-submodules", NULL,
  +                         "reset", "control recursive updating of submodules",
 -                          PARSE_OPT_OPTARG, option_parse_recurse_submodules },
 ++                         PARSE_OPT_OPTARG, option_parse_recurse_submodules_worktree_updater },
                OPT_BOOL('p', "patch", &patch_mode, N_("select hunks interactively")),
                OPT_BOOL('N', "intent-to-add", &intent_to_add,
                                N_("record only the fact that removed paths will be added later")),
                                                PARSE_OPT_KEEP_DASHDASH);
        parse_args(&pathspec, argv, prefix, patch_mode, &rev);
   
 -      if (recurse_submodules != RECURSE_SUBMODULES_DEFAULT) {
 -              gitmodules_config();
 -              git_config(submodule_config, NULL);
 -              set_config_update_recurse_submodules(RECURSE_SUBMODULES_ON);
 -      }
 ++     load_submodule_cache();
  +
        unborn = !strcmp(rev, "HEAD") && get_sha1("HEAD", oid.hash);
        if (unborn) {
                /* reset on unborn branch: treat as reset to empty tree */
Simple merge
Simple merge
diff --cc builtin/rm.c
Simple merge
Simple merge
Simple merge
diff --cc builtin/tag.c
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
diff --cc cache.h
Simple merge
diff --cc combine-diff.c
Simple merge
diff --cc config.c
Simple merge
diff --cc connect.c
Simple merge
diff --cc convert.c
index f1e168bc303c71542b692b2b9d08cdb2e2c98669,4097f521f240240fde1a3bfa8519515fdaac75f6,69f23cfcaa90993416eaa76303059f3bd389bf9a..7d2a519dafe5dcf892df10c51e1bfb83bc8a2091
+++ b/convert.c
@@@@ -1,4 -1,5 -1,5 +1,6 @@@@
+ +#define NO_THE_INDEX_COMPATIBILITY_MACROS
   #include "cache.h"
++ #include "config.h"
   #include "attr.h"
   #include "run-command.h"
   #include "quote.h"
Simple merge
diff --cc diff.c
index acedf86aecc151112898ff54575151f157776281,976a6f91b189914570d1c688525a9ca5e3ef6505,4f9b9f83825ab1a79647969d360296b8311a33c8..41295d4ea9ff5564fa73d45aaa3afaab20103d87
--- 1/diff.c
--- 2/diff.c
--- 3/diff.c
+++ b/diff.c
@@@@ -5266,29 -5270,29 -5271,6 +5267,29 @@@@ size_t fill_textconv(struct userdiff_dr
        return size;
   }
   
 -      fill_filespec(df, oid->hash, oid_valid, mode);
  +int textconv_object(const char *path,
  +                 unsigned mode,
  +                 const struct object_id *oid,
  +                 int oid_valid,
  +                 char **buf,
  +                 unsigned long *buf_size)
  +{
  +     struct diff_filespec *df;
  +     struct userdiff_driver *textconv;
  +
  +     df = alloc_filespec(path);
 ++     fill_filespec(df, oid, oid_valid, mode);
  +     textconv = get_textconv(df);
  +     if (!textconv) {
  +             free_filespec(df);
  +             return 0;
  +     }
  +
  +     *buf_size = fill_textconv(textconv, df, buf);
  +     free_filespec(df);
  +     return 1;
  +}
  +
   void setup_diff_pager(struct diff_options *opt)
   {
        /*
diff --cc dir.c
index 17590638176f26e35f3a728e5cd56917e0568541,f673b86f31eb841ce0ecc34f49ab9ece2dd4d128,42beb65beaa03dbcf5fb312d7c280a1b3251614b..34445374ba60b5a2e8d1c2b6e96ba7dbdb18eb4c
--- 1/dir.c
--- 2/dir.c
--- 3/dir.c
+++ b/dir.c
@@@@ -7,8 -7,8 -7,8 +7,9 @@@@
    * Copyright (C) Linus Torvalds, 2005-2006
    *            Junio Hamano, 2005-2006
    */
  +#define NO_THE_INDEX_COMPATIBILITY_MACROS
   #include "cache.h"
++ #include "config.h"
   #include "dir.h"
   #include "attr.h"
   #include "refs.h"
@@@@ -752,12 -752,12 -746,12 +753,12 @@@@ static int add_excludes(const char *fna
   
        fd = open(fname, O_RDONLY);
        if (fd < 0 || fstat(fd, &st) < 0) {
 --             if (errno != ENOENT)
 --                     warn_on_inaccessible(fname);
 --             if (0 <= fd)
 ++             if (fd < 0)
 ++                     warn_on_fopen_errors(fname);
 ++             else
                        close(fd);
  -             if (!check_index ||
  -                 (buf = read_skip_worktree_file_from_index(fname, &size, sha1_stat)) == NULL)
  +             if (!istate ||
  +                 (buf = read_skip_worktree_file_from_index(istate, fname, &size, sha1_stat)) == NULL)
                        return -1;
                if (size == 0) {
                        free(buf);
                if (sha1_stat) {
                        int pos;
                        if (sha1_stat->valid &&
  -                         !match_stat_data_racy(&the_index, &sha1_stat->stat, &st))
  +                         !match_stat_data_racy(istate, &sha1_stat->stat, &st))
                                ; /* no content change, ss->sha1 still good */
  -                     else if (check_index &&
  -                              (pos = cache_name_pos(fname, strlen(fname))) >= 0 &&
  -                              !ce_stage(active_cache[pos]) &&
  -                              ce_uptodate(active_cache[pos]) &&
  -                              !would_convert_to_git(fname))
  +                     else if (istate &&
  +                              (pos = index_name_pos(istate, fname, strlen(fname))) >= 0 &&
  +                              !ce_stage(istate->cache[pos]) &&
  +                              ce_uptodate(istate->cache[pos]) &&
-                                !would_convert_to_git(fname))
+ +                              !would_convert_to_git(istate, fname))
                                hashcpy(sha1_stat->sha1,
  -                                     active_cache[pos]->oid.hash);
  +                                     istate->cache[pos]->oid.hash);
                        else
                                hash_sha1_file(buf, size, "blob", sha1_stat->sha1);
                        fill_stat_data(&sha1_stat->stat, &st);
diff --cc environment.c
Simple merge
diff --cc fast-import.c
Simple merge
diff --cc fetch-pack.c
Simple merge
diff --cc git.c
index 1b8b7f51a65fa2a8e62d11d7ad99f19e2926977f,8ff44f081d43176474b267de5451f2c2e88089d0,c03de2c0900b47ffefede41223d9b069fe36a49d..5be27b07e5146e89ce6497566ec602a3f58bc313
--- 1/git.c
--- 2/git.c
--- 3/git.c
+++ b/git.c
@@@@ -16,53 -16,51 -17,7 +17,9 @@@@ const char git_more_info_string[] 
           "to read about a specific subcommand or concept.");
   
   static int use_pager = -1;
-- static char *orig_cwd;
-- static const char *env_names[] = {
--      GIT_DIR_ENVIRONMENT,
--      GIT_WORK_TREE_ENVIRONMENT,
--      GIT_IMPLICIT_WORK_TREE_ENVIRONMENT,
--      GIT_PREFIX_ENVIRONMENT
-- };
-- static char *orig_env[4];
-- static int save_restore_env_balance;
 - 
 - static void save_env_before_alias(void)
 - {
 -      int i;
 - 
 -      assert(save_restore_env_balance == 0);
 -      save_restore_env_balance = 1;
 -      orig_cwd = xgetcwd();
 -      for (i = 0; i < ARRAY_SIZE(env_names); i++) {
 -              orig_env[i] = getenv(env_names[i]);
 -              orig_env[i] = xstrdup_or_null(orig_env[i]);
 -      }
 - }
   
 - static void restore_env(int external_alias)
 - {
 -      int i;
 - 
 -      assert(save_restore_env_balance == 1);
 -      save_restore_env_balance = 0;
 -      if (!external_alias && orig_cwd && chdir(orig_cwd))
 -              die_errno("could not move to %s", orig_cwd);
 -      free(orig_cwd);
 -      for (i = 0; i < ARRAY_SIZE(env_names); i++) {
 -              if (external_alias &&
 -                  !strcmp(env_names[i], GIT_PREFIX_ENVIRONMENT))
 -                      continue;
 -              if (orig_env[i]) {
 -                      setenv(env_names[i], orig_env[i], 1);
 -                      free(orig_env[i]);
 -              } else {
 -                      unsetenv(env_names[i]);
 -              }
 -      }
 - }
 ++static void list_builtins(void);
  +
-  static void save_env_before_alias(void)
-  {
-       int i;
-  
-       assert(save_restore_env_balance == 0);
-       save_restore_env_balance = 1;
-       orig_cwd = xgetcwd();
-       for (i = 0; i < ARRAY_SIZE(env_names); i++) {
-               orig_env[i] = getenv(env_names[i]);
-               orig_env[i] = xstrdup_or_null(orig_env[i]);
-       }
-  }
-  
-  static void restore_env(int external_alias)
-  {
-       int i;
-  
-       assert(save_restore_env_balance == 1);
-       save_restore_env_balance = 0;
-       if (!external_alias && orig_cwd && chdir(orig_cwd))
-               die_errno("could not move to %s", orig_cwd);
-       free(orig_cwd);
-       for (i = 0; i < ARRAY_SIZE(env_names); i++) {
-               if (external_alias &&
-                   !strcmp(env_names[i], GIT_PREFIX_ENVIRONMENT))
-                       continue;
-               if (orig_env[i]) {
-                       setenv(env_names[i], orig_env[i], 1);
-                       free(orig_env[i]);
-               } else {
-                       unsetenv(env_names[i]);
-               }
-       }
-  }
-  
   static void commit_pager_choice(void) {
        switch (use_pager) {
        case 0:
diff --cc grep.c
index d7ef21358ea7f592dffff98884eb34169e097880,d03d424e5cf8d32d91e3082555d8add674e01486,d5211fc5a6c0ae86c48f7e17a6be747dfc421f69..30d317a122eb5adc2c6d63eddaa12ca14cafba78
--- 1/grep.c
--- 2/grep.c
--- 3/grep.c
+++ b/grep.c
@@@@ -178,38 -178,23 -179,26 +179,38 @@@@ static void grep_set_pattern_type_optio
   
        case GREP_PATTERN_TYPE_BRE:
                opt->fixed = 0;
  -             opt->pcre = 0;
  -             opt->regflags &= ~REG_EXTENDED;
  +             opt->pcre1 = 0;
 ++             opt->pcre2 = 0;
                break;
   
        case GREP_PATTERN_TYPE_ERE:
                opt->fixed = 0;
  -             opt->pcre = 0;
  +             opt->pcre1 = 0;
 ++             opt->pcre2 = 0;
                opt->regflags |= REG_EXTENDED;
                break;
   
        case GREP_PATTERN_TYPE_FIXED:
                opt->fixed = 1;
  -             opt->pcre = 0;
  -             opt->regflags &= ~REG_EXTENDED;
  +             opt->pcre1 = 0;
 ++             opt->pcre2 = 0;
                break;
   
        case GREP_PATTERN_TYPE_PCRE:
                opt->fixed = 0;
  -             opt->pcre = 1;
  -             opt->regflags &= ~REG_EXTENDED;
 ++#ifdef USE_LIBPCRE2
 ++             opt->pcre1 = 0;
 ++             opt->pcre2 = 1;
 ++#else
 ++             /*
 ++              * It's important that pcre1 always be assigned to
 ++              * even when there's no USE_LIBPCRE* defined. We still
 ++              * call the PCRE stub function, it just dies with
 ++              * "cannot use Perl-compatible regexes[...]".
 ++              */
  +             opt->pcre1 = 1;
 ++             opt->pcre2 = 0;
 ++#endif
                break;
        }
   }
@@@@ -375,30 -360,17 -340,17 +376,30 @@@@ static void compile_pcre1_regexp(struc
        if (is_utf8_locale() && has_non_ascii(p->pattern))
                options |= PCRE_UTF8;
   
  -     p->pcre_regexp = pcre_compile(p->pattern, options, &error, &erroffset,
  -                                   p->pcre_tables);
  -     if (!p->pcre_regexp)
  +     p->pcre1_regexp = pcre_compile(p->pattern, options, &error, &erroffset,
  +                                   p->pcre1_tables);
  +     if (!p->pcre1_regexp)
                compile_regexp_failed(p, error);
   
 -      p->pcre1_extra_info = pcre_study(p->pcre1_regexp, 0, &error);
  -     p->pcre_extra_info = pcre_study(p->pcre_regexp, 0, &error);
  -     if (!p->pcre_extra_info && error)
 ++     p->pcre1_extra_info = pcre_study(p->pcre1_regexp, PCRE_STUDY_JIT_COMPILE, &error);
  +     if (!p->pcre1_extra_info && error)
                die("%s", error);
 ++
 ++#ifdef GIT_PCRE1_USE_JIT
 ++     pcre_config(PCRE_CONFIG_JIT, &p->pcre1_jit_on);
 ++     if (p->pcre1_jit_on == 1) {
 ++             p->pcre1_jit_stack = pcre_jit_stack_alloc(1, 1024 * 1024);
 ++             if (!p->pcre1_jit_stack)
 ++                     die("Couldn't allocate PCRE JIT stack");
 ++             pcre_assign_jit_stack(p->pcre1_extra_info, NULL, p->pcre1_jit_stack);
 ++     } else if (p->pcre1_jit_on != 0) {
 ++             die("BUG: The pcre1_jit_on variable should be 0 or 1, not %d",
 ++                 p->pcre1_jit_on);
 ++     }
 ++#endif
   }
   
  -static int pcrematch(struct grep_pat *p, const char *line, const char *eol,
  +static int pcre1match(struct grep_pat *p, const char *line, const char *eol,
                regmatch_t *match, int eflags)
   {
        int ovector[30], ret, flags = 0;
        if (eflags & REG_NOTBOL)
                flags |= PCRE_NOTBOL;
   
 -      ret = pcre_exec(p->pcre1_regexp, p->pcre1_extra_info, line, eol - line,
  -     ret = pcre_exec(p->pcre_regexp, p->pcre_extra_info, line, eol - line,
 --                     0, flags, ovector, ARRAY_SIZE(ovector));
 ++#ifdef GIT_PCRE1_USE_JIT
 ++     if (p->pcre1_jit_on) {
 ++             ret = pcre_jit_exec(p->pcre1_regexp, p->pcre1_extra_info, line,
 ++                                 eol - line, 0, flags, ovector,
 ++                                 ARRAY_SIZE(ovector), p->pcre1_jit_stack);
 ++     } else
 ++#endif
 ++     {
 ++             ret = pcre_exec(p->pcre1_regexp, p->pcre1_extra_info, line,
 ++                             eol - line, 0, flags, ovector,
 ++                             ARRAY_SIZE(ovector));
 ++     }
 ++
        if (ret < 0 && ret != PCRE_ERROR_NOMATCH)
                die("pcre_exec failed with error code %d", ret);
        if (ret > 0) {
        return ret;
   }
   
  -static void free_pcre_regexp(struct grep_pat *p)
  +static void free_pcre1_regexp(struct grep_pat *p)
   {
  -     pcre_free(p->pcre_regexp);
  -     pcre_free(p->pcre_extra_info);
  -     pcre_free((void *)p->pcre_tables);
  +     pcre_free(p->pcre1_regexp);
 -      pcre_free(p->pcre1_extra_info);
 ++#ifdef GIT_PCRE1_USE_JIT
 ++     if (p->pcre1_jit_on) {
 ++             pcre_free_study(p->pcre1_extra_info);
 ++             pcre_jit_stack_free(p->pcre1_jit_stack);
 ++     } else
 ++#endif
 ++     {
 ++             pcre_free(p->pcre1_extra_info);
 ++     }
  +     pcre_free((void *)p->pcre1_tables);
   }
  -#else /* !USE_LIBPCRE */
  -static void compile_pcre_regexp(struct grep_pat *p, const struct grep_opt *opt)
  +#else /* !USE_LIBPCRE1 */
  +static void compile_pcre1_regexp(struct grep_pat *p, const struct grep_opt *opt)
   {
        die("cannot use Perl-compatible regexes when not compiled with USE_LIBPCRE");
   }
@@@@ -456,132 -409,11 -389,29 +457,132 @@@@ static int pcre1match(struct grep_pat *
        return 1;
   }
   
  -static void free_pcre_regexp(struct grep_pat *p)
  +static void free_pcre1_regexp(struct grep_pat *p)
   {
   }
  -#endif /* !USE_LIBPCRE */
  +#endif /* !USE_LIBPCRE1 */
   
  -static int is_fixed(const char *s, size_t len)
 ++#ifdef USE_LIBPCRE2
 ++static void compile_pcre2_pattern(struct grep_pat *p, const struct grep_opt *opt)
 + {
  -     size_t i;
 ++     int error;
 ++     PCRE2_UCHAR errbuf[256];
 ++     PCRE2_SIZE erroffset;
 ++     int options = PCRE2_MULTILINE;
 ++     const uint8_t *character_tables = NULL;
 ++     int jitret;
 + 
  -     /* regcomp cannot accept patterns with NULs so we
  -      * consider any pattern containing a NUL fixed.
  -      */
  -     if (memchr(s, 0, len))
  -             return 1;
 ++     assert(opt->pcre2);
 + 
  -     for (i = 0; i < len; i++) {
  -             if (is_regex_special(s[i]))
  -                     return 0;
 ++     p->pcre2_compile_context = NULL;
 ++
 ++     if (opt->ignore_case) {
 ++             if (has_non_ascii(p->pattern)) {
 ++                     character_tables = pcre2_maketables(NULL);
 ++                     p->pcre2_compile_context = pcre2_compile_context_create(NULL);
 ++                     pcre2_set_character_tables(p->pcre2_compile_context, character_tables);
 ++             }
 ++             options |= PCRE2_CASELESS;
 ++     }
 ++     if (is_utf8_locale() && has_non_ascii(p->pattern))
 ++             options |= PCRE2_UTF;
 ++
 ++     p->pcre2_pattern = pcre2_compile((PCRE2_SPTR)p->pattern,
 ++                                      p->patternlen, options, &error, &erroffset,
 ++                                      p->pcre2_compile_context);
 ++
 ++     if (p->pcre2_pattern) {
 ++             p->pcre2_match_data = pcre2_match_data_create_from_pattern(p->pcre2_pattern, NULL);
 ++             if (!p->pcre2_match_data)
 ++                     die("Couldn't allocate PCRE2 match data");
 ++     } else {
 ++             pcre2_get_error_message(error, errbuf, sizeof(errbuf));
 ++             compile_regexp_failed(p, (const char *)&errbuf);
 ++     }
 ++
 ++     pcre2_config(PCRE2_CONFIG_JIT, &p->pcre2_jit_on);
 ++     if (p->pcre2_jit_on == 1) {
 ++             jitret = pcre2_jit_compile(p->pcre2_pattern, PCRE2_JIT_COMPLETE);
 ++             if (jitret)
 ++                     die("Couldn't JIT the PCRE2 pattern '%s', got '%d'\n", p->pattern, jitret);
 ++             p->pcre2_jit_stack = pcre2_jit_stack_create(1, 1024 * 1024, NULL);
 ++             if (!p->pcre2_jit_stack)
 ++                     die("Couldn't allocate PCRE2 JIT stack");
 ++             p->pcre2_match_context = pcre2_match_context_create(NULL);
 ++             if (!p->pcre2_jit_stack)
 ++                     die("Couldn't allocate PCRE2 match context");
 ++             pcre2_jit_stack_assign(p->pcre2_match_context, NULL, p->pcre2_jit_stack);
 ++     } else if (p->pcre2_jit_on != 0) {
 ++             die("BUG: The pcre2_jit_on variable should be 0 or 1, not %d",
 ++                 p->pcre1_jit_on);
 +      }
 ++}
 ++
 ++static int pcre2match(struct grep_pat *p, const char *line, const char *eol,
 ++             regmatch_t *match, int eflags)
 ++{
 ++     int ret, flags = 0;
 ++     PCRE2_SIZE *ovector;
 ++     PCRE2_UCHAR errbuf[256];
 ++
 ++     if (eflags & REG_NOTBOL)
 ++             flags |= PCRE2_NOTBOL;
 + 
 ++     if (p->pcre2_jit_on)
 ++             ret = pcre2_jit_match(p->pcre2_pattern, (unsigned char *)line,
 ++                                   eol - line, 0, flags, p->pcre2_match_data,
 ++                                   NULL);
 ++     else
 ++             ret = pcre2_match(p->pcre2_pattern, (unsigned char *)line,
 ++                               eol - line, 0, flags, p->pcre2_match_data,
 ++                               NULL);
 ++
 ++     if (ret < 0 && ret != PCRE2_ERROR_NOMATCH) {
 ++             pcre2_get_error_message(ret, errbuf, sizeof(errbuf));
 ++             die("%s failed with error code %d: %s",
 ++                 (p->pcre2_jit_on ? "pcre2_jit_match" : "pcre2_match"), ret,
 ++                 errbuf);
 ++     }
 ++     if (ret > 0) {
 ++             ovector = pcre2_get_ovector_pointer(p->pcre2_match_data);
 ++             ret = 0;
 ++             match->rm_so = (int)ovector[0];
 ++             match->rm_eo = (int)ovector[1];
 ++     }
 ++
 ++     return ret;
 ++}
 ++
 ++static void free_pcre2_pattern(struct grep_pat *p)
 ++{
 ++     pcre2_compile_context_free(p->pcre2_compile_context);
 ++     pcre2_code_free(p->pcre2_pattern);
 ++     pcre2_match_data_free(p->pcre2_match_data);
 ++     pcre2_jit_stack_free(p->pcre2_jit_stack);
 ++     pcre2_match_context_free(p->pcre2_match_context);
 ++}
 ++#else /* !USE_LIBPCRE2 */
 ++static void compile_pcre2_pattern(struct grep_pat *p, const struct grep_opt *opt)
 ++{
 ++     /*
 ++      * Unreachable until USE_LIBPCRE2 becomes synonymous with
 ++      * USE_LIBPCRE. See the sibling comment in
 ++      * grep_set_pattern_type_option().
 ++      */
 ++     die("cannot use Perl-compatible regexes when not compiled with USE_LIBPCRE");
 ++}
 ++
 ++static int pcre2match(struct grep_pat *p, const char *line, const char *eol,
 ++             regmatch_t *match, int eflags)
 ++{
 +      return 1;
 + }
 + 
 ++static void free_pcre2_pattern(struct grep_pat *p)
 ++{
 ++}
 ++#endif /* !USE_LIBPCRE2 */
 ++
   static void compile_fixed_regexp(struct grep_pat *p, struct grep_opt *opt)
   {
        struct strbuf sb = STRBUF_INIT;
@@@@ -647,13 -479,8 -476,8 +648,13 @@@@ static void compile_regexp(struct grep_
                return;
        }
   
  -     if (opt->pcre) {
  -             compile_pcre_regexp(p, opt);
 ++     if (opt->pcre2) {
 ++             compile_pcre2_pattern(p, opt);
 ++             return;
 ++     }
 ++
  +     if (opt->pcre1) {
  +             compile_pcre1_regexp(p, opt);
                return;
        }
   
@@@@ -1009,10 -836,8 -833,8 +1010,10 @@@@ void free_grep_patterns(struct grep_op
                case GREP_PATTERN_BODY:
                        if (p->kws)
                                kwsfree(p->kws);
  -                     else if (p->pcre_regexp)
  -                             free_pcre_regexp(p);
  +                     else if (p->pcre1_regexp)
  +                             free_pcre1_regexp(p);
 ++                     else if (p->pcre2_pattern)
 ++                             free_pcre2_pattern(p);
                        else
                                regfree(&p->regexp);
                        free(p->pattern);
@@@@ -1091,10 -916,8 -913,8 +1092,10 @@@@ static int patmatch(struct grep_pat *p
   
        if (p->fixed)
                hit = !fixmatch(p, line, eol, match);
  -     else if (p->pcre_regexp)
  -             hit = !pcrematch(p, line, eol, match, eflags);
  +     else if (p->pcre1_regexp)
  +             hit = !pcre1match(p, line, eol, match, eflags);
 ++     else if (p->pcre2_pattern)
 ++             hit = !pcre2match(p, line, eol, match, eflags);
        else
                hit = !regexec_buf(&p->regexp, line, eol - line, 1, match,
                                   eflags);
diff --cc help.c
index f637fc80062094784d5734df91523642933ddcfc,db7f3d79a016881639a8c0640451afe35b011e5e,b8f3a98e4cbe09dd903dfb86653938c1d7604e3d..8ba0777410bd6377a1325622f7d73a53a0aa5a60
--- 1/help.c
--- 2/help.c
--- 3/help.c
+++ b/help.c
@@@@ -1,7 -1,7 -1,7 +1,8 @@@@
   #include "cache.h"
++ #include "config.h"
   #include "builtin.h"
   #include "exec_cmd.h"
  +#include "run-command.h"
   #include "levenshtein.h"
   #include "help.h"
   #include "common-cmds.h"
diff --cc http-backend.c
Simple merge
diff --cc ident.c
Simple merge
diff --cc ll-merge.c
Simple merge
diff --cc log-tree.c
Simple merge
diff --cc mailinfo.c
Simple merge
Simple merge
diff --cc notes-utils.c
Simple merge
diff --cc notes.c
Simple merge
diff --cc parse-options.c
Simple merge
diff --cc pathspec.c
index 828405021fca4214585e1d46b65f604d14e61143,828405021fca4214585e1d46b65f604d14e61143,e4659b1440c94d0f65ef486a488b604d6195d81c..ecc5331c232ef81f26343fd958a9b66e92a3fa5e
@@@@ -1,5 -1,5 -1,5 +1,6 @@@@
  +#define NO_THE_INDEX_COMPATIBILITY_MACROS
   #include "cache.h"
++ #include "config.h"
   #include "dir.h"
   #include "pathspec.h"
   #include "attr.h"
diff --cc pretty.c
Simple merge
diff --cc read-cache.c
Simple merge
diff --cc refs.c
Simple merge
Simple merge
diff --cc remote.c
Simple merge
diff --cc rerere.c
Simple merge
diff --cc sequencer.c
Simple merge
diff --cc setup.c
Simple merge
diff --cc sha1_file.c
Simple merge
diff --cc sha1_name.c
Simple merge
diff --cc submodule.c
index 1b8a3b575db6c85a42e9c9e285617113ecac4a84,bf5a93d16fb71cdeb87f589732b6f95f4a83fbe0,8cfcb3bedd8fea4429d628ad4fcac3764a49b4ac..da0b805493b9e7cd4c26f027a9f24c823109850a
   #include "quote.h"
   #include "remote.h"
   #include "worktree.h"
 ++#include "parse-options.h"
   
   static int config_fetch_recurse_submodules = RECURSE_SUBMODULES_ON_DEMAND;
 --static int config_update_recurse_submodules = RECURSE_SUBMODULES_DEFAULT;
 ++static int config_update_recurse_submodules = RECURSE_SUBMODULES_OFF;
   static int parallel_jobs = 1;
  -static struct string_list changed_submodule_paths = STRING_LIST_INIT_NODUP;
  +static struct string_list changed_submodule_paths = STRING_LIST_INIT_DUP;
   static int initialized_fetch_ref_tips;
   static struct oid_array ref_tips_before_fetch;
   static struct oid_array ref_tips_after_fetch;
Simple merge
Simple merge
diff --cc transport.c
Simple merge
diff --cc unpack-trees.c
Simple merge
diff --cc upload-pack.c
Simple merge
diff --cc wrapper.c
Simple merge
Simple merge