Sync with master
authorJunio C Hamano <gitster@pobox.com>
Wed, 14 Feb 2018 00:43:09 +0000 (16:43 -0800)
committerJunio C Hamano <gitster@pobox.com>
Wed, 14 Feb 2018 00:43:09 +0000 (16:43 -0800)
* master:
Second batch for 2.17

92 files changed:
Documentation/git-daemon.txt
Documentation/git-rebase.txt
Documentation/gitignore.txt
Documentation/technical/api-object-access.txt
Makefile
apply.c
blame.c
builtin/am.c
builtin/checkout.c
builtin/commit-tree.c
builtin/commit.c
builtin/fsck.c
builtin/hash-object.c
builtin/index-pack.c
builtin/log.c
builtin/merge.c
builtin/mktag.c
builtin/mktree.c
builtin/notes.c
builtin/pack-objects.c
builtin/pull.c
builtin/rebase--helper.c
builtin/receive-pack.c
builtin/replace.c
builtin/reset.c
builtin/tag.c
builtin/unpack-objects.c
builtin/worktree.c
bulk-checkin.c
cache-tree.c
cache.h
commit.c
commit.h
contrib/coccinelle/strbuf.cocci
convert.c
csum-file.c
csum-file.h
daemon.c
diff-lib.c
diffcore-rename.c
dir.c
dir.h
fast-import.c
fsmonitor.c
fsmonitor.h
git-rebase--am.sh
git-rebase--interactive.sh
git-rebase--merge.sh
git-rebase.sh
hash.h
log-tree.c
match-trees.c
merge-recursive.c
name-hash.c
notes-cache.c
notes-merge.c
notes-utils.c
notes-utils.h
notes.c
notes.h
pack-bitmap-write.c
pack-check.c
pack-write.c
pack.h
packfile.c
preload-index.c
read-cache.c
refs/packed-backend.c
sequencer.c
sha1-lookup.c
sha1-lookup.h
sha1_file.c
sha1dc_git.h
t/helper/test-dump-untracked-cache.c
t/helper/test-wildmatch.c
t/perf/aggregate.perl
t/t3070-wildmatch.sh
t/t3405-rebase-malformed.sh
t/t3501-revert-cherry-pick.sh
t/t4001-diff-rename.sh
t/t4052-stat-output.sh
t/t5510-fetch.sh
t/t5536-fetch-conflicts.sh
t/t5541-http-push-smart.sh
t/t5812-proto-disable-http.sh
t/t6022-merge-rename.sh
t/t7063-status-untracked-cache.sh
t/t7519-status-fsmonitor.sh
t/t7607-merge-overwrite.sh
t/test-lib-functions.sh
t/test-lib.sh
unpack-trees.c
index 3c91db7bed038f7ba28a4e7554cc6e63c5d91958..56d54a489875652e754f7cd16ee5a77c2f5e5202 100644 (file)
@@ -20,6 +20,7 @@ SYNOPSIS
             [--inetd |
              [--listen=<host_or_ipaddr>] [--port=<n>]
              [--user=<user> [--group=<group>]]]
+            [--log-destination=(stderr|syslog|none)]
             [<directory>...]
 
 DESCRIPTION
@@ -80,7 +81,8 @@ OPTIONS
        do not have the 'git-daemon-export-ok' file.
 
 --inetd::
-       Have the server run as an inetd service. Implies --syslog.
+       Have the server run as an inetd service. Implies --syslog (may be
+       overridden with `--log-destination=`).
        Incompatible with --detach, --port, --listen, --user and --group
        options.
 
@@ -110,8 +112,28 @@ OPTIONS
        zero for no limit.
 
 --syslog::
-       Log to syslog instead of stderr. Note that this option does not imply
-       --verbose, thus by default only error conditions will be logged.
+       Short for `--log-destination=syslog`.
+
+--log-destination=<destination>::
+       Send log messages to the specified destination.
+       Note that this option does not imply --verbose,
+       thus by default only error conditions will be logged.
+       The <destination> must be one of:
++
+--
+stderr::
+       Write to standard error.
+       Note that if `--detach` is specified,
+       the process disconnects from the real standard error,
+       making this destination effectively equivalent to `none`.
+syslog::
+       Write to syslog, using the `git-daemon` identifier.
+none::
+       Disable all logging.
+--
++
+The default destination is `syslog` if `--inetd` or `--detach` is specified,
+otherwise `stderr`.
 
 --user-path::
 --user-path=<path>::
index 8a861c1e0d69eda71fa2eec791e67c136b63b177..d713951b86abaa3fbea48703f87cce5cf0330019 100644 (file)
@@ -244,6 +244,11 @@ leave out at most one of A and B, in which case it defaults to HEAD.
        Keep the commits that do not change anything from its
        parents in the result.
 
+--allow-empty-message::
+       By default, rebasing commits with an empty message will fail.
+       This option overrides that behavior, allowing commits with empty
+       messages to be rebased.
+
 --skip::
        Restart the rebasing process by skipping the current patch.
 
index 63260f0056491308cb35677917530a987c21c8a2..ff5d7f9ed6f089646807f93d59e35a10763e46c2 100644 (file)
@@ -102,12 +102,11 @@ PATTERN FORMAT
    (relative to the toplevel of the work tree if not from a
    `.gitignore` file).
 
- - Otherwise, Git treats the pattern as a shell glob suitable
-   for consumption by fnmatch(3) with the FNM_PATHNAME flag:
-   wildcards in the pattern will not match a / in the pathname.
-   For example, "Documentation/{asterisk}.html" matches
-   "Documentation/git.html" but not "Documentation/ppc/ppc.html"
-   or "tools/perf/Documentation/perf.html".
+ - Otherwise, Git treats the pattern as a shell glob: "`*`" matches
+   anything except "`/`", "`?`" matches any one character except "`/`"
+   and "`[]`" matches one character in a selected range. See
+   fnmatch(3) and the FNM_PATHNAME flag for a more detailed
+   description.
 
  - A leading slash matches the beginning of the pathname.
    For example, "/{asterisk}.c" matches "cat-file.c" but not
index 03bb0e950dd1616b00f950f83263835c57bfa70a..a1162e5bcd19ba509fff39bceca49e1b33e2add2 100644 (file)
@@ -7,7 +7,7 @@ Talk about <sha1_file.c> and <object.h> family, things like
 * read_object_with_reference()
 * has_sha1_file()
 * write_sha1_file()
-* pretend_sha1_file()
+* pretend_object_file()
 * lookup_{object,commit,tag,blob,tree}
 * parse_{object,commit,tag,blob,tree}
 * Use of object flags
index 5bcd83ddf32707f8b98f650fd08d8eac5edf14af..c56fdc14ca154b7d80541569d9abf700ea419499 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1513,7 +1513,9 @@ else
        LIB_OBJS += sha1dc_git.o
 ifdef DC_SHA1_EXTERNAL
        ifdef DC_SHA1_SUBMODULE
+               ifneq ($(DC_SHA1_SUBMODULE),auto)
 $(error Only set DC_SHA1_EXTERNAL or DC_SHA1_SUBMODULE, not both)
+               endif
        endif
        BASIC_CFLAGS += -DDC_SHA1_EXTERNAL
        EXTLIBS += -lsha1detectcoll
@@ -2668,6 +2670,21 @@ dist: git-archive$(X) configure
                $(GIT_TARNAME)/configure \
                $(GIT_TARNAME)/version \
                $(GIT_TARNAME)/git-gui/version
+ifdef DC_SHA1_SUBMODULE
+       @mkdir -p $(GIT_TARNAME)/sha1collisiondetection/lib
+       @cp sha1collisiondetection/LICENSE.txt \
+               $(GIT_TARNAME)/sha1collisiondetection/
+       @cp sha1collisiondetection/LICENSE.txt \
+               $(GIT_TARNAME)/sha1collisiondetection/
+       @cp sha1collisiondetection/lib/sha1.[ch] \
+               $(GIT_TARNAME)/sha1collisiondetection/lib/
+       @cp sha1collisiondetection/lib/ubc_check.[ch] \
+               $(GIT_TARNAME)/sha1collisiondetection/lib/
+       $(TAR) rf $(GIT_TARNAME).tar \
+               $(GIT_TARNAME)/sha1collisiondetection/LICENSE.txt \
+               $(GIT_TARNAME)/sha1collisiondetection/lib/sha1.[ch] \
+               $(GIT_TARNAME)/sha1collisiondetection/lib/ubc_check.[ch]
+endif
        @$(RM) -r $(GIT_TARNAME)
        gzip -f -9 $(GIT_TARNAME).tar
 
diff --git a/apply.c b/apply.c
index f8b67bfee2c39cc3fbebb7a3c72dfb9cb4fcb56f..40a368b3153f90ff0061894d0af5db5b401a00d9 100644 (file)
--- a/apply.c
+++ b/apply.c
@@ -3154,7 +3154,7 @@ static int apply_binary(struct apply_state *state,
                 * See if the old one matches what the patch
                 * applies to.
                 */
-               hash_sha1_file(img->buf, img->len, blob_type, oid.hash);
+               hash_object_file(img->buf, img->len, blob_type, &oid);
                if (strcmp(oid_to_hex(&oid), patch->old_sha1_prefix))
                        return error(_("the patch applies to '%s' (%s), "
                                       "which does not match the "
@@ -3199,7 +3199,7 @@ static int apply_binary(struct apply_state *state,
                                     name);
 
                /* verify that the result matches */
-               hash_sha1_file(img->buf, img->len, blob_type, oid.hash);
+               hash_object_file(img->buf, img->len, blob_type, &oid);
                if (strcmp(oid_to_hex(&oid), patch->new_sha1_prefix))
                        return error(_("binary patch to '%s' creates incorrect result (expecting %s, got %s)"),
                                name, patch->new_sha1_prefix, oid_to_hex(&oid));
@@ -3554,7 +3554,7 @@ static int try_threeway(struct apply_state *state,
 
        /* Preimage the patch was prepared for */
        if (patch->is_new)
-               write_sha1_file("", 0, blob_type, pre_oid.hash);
+               write_object_file("", 0, blob_type, &pre_oid);
        else if (get_oid(patch->old_sha1_prefix, &pre_oid) ||
                 read_blob_object(&buf, &pre_oid, patch->old_mode))
                return error(_("repository lacks the necessary blob to fall back on 3-way merge."));
@@ -3570,7 +3570,7 @@ static int try_threeway(struct apply_state *state,
                return -1;
        }
        /* post_oid is theirs */
-       write_sha1_file(tmp_image.buf, tmp_image.len, blob_type, post_oid.hash);
+       write_object_file(tmp_image.buf, tmp_image.len, blob_type, &post_oid);
        clear_image(&tmp_image);
 
        /* our_oid is ours */
@@ -3583,7 +3583,7 @@ static int try_threeway(struct apply_state *state,
                        return error(_("cannot read the current contents of '%s'"),
                                     patch->old_name);
        }
-       write_sha1_file(tmp_image.buf, tmp_image.len, blob_type, our_oid.hash);
+       write_object_file(tmp_image.buf, tmp_image.len, blob_type, &our_oid);
        clear_image(&tmp_image);
 
        /* in-core three-way merge between post and our using pre as base */
@@ -4291,7 +4291,7 @@ static int add_index_file(struct apply_state *state,
                        }
                        fill_stat_cache_info(ce, &st);
                }
-               if (write_sha1_file(buf, size, blob_type, ce->oid.hash) < 0) {
+               if (write_object_file(buf, size, blob_type, &ce->oid) < 0) {
                        free(ce);
                        return error(_("unable to create backing store "
                                       "for newly created file %s"), path);
diff --git a/blame.c b/blame.c
index 2893f3c1030aab91a42ff9e0daf8a54ba8c3ef3c..1fc22b304b0c725c42b70d6baa00bd90d03bb37c 100644 (file)
--- a/blame.c
+++ b/blame.c
@@ -232,7 +232,7 @@ static struct commit *fake_working_tree_commit(struct diff_options *opt,
        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);
+       pretend_object_file(buf.buf, buf.len, OBJ_BLOB, &origin->blob_oid);
 
        /*
         * Read the current index, replace the path entry with
index 5bdd2d75781076636f93800520e9ed161295724f..6661edc162b770d40c62f3a03b7c0e59cb47ca51 100644 (file)
@@ -1641,8 +1641,8 @@ static void do_commit(const struct am_state *state)
                setenv("GIT_COMMITTER_DATE",
                        state->ignore_date ? "" : state->author_date, 1);
 
-       if (commit_tree(state->msg, state->msg_len, tree.hash, parents, commit.hash,
-                               author, state->sign_commit))
+       if (commit_tree(state->msg, state->msg_len, &tree, parents, &commit,
+                       author, state->sign_commit))
                die(_("failed to write commit object"));
 
        reflog_msg = getenv("GIT_REFLOG_ACTION");
index c54c78df547c8c66377f023730958f7a95d3aea1..191b96c49ca2c327805f6ff19b5385b2f49bdc93 100644 (file)
@@ -227,8 +227,7 @@ static int checkout_merged(int pos, const struct checkout *state)
         * (it also writes the merge result to the object database even
         * when it may contain conflicts).
         */
-       if (write_sha1_file(result_buf.ptr, result_buf.size,
-                           blob_type, oid.hash))
+       if (write_object_file(result_buf.ptr, result_buf.size, blob_type, &oid))
                die(_("Unable to add merge result for '%s'"), path);
        free(result_buf.ptr);
        ce = make_cache_entry(mode, oid.hash, path, 2, 0);
index 2177251e247cc144d6ac8619fa5940262430d50a..e5bdf57b1e14cf54916c7eef077e63edddb28901 100644 (file)
@@ -117,8 +117,8 @@ int cmd_commit_tree(int argc, const char **argv, const char *prefix)
                        die_errno("git commit-tree: failed to read");
        }
 
-       if (commit_tree(buffer.buf, buffer.len, tree_oid.hash, parents,
-                       commit_oid.hash, NULL, sign_commit)) {
+       if (commit_tree(buffer.buf, buffer.len, &tree_oid, parents, &commit_oid,
+                       NULL, sign_commit)) {
                strbuf_release(&buffer);
                return 1;
        }
index 5dd766af2842dddb80d30cd73b8be8ccb4956eac..e8e8d13be4016e94014e98bcbe3489fad373d204 100644 (file)
@@ -1579,8 +1579,9 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
                append_merge_tag_headers(parents, &tail);
        }
 
-       if (commit_tree_extended(sb.buf, sb.len, active_cache_tree->oid.hash,
-                        parents, oid.hash, author_ident.buf, sign_commit, extra)) {
+       if (commit_tree_extended(sb.buf, sb.len, &active_cache_tree->oid,
+                                parents, &oid, author_ident.buf, sign_commit,
+                                extra)) {
                rollback_index_files();
                die(_("failed to write commit object"));
        }
index 7a8a679d4f3d0cf6d95991927947cbd00359868c..9981db22637c027019c206583f24dc2b665deeff 100644 (file)
@@ -180,7 +180,13 @@ static void mark_object_reachable(struct object *obj)
 
 static int traverse_one_object(struct object *obj)
 {
-       return fsck_walk(obj, obj, &fsck_walk_options);
+       int result = fsck_walk(obj, obj, &fsck_walk_options);
+
+       if (obj->type == OBJ_TREE) {
+               struct tree *tree = (struct tree *)obj;
+               free_tree_buffer(tree);
+       }
+       return result;
 }
 
 static int traverse_reachable(void)
index c532ff9320c751d1db5475add51f2c3c6a8c7146..526da5c1856ed1c387975a767f4d01382d1ea1a9 100644 (file)
@@ -24,7 +24,8 @@ static int hash_literally(struct object_id *oid, int fd, const char *type, unsig
        if (strbuf_read(&buf, fd, 4096) < 0)
                ret = -1;
        else
-               ret = hash_sha1_file_literally(buf.buf, buf.len, type, oid, flags);
+               ret = hash_object_file_literally(buf.buf, buf.len, type, oid,
+                                                flags);
        strbuf_release(&buf);
        return ret;
 }
index 5ebd370c56d2611494868ad1cf5957b5e9ea636e..7e3e1a461c4469ea0272d9545d7173e984b1ebf4 100644 (file)
@@ -91,7 +91,7 @@ static unsigned int input_offset, input_len;
 static off_t consumed_bytes;
 static off_t max_input_size;
 static unsigned deepest_delta;
-static git_SHA_CTX input_ctx;
+static git_hash_ctx input_ctx;
 static uint32_t input_crc32;
 static int input_fd, output_fd;
 static const char *curr_pack;
@@ -253,7 +253,7 @@ static void flush(void)
        if (input_offset) {
                if (output_fd >= 0)
                        write_or_die(output_fd, input_buffer, input_offset);
-               git_SHA1_Update(&input_ctx, input_buffer, input_offset);
+               the_hash_algo->update_fn(&input_ctx, input_buffer, input_offset);
                memmove(input_buffer, input_buffer + input_offset, input_len);
                input_offset = 0;
        }
@@ -326,7 +326,7 @@ static const char *open_pack_file(const char *pack_name)
                output_fd = -1;
                nothread_data.pack_fd = input_fd;
        }
-       git_SHA1_Init(&input_ctx);
+       the_hash_algo->init_fn(&input_ctx);
        return pack_name;
 }
 
@@ -437,22 +437,22 @@ static int is_delta_type(enum object_type type)
 }
 
 static void *unpack_entry_data(off_t offset, unsigned long size,
-                              enum object_type type, unsigned char *sha1)
+                              enum object_type type, struct object_id *oid)
 {
        static char fixed_buf[8192];
        int status;
        git_zstream stream;
        void *buf;
-       git_SHA_CTX c;
+       git_hash_ctx c;
        char hdr[32];
        int hdrlen;
 
        if (!is_delta_type(type)) {
                hdrlen = xsnprintf(hdr, sizeof(hdr), "%s %lu", typename(type), size) + 1;
-               git_SHA1_Init(&c);
-               git_SHA1_Update(&c, hdr, hdrlen);
+               the_hash_algo->init_fn(&c);
+               the_hash_algo->update_fn(&c, hdr, hdrlen);
        } else
-               sha1 = NULL;
+               oid = NULL;
        if (type == OBJ_BLOB && size > big_file_threshold)
                buf = fixed_buf;
        else
@@ -469,8 +469,8 @@ static void *unpack_entry_data(off_t offset, unsigned long size,
                stream.avail_in = input_len;
                status = git_inflate(&stream, 0);
                use(input_len - stream.avail_in);
-               if (sha1)
-                       git_SHA1_Update(&c, last_out, stream.next_out - last_out);
+               if (oid)
+                       the_hash_algo->update_fn(&c, last_out, stream.next_out - last_out);
                if (buf == fixed_buf) {
                        stream.next_out = buf;
                        stream.avail_out = sizeof(fixed_buf);
@@ -479,15 +479,15 @@ static void *unpack_entry_data(off_t offset, unsigned long size,
        if (stream.total_out != size || status != Z_STREAM_END)
                bad_object(offset, _("inflate returned %d"), status);
        git_inflate_end(&stream);
-       if (sha1)
-               git_SHA1_Final(sha1, &c);
+       if (oid)
+               the_hash_algo->final_fn(oid->hash, &c);
        return buf == fixed_buf ? NULL : buf;
 }
 
 static void *unpack_raw_entry(struct object_entry *obj,
                              off_t *ofs_offset,
-                             unsigned char *ref_sha1,
-                             unsigned char *sha1)
+                             struct object_id *ref_oid,
+                             struct object_id *oid)
 {
        unsigned char *p;
        unsigned long size, c;
@@ -515,8 +515,8 @@ static void *unpack_raw_entry(struct object_entry *obj,
 
        switch (obj->type) {
        case OBJ_REF_DELTA:
-               hashcpy(ref_sha1, fill(20));
-               use(20);
+               hashcpy(ref_oid->hash, fill(the_hash_algo->rawsz));
+               use(the_hash_algo->rawsz);
                break;
        case OBJ_OFS_DELTA:
                p = fill(1);
@@ -546,7 +546,7 @@ static void *unpack_raw_entry(struct object_entry *obj,
        }
        obj->hdr_size = consumed_bytes - obj->idx.offset;
 
-       data = unpack_entry_data(obj->idx.offset, obj->size, obj->type, sha1);
+       data = unpack_entry_data(obj->idx.offset, obj->size, obj->type, oid);
        obj->idx.crc32 = input_crc32;
        return data;
 }
@@ -958,9 +958,8 @@ static void resolve_delta(struct object_entry *delta_obj,
        free(delta_data);
        if (!result->data)
                bad_object(delta_obj->idx.offset, _("failed to apply delta"));
-       hash_sha1_file(result->data, result->size,
-                      typename(delta_obj->real_type),
-                      delta_obj->idx.oid.hash);
+       hash_object_file(result->data, result->size,
+                        typename(delta_obj->real_type), &delta_obj->idx.oid);
        sha1_object(result->data, NULL, result->size, delta_obj->real_type,
                    &delta_obj->idx.oid);
        counter_lock();
@@ -1119,11 +1118,11 @@ static void *threaded_second_pass(void *data)
  * - calculate SHA1 of all non-delta objects;
  * - remember base (SHA1 or offset) for all deltas.
  */
-static void parse_pack_objects(unsigned char *sha1)
+static void parse_pack_objects(unsigned char *hash)
 {
        int i, nr_delays = 0;
        struct ofs_delta_entry *ofs_delta = ofs_deltas;
-       unsigned char ref_delta_sha1[20];
+       struct object_id ref_delta_oid;
        struct stat st;
 
        if (verbose)
@@ -1133,8 +1132,8 @@ static void parse_pack_objects(unsigned char *sha1)
        for (i = 0; i < nr_objects; i++) {
                struct object_entry *obj = &objects[i];
                void *data = unpack_raw_entry(obj, &ofs_delta->offset,
-                                             ref_delta_sha1,
-                                             obj->idx.oid.hash);
+                                             &ref_delta_oid,
+                                             &obj->idx.oid);
                obj->real_type = obj->type;
                if (obj->type == OBJ_OFS_DELTA) {
                        nr_ofs_deltas++;
@@ -1142,7 +1141,7 @@ static void parse_pack_objects(unsigned char *sha1)
                        ofs_delta++;
                } else if (obj->type == OBJ_REF_DELTA) {
                        ALLOC_GROW(ref_deltas, nr_ref_deltas + 1, ref_deltas_alloc);
-                       hashcpy(ref_deltas[nr_ref_deltas].sha1, ref_delta_sha1);
+                       hashcpy(ref_deltas[nr_ref_deltas].sha1, ref_delta_oid.hash);
                        ref_deltas[nr_ref_deltas].obj_no = i;
                        nr_ref_deltas++;
                } else if (!data) {
@@ -1160,10 +1159,10 @@ static void parse_pack_objects(unsigned char *sha1)
 
        /* Check pack integrity */
        flush();
-       git_SHA1_Final(sha1, &input_ctx);
-       if (hashcmp(fill(20), sha1))
+       the_hash_algo->final_fn(hash, &input_ctx);
+       if (hashcmp(fill(the_hash_algo->rawsz), hash))
                die(_("pack is corrupted (SHA1 mismatch)"));
-       use(20);
+       use(the_hash_algo->rawsz);
 
        /* If input_fd is a file, we should have reached its end now. */
        if (fstat(input_fd, &st))
@@ -1239,21 +1238,21 @@ static void resolve_deltas(void)
 /*
  * Third pass:
  * - append objects to convert thin pack to full pack if required
- * - write the final 20-byte SHA-1
+ * - write the final pack hash
  */
-static void fix_unresolved_deltas(struct sha1file *f);
-static void conclude_pack(int fix_thin_pack, const char *curr_pack, unsigned char *pack_sha1)
+static void fix_unresolved_deltas(struct hashfile *f);
+static void conclude_pack(int fix_thin_pack, const char *curr_pack, unsigned char *pack_hash)
 {
        if (nr_ref_deltas + nr_ofs_deltas == nr_resolved_deltas) {
                stop_progress(&progress);
-               /* Flush remaining pack final 20-byte SHA1. */
+               /* Flush remaining pack final hash. */
                flush();
                return;
        }
 
        if (fix_thin_pack) {
-               struct sha1file *f;
-               unsigned char read_sha1[20], tail_sha1[20];
+               struct hashfile *f;
+               unsigned char read_hash[GIT_MAX_RAWSZ], tail_hash[GIT_MAX_RAWSZ];
                struct strbuf msg = STRBUF_INIT;
                int nr_unresolved = nr_ofs_deltas + nr_ref_deltas - nr_resolved_deltas;
                int nr_objects_initial = nr_objects;
@@ -1262,7 +1261,7 @@ static void conclude_pack(int fix_thin_pack, const char *curr_pack, unsigned cha
                REALLOC_ARRAY(objects, nr_objects + nr_unresolved + 1);
                memset(objects + nr_objects + 1, 0,
                       nr_unresolved * sizeof(*objects));
-               f = sha1fd(output_fd, curr_pack);
+               f = hashfd(output_fd, curr_pack);
                fix_unresolved_deltas(f);
                strbuf_addf(&msg, Q_("completed with %d local object",
                                     "completed with %d local objects",
@@ -1270,12 +1269,12 @@ static void conclude_pack(int fix_thin_pack, const char *curr_pack, unsigned cha
                            nr_objects - nr_objects_initial);
                stop_progress_msg(&progress, msg.buf);
                strbuf_release(&msg);
-               sha1close(f, tail_sha1, 0);
-               hashcpy(read_sha1, pack_sha1);
-               fixup_pack_header_footer(output_fd, pack_sha1,
+               hashclose(f, tail_hash, 0);
+               hashcpy(read_hash, pack_hash);
+               fixup_pack_header_footer(output_fd, pack_hash,
                                         curr_pack, nr_objects,
-                                        read_sha1, consumed_bytes-20);
-               if (hashcmp(read_sha1, tail_sha1) != 0)
+                                        read_hash, consumed_bytes-the_hash_algo->rawsz);
+               if (hashcmp(read_hash, tail_hash) != 0)
                        die(_("Unexpected tail checksum for %s "
                              "(disk corruption?)"), curr_pack);
        }
@@ -1286,7 +1285,7 @@ static void conclude_pack(int fix_thin_pack, const char *curr_pack, unsigned cha
                    nr_ofs_deltas + nr_ref_deltas - nr_resolved_deltas);
 }
 
-static int write_compressed(struct sha1file *f, void *in, unsigned int size)
+static int write_compressed(struct hashfile *f, void *in, unsigned int size)
 {
        git_zstream stream;
        int status;
@@ -1300,7 +1299,7 @@ static int write_compressed(struct sha1file *f, void *in, unsigned int size)
                stream.next_out = outbuf;
                stream.avail_out = sizeof(outbuf);
                status = git_deflate(&stream, Z_FINISH);
-               sha1write(f, outbuf, sizeof(outbuf) - stream.avail_out);
+               hashwrite(f, outbuf, sizeof(outbuf) - stream.avail_out);
        } while (status == Z_OK);
 
        if (status != Z_STREAM_END)
@@ -1310,7 +1309,7 @@ static int write_compressed(struct sha1file *f, void *in, unsigned int size)
        return size;
 }
 
-static struct object_entry *append_obj_to_pack(struct sha1file *f,
+static struct object_entry *append_obj_to_pack(struct hashfile *f,
                               const unsigned char *sha1, void *buf,
                               unsigned long size, enum object_type type)
 {
@@ -1327,7 +1326,7 @@ static struct object_entry *append_obj_to_pack(struct sha1file *f,
        }
        header[n++] = c;
        crc32_begin(f);
-       sha1write(f, header, n);
+       hashwrite(f, header, n);
        obj[0].size = size;
        obj[0].hdr_size = n;
        obj[0].type = type;
@@ -1335,7 +1334,7 @@ static struct object_entry *append_obj_to_pack(struct sha1file *f,
        obj[1].idx.offset = obj[0].idx.offset + n;
        obj[1].idx.offset += write_compressed(f, buf, size);
        obj[0].idx.crc32 = crc32_end(f);
-       sha1flush(f);
+       hashflush(f);
        hashcpy(obj->idx.oid.hash, sha1);
        return obj;
 }
@@ -1347,7 +1346,7 @@ static int delta_pos_compare(const void *_a, const void *_b)
        return a->obj_no - b->obj_no;
 }
 
-static void fix_unresolved_deltas(struct sha1file *f)
+static void fix_unresolved_deltas(struct hashfile *f)
 {
        struct ref_delta_entry **sorted_by_pos;
        int i;
@@ -1403,7 +1402,7 @@ static const char *derive_filename(const char *pack_name, const char *suffix,
 }
 
 static void write_special_file(const char *suffix, const char *msg,
-                              const char *pack_name, const unsigned char *sha1,
+                              const char *pack_name, const unsigned char *hash,
                               const char **report)
 {
        struct strbuf name_buf = STRBUF_INIT;
@@ -1414,7 +1413,7 @@ static void write_special_file(const char *suffix, const char *msg,
        if (pack_name)
                filename = derive_filename(pack_name, suffix, &name_buf);
        else
-               filename = odb_pack_name(&name_buf, sha1, suffix);
+               filename = odb_pack_name(&name_buf, hash, suffix);
 
        fd = odb_pack_keep(filename);
        if (fd < 0) {
@@ -1438,7 +1437,7 @@ static void write_special_file(const char *suffix, const char *msg,
 static void final(const char *final_pack_name, const char *curr_pack_name,
                  const char *final_index_name, const char *curr_index_name,
                  const char *keep_msg, const char *promisor_msg,
-                 unsigned char *sha1)
+                 unsigned char *hash)
 {
        const char *report = "pack";
        struct strbuf pack_name = STRBUF_INIT;
@@ -1455,15 +1454,15 @@ static void final(const char *final_pack_name, const char *curr_pack_name,
        }
 
        if (keep_msg)
-               write_special_file("keep", keep_msg, final_pack_name, sha1,
+               write_special_file("keep", keep_msg, final_pack_name, hash,
                                   &report);
        if (promisor_msg)
                write_special_file("promisor", promisor_msg, final_pack_name,
-                                  sha1, NULL);
+                                  hash, NULL);
 
        if (final_pack_name != curr_pack_name) {
                if (!final_pack_name)
-                       final_pack_name = odb_pack_name(&pack_name, sha1, "pack");
+                       final_pack_name = odb_pack_name(&pack_name, hash, "pack");
                if (finalize_object_file(curr_pack_name, final_pack_name))
                        die(_("cannot store pack file"));
        } else if (from_stdin)
@@ -1471,18 +1470,18 @@ static void final(const char *final_pack_name, const char *curr_pack_name,
 
        if (final_index_name != curr_index_name) {
                if (!final_index_name)
-                       final_index_name = odb_pack_name(&index_name, sha1, "idx");
+                       final_index_name = odb_pack_name(&index_name, hash, "idx");
                if (finalize_object_file(curr_index_name, final_index_name))
                        die(_("cannot store index file"));
        } else
                chmod(final_index_name, 0444);
 
        if (!from_stdin) {
-               printf("%s\n", sha1_to_hex(sha1));
+               printf("%s\n", sha1_to_hex(hash));
        } else {
                struct strbuf buf = STRBUF_INIT;
 
-               strbuf_addf(&buf, "%s\t%s\n", report, sha1_to_hex(sha1));
+               strbuf_addf(&buf, "%s\t%s\n", report, sha1_to_hex(hash));
                write_or_die(1, buf.buf, buf.len);
                strbuf_release(&buf);
 
@@ -1653,7 +1652,7 @@ int cmd_index_pack(int argc, const char **argv, const char *prefix)
        struct strbuf index_name_buf = STRBUF_INIT;
        struct pack_idx_entry **idx_objects;
        struct pack_idx_option opts;
-       unsigned char pack_sha1[20];
+       unsigned char pack_hash[GIT_MAX_RAWSZ];
        unsigned foreign_nr = 1;        /* zero is a "good" value, assume bad */
        int report_end_of_input = 0;
 
@@ -1790,11 +1789,11 @@ int cmd_index_pack(int argc, const char **argv, const char *prefix)
        if (show_stat)
                obj_stat = xcalloc(st_add(nr_objects, 1), sizeof(struct object_stat));
        ofs_deltas = xcalloc(nr_objects, sizeof(struct ofs_delta_entry));
-       parse_pack_objects(pack_sha1);
+       parse_pack_objects(pack_hash);
        if (report_end_of_input)
                write_in_full(2, "\0", 1);
        resolve_deltas();
-       conclude_pack(fix_thin_pack, curr_pack, pack_sha1);
+       conclude_pack(fix_thin_pack, curr_pack, pack_hash);
        free(ofs_deltas);
        free(ref_deltas);
        if (strict)
@@ -1806,14 +1805,14 @@ int cmd_index_pack(int argc, const char **argv, const char *prefix)
        ALLOC_ARRAY(idx_objects, nr_objects);
        for (i = 0; i < nr_objects; i++)
                idx_objects[i] = &objects[i].idx;
-       curr_index = write_idx_file(index_name, idx_objects, nr_objects, &opts, pack_sha1);
+       curr_index = write_idx_file(index_name, idx_objects, nr_objects, &opts, pack_hash);
        free(idx_objects);
 
        if (!verify)
                final(pack_name, curr_pack,
                      index_name, curr_index,
                      keep_msg, promisor_msg,
-                     pack_sha1);
+                     pack_hash);
        else
                close(input_fd);
        free(objects);
index 46b4ca13e5c11ff43c15d80e618914e671ff17a0..94ee177d56d6ff9c82b02ebfb2d27cf789527974 100644 (file)
@@ -29,6 +29,8 @@
 #include "gpg-interface.h"
 #include "progress.h"
 
+#define MAIL_DEFAULT_WRAP 72
+
 /* Set a default date-time format for git log ("log.date" config variable) */
 static const char *default_date_mode = NULL;
 
@@ -1044,7 +1046,7 @@ static void make_cover_letter(struct rev_info *rev, int use_stdout,
 
        shortlog_init(&log);
        log.wrap_lines = 1;
-       log.wrap = 72;
+       log.wrap = MAIL_DEFAULT_WRAP;
        log.in1 = 2;
        log.in2 = 4;
        log.file = rev->diffopt.file;
@@ -1061,6 +1063,7 @@ static void make_cover_letter(struct rev_info *rev, int use_stdout,
 
        memcpy(&opts, &rev->diffopt, sizeof(opts));
        opts.output_format = DIFF_FORMAT_SUMMARY | DIFF_FORMAT_DIFFSTAT;
+       opts.stat_width = MAIL_DEFAULT_WRAP;
 
        diff_setup_done(&opts);
 
@@ -1614,6 +1617,8 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
                (!rev.diffopt.output_format ||
                 rev.diffopt.output_format == DIFF_FORMAT_PATCH))
                rev.diffopt.output_format = DIFF_FORMAT_DIFFSTAT | DIFF_FORMAT_SUMMARY;
+       if (!rev.diffopt.stat_width)
+               rev.diffopt.stat_width = MAIL_DEFAULT_WRAP;
 
        /* Always generate a patch */
        rev.diffopt.output_format |= DIFF_FORMAT_PATCH;
index 30264cfd7c1720aee814699eb3ca057e292b082d..92ba99a1a5efff8598251c2ed806bae12832ae0a 100644 (file)
@@ -820,8 +820,8 @@ static int merge_trivial(struct commit *head, struct commit_list *remoteheads)
        pptr = commit_list_append(head, pptr);
        pptr = commit_list_append(remoteheads->item, pptr);
        prepare_to_commit(remoteheads);
-       if (commit_tree(merge_msg.buf, merge_msg.len, result_tree.hash, parents,
-                       result_commit.hash, NULL, sign_commit))
+       if (commit_tree(merge_msg.buf, merge_msg.len, &result_tree, parents,
+                       &result_commit, NULL, sign_commit))
                die(_("failed to write commit object"));
        finish(head, remoteheads, &result_commit, "In-index merge");
        drop_save();
@@ -845,8 +845,8 @@ static int finish_automerge(struct commit *head,
                commit_list_insert(head, &parents);
        strbuf_addch(&merge_msg, '\n');
        prepare_to_commit(remoteheads);
-       if (commit_tree(merge_msg.buf, merge_msg.len, result_tree->hash, parents,
-                       result_commit.hash, NULL, sign_commit))
+       if (commit_tree(merge_msg.buf, merge_msg.len, result_tree, parents,
+                       &result_commit, NULL, sign_commit))
                die(_("failed to write commit object"));
        strbuf_addf(&buf, "Merge made by the '%s' strategy.", wt_strategy);
        finish(head, remoteheads, &result_commit, buf.buf);
index 031b750f068dea5e1652129a5df6d684f6bca850..beb552847ba1ef36c78d9d10d3ff9e98e6a288bc 100644 (file)
@@ -151,7 +151,7 @@ static int verify_tag(char *buffer, unsigned long size)
 int cmd_mktag(int argc, const char **argv, const char *prefix)
 {
        struct strbuf buf = STRBUF_INIT;
-       unsigned char result_sha1[20];
+       struct object_id result;
 
        if (argc != 1)
                usage("git mktag");
@@ -165,10 +165,10 @@ int cmd_mktag(int argc, const char **argv, const char *prefix)
        if (verify_tag(buf.buf, buf.len) < 0)
                die("invalid tag signature file");
 
-       if (write_sha1_file(buf.buf, buf.len, tag_type, result_sha1) < 0)
+       if (write_object_file(buf.buf, buf.len, tag_type, &result) < 0)
                die("unable to write tag file");
 
        strbuf_release(&buf);
-       printf("%s\n", sha1_to_hex(result_sha1));
+       printf("%s\n", oid_to_hex(&result));
        return 0;
 }
index da0fd8cd706659a8784da8112cd1b3acd306375f..8dd9f52f77329edb0e270552cab0f0c1298e7e32 100644 (file)
@@ -40,7 +40,7 @@ static int ent_compare(const void *a_, const void *b_)
                                 b->name, b->len, b->mode);
 }
 
-static void write_tree(unsigned char *sha1)
+static void write_tree(struct object_id *oid)
 {
        struct strbuf buf;
        size_t size;
@@ -57,7 +57,7 @@ static void write_tree(unsigned char *sha1)
                strbuf_add(&buf, ent->sha1, 20);
        }
 
-       write_sha1_file(buf.buf, buf.len, tree_type, sha1);
+       write_object_file(buf.buf, buf.len, tree_type, oid);
        strbuf_release(&buf);
 }
 
@@ -142,7 +142,7 @@ static void mktree_line(char *buf, size_t len, int nul_term_line, int allow_miss
 int cmd_mktree(int ac, const char **av, const char *prefix)
 {
        struct strbuf sb = STRBUF_INIT;
-       unsigned char sha1[20];
+       struct object_id oid;
        int nul_term_line = 0;
        int allow_missing = 0;
        int is_batch_mode = 0;
@@ -181,8 +181,8 @@ int cmd_mktree(int ac, const char **av, const char *prefix)
                         */
                        ; /* skip creating an empty tree */
                } else {
-                       write_tree(sha1);
-                       puts(sha1_to_hex(sha1));
+                       write_tree(&oid);
+                       puts(oid_to_hex(&oid));
                        fflush(stdout);
                }
                used=0; /* reset tree entry buffer for re-use in batch mode */
index 7c8176164561be1d57771ad2fdeb9260cc1d8c87..39304ba743b34ad9ff73583f691c6f8d79379eb5 100644 (file)
@@ -198,9 +198,9 @@ static void prepare_note_data(const struct object_id *object, struct note_data *
        }
 }
 
-static void write_note_data(struct note_data *d, unsigned char *sha1)
+static void write_note_data(struct note_data *d, struct object_id *oid)
 {
-       if (write_sha1_file(d->buf.buf, d->buf.len, blob_type, sha1)) {
+       if (write_object_file(d->buf.buf, d->buf.len, blob_type, oid)) {
                error(_("unable to write note object"));
                if (d->edit_path)
                        error(_("the note contents have been left in %s"),
@@ -459,7 +459,7 @@ static int add(int argc, const char **argv, const char *prefix)
 
        prepare_note_data(&object, &d, note ? note->hash : NULL);
        if (d.buf.len || allow_empty) {
-               write_note_data(&d, new_note.hash);
+               write_note_data(&d, &new_note);
                if (add_note(t, &object, &new_note, combine_notes_overwrite))
                        die("BUG: combine_notes_overwrite failed");
                commit_notes(t, "Notes added by 'git notes add'");
@@ -619,7 +619,7 @@ static int append_edit(int argc, const char **argv, const char *prefix)
        }
 
        if (d.buf.len || allow_empty) {
-               write_note_data(&d, new_note.hash);
+               write_note_data(&d, &new_note);
                if (add_note(t, &object, &new_note, combine_notes_overwrite))
                        die("BUG: combine_notes_overwrite failed");
                logmsg = xstrfmt("Notes added by 'git notes %s'", argv[0]);
index 83dcbc97731d2b0feeb72289f0ffa4c623952dec..5c674b2843ccadec710596f7b8c293bbbc6130ea 100644 (file)
@@ -164,7 +164,7 @@ static unsigned long do_compress(void **pptr, unsigned long size)
        return stream.total_out;
 }
 
-static unsigned long write_large_blob_data(struct git_istream *st, struct sha1file *f,
+static unsigned long write_large_blob_data(struct git_istream *st, struct hashfile *f,
                                           const struct object_id *oid)
 {
        git_zstream stream;
@@ -188,7 +188,7 @@ static unsigned long write_large_blob_data(struct git_istream *st, struct sha1fi
                        stream.next_out = obuf;
                        stream.avail_out = sizeof(obuf);
                        zret = git_deflate(&stream, readlen ? 0 : Z_FINISH);
-                       sha1write(f, obuf, stream.next_out - obuf);
+                       hashwrite(f, obuf, stream.next_out - obuf);
                        olen += stream.next_out - obuf;
                }
                if (stream.avail_in)
@@ -233,7 +233,7 @@ static int check_pack_inflate(struct packed_git *p,
                stream.total_in == len) ? 0 : -1;
 }
 
-static void copy_pack_data(struct sha1file *f,
+static void copy_pack_data(struct hashfile *f,
                struct packed_git *p,
                struct pack_window **w_curs,
                off_t offset,
@@ -246,14 +246,14 @@ static void copy_pack_data(struct sha1file *f,
                in = use_pack(p, w_curs, offset, &avail);
                if (avail > len)
                        avail = (unsigned long)len;
-               sha1write(f, in, avail);
+               hashwrite(f, in, avail);
                offset += avail;
                len -= avail;
        }
 }
 
 /* Return 0 if we will bust the pack-size limit */
-static unsigned long write_no_reuse_object(struct sha1file *f, struct object_entry *entry,
+static unsigned long write_no_reuse_object(struct hashfile *f, struct object_entry *entry,
                                           unsigned long limit, int usable_delta)
 {
        unsigned long size, datalen;
@@ -326,8 +326,8 @@ static unsigned long write_no_reuse_object(struct sha1file *f, struct object_ent
                        free(buf);
                        return 0;
                }
-               sha1write(f, header, hdrlen);
-               sha1write(f, dheader + pos, sizeof(dheader) - pos);
+               hashwrite(f, header, hdrlen);
+               hashwrite(f, dheader + pos, sizeof(dheader) - pos);
                hdrlen += sizeof(dheader) - pos;
        } else if (type == OBJ_REF_DELTA) {
                /*
@@ -340,8 +340,8 @@ static unsigned long write_no_reuse_object(struct sha1file *f, struct object_ent
                        free(buf);
                        return 0;
                }
-               sha1write(f, header, hdrlen);
-               sha1write(f, entry->delta->idx.oid.hash, 20);
+               hashwrite(f, header, hdrlen);
+               hashwrite(f, entry->delta->idx.oid.hash, 20);
                hdrlen += 20;
        } else {
                if (limit && hdrlen + datalen + 20 >= limit) {
@@ -350,13 +350,13 @@ static unsigned long write_no_reuse_object(struct sha1file *f, struct object_ent
                        free(buf);
                        return 0;
                }
-               sha1write(f, header, hdrlen);
+               hashwrite(f, header, hdrlen);
        }
        if (st) {
                datalen = write_large_blob_data(st, f, &entry->idx.oid);
                close_istream(st);
        } else {
-               sha1write(f, buf, datalen);
+               hashwrite(f, buf, datalen);
                free(buf);
        }
 
@@ -364,7 +364,7 @@ static unsigned long write_no_reuse_object(struct sha1file *f, struct object_ent
 }
 
 /* Return 0 if we will bust the pack-size limit */
-static off_t write_reuse_object(struct sha1file *f, struct object_entry *entry,
+static off_t write_reuse_object(struct hashfile *f, struct object_entry *entry,
                                unsigned long limit, int usable_delta)
 {
        struct packed_git *p = entry->in_pack;
@@ -415,8 +415,8 @@ static off_t write_reuse_object(struct sha1file *f, struct object_entry *entry,
                        unuse_pack(&w_curs);
                        return 0;
                }
-               sha1write(f, header, hdrlen);
-               sha1write(f, dheader + pos, sizeof(dheader) - pos);
+               hashwrite(f, header, hdrlen);
+               hashwrite(f, dheader + pos, sizeof(dheader) - pos);
                hdrlen += sizeof(dheader) - pos;
                reused_delta++;
        } else if (type == OBJ_REF_DELTA) {
@@ -424,8 +424,8 @@ static off_t write_reuse_object(struct sha1file *f, struct object_entry *entry,
                        unuse_pack(&w_curs);
                        return 0;
                }
-               sha1write(f, header, hdrlen);
-               sha1write(f, entry->delta->idx.oid.hash, 20);
+               hashwrite(f, header, hdrlen);
+               hashwrite(f, entry->delta->idx.oid.hash, 20);
                hdrlen += 20;
                reused_delta++;
        } else {
@@ -433,7 +433,7 @@ static off_t write_reuse_object(struct sha1file *f, struct object_entry *entry,
                        unuse_pack(&w_curs);
                        return 0;
                }
-               sha1write(f, header, hdrlen);
+               hashwrite(f, header, hdrlen);
        }
        copy_pack_data(f, p, &w_curs, offset, datalen);
        unuse_pack(&w_curs);
@@ -442,7 +442,7 @@ static off_t write_reuse_object(struct sha1file *f, struct object_entry *entry,
 }
 
 /* Return 0 if we will bust the pack-size limit */
-static off_t write_object(struct sha1file *f,
+static off_t write_object(struct hashfile *f,
                          struct object_entry *entry,
                          off_t write_offset)
 {
@@ -515,7 +515,7 @@ enum write_one_status {
        WRITE_ONE_RECURSIVE = 2 /* already scheduled to be written */
 };
 
-static enum write_one_status write_one(struct sha1file *f,
+static enum write_one_status write_one(struct hashfile *f,
                                       struct object_entry *e,
                                       off_t *offset)
 {
@@ -734,7 +734,7 @@ static struct object_entry **compute_write_order(void)
        return wo;
 }
 
-static off_t write_reused_pack(struct sha1file *f)
+static off_t write_reused_pack(struct hashfile *f)
 {
        unsigned char buffer[8192];
        off_t to_write, total;
@@ -765,7 +765,7 @@ static off_t write_reused_pack(struct sha1file *f)
                if (read_pack > to_write)
                        read_pack = to_write;
 
-               sha1write(f, buffer, read_pack);
+               hashwrite(f, buffer, read_pack);
                to_write -= read_pack;
 
                /*
@@ -794,7 +794,7 @@ static const char no_split_warning[] = N_(
 static void write_pack_file(void)
 {
        uint32_t i = 0, j;
-       struct sha1file *f;
+       struct hashfile *f;
        off_t offset;
        uint32_t nr_remaining = nr_result;
        time_t last_mtime = 0;
@@ -810,7 +810,7 @@ static void write_pack_file(void)
                char *pack_tmp_name = NULL;
 
                if (pack_to_stdout)
-                       f = sha1fd_throughput(1, "<stdout>", progress_state);
+                       f = hashfd_throughput(1, "<stdout>", progress_state);
                else
                        f = create_tmp_packfile(&pack_tmp_name);
 
@@ -837,11 +837,11 @@ static void write_pack_file(void)
                 * If so, rewrite it like in fast-import
                 */
                if (pack_to_stdout) {
-                       sha1close(f, oid.hash, CSUM_CLOSE);
+                       hashclose(f, oid.hash, CSUM_CLOSE);
                } else if (nr_written == nr_remaining) {
-                       sha1close(f, oid.hash, CSUM_FSYNC);
+                       hashclose(f, oid.hash, CSUM_FSYNC);
                } else {
-                       int fd = sha1close(f, oid.hash, 0);
+                       int fd = hashclose(f, oid.hash, 0);
                        fixup_pack_header_footer(fd, oid.hash, pack_tmp_name,
                                                 nr_written, oid.hash, offset);
                        close(fd);
@@ -2793,7 +2793,7 @@ static void loosen_unused_packed_objects(struct rev_info *revs)
                        if (!packlist_find(&to_pack, oid.hash, NULL) &&
                            !has_sha1_pack_kept_or_nonlocal(&oid) &&
                            !loosened_object_can_be_discarded(&oid, p->mtime))
-                               if (force_object_loose(oid.hash, p->mtime))
+                               if (force_object_loose(&oid, p->mtime))
                                        die("unable to force loose object");
                }
        }
index 511dbbe0f6e25d8f0e8c6ce511cc0ff734adc9bc..1876271af9423dc58bb66d00bdd1eaa62a983dab 100644 (file)
@@ -574,6 +574,7 @@ static int rebase_submodules(void)
        cp.no_stdin = 1;
        argv_array_pushl(&cp.args, "submodule", "update",
                                   "--recursive", "--rebase", NULL);
+       argv_push_verbosity(&cp.args);
 
        return run_command(&cp);
 }
@@ -586,6 +587,7 @@ static int update_submodules(void)
        cp.no_stdin = 1;
        argv_array_pushl(&cp.args, "submodule", "update",
                                   "--recursive", "--checkout", NULL);
+       argv_push_verbosity(&cp.args);
 
        return run_command(&cp);
 }
index 00faf14d07403fedd07bfbbaf1123bea07e3e328..ad074705bb51d1de4221b3c5dfaa7229903c0ef0 100644 (file)
@@ -22,6 +22,8 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix)
        struct option options[] = {
                OPT_BOOL(0, "ff", &opts.allow_ff, N_("allow fast-forward")),
                OPT_BOOL(0, "keep-empty", &keep_empty, N_("keep empty commits")),
+               OPT_BOOL(0, "allow-empty-message", &opts.allow_empty_message,
+                       N_("allow commits with empty messages")),
                OPT_CMDMODE(0, "continue", &command, N_("continue rebase"),
                                CONTINUE),
                OPT_CMDMODE(0, "abort", &command, N_("abort rebase"),
index b7ce7c7f5275febbf6db6b71e3b610b09a4fe191..75e7f18aceffc42b5fdc58296559c67d47203098 100644 (file)
@@ -69,7 +69,7 @@ static int sent_capabilities;
 static int shallow_update;
 static const char *alt_shallow_file;
 static struct strbuf push_cert = STRBUF_INIT;
-static unsigned char push_cert_sha1[20];
+static struct object_id push_cert_oid;
 static struct signature_check sigcheck;
 static const char *push_cert_nonce;
 static const char *cert_nonce_seed;
@@ -633,8 +633,9 @@ static void prepare_push_cert_sha1(struct child_process *proc)
                int bogs /* beginning_of_gpg_sig */;
 
                already_done = 1;
-               if (write_sha1_file(push_cert.buf, push_cert.len, "blob", push_cert_sha1))
-                       hashclr(push_cert_sha1);
+               if (write_object_file(push_cert.buf, push_cert.len, "blob",
+                                     &push_cert_oid))
+                       oidclr(&push_cert_oid);
 
                memset(&sigcheck, '\0', sizeof(sigcheck));
                sigcheck.result = 'N';
@@ -655,9 +656,9 @@ static void prepare_push_cert_sha1(struct child_process *proc)
                strbuf_release(&gpg_status);
                nonce_status = check_nonce(push_cert.buf, bogs);
        }
-       if (!is_null_sha1(push_cert_sha1)) {
+       if (!is_null_oid(&push_cert_oid)) {
                argv_array_pushf(&proc->env_array, "GIT_PUSH_CERT=%s",
-                                sha1_to_hex(push_cert_sha1));
+                                oid_to_hex(&push_cert_oid));
                argv_array_pushf(&proc->env_array, "GIT_PUSH_CERT_SIGNER=%s",
                                 sigcheck.signer ? sigcheck.signer : "");
                argv_array_pushf(&proc->env_array, "GIT_PUSH_CERT_KEY=%s",
index 10078ae37136f154486d8163b6b905ad163c7047..83d3235721470167d362f64763745d8fb9852d7b 100644 (file)
@@ -355,7 +355,7 @@ static void check_one_mergetag(struct commit *commit,
        struct tag *tag;
        int i;
 
-       hash_sha1_file(extra->value, extra->len, typename(OBJ_TAG), tag_oid.hash);
+       hash_object_file(extra->value, extra->len, typename(OBJ_TAG), &tag_oid);
        tag = lookup_tag(&tag_oid);
        if (!tag)
                die(_("bad mergetag in commit '%s'"), ref);
@@ -410,7 +410,7 @@ static int create_graft(int argc, const char **argv, int force)
 
        check_mergetags(commit, argc, argv);
 
-       if (write_sha1_file(buf.buf, buf.len, commit_type, new.hash))
+       if (write_object_file(buf.buf, buf.len, commit_type, &new))
                die(_("could not write replacement commit for: '%s'"), old_ref);
 
        strbuf_release(&buf);
index e15f595799c40933e31f909715e35b4d0a665fc0..5da0f75de95cc9dc19db7d53a5e4df5140845082 100644 (file)
@@ -106,24 +106,16 @@ static int reset_index(const struct object_id *oid, int reset_type, int quiet)
 
 static void print_new_head_line(struct commit *commit)
 {
-       const char *hex, *body;
-       const char *msg;
-
-       hex = find_unique_abbrev(commit->object.oid.hash, DEFAULT_ABBREV);
-       printf(_("HEAD is now at %s"), hex);
-       msg = logmsg_reencode(commit, NULL, get_log_output_encoding());
-       body = strstr(msg, "\n\n");
-       if (body) {
-               const char *eol;
-               size_t len;
-               body = skip_blank_lines(body + 2);
-               eol = strchr(body, '\n');
-               len = eol ? eol - body : strlen(body);
-               printf(" %.*s\n", (int) len, body);
-       }
-       else
-               printf("\n");
-       unuse_commit_buffer(commit, msg);
+       struct strbuf buf = STRBUF_INIT;
+
+       printf(_("HEAD is now at %s"),
+               find_unique_abbrev(commit->object.oid.hash, DEFAULT_ABBREV));
+
+       pp_commit_easy(CMIT_FMT_ONELINE, commit, &buf);
+       if (buf.len > 0)
+               printf(" %s", buf.buf);
+       putchar('\n');
+       strbuf_release(&buf);
 }
 
 static void update_index_from_diff(struct diff_queue_struct *q,
index a7e6a5b0f234a95fb45a71d7e9aa7f0baa2b47f8..8885e21ddc81e4d2686aaeb6fe4c1bbffc916ec1 100644 (file)
@@ -187,7 +187,7 @@ static int build_tag_object(struct strbuf *buf, int sign, struct object_id *resu
 {
        if (sign && do_sign(buf) < 0)
                return error(_("unable to sign the tag"));
-       if (write_sha1_file(buf->buf, buf->len, tag_type, result->hash) < 0)
+       if (write_object_file(buf->buf, buf->len, tag_type, result) < 0)
                return error(_("unable to write tag file"));
        return 0;
 }
index 62ea264c46783374d0f1968c19ea7581498a1f87..7235d2ffbff78400384f92ea53233ec4dfbf0687 100644 (file)
@@ -21,7 +21,7 @@ static unsigned char buffer[4096];
 static unsigned int offset, len;
 static off_t consumed_bytes;
 static off_t max_input_size;
-static git_SHA_CTX ctx;
+static git_hash_ctx ctx;
 static struct fsck_options fsck_options = FSCK_OPTIONS_STRICT;
 
 /*
@@ -62,7 +62,7 @@ static void *fill(int min)
        if (min > sizeof(buffer))
                die("cannot fill %d bytes", min);
        if (offset) {
-               git_SHA1_Update(&ctx, buffer, offset);
+               the_hash_algo->update_fn(&ctx, buffer, offset);
                memmove(buffer, buffer + offset, len);
                offset = 0;
        }
@@ -172,7 +172,8 @@ static void write_cached_object(struct object *obj, struct obj_buffer *obj_buf)
 {
        struct object_id oid;
 
-       if (write_sha1_file(obj_buf->buffer, obj_buf->size, typename(obj->type), oid.hash) < 0)
+       if (write_object_file(obj_buf->buffer, obj_buf->size,
+                             typename(obj->type), &oid) < 0)
                die("failed to write object %s", oid_to_hex(&obj->oid));
        obj->flags |= FLAG_WRITTEN;
 }
@@ -237,14 +238,16 @@ static void write_object(unsigned nr, enum object_type type,
                         void *buf, unsigned long size)
 {
        if (!strict) {
-               if (write_sha1_file(buf, size, typename(type), obj_list[nr].oid.hash) < 0)
+               if (write_object_file(buf, size, typename(type),
+                                     &obj_list[nr].oid) < 0)
                        die("failed to write object");
                added_object(nr, type, buf, size);
                free(buf);
                obj_list[nr].obj = NULL;
        } else if (type == OBJ_BLOB) {
                struct blob *blob;
-               if (write_sha1_file(buf, size, typename(type), obj_list[nr].oid.hash) < 0)
+               if (write_object_file(buf, size, typename(type),
+                                     &obj_list[nr].oid) < 0)
                        die("failed to write object");
                added_object(nr, type, buf, size);
                free(buf);
@@ -258,7 +261,7 @@ static void write_object(unsigned nr, enum object_type type,
        } else {
                struct object *obj;
                int eaten;
-               hash_sha1_file(buf, size, typename(type), obj_list[nr].oid.hash);
+               hash_object_file(buf, size, typename(type), &obj_list[nr].oid);
                added_object(nr, type, buf, size);
                obj = parse_object_buffer(&obj_list[nr].oid, type, size, buf,
                                          &eaten);
@@ -345,8 +348,8 @@ static void unpack_delta_entry(enum object_type type, unsigned long delta_size,
        struct object_id base_oid;
 
        if (type == OBJ_REF_DELTA) {
-               hashcpy(base_oid.hash, fill(GIT_SHA1_RAWSZ));
-               use(GIT_SHA1_RAWSZ);
+               hashcpy(base_oid.hash, fill(the_hash_algo->rawsz));
+               use(the_hash_algo->rawsz);
                delta_data = get_data(delta_size);
                if (dry_run || !delta_data) {
                        free(delta_data);
@@ -564,15 +567,15 @@ int cmd_unpack_objects(int argc, const char **argv, const char *prefix)
                /* We don't take any non-flag arguments now.. Maybe some day */
                usage(unpack_usage);
        }
-       git_SHA1_Init(&ctx);
+       the_hash_algo->init_fn(&ctx);
        unpack_all();
-       git_SHA1_Update(&ctx, buffer, offset);
-       git_SHA1_Final(oid.hash, &ctx);
+       the_hash_algo->update_fn(&ctx, buffer, offset);
+       the_hash_algo->final_fn(oid.hash, &ctx);
        if (strict)
                write_rest();
-       if (hashcmp(fill(GIT_SHA1_RAWSZ), oid.hash))
+       if (hashcmp(fill(the_hash_algo->rawsz), oid.hash))
                die("final sha1 did not match");
-       use(GIT_SHA1_RAWSZ);
+       use(the_hash_algo->rawsz);
 
        /* Write the last part of the buffer to stdout */
        while (len) {
index 7cef5b120b7786d107282d03052c5e06d3a2c85a..9efdc224661b02192d06c6877e49c5585ddbcdca 100644 (file)
@@ -14,7 +14,7 @@
 #include "worktree.h"
 
 static const char * const worktree_usage[] = {
-       N_("git worktree add [<options>] <path> [<branch>]"),
+       N_("git worktree add [<options>] <path> [<commit-ish>]"),
        N_("git worktree list [<options>]"),
        N_("git worktree lock [<options>] <path>"),
        N_("git worktree prune [<options>]"),
index 3310fd210a151545076169b45f5555b52acbbf9d..8bcd1c8665d02840d7d77bc677b293595f9e0a31 100644 (file)
@@ -12,7 +12,7 @@ static struct bulk_checkin_state {
        unsigned plugged:1;
 
        char *pack_tmp_name;
-       struct sha1file *f;
+       struct hashfile *f;
        off_t offset;
        struct pack_idx_option pack_idx_opts;
 
@@ -35,9 +35,9 @@ static void finish_bulk_checkin(struct bulk_checkin_state *state)
                unlink(state->pack_tmp_name);
                goto clear_exit;
        } else if (state->nr_written == 1) {
-               sha1close(state->f, oid.hash, CSUM_FSYNC);
+               hashclose(state->f, oid.hash, CSUM_FSYNC);
        } else {
-               int fd = sha1close(state->f, oid.hash, 0);
+               int fd = hashclose(state->f, oid.hash, 0);
                fixup_pack_header_footer(fd, oid.hash, state->pack_tmp_name,
                                         state->nr_written, oid.hash,
                                         state->offset);
@@ -93,7 +93,7 @@ static int already_written(struct bulk_checkin_state *state, unsigned char sha1[
  * with a new pack.
  */
 static int stream_to_pack(struct bulk_checkin_state *state,
-                         git_SHA_CTX *ctx, off_t *already_hashed_to,
+                         git_hash_ctx *ctx, off_t *already_hashed_to,
                          int fd, size_t size, enum object_type type,
                          const char *path, unsigned flags)
 {
@@ -127,7 +127,7 @@ static int stream_to_pack(struct bulk_checkin_state *state,
                                if (rsize < hsize)
                                        hsize = rsize;
                                if (hsize)
-                                       git_SHA1_Update(ctx, ibuf, hsize);
+                                       the_hash_algo->update_fn(ctx, ibuf, hsize);
                                *already_hashed_to = offset;
                        }
                        s.next_in = ibuf;
@@ -149,7 +149,7 @@ static int stream_to_pack(struct bulk_checkin_state *state,
                                        return -1;
                                }
 
-                               sha1write(state->f, obuf, written);
+                               hashwrite(state->f, obuf, written);
                                state->offset += written;
                        }
                        s.next_out = obuf;
@@ -192,10 +192,10 @@ static int deflate_to_pack(struct bulk_checkin_state *state,
                           unsigned flags)
 {
        off_t seekback, already_hashed_to;
-       git_SHA_CTX ctx;
+       git_hash_ctx ctx;
        unsigned char obuf[16384];
        unsigned header_len;
-       struct sha1file_checkpoint checkpoint;
+       struct hashfile_checkpoint checkpoint;
        struct pack_idx_entry *idx = NULL;
 
        seekback = lseek(fd, 0, SEEK_CUR);
@@ -204,8 +204,8 @@ static int deflate_to_pack(struct bulk_checkin_state *state,
 
        header_len = xsnprintf((char *)obuf, sizeof(obuf), "%s %" PRIuMAX,
                               typename(type), (uintmax_t)size) + 1;
-       git_SHA1_Init(&ctx);
-       git_SHA1_Update(&ctx, obuf, header_len);
+       the_hash_algo->init_fn(&ctx);
+       the_hash_algo->update_fn(&ctx, obuf, header_len);
 
        /* Note: idx is non-NULL when we are writing */
        if ((flags & HASH_WRITE_OBJECT) != 0)
@@ -216,7 +216,7 @@ static int deflate_to_pack(struct bulk_checkin_state *state,
        while (1) {
                prepare_to_stream(state, flags);
                if (idx) {
-                       sha1file_checkpoint(state->f, &checkpoint);
+                       hashfile_checkpoint(state->f, &checkpoint);
                        idx->offset = state->offset;
                        crc32_begin(state->f);
                }
@@ -230,19 +230,19 @@ static int deflate_to_pack(struct bulk_checkin_state *state,
                 */
                if (!idx)
                        die("BUG: should not happen");
-               sha1file_truncate(state->f, &checkpoint);
+               hashfile_truncate(state->f, &checkpoint);
                state->offset = checkpoint.offset;
                finish_bulk_checkin(state);
                if (lseek(fd, seekback, SEEK_SET) == (off_t) -1)
                        return error("cannot seek back");
        }
-       git_SHA1_Final(result_sha1, &ctx);
+       the_hash_algo->final_fn(result_sha1, &ctx);
        if (!idx)
                return 0;
 
        idx->crc32 = crc32_end(state->f);
        if (already_written(state, result_sha1)) {
-               sha1file_truncate(state->f, &checkpoint);
+               hashfile_truncate(state->f, &checkpoint);
                state->offset = checkpoint.offset;
                free(idx);
        } else {
index 3841cef0c064b19722cb60742ed3bd95b9cde520..c52e4303dfcbc6a17796f536e8602017b1d951f0 100644 (file)
@@ -399,16 +399,16 @@ static int update_one(struct cache_tree *it,
        }
 
        if (repair) {
-               unsigned char sha1[20];
-               hash_sha1_file(buffer.buf, buffer.len, tree_type, sha1);
-               if (has_sha1_file(sha1))
-                       hashcpy(it->oid.hash, sha1);
+               struct object_id oid;
+               hash_object_file(buffer.buf, buffer.len, tree_type, &oid);
+               if (has_sha1_file(oid.hash))
+                       oidcpy(&it->oid, &oid);
                else
                        to_invalidate = 1;
-       } else if (dryrun)
-               hash_sha1_file(buffer.buf, buffer.len, tree_type,
-                              it->oid.hash);
-       else if (write_sha1_file(buffer.buf, buffer.len, tree_type, it->oid.hash)) {
+       } else if (dryrun) {
+               hash_object_file(buffer.buf, buffer.len, tree_type, &it->oid);
+       } else if (write_object_file(buffer.buf, buffer.len, tree_type,
+                                    &it->oid)) {
                strbuf_release(&buffer);
                return -1;
        }
diff --git a/cache.h b/cache.h
index 9cac7bb5185fff37e9906dd0dcad9187673c7e1f..21fbcc2414953d00929185aeb97f3a6ae9a3f73a 100644 (file)
--- a/cache.h
+++ b/cache.h
 #include "sha1-array.h"
 #include "repository.h"
 
-#ifndef platform_SHA_CTX
-/*
- * platform's underlying implementation of SHA-1; could be OpenSSL,
- * blk_SHA, Apple CommonCrypto, etc...  Note that including
- * SHA1_HEADER may have already defined platform_SHA_CTX for our
- * own implementations like block-sha1 and ppc-sha1, so we list
- * the default for OpenSSL compatible SHA-1 implementations here.
- */
-#define platform_SHA_CTX       SHA_CTX
-#define platform_SHA1_Init     SHA1_Init
-#define platform_SHA1_Update   SHA1_Update
-#define platform_SHA1_Final            SHA1_Final
-#endif
-
-#define git_SHA_CTX            platform_SHA_CTX
-#define git_SHA1_Init          platform_SHA1_Init
-#define git_SHA1_Update                platform_SHA1_Update
-#define git_SHA1_Final         platform_SHA1_Final
-
-#ifdef SHA1_MAX_BLOCK_SIZE
-#include "compat/sha1-chunked.h"
-#undef git_SHA1_Update
-#define git_SHA1_Update                git_SHA1_Update_Chunked
-#endif
-
 #include <zlib.h>
 typedef struct git_zstream {
        z_stream z;
@@ -1032,7 +1007,7 @@ static inline void hashclr(unsigned char *hash)
 
 static inline void oidclr(struct object_id *oid)
 {
-       hashclr(oid->hash);
+       memset(oid->hash, 0, GIT_MAX_RAWSZ);
 }
 
 
@@ -1050,8 +1025,6 @@ extern const struct object_id empty_tree_oid;
        "\xe6\x9d\xe2\x9b\xb2\xd1\xd6\x43\x4b\x8b" \
        "\x29\xae\x77\x5a\xd8\xc2\xe4\x8c\x53\x91"
 extern const struct object_id empty_blob_oid;
-#define EMPTY_BLOB_SHA1_BIN (empty_blob_oid.hash)
-
 
 static inline int is_empty_blob_sha1(const unsigned char *sha1)
 {
@@ -1241,11 +1214,22 @@ static inline const unsigned char *lookup_replace_object(const unsigned char *sh
 
 /* Read and unpack a sha1 file into memory, write memory to a sha1 file */
 extern int sha1_object_info(const unsigned char *, unsigned long *);
-extern int hash_sha1_file(const void *buf, unsigned long len, const char *type, unsigned char *sha1);
-extern int write_sha1_file(const void *buf, unsigned long len, const char *type, unsigned char *return_sha1);
-extern int hash_sha1_file_literally(const void *buf, unsigned long len, const char *type, struct object_id *oid, unsigned flags);
-extern int pretend_sha1_file(void *, unsigned long, enum object_type, unsigned char *);
-extern int force_object_loose(const unsigned char *sha1, time_t mtime);
+
+extern int hash_object_file(const void *buf, unsigned long len,
+                           const char *type, struct object_id *oid);
+
+extern int write_object_file(const void *buf, unsigned long len,
+                            const char *type, struct object_id *oid);
+
+extern int hash_object_file_literally(const void *buf, unsigned long len,
+                                     const char *type, struct object_id *oid,
+                                     unsigned flags);
+
+extern int pretend_object_file(void *, unsigned long, enum object_type,
+                              struct object_id *oid);
+
+extern int force_object_loose(const struct object_id *oid, time_t mtime);
+
 extern int git_open_cloexec(const char *name, int flags);
 #define git_open(name) git_open_cloexec(name, O_RDONLY)
 extern void *map_sha1_file(const unsigned char *sha1, unsigned long *size);
index c948c8b0e46a4b13d1e3045944ca1cea05d75517..e8a49b9c84bf24a6ef1455f975aa9e28e2156d77 100644 (file)
--- a/commit.c
+++ b/commit.c
@@ -1378,9 +1378,8 @@ void free_commit_extra_headers(struct commit_extra_header *extra)
        }
 }
 
-int commit_tree(const char *msg, size_t msg_len,
-               const unsigned char *tree,
-               struct commit_list *parents, unsigned char *ret,
+int commit_tree(const char *msg, size_t msg_len, const struct object_id *tree,
+               struct commit_list *parents, struct object_id *ret,
                const char *author, const char *sign_commit)
 {
        struct commit_extra_header *extra = NULL, **tail = &extra;
@@ -1509,8 +1508,8 @@ N_("Warning: commit message did not conform to UTF-8.\n"
    "variable i18n.commitencoding to the encoding your project uses.\n");
 
 int commit_tree_extended(const char *msg, size_t msg_len,
-                        const unsigned char *tree,
-                        struct commit_list *parents, unsigned char *ret,
+                        const struct object_id *tree,
+                        struct commit_list *parents, struct object_id *ret,
                         const char *author, const char *sign_commit,
                         struct commit_extra_header *extra)
 {
@@ -1518,7 +1517,7 @@ int commit_tree_extended(const char *msg, size_t msg_len,
        int encoding_is_utf8;
        struct strbuf buffer;
 
-       assert_sha1_type(tree, OBJ_TREE);
+       assert_sha1_type(tree->hash, OBJ_TREE);
 
        if (memchr(msg, '\0', msg_len))
                return error("a NUL byte in commit log message not allowed.");
@@ -1527,7 +1526,7 @@ int commit_tree_extended(const char *msg, size_t msg_len,
        encoding_is_utf8 = is_encoding_utf8(git_commit_encoding);
 
        strbuf_init(&buffer, 8192); /* should avoid reallocs for the headers */
-       strbuf_addf(&buffer, "tree %s\n", sha1_to_hex(tree));
+       strbuf_addf(&buffer, "tree %s\n", oid_to_hex(tree));
 
        /*
         * NOTE! This ordering means that the same exact tree merged with a
@@ -1566,7 +1565,7 @@ int commit_tree_extended(const char *msg, size_t msg_len,
                goto out;
        }
 
-       result = write_sha1_file(buffer.buf, buffer.len, commit_type, ret);
+       result = write_object_file(buffer.buf, buffer.len, commit_type, ret);
 out:
        strbuf_release(&buffer);
        return result;
index 425f4027752fb47190a53ddc72a64ebf9d928633..0fb8271665c6c98ccca803fbe002327bf38fcfb3 100644 (file)
--- a/commit.h
+++ b/commit.h
@@ -262,14 +262,15 @@ extern void append_merge_tag_headers(struct commit_list *parents,
                                     struct commit_extra_header ***tail);
 
 extern int commit_tree(const char *msg, size_t msg_len,
-                      const unsigned char *tree,
-                      struct commit_list *parents, unsigned char *ret,
+                      const struct object_id *tree,
+                      struct commit_list *parents, struct object_id *ret,
                       const char *author, const char *sign_commit);
 
 extern int commit_tree_extended(const char *msg, size_t msg_len,
-                               const unsigned char *tree,
-                               struct commit_list *parents, unsigned char *ret,
-                               const char *author, const char *sign_commit,
+                               const struct object_id *tree,
+                               struct commit_list *parents,
+                               struct object_id *ret, const char *author,
+                               const char *sign_commit,
                                struct commit_extra_header *);
 
 extern struct commit_extra_header *read_commit_extra_headers(struct commit *, const char **);
index 6fe8727421101efc04c15d8c6def448984eff74d..e34eada1ad52933230c7fcace595677747f9e1d6 100644 (file)
@@ -1,21 +1,6 @@
 @ strbuf_addf_with_format_only @
 expression E;
-constant fmt;
-@@
-  strbuf_addf(E,
-(
-  fmt
-|
-  _(fmt)
-)
-  );
-
-@ script:python @
-fmt << strbuf_addf_with_format_only.fmt;
-@@
-cocci.include_match("%" not in fmt)
-
-@ extends strbuf_addf_with_format_only @
+constant fmt !~ "%";
 @@
 - strbuf_addf
 + strbuf_addstr
index b976eb968c8289414c415e7beefa91c0816d5158..cc562f65094cd696466f86c3184f61cd025c2117 100644 (file)
--- a/convert.c
+++ b/convert.c
@@ -898,7 +898,7 @@ static int ident_to_git(const char *path, const char *src, size_t len,
 static int ident_to_worktree(const char *path, const char *src, size_t len,
                              struct strbuf *buf, int ident)
 {
-       unsigned char sha1[20];
+       struct object_id oid;
        char *to_free = NULL, *dollar, *spc;
        int cnt;
 
@@ -912,7 +912,7 @@ static int ident_to_worktree(const char *path, const char *src, size_t len,
        /* are we "faking" in place editing ? */
        if (src == buf->buf)
                to_free = strbuf_detach(buf, NULL);
-       hash_sha1_file(src, len, "blob", sha1);
+       hash_object_file(src, len, "blob", &oid);
 
        strbuf_grow(buf, len + cnt * 43);
        for (;;) {
@@ -969,7 +969,7 @@ static int ident_to_worktree(const char *path, const char *src, size_t len,
 
                /* step 4: substitute */
                strbuf_addstr(buf, "Id: ");
-               strbuf_add(buf, sha1_to_hex(sha1), 40);
+               strbuf_addstr(buf, oid_to_hex(&oid));
                strbuf_addstr(buf, " $");
        }
        strbuf_add(buf, src, len);
index 2adae04073816a781d01d85433d8d8922baafd7f..5eda7fb6af673ae82989dab871aaac74ec9ff629 100644 (file)
@@ -11,7 +11,7 @@
 #include "progress.h"
 #include "csum-file.h"
 
-static void flush(struct sha1file *f, const void *buf, unsigned int count)
+static void flush(struct hashfile *f, const void *buf, unsigned int count)
 {
        if (0 <= f->check_fd && count)  {
                unsigned char check_buffer[8192];
@@ -42,28 +42,28 @@ static void flush(struct sha1file *f, const void *buf, unsigned int count)
        }
 }
 
-void sha1flush(struct sha1file *f)
+void hashflush(struct hashfile *f)
 {
        unsigned offset = f->offset;
 
        if (offset) {
-               git_SHA1_Update(&f->ctx, f->buffer, offset);
+               the_hash_algo->update_fn(&f->ctx, f->buffer, offset);
                flush(f, f->buffer, offset);
                f->offset = 0;
        }
 }
 
-int sha1close(struct sha1file *f, unsigned char *result, unsigned int flags)
+int hashclose(struct hashfile *f, unsigned char *result, unsigned int flags)
 {
        int fd;
 
-       sha1flush(f);
-       git_SHA1_Final(f->buffer, &f->ctx);
+       hashflush(f);
+       the_hash_algo->final_fn(f->buffer, &f->ctx);
        if (result)
                hashcpy(result, f->buffer);
        if (flags & (CSUM_CLOSE | CSUM_FSYNC)) {
                /* write checksum and close fd */
-               flush(f, f->buffer, 20);
+               flush(f, f->buffer, the_hash_algo->rawsz);
                if (flags & CSUM_FSYNC)
                        fsync_or_die(f->fd, f->name);
                if (close(f->fd))
@@ -86,7 +86,7 @@ int sha1close(struct sha1file *f, unsigned char *result, unsigned int flags)
        return fd;
 }
 
-void sha1write(struct sha1file *f, const void *buf, unsigned int count)
+void hashwrite(struct hashfile *f, const void *buf, unsigned int count)
 {
        while (count) {
                unsigned offset = f->offset;
@@ -110,7 +110,7 @@ void sha1write(struct sha1file *f, const void *buf, unsigned int count)
                buf = (char *) buf + nr;
                left -= nr;
                if (!left) {
-                       git_SHA1_Update(&f->ctx, data, offset);
+                       the_hash_algo->update_fn(&f->ctx, data, offset);
                        flush(f, data, offset);
                        offset = 0;
                }
@@ -118,15 +118,15 @@ void sha1write(struct sha1file *f, const void *buf, unsigned int count)
        }
 }
 
-struct sha1file *sha1fd(int fd, const char *name)
+struct hashfile *hashfd(int fd, const char *name)
 {
-       return sha1fd_throughput(fd, name, NULL);
+       return hashfd_throughput(fd, name, NULL);
 }
 
-struct sha1file *sha1fd_check(const char *name)
+struct hashfile *hashfd_check(const char *name)
 {
        int sink, check;
-       struct sha1file *f;
+       struct hashfile *f;
 
        sink = open("/dev/null", O_WRONLY);
        if (sink < 0)
@@ -134,14 +134,14 @@ struct sha1file *sha1fd_check(const char *name)
        check = open(name, O_RDONLY);
        if (check < 0)
                die_errno("unable to open '%s'", name);
-       f = sha1fd(sink, name);
+       f = hashfd(sink, name);
        f->check_fd = check;
        return f;
 }
 
-struct sha1file *sha1fd_throughput(int fd, const char *name, struct progress *tp)
+struct hashfile *hashfd_throughput(int fd, const char *name, struct progress *tp)
 {
-       struct sha1file *f = xmalloc(sizeof(*f));
+       struct hashfile *f = xmalloc(sizeof(*f));
        f->fd = fd;
        f->check_fd = -1;
        f->offset = 0;
@@ -149,18 +149,18 @@ struct sha1file *sha1fd_throughput(int fd, const char *name, struct progress *tp
        f->tp = tp;
        f->name = name;
        f->do_crc = 0;
-       git_SHA1_Init(&f->ctx);
+       the_hash_algo->init_fn(&f->ctx);
        return f;
 }
 
-void sha1file_checkpoint(struct sha1file *f, struct sha1file_checkpoint *checkpoint)
+void hashfile_checkpoint(struct hashfile *f, struct hashfile_checkpoint *checkpoint)
 {
-       sha1flush(f);
+       hashflush(f);
        checkpoint->offset = f->total;
        checkpoint->ctx = f->ctx;
 }
 
-int sha1file_truncate(struct sha1file *f, struct sha1file_checkpoint *checkpoint)
+int hashfile_truncate(struct hashfile *f, struct hashfile_checkpoint *checkpoint)
 {
        off_t offset = checkpoint->offset;
 
@@ -169,17 +169,17 @@ int sha1file_truncate(struct sha1file *f, struct sha1file_checkpoint *checkpoint
                return -1;
        f->total = offset;
        f->ctx = checkpoint->ctx;
-       f->offset = 0; /* sha1flush() was called in checkpoint */
+       f->offset = 0; /* hashflush() was called in checkpoint */
        return 0;
 }
 
-void crc32_begin(struct sha1file *f)
+void crc32_begin(struct hashfile *f)
 {
        f->crc32 = crc32(0, NULL, 0);
        f->do_crc = 1;
 }
 
-uint32_t crc32_end(struct sha1file *f)
+uint32_t crc32_end(struct hashfile *f)
 {
        f->do_crc = 0;
        return f->crc32;
index 7530927d774562f82636aa773481ae93600c1756..992e5c014122d8fed3ee782d400e61de78e55271 100644 (file)
@@ -4,11 +4,11 @@
 struct progress;
 
 /* A SHA1-protected file */
-struct sha1file {
+struct hashfile {
        int fd;
        int check_fd;
        unsigned int offset;
-       git_SHA_CTX ctx;
+       git_hash_ctx ctx;
        off_t total;
        struct progress *tp;
        const char *name;
@@ -18,36 +18,36 @@ struct sha1file {
 };
 
 /* Checkpoint */
-struct sha1file_checkpoint {
+struct hashfile_checkpoint {
        off_t offset;
-       git_SHA_CTX ctx;
+       git_hash_ctx ctx;
 };
 
-extern void sha1file_checkpoint(struct sha1file *, struct sha1file_checkpoint *);
-extern int sha1file_truncate(struct sha1file *, struct sha1file_checkpoint *);
+extern void hashfile_checkpoint(struct hashfile *, struct hashfile_checkpoint *);
+extern int hashfile_truncate(struct hashfile *, struct hashfile_checkpoint *);
 
-/* sha1close flags */
+/* hashclose flags */
 #define CSUM_CLOSE     1
 #define CSUM_FSYNC     2
 
-extern struct sha1file *sha1fd(int fd, const char *name);
-extern struct sha1file *sha1fd_check(const char *name);
-extern struct sha1file *sha1fd_throughput(int fd, const char *name, struct progress *tp);
-extern int sha1close(struct sha1file *, unsigned char *, unsigned int);
-extern void sha1write(struct sha1file *, const void *, unsigned int);
-extern void sha1flush(struct sha1file *f);
-extern void crc32_begin(struct sha1file *);
-extern uint32_t crc32_end(struct sha1file *);
+extern struct hashfile *hashfd(int fd, const char *name);
+extern struct hashfile *hashfd_check(const char *name);
+extern struct hashfile *hashfd_throughput(int fd, const char *name, struct progress *tp);
+extern int hashclose(struct hashfile *, unsigned char *, unsigned int);
+extern void hashwrite(struct hashfile *, const void *, unsigned int);
+extern void hashflush(struct hashfile *f);
+extern void crc32_begin(struct hashfile *);
+extern uint32_t crc32_end(struct hashfile *);
 
-static inline void sha1write_u8(struct sha1file *f, uint8_t data)
+static inline void hashwrite_u8(struct hashfile *f, uint8_t data)
 {
-       sha1write(f, &data, sizeof(data));
+       hashwrite(f, &data, sizeof(data));
 }
 
-static inline void sha1write_be32(struct sha1file *f, uint32_t data)
+static inline void hashwrite_be32(struct hashfile *f, uint32_t data)
 {
        data = htonl(data);
-       sha1write(f, &data, sizeof(data));
+       hashwrite(f, &data, sizeof(data));
 }
 
 #endif
index 72dfeaf6e296323db7baf9e4545e412c01878417..fe833ea7de7685968915c93950bb54768dd04586 100644 (file)
--- a/daemon.c
+++ b/daemon.c
@@ -9,7 +9,12 @@
 #define initgroups(x, y) (0) /* nothing */
 #endif
 
-static int log_syslog;
+static enum log_destination {
+       LOG_DESTINATION_UNSET = -1,
+       LOG_DESTINATION_NONE = 0,
+       LOG_DESTINATION_STDERR = 1,
+       LOG_DESTINATION_SYSLOG = 2,
+} log_destination = LOG_DESTINATION_UNSET;
 static int verbose;
 static int reuseaddr;
 static int informative_errors;
@@ -25,6 +30,7 @@ static const char daemon_usage[] =
 "           [--access-hook=<path>]\n"
 "           [--inetd | [--listen=<host_or_ipaddr>] [--port=<n>]\n"
 "                      [--detach] [--user=<user> [--group=<group>]]\n"
+"           [--log-destination=(stderr|syslog|none)]\n"
 "           [<directory>...]";
 
 /* List of acceptable pathname prefixes */
@@ -74,11 +80,14 @@ static const char *get_ip_address(struct hostinfo *hi)
 
 static void logreport(int priority, const char *err, va_list params)
 {
-       if (log_syslog) {
+       switch (log_destination) {
+       case LOG_DESTINATION_SYSLOG: {
                char buf[1024];
                vsnprintf(buf, sizeof(buf), err, params);
                syslog(priority, "%s", buf);
-       } else {
+               break;
+       }
+       case LOG_DESTINATION_STDERR:
                /*
                 * Since stderr is set to buffered mode, the
                 * logging of different processes will not overlap
@@ -88,6 +97,11 @@ static void logreport(int priority, const char *err, va_list params)
                vfprintf(stderr, err, params);
                fputc('\n', stderr);
                fflush(stderr);
+               break;
+       case LOG_DESTINATION_NONE:
+               break;
+       case LOG_DESTINATION_UNSET:
+               BUG("log destination not initialized correctly");
        }
 }
 
@@ -1286,7 +1300,6 @@ int cmd_main(int argc, const char **argv)
                }
                if (!strcmp(arg, "--inetd")) {
                        inetd_mode = 1;
-                       log_syslog = 1;
                        continue;
                }
                if (!strcmp(arg, "--verbose")) {
@@ -1294,9 +1307,22 @@ int cmd_main(int argc, const char **argv)
                        continue;
                }
                if (!strcmp(arg, "--syslog")) {
-                       log_syslog = 1;
+                       log_destination = LOG_DESTINATION_SYSLOG;
                        continue;
                }
+               if (skip_prefix(arg, "--log-destination=", &v)) {
+                       if (!strcmp(v, "syslog")) {
+                               log_destination = LOG_DESTINATION_SYSLOG;
+                               continue;
+                       } else if (!strcmp(v, "stderr")) {
+                               log_destination = LOG_DESTINATION_STDERR;
+                               continue;
+                       } else if (!strcmp(v, "none")) {
+                               log_destination = LOG_DESTINATION_NONE;
+                               continue;
+                       } else
+                               die("unknown log destination '%s'", v);
+               }
                if (!strcmp(arg, "--export-all")) {
                        export_all_trees = 1;
                        continue;
@@ -1353,7 +1379,6 @@ int cmd_main(int argc, const char **argv)
                }
                if (!strcmp(arg, "--detach")) {
                        detach = 1;
-                       log_syslog = 1;
                        continue;
                }
                if (skip_prefix(arg, "--user=", &v)) {
@@ -1399,7 +1424,14 @@ int cmd_main(int argc, const char **argv)
                usage(daemon_usage);
        }
 
-       if (log_syslog) {
+       if (log_destination == LOG_DESTINATION_UNSET) {
+               if (inetd_mode || detach)
+                       log_destination = LOG_DESTINATION_SYSLOG;
+               else
+                       log_destination = LOG_DESTINATION_STDERR;
+       }
+
+       if (log_destination == LOG_DESTINATION_SYSLOG) {
                openlog("git-daemon", LOG_PID, LOG_DAEMON);
                set_die_routine(daemon_die);
        } else
index 8104603a3b36f2fd73761db34efde44d5938f68f..a228e1a219b56a6350160b279c86d63de1e42e0e 100644 (file)
@@ -92,6 +92,7 @@ int run_diff_files(struct rev_info *revs, unsigned int option)
        int diff_unmerged_stage = revs->max_count;
        unsigned ce_option = ((option & DIFF_RACY_IS_MODIFIED)
                              ? CE_MATCH_RACY_IS_DIRTY : 0);
+       uint64_t start = getnanotime();
 
        diff_set_mnemonic_prefix(&revs->diffopt, "i/", "w/");
 
@@ -246,6 +247,7 @@ int run_diff_files(struct rev_info *revs, unsigned int option)
        }
        diffcore_std(&revs->diffopt);
        diff_flush(&revs->diffopt);
+       trace_performance_since(start, "diff-files");
        return 0;
 }
 
@@ -512,6 +514,7 @@ static int diff_cache(struct rev_info *revs,
 int run_diff_index(struct rev_info *revs, int cached)
 {
        struct object_array_entry *ent;
+       uint64_t start = getnanotime();
 
        ent = revs->pending.objects;
        if (diff_cache(revs, &ent->item->oid, ent->name, cached))
@@ -521,6 +524,7 @@ int run_diff_index(struct rev_info *revs, int cached)
        diffcore_fix_diff_index(&revs->diffopt);
        diffcore_std(&revs->diffopt);
        diff_flush(&revs->diffopt);
+       trace_performance_since(start, "diff-index");
        return 0;
 }
 
index 888a4b0189c00e3dcf99a3684afe88d62f7921b2..0b7e4989a87214faa22e4f8ec75a719d3fd857ae 100644 (file)
@@ -260,8 +260,8 @@ static unsigned int hash_filespec(struct diff_filespec *filespec)
        if (!filespec->oid_valid) {
                if (diff_populate_filespec(filespec, 0))
                        return 0;
-               hash_sha1_file(filespec->data, filespec->size, "blob",
-                              filespec->oid.hash);
+               hash_object_file(filespec->data, filespec->size, "blob",
+                                &filespec->oid);
        }
        return sha1hash(filespec->oid.hash);
 }
diff --git a/dir.c b/dir.c
index ce6e50d2a2399122ee5c12b18a0ebb8a07dc3f75..6dd91be8185d4012e11495a9238636913fedeeef 100644 (file)
--- a/dir.c
+++ b/dir.c
@@ -231,12 +231,10 @@ int within_depth(const char *name, int namelen,
  *     1 along with { data, size } of the (possibly augmented) buffer
  *       when successful.
  *
- * Optionally updates the given sha1_stat with the given OID (when valid).
+ * Optionally updates the given oid_stat with the given OID (when valid).
  */
-static int do_read_blob(const struct object_id *oid,
-                       struct sha1_stat *sha1_stat,
-                       size_t *size_out,
-                       char **data_out)
+static int do_read_blob(const struct object_id *oid, struct oid_stat *oid_stat,
+                       size_t *size_out, char **data_out)
 {
        enum object_type type;
        unsigned long sz;
@@ -251,9 +249,9 @@ static int do_read_blob(const struct object_id *oid,
                return -1;
        }
 
-       if (sha1_stat) {
-               memset(&sha1_stat->stat, 0, sizeof(sha1_stat->stat));
-               hashcpy(sha1_stat->sha1, oid->hash);
+       if (oid_stat) {
+               memset(&oid_stat->stat, 0, sizeof(oid_stat->stat));
+               oidcpy(&oid_stat->oid, oid);
        }
 
        if (sz == 0) {
@@ -654,9 +652,8 @@ void add_exclude(const char *string, const char *base,
 
 static int read_skip_worktree_file_from_index(const struct index_state *istate,
                                              const char *path,
-                                             size_t *size_out,
-                                             char **data_out,
-                                             struct sha1_stat *sha1_stat)
+                                             size_t *size_out, char **data_out,
+                                             struct oid_stat *oid_stat)
 {
        int pos, len;
 
@@ -667,7 +664,7 @@ static int read_skip_worktree_file_from_index(const struct index_state *istate,
        if (!ce_skip_worktree(istate->cache[pos]))
                return -1;
 
-       return do_read_blob(&istate->cache[pos]->oid, sha1_stat, size_out, data_out);
+       return do_read_blob(&istate->cache[pos]->oid, oid_stat, size_out, data_out);
 }
 
 /*
@@ -774,7 +771,16 @@ static void invalidate_directory(struct untracked_cache *uc,
                                 struct untracked_cache_dir *dir)
 {
        int i;
-       uc->dir_invalidated++;
+
+       /*
+        * Invalidation increment here is just roughly correct. If
+        * untracked_nr or any of dirs[].recurse is non-zero, we
+        * should increment dir_invalidated too. But that's more
+        * expensive to do.
+        */
+       if (dir->valid)
+               uc->dir_invalidated++;
+
        dir->valid = 0;
        dir->untracked_nr = 0;
        for (i = 0; i < dir->dirs_nr; i++)
@@ -795,9 +801,8 @@ static int add_excludes_from_buffer(char *buf, size_t size,
  * ss_valid is non-zero, "ss" must contain good value as input.
  */
 static int add_excludes(const char *fname, const char *base, int baselen,
-                       struct exclude_list *el,
-                       struct index_state *istate,
-                       struct sha1_stat *sha1_stat)
+                       struct exclude_list *el, struct index_state *istate,
+                       struct oid_stat *oid_stat)
 {
        struct stat st;
        int r;
@@ -815,16 +820,16 @@ static int add_excludes(const char *fname, const char *base, int baselen,
                        return -1;
                r = read_skip_worktree_file_from_index(istate, fname,
                                                       &size, &buf,
-                                                      sha1_stat);
+                                                      oid_stat);
                if (r != 1)
                        return r;
        } else {
                size = xsize_t(st.st_size);
                if (size == 0) {
-                       if (sha1_stat) {
-                               fill_stat_data(&sha1_stat->stat, &st);
-                               hashcpy(sha1_stat->sha1, EMPTY_BLOB_SHA1_BIN);
-                               sha1_stat->valid = 1;
+                       if (oid_stat) {
+                               fill_stat_data(&oid_stat->stat, &st);
+                               oidcpy(&oid_stat->oid, &empty_blob_oid);
+                               oid_stat->valid = 1;
                        }
                        close(fd);
                        return 0;
@@ -837,22 +842,23 @@ static int add_excludes(const char *fname, const char *base, int baselen,
                }
                buf[size++] = '\n';
                close(fd);
-               if (sha1_stat) {
+               if (oid_stat) {
                        int pos;
-                       if (sha1_stat->valid &&
-                           !match_stat_data_racy(istate, &sha1_stat->stat, &st))
+                       if (oid_stat->valid &&
+                           !match_stat_data_racy(istate, &oid_stat->stat, &st))
                                ; /* no content change, ss->sha1 still good */
                        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(istate, fname))
-                               hashcpy(sha1_stat->sha1,
-                                       istate->cache[pos]->oid.hash);
+                               oidcpy(&oid_stat->oid,
+                                      &istate->cache[pos]->oid);
                        else
-                               hash_sha1_file(buf, size, "blob", sha1_stat->sha1);
-                       fill_stat_data(&sha1_stat->stat, &st);
-                       sha1_stat->valid = 1;
+                               hash_object_file(buf, size, "blob",
+                                                &oid_stat->oid);
+                       fill_stat_data(&oid_stat->stat, &st);
+                       oid_stat->valid = 1;
                }
        }
 
@@ -930,7 +936,7 @@ struct exclude_list *add_exclude_list(struct dir_struct *dir,
  * Used to set up core.excludesfile and .git/info/exclude lists.
  */
 static void add_excludes_from_file_1(struct dir_struct *dir, const char *fname,
-                                    struct sha1_stat *sha1_stat)
+                                    struct oid_stat *oid_stat)
 {
        struct exclude_list *el;
        /*
@@ -941,7 +947,7 @@ static void add_excludes_from_file_1(struct dir_struct *dir, const char *fname,
        if (!dir->untracked)
                dir->unmanaged_exclude_files++;
        el = add_exclude_list(dir, EXC_FILE, fname);
-       if (add_excludes(fname, "", 0, el, NULL, sha1_stat) < 0)
+       if (add_excludes(fname, "", 0, el, NULL, oid_stat) < 0)
                die("cannot use %s as an exclude file", fname);
 }
 
@@ -1180,7 +1186,7 @@ static void prep_exclude(struct dir_struct *dir,
 
        while (current < baselen) {
                const char *cp;
-               struct sha1_stat sha1_stat;
+               struct oid_stat oid_stat;
 
                stk = xcalloc(1, sizeof(*stk));
                if (current < 0) {
@@ -1223,8 +1229,8 @@ static void prep_exclude(struct dir_struct *dir,
                }
 
                /* Try to read per-directory file */
-               hashclr(sha1_stat.sha1);
-               sha1_stat.valid = 0;
+               oidclr(&oid_stat.oid);
+               oid_stat.valid = 0;
                if (dir->exclude_per_dir &&
                    /*
                     * If we know that no files have been added in
@@ -1252,7 +1258,7 @@ static void prep_exclude(struct dir_struct *dir,
                        strbuf_addstr(&sb, dir->exclude_per_dir);
                        el->src = strbuf_detach(&sb, NULL);
                        add_excludes(el->src, el->src, stk->baselen, el, istate,
-                                    untracked ? &sha1_stat : NULL);
+                                    untracked ? &oid_stat : NULL);
                }
                /*
                 * NEEDSWORK: when untracked cache is enabled, prep_exclude()
@@ -1269,9 +1275,9 @@ static void prep_exclude(struct dir_struct *dir,
                 * order, though, if you do that.
                 */
                if (untracked &&
-                   hashcmp(sha1_stat.sha1, untracked->exclude_sha1)) {
+                   hashcmp(oid_stat.oid.hash, untracked->exclude_sha1)) {
                        invalidate_gitignore(dir->untracked, untracked);
-                       hashcpy(untracked->exclude_sha1, sha1_stat.sha1);
+                       hashcpy(untracked->exclude_sha1, oid_stat.oid.hash);
                }
                dir->exclude_stack = stk;
                current = stk->baselen;
@@ -1773,7 +1779,7 @@ static enum path_treatment treat_path(struct dir_struct *dir,
        if (!de)
                return treat_path_fast(dir, untracked, cdir, istate, path,
                                       baselen, pathspec);
-       if (is_dot_or_dotdot(de->d_name) || !strcmp(de->d_name, ".git"))
+       if (is_dot_or_dotdot(de->d_name) || !fspathcmp(de->d_name, ".git"))
                return path_none;
        strbuf_setlen(path, baselen);
        strbuf_addstr(path, de->d_name);
@@ -1809,24 +1815,19 @@ static int valid_cached_dir(struct dir_struct *dir,
         */
        refresh_fsmonitor(istate);
        if (!(dir->untracked->use_fsmonitor && untracked->valid)) {
-               if (stat(path->len ? path->buf : ".", &st)) {
-                       invalidate_directory(dir->untracked, untracked);
+               if (lstat(path->len ? path->buf : ".", &st)) {
                        memset(&untracked->stat_data, 0, sizeof(untracked->stat_data));
                        return 0;
                }
                if (!untracked->valid ||
                        match_stat_data_racy(istate, &untracked->stat_data, &st)) {
-                       if (untracked->valid)
-                               invalidate_directory(dir->untracked, untracked);
                        fill_stat_data(&untracked->stat_data, &st);
                        return 0;
                }
        }
 
-       if (untracked->check_only != !!check_only) {
-               invalidate_directory(dir->untracked, untracked);
+       if (untracked->check_only != !!check_only)
                return 0;
-       }
 
        /*
         * prep_exclude will be called eventually on this directory,
@@ -1853,13 +1854,20 @@ static int open_cached_dir(struct cached_dir *cdir,
                           struct strbuf *path,
                           int check_only)
 {
+       const char *c_path;
+
        memset(cdir, 0, sizeof(*cdir));
        cdir->untracked = untracked;
        if (valid_cached_dir(dir, untracked, istate, path, check_only))
                return 0;
-       cdir->fdir = opendir(path->len ? path->buf : ".");
-       if (dir->untracked)
+       c_path = path->len ? path->buf : ".";
+       cdir->fdir = opendir(c_path);
+       if (!cdir->fdir)
+               warning_errno(_("could not open directory '%s'"), c_path);
+       if (dir->untracked) {
+               invalidate_directory(dir->untracked, untracked);
                dir->untracked->dir_opened++;
+       }
        if (!cdir->fdir)
                return -1;
        return 0;
@@ -2228,13 +2236,13 @@ static struct untracked_cache_dir *validate_untracked_cache(struct dir_struct *d
 
        /* Validate $GIT_DIR/info/exclude and core.excludesfile */
        root = dir->untracked->root;
-       if (hashcmp(dir->ss_info_exclude.sha1,
-                   dir->untracked->ss_info_exclude.sha1)) {
+       if (oidcmp(&dir->ss_info_exclude.oid,
+                  &dir->untracked->ss_info_exclude.oid)) {
                invalidate_gitignore(dir->untracked, root);
                dir->untracked->ss_info_exclude = dir->ss_info_exclude;
        }
-       if (hashcmp(dir->ss_excludes_file.sha1,
-                   dir->untracked->ss_excludes_file.sha1)) {
+       if (oidcmp(&dir->ss_excludes_file.oid,
+                  &dir->untracked->ss_excludes_file.oid)) {
                invalidate_gitignore(dir->untracked, root);
                dir->untracked->ss_excludes_file = dir->ss_excludes_file;
        }
@@ -2248,6 +2256,7 @@ int read_directory(struct dir_struct *dir, struct index_state *istate,
                   const char *path, int len, const struct pathspec *pathspec)
 {
        struct untracked_cache_dir *untracked;
+       uint64_t start = getnanotime();
 
        if (has_symlink_leading_path(path, len))
                return dir->nr;
@@ -2286,6 +2295,7 @@ int read_directory(struct dir_struct *dir, struct index_state *istate,
                dir->nr = i;
        }
 
+       trace_performance_since(start, "read directory %.*s", len, path);
        if (dir->untracked) {
                static struct trace_key trace_untracked_stats = TRACE_KEY_INIT(UNTRACKED_STATS);
                trace_printf_key(&trace_untracked_stats,
@@ -2638,8 +2648,8 @@ void write_untracked_extension(struct strbuf *out, struct untracked_cache *untra
        FLEX_ALLOC_MEM(ouc, exclude_per_dir, untracked->exclude_per_dir, len);
        stat_data_to_disk(&ouc->info_exclude_stat, &untracked->ss_info_exclude.stat);
        stat_data_to_disk(&ouc->excludes_file_stat, &untracked->ss_excludes_file.stat);
-       hashcpy(ouc->info_exclude_sha1, untracked->ss_info_exclude.sha1);
-       hashcpy(ouc->excludes_file_sha1, untracked->ss_excludes_file.sha1);
+       hashcpy(ouc->info_exclude_sha1, untracked->ss_info_exclude.oid.hash);
+       hashcpy(ouc->excludes_file_sha1, untracked->ss_excludes_file.oid.hash);
        ouc->dir_flags = htonl(untracked->dir_flags);
 
        varint_len = encode_varint(untracked->ident.len, varbuf);
@@ -2816,13 +2826,12 @@ static void read_sha1(size_t pos, void *cb)
        rd->data += 20;
 }
 
-static void load_sha1_stat(struct sha1_stat *sha1_stat,
-                          const unsigned char *data,
-                          const unsigned char *sha1)
+static void load_oid_stat(struct oid_stat *oid_stat, const unsigned char *data,
+                         const unsigned char *sha1)
 {
-       stat_data_from_disk(&sha1_stat->stat, data);
-       hashcpy(sha1_stat->sha1, sha1);
-       sha1_stat->valid = 1;
+       stat_data_from_disk(&oid_stat->stat, data);
+       hashcpy(oid_stat->oid.hash, sha1);
+       oid_stat->valid = 1;
 }
 
 struct untracked_cache *read_untracked_extension(const void *data, unsigned long sz)
@@ -2850,12 +2859,12 @@ struct untracked_cache *read_untracked_extension(const void *data, unsigned long
        uc = xcalloc(1, sizeof(*uc));
        strbuf_init(&uc->ident, ident_len);
        strbuf_add(&uc->ident, ident, ident_len);
-       load_sha1_stat(&uc->ss_info_exclude,
-                      next + ouc_offset(info_exclude_stat),
-                      next + ouc_offset(info_exclude_sha1));
-       load_sha1_stat(&uc->ss_excludes_file,
-                      next + ouc_offset(excludes_file_stat),
-                      next + ouc_offset(excludes_file_sha1));
+       load_oid_stat(&uc->ss_info_exclude,
+                     next + ouc_offset(info_exclude_stat),
+                     next + ouc_offset(info_exclude_sha1));
+       load_oid_stat(&uc->ss_excludes_file,
+                     next + ouc_offset(excludes_file_stat),
+                     next + ouc_offset(excludes_file_sha1));
        uc->dir_flags = get_be32(next + ouc_offset(dir_flags));
        exclude_per_dir = (const char *)next + ouc_offset(exclude_per_dir);
        uc->exclude_per_dir = xstrdup(exclude_per_dir);
@@ -2968,10 +2977,12 @@ static int invalidate_one_component(struct untracked_cache *uc,
 }
 
 void untracked_cache_invalidate_path(struct index_state *istate,
-                                    const char *path)
+                                    const char *path, int safe_path)
 {
        if (!istate->untracked || !istate->untracked->root)
                return;
+       if (!safe_path && !verify_path(path))
+               return;
        invalidate_one_component(istate->untracked, istate->untracked->root,
                                 path, strlen(path));
 }
@@ -2979,13 +2990,13 @@ void untracked_cache_invalidate_path(struct index_state *istate,
 void untracked_cache_remove_from_index(struct index_state *istate,
                                       const char *path)
 {
-       untracked_cache_invalidate_path(istate, path);
+       untracked_cache_invalidate_path(istate, path, 1);
 }
 
 void untracked_cache_add_to_index(struct index_state *istate,
                                  const char *path)
 {
-       untracked_cache_invalidate_path(istate, path);
+       untracked_cache_invalidate_path(istate, path, 1);
 }
 
 /* Update gitfile and core.worktree setting to connect work tree and git dir */
diff --git a/dir.h b/dir.h
index 11a047ba486b81f624fb021418f06cbbd65da676..b0758b82a20017dd3ce29c54454678f026718078 100644 (file)
--- a/dir.h
+++ b/dir.h
@@ -74,9 +74,9 @@ struct exclude_list_group {
        struct exclude_list *el;
 };
 
-struct sha1_stat {
+struct oid_stat {
        struct stat_data stat;
-       unsigned char sha1[20];
+       struct object_id oid;
        int valid;
 };
 
@@ -124,8 +124,8 @@ struct untracked_cache_dir {
 };
 
 struct untracked_cache {
-       struct sha1_stat ss_info_exclude;
-       struct sha1_stat ss_excludes_file;
+       struct oid_stat ss_info_exclude;
+       struct oid_stat ss_excludes_file;
        const char *exclude_per_dir;
        struct strbuf ident;
        /*
@@ -195,8 +195,8 @@ struct dir_struct {
 
        /* Enable untracked file cache if set */
        struct untracked_cache *untracked;
-       struct sha1_stat ss_info_exclude;
-       struct sha1_stat ss_excludes_file;
+       struct oid_stat ss_info_exclude;
+       struct oid_stat ss_excludes_file;
        unsigned unmanaged_exclude_files;
 };
 
@@ -350,7 +350,7 @@ static inline int dir_path_match(const struct dir_entry *ent,
 int cmp_dir_entry(const void *p1, const void *p2);
 int check_dir_entry_contains(const struct dir_entry *out, const struct dir_entry *in);
 
-void untracked_cache_invalidate_path(struct index_state *, const char *);
+void untracked_cache_invalidate_path(struct index_state *, const char *, int safe_path);
 void untracked_cache_remove_from_index(struct index_state *, const char *);
 void untracked_cache_add_to_index(struct index_state *, const char *);
 
index b70ac025e0428b239c9cb8b8a70dda70c0cc1007..0f818cd9328d182b44649a130645a871eb63cfb5 100644 (file)
@@ -316,7 +316,7 @@ static struct atom_str **atom_table;
 /* The .pack file being generated */
 static struct pack_idx_option pack_idx_opts;
 static unsigned int pack_id;
-static struct sha1file *pack_file;
+static struct hashfile *pack_file;
 static struct packed_git *pack_data;
 static struct packed_git **all_packs;
 static off_t pack_size;
@@ -905,12 +905,12 @@ static void start_packfile(void)
 
        p->pack_fd = pack_fd;
        p->do_not_close = 1;
-       pack_file = sha1fd(pack_fd, p->pack_name);
+       pack_file = hashfd(pack_fd, p->pack_name);
 
        hdr.hdr_signature = htonl(PACK_SIGNATURE);
        hdr.hdr_version = htonl(2);
        hdr.hdr_entries = 0;
-       sha1write(pack_file, &hdr, sizeof(hdr));
+       hashwrite(pack_file, &hdr, sizeof(hdr));
 
        pack_data = p;
        pack_size = sizeof(hdr);
@@ -1016,7 +1016,7 @@ static void end_packfile(void)
                struct tag *t;
 
                close_pack_windows(pack_data);
-               sha1close(pack_file, cur_pack_oid.hash, 0);
+               hashclose(pack_file, cur_pack_oid.hash, 0);
                fixup_pack_header_footer(pack_data->pack_fd, pack_data->sha1,
                                    pack_data->pack_name, object_count,
                                    cur_pack_oid.hash, pack_size);
@@ -1092,15 +1092,15 @@ static int store_object(
        unsigned char hdr[96];
        struct object_id oid;
        unsigned long hdrlen, deltalen;
-       git_SHA_CTX c;
+       git_hash_ctx c;
        git_zstream s;
 
        hdrlen = xsnprintf((char *)hdr, sizeof(hdr), "%s %lu",
                           typename(type), (unsigned long)dat->len) + 1;
-       git_SHA1_Init(&c);
-       git_SHA1_Update(&c, hdr, hdrlen);
-       git_SHA1_Update(&c, dat->buf, dat->len);
-       git_SHA1_Final(oid.hash, &c);
+       the_hash_algo->init_fn(&c);
+       the_hash_algo->update_fn(&c, hdr, hdrlen);
+       the_hash_algo->update_fn(&c, dat->buf, dat->len);
+       the_hash_algo->final_fn(oid.hash, &c);
        if (oidout)
                oidcpy(oidout, &oid);
 
@@ -1118,11 +1118,13 @@ static int store_object(
                return 1;
        }
 
-       if (last && last->data.buf && last->depth < max_depth && dat->len > 20) {
+       if (last && last->data.buf && last->depth < max_depth
+               && dat->len > the_hash_algo->rawsz) {
+
                delta_count_attempts_by_type[type]++;
                delta = diff_delta(last->data.buf, last->data.len,
                        dat->buf, dat->len,
-                       &deltalen, dat->len - 20);
+                       &deltalen, dat->len - the_hash_algo->rawsz);
        } else
                delta = NULL;
 
@@ -1180,23 +1182,23 @@ static int store_object(
 
                hdrlen = encode_in_pack_object_header(hdr, sizeof(hdr),
                                                      OBJ_OFS_DELTA, deltalen);
-               sha1write(pack_file, hdr, hdrlen);
+               hashwrite(pack_file, hdr, hdrlen);
                pack_size += hdrlen;
 
                hdr[pos] = ofs & 127;
                while (ofs >>= 7)
                        hdr[--pos] = 128 | (--ofs & 127);
-               sha1write(pack_file, hdr + pos, sizeof(hdr) - pos);
+               hashwrite(pack_file, hdr + pos, sizeof(hdr) - pos);
                pack_size += sizeof(hdr) - pos;
        } else {
                e->depth = 0;
                hdrlen = encode_in_pack_object_header(hdr, sizeof(hdr),
                                                      type, dat->len);
-               sha1write(pack_file, hdr, hdrlen);
+               hashwrite(pack_file, hdr, hdrlen);
                pack_size += hdrlen;
        }
 
-       sha1write(pack_file, out, s.total_out);
+       hashwrite(pack_file, out, s.total_out);
        pack_size += s.total_out;
 
        e->idx.crc32 = crc32_end(pack_file);
@@ -1215,9 +1217,9 @@ static int store_object(
        return 0;
 }
 
-static void truncate_pack(struct sha1file_checkpoint *checkpoint)
+static void truncate_pack(struct hashfile_checkpoint *checkpoint)
 {
-       if (sha1file_truncate(pack_file, checkpoint))
+       if (hashfile_truncate(pack_file, checkpoint))
                die_errno("cannot truncate pack to skip duplicate");
        pack_size = checkpoint->offset;
 }
@@ -1231,9 +1233,9 @@ static void stream_blob(uintmax_t len, struct object_id *oidout, uintmax_t mark)
        struct object_id oid;
        unsigned long hdrlen;
        off_t offset;
-       git_SHA_CTX c;
+       git_hash_ctx c;
        git_zstream s;
-       struct sha1file_checkpoint checkpoint;
+       struct hashfile_checkpoint checkpoint;
        int status = Z_OK;
 
        /* Determine if we should auto-checkpoint. */
@@ -1241,13 +1243,13 @@ static void stream_blob(uintmax_t len, struct object_id *oidout, uintmax_t mark)
                || (pack_size + 60 + len) < pack_size)
                cycle_packfile();
 
-       sha1file_checkpoint(pack_file, &checkpoint);
+       hashfile_checkpoint(pack_file, &checkpoint);
        offset = checkpoint.offset;
 
        hdrlen = xsnprintf((char *)out_buf, out_sz, "blob %" PRIuMAX, len) + 1;
 
-       git_SHA1_Init(&c);
-       git_SHA1_Update(&c, out_buf, hdrlen);
+       the_hash_algo->init_fn(&c);
+       the_hash_algo->update_fn(&c, out_buf, hdrlen);
 
        crc32_begin(pack_file);
 
@@ -1265,7 +1267,7 @@ static void stream_blob(uintmax_t len, struct object_id *oidout, uintmax_t mark)
                        if (!n && feof(stdin))
                                die("EOF in data (%" PRIuMAX " bytes remaining)", len);
 
-                       git_SHA1_Update(&c, in_buf, n);
+                       the_hash_algo->update_fn(&c, in_buf, n);
                        s.next_in = in_buf;
                        s.avail_in = n;
                        len -= n;
@@ -1275,7 +1277,7 @@ static void stream_blob(uintmax_t len, struct object_id *oidout, uintmax_t mark)
 
                if (!s.avail_out || status == Z_STREAM_END) {
                        size_t n = s.next_out - out_buf;
-                       sha1write(pack_file, out_buf, n);
+                       hashwrite(pack_file, out_buf, n);
                        pack_size += n;
                        s.next_out = out_buf;
                        s.avail_out = out_sz;
@@ -1291,7 +1293,7 @@ static void stream_blob(uintmax_t len, struct object_id *oidout, uintmax_t mark)
                }
        }
        git_deflate_end(&s);
-       git_SHA1_Final(oid.hash, &c);
+       the_hash_algo->final_fn(oid.hash, &c);
 
        if (oidout)
                oidcpy(oidout, &oid);
@@ -1350,25 +1352,25 @@ static void *gfi_unpack_entry(
 {
        enum object_type type;
        struct packed_git *p = all_packs[oe->pack_id];
-       if (p == pack_data && p->pack_size < (pack_size + 20)) {
+       if (p == pack_data && p->pack_size < (pack_size + the_hash_algo->rawsz)) {
                /* The object is stored in the packfile we are writing to
                 * and we have modified it since the last time we scanned
                 * back to read a previously written object.  If an old
-                * window covered [p->pack_size, p->pack_size + 20) its
+                * window covered [p->pack_size, p->pack_size + rawsz) its
                 * data is stale and is not valid.  Closing all windows
                 * and updating the packfile length ensures we can read
                 * the newly written data.
                 */
                close_pack_windows(p);
-               sha1flush(pack_file);
+               hashflush(pack_file);
 
-               /* We have to offer 20 bytes additional on the end of
+               /* We have to offer rawsz bytes additional on the end of
                 * the packfile as the core unpacker code assumes the
                 * footer is present at the file end and must promise
-                * at least 20 bytes within any window it maps.  But
+                * at least rawsz bytes within any window it maps.  But
                 * we don't actually create the footer here.
                 */
-               p->pack_size = pack_size + 20;
+               p->pack_size = pack_size + the_hash_algo->rawsz;
        }
        return unpack_entry(p, oe->idx.offset, &type, sizep);
 }
@@ -2204,7 +2206,7 @@ static void construct_path_with_fanout(const char *hex_sha1,
                unsigned char fanout, char *path)
 {
        unsigned int i = 0, j = 0;
-       if (fanout >= 20)
+       if (fanout >= the_hash_algo->rawsz)
                die("Too large fanout (%u)", fanout);
        while (fanout) {
                path[i++] = hex_sha1[j++];
@@ -2212,8 +2214,8 @@ static void construct_path_with_fanout(const char *hex_sha1,
                path[i++] = '/';
                fanout--;
        }
-       memcpy(path + i, hex_sha1 + j, GIT_SHA1_HEXSZ - j);
-       path[i + GIT_SHA1_HEXSZ - j] = '\0';
+       memcpy(path + i, hex_sha1 + j, the_hash_algo->hexsz - j);
+       path[i + the_hash_algo->hexsz - j] = '\0';
 }
 
 static uintmax_t do_change_note_fanout(
index 0af7c4edba37fd9f6a8cee83cd2715c3fa08b488..6d7bcd5d0ed8f2d3f5abdea2f26c6be72909b657 100644 (file)
@@ -130,7 +130,7 @@ static void fsmonitor_refresh_callback(struct index_state *istate, const char *n
         * as it could be a new untracked file.
         */
        trace_printf_key(&trace_fsmonitor, "fsmonitor_refresh_callback '%s'", name);
-       untracked_cache_invalidate_path(istate, name);
+       untracked_cache_invalidate_path(istate, name, 0);
 }
 
 void refresh_fsmonitor(struct index_state *istate)
index cd3cc0ccf228c9d601621685042d51368a71c707..65f37436369cd934f2bdb3b627396c5f72a7cb03 100644 (file)
@@ -65,7 +65,7 @@ static inline void mark_fsmonitor_invalid(struct index_state *istate, struct cac
 {
        if (core_fsmonitor) {
                ce->ce_flags &= ~CE_FSMONITOR_VALID;
-               untracked_cache_invalidate_path(istate, ce->name);
+               untracked_cache_invalidate_path(istate, ce->name, 1);
                trace_printf_key(&trace_fsmonitor, "mark_fsmonitor_invalid '%s'", ce->name);
        }
 }
index 14c50782e096966b860d49cbaed7658e9f56958f..0f78051792fae93f7966c2a3f9fc670b4fca9188 100644 (file)
@@ -46,6 +46,7 @@ then
        # makes this easy
        git cherry-pick ${gpg_sign_opt:+"$gpg_sign_opt"} --allow-empty \
                $allow_rerere_autoupdate --right-only "$revisions" \
+               $allow_empty_message \
                ${restrict_revision+^$restrict_revision}
        ret=$?
 else
index d47bd29593ad8711448293f3b6bf2e059323ff78..81c5b42875771ab98ca86e718e14a5a393aa1a86 100644 (file)
@@ -281,7 +281,7 @@ pick_one () {
 
        test -d "$rewritten" &&
                pick_one_preserving_merges "$@" && return
-       output eval git cherry-pick $allow_rerere_autoupdate \
+       output eval git cherry-pick $allow_rerere_autoupdate $allow_empty_message \
                        ${gpg_sign_opt:+$(git rev-parse --sq-quote "$gpg_sign_opt")} \
                        "$strategy_args" $empty_args $ff "$@"
 
@@ -406,6 +406,7 @@ pick_one_preserving_merges () {
                        ;;
                *)
                        output eval git cherry-pick $allow_rerere_autoupdate \
+                               $allow_empty_message \
                                ${gpg_sign_opt:+$(git rev-parse --sq-quote "$gpg_sign_opt")} \
                                "$strategy_args" "$@" ||
                                die_with_patch $sha1 "$(eval_gettext "Could not pick \$sha1")"
@@ -559,7 +560,8 @@ do_next () {
 
                mark_action_done
                do_pick $sha1 "$rest"
-               git commit --amend --no-post-rewrite ${gpg_sign_opt:+"$gpg_sign_opt"} || {
+               git commit --amend --no-post-rewrite ${gpg_sign_opt:+"$gpg_sign_opt"} \
+                       $allow_empty_message || {
                        warn "$(eval_gettext "\
 Could not amend commit after successfully picking \$sha1... \$rest
 This is most likely due to an empty commit message, or the pre-commit hook
@@ -607,7 +609,7 @@ you are able to reword the commit.")"
                        # This is an intermediate commit; its message will only be
                        # used in case of trouble.  So use the long version:
                        do_with_author output git commit --amend --no-verify -F "$squash_msg" \
-                               ${gpg_sign_opt:+"$gpg_sign_opt"} ||
+                               ${gpg_sign_opt:+"$gpg_sign_opt"} $allow_empty_message ||
                                die_failed_squash $sha1 "$rest"
                        ;;
                *)
@@ -615,13 +617,13 @@ you are able to reword the commit.")"
                        if test -f "$fixup_msg"
                        then
                                do_with_author git commit --amend --no-verify -F "$fixup_msg" \
-                                       ${gpg_sign_opt:+"$gpg_sign_opt"} ||
+                                       ${gpg_sign_opt:+"$gpg_sign_opt"} $allow_empty_message ||
                                        die_failed_squash $sha1 "$rest"
                        else
                                cp "$squash_msg" "$GIT_DIR"/SQUASH_MSG || exit
                                rm -f "$GIT_DIR"/MERGE_MSG
                                do_with_author git commit --amend --no-verify -F "$GIT_DIR"/SQUASH_MSG -e \
-                                       ${gpg_sign_opt:+"$gpg_sign_opt"} ||
+                                       ${gpg_sign_opt:+"$gpg_sign_opt"} $allow_empty_message ||
                                        die_failed_squash $sha1 "$rest"
                        fi
                        rm -f "$squash_msg" "$fixup_msg"
@@ -754,7 +756,8 @@ case "$action" in
 continue)
        if test ! -d "$rewritten"
        then
-               exec git rebase--helper ${force_rebase:+--no-ff} --continue
+               exec git rebase--helper ${force_rebase:+--no-ff} $allow_empty_message \
+                       --continue
        fi
        # do we have anything to commit?
        if git diff-index --cached --quiet HEAD --
@@ -794,11 +797,11 @@ In both cases, once you're done, continue with:
 You have uncommitted changes in your working tree. Please commit them
 first and then run 'git rebase --continue' again.")"
                        do_with_author git commit --amend --no-verify -F "$msg" -e \
-                               ${gpg_sign_opt:+"$gpg_sign_opt"} ||
+                               ${gpg_sign_opt:+"$gpg_sign_opt"} $allow_empty_message ||
                                die "$(gettext "Could not commit staged changes.")"
                else
                        do_with_author git commit --no-verify -F "$msg" -e \
-                               ${gpg_sign_opt:+"$gpg_sign_opt"} ||
+                               ${gpg_sign_opt:+"$gpg_sign_opt"} $allow_empty_message ||
                                die "$(gettext "Could not commit staged changes.")"
                fi
        fi
@@ -817,7 +820,8 @@ skip)
 
        if test ! -d "$rewritten"
        then
-               exec git rebase--helper ${force_rebase:+--no-ff} --continue
+               exec git rebase--helper ${force_rebase:+--no-ff} $allow_empty_message \
+                       --continue
        fi
        do_rest
        return 0
@@ -1016,7 +1020,8 @@ checkout_onto
 if test -z "$rebase_root" && test ! -d "$rewritten"
 then
        require_clean_work_tree "rebase"
-       exec git rebase--helper ${force_rebase:+--no-ff} --continue
+       exec git rebase--helper ${force_rebase:+--no-ff} $allow_empty_message \
+               --continue
 fi
 do_rest
 
index 06a4723d4db3db74ea17ace60d824e83cdee25e9..1831e589b8c94b3fbcee710c5742b71a3e7e8f9e 100644 (file)
@@ -27,7 +27,8 @@ continue_merge () {
        cmt=$(cat "$state_dir/current")
        if ! git diff-index --quiet --ignore-submodules HEAD --
        then
-               if ! git commit ${gpg_sign_opt:+"$gpg_sign_opt"} --no-verify -C "$cmt"
+               if ! git commit ${gpg_sign_opt:+"$gpg_sign_opt"} $allow_empty_message \
+                       --no-verify -C "$cmt"
                then
                        echo "Commit failed, please do not call \"git commit\""
                        echo "directly, but instead do one of the following: "
index fd72a35c65b43537b292445b87ffb7e682cc076a..b353c33d417a913c2b356b3c070b1dbbc033f162 100755 (executable)
@@ -24,6 +24,7 @@ m,merge!           use merging strategies to rebase
 i,interactive!     let the user edit the list of commits to rebase
 x,exec=!           add exec lines after each commit of the editable list
 k,keep-empty      preserve empty commits during rebase
+allow-empty-message allow rebasing commits with empty messages
 f,force-rebase!    force rebase even if branch is up to date
 X,strategy-option=! pass the argument through to the merge strategy
 stat!              display a diffstat of what changed upstream
@@ -89,6 +90,7 @@ action=
 preserve_merges=
 autosquash=
 keep_empty=
+allow_empty_message=
 test "$(git config --bool rebase.autosquash)" = "true" && autosquash=t
 case "$(git config --bool commit.gpgsign)" in
 true)  gpg_sign_opt=-S ;;
@@ -262,6 +264,9 @@ do
        --keep-empty)
                keep_empty=yes
                ;;
+       --allow-empty-message)
+               allow_empty_message=--allow-empty-message
+               ;;
        --preserve-merges)
                preserve_merges=t
                test -z "$interactive_rebase" && interactive_rebase=implied
diff --git a/hash.h b/hash.h
index 7d7a864f5dd43bb53ee6b31d391df3e15cbdbb08..7c8238bc2ebfded778351b58c16a3854617082c6 100644 (file)
--- a/hash.h
+++ b/hash.h
 #include "block-sha1/sha1.h"
 #endif
 
+#ifndef platform_SHA_CTX
+/*
+ * platform's underlying implementation of SHA-1; could be OpenSSL,
+ * blk_SHA, Apple CommonCrypto, etc...  Note that the relevant
+ * SHA-1 header may have already defined platform_SHA_CTX for our
+ * own implementations like block-sha1 and ppc-sha1, so we list
+ * the default for OpenSSL compatible SHA-1 implementations here.
+ */
+#define platform_SHA_CTX       SHA_CTX
+#define platform_SHA1_Init     SHA1_Init
+#define platform_SHA1_Update   SHA1_Update
+#define platform_SHA1_Final            SHA1_Final
+#endif
+
+#define git_SHA_CTX            platform_SHA_CTX
+#define git_SHA1_Init          platform_SHA1_Init
+#define git_SHA1_Update                platform_SHA1_Update
+#define git_SHA1_Final         platform_SHA1_Final
+
+#ifdef SHA1_MAX_BLOCK_SIZE
+#include "compat/sha1-chunked.h"
+#undef git_SHA1_Update
+#define git_SHA1_Update                git_SHA1_Update_Chunked
+#endif
+
 /*
  * Note that these constants are suitable for indexing the hash_algos array and
  * comparing against each other, but are otherwise arbitrary, so they should not
 /* Number of algorithms supported (including unknown). */
 #define GIT_HASH_NALGOS (GIT_HASH_SHA1 + 1)
 
-typedef void (*git_hash_init_fn)(void *ctx);
-typedef void (*git_hash_update_fn)(void *ctx, const void *in, size_t len);
-typedef void (*git_hash_final_fn)(unsigned char *hash, void *ctx);
+/* A suitably aligned type for stack allocations of hash contexts. */
+union git_hash_ctx {
+       git_SHA_CTX sha1;
+};
+typedef union git_hash_ctx git_hash_ctx;
+
+typedef void (*git_hash_init_fn)(git_hash_ctx *ctx);
+typedef void (*git_hash_update_fn)(git_hash_ctx *ctx, const void *in, size_t len);
+typedef void (*git_hash_final_fn)(unsigned char *hash, git_hash_ctx *ctx);
 
 struct git_hash_algo {
        /*
@@ -44,9 +75,6 @@ struct git_hash_algo {
        /* A four-byte version identifier, used in pack indices. */
        uint32_t format_id;
 
-       /* The size of a hash context (e.g. git_SHA_CTX). */
-       size_t ctxsz;
-
        /* The length of the hash in binary. */
        size_t rawsz;
 
index fca29d4799da27164394a8c59da067a0522241fe..fc0cc0d6d11cbec37b87004f3a56cc4c5495bc72 100644 (file)
@@ -499,7 +499,7 @@ static void show_one_mergetag(struct commit *commit,
        int status, nth;
        size_t payload_size, gpg_message_offset;
 
-       hash_sha1_file(extra->value, extra->len, typename(OBJ_TAG), oid.hash);
+       hash_object_file(extra->value, extra->len, typename(OBJ_TAG), &oid);
        tag = lookup_tag(&oid);
        if (!tag)
                return; /* error message already given */
index 396b7338df2c53009900fbd3df36dd06a7219493..0ca99d51626f49b5d4a88b9edc43c533c970dd0e 100644 (file)
@@ -158,22 +158,20 @@ static void match_trees(const struct object_id *hash1,
 }
 
 /*
- * A tree "hash1" has a subdirectory at "prefix".  Come up with a
- * tree object by replacing it with another tree "hash2".
+ * A tree "oid1" has a subdirectory at "prefix".  Come up with a tree object by
+ * replacing it with another tree "oid2".
  */
-static int splice_tree(const unsigned char *hash1,
-                      const char *prefix,
-                      const unsigned char *hash2,
-                      unsigned char *result)
+static int splice_tree(const struct object_id *oid1, const char *prefix,
+                      const struct object_id *oid2, struct object_id *result)
 {
        char *subpath;
        int toplen;
        char *buf;
        unsigned long sz;
        struct tree_desc desc;
-       unsigned char *rewrite_here;
-       const unsigned char *rewrite_with;
-       unsigned char subtree[20];
+       struct object_id *rewrite_here;
+       const struct object_id *rewrite_with;
+       struct object_id subtree;
        enum object_type type;
        int status;
 
@@ -182,9 +180,9 @@ static int splice_tree(const unsigned char *hash1,
        if (*subpath)
                subpath++;
 
-       buf = read_sha1_file(hash1, &type, &sz);
+       buf = read_sha1_file(oid1->hash, &type, &sz);
        if (!buf)
-               die("cannot read tree %s", sha1_to_hex(hash1));
+               die("cannot read tree %s", oid_to_hex(oid1));
        init_tree_desc(&desc, buf, sz);
 
        rewrite_here = NULL;
@@ -197,26 +195,26 @@ static int splice_tree(const unsigned char *hash1,
                if (strlen(name) == toplen &&
                    !memcmp(name, prefix, toplen)) {
                        if (!S_ISDIR(mode))
-                               die("entry %s in tree %s is not a tree",
-                                   name, sha1_to_hex(hash1));
-                       rewrite_here = (unsigned char *) oid->hash;
+                               die("entry %s in tree %s is not a tree", name,
+                                   oid_to_hex(oid1));
+                       rewrite_here = (struct object_id *)oid;
                        break;
                }
                update_tree_entry(&desc);
        }
        if (!rewrite_here)
-               die("entry %.*s not found in tree %s",
-                   toplen, prefix, sha1_to_hex(hash1));
+               die("entry %.*s not found in tree %s", toplen, prefix,
+                   oid_to_hex(oid1));
        if (*subpath) {
-               status = splice_tree(rewrite_here, subpath, hash2, subtree);
+               status = splice_tree(rewrite_here, subpath, oid2, &subtree);
                if (status)
                        return status;
-               rewrite_with = subtree;
+               rewrite_with = &subtree;
+       } else {
+               rewrite_with = oid2;
        }
-       else
-               rewrite_with = hash2;
-       hashcpy(rewrite_here, rewrite_with);
-       status = write_sha1_file(buf, sz, tree_type, result);
+       oidcpy(rewrite_here, rewrite_with);
+       status = write_object_file(buf, sz, tree_type, result);
        free(buf);
        return status;
 }
@@ -280,7 +278,7 @@ void shift_tree(const struct object_id *hash1,
        if (!*add_prefix)
                return;
 
-       splice_tree(hash1->hash, add_prefix, hash2->hash, shifted->hash);
+       splice_tree(hash1, add_prefix, hash2, shifted);
 }
 
 /*
@@ -334,7 +332,7 @@ void shift_tree_by(const struct object_id *hash1,
                 * shift tree2 down by adding shift_prefix above it
                 * to match tree1.
                 */
-               splice_tree(hash1->hash, shift_prefix, hash2->hash, shifted->hash);
+               splice_tree(hash1, shift_prefix, hash2, shifted);
        else
                /*
                 * shift tree2 up by removing shift_prefix from it
index cc5fa0a94965fad8821cdf81dfe84737f4dee043..6ff971f9a2a8e251b8762d75214697698e2d1ce6 100644 (file)
@@ -513,6 +513,25 @@ static void record_df_conflict_files(struct merge_options *o,
 
 struct rename {
        struct diff_filepair *pair;
+       /*
+        * Purpose of src_entry and dst_entry:
+        *
+        * If 'before' is renamed to 'after' then src_entry will contain
+        * the versions of 'before' from the merge_base, HEAD, and MERGE in
+        * stages 1, 2, and 3; dst_entry will contain the respective
+        * versions of 'after' in corresponding locations.  Thus, we have a
+        * total of six modes and oids, though some will be null.  (Stage 0
+        * is ignored; we're interested in handling conflicts.)
+        *
+        * Since we don't turn on break-rewrites by default, neither
+        * src_entry nor dst_entry can have all three of their stages have
+        * non-null oids, meaning at most four of the six will be non-null.
+        * Also, since this is a rename, both src_entry and dst_entry will
+        * have at least one non-null oid, meaning at least two will be
+        * non-null.  Of the six oids, a typical rename will have three be
+        * non-null.  Only two implies a rename/delete, and four implies a
+        * rename/add.
+        */
        struct stage_data *src_entry;
        struct stage_data *dst_entry;
        unsigned processed:1;
@@ -1009,8 +1028,9 @@ static int merge_file_1(struct merge_options *o,
                        if ((merge_status < 0) || !result_buf.ptr)
                                ret = err(o, _("Failed to execute internal merge"));
 
-                       if (!ret && write_sha1_file(result_buf.ptr, result_buf.size,
-                                                   blob_type, result->oid.hash))
+                       if (!ret &&
+                           write_object_file(result_buf.ptr, result_buf.size,
+                                             blob_type, &result->oid))
                                ret = err(o, _("Unable to add %s to database"),
                                          a->path);
 
@@ -1998,10 +2018,10 @@ int merge_trees(struct merge_options *o,
                get_files_dirs(o, merge);
 
                entries = get_unmerged();
-               record_df_conflict_files(o, entries);
                re_head  = get_renames(o, head, common, head, merge, entries);
                re_merge = get_renames(o, merge, common, head, merge, entries);
                clean = process_renames(o, re_head, re_merge);
+               record_df_conflict_files(o, entries);
                if (clean < 0)
                        goto cleanup;
                for (i = entries->nr-1; 0 <= i; i--) {
index 45c98db0a057e93b5f3f84eba2008da86130010d..ada66f066a002ac5ecb73f94a582d758c0a3a657 100644 (file)
@@ -578,6 +578,8 @@ static void threaded_lazy_init_name_hash(
 
 static void lazy_init_name_hash(struct index_state *istate)
 {
+       uint64_t start = getnanotime();
+
        if (istate->name_hash_initialized)
                return;
        hashmap_init(&istate->name_hash, cache_entry_cmp, NULL, istate->cache_nr);
@@ -600,6 +602,7 @@ static void lazy_init_name_hash(struct index_state *istate)
        }
 
        istate->name_hash_initialized = 1;
+       trace_performance_since(start, "initialize name hash");
 }
 
 /*
index 17ee8602b3d2fbc2469a98e6cdeab0f2ff2b7ad3..398e61d5e943b1e6e143f159739f83fc0df9b6b8 100644 (file)
@@ -54,10 +54,10 @@ int notes_cache_write(struct notes_cache *c)
        if (!c->tree.dirty)
                return 0;
 
-       if (write_notes_tree(&c->tree, tree_oid.hash))
+       if (write_notes_tree(&c->tree, &tree_oid))
                return -1;
-       if (commit_tree(c->validity, strlen(c->validity), tree_oid.hash, NULL,
-                       commit_oid.hash, NULL, NULL) < 0)
+       if (commit_tree(c->validity, strlen(c->validity), &tree_oid, NULL,
+                       &commit_oid, NULL, NULL) < 0)
                return -1;
        if (update_ref("update notes cache", c->tree.update_ref, &commit_oid,
                       NULL, 0, UPDATE_REFS_QUIET_ON_ERR) < 0)
@@ -88,7 +88,7 @@ int notes_cache_put(struct notes_cache *c, struct object_id *key_oid,
 {
        struct object_id value_oid;
 
-       if (write_sha1_file(data, size, "blob", value_oid.hash) < 0)
+       if (write_object_file(data, size, "blob", &value_oid) < 0)
                return -1;
        return add_note(&c->tree, key_oid, &value_oid, NULL);
 }
index 0f6573cb17cbbbc2219453bdca424fd7ebc156dc..c09c5e0e474a30b0a8bf3d91063c8bbc61e63557 100644 (file)
@@ -642,9 +642,8 @@ int notes_merge(struct notes_merge_options *o,
                struct commit_list *parents = NULL;
                commit_list_insert(remote, &parents); /* LIFO order */
                commit_list_insert(local, &parents);
-               create_notes_commit(local_tree, parents,
-                                   o->commit_msg.buf, o->commit_msg.len,
-                                   result_oid->hash);
+               create_notes_commit(local_tree, parents, o->commit_msg.buf,
+                                   o->commit_msg.len, result_oid);
        }
 
 found_result:
@@ -718,8 +717,8 @@ int notes_merge_commit(struct notes_merge_options *o,
                strbuf_setlen(&path, baselen);
        }
 
-       create_notes_commit(partial_tree, partial_commit->parents,
-                           msg, strlen(msg), result_oid->hash);
+       create_notes_commit(partial_tree, partial_commit->parents, msg,
+                           strlen(msg), result_oid);
        unuse_commit_buffer(partial_commit, buffer);
        if (o->verbosity >= 4)
                printf("Finalized notes merge commit: %s\n",
index 5c8e70c98fd26cca8bc690bc92653dd578a78c92..02407fe2a7327947dda6bf755405d2778ae450ae 100644 (file)
@@ -6,13 +6,13 @@
 
 void create_notes_commit(struct notes_tree *t, struct commit_list *parents,
                         const char *msg, size_t msg_len,
-                        unsigned char *result_sha1)
+                        struct object_id *result_oid)
 {
        struct object_id tree_oid;
 
        assert(t->initialized);
 
-       if (write_notes_tree(t, tree_oid.hash))
+       if (write_notes_tree(t, &tree_oid))
                die("Failed to write notes tree to database");
 
        if (!parents) {
@@ -27,7 +27,8 @@ void create_notes_commit(struct notes_tree *t, struct commit_list *parents,
                /* else: t->ref points to nothing, assume root/orphan commit */
        }
 
-       if (commit_tree(msg, msg_len, tree_oid.hash, parents, result_sha1, NULL, NULL))
+       if (commit_tree(msg, msg_len, &tree_oid, parents, result_oid, NULL,
+                       NULL))
                die("Failed to commit notes tree to database");
 }
 
@@ -47,7 +48,7 @@ void commit_notes(struct notes_tree *t, const char *msg)
        strbuf_addstr(&buf, msg);
        strbuf_complete_line(&buf);
 
-       create_notes_commit(t, NULL, buf.buf, buf.len, commit_oid.hash);
+       create_notes_commit(t, NULL, buf.buf, buf.len, &commit_oid);
        strbuf_insert(&buf, 0, "notes: ", 7); /* commit message starts at index 7 */
        update_ref(buf.buf, t->update_ref, &commit_oid, NULL, 0,
                   UPDATE_REFS_DIE_ON_ERR);
index 11905783989aa0d87be08e0c4311762b4647e9a4..5d79cbef512e3bdbbfafedbd7650036aff695f83 100644 (file)
@@ -15,7 +15,8 @@
  * The resulting commit SHA1 is stored in result_sha1.
  */
 void create_notes_commit(struct notes_tree *t, struct commit_list *parents,
-                        const char *msg, size_t msg_len, unsigned char *result_sha1);
+                        const char *msg, size_t msg_len,
+                        struct object_id *result_oid);
 
 void commit_notes(struct notes_tree *t, const char *msg);
 
diff --git a/notes.c b/notes.c
index c7f21fae441067f7250caf0b4186fcbcbc7630bb..ce9a8f53f8668bbbf790f3b2d20f641fc034c301 100644 (file)
--- a/notes.c
+++ b/notes.c
@@ -270,8 +270,8 @@ static int note_tree_insert(struct notes_tree *t, struct int_node *tree,
                                if (!oidcmp(&l->val_oid, &entry->val_oid))
                                        return 0;
 
-                               ret = combine_notes(l->val_oid.hash,
-                                                   entry->val_oid.hash);
+                               ret = combine_notes(&l->val_oid,
+                                                   &entry->val_oid);
                                if (!ret && is_null_oid(&l->val_oid))
                                        note_tree_remove(t, tree, n, entry);
                                free(entry);
@@ -667,7 +667,7 @@ static int tree_write_stack_finish_subtree(struct tree_write_stack *tws)
                ret = tree_write_stack_finish_subtree(n);
                if (ret)
                        return ret;
-               ret = write_sha1_file(n->buf.buf, n->buf.len, tree_type, s.hash);
+               ret = write_object_file(n->buf.buf, n->buf.len, tree_type, &s);
                if (ret)
                        return ret;
                strbuf_release(&n->buf);
@@ -786,8 +786,8 @@ static int prune_notes_helper(const struct object_id *object_oid,
        return 0;
 }
 
-int combine_notes_concatenate(unsigned char *cur_sha1,
-               const unsigned char *new_sha1)
+int combine_notes_concatenate(struct object_id *cur_oid,
+                             const struct object_id *new_oid)
 {
        char *cur_msg = NULL, *new_msg = NULL, *buf;
        unsigned long cur_len, new_len, buf_len;
@@ -795,18 +795,18 @@ int combine_notes_concatenate(unsigned char *cur_sha1,
        int ret;
 
        /* read in both note blob objects */
-       if (!is_null_sha1(new_sha1))
-               new_msg = read_sha1_file(new_sha1, &new_type, &new_len);
+       if (!is_null_oid(new_oid))
+               new_msg = read_sha1_file(new_oid->hash, &new_type, &new_len);
        if (!new_msg || !new_len || new_type != OBJ_BLOB) {
                free(new_msg);
                return 0;
        }
-       if (!is_null_sha1(cur_sha1))
-               cur_msg = read_sha1_file(cur_sha1, &cur_type, &cur_len);
+       if (!is_null_oid(cur_oid))
+               cur_msg = read_sha1_file(cur_oid->hash, &cur_type, &cur_len);
        if (!cur_msg || !cur_len || cur_type != OBJ_BLOB) {
                free(cur_msg);
                free(new_msg);
-               hashcpy(cur_sha1, new_sha1);
+               oidcpy(cur_oid, new_oid);
                return 0;
        }
 
@@ -825,20 +825,20 @@ int combine_notes_concatenate(unsigned char *cur_sha1,
        free(new_msg);
 
        /* create a new blob object from buf */
-       ret = write_sha1_file(buf, buf_len, blob_type, cur_sha1);
+       ret = write_object_file(buf, buf_len, blob_type, cur_oid);
        free(buf);
        return ret;
 }
 
-int combine_notes_overwrite(unsigned char *cur_sha1,
-               const unsigned char *new_sha1)
+int combine_notes_overwrite(struct object_id *cur_oid,
+                           const struct object_id *new_oid)
 {
-       hashcpy(cur_sha1, new_sha1);
+       oidcpy(cur_oid, new_oid);
        return 0;
 }
 
-int combine_notes_ignore(unsigned char *cur_sha1,
-               const unsigned char *new_sha1)
+int combine_notes_ignore(struct object_id *cur_oid,
+                        const struct object_id *new_oid)
 {
        return 0;
 }
@@ -848,17 +848,17 @@ int combine_notes_ignore(unsigned char *cur_sha1,
  * newlines removed.
  */
 static int string_list_add_note_lines(struct string_list *list,
-                                     const unsigned char *sha1)
+                                     const struct object_id *oid)
 {
        char *data;
        unsigned long len;
        enum object_type t;
 
-       if (is_null_sha1(sha1))
+       if (is_null_oid(oid))
                return 0;
 
        /* read_sha1_file NUL-terminates */
-       data = read_sha1_file(sha1, &t, &len);
+       data = read_sha1_file(oid->hash, &t, &len);
        if (t != OBJ_BLOB || !data || !len) {
                free(data);
                return t != OBJ_BLOB || !data;
@@ -884,17 +884,17 @@ static int string_list_join_lines_helper(struct string_list_item *item,
        return 0;
 }
 
-int combine_notes_cat_sort_uniq(unsigned char *cur_sha1,
-               const unsigned char *new_sha1)
+int combine_notes_cat_sort_uniq(struct object_id *cur_oid,
+                               const struct object_id *new_oid)
 {
        struct string_list sort_uniq_list = STRING_LIST_INIT_DUP;
        struct strbuf buf = STRBUF_INIT;
        int ret = 1;
 
        /* read both note blob objects into unique_lines */
-       if (string_list_add_note_lines(&sort_uniq_list, cur_sha1))
+       if (string_list_add_note_lines(&sort_uniq_list, cur_oid))
                goto out;
-       if (string_list_add_note_lines(&sort_uniq_list, new_sha1))
+       if (string_list_add_note_lines(&sort_uniq_list, new_oid))
                goto out;
        string_list_remove_empty_items(&sort_uniq_list, 0);
        string_list_sort(&sort_uniq_list);
@@ -905,7 +905,7 @@ int combine_notes_cat_sort_uniq(unsigned char *cur_sha1,
                                 string_list_join_lines_helper, &buf))
                goto out;
 
-       ret = write_sha1_file(buf.buf, buf.len, blob_type, cur_sha1);
+       ret = write_object_file(buf.buf, buf.len, blob_type, cur_oid);
 
 out:
        strbuf_release(&buf);
@@ -1123,11 +1123,12 @@ int for_each_note(struct notes_tree *t, int flags, each_note_fn fn,
        return for_each_note_helper(t, t->root, 0, 0, flags, fn, cb_data);
 }
 
-int write_notes_tree(struct notes_tree *t, unsigned char *result)
+int write_notes_tree(struct notes_tree *t, struct object_id *result)
 {
        struct tree_write_stack root;
        struct write_each_note_data cb_data;
        int ret;
+       int flags;
 
        if (!t)
                t = &default_notes_tree;
@@ -1141,12 +1142,12 @@ int write_notes_tree(struct notes_tree *t, unsigned char *result)
        cb_data.next_non_note = t->first_non_note;
 
        /* Write tree objects representing current notes tree */
-       ret = for_each_note(t, FOR_EACH_NOTE_DONT_UNPACK_SUBTREES |
-                               FOR_EACH_NOTE_YIELD_SUBTREES,
-                       write_each_note, &cb_data) ||
-               write_each_non_note_until(NULL, &cb_data) ||
-               tree_write_stack_finish_subtree(&root) ||
-               write_sha1_file(root.buf.buf, root.buf.len, tree_type, result);
+       flags = FOR_EACH_NOTE_DONT_UNPACK_SUBTREES |
+               FOR_EACH_NOTE_YIELD_SUBTREES;
+       ret = for_each_note(t, flags, write_each_note, &cb_data) ||
+             write_each_non_note_until(NULL, &cb_data) ||
+             tree_write_stack_finish_subtree(&root) ||
+             write_object_file(root.buf.buf, root.buf.len, tree_type, result);
        strbuf_release(&root.buf);
        return ret;
 }
diff --git a/notes.h b/notes.h
index 3848c2fb3f03510c1d0e1bd23ef6fbb3060b89c6..0433f45db55b5b807abcd633f507e9c75324d4e6 100644 (file)
--- a/notes.h
+++ b/notes.h
@@ -9,27 +9,32 @@
  * When adding a new note annotating the same object as an existing note, it is
  * up to the caller to decide how to combine the two notes. The decision is
  * made by passing in a function of the following form. The function accepts
- * two SHA1s -- of the existing note and the new note, respectively. The
+ * two object_ids -- of the existing note and the new note, respectively. The
  * function then combines the notes in whatever way it sees fit, and writes the
- * resulting SHA1 into the first SHA1 argument (cur_sha1). A non-zero return
+ * resulting oid into the first argument (cur_oid). A non-zero return
  * value indicates failure.
  *
- * The two given SHA1s shall both be non-NULL and different from each other.
- * Either of them (but not both) may be == null_sha1, which indicates an
- * empty/non-existent note. If the resulting SHA1 (cur_sha1) is == null_sha1,
+ * The two given object_ids shall both be non-NULL and different from each
+ * other. Either of them (but not both) may be == null_oid, which indicates an
+ * empty/non-existent note. If the resulting oid (cur_oid) is == null_oid,
  * the note will be removed from the notes tree.
  *
  * The default combine_notes function (you get this when passing NULL) is
  * combine_notes_concatenate(), which appends the contents of the new note to
  * the contents of the existing note.
  */
-typedef int (*combine_notes_fn)(unsigned char *cur_sha1, const unsigned char *new_sha1);
+typedef int (*combine_notes_fn)(struct object_id *cur_oid,
+                               const struct object_id *new_oid);
 
 /* Common notes combinators */
-int combine_notes_concatenate(unsigned char *cur_sha1, const unsigned char *new_sha1);
-int combine_notes_overwrite(unsigned char *cur_sha1, const unsigned char *new_sha1);
-int combine_notes_ignore(unsigned char *cur_sha1, const unsigned char *new_sha1);
-int combine_notes_cat_sort_uniq(unsigned char *cur_sha1, const unsigned char *new_sha1);
+int combine_notes_concatenate(struct object_id *cur_oid,
+                             const struct object_id *new_oid);
+int combine_notes_overwrite(struct object_id *cur_oid,
+                           const struct object_id *new_oid);
+int combine_notes_ignore(struct object_id *cur_oid,
+                        const struct object_id *new_oid);
+int combine_notes_cat_sort_uniq(struct object_id *cur_oid,
+                               const struct object_id *new_oid);
 
 /*
  * Notes tree object
@@ -212,7 +217,7 @@ int for_each_note(struct notes_tree *t, int flags, each_note_fn fn,
  * Write the given notes_tree structure to the object database
  *
  * Creates a new tree object encapsulating the current state of the given
- * notes_tree, and stores its SHA1 into the 'result' argument.
+ * notes_tree, and stores its object id into the 'result' argument.
  *
  * Returns zero on success, non-zero on failure.
  *
@@ -220,7 +225,7 @@ int for_each_note(struct notes_tree *t, int flags, each_note_fn fn,
  * this function has returned zero. Please also remember to create a
  * corresponding commit object, and update the appropriate notes ref.
  */
-int write_notes_tree(struct notes_tree *t, unsigned char *result);
+int write_notes_tree(struct notes_tree *t, struct object_id *result);
 
 /* Flags controlling the operation of prune */
 #define NOTES_PRUNE_VERBOSE 1
index a8df5ce2ab67bfdb5445e4c02e4ad65032abe9a0..e01f9928840488b85db2ebc62527d8e4aab81ffc 100644 (file)
@@ -440,19 +440,19 @@ void bitmap_writer_select_commits(struct commit **indexed_commits,
 }
 
 
-static int sha1write_ewah_helper(void *f, const void *buf, size_t len)
+static int hashwrite_ewah_helper(void *f, const void *buf, size_t len)
 {
-       /* sha1write will die on error */
-       sha1write(f, buf, len);
+       /* hashwrite will die on error */
+       hashwrite(f, buf, len);
        return len;
 }
 
 /**
  * Write the bitmap index to disk
  */
-static inline void dump_bitmap(struct sha1file *f, struct ewah_bitmap *bitmap)
+static inline void dump_bitmap(struct hashfile *f, struct ewah_bitmap *bitmap)
 {
-       if (ewah_serialize_to(bitmap, sha1write_ewah_helper, f) < 0)
+       if (ewah_serialize_to(bitmap, hashwrite_ewah_helper, f) < 0)
                die("Failed to write bitmap index");
 }
 
@@ -462,7 +462,7 @@ static const unsigned char *sha1_access(size_t pos, void *table)
        return index[pos]->oid.hash;
 }
 
-static void write_selected_commits_v1(struct sha1file *f,
+static void write_selected_commits_v1(struct hashfile *f,
                                      struct pack_idx_entry **index,
                                      uint32_t index_nr)
 {
@@ -477,15 +477,15 @@ static void write_selected_commits_v1(struct sha1file *f,
                if (commit_pos < 0)
                        die("BUG: trying to write commit not in index");
 
-               sha1write_be32(f, commit_pos);
-               sha1write_u8(f, stored->xor_offset);
-               sha1write_u8(f, stored->flags);
+               hashwrite_be32(f, commit_pos);
+               hashwrite_u8(f, stored->xor_offset);
+               hashwrite_u8(f, stored->flags);
 
                dump_bitmap(f, stored->write_as);
        }
 }
 
-static void write_hash_cache(struct sha1file *f,
+static void write_hash_cache(struct hashfile *f,
                             struct pack_idx_entry **index,
                             uint32_t index_nr)
 {
@@ -494,7 +494,7 @@ static void write_hash_cache(struct sha1file *f,
        for (i = 0; i < index_nr; ++i) {
                struct object_entry *entry = (struct object_entry *)index[i];
                uint32_t hash_value = htonl(entry->hash);
-               sha1write(f, &hash_value, sizeof(hash_value));
+               hashwrite(f, &hash_value, sizeof(hash_value));
        }
 }
 
@@ -511,13 +511,13 @@ void bitmap_writer_finish(struct pack_idx_entry **index,
        static uint16_t default_version = 1;
        static uint16_t flags = BITMAP_OPT_FULL_DAG;
        struct strbuf tmp_file = STRBUF_INIT;
-       struct sha1file *f;
+       struct hashfile *f;
 
        struct bitmap_disk_header header;
 
        int fd = odb_mkstemp(&tmp_file, "pack/tmp_bitmap_XXXXXX");
 
-       f = sha1fd(fd, tmp_file.buf);
+       f = hashfd(fd, tmp_file.buf);
 
        memcpy(header.magic, BITMAP_IDX_SIGNATURE, sizeof(BITMAP_IDX_SIGNATURE));
        header.version = htons(default_version);
@@ -525,7 +525,7 @@ void bitmap_writer_finish(struct pack_idx_entry **index,
        header.entry_count = htonl(writer.selected_nr);
        hashcpy(header.checksum, writer.pack_checksum);
 
-       sha1write(f, &header, sizeof(header));
+       hashwrite(f, &header, sizeof(header));
        dump_bitmap(f, writer.commits);
        dump_bitmap(f, writer.trees);
        dump_bitmap(f, writer.blobs);
@@ -535,7 +535,7 @@ void bitmap_writer_finish(struct pack_idx_entry **index,
        if (options & BITMAP_OPT_HASH_CACHE)
                write_hash_cache(f, index, index_nr);
 
-       sha1close(f, NULL, CSUM_FSYNC);
+       hashclose(f, NULL, CSUM_FSYNC);
 
        if (adjust_shared_perm(tmp_file.buf))
                die_errno("unable to make temporary bitmap file readable");
index 073c1fbd46dfeeb215c209aa0659768e72b81c3b..403a5725675e59b94322ef30e8aae9b04b3ff87a 100644 (file)
@@ -41,7 +41,7 @@ int check_pack_crc(struct packed_git *p, struct pack_window **w_curs,
        } while (len);
 
        index_crc = p->index_data;
-       index_crc += 2 + 256 + p->num_objects * (20/4) + nr;
+       index_crc += 2 + 256 + p->num_objects * (the_hash_algo->rawsz/4) + nr;
 
        return data_crc != ntohl(*index_crc);
 }
@@ -54,7 +54,7 @@ static int verify_packfile(struct packed_git *p,
 {
        off_t index_size = p->index_size;
        const unsigned char *index_base = p->index_data;
-       git_SHA_CTX ctx;
+       git_hash_ctx ctx;
        unsigned char hash[GIT_MAX_RAWSZ], *pack_sig;
        off_t offset = 0, pack_sig_ofs = 0;
        uint32_t nr_objects, i;
@@ -64,24 +64,24 @@ static int verify_packfile(struct packed_git *p,
        if (!is_pack_valid(p))
                return error("packfile %s cannot be accessed", p->pack_name);
 
-       git_SHA1_Init(&ctx);
+       the_hash_algo->init_fn(&ctx);
        do {
                unsigned long remaining;
                unsigned char *in = use_pack(p, w_curs, offset, &remaining);
                offset += remaining;
                if (!pack_sig_ofs)
-                       pack_sig_ofs = p->pack_size - 20;
+                       pack_sig_ofs = p->pack_size - the_hash_algo->rawsz;
                if (offset > pack_sig_ofs)
                        remaining -= (unsigned int)(offset - pack_sig_ofs);
-               git_SHA1_Update(&ctx, in, remaining);
+               the_hash_algo->update_fn(&ctx, in, remaining);
        } while (offset < pack_sig_ofs);
-       git_SHA1_Final(hash, &ctx);
+       the_hash_algo->final_fn(hash, &ctx);
        pack_sig = use_pack(p, w_curs, pack_sig_ofs, NULL);
        if (hashcmp(hash, pack_sig))
-               err = error("%s SHA1 checksum mismatch",
+               err = error("%s pack checksum mismatch",
                            p->pack_name);
-       if (hashcmp(index_base + index_size - 40, pack_sig))
-               err = error("%s SHA1 does not match its index",
+       if (hashcmp(index_base + index_size - the_hash_algo->hexsz, pack_sig))
+               err = error("%s pack checksum does not match its index",
                            p->pack_name);
        unuse_pack(w_curs);
 
@@ -165,8 +165,8 @@ int verify_pack_index(struct packed_git *p)
 {
        off_t index_size;
        const unsigned char *index_base;
-       git_SHA_CTX ctx;
-       unsigned char sha1[20];
+       git_hash_ctx ctx;
+       unsigned char hash[GIT_MAX_RAWSZ];
        int err = 0;
 
        if (open_pack_index(p))
@@ -175,11 +175,11 @@ int verify_pack_index(struct packed_git *p)
        index_base = p->index_data;
 
        /* Verify SHA1 sum of the index file */
-       git_SHA1_Init(&ctx);
-       git_SHA1_Update(&ctx, index_base, (unsigned int)(index_size - 20));
-       git_SHA1_Final(sha1, &ctx);
-       if (hashcmp(sha1, index_base + index_size - 20))
-               err = error("Packfile index for %s SHA1 mismatch",
+       the_hash_algo->init_fn(&ctx);
+       the_hash_algo->update_fn(&ctx, index_base, (unsigned int)(index_size - the_hash_algo->rawsz));
+       the_hash_algo->final_fn(hash, &ctx);
+       if (hashcmp(hash, index_base + index_size - the_hash_algo->rawsz))
+               err = error("Packfile index for %s hash mismatch",
                            p->pack_name);
        return err;
 }
index fea62841920c9647edfcfba249a59bfb91170d8e..d775c7406dd5a869a1ce4d28f6ef872e08476b77 100644 (file)
@@ -46,7 +46,7 @@ const char *write_idx_file(const char *index_name, struct pack_idx_entry **objec
                           int nr_objects, const struct pack_idx_option *opts,
                           const unsigned char *sha1)
 {
-       struct sha1file *f;
+       struct hashfile *f;
        struct pack_idx_entry **sorted_by_sha, **list, **last;
        off_t last_obj_offset = 0;
        uint32_t array[256];
@@ -68,7 +68,7 @@ const char *write_idx_file(const char *index_name, struct pack_idx_entry **objec
 
        if (opts->flags & WRITE_IDX_VERIFY) {
                assert(index_name);
-               f = sha1fd_check(index_name);
+               f = hashfd_check(index_name);
        } else {
                if (!index_name) {
                        struct strbuf tmp_file = STRBUF_INIT;
@@ -80,7 +80,7 @@ const char *write_idx_file(const char *index_name, struct pack_idx_entry **objec
                        if (fd < 0)
                                die_errno("unable to create '%s'", index_name);
                }
-               f = sha1fd(fd, index_name);
+               f = hashfd(fd, index_name);
        }
 
        /* if last object's offset is >= 2^31 we should use index V2 */
@@ -91,7 +91,7 @@ const char *write_idx_file(const char *index_name, struct pack_idx_entry **objec
                struct pack_idx_header hdr;
                hdr.idx_signature = htonl(PACK_IDX_SIGNATURE);
                hdr.idx_version = htonl(index_version);
-               sha1write(f, &hdr, sizeof(hdr));
+               hashwrite(f, &hdr, sizeof(hdr));
        }
 
        /*
@@ -110,7 +110,7 @@ const char *write_idx_file(const char *index_name, struct pack_idx_entry **objec
                array[i] = htonl(next - sorted_by_sha);
                list = next;
        }
-       sha1write(f, array, 256 * 4);
+       hashwrite(f, array, 256 * 4);
 
        /*
         * Write the actual SHA1 entries..
@@ -120,9 +120,9 @@ const char *write_idx_file(const char *index_name, struct pack_idx_entry **objec
                struct pack_idx_entry *obj = *list++;
                if (index_version < 2) {
                        uint32_t offset = htonl(obj->offset);
-                       sha1write(f, &offset, 4);
+                       hashwrite(f, &offset, 4);
                }
-               sha1write(f, obj->oid.hash, 20);
+               hashwrite(f, obj->oid.hash, the_hash_algo->rawsz);
                if ((opts->flags & WRITE_IDX_STRICT) &&
                    (i && !oidcmp(&list[-2]->oid, &obj->oid)))
                        die("The same object %s appears twice in the pack",
@@ -137,7 +137,7 @@ const char *write_idx_file(const char *index_name, struct pack_idx_entry **objec
                for (i = 0; i < nr_objects; i++) {
                        struct pack_idx_entry *obj = *list++;
                        uint32_t crc32_val = htonl(obj->crc32);
-                       sha1write(f, &crc32_val, 4);
+                       hashwrite(f, &crc32_val, 4);
                }
 
                /* write the 32-bit offset table */
@@ -150,7 +150,7 @@ const char *write_idx_file(const char *index_name, struct pack_idx_entry **objec
                                  ? (0x80000000 | nr_large_offset++)
                                  : obj->offset);
                        offset = htonl(offset);
-                       sha1write(f, &offset, 4);
+                       hashwrite(f, &offset, 4);
                }
 
                /* write the large offset table */
@@ -164,25 +164,25 @@ const char *write_idx_file(const char *index_name, struct pack_idx_entry **objec
                                continue;
                        split[0] = htonl(offset >> 32);
                        split[1] = htonl(offset & 0xffffffff);
-                       sha1write(f, split, 8);
+                       hashwrite(f, split, 8);
                        nr_large_offset--;
                }
        }
 
-       sha1write(f, sha1, 20);
-       sha1close(f, NULL, ((opts->flags & WRITE_IDX_VERIFY)
+       hashwrite(f, sha1, the_hash_algo->rawsz);
+       hashclose(f, NULL, ((opts->flags & WRITE_IDX_VERIFY)
                            ? CSUM_CLOSE : CSUM_FSYNC));
        return index_name;
 }
 
-off_t write_pack_header(struct sha1file *f, uint32_t nr_entries)
+off_t write_pack_header(struct hashfile *f, uint32_t nr_entries)
 {
        struct pack_header hdr;
 
        hdr.hdr_signature = htonl(PACK_SIGNATURE);
        hdr.hdr_version = htonl(PACK_VERSION);
        hdr.hdr_entries = htonl(nr_entries);
-       sha1write(f, &hdr, sizeof(hdr));
+       hashwrite(f, &hdr, sizeof(hdr));
        return sizeof(hdr);
 }
 
@@ -203,20 +203,20 @@ off_t write_pack_header(struct sha1file *f, uint32_t nr_entries)
  * interested in the resulting SHA1 of pack data above partial_pack_offset.
  */
 void fixup_pack_header_footer(int pack_fd,
-                        unsigned char *new_pack_sha1,
+                        unsigned char *new_pack_hash,
                         const char *pack_name,
                         uint32_t object_count,
-                        unsigned char *partial_pack_sha1,
+                        unsigned char *partial_pack_hash,
                         off_t partial_pack_offset)
 {
        int aligned_sz, buf_sz = 8 * 1024;
-       git_SHA_CTX old_sha1_ctx, new_sha1_ctx;
+       git_hash_ctx old_hash_ctx, new_hash_ctx;
        struct pack_header hdr;
        char *buf;
        ssize_t read_result;
 
-       git_SHA1_Init(&old_sha1_ctx);
-       git_SHA1_Init(&new_sha1_ctx);
+       the_hash_algo->init_fn(&old_hash_ctx);
+       the_hash_algo->init_fn(&new_hash_ctx);
 
        if (lseek(pack_fd, 0, SEEK_SET) != 0)
                die_errno("Failed seeking to start of '%s'", pack_name);
@@ -228,9 +228,9 @@ void fixup_pack_header_footer(int pack_fd,
                          pack_name);
        if (lseek(pack_fd, 0, SEEK_SET) != 0)
                die_errno("Failed seeking to start of '%s'", pack_name);
-       git_SHA1_Update(&old_sha1_ctx, &hdr, sizeof(hdr));
+       the_hash_algo->update_fn(&old_hash_ctx, &hdr, sizeof(hdr));
        hdr.hdr_entries = htonl(object_count);
-       git_SHA1_Update(&new_sha1_ctx, &hdr, sizeof(hdr));
+       the_hash_algo->update_fn(&new_hash_ctx, &hdr, sizeof(hdr));
        write_or_die(pack_fd, &hdr, sizeof(hdr));
        partial_pack_offset -= sizeof(hdr);
 
@@ -238,28 +238,28 @@ void fixup_pack_header_footer(int pack_fd,
        aligned_sz = buf_sz - sizeof(hdr);
        for (;;) {
                ssize_t m, n;
-               m = (partial_pack_sha1 && partial_pack_offset < aligned_sz) ?
+               m = (partial_pack_hash && partial_pack_offset < aligned_sz) ?
                        partial_pack_offset : aligned_sz;
                n = xread(pack_fd, buf, m);
                if (!n)
                        break;
                if (n < 0)
                        die_errno("Failed to checksum '%s'", pack_name);
-               git_SHA1_Update(&new_sha1_ctx, buf, n);
+               the_hash_algo->update_fn(&new_hash_ctx, buf, n);
 
                aligned_sz -= n;
                if (!aligned_sz)
                        aligned_sz = buf_sz;
 
-               if (!partial_pack_sha1)
+               if (!partial_pack_hash)
                        continue;
 
-               git_SHA1_Update(&old_sha1_ctx, buf, n);
+               the_hash_algo->update_fn(&old_hash_ctx, buf, n);
                partial_pack_offset -= n;
                if (partial_pack_offset == 0) {
-                       unsigned char sha1[20];
-                       git_SHA1_Final(sha1, &old_sha1_ctx);
-                       if (hashcmp(sha1, partial_pack_sha1) != 0)
+                       unsigned char hash[GIT_MAX_RAWSZ];
+                       the_hash_algo->final_fn(hash, &old_hash_ctx);
+                       if (hashcmp(hash, partial_pack_hash) != 0)
                                die("Unexpected checksum for %s "
                                    "(disk corruption?)", pack_name);
                        /*
@@ -267,23 +267,24 @@ void fixup_pack_header_footer(int pack_fd,
                         * pack, which also means making partial_pack_offset
                         * big enough not to matter anymore.
                         */
-                       git_SHA1_Init(&old_sha1_ctx);
+                       the_hash_algo->init_fn(&old_hash_ctx);
                        partial_pack_offset = ~partial_pack_offset;
                        partial_pack_offset -= MSB(partial_pack_offset, 1);
                }
        }
        free(buf);
 
-       if (partial_pack_sha1)
-               git_SHA1_Final(partial_pack_sha1, &old_sha1_ctx);
-       git_SHA1_Final(new_pack_sha1, &new_sha1_ctx);
-       write_or_die(pack_fd, new_pack_sha1, 20);
+       if (partial_pack_hash)
+               the_hash_algo->final_fn(partial_pack_hash, &old_hash_ctx);
+       the_hash_algo->final_fn(new_pack_hash, &new_hash_ctx);
+       write_or_die(pack_fd, new_pack_hash, the_hash_algo->rawsz);
        fsync_or_die(pack_fd, pack_name);
 }
 
 char *index_pack_lockfile(int ip_out)
 {
-       char packname[46];
+       char packname[GIT_MAX_HEXSZ + 6];
+       const int len = the_hash_algo->hexsz + 6;
 
        /*
         * The first thing we expect from index-pack's output
@@ -292,9 +293,9 @@ char *index_pack_lockfile(int ip_out)
         * case, we need it to remove the corresponding .keep file
         * later on.  If we don't get that then tough luck with it.
         */
-       if (read_in_full(ip_out, packname, 46) == 46 && packname[45] == '\n') {
+       if (read_in_full(ip_out, packname, len) == len && packname[len-1] == '\n') {
                const char *name;
-               packname[45] = 0;
+               packname[len-1] = 0;
                if (skip_prefix(packname, "keep\t", &name))
                        return xstrfmt("%s/pack/pack-%s.keep",
                                       get_object_directory(), name);
@@ -332,14 +333,14 @@ int encode_in_pack_object_header(unsigned char *hdr, int hdr_len,
        return n;
 }
 
-struct sha1file *create_tmp_packfile(char **pack_tmp_name)
+struct hashfile *create_tmp_packfile(char **pack_tmp_name)
 {
        struct strbuf tmpname = STRBUF_INIT;
        int fd;
 
        fd = odb_mkstemp(&tmpname, "pack/tmp_pack_XXXXXX");
        *pack_tmp_name = strbuf_detach(&tmpname, NULL);
-       return sha1fd(fd, *pack_tmp_name);
+       return hashfd(fd, *pack_tmp_name);
 }
 
 void finish_tmp_packfile(struct strbuf *name_buffer,
diff --git a/pack.h b/pack.h
index 8294341af174ad67693006dfcb49a7208732f45b..34a9d458b411927b7c1e121e88387e022841ea2a 100644 (file)
--- a/pack.h
+++ b/pack.h
@@ -81,7 +81,7 @@ extern const char *write_idx_file(const char *index_name, struct pack_idx_entry
 extern int check_pack_crc(struct packed_git *p, struct pack_window **w_curs, off_t offset, off_t len, unsigned int nr);
 extern int verify_pack_index(struct packed_git *);
 extern int verify_pack(struct packed_git *, verify_fn fn, struct progress *, uint32_t);
-extern off_t write_pack_header(struct sha1file *f, uint32_t);
+extern off_t write_pack_header(struct hashfile *f, uint32_t);
 extern void fixup_pack_header_footer(int, unsigned char *, const char *, uint32_t, unsigned char *, off_t);
 extern char *index_pack_lockfile(int fd);
 
@@ -98,7 +98,7 @@ extern int encode_in_pack_object_header(unsigned char *hdr, int hdr_len,
 #define PH_ERROR_PROTOCOL      (-3)
 extern int read_pack_header(int fd, struct pack_header *);
 
-extern struct sha1file *create_tmp_packfile(char **pack_tmp_name);
+extern struct hashfile *create_tmp_packfile(char **pack_tmp_name);
 extern void finish_tmp_packfile(struct strbuf *name_buffer, const char *pack_tmp_name, struct pack_idx_entry **written_list, uint32_t nr_written, struct pack_idx_option *pack_idx_opts, unsigned char sha1[]);
 
 #endif
index 7dbe8739d17d64fad79eac9e7477d00ea3d80df2..860e6d7fe4d0d115b0b635599271f302c5bedb69 100644 (file)
@@ -1722,11 +1722,8 @@ off_t find_pack_entry_one(const unsigned char *sha1,
 {
        const uint32_t *level1_ofs = p->index_data;
        const unsigned char *index = p->index_data;
-       unsigned hi, lo, stride;
-       static int debug_lookup = -1;
-
-       if (debug_lookup < 0)
-               debug_lookup = !!getenv("GIT_DEBUG_LOOKUP");
+       unsigned stride;
+       int ret;
 
        if (!index) {
                if (open_pack_index(p))
@@ -1739,8 +1736,6 @@ off_t find_pack_entry_one(const unsigned char *sha1,
                index += 8;
        }
        index += 4 * 256;
-       hi = ntohl(level1_ofs[*sha1]);
-       lo = ((*sha1 == 0x0) ? 0 : ntohl(level1_ofs[*sha1 - 1]));
        if (p->index_version > 1) {
                stride = 20;
        } else {
@@ -1748,24 +1743,9 @@ off_t find_pack_entry_one(const unsigned char *sha1,
                index += 4;
        }
 
-       if (debug_lookup)
-               printf("%02x%02x%02x... lo %u hi %u nr %"PRIu32"\n",
-                      sha1[0], sha1[1], sha1[2], lo, hi, p->num_objects);
-
-       while (lo < hi) {
-               unsigned mi = lo + (hi - lo) / 2;
-               int cmp = hashcmp(index + mi * stride, sha1);
-
-               if (debug_lookup)
-                       printf("lo %u hi %u rg %u mi %u\n",
-                              lo, hi, hi - lo, mi);
-               if (!cmp)
-                       return nth_packed_object_offset(p, mi);
-               if (cmp > 0)
-                       hi = mi;
-               else
-                       lo = mi+1;
-       }
+       ret = bsearch_hash(sha1, level1_ofs, index, stride);
+       if (ret >= 0)
+               return nth_packed_object_offset(p, ret);
        return 0;
 }
 
index 2a83255e4eeaf8e8ce74516880b0333b23d6f583..4d08d4487460f839f39f667c714f1bb85fa1e144 100644 (file)
@@ -78,6 +78,7 @@ static void preload_index(struct index_state *index,
 {
        int threads, i, work, offset;
        struct thread_data data[MAX_PARALLEL];
+       uint64_t start = getnanotime();
 
        if (!core_preload_index)
                return;
@@ -108,6 +109,7 @@ static void preload_index(struct index_state *index,
                if (pthread_join(p->pthread, NULL))
                        die("unable to join threaded lstat");
        }
+       trace_performance_since(start, "preload index");
 }
 #endif
 
index 9925a94a6ba6b98693efff59a81878e0ffc42a76..28bf0db9d95777659ffe43d994f4970b46a78f56 100644 (file)
@@ -631,10 +631,10 @@ static struct cache_entry *create_alias_ce(struct index_state *istate,
 
 void set_object_name_for_intent_to_add_entry(struct cache_entry *ce)
 {
-       unsigned char sha1[20];
-       if (write_sha1_file("", 0, blob_type, sha1))
+       struct object_id oid;
+       if (write_object_file("", 0, blob_type, &oid))
                die("cannot create an empty blob in the object database");
-       hashcpy(ce->oid.hash, sha1);
+       oidcpy(&ce->oid, &oid);
 }
 
 int add_to_index(struct index_state *istate, const char *path, struct stat *st, int flags)
@@ -1371,6 +1371,7 @@ int refresh_index(struct index_state *istate, unsigned int flags,
        const char *typechange_fmt;
        const char *added_fmt;
        const char *unmerged_fmt;
+       uint64_t start = getnanotime();
 
        modified_fmt = (in_porcelain ? "M\t%s\n" : "%s: needs update\n");
        deleted_fmt = (in_porcelain ? "D\t%s\n" : "%s: needs update\n");
@@ -1441,6 +1442,7 @@ int refresh_index(struct index_state *istate, unsigned int flags,
 
                replace_index_entry(istate, i, new);
        }
+       trace_performance_since(start, "refresh index");
        return has_errors;
 }
 
@@ -1544,8 +1546,8 @@ int verify_ce_order;
 
 static int verify_hdr(struct cache_header *hdr, unsigned long size)
 {
-       git_SHA_CTX c;
-       unsigned char sha1[20];
+       git_hash_ctx c;
+       unsigned char hash[GIT_MAX_RAWSZ];
        int hdr_version;
 
        if (hdr->hdr_signature != htonl(CACHE_SIGNATURE))
@@ -1557,10 +1559,10 @@ static int verify_hdr(struct cache_header *hdr, unsigned long size)
        if (!verify_index_checksum)
                return 0;
 
-       git_SHA1_Init(&c);
-       git_SHA1_Update(&c, hdr, size - 20);
-       git_SHA1_Final(sha1, &c);
-       if (hashcmp(sha1, (unsigned char *)hdr + size - 20))
+       the_hash_algo->init_fn(&c);
+       the_hash_algo->update_fn(&c, hdr, size - the_hash_algo->rawsz);
+       the_hash_algo->final_fn(hash, &c);
+       if (hashcmp(hash, (unsigned char *)hdr + size - the_hash_algo->rawsz))
                return error("bad index file sha1 signature");
        return 0;
 }
@@ -1790,7 +1792,7 @@ int do_read_index(struct index_state *istate, const char *path, int must_exist)
                die_errno("cannot stat the open index");
 
        mmap_size = xsize_t(st.st_size);
-       if (mmap_size < sizeof(struct cache_header) + 20)
+       if (mmap_size < sizeof(struct cache_header) + the_hash_algo->rawsz)
                die("index file smaller than expected");
 
        mmap = xmmap(NULL, mmap_size, PROT_READ, MAP_PRIVATE, fd, 0);
@@ -1802,7 +1804,7 @@ int do_read_index(struct index_state *istate, const char *path, int must_exist)
        if (verify_hdr(hdr, mmap_size) < 0)
                goto unmap;
 
-       hashcpy(istate->sha1, (const unsigned char *)hdr + mmap_size - 20);
+       hashcpy(istate->sha1, (const unsigned char *)hdr + mmap_size - the_hash_algo->rawsz);
        istate->version = ntohl(hdr->hdr_version);
        istate->cache_nr = ntohl(hdr->hdr_entries);
        istate->cache_alloc = alloc_nr(istate->cache_nr);
@@ -1830,7 +1832,7 @@ int do_read_index(struct index_state *istate, const char *path, int must_exist)
        istate->timestamp.sec = st.st_mtime;
        istate->timestamp.nsec = ST_MTIME_NSEC(st);
 
-       while (src_offset <= mmap_size - 20 - 8) {
+       while (src_offset <= mmap_size - the_hash_algo->rawsz - 8) {
                /* After an array of active_nr index entries,
                 * there can be arbitrary number of extended
                 * sections, each of which is prefixed with
@@ -1871,6 +1873,7 @@ static void freshen_shared_index(const char *shared_index, int warn)
 int read_index_from(struct index_state *istate, const char *path,
                    const char *gitdir)
 {
+       uint64_t start = getnanotime();
        struct split_index *split_index;
        int ret;
        char *base_sha1_hex;
@@ -1881,6 +1884,7 @@ int read_index_from(struct index_state *istate, const char *path,
                return istate->cache_nr;
 
        ret = do_read_index(istate, path, 0);
+       trace_performance_since(start, "read cache %s", path);
 
        split_index = istate->split_index;
        if (!split_index || is_null_sha1(split_index->base_sha1)) {
@@ -1904,6 +1908,7 @@ int read_index_from(struct index_state *istate, const char *path,
        freshen_shared_index(base_path, 0);
        merge_base_index(istate);
        post_read_index_from(istate);
+       trace_performance_since(start, "read cache %s", base_path);
        free(base_path);
        return ret;
 }
@@ -1956,11 +1961,11 @@ int unmerged_index(const struct index_state *istate)
 static unsigned char write_buffer[WRITE_BUFFER_SIZE];
 static unsigned long write_buffer_len;
 
-static int ce_write_flush(git_SHA_CTX *context, int fd)
+static int ce_write_flush(git_hash_ctx *context, int fd)
 {
        unsigned int buffered = write_buffer_len;
        if (buffered) {
-               git_SHA1_Update(context, write_buffer, buffered);
+               the_hash_algo->update_fn(context, write_buffer, buffered);
                if (write_in_full(fd, write_buffer, buffered) < 0)
                        return -1;
                write_buffer_len = 0;
@@ -1968,7 +1973,7 @@ static int ce_write_flush(git_SHA_CTX *context, int fd)
        return 0;
 }
 
-static int ce_write(git_SHA_CTX *context, int fd, void *data, unsigned int len)
+static int ce_write(git_hash_ctx *context, int fd, void *data, unsigned int len)
 {
        while (len) {
                unsigned int buffered = write_buffer_len;
@@ -1990,7 +1995,7 @@ static int ce_write(git_SHA_CTX *context, int fd, void *data, unsigned int len)
        return 0;
 }
 
-static int write_index_ext_header(git_SHA_CTX *context, int fd,
+static int write_index_ext_header(git_hash_ctx *context, int fd,
                                  unsigned int ext, unsigned int sz)
 {
        ext = htonl(ext);
@@ -1999,26 +2004,26 @@ static int write_index_ext_header(git_SHA_CTX *context, int fd,
                (ce_write(context, fd, &sz, 4) < 0)) ? -1 : 0;
 }
 
-static int ce_flush(git_SHA_CTX *context, int fd, unsigned char *sha1)
+static int ce_flush(git_hash_ctx *context, int fd, unsigned char *hash)
 {
        unsigned int left = write_buffer_len;
 
        if (left) {
                write_buffer_len = 0;
-               git_SHA1_Update(context, write_buffer, left);
+               the_hash_algo->update_fn(context, write_buffer, left);
        }
 
-       /* Flush first if not enough space for SHA1 signature */
-       if (left + 20 > WRITE_BUFFER_SIZE) {
+       /* Flush first if not enough space for hash signature */
+       if (left + the_hash_algo->rawsz > WRITE_BUFFER_SIZE) {
                if (write_in_full(fd, write_buffer, left) < 0)
                        return -1;
                left = 0;
        }
 
-       /* Append the SHA1 signature at the end */
-       git_SHA1_Final(write_buffer + left, context);
-       hashcpy(sha1, write_buffer + left);
-       left += 20;
+       /* Append the hash signature at the end */
+       the_hash_algo->final_fn(write_buffer + left, context);
+       hashcpy(hash, write_buffer + left);
+       left += the_hash_algo->rawsz;
        return (write_in_full(fd, write_buffer, left) < 0) ? -1 : 0;
 }
 
@@ -2099,7 +2104,7 @@ static void copy_cache_entry_to_ondisk(struct ondisk_cache_entry *ondisk,
        }
 }
 
-static int ce_write_entry(git_SHA_CTX *c, int fd, struct cache_entry *ce,
+static int ce_write_entry(git_hash_ctx *c, int fd, struct cache_entry *ce,
                          struct strbuf *previous_name, struct ondisk_cache_entry *ondisk)
 {
        int size;
@@ -2166,7 +2171,7 @@ static int verify_index_from(const struct index_state *istate, const char *path)
        int fd;
        ssize_t n;
        struct stat st;
-       unsigned char sha1[20];
+       unsigned char hash[GIT_MAX_RAWSZ];
 
        if (!istate->initialized)
                return 0;
@@ -2178,14 +2183,14 @@ static int verify_index_from(const struct index_state *istate, const char *path)
        if (fstat(fd, &st))
                goto out;
 
-       if (st.st_size < sizeof(struct cache_header) + 20)
+       if (st.st_size < sizeof(struct cache_header) + the_hash_algo->rawsz)
                goto out;
 
-       n = pread_in_full(fd, sha1, 20, st.st_size - 20);
-       if (n != 20)
+       n = pread_in_full(fd, hash, the_hash_algo->rawsz, st.st_size - the_hash_algo->rawsz);
+       if (n != the_hash_algo->rawsz)
                goto out;
 
-       if (hashcmp(istate->sha1, sha1))
+       if (hashcmp(istate->sha1, hash))
                goto out;
 
        close(fd);
@@ -2233,8 +2238,9 @@ void update_index_if_able(struct index_state *istate, struct lock_file *lockfile
 static int do_write_index(struct index_state *istate, struct tempfile *tempfile,
                          int strip_extensions)
 {
+       uint64_t start = getnanotime();
        int newfd = tempfile->fd;
-       git_SHA_CTX c;
+       git_hash_ctx c;
        struct cache_header hdr;
        int i, err = 0, removed, extended, hdr_version;
        struct cache_entry **cache = istate->cache;
@@ -2272,7 +2278,7 @@ static int do_write_index(struct index_state *istate, struct tempfile *tempfile,
        hdr.hdr_version = htonl(hdr_version);
        hdr.hdr_entries = htonl(entries - removed);
 
-       git_SHA1_Init(&c);
+       the_hash_algo->init_fn(&c);
        if (ce_write(&c, newfd, &hdr, sizeof(hdr)) < 0)
                return -1;
 
@@ -2373,6 +2379,7 @@ static int do_write_index(struct index_state *istate, struct tempfile *tempfile,
                return -1;
        istate->timestamp.sec = (unsigned int)st.st_mtime;
        istate->timestamp.nsec = ST_MTIME_NSEC(st);
+       trace_performance_since(start, "write index, changed mask = %x", istate->cache_changed);
        return 0;
 }
 
index 023243fd5f1833f3c5f0b6fd3cd82b2e0c69644e..65288c647278aa27790b13c0360f756686dadf7a 100644 (file)
@@ -68,17 +68,21 @@ struct snapshot {
        int mmapped;
 
        /*
-        * The contents of the `packed-refs` file. If the file was
-        * already sorted, this points at the mmapped contents of the
-        * file. If not, this points at heap-allocated memory
-        * containing the contents, sorted. If there were no contents
-        * (e.g., because the file didn't exist), `buf` and `eof` are
-        * both NULL.
+        * The contents of the `packed-refs` file:
+        *
+        * - buf -- a pointer to the start of the memory
+        * - start -- a pointer to the first byte of actual references
+        *   (i.e., after the header line, if one is present)
+        * - eof -- a pointer just past the end of the reference
+        *   contents
+        *
+        * If the `packed-refs` file was already sorted, `buf` points
+        * at the mmapped contents of the file. If not, it points at
+        * heap-allocated memory containing the contents, sorted. If
+        * there were no contents (e.g., because the file didn't
+        * exist), `buf`, `start`, and `eof` are all NULL.
         */
-       char *buf, *eof;
-
-       /* The size of the header line, if any; otherwise, 0: */
-       size_t header_len;
+       char *buf, *start, *eof;
 
        /*
         * What is the peeled state of the `packed-refs` file that
@@ -169,8 +173,7 @@ static void clear_snapshot_buffer(struct snapshot *snapshot)
        } else {
                free(snapshot->buf);
        }
-       snapshot->buf = snapshot->eof = NULL;
-       snapshot->header_len = 0;
+       snapshot->buf = snapshot->start = snapshot->eof = NULL;
 }
 
 /*
@@ -319,13 +322,14 @@ static void sort_snapshot(struct snapshot *snapshot)
        size_t len, i;
        char *new_buffer, *dst;
 
-       pos = snapshot->buf + snapshot->header_len;
+       pos = snapshot->start;
        eof = snapshot->eof;
-       len = eof - pos;
 
-       if (!len)
+       if (pos == eof)
                return;
 
+       len = eof - pos;
+
        /*
         * Initialize records based on a crude estimate of the number
         * of references in the file (we'll grow it below if needed):
@@ -391,9 +395,8 @@ static void sort_snapshot(struct snapshot *snapshot)
         * place:
         */
        clear_snapshot_buffer(snapshot);
-       snapshot->buf = new_buffer;
+       snapshot->buf = snapshot->start = new_buffer;
        snapshot->eof = new_buffer + len;
-       snapshot->header_len = 0;
 
 cleanup:
        free(records);
@@ -442,23 +445,26 @@ static const char *find_end_of_record(const char *p, const char *end)
  */
 static void verify_buffer_safe(struct snapshot *snapshot)
 {
-       const char *buf = snapshot->buf + snapshot->header_len;
+       const char *start = snapshot->start;
        const char *eof = snapshot->eof;
        const char *last_line;
 
-       if (buf == eof)
+       if (start == eof)
                return;
 
-       last_line = find_start_of_record(buf, eof - 1);
+       last_line = find_start_of_record(start, eof - 1);
        if (*(eof - 1) != '\n' || eof - last_line < GIT_SHA1_HEXSZ + 2)
                die_invalid_line(snapshot->refs->path,
                                 last_line, eof - last_line);
 }
 
+#define SMALL_FILE_SIZE (32*1024)
+
 /*
  * Depending on `mmap_strategy`, either mmap or read the contents of
  * the `packed-refs` file into the snapshot. Return 1 if the file
- * existed and was read, or 0 if the file was absent. Die on errors.
+ * existed and was read, or 0 if the file was absent or empty. Die on
+ * errors.
  */
 static int load_contents(struct snapshot *snapshot)
 {
@@ -489,24 +495,23 @@ static int load_contents(struct snapshot *snapshot)
                die_errno("couldn't stat %s", snapshot->refs->path);
        size = xsize_t(st.st_size);
 
-       switch (mmap_strategy) {
-       case MMAP_NONE:
+       if (!size) {
+               return 0;
+       } else if (mmap_strategy == MMAP_NONE || size <= SMALL_FILE_SIZE) {
                snapshot->buf = xmalloc(size);
                bytes_read = read_in_full(fd, snapshot->buf, size);
                if (bytes_read < 0 || bytes_read != size)
                        die_errno("couldn't read %s", snapshot->refs->path);
-               snapshot->eof = snapshot->buf + size;
                snapshot->mmapped = 0;
-               break;
-       case MMAP_TEMPORARY:
-       case MMAP_OK:
+       } else {
                snapshot->buf = xmmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0);
-               snapshot->eof = snapshot->buf + size;
                snapshot->mmapped = 1;
-               break;
        }
        close(fd);
 
+       snapshot->start = snapshot->buf;
+       snapshot->eof = snapshot->buf + size;
+
        return 1;
 }
 
@@ -515,9 +520,11 @@ static int load_contents(struct snapshot *snapshot)
  * `refname` starts. If `mustexist` is true and the reference doesn't
  * exist, then return NULL. If `mustexist` is false and the reference
  * doesn't exist, then return the point where that reference would be
- * inserted. In the latter mode, `refname` doesn't have to be a proper
- * reference name; for example, one could search for "refs/replace/"
- * to find the start of any replace references.
+ * inserted, or `snapshot->eof` (which might be NULL) if it would be
+ * inserted at the end of the file. In the latter mode, `refname`
+ * doesn't have to be a proper reference name; for example, one could
+ * search for "refs/replace/" to find the start of any replace
+ * references.
  *
  * The record is sought using a binary search, so `snapshot->buf` must
  * be sorted.
@@ -539,7 +546,7 @@ static const char *find_reference_location(struct snapshot *snapshot,
         * preceding records all have reference names that come
         * *before* `refname`.
         */
-       const char *lo = snapshot->buf + snapshot->header_len;
+       const char *lo = snapshot->start;
 
        /*
         * A pointer to a the first character of a record whose
@@ -547,7 +554,7 @@ static const char *find_reference_location(struct snapshot *snapshot,
         */
        const char *hi = snapshot->eof;
 
-       while (lo < hi) {
+       while (lo != hi) {
                const char *mid, *rec;
                int cmp;
 
@@ -616,9 +623,7 @@ static struct snapshot *create_snapshot(struct packed_ref_store *refs)
 
        /* If the file has a header line, process it: */
        if (snapshot->buf < snapshot->eof && *snapshot->buf == '#') {
-               struct strbuf tmp = STRBUF_INIT;
-               char *p;
-               const char *eol;
+               char *tmp, *p, *eol;
                struct string_list traits = STRING_LIST_INIT_NODUP;
 
                eol = memchr(snapshot->buf, '\n',
@@ -628,9 +633,9 @@ static struct snapshot *create_snapshot(struct packed_ref_store *refs)
                                              snapshot->buf,
                                              snapshot->eof - snapshot->buf);
 
-               strbuf_add(&tmp, snapshot->buf, eol - snapshot->buf);
+               tmp = xmemdupz(snapshot->buf, eol - snapshot->buf);
 
-               if (!skip_prefix(tmp.buf, "# pack-refs with:", (const char **)&p))
+               if (!skip_prefix(tmp, "# pack-refs with:", (const char **)&p))
                        die_invalid_line(refs->path,
                                         snapshot->buf,
                                         snapshot->eof - snapshot->buf);
@@ -647,10 +652,10 @@ static struct snapshot *create_snapshot(struct packed_ref_store *refs)
                /* perhaps other traits later as well */
 
                /* The "+ 1" is for the LF character. */
-               snapshot->header_len = eol + 1 - snapshot->buf;
+               snapshot->start = eol + 1;
 
                string_list_clear(&traits, 0);
-               strbuf_release(&tmp);
+               free(tmp);
        }
 
        verify_buffer_safe(snapshot);
@@ -671,13 +676,12 @@ static struct snapshot *create_snapshot(struct packed_ref_store *refs)
                 * We don't want to leave the file mmapped, so we are
                 * forced to make a copy now:
                 */
-               size_t size = snapshot->eof -
-                       (snapshot->buf + snapshot->header_len);
+               size_t size = snapshot->eof - snapshot->start;
                char *buf_copy = xmalloc(size);
 
-               memcpy(buf_copy, snapshot->buf + snapshot->header_len, size);
+               memcpy(buf_copy, snapshot->start, size);
                clear_snapshot_buffer(snapshot);
-               snapshot->buf = buf_copy;
+               snapshot->buf = snapshot->start = buf_copy;
                snapshot->eof = buf_copy + size;
        }
 
@@ -924,7 +928,12 @@ static struct ref_iterator *packed_ref_iterator_begin(
         */
        snapshot = get_snapshot(refs);
 
-       if (!snapshot->buf)
+       if (prefix && *prefix)
+               start = find_reference_location(snapshot, prefix, 0);
+       else
+               start = snapshot->start;
+
+       if (start == snapshot->eof)
                return empty_ref_iterator_begin();
 
        iter = xcalloc(1, sizeof(*iter));
@@ -934,11 +943,6 @@ static struct ref_iterator *packed_ref_iterator_begin(
        iter->snapshot = snapshot;
        acquire_snapshot(snapshot);
 
-       if (prefix && *prefix)
-               start = find_reference_location(snapshot, prefix, 0);
-       else
-               start = snapshot->buf + snapshot->header_len;
-
        iter->pos = start;
        iter->eof = snapshot->eof;
        strbuf_init(&iter->refname_buf, 0);
index 5bfdc4044233d5f809f9f1fbc55ebe3da477e3f0..e9baaf59bd954279970367631c930fe051712cda 100644 (file)
@@ -1149,8 +1149,8 @@ static int try_to_commit(struct strbuf *msg, const char *author,
                goto out;
        }
 
-       if (commit_tree_extended(msg->buf, msg->len, tree.hash, parents,
-                                oid->hash, author, opts->gpg_sign, extra)) {
+       if (commit_tree_extended(msg->buf, msg->len, &tree, parents,
+                                oid, author, opts->gpg_sign, extra)) {
                res = error(_("failed to write commit object"));
                goto out;
        }
index 4cf3ebd9212f6d5c9b9829373e58c34b83f0a548..d11c5e526052e708a9a357ca4d4687d09467e382 100644 (file)
@@ -99,3 +99,27 @@ int sha1_pos(const unsigned char *sha1, void *table, size_t nr,
        } while (lo < hi);
        return -lo-1;
 }
+
+int bsearch_hash(const unsigned char *sha1, const void *fanout_,
+                const void *table_, size_t stride)
+{
+       const uint32_t *fanout = fanout_;
+       const unsigned char *table = table_;
+       int hi, lo;
+
+       hi = ntohl(fanout[*sha1]);
+       lo = ((*sha1 == 0x0) ? 0 : ntohl(fanout[*sha1 - 1]));
+
+       while (lo < hi) {
+               unsigned mi = lo + (hi - lo) / 2;
+               int cmp = hashcmp(table + mi * stride, sha1);
+
+               if (!cmp)
+                       return mi;
+               if (cmp > 0)
+                       hi = mi;
+               else
+                       lo = mi + 1;
+       }
+       return -lo - 1;
+}
index cf5314f402ce78f0d5ab2bd72ee7f334b6394e04..3c59e9cb1e0792b891dd0bd033f337c7da708e8e 100644 (file)
@@ -7,4 +7,25 @@ extern int sha1_pos(const unsigned char *sha1,
                    void *table,
                    size_t nr,
                    sha1_access_fn fn);
+
+/*
+ * Searches for sha1 in table, using the given fanout table to determine the
+ * interval to search, then using binary search. Returns the element index of
+ * the position found if successful, -i-1 if not (where i is the index of the
+ * least element that is greater than sha1).
+ *
+ * Takes the following parameters:
+ *
+ *  - sha1: the hash to search for
+ *  - fanout: a 256-element array of NETWORK-order 32-bit integers; the integer
+ *    at position i represents the number of elements in table whose first byte
+ *    is less than or equal to i
+ *  - table: a sorted list of hashes with optional extra information in between
+ *  - stride: distance between two consecutive elements in table (should be
+ *    GIT_MAX_RAWSZ or greater)
+ *
+ * This function does not verify the validity of the fanout table.
+ */
+extern int bsearch_hash(const unsigned char *sha1, const void *fanout,
+                       const void *table, size_t stride);
 #endif
index 831d9e73438487d5d4918d3c21ae1725d915501f..826d7a0ae377445c117a646ef26f79dc02785122 100644 (file)
@@ -39,32 +39,32 @@ const struct object_id empty_blob_oid = {
        EMPTY_BLOB_SHA1_BIN_LITERAL
 };
 
-static void git_hash_sha1_init(void *ctx)
+static void git_hash_sha1_init(git_hash_ctx *ctx)
 {
-       git_SHA1_Init((git_SHA_CTX *)ctx);
+       git_SHA1_Init(&ctx->sha1);
 }
 
-static void git_hash_sha1_update(void *ctx, const void *data, size_t len)
+static void git_hash_sha1_update(git_hash_ctx *ctx, const void *data, size_t len)
 {
-       git_SHA1_Update((git_SHA_CTX *)ctx, data, len);
+       git_SHA1_Update(&ctx->sha1, data, len);
 }
 
-static void git_hash_sha1_final(unsigned char *hash, void *ctx)
+static void git_hash_sha1_final(unsigned char *hash, git_hash_ctx *ctx)
 {
-       git_SHA1_Final(hash, (git_SHA_CTX *)ctx);
+       git_SHA1_Final(hash, &ctx->sha1);
 }
 
-static void git_hash_unknown_init(void *ctx)
+static void git_hash_unknown_init(git_hash_ctx *ctx)
 {
        die("trying to init unknown hash");
 }
 
-static void git_hash_unknown_update(void *ctx, const void *data, size_t len)
+static void git_hash_unknown_update(git_hash_ctx *ctx, const void *data, size_t len)
 {
        die("trying to update unknown hash");
 }
 
-static void git_hash_unknown_final(unsigned char *hash, void *ctx)
+static void git_hash_unknown_final(unsigned char *hash, git_hash_ctx *ctx)
 {
        die("trying to finalize unknown hash");
 }
@@ -75,7 +75,6 @@ const struct git_hash_algo hash_algos[GIT_HASH_NALGOS] = {
                0x00000000,
                0,
                0,
-               0,
                git_hash_unknown_init,
                git_hash_unknown_update,
                git_hash_unknown_final,
@@ -86,7 +85,6 @@ const struct git_hash_algo hash_algos[GIT_HASH_NALGOS] = {
                "sha-1",
                /* "sha1", big-endian */
                0x73686131,
-               sizeof(git_SHA_CTX),
                GIT_SHA1_RAWSZ,
                GIT_SHA1_HEXSZ,
                git_hash_sha1_init,
@@ -789,16 +787,16 @@ void *xmmap(void *start, size_t length,
 int check_sha1_signature(const unsigned char *sha1, void *map,
                         unsigned long size, const char *type)
 {
-       unsigned char real_sha1[20];
+       struct object_id real_oid;
        enum object_type obj_type;
        struct git_istream *st;
-       git_SHA_CTX c;
+       git_hash_ctx c;
        char hdr[32];
        int hdrlen;
 
        if (map) {
-               hash_sha1_file(map, size, type, real_sha1);
-               return hashcmp(sha1, real_sha1) ? -1 : 0;
+               hash_object_file(map, size, type, &real_oid);
+               return hashcmp(sha1, real_oid.hash) ? -1 : 0;
        }
 
        st = open_istream(sha1, &obj_type, &size, NULL);
@@ -809,8 +807,8 @@ int check_sha1_signature(const unsigned char *sha1, void *map,
        hdrlen = xsnprintf(hdr, sizeof(hdr), "%s %lu", typename(obj_type), size) + 1;
 
        /* Sha1.. */
-       git_SHA1_Init(&c);
-       git_SHA1_Update(&c, hdr, hdrlen);
+       the_hash_algo->init_fn(&c);
+       the_hash_algo->update_fn(&c, hdr, hdrlen);
        for (;;) {
                char buf[1024 * 16];
                ssize_t readlen = read_istream(st, buf, sizeof(buf));
@@ -821,11 +819,11 @@ int check_sha1_signature(const unsigned char *sha1, void *map,
                }
                if (!readlen)
                        break;
-               git_SHA1_Update(&c, buf, readlen);
+               the_hash_algo->update_fn(&c, buf, readlen);
        }
-       git_SHA1_Final(real_sha1, &c);
+       the_hash_algo->final_fn(real_oid.hash, &c);
        close_istream(st);
-       return hashcmp(sha1, real_sha1) ? -1 : 0;
+       return hashcmp(sha1, real_oid.hash) ? -1 : 0;
 }
 
 int git_open_cloexec(const char *name, int flags)
@@ -1336,13 +1334,13 @@ static void *read_object(const unsigned char *sha1, enum object_type *type,
        return content;
 }
 
-int pretend_sha1_file(void *buf, unsigned long len, enum object_type type,
-                     unsigned char *sha1)
+int pretend_object_file(void *buf, unsigned long len, enum object_type type,
+                       struct object_id *oid)
 {
        struct cached_object *co;
 
-       hash_sha1_file(buf, len, typename(type), sha1);
-       if (has_sha1_file(sha1) || find_cached_object(sha1))
+       hash_object_file(buf, len, typename(type), oid);
+       if (has_sha1_file(oid->hash) || find_cached_object(oid->hash))
                return 0;
        ALLOC_GROW(cached_objects, cached_object_nr + 1, cached_object_alloc);
        co = &cached_objects[cached_object_nr++];
@@ -1350,7 +1348,7 @@ int pretend_sha1_file(void *buf, unsigned long len, enum object_type type,
        co->type = type;
        co->buf = xmalloc(len);
        memcpy(co->buf, buf, len);
-       hashcpy(co->sha1, sha1);
+       hashcpy(co->sha1, oid->hash);
        return 0;
 }
 
@@ -1443,20 +1441,20 @@ void *read_object_with_reference(const unsigned char *sha1,
        }
 }
 
-static void write_sha1_file_prepare(const void *buf, unsigned long len,
-                                    const char *type, unsigned char *sha1,
-                                    char *hdr, int *hdrlen)
+static void write_object_file_prepare(const void *buf, unsigned long len,
+                                     const char *type, struct object_id *oid,
+                                     char *hdr, int *hdrlen)
 {
-       git_SHA_CTX c;
+       git_hash_ctx c;
 
        /* Generate the header */
        *hdrlen = xsnprintf(hdr, *hdrlen, "%s %lu", type, len)+1;
 
        /* Sha1.. */
-       git_SHA1_Init(&c);
-       git_SHA1_Update(&c, hdr, *hdrlen);
-       git_SHA1_Update(&c, buf, len);
-       git_SHA1_Final(sha1, &c);
+       the_hash_algo->init_fn(&c);
+       the_hash_algo->update_fn(&c, hdr, *hdrlen);
+       the_hash_algo->update_fn(&c, buf, len);
+       the_hash_algo->final_fn(oid->hash, &c);
 }
 
 /*
@@ -1509,12 +1507,12 @@ static int write_buffer(int fd, const void *buf, size_t len)
        return 0;
 }
 
-int hash_sha1_file(const void *buf, unsigned long len, const char *type,
-                   unsigned char *sha1)
+int hash_object_file(const void *buf, unsigned long len, const char *type,
+                    struct object_id *oid)
 {
        char hdr[32];
        int hdrlen = sizeof(hdr);
-       write_sha1_file_prepare(buf, len, type, sha1, hdr, &hdrlen);
+       write_object_file_prepare(buf, len, type, oid, hdr, &hdrlen);
        return 0;
 }
 
@@ -1572,19 +1570,20 @@ static int create_tmpfile(struct strbuf *tmp, const char *filename)
        return fd;
 }
 
-static int write_loose_object(const unsigned char *sha1, char *hdr, int hdrlen,
-                             const void *buf, unsigned long len, time_t mtime)
+static int write_loose_object(const struct object_id *oid, char *hdr,
+                             int hdrlen, const void *buf, unsigned long len,
+                             time_t mtime)
 {
        int fd, ret;
        unsigned char compressed[4096];
        git_zstream stream;
-       git_SHA_CTX c;
-       unsigned char parano_sha1[20];
+       git_hash_ctx c;
+       struct object_id parano_oid;
        static struct strbuf tmp_file = STRBUF_INIT;
        static struct strbuf filename = STRBUF_INIT;
 
        strbuf_reset(&filename);
-       sha1_file_name(&filename, sha1);
+       sha1_file_name(&filename, oid->hash);
 
        fd = create_tmpfile(&tmp_file, filename.buf);
        if (fd < 0) {
@@ -1598,14 +1597,14 @@ static int write_loose_object(const unsigned char *sha1, char *hdr, int hdrlen,
        git_deflate_init(&stream, zlib_compression_level);
        stream.next_out = compressed;
        stream.avail_out = sizeof(compressed);
-       git_SHA1_Init(&c);
+       the_hash_algo->init_fn(&c);
 
        /* First header.. */
        stream.next_in = (unsigned char *)hdr;
        stream.avail_in = hdrlen;
        while (git_deflate(&stream, 0) == Z_OK)
                ; /* nothing */
-       git_SHA1_Update(&c, hdr, hdrlen);
+       the_hash_algo->update_fn(&c, hdr, hdrlen);
 
        /* Then the data itself.. */
        stream.next_in = (void *)buf;
@@ -1613,7 +1612,7 @@ static int write_loose_object(const unsigned char *sha1, char *hdr, int hdrlen,
        do {
                unsigned char *in0 = stream.next_in;
                ret = git_deflate(&stream, Z_FINISH);
-               git_SHA1_Update(&c, in0, stream.next_in - in0);
+               the_hash_algo->update_fn(&c, in0, stream.next_in - in0);
                if (write_buffer(fd, compressed, stream.next_out - compressed) < 0)
                        die("unable to write sha1 file");
                stream.next_out = compressed;
@@ -1621,13 +1620,16 @@ static int write_loose_object(const unsigned char *sha1, char *hdr, int hdrlen,
        } while (ret == Z_OK);
 
        if (ret != Z_STREAM_END)
-               die("unable to deflate new object %s (%d)", sha1_to_hex(sha1), ret);
+               die("unable to deflate new object %s (%d)", oid_to_hex(oid),
+                   ret);
        ret = git_deflate_end_gently(&stream);
        if (ret != Z_OK)
-               die("deflateEnd on object %s failed (%d)", sha1_to_hex(sha1), ret);
-       git_SHA1_Final(parano_sha1, &c);
-       if (hashcmp(sha1, parano_sha1) != 0)
-               die("confused by unstable object source data for %s", sha1_to_hex(sha1));
+               die("deflateEnd on object %s failed (%d)", oid_to_hex(oid),
+                   ret);
+       the_hash_algo->final_fn(parano_oid.hash, &c);
+       if (oidcmp(oid, &parano_oid) != 0)
+               die("confused by unstable object source data for %s",
+                   oid_to_hex(oid));
 
        close_sha1_file(fd);
 
@@ -1660,7 +1662,8 @@ static int freshen_packed_object(const unsigned char *sha1)
        return 1;
 }
 
-int write_sha1_file(const void *buf, unsigned long len, const char *type, unsigned char *sha1)
+int write_object_file(const void *buf, unsigned long len, const char *type,
+                     struct object_id *oid)
 {
        char hdr[32];
        int hdrlen = sizeof(hdr);
@@ -1668,14 +1671,15 @@ int write_sha1_file(const void *buf, unsigned long len, const char *type, unsign
        /* Normally if we have it in the pack then we do not bother writing
         * it out into .git/objects/??/?{38} file.
         */
-       write_sha1_file_prepare(buf, len, type, sha1, hdr, &hdrlen);
-       if (freshen_packed_object(sha1) || freshen_loose_object(sha1))
+       write_object_file_prepare(buf, len, type, oid, hdr, &hdrlen);
+       if (freshen_packed_object(oid->hash) || freshen_loose_object(oid->hash))
                return 0;
-       return write_loose_object(sha1, hdr, hdrlen, buf, len, 0);
+       return write_loose_object(oid, hdr, hdrlen, buf, len, 0);
 }
 
-int hash_sha1_file_literally(const void *buf, unsigned long len, const char *type,
-                            struct object_id *oid, unsigned flags)
+int hash_object_file_literally(const void *buf, unsigned long len,
+                              const char *type, struct object_id *oid,
+                              unsigned flags)
 {
        char *header;
        int hdrlen, status = 0;
@@ -1683,20 +1687,20 @@ int hash_sha1_file_literally(const void *buf, unsigned long len, const char *typ
        /* type string, SP, %lu of the length plus NUL must fit this */
        hdrlen = strlen(type) + 32;
        header = xmalloc(hdrlen);
-       write_sha1_file_prepare(buf, len, type, oid->hash, header, &hdrlen);
+       write_object_file_prepare(buf, len, type, oid, header, &hdrlen);
 
        if (!(flags & HASH_WRITE_OBJECT))
                goto cleanup;
        if (freshen_packed_object(oid->hash) || freshen_loose_object(oid->hash))
                goto cleanup;
-       status = write_loose_object(oid->hash, header, hdrlen, buf, len, 0);
+       status = write_loose_object(oid, header, hdrlen, buf, len, 0);
 
 cleanup:
        free(header);
        return status;
 }
 
-int force_object_loose(const unsigned char *sha1, time_t mtime)
+int force_object_loose(const struct object_id *oid, time_t mtime)
 {
        void *buf;
        unsigned long len;
@@ -1705,13 +1709,13 @@ int force_object_loose(const unsigned char *sha1, time_t mtime)
        int hdrlen;
        int ret;
 
-       if (has_loose_object(sha1))
+       if (has_loose_object(oid->hash))
                return 0;
-       buf = read_object(sha1, &type, &len);
+       buf = read_object(oid->hash, &type, &len);
        if (!buf)
-               return error("cannot read sha1_file for %s", sha1_to_hex(sha1));
+               return error("cannot read sha1_file for %s", oid_to_hex(oid));
        hdrlen = xsnprintf(hdr, sizeof(hdr), "%s %lu", typename(type), len) + 1;
-       ret = write_loose_object(sha1, hdr, hdrlen, buf, len, mtime);
+       ret = write_loose_object(oid, hdr, hdrlen, buf, len, mtime);
        free(buf);
 
        return ret;
@@ -1794,9 +1798,9 @@ static int index_mem(struct object_id *oid, void *buf, size_t size,
        }
 
        if (write_object)
-               ret = write_sha1_file(buf, size, typename(type), oid->hash);
+               ret = write_object_file(buf, size, typename(type), oid);
        else
-               ret = hash_sha1_file(buf, size, typename(type), oid->hash);
+               ret = hash_object_file(buf, size, typename(type), oid);
        if (re_allocated)
                free(buf);
        return ret;
@@ -1816,11 +1820,11 @@ static int index_stream_convert_blob(struct object_id *oid, int fd,
                                 get_conv_flags(flags));
 
        if (write_object)
-               ret = write_sha1_file(sbuf.buf, sbuf.len, typename(OBJ_BLOB),
-                                     oid->hash);
+               ret = write_object_file(sbuf.buf, sbuf.len, typename(OBJ_BLOB),
+                                       oid);
        else
-               ret = hash_sha1_file(sbuf.buf, sbuf.len, typename(OBJ_BLOB),
-                                    oid->hash);
+               ret = hash_object_file(sbuf.buf, sbuf.len, typename(OBJ_BLOB),
+                                      oid);
        strbuf_release(&sbuf);
        return ret;
 }
@@ -1934,8 +1938,8 @@ int index_path(struct object_id *oid, const char *path, struct stat *st, unsigne
                if (strbuf_readlink(&sb, path, st->st_size))
                        return error_errno("readlink(\"%s\")", path);
                if (!(flags & HASH_WRITE_OBJECT))
-                       hash_sha1_file(sb.buf, sb.len, blob_type, oid->hash);
-               else if (write_sha1_file(sb.buf, sb.len, blob_type, oid->hash))
+                       hash_object_file(sb.buf, sb.len, blob_type, oid);
+               else if (write_object_file(sb.buf, sb.len, blob_type, oid))
                        rc = error("%s: failed to insert into database", path);
                strbuf_release(&sb);
                break;
@@ -2120,14 +2124,14 @@ static int check_stream_sha1(git_zstream *stream,
                             const char *path,
                             const unsigned char *expected_sha1)
 {
-       git_SHA_CTX c;
+       git_hash_ctx c;
        unsigned char real_sha1[GIT_MAX_RAWSZ];
        unsigned char buf[4096];
        unsigned long total_read;
        int status = Z_OK;
 
-       git_SHA1_Init(&c);
-       git_SHA1_Update(&c, hdr, stream->total_out);
+       the_hash_algo->init_fn(&c);
+       the_hash_algo->update_fn(&c, hdr, stream->total_out);
 
        /*
         * We already read some bytes into hdr, but the ones up to the NUL
@@ -2146,7 +2150,7 @@ static int check_stream_sha1(git_zstream *stream,
                if (size - total_read < stream->avail_out)
                        stream->avail_out = size - total_read;
                status = git_inflate(stream, Z_FINISH);
-               git_SHA1_Update(&c, buf, stream->next_out - buf);
+               the_hash_algo->update_fn(&c, buf, stream->next_out - buf);
                total_read += stream->next_out - buf;
        }
        git_inflate_end(stream);
@@ -2161,7 +2165,7 @@ static int check_stream_sha1(git_zstream *stream,
                return -1;
        }
 
-       git_SHA1_Final(real_sha1, &c);
+       the_hash_algo->final_fn(real_sha1, &c);
        if (hashcmp(expected_sha1, real_sha1)) {
                error("sha1 mismatch for %s (expected %s)", path,
                      sha1_to_hex(expected_sha1));
index a8c272927842901190b07098911ef785a458bcf3..41e1c3fd3f787e04d6e4fa9eb7c56b617f1c5fa5 100644 (file)
@@ -1,9 +1,9 @@
 /* Plumbing with collition-detecting SHA1 code */
 
-#ifdef DC_SHA1_SUBMODULE
-#include "sha1collisiondetection/lib/sha1.h"
-#elif defined(DC_SHA1_EXTERNAL)
+#ifdef DC_SHA1_EXTERNAL
 #include <sha1dc/sha1.h>
+#elif defined(DC_SHA1_SUBMODULE)
+#include "sha1collisiondetection/lib/sha1.h"
 #else
 #include "sha1dc/sha1.h"
 #endif
index f752532ffbcd130c3c3cb25ae20da41d4f74ae68..d7c55c2355ec7067e15655e99df8077344ed78fa 100644 (file)
@@ -54,8 +54,8 @@ int cmd_main(int ac, const char **av)
                printf("no untracked cache\n");
                return 0;
        }
-       printf("info/exclude %s\n", sha1_to_hex(uc->ss_info_exclude.sha1));
-       printf("core.excludesfile %s\n", sha1_to_hex(uc->ss_excludes_file.sha1));
+       printf("info/exclude %s\n", oid_to_hex(&uc->ss_info_exclude.oid));
+       printf("core.excludesfile %s\n", oid_to_hex(&uc->ss_excludes_file.oid));
        printf("exclude_per_dir %s\n", uc->exclude_per_dir);
        printf("flags %08x\n", uc->dir_flags);
        if (uc->root)
index 921d7b3e7ea20efe85f15beb7c75b8a5263267fb..66d33dfcfd1a0b3fa6b94a029aab9117a2511224 100644 (file)
@@ -16,6 +16,8 @@ int cmd_main(int argc, const char **argv)
                return !!wildmatch(argv[3], argv[2], WM_PATHNAME | WM_CASEFOLD);
        else if (!strcmp(argv[1], "pathmatch"))
                return !!wildmatch(argv[3], argv[2], 0);
+       else if (!strcmp(argv[1], "ipathmatch"))
+               return !!wildmatch(argv[3], argv[2], WM_CASEFOLD);
        else
                return 1;
 }
index 3a0917fa61ef6e630ca4dc2bb28c2af671f98804..821cf1498b78bbb5b43b2bda32bbcc88d580c31b 100755 (executable)
@@ -36,7 +36,8 @@ sub format_times {
        return $out;
 }
 
-my (@dirs, %dirnames, %dirabbrevs, %prefixes, @tests, $codespeed);
+my (@dirs, %dirnames, %dirabbrevs, %prefixes, @tests,
+    $codespeed, $subsection, $reponame);
 while (scalar @ARGV) {
        my $arg = $ARGV[0];
        my $dir;
@@ -45,6 +46,24 @@ sub format_times {
                shift @ARGV;
                next;
        }
+       if ($arg eq "--subsection") {
+               shift @ARGV;
+               $subsection = $ARGV[0];
+               shift @ARGV;
+               if (! $subsection) {
+                       die "empty subsection";
+               }
+               next;
+       }
+       if ($arg eq "--reponame") {
+               shift @ARGV;
+               $reponame = $ARGV[0];
+               shift @ARGV;
+               if (! $reponame) {
+                       die "empty reponame";
+               }
+               next;
+       }
        last if -f $arg or $arg eq "--";
        if (! -d $arg) {
                my $rev = Git::command_oneline(qw(rev-parse --verify), $arg);
@@ -76,10 +95,15 @@ sub format_times {
 }
 
 my $resultsdir = "test-results";
-my $results_section = "";
-if (exists $ENV{GIT_PERF_SUBSECTION} and $ENV{GIT_PERF_SUBSECTION} ne "") {
-       $resultsdir .= "/" . $ENV{GIT_PERF_SUBSECTION};
-       $results_section = $ENV{GIT_PERF_SUBSECTION};
+
+if (! $subsection and
+    exists $ENV{GIT_PERF_SUBSECTION} and
+    $ENV{GIT_PERF_SUBSECTION} ne "") {
+       $subsection = $ENV{GIT_PERF_SUBSECTION};
+}
+
+if ($subsection) {
+       $resultsdir .= "/" . $subsection;
 }
 
 my @subtests;
@@ -183,19 +207,21 @@ sub print_default_results {
 }
 
 sub print_codespeed_results {
-       my ($results_section) = @_;
+       my ($subsection) = @_;
 
        my $project = "Git";
 
        my $executable = `uname -s -m`;
        chomp $executable;
 
-       if ($results_section ne "") {
-               $executable .= ", " . $results_section;
+       if ($subsection) {
+               $executable .= ", " . $subsection;
        }
 
        my $environment;
-       if (exists $ENV{GIT_PERF_REPO_NAME} and $ENV{GIT_PERF_REPO_NAME} ne "") {
+       if ($reponame) {
+               $environment = $reponame;
+       } elsif (exists $ENV{GIT_PERF_REPO_NAME} and $ENV{GIT_PERF_REPO_NAME} ne "") {
                $environment = $ENV{GIT_PERF_REPO_NAME};
        } elsif (exists $ENV{GIT_TEST_INSTALLED} and $ENV{GIT_TEST_INSTALLED} ne "") {
                $environment = $ENV{GIT_TEST_INSTALLED};
@@ -227,13 +253,13 @@ sub print_codespeed_results {
                }
        }
 
-       print to_json(\@data, {utf8 => 1, pretty => 1}), "\n";
+       print to_json(\@data, {utf8 => 1, pretty => 1, canonical => 1}), "\n";
 }
 
 binmode STDOUT, ":utf8" or die "PANIC on binmode: $!";
 
 if ($codespeed) {
-       print_codespeed_results($results_section);
+       print_codespeed_results($subsection);
 } else {
        print_default_results();
 }
index 163a14a1c2cb77b2a644a7342fd554940f7dd2e3..c1fc6ca7301eaa9b15ef091ce592989956efc156 100755 (executable)
@@ -4,266 +4,431 @@ test_description='wildmatch tests'
 
 . ./test-lib.sh
 
-match() {
-    if [ $1 = 1 ]; then
-       test_expect_success "wildmatch:     match '$3' '$4'" "
-           test-wildmatch wildmatch '$3' '$4'
-       "
-    else
-       test_expect_success "wildmatch:  no match '$3' '$4'" "
-           ! test-wildmatch wildmatch '$3' '$4'
-       "
-    fi
+should_create_test_file() {
+       file=$1
+
+       case $file in
+       # `touch .` will succeed but obviously not do what we intend
+       # here.
+       ".")
+               return 1
+               ;;
+       # We cannot create a file with an empty filename.
+       "")
+               return 1
+               ;;
+       # The tests that are testing that e.g. foo//bar is matched by
+       # foo/*/bar can't be tested on filesystems since there's no
+       # way we're getting a double slash.
+       *//*)
+               return 1
+               ;;
+       # When testing the difference between foo/bar and foo/bar/ we
+       # can't test the latter.
+       */)
+               return 1
+               ;;
+       # On Windows, \ in paths is silently converted to /, which
+       # would result in the "touch" below working, but the test
+       # itself failing. See 6fd1106aa4 ("t3700: Skip a test with
+       # backslashes in pathspec", 2009-03-13) for prior art and
+       # details.
+       *\\*)
+               if ! test_have_prereq BSLASHPSPEC
+               then
+                       return 1
+               fi
+               # NOTE: The ;;& bash extension is not portable, so
+               # this test needs to be at the end of the pattern
+               # list.
+               #
+               # If we want to add more conditional returns we either
+               # need a new case statement, or turn this whole thing
+               # into a series of "if" tests.
+               ;;
+       esac
+
+
+       # On Windows proper (i.e. not Cygwin) many file names which
+       # under Cygwin would be emulated don't work.
+       if test_have_prereq MINGW
+       then
+               case $file in
+               " ")
+                       # Files called " " are forbidden on Windows
+                       return 1
+                       ;;
+               *\<*|*\>*|*:*|*\"*|*\|*|*\?*|*\**)
+                       # Files with various special characters aren't
+                       # allowed on Windows. Sourced from
+                       # https://stackoverflow.com/a/31976060
+                       return 1
+                       ;;
+               esac
+       fi
+
+       return 0
 }
 
-imatch() {
-    if [ $1 = 1 ]; then
-       test_expect_success "iwildmatch:    match '$2' '$3'" "
-           test-wildmatch iwildmatch '$2' '$3'
-       "
-    else
-       test_expect_success "iwildmatch: no match '$2' '$3'" "
-           ! test-wildmatch iwildmatch '$2' '$3'
-       "
-    fi
+match_with_function() {
+       text=$1
+       pattern=$2
+       match_expect=$3
+       match_function=$4
+
+       if test "$match_expect" = 1
+       then
+               test_expect_success "$match_function: match '$text' '$pattern'" "
+                       test-wildmatch $match_function '$text' '$pattern'
+               "
+       elif test "$match_expect" = 0
+       then
+               test_expect_success "$match_function: no match '$text' '$pattern'" "
+                       test_must_fail test-wildmatch $match_function '$text' '$pattern'
+               "
+       else
+               test_expect_success "PANIC: Test framework error. Unknown matches value $match_expect" 'false'
+       fi
+
+}
+
+match_with_ls_files() {
+       text=$1
+       pattern=$2
+       match_expect=$3
+       match_function=$4
+       ls_files_args=$5
+
+       match_stdout_stderr_cmp="
+               tr -d '\0' <actual.raw >actual &&
+               >expect.err &&
+               test_cmp expect.err actual.err &&
+               test_cmp expect actual"
+
+       if test "$match_expect" = 'E'
+       then
+               if test -e .git/created_test_file
+               then
+                       test_expect_success EXPENSIVE_ON_WINDOWS "$match_function (via ls-files): match dies on '$pattern' '$text'" "
+                               printf '%s' '$text' >expect &&
+                               test_must_fail git$ls_files_args ls-files -z -- '$pattern'
+                       "
+               else
+                       test_expect_failure EXPENSIVE_ON_WINDOWS "$match_function (via ls-files): match skip '$pattern' '$text'" 'false'
+               fi
+       elif test "$match_expect" = 1
+       then
+               if test -e .git/created_test_file
+               then
+                       test_expect_success EXPENSIVE_ON_WINDOWS "$match_function (via ls-files): match '$pattern' '$text'" "
+                               printf '%s' '$text' >expect &&
+                               git$ls_files_args ls-files -z -- '$pattern' >actual.raw 2>actual.err &&
+                               $match_stdout_stderr_cmp
+                       "
+               else
+                       test_expect_failure EXPENSIVE_ON_WINDOWS "$match_function (via ls-files): match skip '$pattern' '$text'" 'false'
+               fi
+       elif test "$match_expect" = 0
+       then
+               if test -e .git/created_test_file
+               then
+                       test_expect_success EXPENSIVE_ON_WINDOWS "$match_function (via ls-files): no match '$pattern' '$text'" "
+                               >expect &&
+                               git$ls_files_args ls-files -z -- '$pattern' >actual.raw 2>actual.err &&
+                               $match_stdout_stderr_cmp
+                       "
+               else
+                       test_expect_failure EXPENSIVE_ON_WINDOWS "$match_function (via ls-files): no match skip '$pattern' '$text'" 'false'
+               fi
+       else
+               test_expect_success "PANIC: Test framework error. Unknown matches value $match_expect" 'false'
+       fi
 }
 
-pathmatch() {
-    if [ $1 = 1 ]; then
-       test_expect_success "pathmatch:     match '$2' '$3'" "
-           test-wildmatch pathmatch '$2' '$3'
-       "
-    else
-       test_expect_success "pathmatch:  no match '$2' '$3'" "
-           ! test-wildmatch pathmatch '$2' '$3'
-       "
-    fi
+match() {
+       if test "$#" = 6
+       then
+               # When test-wildmatch and git ls-files produce the same
+               # result.
+               match_glob=$1
+               match_file_glob=$match_glob
+               match_iglob=$2
+               match_file_iglob=$match_iglob
+               match_pathmatch=$3
+               match_file_pathmatch=$match_pathmatch
+               match_pathmatchi=$4
+               match_file_pathmatchi=$match_pathmatchi
+               text=$5
+               pattern=$6
+       elif test "$#" = 10
+       then
+               match_glob=$1
+               match_iglob=$2
+               match_pathmatch=$3
+               match_pathmatchi=$4
+               match_file_glob=$5
+               match_file_iglob=$6
+               match_file_pathmatch=$7
+               match_file_pathmatchi=$8
+               text=$9
+               pattern=${10}
+       fi
+
+       test_expect_success EXPENSIVE_ON_WINDOWS 'cleanup after previous file test' '
+               if test -e .git/created_test_file
+               then
+                       git reset &&
+                       git clean -df
+               fi
+       '
+
+       printf '%s' "$text" >.git/expected_test_file
+
+       test_expect_success EXPENSIVE_ON_WINDOWS "setup match file test for $text" '
+               file=$(cat .git/expected_test_file) &&
+               if should_create_test_file "$file"
+               then
+                       dirs=${file%/*}
+                       if test "$file" != "$dirs"
+                       then
+                               mkdir -p -- "$dirs" &&
+                               touch -- "./$text"
+                       else
+                               touch -- "./$file"
+                       fi &&
+                       git add -A &&
+                       printf "%s" "$file" >.git/created_test_file
+               elif test -e .git/created_test_file
+               then
+                       rm .git/created_test_file
+               fi
+       '
+
+       # $1: Case sensitive glob match: test-wildmatch & ls-files
+       match_with_function "$text" "$pattern" $match_glob "wildmatch"
+       match_with_ls_files "$text" "$pattern" $match_file_glob "wildmatch" " --glob-pathspecs"
+
+       # $2: Case insensitive glob match: test-wildmatch & ls-files
+       match_with_function "$text" "$pattern" $match_iglob "iwildmatch"
+       match_with_ls_files "$text" "$pattern" $match_file_iglob "iwildmatch" " --glob-pathspecs --icase-pathspecs"
+
+       # $3: Case sensitive path match: test-wildmatch & ls-files
+       match_with_function "$text" "$pattern" $match_pathmatch "pathmatch"
+       match_with_ls_files "$text" "$pattern" $match_file_pathmatch "pathmatch" ""
+
+       # $4: Case insensitive path match: test-wildmatch & ls-files
+       match_with_function "$text" "$pattern" $match_pathmatchi "ipathmatch"
+       match_with_ls_files "$text" "$pattern" $match_file_pathmatchi "ipathmatch" " --icase-pathspecs"
 }
 
-# Basic wildmat features
-match 1 1 foo foo
-match 0 0 foo bar
-match 1 1 '' ""
-match 1 1 foo '???'
-match 0 0 foo '??'
-match 1 1 foo '*'
-match 1 1 foo 'f*'
-match 0 0 foo '*f'
-match 1 1 foo '*foo*'
-match 1 1 foobar '*ob*a*r*'
-match 1 1 aaaaaaabababab '*ab'
-match 1 1 'foo*' 'foo\*'
-match 0 0 foobar 'foo\*bar'
-match 1 1 'f\oo' 'f\\oo'
-match 1 1 ball '*[al]?'
-match 0 0 ten '[ten]'
-match 0 1 ten '**[!te]'
-match 0 0 ten '**[!ten]'
-match 1 1 ten 't[a-g]n'
-match 0 0 ten 't[!a-g]n'
-match 1 1 ton 't[!a-g]n'
-match 1 1 ton 't[^a-g]n'
-match 1 x 'a]b' 'a[]]b'
-match 1 x a-b 'a[]-]b'
-match 1 x 'a]b' 'a[]-]b'
-match 0 x aab 'a[]-]b'
-match 1 x aab 'a[]a-]b'
-match 1 1 ']' ']'
+# Basic wildmatch features
+match 1 1 1 1 foo foo
+match 0 0 0 0 foo bar
+match 1 1 1 1 '' ""
+match 1 1 1 1 foo '???'
+match 0 0 0 0 foo '??'
+match 1 1 1 1 foo '*'
+match 1 1 1 1 foo 'f*'
+match 0 0 0 0 foo '*f'
+match 1 1 1 1 foo '*foo*'
+match 1 1 1 1 foobar '*ob*a*r*'
+match 1 1 1 1 aaaaaaabababab '*ab'
+match 1 1 1 1 'foo*' 'foo\*'
+match 0 0 0 0 foobar 'foo\*bar'
+match 1 1 1 1 'f\oo' 'f\\oo'
+match 1 1 1 1 ball '*[al]?'
+match 0 0 0 0 ten '[ten]'
+match 0 0 1 1 ten '**[!te]'
+match 0 0 0 0 ten '**[!ten]'
+match 1 1 1 1 ten 't[a-g]n'
+match 0 0 0 0 ten 't[!a-g]n'
+match 1 1 1 1 ton 't[!a-g]n'
+match 1 1 1 1 ton 't[^a-g]n'
+match 1 1 1 1 'a]b' 'a[]]b'
+match 1 1 1 1 a-b 'a[]-]b'
+match 1 1 1 1 'a]b' 'a[]-]b'
+match 0 0 0 0 aab 'a[]-]b'
+match 1 1 1 1 aab 'a[]a-]b'
+match 1 1 1 1 ']' ']'
 
 # Extended slash-matching features
-match 0 0 'foo/baz/bar' 'foo*bar'
-match 0 0 'foo/baz/bar' 'foo**bar'
-match 0 1 'foobazbar' 'foo**bar'
-match 1 1 'foo/baz/bar' 'foo/**/bar'
-match 1 0 'foo/baz/bar' 'foo/**/**/bar'
-match 1 0 'foo/b/a/z/bar' 'foo/**/bar'
-match 1 0 'foo/b/a/z/bar' 'foo/**/**/bar'
-match 1 0 'foo/bar' 'foo/**/bar'
-match 1 0 'foo/bar' 'foo/**/**/bar'
-match 0 0 'foo/bar' 'foo?bar'
-match 0 0 'foo/bar' 'foo[/]bar'
-match 0 0 'foo/bar' 'foo[^a-z]bar'
-match 0 0 'foo/bar' 'f[^eiu][^eiu][^eiu][^eiu][^eiu]r'
-match 1 1 'foo-bar' 'f[^eiu][^eiu][^eiu][^eiu][^eiu]r'
-match 1 0 'foo' '**/foo'
-match 1 x 'XXX/foo' '**/foo'
-match 1 0 'bar/baz/foo' '**/foo'
-match 0 0 'bar/baz/foo' '*/foo'
-match 0 0 'foo/bar/baz' '**/bar*'
-match 1 0 'deep/foo/bar/baz' '**/bar/*'
-match 0 0 'deep/foo/bar/baz/' '**/bar/*'
-match 1 0 'deep/foo/bar/baz/' '**/bar/**'
-match 0 0 'deep/foo/bar' '**/bar/*'
-match 1 0 'deep/foo/bar/' '**/bar/**'
-match 0 0 'foo/bar/baz' '**/bar**'
-match 1 0 'foo/bar/baz/x' '*/bar/**'
-match 0 0 'deep/foo/bar/baz/x' '*/bar/**'
-match 1 0 'deep/foo/bar/baz/x' '**/bar/*/*'
+match 0 0 1 1 'foo/baz/bar' 'foo*bar'
+match 0 0 1 1 'foo/baz/bar' 'foo**bar'
+match 0 0 1 1 'foobazbar' 'foo**bar'
+match 1 1 1 1 'foo/baz/bar' 'foo/**/bar'
+match 1 1 0 0 'foo/baz/bar' 'foo/**/**/bar'
+match 1 1 1 1 'foo/b/a/z/bar' 'foo/**/bar'
+match 1 1 1 1 'foo/b/a/z/bar' 'foo/**/**/bar'
+match 1 1 0 0 'foo/bar' 'foo/**/bar'
+match 1 1 0 0 'foo/bar' 'foo/**/**/bar'
+match 0 0 1 1 'foo/bar' 'foo?bar'
+match 0 0 1 1 'foo/bar' 'foo[/]bar'
+match 0 0 1 1 'foo/bar' 'foo[^a-z]bar'
+match 0 0 1 1 'foo/bar' 'f[^eiu][^eiu][^eiu][^eiu][^eiu]r'
+match 1 1 1 1 'foo-bar' 'f[^eiu][^eiu][^eiu][^eiu][^eiu]r'
+match 1 1 0 0 'foo' '**/foo'
+match 1 1 1 1 'XXX/foo' '**/foo'
+match 1 1 1 1 'bar/baz/foo' '**/foo'
+match 0 0 1 1 'bar/baz/foo' '*/foo'
+match 0 0 1 1 'foo/bar/baz' '**/bar*'
+match 1 1 1 1 'deep/foo/bar/baz' '**/bar/*'
+match 0 0 1 1 'deep/foo/bar/baz/' '**/bar/*'
+match 1 1 1 1 'deep/foo/bar/baz/' '**/bar/**'
+match 0 0 0 0 'deep/foo/bar' '**/bar/*'
+match 1 1 1 1 'deep/foo/bar/' '**/bar/**'
+match 0 0 1 1 'foo/bar/baz' '**/bar**'
+match 1 1 1 1 'foo/bar/baz/x' '*/bar/**'
+match 0 0 1 1 'deep/foo/bar/baz/x' '*/bar/**'
+match 1 1 1 1 'deep/foo/bar/baz/x' '**/bar/*/*'
 
 # Various additional tests
-match 0 0 'acrt' 'a[c-c]st'
-match 1 1 'acrt' 'a[c-c]rt'
-match 0 0 ']' '[!]-]'
-match 1 x 'a' '[!]-]'
-match 0 0 '' '\'
-match 0 x '\' '\'
-match 0 x 'XXX/\' '*/\'
-match 1 x 'XXX/\' '*/\\'
-match 1 1 'foo' 'foo'
-match 1 1 '@foo' '@foo'
-match 0 0 'foo' '@foo'
-match 1 1 '[ab]' '\[ab]'
-match 1 1 '[ab]' '[[]ab]'
-match 1 x '[ab]' '[[:]ab]'
-match 0 x '[ab]' '[[::]ab]'
-match 1 x '[ab]' '[[:digit]ab]'
-match 1 x '[ab]' '[\[:]ab]'
-match 1 1 '?a?b' '\??\?b'
-match 1 1 'abc' '\a\b\c'
-match 0 0 'foo' ''
-match 1 0 'foo/bar/baz/to' '**/t[o]'
+match 0 0 0 0 'acrt' 'a[c-c]st'
+match 1 1 1 1 'acrt' 'a[c-c]rt'
+match 0 0 0 0 ']' '[!]-]'
+match 1 1 1 1 'a' '[!]-]'
+match 0 0 0 0 '' '\'
+match 0 0 0 0 \
+      1 1 1 1 '\' '\'
+match 0 0 0 0 'XXX/\' '*/\'
+match 1 1 1 1 'XXX/\' '*/\\'
+match 1 1 1 1 'foo' 'foo'
+match 1 1 1 1 '@foo' '@foo'
+match 0 0 0 0 'foo' '@foo'
+match 1 1 1 1 '[ab]' '\[ab]'
+match 1 1 1 1 '[ab]' '[[]ab]'
+match 1 1 1 1 '[ab]' '[[:]ab]'
+match 0 0 0 0 '[ab]' '[[::]ab]'
+match 1 1 1 1 '[ab]' '[[:digit]ab]'
+match 1 1 1 1 '[ab]' '[\[:]ab]'
+match 1 1 1 1 '?a?b' '\??\?b'
+match 1 1 1 1 'abc' '\a\b\c'
+match 0 0 0 0 \
+      E E E E 'foo' ''
+match 1 1 1 1 'foo/bar/baz/to' '**/t[o]'
 
 # Character class tests
-match 1 x 'a1B' '[[:alpha:]][[:digit:]][[:upper:]]'
-match 0 x 'a' '[[:digit:][:upper:][:space:]]'
-match 1 x 'A' '[[:digit:][:upper:][:space:]]'
-match 1 x '1' '[[:digit:][:upper:][:space:]]'
-match 0 x '1' '[[:digit:][:upper:][:spaci:]]'
-match 1 x ' ' '[[:digit:][:upper:][:space:]]'
-match 0 x '.' '[[:digit:][:upper:][:space:]]'
-match 1 x '.' '[[:digit:][:punct:][:space:]]'
-match 1 x '5' '[[:xdigit:]]'
-match 1 x 'f' '[[:xdigit:]]'
-match 1 x 'D' '[[:xdigit:]]'
-match 1 x '_' '[[:alnum:][:alpha:][:blank:][:cntrl:][:digit:][:graph:][:lower:][:print:][:punct:][:space:][:upper:][:xdigit:]]'
-match 1 x '.' '[^[:alnum:][:alpha:][:blank:][:cntrl:][:digit:][:lower:][:space:][:upper:][:xdigit:]]'
-match 1 x '5' '[a-c[:digit:]x-z]'
-match 1 x 'b' '[a-c[:digit:]x-z]'
-match 1 x 'y' '[a-c[:digit:]x-z]'
-match 0 x 'q' '[a-c[:digit:]x-z]'
-
-# Additional tests, including some malformed wildmats
-match 1 x ']' '[\\-^]'
-match 0 0 '[' '[\\-^]'
-match 1 x '-' '[\-_]'
-match 1 x ']' '[\]]'
-match 0 0 '\]' '[\]]'
-match 0 0 '\' '[\]]'
-match 0 0 'ab' 'a[]b'
-match 0 x 'a[]b' 'a[]b'
-match 0 x 'ab[' 'ab['
-match 0 0 'ab' '[!'
-match 0 0 'ab' '[-'
-match 1 1 '-' '[-]'
-match 0 0 '-' '[a-'
-match 0 0 '-' '[!a-'
-match 1 x '-' '[--A]'
-match 1 x '5' '[--A]'
-match 1 1 ' ' '[ --]'
-match 1 1 '$' '[ --]'
-match 1 1 '-' '[ --]'
-match 0 0 '0' '[ --]'
-match 1 x '-' '[---]'
-match 1 x '-' '[------]'
-match 0 0 'j' '[a-e-n]'
-match 1 x '-' '[a-e-n]'
-match 1 x 'a' '[!------]'
-match 0 0 '[' '[]-a]'
-match 1 x '^' '[]-a]'
-match 0 0 '^' '[!]-a]'
-match 1 x '[' '[!]-a]'
-match 1 1 '^' '[a^bc]'
-match 1 x '-b]' '[a-]b]'
-match 0 0 '\' '[\]'
-match 1 1 '\' '[\\]'
-match 0 0 '\' '[!\\]'
-match 1 1 'G' '[A-\\]'
-match 0 0 'aaabbb' 'b*a'
-match 0 0 'aabcaa' '*ba*'
-match 1 1 ',' '[,]'
-match 1 1 ',' '[\\,]'
-match 1 1 '\' '[\\,]'
-match 1 1 '-' '[,-.]'
-match 0 0 '+' '[,-.]'
-match 0 0 '-.]' '[,-.]'
-match 1 1 '2' '[\1-\3]'
-match 1 1 '3' '[\1-\3]'
-match 0 0 '4' '[\1-\3]'
-match 1 1 '\' '[[-\]]'
-match 1 1 '[' '[[-\]]'
-match 1 1 ']' '[[-\]]'
-match 0 0 '-' '[[-\]]'
+match 1 1 1 1 'a1B' '[[:alpha:]][[:digit:]][[:upper:]]'
+match 0 1 0 1 'a' '[[:digit:][:upper:][:space:]]'
+match 1 1 1 1 'A' '[[:digit:][:upper:][:space:]]'
+match 1 1 1 1 '1' '[[:digit:][:upper:][:space:]]'
+match 0 0 0 0 '1' '[[:digit:][:upper:][:spaci:]]'
+match 1 1 1 1 ' ' '[[:digit:][:upper:][:space:]]'
+match 0 0 0 0 '.' '[[:digit:][:upper:][:space:]]'
+match 1 1 1 1 '.' '[[:digit:][:punct:][:space:]]'
+match 1 1 1 1 '5' '[[:xdigit:]]'
+match 1 1 1 1 'f' '[[:xdigit:]]'
+match 1 1 1 1 'D' '[[:xdigit:]]'
+match 1 1 1 1 '_' '[[:alnum:][:alpha:][:blank:][:cntrl:][:digit:][:graph:][:lower:][:print:][:punct:][:space:][:upper:][:xdigit:]]'
+match 1 1 1 1 '.' '[^[:alnum:][:alpha:][:blank:][:cntrl:][:digit:][:lower:][:space:][:upper:][:xdigit:]]'
+match 1 1 1 1 '5' '[a-c[:digit:]x-z]'
+match 1 1 1 1 'b' '[a-c[:digit:]x-z]'
+match 1 1 1 1 'y' '[a-c[:digit:]x-z]'
+match 0 0 0 0 'q' '[a-c[:digit:]x-z]'
 
-# Test recursion and the abort code (use "wildtest -i" to see iteration counts)
-match 1 1 '-adobe-courier-bold-o-normal--12-120-75-75-m-70-iso8859-1' '-*-*-*-*-*-*-12-*-*-*-m-*-*-*'
-match 0 0 '-adobe-courier-bold-o-normal--12-120-75-75-X-70-iso8859-1' '-*-*-*-*-*-*-12-*-*-*-m-*-*-*'
-match 0 0 '-adobe-courier-bold-o-normal--12-120-75-75-/-70-iso8859-1' '-*-*-*-*-*-*-12-*-*-*-m-*-*-*'
-match 1 1 'XXX/adobe/courier/bold/o/normal//12/120/75/75/m/70/iso8859/1' 'XXX/*/*/*/*/*/*/12/*/*/*/m/*/*/*'
-match 0 0 'XXX/adobe/courier/bold/o/normal//12/120/75/75/X/70/iso8859/1' 'XXX/*/*/*/*/*/*/12/*/*/*/m/*/*/*'
-match 1 0 'abcd/abcdefg/abcdefghijk/abcdefghijklmnop.txt' '**/*a*b*g*n*t'
-match 0 0 'abcd/abcdefg/abcdefghijk/abcdefghijklmnop.txtz' '**/*a*b*g*n*t'
-match 0 x foo '*/*/*'
-match 0 x foo/bar '*/*/*'
-match 1 x foo/bba/arr '*/*/*'
-match 0 x foo/bb/aa/rr '*/*/*'
-match 1 x foo/bb/aa/rr '**/**/**'
-match 1 x abcXdefXghi '*X*i'
-match 0 x ab/cXd/efXg/hi '*X*i'
-match 1 x ab/cXd/efXg/hi '*/*X*/*/*i'
-match 1 x ab/cXd/efXg/hi '**/*X*/**/*i'
+# Additional tests, including some malformed wildmatch patterns
+match 1 1 1 1 ']' '[\\-^]'
+match 0 0 0 0 '[' '[\\-^]'
+match 1 1 1 1 '-' '[\-_]'
+match 1 1 1 1 ']' '[\]]'
+match 0 0 0 0 '\]' '[\]]'
+match 0 0 0 0 '\' '[\]]'
+match 0 0 0 0 'ab' 'a[]b'
+match 0 0 0 0 \
+      1 1 1 1 'a[]b' 'a[]b'
+match 0 0 0 0 \
+      1 1 1 1 'ab[' 'ab['
+match 0 0 0 0 'ab' '[!'
+match 0 0 0 0 'ab' '[-'
+match 1 1 1 1 '-' '[-]'
+match 0 0 0 0 '-' '[a-'
+match 0 0 0 0 '-' '[!a-'
+match 1 1 1 1 '-' '[--A]'
+match 1 1 1 1 '5' '[--A]'
+match 1 1 1 1 ' ' '[ --]'
+match 1 1 1 1 '$' '[ --]'
+match 1 1 1 1 '-' '[ --]'
+match 0 0 0 0 '0' '[ --]'
+match 1 1 1 1 '-' '[---]'
+match 1 1 1 1 '-' '[------]'
+match 0 0 0 0 'j' '[a-e-n]'
+match 1 1 1 1 '-' '[a-e-n]'
+match 1 1 1 1 'a' '[!------]'
+match 0 0 0 0 '[' '[]-a]'
+match 1 1 1 1 '^' '[]-a]'
+match 0 0 0 0 '^' '[!]-a]'
+match 1 1 1 1 '[' '[!]-a]'
+match 1 1 1 1 '^' '[a^bc]'
+match 1 1 1 1 '-b]' '[a-]b]'
+match 0 0 0 0 '\' '[\]'
+match 1 1 1 1 '\' '[\\]'
+match 0 0 0 0 '\' '[!\\]'
+match 1 1 1 1 'G' '[A-\\]'
+match 0 0 0 0 'aaabbb' 'b*a'
+match 0 0 0 0 'aabcaa' '*ba*'
+match 1 1 1 1 ',' '[,]'
+match 1 1 1 1 ',' '[\\,]'
+match 1 1 1 1 '\' '[\\,]'
+match 1 1 1 1 '-' '[,-.]'
+match 0 0 0 0 '+' '[,-.]'
+match 0 0 0 0 '-.]' '[,-.]'
+match 1 1 1 1 '2' '[\1-\3]'
+match 1 1 1 1 '3' '[\1-\3]'
+match 0 0 0 0 '4' '[\1-\3]'
+match 1 1 1 1 '\' '[[-\]]'
+match 1 1 1 1 '[' '[[-\]]'
+match 1 1 1 1 ']' '[[-\]]'
+match 0 0 0 0 '-' '[[-\]]'
 
-pathmatch 1 foo foo
-pathmatch 0 foo fo
-pathmatch 1 foo/bar foo/bar
-pathmatch 1 foo/bar 'foo/*'
-pathmatch 1 foo/bba/arr 'foo/*'
-pathmatch 1 foo/bba/arr 'foo/**'
-pathmatch 1 foo/bba/arr 'foo*'
-pathmatch 1 foo/bba/arr 'foo**'
-pathmatch 1 foo/bba/arr 'foo/*arr'
-pathmatch 1 foo/bba/arr 'foo/**arr'
-pathmatch 0 foo/bba/arr 'foo/*z'
-pathmatch 0 foo/bba/arr 'foo/**z'
-pathmatch 1 foo/bar 'foo?bar'
-pathmatch 1 foo/bar 'foo[/]bar'
-pathmatch 1 foo/bar 'foo[^a-z]bar'
-pathmatch 0 foo '*/*/*'
-pathmatch 0 foo/bar '*/*/*'
-pathmatch 1 foo/bba/arr '*/*/*'
-pathmatch 1 foo/bb/aa/rr '*/*/*'
-pathmatch 1 abcXdefXghi '*X*i'
-pathmatch 1 ab/cXd/efXg/hi '*/*X*/*/*i'
-pathmatch 1 ab/cXd/efXg/hi '*Xg*i'
+# Test recursion
+match 1 1 1 1 '-adobe-courier-bold-o-normal--12-120-75-75-m-70-iso8859-1' '-*-*-*-*-*-*-12-*-*-*-m-*-*-*'
+match 0 0 0 0 '-adobe-courier-bold-o-normal--12-120-75-75-X-70-iso8859-1' '-*-*-*-*-*-*-12-*-*-*-m-*-*-*'
+match 0 0 0 0 '-adobe-courier-bold-o-normal--12-120-75-75-/-70-iso8859-1' '-*-*-*-*-*-*-12-*-*-*-m-*-*-*'
+match 1 1 1 1 'XXX/adobe/courier/bold/o/normal//12/120/75/75/m/70/iso8859/1' 'XXX/*/*/*/*/*/*/12/*/*/*/m/*/*/*'
+match 0 0 0 0 'XXX/adobe/courier/bold/o/normal//12/120/75/75/X/70/iso8859/1' 'XXX/*/*/*/*/*/*/12/*/*/*/m/*/*/*'
+match 1 1 1 1 'abcd/abcdefg/abcdefghijk/abcdefghijklmnop.txt' '**/*a*b*g*n*t'
+match 0 0 0 0 'abcd/abcdefg/abcdefghijk/abcdefghijklmnop.txtz' '**/*a*b*g*n*t'
+match 0 0 0 0 foo '*/*/*'
+match 0 0 0 0 foo/bar '*/*/*'
+match 1 1 1 1 foo/bba/arr '*/*/*'
+match 0 0 1 1 foo/bb/aa/rr '*/*/*'
+match 1 1 1 1 foo/bb/aa/rr '**/**/**'
+match 1 1 1 1 abcXdefXghi '*X*i'
+match 0 0 1 1 ab/cXd/efXg/hi '*X*i'
+match 1 1 1 1 ab/cXd/efXg/hi '*/*X*/*/*i'
+match 1 1 1 1 ab/cXd/efXg/hi '**/*X*/**/*i'
 
-# Case-sensitivity features
-match 0 x 'a' '[A-Z]'
-match 1 x 'A' '[A-Z]'
-match 0 x 'A' '[a-z]'
-match 1 x 'a' '[a-z]'
-match 0 x 'a' '[[:upper:]]'
-match 1 x 'A' '[[:upper:]]'
-match 0 x 'A' '[[:lower:]]'
-match 1 x 'a' '[[:lower:]]'
-match 0 x 'A' '[B-Za]'
-match 1 x 'a' '[B-Za]'
-match 0 x 'A' '[B-a]'
-match 1 x 'a' '[B-a]'
-match 0 x 'z' '[Z-y]'
-match 1 x 'Z' '[Z-y]'
+# Extra pathmatch tests
+match 0 0 0 0 foo fo
+match 1 1 1 1 foo/bar foo/bar
+match 1 1 1 1 foo/bar 'foo/*'
+match 0 0 1 1 foo/bba/arr 'foo/*'
+match 1 1 1 1 foo/bba/arr 'foo/**'
+match 0 0 1 1 foo/bba/arr 'foo*'
+match 0 0 1 1 \
+      1 1 1 1 foo/bba/arr 'foo**'
+match 0 0 1 1 foo/bba/arr 'foo/*arr'
+match 0 0 1 1 foo/bba/arr 'foo/**arr'
+match 0 0 0 0 foo/bba/arr 'foo/*z'
+match 0 0 0 0 foo/bba/arr 'foo/**z'
+match 0 0 1 1 foo/bar 'foo?bar'
+match 0 0 1 1 foo/bar 'foo[/]bar'
+match 0 0 1 1 foo/bar 'foo[^a-z]bar'
+match 0 0 1 1 ab/cXd/efXg/hi '*Xg*i'
 
-imatch 1 'a' '[A-Z]'
-imatch 1 'A' '[A-Z]'
-imatch 1 'A' '[a-z]'
-imatch 1 'a' '[a-z]'
-imatch 1 'a' '[[:upper:]]'
-imatch 1 'A' '[[:upper:]]'
-imatch 1 'A' '[[:lower:]]'
-imatch 1 'a' '[[:lower:]]'
-imatch 1 'A' '[B-Za]'
-imatch 1 'a' '[B-Za]'
-imatch 1 'A' '[B-a]'
-imatch 1 'a' '[B-a]'
-imatch 1 'z' '[Z-y]'
-imatch 1 'Z' '[Z-y]'
+# Extra case-sensitivity tests
+match 0 1 0 1 'a' '[A-Z]'
+match 1 1 1 1 'A' '[A-Z]'
+match 0 1 0 1 'A' '[a-z]'
+match 1 1 1 1 'a' '[a-z]'
+match 0 1 0 1 'a' '[[:upper:]]'
+match 1 1 1 1 'A' '[[:upper:]]'
+match 0 1 0 1 'A' '[[:lower:]]'
+match 1 1 1 1 'a' '[[:lower:]]'
+match 0 1 0 1 'A' '[B-Za]'
+match 1 1 1 1 'a' '[B-Za]'
+match 0 1 0 1 'A' '[B-a]'
+match 1 1 1 1 'a' '[B-a]'
+match 0 1 0 1 'z' '[Z-y]'
+match 1 1 1 1 'Z' '[Z-y]'
 
 test_done
index ff8c360cd58bc11366ac2cf9e7c0b141e4ac3a39..cb7c6de84abf88bf90ac9716bb24ac91b8f64bf9 100755 (executable)
@@ -3,6 +3,7 @@
 test_description='rebase should handle arbitrary git message'
 
 . ./test-lib.sh
+. "$TEST_DIRECTORY"/lib-rebase.sh
 
 cat >F <<\EOF
 This is an example of a commit log message
@@ -25,6 +26,7 @@ test_expect_success setup '
        test_tick &&
        git commit -m "Initial commit" &&
        git branch diff-in-message &&
+       git branch empty-message-merge &&
 
        git checkout -b multi-line-subject &&
        cat F >file2 &&
@@ -45,6 +47,11 @@ test_expect_success setup '
 
        git cat-file commit HEAD | sed -e "1,/^\$/d" >G0 &&
 
+       git checkout empty-message-merge &&
+       echo file3 >file3 &&
+       git add file3 &&
+       git commit --allow-empty-message -m "" &&
+
        git checkout master &&
 
        echo One >file1 &&
@@ -69,4 +76,20 @@ test_expect_success 'rebase commit with diff in message' '
        test_cmp G G0
 '
 
+test_expect_success 'rebase -m commit with empty message' '
+       test_must_fail git rebase -m master empty-message-merge &&
+       git rebase --abort &&
+       git rebase -m --allow-empty-message master empty-message-merge
+'
+
+test_expect_success 'rebase -i commit with empty message' '
+       git checkout diff-in-message &&
+       set_fake_editor &&
+       test_must_fail env FAKE_COMMIT_MESSAGE=" " FAKE_LINES="reword 1" \
+               git rebase -i HEAD^ &&
+       git rebase --abort &&
+       FAKE_COMMIT_MESSAGE=" " FAKE_LINES="reword 1" \
+               git rebase -i --allow-empty-message HEAD^
+'
+
 test_done
index 4f2a263b63e14348032959059c15b160fecba39c..783bdbf59db07ebf2afac83165d31b86fd6b95db 100755 (executable)
@@ -141,7 +141,7 @@ test_expect_success 'cherry-pick "-" works with arguments' '
        test_cmp expect actual
 '
 
-test_expect_success 'cherry-pick works with dirty renamed file' '
+test_expect_failure 'cherry-pick works with dirty renamed file' '
        test_commit to-rename &&
        git checkout -b unrelated &&
        test_commit unrelated &&
@@ -150,7 +150,10 @@ test_expect_success 'cherry-pick works with dirty renamed file' '
        test_tick &&
        git commit -m renamed &&
        echo modified >renamed &&
-       git cherry-pick refs/heads/unrelated
+       test_must_fail git cherry-pick refs/heads/unrelated >out &&
+       test_i18ngrep "Refusing to lose dirty file at renamed" out &&
+       test $(git rev-parse :0:renamed) = $(git rev-parse HEAD^:to-rename.t) &&
+       grep -q "^modified$" renamed
 '
 
 test_done
index eadf4f62444350c711a313d2161c9fa17c7aa405..a07816d5605f30ccb7f7ce6fe83288fff535538c 100755 (executable)
@@ -134,11 +134,15 @@ test_expect_success 'favour same basenames over different ones' '
        git rm path1 &&
        mkdir subdir &&
        git mv another-path subdir/path1 &&
-       git status | test_i18ngrep "renamed: .*path1 -> subdir/path1"'
+       git status >out &&
+       test_i18ngrep "renamed: .*path1 -> subdir/path1" out
+'
 
 test_expect_success 'favour same basenames even with minor differences' '
        git show HEAD:path1 | sed "s/15/16/" > subdir/path1 &&
-       git status | test_i18ngrep "renamed: .*path1 -> subdir/path1"'
+       git status >out &&
+       test_i18ngrep "renamed: .*path1 -> subdir/path1" out
+'
 
 test_expect_success 'two files with same basename and same content' '
        git reset --hard &&
@@ -148,7 +152,8 @@ test_expect_success 'two files with same basename and same content' '
        git add dir &&
        git commit -m 2 &&
        git mv dir other-dir &&
-       git status | test_i18ngrep "renamed: .*dir/A/file -> other-dir/A/file"
+       git status >out &&
+       test_i18ngrep "renamed: .*dir/A/file -> other-dir/A/file" out
 '
 
 test_expect_success 'setup for many rename source candidates' '
index 9f563db20a867156a825dfc0ce810c4f59109ac8..6e2cf933f761683781525b36330e38c758aaabd6 100755 (executable)
@@ -19,17 +19,33 @@ test_expect_success 'preparation' '
        git commit -m message "$name"
 '
 
+cat >expect72 <<-'EOF'
+ ...aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa | 1 +
+EOF
+test_expect_success "format-patch: small change with long name gives more space to the name" '
+       git format-patch -1 --stdout >output &&
+       grep " | " output >actual &&
+       test_cmp expect72 actual
+'
+
 while read cmd args
 do
-       cat >expect <<-'EOF'
+       cat >expect80 <<-'EOF'
         ...aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa | 1 +
        EOF
        test_expect_success "$cmd: small change with long name gives more space to the name" '
                git $cmd $args >output &&
                grep " | " output >actual &&
-               test_cmp expect actual
+               test_cmp expect80 actual
        '
+done <<\EOF
+diff HEAD^ HEAD --stat
+show --stat
+log -1 --stat
+EOF
 
+while read cmd args
+do
        cat >expect <<-'EOF'
         ...aaaaaaaaaaaaaaaaaaaaaaaaaaaaa | 1 +
        EOF
@@ -79,11 +95,11 @@ test_expect_success 'preparation for big change tests' '
        git commit -m message abcd
 '
 
-cat >expect80 <<'EOF'
- abcd | 1000 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+cat >expect72 <<'EOF'
+ abcd | 1000 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 EOF
-cat >expect80-graph <<'EOF'
-|  abcd | 1000 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+cat >expect72-graph <<'EOF'
+|  abcd | 1000 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 EOF
 cat >expect200 <<'EOF'
  abcd | 1000 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
@@ -107,7 +123,7 @@ do
                test_cmp "$expect-graph" actual
        '
 done <<\EOF
-ignores expect80 format-patch -1 --stdout
+ignores expect72 format-patch -1 --stdout
 respects expect200 diff HEAD^ HEAD --stat
 respects expect200 show --stat
 respects expect200 log -1 --stat
@@ -135,7 +151,7 @@ do
                test_cmp "$expect-graph" actual
        '
 done <<\EOF
-ignores expect80 format-patch -1 --stdout
+ignores expect72 format-patch -1 --stdout
 respects expect40 diff HEAD^ HEAD --stat
 respects expect40 show --stat
 respects expect40 log -1 --stat
@@ -163,7 +179,7 @@ do
                test_cmp "$expect-graph" actual
        '
 done <<\EOF
-ignores expect80 format-patch -1 --stdout
+ignores expect72 format-patch -1 --stdout
 respects expect40 diff HEAD^ HEAD --stat
 respects expect40 show --stat
 respects expect40 log -1 --stat
@@ -250,11 +266,11 @@ show --stat
 log -1 --stat
 EOF
 
-cat >expect80 <<'EOF'
- ...aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa | 1000 ++++++++++++++++++++
+cat >expect72 <<'EOF'
+ ...aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa | 1000 +++++++++++++++++
 EOF
-cat >expect80-graph <<'EOF'
-|  ...aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa | 1000 ++++++++++++++++++++
+cat >expect72-graph <<'EOF'
+|  ...aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa | 1000 +++++++++++++++++
 EOF
 cat >expect200 <<'EOF'
  aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa | 1000 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
@@ -278,7 +294,7 @@ do
                test_cmp "$expect-graph" actual
        '
 done <<\EOF
-ignores expect80 format-patch -1 --stdout
+ignores expect72 format-patch -1 --stdout
 respects expect200 diff HEAD^ HEAD --stat
 respects expect200 show --stat
 respects expect200 log -1 --stat
@@ -308,7 +324,7 @@ do
                test_cmp "$expect-graph" actual
        '
 done <<\EOF
-ignores expect80 format-patch -1 --stdout
+ignores expect72 format-patch -1 --stdout
 respects expect1 diff HEAD^ HEAD --stat
 respects expect1 show --stat
 respects expect1 log -1 --stat
index 668c54be41eb4fda17e9b43000081c7b374990c2..3debc87d4aefb2d0d5c77881a9485c06a2908858 100755 (executable)
@@ -222,12 +222,9 @@ test_expect_success 'fetch uses remote ref names to describe new refs' '
        (
                cd descriptive &&
                git fetch o 2>actual &&
-               grep " -> refs/crazyheads/descriptive-branch$" actual |
-               test_i18ngrep "new branch" &&
-               grep " -> descriptive-tag$" actual |
-               test_i18ngrep "new tag" &&
-               grep " -> crazy$" actual |
-               test_i18ngrep "new ref"
+               test_i18ngrep "new branch.* -> refs/crazyheads/descriptive-branch$" actual &&
+               test_i18ngrep "new tag.* -> descriptive-tag$" actual &&
+               test_i18ngrep "new ref.* -> crazy$" actual
        ) &&
        git checkout master
 '
index 2e42cf331648a8ba57b3806443e70b94b09eb382..644736b8a3b95c501bd8bb99850dd8de474b10d6 100755 (executable)
@@ -22,7 +22,7 @@ verify_stderr () {
        cat >expected &&
        # We're not interested in the error
        # "fatal: The remote end hung up unexpectedly":
-       test_i18ngrep -E '^(fatal|warning):' <error | grep -v 'hung up' >actual | sort &&
+       test_i18ngrep -E '^(fatal|warning):' error | grep -v 'hung up' >actual | sort &&
        test_i18ncmp expected actual
 }
 
index d38bf32470c592f89cbd31aa08a3c1de6fffe540..21340e89c9650e43fda9a6176c6fe814360edb8b 100755 (executable)
@@ -234,7 +234,7 @@ test_expect_success TTY 'push --no-progress silences progress but not status' '
        test_commit no-progress &&
        test_terminal git push --no-progress >output 2>&1 &&
        test_i18ngrep "^To http" output &&
-       test_i18ngrep ! "^Writing objects"
+       test_i18ngrep ! "^Writing objects" output
 '
 
 test_expect_success 'push --progress shows progress to non-tty' '
index d911afd24cd7d43fc412adb34144b90b66082b73..872788ac8ca4ecc0a54c14a04e3f72661306f1d3 100755 (executable)
@@ -20,10 +20,7 @@ test_expect_success 'curl redirects respect whitelist' '
        test_must_fail env GIT_ALLOW_PROTOCOL=http:https \
                           GIT_SMART_HTTP=0 \
                git clone "$HTTPD_URL/ftp-redir/repo.git" 2>stderr &&
-       {
-               test_i18ngrep "ftp.*disabled" stderr ||
-               test_i18ngrep "your curl version is too old"
-       }
+       test_i18ngrep -E "(ftp.*disabled|your curl version is too old)" stderr
 '
 
 test_expect_success 'curl limits redirects' '
index 05ebba7afa29977196370d178af728ec1d0d9a81..c01f721f13dba71fae681d6ba5100e02e58de4d8 100755 (executable)
@@ -242,10 +242,12 @@ test_expect_success 'merge of identical changes in a renamed file' '
        rm -f A M N &&
        git reset --hard &&
        git checkout change+rename &&
-       GIT_MERGE_VERBOSITY=3 git merge change | test_i18ngrep "^Skipped B" &&
+       GIT_MERGE_VERBOSITY=3 git merge change >out &&
+       test_i18ngrep "^Skipped B" out &&
        git reset --hard HEAD^ &&
        git checkout change &&
-       GIT_MERGE_VERBOSITY=3 git merge change+rename | test_i18ngrep "^Skipped B"
+       GIT_MERGE_VERBOSITY=3 git merge change+rename >out &&
+       test_i18ngrep "^Skipped B" out
 '
 
 test_expect_success 'setup for rename + d/f conflicts' '
index e5fb892f9575fda4baf0b2a0e6b31cf13a0d6c0b..46b947824fd68150cfaa6018355cd086c5a8759e 100755 (executable)
@@ -22,6 +22,12 @@ avoid_racy() {
        sleep 1
 }
 
+status_is_clean() {
+       >../status.expect &&
+       git status --porcelain >../status.actual &&
+       test_cmp ../status.expect ../status.actual
+}
+
 test_lazy_prereq UNTRACKED_CACHE '
        { git update-index --test-untracked-cache; ret=$?; } &&
        test $ret -ne 1
@@ -683,4 +689,85 @@ test_expect_success 'untracked cache survives a commit' '
        test_cmp ../before ../after
 '
 
+test_expect_success 'teardown worktree' '
+       cd ..
+'
+
+test_expect_success SYMLINKS 'setup worktree for symlink test' '
+       git init worktree-symlink &&
+       cd worktree-symlink &&
+       git config core.untrackedCache true &&
+       mkdir one two &&
+       touch one/file two/file &&
+       git add one/file two/file &&
+       git commit -m"first commit" &&
+       git rm -rf one &&
+       ln -s two one &&
+       git add one &&
+       git commit -m"second commit"
+'
+
+test_expect_success SYMLINKS '"status" after symlink replacement should be clean with UC=true' '
+       git checkout HEAD~ &&
+       status_is_clean &&
+       status_is_clean &&
+       git checkout master &&
+       avoid_racy &&
+       status_is_clean &&
+       status_is_clean
+'
+
+test_expect_success SYMLINKS '"status" after symlink replacement should be clean with UC=false' '
+       git config core.untrackedCache false &&
+       git checkout HEAD~ &&
+       status_is_clean &&
+       status_is_clean &&
+       git checkout master &&
+       avoid_racy &&
+       status_is_clean &&
+       status_is_clean
+'
+
+test_expect_success 'setup worktree for non-symlink test' '
+       git init worktree-non-symlink &&
+       cd worktree-non-symlink &&
+       git config core.untrackedCache true &&
+       mkdir one two &&
+       touch one/file two/file &&
+       git add one/file two/file &&
+       git commit -m"first commit" &&
+       git rm -rf one &&
+       cp two/file one &&
+       git add one &&
+       git commit -m"second commit"
+'
+
+test_expect_success '"status" after file replacement should be clean with UC=true' '
+       git checkout HEAD~ &&
+       status_is_clean &&
+       status_is_clean &&
+       git checkout master &&
+       avoid_racy &&
+       status_is_clean &&
+       test-dump-untracked-cache >../actual &&
+       grep -F "recurse valid" ../actual >../actual.grep &&
+       cat >../expect.grep <<EOF &&
+/ 0000000000000000000000000000000000000000 recurse valid
+/two/ 0000000000000000000000000000000000000000 recurse valid
+EOF
+       status_is_clean &&
+       test_cmp ../expect.grep ../actual.grep
+'
+
+test_expect_success '"status" after file replacement should be clean with UC=false' '
+       git config core.untrackedCache false &&
+       git checkout HEAD~ &&
+       status_is_clean &&
+       status_is_clean &&
+       git checkout master &&
+       avoid_racy &&
+       status_is_clean &&
+       status_is_clean
+'
+
 test_done
index eb2d13bbcf8abefd7af2be6f9cb3bf97e389ab15..756beb0d8eb466d78b235af363b6a36dde37c79e 100755 (executable)
@@ -314,4 +314,43 @@ test_expect_success 'splitting the index results in the same state' '
        test_cmp expect actual
 '
 
+test_expect_success UNTRACKED_CACHE 'ignore .git changes when invalidating UNTR' '
+       test_create_repo dot-git &&
+       (
+               cd dot-git &&
+               mkdir -p .git/hooks &&
+               : >tracked &&
+               : >modified &&
+               mkdir dir1 &&
+               : >dir1/tracked &&
+               : >dir1/modified &&
+               mkdir dir2 &&
+               : >dir2/tracked &&
+               : >dir2/modified &&
+               write_integration_script &&
+               git config core.fsmonitor .git/hooks/fsmonitor-test &&
+               git update-index --untracked-cache &&
+               git update-index --fsmonitor &&
+               GIT_TRACE_UNTRACKED_STATS="$TRASH_DIRECTORY/trace-before" \
+               git status &&
+               test-dump-untracked-cache >../before
+       ) &&
+       cat >>dot-git/.git/hooks/fsmonitor-test <<-\EOF &&
+       printf ".git\0"
+       printf ".git/index\0"
+       printf "dir1/.git\0"
+       printf "dir1/.git/index\0"
+       EOF
+       (
+               cd dot-git &&
+               GIT_TRACE_UNTRACKED_STATS="$TRASH_DIRECTORY/trace-after" \
+               git status &&
+               test-dump-untracked-cache >../after
+       ) &&
+       grep "directory invalidation" trace-before >>before &&
+       grep "directory invalidation" trace-after >>after &&
+       # UNTR extension unchanged, dir invalidation count unchanged
+       test_cmp before after
+'
+
 test_done
index 9444d6a9b9026748028178c4b66ee8bbbc1d89fa..9c422bcd7cc8c1b2525579ca3a7ffa6ee412ba42 100755 (executable)
@@ -97,7 +97,10 @@ test_expect_failure 'will not overwrite unstaged changes in renamed file' '
        git mv c1.c other.c &&
        git commit -m rename &&
        cp important other.c &&
-       git merge c1a &&
+       test_must_fail git merge c1a >out &&
+       test_i18ngrep "Refusing to lose dirty file at other.c" out &&
+       test_path_is_file other.c~HEAD &&
+       test $(git hash-object other.c~HEAD) = $(git rev-parse c1a:c1.c) &&
        test_cmp important other.c
 '
 
index a679b02a1c3bd181aff94d36e6e2f3347cf2c34f..67b5994afb76810b15634e1b3bb6f9717298b029 100644 (file)
@@ -705,6 +705,60 @@ test_cmp_bin() {
        cmp "$@"
 }
 
+# Use this instead of test_cmp to compare files that contain expected and
+# actual output from git commands that can be translated.  When running
+# under GETTEXT_POISON this pretends that the command produced expected
+# results.
+test_i18ncmp () {
+       test -n "$GETTEXT_POISON" || test_cmp "$@"
+}
+
+# Use this instead of "grep expected-string actual" to see if the
+# output from a git command that can be translated either contains an
+# expected string, or does not contain an unwanted one.  When running
+# under GETTEXT_POISON this pretends that the command produced expected
+# results.
+test_i18ngrep () {
+       eval "last_arg=\${$#}"
+
+       test -f "$last_arg" ||
+       error "bug in the test script: test_i18ngrep requires a file" \
+             "to read as the last parameter"
+
+       if test $# -lt 2 ||
+          { test "x!" = "x$1" && test $# -lt 3 ; }
+       then
+               error "bug in the test script: too few parameters to test_i18ngrep"
+       fi
+
+       if test -n "$GETTEXT_POISON"
+       then
+               # pretend success
+               return 0
+       fi
+
+       if test "x!" = "x$1"
+       then
+               shift
+               ! grep "$@" && return 0
+
+               echo >&2 "error: '! grep $@' did find a match in:"
+       else
+               grep "$@" && return 0
+
+               echo >&2 "error: 'grep $@' didn't find a match in:"
+       fi
+
+       if test -s "$last_arg"
+       then
+               cat >&2 "$last_arg"
+       else
+               echo >&2 "<File '$last_arg' is empty>"
+       fi
+
+       return 1
+}
+
 # Call any command "$@" but be more verbose about its
 # failure. This is handy for commands like "test" which do
 # not output anything when they fail.
index 9af19055b307e2c8306efbd41a89338ee408b838..33f6ce26f69d442238c60619a5f70673d451a7fb 100644 (file)
@@ -1062,32 +1062,6 @@ else
        test_set_prereq C_LOCALE_OUTPUT
 fi
 
-# Use this instead of test_cmp to compare files that contain expected and
-# actual output from git commands that can be translated.  When running
-# under GETTEXT_POISON this pretends that the command produced expected
-# results.
-test_i18ncmp () {
-       test -n "$GETTEXT_POISON" || test_cmp "$@"
-}
-
-# Use this instead of "grep expected-string actual" to see if the
-# output from a git command that can be translated either contains an
-# expected string, or does not contain an unwanted one.  When running
-# under GETTEXT_POISON this pretends that the command produced expected
-# results.
-test_i18ngrep () {
-       if test -n "$GETTEXT_POISON"
-       then
-           : # pretend success
-       elif test "x!" = "x$1"
-       then
-               shift
-               ! grep "$@"
-       else
-               grep "$@"
-       fi
-}
-
 test_lazy_prereq PIPE '
        # test whether the filesystem supports FIFOs
        test_have_prereq !MINGW,!CYGWIN &&
@@ -1132,6 +1106,10 @@ test_lazy_prereq EXPENSIVE '
        test -n "$GIT_TEST_LONG"
 '
 
+test_lazy_prereq EXPENSIVE_ON_WINDOWS '
+       test_have_prereq EXPENSIVE || test_have_prereq !MINGW,!CYGWIN
+'
+
 test_lazy_prereq USR_BIN_TIME '
        test -x /usr/bin/time
 '
index e6a15bbe44f24555a8edb9461c2af553de70cba0..c9f6e314d5cd830d63236ea88c5ff9c7baf418bb 100644 (file)
@@ -1528,7 +1528,7 @@ static void invalidate_ce_path(const struct cache_entry *ce,
        if (!ce)
                return;
        cache_tree_invalidate_path(o->src_index, ce->name);
-       untracked_cache_invalidate_path(o->src_index, ce->name);
+       untracked_cache_invalidate_path(o->src_index, ce->name, 1);
 }
 
 /*