Merge branch 'svn-crlf' of git://bogomips.org/git-svn into ew/svn-crlf
authorJunio C Hamano <gitster@pobox.com>
Thu, 14 Dec 2017 17:26:32 +0000 (09:26 -0800)
committerJunio C Hamano <gitster@pobox.com>
Thu, 14 Dec 2017 17:26:32 +0000 (09:26 -0800)
* 'svn-crlf' of git://bogomips.org/git-svn:
git-svn: convert CRLF to LF in commit message to SVN

39 files changed:
Documentation/RelNotes/2.16.0.txt
Documentation/git-checkout.txt
Documentation/git-log.txt
Documentation/git-send-email.txt
Documentation/git-status.txt
Documentation/githooks.txt
builtin/am.c
builtin/checkout.c
builtin/diff.c
builtin/log.c
builtin/pull.c
builtin/submodule--helper.c
cache.h
diff-lib.c
git-send-email.perl
grep.c
hash.h
hashmap.h
log-tree.c
log-tree.h
merge-recursive.c
notes-merge.c
pretty.c
progress.c
refs.c
refs.h
repository.c
repository.h
revision.c
sequencer.c
setup.c
sha1_file.c
strbuf.h
submodule.c
t/README
t/perf/p4211-line-log.sh
t/t4202-log.sh
t/t7810-grep.sh
t/test-lib.sh
index 431bd5e34ace656c3462e5cb4cf6bd3b77adfece..3eeeb83674828787c3c715795db6c7bdcb0b76d3 100644 (file)
@@ -96,6 +96,17 @@ UI, Workflows & Features
  * The shell completion (in contrib/) learned that "git pull" can take
    the "--autostash" option.
 
+ * The tagnames "git log --decorate" uses to annotate the commits can
+   now be limited to subset of available refs with the two additional
+   options, --decorate-refs[-exclude]=<pattern>.
+
+ * "git grep" compiled with libpcre2 sometimes triggered a segfault,
+   which is being fixed.
+
+ * "git send-email" tries to see if the sendmail program is available
+   in /usr/lib and /usr/sbin; extend the list of locations to be
+   checked to also include directories on $PATH.
+
 
 Performance, Internal Implementation, Development Support etc.
 
@@ -143,6 +154,15 @@ Performance, Internal Implementation, Development Support etc.
    and demonstrated that it works with the older versions of Git
    without harming them.
 
+ * An infrastructure to define what hash function is used in Git is
+   introduced, and an effort to plumb that throughout various
+   codepaths has been started.
+
+ * The code to iterate over loose object files got optimized.
+
+ * An internal function that was left for backward compatibility has
+   been removed, as there is no remaining callers.
+
 Also contains various documentation updates and code clean-ups.
 
 
@@ -302,8 +322,19 @@ Fixes since v2.15
    accept "git stash -mmessage" form.
    (merge 5675473fcb ph/stash-save-m-option-fix later to maint).
 
+ * @{-N} in "git checkout @{-N}" may refer to a detached HEAD state,
+   but the documentation was not clear about it, which has been fixed.
+   (merge 75ce149575 ks/doc-checkout-previous later to maint).
+
+ * A regression in the progress eye-candy was fixed.
+   (merge 9c5951cacf jk/progress-delay-fix later to maint).
+
  * Other minor doc, test and build updates and code cleanups.
    (merge 1a1fc2d5b5 rd/man-prune-progress later to maint).
    (merge 0ba014035a rd/man-reflog-add-n later to maint).
    (merge e54b63359f rd/doc-notes-prune-fix later to maint).
    (merge ff4c9b413a sp/doc-info-attributes later to maint).
+   (merge 7db2cbf4f1 jc/receive-pack-hook-doc later to maint).
+   (merge 5a0526264b tg/t-readme-updates later to maint).
+   (merge 5e83cca0b8 jk/no-optional-locks later to maint).
+   (merge 826c778f7c js/hashmap-update-sample later to maint).
index bfa64ca5c98c54b9b9465d45669f45ab887605cf..ca5fc9c79887652e38e3d11dc86dba657fe585c0 100644 (file)
@@ -274,11 +274,11 @@ section of linkgit:git-add[1] to learn how to operate the `--patch` mode.
        commit, your HEAD becomes "detached" and you are no longer on
        any branch (see below for details).
 +
-As a special case, the `"@{-N}"` syntax for the N-th last branch/commit
-checks out branches (instead of detaching).  You may also specify
-`-` which is synonymous with `"@{-1}"`.
+You can use the `"@{-N}"` syntax to refer to the N-th last
+branch/commit checked out using "git checkout" operation. You may
+also specify `-` which is synonymous to `"@{-1}`.
 +
-As a further special case, you may use `"A...B"` as a shortcut for the
+As a special case, you may use `"A...B"` as a shortcut for the
 merge base of `A` and `B` if there is exactly one merge base. You can
 leave out at most one of `A` and `B`, in which case it defaults to `HEAD`.
 
index 32246fdb007e9b25f414cff092b9bf0426c55d15..5437f8b0f0e6699eca662879290d47df85387f0f 100644 (file)
@@ -38,6 +38,13 @@ OPTIONS
        are shown as if 'short' were given, otherwise no ref names are
        shown. The default option is 'short'.
 
+--decorate-refs=<pattern>::
+--decorate-refs-exclude=<pattern>::
+       If no `--decorate-refs` is given, pretend as if all refs were
+       included.  For each candidate, do not use it for decoration if it
+       matches any patterns given to `--decorate-refs-exclude` or if it
+       doesn't match any of the patterns given to `--decorate-refs`.
+
 --source::
        Print out the ref name given on the command line by which each
        commit was reached.
index bac9014ac71775e5116ad7686af697eb22286ee2..8060ea35c5f932c1e4328f000a501ff399418f27 100644 (file)
@@ -203,9 +203,9 @@ a password is obtained using 'git-credential'.
        specify a full pathname of a sendmail-like program instead;
        the program must support the `-i` option.  Default value can
        be specified by the `sendemail.smtpServer` configuration
-       option; the built-in default is `/usr/sbin/sendmail` or
-       `/usr/lib/sendmail` if such program is available, or
-       `localhost` otherwise.
+       option; the built-in default is to search for `sendmail` in
+       `/usr/sbin`, `/usr/lib` and $PATH if such program is
+       available, falling back to `localhost` otherwise.
 
 --smtp-server-port=<port>::
        Specifies a port different from the default port (SMTP
index fc282e0a920c84f491d24e3cf765ca634b54c425..81cab9aefb014690d93f9602ebebc9058c3d168e 100644 (file)
@@ -387,6 +387,19 @@ ignored submodules you can either use the --ignore-submodules=dirty command
 line option or the 'git submodule summary' command, which shows a similar
 output but does not honor these settings.
 
+BACKGROUND REFRESH
+------------------
+
+By default, `git status` will automatically refresh the index, updating
+the cached stat information from the working tree and writing out the
+result. Writing out the updated index is an optimization that isn't
+strictly necessary (`status` computes the values for itself, but writing
+them out is just to save subsequent programs from repeating our
+computation). When `status` is run in the background, the lock held
+during the write may conflict with other simultaneous processes, causing
+them to fail. Scripts running `status` in the background should consider
+using `git --no-optional-locks status` (see linkgit:git[1] for details).
+
 SEE ALSO
 --------
 linkgit:gitignore[5]
index 0bb0042d8c2ee761743a93346dc5bea9312d3d7e..b63f2ea860be34fb49de77a2de5b68336e4a49bd 100644 (file)
@@ -223,8 +223,8 @@ to the user by writing to standard error.
 pre-receive
 ~~~~~~~~~~~
 
-This hook is invoked by 'git-receive-pack' on the remote repository,
-which happens when a 'git push' is done on a local repository.
+This hook is invoked by 'git-receive-pack' when it reacts to
+'git push' and updates reference(s) in its repository.
 Just before starting to update refs on the remote repository, the
 pre-receive hook is invoked.  Its exit status determines the success
 or failure of the update.
@@ -264,8 +264,8 @@ linkgit:git-receive-pack[1] for some caveats.
 update
 ~~~~~~
 
-This hook is invoked by 'git-receive-pack' on the remote repository,
-which happens when a 'git push' is done on a local repository.
+This hook is invoked by 'git-receive-pack' when it reacts to
+'git push' and updates reference(s) in its repository.
 Just before updating the ref on the remote repository, the update hook
 is invoked.  Its exit status determines the success or failure of
 the ref update.
@@ -309,8 +309,8 @@ unannotated tags to be pushed.
 post-receive
 ~~~~~~~~~~~~
 
-This hook is invoked by 'git-receive-pack' on the remote repository,
-which happens when a 'git push' is done on a local repository.
+This hook is invoked by 'git-receive-pack' when it reacts to
+'git push' and updates reference(s) in its repository.
 It executes on the remote repository once after all the refs have
 been updated.
 
@@ -348,8 +348,8 @@ will be set to zero, `GIT_PUSH_OPTION_COUNT=0`.
 post-update
 ~~~~~~~~~~~
 
-This hook is invoked by 'git-receive-pack' on the remote repository,
-which happens when a 'git push' is done on a local repository.
+This hook is invoked by 'git-receive-pack' when it reacts to
+'git push' and updates reference(s) in its repository.
 It executes on the remote repository once after all the refs have
 been updated.
 
@@ -379,8 +379,8 @@ for the user.
 push-to-checkout
 ~~~~~~~~~~~~~~~~
 
-This hook is invoked by 'git-receive-pack' on the remote repository,
-which happens when a 'git push' is done on a local repository, when
+This hook is invoked by 'git-receive-pack' when it reacts to
+'git push' and updates reference(s) in its repository, and when
 the push tries to update the branch that is currently checked out
 and the `receive.denyCurrentBranch` configuration variable is set to
 `updateInstead`.  Such a push by default is refused if the working
index 02853b3e05bfef638963dbfe91a7eccf3d40b9e6..3d98e52085711abc6fa5ff9fd16d2828156df375 100644 (file)
@@ -1433,7 +1433,7 @@ static void write_index_patch(const struct am_state *state)
        if (!get_oid_tree("HEAD", &head))
                tree = lookup_tree(&head);
        else
-               tree = lookup_tree(&empty_tree_oid);
+               tree = lookup_tree(the_hash_algo->empty_tree);
 
        fp = xfopen(am_path(state, "patch"), "w");
        init_revisions(&rev_info, NULL);
index 3faae382de4fa345f6d54c9120d33ed86c02e2cc..e1e157d205a06ffad39a9685cab55b16c69d339c 100644 (file)
@@ -514,7 +514,7 @@ static int merge_working_tree(const struct checkout_opts *opts,
                }
                tree = parse_tree_indirect(old->commit ?
                                           &old->commit->object.oid :
-                                          &empty_tree_oid);
+                                          the_hash_algo->empty_tree);
                init_tree_desc(&trees[0], tree->buffer, tree->size);
                tree = parse_tree_indirect(&new->commit->object.oid);
                init_tree_desc(&trees[1], tree->buffer, tree->size);
index 9808d062a80a2ff07699fb0ea4cbd29f560630d3..16bfb22f7381ee8e6967ab836686c5def7cff892 100644 (file)
@@ -379,7 +379,7 @@ int cmd_diff(int argc, const char **argv, const char *prefix)
                                add_head_to_pending(&rev);
                                if (!rev.pending.nr) {
                                        struct tree *tree;
-                                       tree = lookup_tree(&empty_tree_oid);
+                                       tree = lookup_tree(the_hash_algo->empty_tree);
                                        add_pending_object(&rev, &tree->object, "HEAD");
                                }
                                break;
index 6c1fa896ad01a8de0dcd99be80827d436d2cc857..14fdf39165d20602ad8b682b55660ec2466c1d20 100644 (file)
@@ -142,11 +142,19 @@ static void cmd_log_init_finish(int argc, const char **argv, const char *prefix,
        struct userformat_want w;
        int quiet = 0, source = 0, mailmap = 0;
        static struct line_opt_callback_data line_cb = {NULL, NULL, STRING_LIST_INIT_DUP};
+       static struct string_list decorate_refs_exclude = STRING_LIST_INIT_NODUP;
+       static struct string_list decorate_refs_include = STRING_LIST_INIT_NODUP;
+       struct decoration_filter decoration_filter = {&decorate_refs_include,
+                                                     &decorate_refs_exclude};
 
        const struct option builtin_log_options[] = {
                OPT__QUIET(&quiet, N_("suppress diff output")),
                OPT_BOOL(0, "source", &source, N_("show source")),
                OPT_BOOL(0, "use-mailmap", &mailmap, N_("Use mail map file")),
+               OPT_STRING_LIST(0, "decorate-refs", &decorate_refs_include,
+                               N_("pattern"), N_("only decorate refs that match <pattern>")),
+               OPT_STRING_LIST(0, "decorate-refs-exclude", &decorate_refs_exclude,
+                               N_("pattern"), N_("do not decorate refs that match <pattern>")),
                { OPTION_CALLBACK, 0, "decorate", NULL, NULL, N_("decorate options"),
                  PARSE_OPT_OPTARG, decorate_callback},
                OPT_CALLBACK('L', NULL, &line_cb, "n,m:file",
@@ -205,7 +213,7 @@ static void cmd_log_init_finish(int argc, const char **argv, const char *prefix,
 
        if (decoration_style) {
                rev->show_decorations = 1;
-               load_ref_decorations(decoration_style);
+               load_ref_decorations(&decoration_filter, decoration_style);
        }
 
        if (rev->line_level_traverse)
index 166b777ed69073f44f82e8052a0bdb6f287d22a9..511dbbe0f6e25d8f0e8c6ce511cc0ff734adc9bc 100644 (file)
@@ -557,7 +557,7 @@ static int pull_into_void(const struct object_id *merge_head,
         * index/worktree changes that the user already made on the unborn
         * branch.
         */
-       if (checkout_fast_forward(&empty_tree_oid, merge_head, 0))
+       if (checkout_fast_forward(the_hash_algo->empty_tree, merge_head, 0))
                return 1;
 
        if (update_ref("initial pull", "HEAD", merge_head, curr_head, 0, UPDATE_REFS_DIE_ON_ERR))
index 2086f0eb089b34bd38b2a4f47ae4b710b7cb0ba1..a5c4a8a6941d46c78e4dc58d0df47532f0bb2b45 100644 (file)
@@ -623,7 +623,7 @@ static void status_submodule(const char *path, const struct object_id *ce_oid,
 
                if (refs_head_ref(get_submodule_ref_store(path),
                                  handle_submodule_head_ref, &oid))
-                       die(_("could not resolve HEAD ref inside the"
+                       die(_("could not resolve HEAD ref inside the "
                              "submodule '%s'"), path);
 
                print_status(flags, '+', path, &oid, displaypath);
diff --git a/cache.h b/cache.h
index cb5db7bf83053f675acebe4f8255f52881425773..d3e240228c9c488f78ee9be06c9d151f1d2325b2 100644 (file)
--- a/cache.h
+++ b/cache.h
@@ -14,6 +14,7 @@
 #include "hash.h"
 #include "path.h"
 #include "sha1-array.h"
+#include "repository.h"
 
 #ifndef platform_SHA_CTX
 /*
@@ -77,6 +78,8 @@ struct object_id {
        unsigned char hash[GIT_MAX_RAWSZ];
 };
 
+#define the_hash_algo the_repository->hash_algo
+
 #if defined(DT_UNKNOWN) && !defined(NO_D_TYPE_IN_DIRENT)
 #define DTYPE(de)      ((de)->d_type)
 #else
@@ -907,6 +910,7 @@ struct repository_format {
        int version;
        int precious_objects;
        int is_bare;
+       int hash_algo;
        char *work_tree;
        struct string_list unknown_extensions;
 };
@@ -1039,22 +1043,22 @@ extern const struct object_id empty_blob_oid;
 
 static inline int is_empty_blob_sha1(const unsigned char *sha1)
 {
-       return !hashcmp(sha1, EMPTY_BLOB_SHA1_BIN);
+       return !hashcmp(sha1, the_hash_algo->empty_blob->hash);
 }
 
 static inline int is_empty_blob_oid(const struct object_id *oid)
 {
-       return !hashcmp(oid->hash, EMPTY_BLOB_SHA1_BIN);
+       return !oidcmp(oid, the_hash_algo->empty_blob);
 }
 
 static inline int is_empty_tree_sha1(const unsigned char *sha1)
 {
-       return !hashcmp(sha1, EMPTY_TREE_SHA1_BIN);
+       return !hashcmp(sha1, the_hash_algo->empty_tree->hash);
 }
 
 static inline int is_empty_tree_oid(const struct object_id *oid)
 {
-       return !hashcmp(oid->hash, EMPTY_TREE_SHA1_BIN);
+       return !oidcmp(oid, the_hash_algo->empty_tree);
 }
 
 /* set default permissions by passing mode arguments to open(2) */
index 5173023cd3c3e4390e9ddc08e898d813f6a32093..8104603a3b36f2fd73761db34efde44d5938f68f 100644 (file)
@@ -218,7 +218,7 @@ int run_diff_files(struct rev_info *revs, unsigned int option)
                        } else if (revs->diffopt.ita_invisible_in_index &&
                                   ce_intent_to_add(ce)) {
                                diff_addremove(&revs->diffopt, '+', ce->ce_mode,
-                                              &empty_tree_oid, 0,
+                                              the_hash_algo->empty_tree, 0,
                                               ce->name, 0);
                                continue;
                        }
index 2208dcc2139be7130749fd3bae462320f17d3b21..edcc6d34692b28575d9728c25a407782310a39fb 100755 (executable)
@@ -885,7 +885,9 @@ sub expand_one_alias {
 }
 
 if (!defined $smtp_server) {
-       foreach (qw( /usr/sbin/sendmail /usr/lib/sendmail )) {
+       my @sendmail_paths = qw( /usr/sbin/sendmail /usr/lib/sendmail );
+       push @sendmail_paths, map {"$_/sendmail"} split /:/, $ENV{PATH};
+       foreach (@sendmail_paths) {
                if (-x $_) {
                        $smtp_server = $_;
                        last;
diff --git a/grep.c b/grep.c
index a69c05edc2e4fc6787076531b43a49c7ccdc1113..3d7cd0e96f1ee160a66dd500c58d4026bf24e34c 100644 (file)
--- a/grep.c
+++ b/grep.c
@@ -477,6 +477,8 @@ static void compile_pcre2_pattern(struct grep_pat *p, const struct grep_opt *opt
        int options = PCRE2_MULTILINE;
        const uint8_t *character_tables = NULL;
        int jitret;
+       int patinforet;
+       size_t jitsizearg;
 
        assert(opt->pcre2);
 
@@ -511,6 +513,30 @@ static void compile_pcre2_pattern(struct grep_pat *p, const struct grep_opt *opt
                jitret = pcre2_jit_compile(p->pcre2_pattern, PCRE2_JIT_COMPLETE);
                if (jitret)
                        die("Couldn't JIT the PCRE2 pattern '%s', got '%d'\n", p->pattern, jitret);
+
+               /*
+                * The pcre2_config(PCRE2_CONFIG_JIT, ...) call just
+                * tells us whether the library itself supports JIT,
+                * but to see whether we're going to be actually using
+                * JIT we need to extract PCRE2_INFO_JITSIZE from the
+                * pattern *after* we do pcre2_jit_compile() above.
+                *
+                * This is because if the pattern contains the
+                * (*NO_JIT) verb (see pcre2syntax(3))
+                * pcre2_jit_compile() will exit early with 0. If we
+                * then proceed to call pcre2_jit_match() further down
+                * the line instead of pcre2_match() we'll either
+                * segfault (pre PCRE 10.31) or run into a fatal error
+                * (post PCRE2 10.31)
+                */
+               patinforet = pcre2_pattern_info(p->pcre2_pattern, PCRE2_INFO_JITSIZE, &jitsizearg);
+               if (patinforet)
+                       BUG("pcre2_pattern_info() failed: %d", patinforet);
+               if (jitsizearg == 0) {
+                       p->pcre2_jit_on = 0;
+                       return;
+               }
+
                p->pcre2_jit_stack = pcre2_jit_stack_create(1, 1024 * 1024, NULL);
                if (!p->pcre2_jit_stack)
                        die("Couldn't allocate PCRE2 JIT stack");
diff --git a/hash.h b/hash.h
index 024d0d3d50b174aac1d948e9ecfa7ae92020355a..7d7a864f5dd43bb53ee6b31d391df3e15cbdbb08 100644 (file)
--- a/hash.h
+++ b/hash.h
@@ -1,6 +1,8 @@
 #ifndef HASH_H
 #define HASH_H
 
+#include "git-compat-util.h"
+
 #if defined(SHA1_PPC)
 #include "ppc/sha1.h"
 #elif defined(SHA1_APPLE)
 #include "block-sha1/sha1.h"
 #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
+ * be exposed to the user or serialized to disk.  To know whether a
+ * git_hash_algo struct points to some usable hash function, test the format_id
+ * field for being non-zero.  Use the name field for user-visible situations and
+ * the format_id field for fixed-length fields on disk.
+ */
+/* An unknown hash function. */
+#define GIT_HASH_UNKNOWN 0
+/* SHA-1 */
+#define GIT_HASH_SHA1 1
+/* 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);
+
+struct git_hash_algo {
+       /*
+        * The name of the algorithm, as appears in the config file and in
+        * messages.
+        */
+       const char *name;
+
+       /* 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;
+
+       /* The length of the hash in hex characters. */
+       size_t hexsz;
+
+       /* The hash initialization function. */
+       git_hash_init_fn init_fn;
+
+       /* The hash update function. */
+       git_hash_update_fn update_fn;
+
+       /* The hash finalization function. */
+       git_hash_final_fn final_fn;
+
+       /* The OID of the empty tree. */
+       const struct object_id *empty_tree;
+
+       /* The OID of the empty blob. */
+       const struct object_id *empty_blob;
+};
+extern const struct git_hash_algo hash_algos[GIT_HASH_NALGOS];
+
 #endif
index 7cb29a6aede8e24320555e1845f8e4eb2032ade9..7ce79f3f72c144063b56f44368ad00c34e6aa786 100644 (file)
--- a/hashmap.h
+++ b/hashmap.h
  *
  * #define COMPARE_VALUE 1
  *
- * static int long2string_cmp(const struct long2string *e1,
+ * static int long2string_cmp(const void *hashmap_cmp_fn_data,
+ *                            const struct long2string *e1,
  *                            const struct long2string *e2,
- *                            const void *keydata, const void *userdata)
+ *                            const void *keydata)
  * {
- *     char *string = keydata;
- *     unsigned *flags = (unsigned*)userdata;
+ *     const char *string = keydata;
+ *     unsigned flags = *(unsigned *)hashmap_cmp_fn_data;
  *
  *     if (flags & COMPARE_VALUE)
- *         return !(e1->key == e2->key) || (keydata ?
- *                  strcmp(e1->value, keydata) : strcmp(e1->value, e2->value));
+ *         return e1->key != e2->key ||
+ *                  strcmp(e1->value, string ? string : e2->value);
  *     else
- *         return !(e1->key == e2->key);
+ *         return e1->key != e2->key;
  * }
  *
  * int main(int argc, char **argv)
  * {
  *     long key;
- *     char *value, *action;
- *
- *     unsigned flags = ALLOW_DUPLICATE_KEYS;
+ *     char value[255], action[32];
+ *     unsigned flags = 0;
  *
  *     hashmap_init(&map, (hashmap_cmp_fn) long2string_cmp, &flags, 0);
  *
- *     while (scanf("%s %l %s", action, key, value)) {
+ *     while (scanf("%s %ld %s", action, &key, value)) {
  *
  *         if (!strcmp("add", action)) {
  *             struct long2string *e;
- *             e = malloc(sizeof(struct long2string) + strlen(value));
+ *             FLEX_ALLOC_STR(e, value, value);
  *             hashmap_entry_init(e, memhash(&key, sizeof(long)));
  *             e->key = key;
- *             memcpy(e->value, value, strlen(value));
  *             hashmap_add(&map, e);
  *         }
  *
  *         if (!strcmp("print_all_by_key", action)) {
- *             flags &= ~COMPARE_VALUE;
- *
- *             struct long2string k;
+ *             struct long2string k, *e;
  *             hashmap_entry_init(&k, memhash(&key, sizeof(long)));
  *             k.key = key;
  *
- *             struct long2string *e = hashmap_get(&map, &k, NULL);
+ *             flags &= ~COMPARE_VALUE;
+ *             e = hashmap_get(&map, &k, NULL);
  *             if (e) {
- *                 printf("first: %l %s\n", e->key, e->value);
- *                 while (e = hashmap_get_next(&map, e))
- *                     printf("found more: %l %s\n", e->key, e->value);
+ *                 printf("first: %ld %s\n", e->key, e->value);
+ *                 while ((e = hashmap_get_next(&map, e)))
+ *                     printf("found more: %ld %s\n", e->key, e->value);
  *             }
  *         }
  *
  *         if (!strcmp("has_exact_match", action)) {
- *             flags |= COMPARE_VALUE;
- *
  *             struct long2string *e;
- *             e = malloc(sizeof(struct long2string) + strlen(value));
+ *             FLEX_ALLOC_STR(e, value, value);
  *             hashmap_entry_init(e, memhash(&key, sizeof(long)));
  *             e->key = key;
- *             memcpy(e->value, value, strlen(value));
  *
- *             printf("%s found\n", hashmap_get(&map, e, NULL) ? "" : "not");
+ *             flags |= COMPARE_VALUE;
+ *             printf("%sfound\n", hashmap_get(&map, e, NULL) ? "" : "not ");
+ *             free(e);
  *         }
  *
  *         if (!strcmp("has_exact_match_no_heap_alloc", action)) {
- *             flags |= COMPARE_VALUE;
- *
- *             struct long2string e;
- *             hashmap_entry_init(e, memhash(&key, sizeof(long)));
- *             e.key = key;
+ *             struct long2string k;
+ *             hashmap_entry_init(&k, memhash(&key, sizeof(long)));
+ *             k.key = key;
  *
- *             printf("%s found\n", hashmap_get(&map, e, value) ? "" : "not");
+ *             flags |= COMPARE_VALUE;
+ *             printf("%sfound\n", hashmap_get(&map, &k, value) ? "" : "not ");
  *         }
  *
  *         if (!strcmp("end", action)) {
@@ -94,6 +90,8 @@
  *             break;
  *         }
  *     }
+ *
+ *     return 0;
  * }
  */
 
index 3b904f0375e233db974ab49b3b31dd2fc73e842d..fca29d4799da27164394a8c59da067a0522241fe 100644 (file)
@@ -94,8 +94,12 @@ static int add_ref_decoration(const char *refname, const struct object_id *oid,
 {
        struct object *obj;
        enum decoration_type type = DECORATION_NONE;
+       struct decoration_filter *filter = (struct decoration_filter *)cb_data;
 
-       assert(cb_data == NULL);
+       if (filter && !ref_filter_match(refname,
+                             filter->include_ref_pattern,
+                             filter->exclude_ref_pattern))
+               return 0;
 
        if (starts_with(refname, git_replace_ref_base)) {
                struct object_id original_oid;
@@ -148,15 +152,23 @@ static int add_graft_decoration(const struct commit_graft *graft, void *cb_data)
        return 0;
 }
 
-void load_ref_decorations(int flags)
+void load_ref_decorations(struct decoration_filter *filter, int flags)
 {
        if (!decoration_loaded) {
-
+               if (filter) {
+                       struct string_list_item *item;
+                       for_each_string_list_item(item, filter->exclude_ref_pattern) {
+                               normalize_glob_ref(item, NULL, item->string);
+                       }
+                       for_each_string_list_item(item, filter->include_ref_pattern) {
+                               normalize_glob_ref(item, NULL, item->string);
+                       }
+               }
                decoration_loaded = 1;
                decoration_flags = flags;
-               for_each_ref(add_ref_decoration, NULL);
-               head_ref(add_ref_decoration, NULL);
-               for_each_commit_graft(add_graft_decoration, NULL);
+               for_each_ref(add_ref_decoration, filter);
+               head_ref(add_ref_decoration, filter);
+               for_each_commit_graft(add_graft_decoration, filter);
        }
 }
 
index 48f11fb740ddf670cac819cb733cbc736cc30d0e..deba035187185bc28a83520b47480c3141d8398e 100644 (file)
@@ -7,6 +7,10 @@ struct log_info {
        struct commit *commit, *parent;
 };
 
+struct decoration_filter {
+       struct string_list *include_ref_pattern, *exclude_ref_pattern;
+};
+
 int parse_decorate_color_config(const char *var, const char *slot_name, const char *value);
 void init_log_tree_opt(struct rev_info *);
 int log_tree_diff_flush(struct rev_info *);
@@ -24,7 +28,7 @@ void show_decorations(struct rev_info *opt, struct commit *commit);
 void log_write_email_headers(struct rev_info *opt, struct commit *commit,
                             const char **extra_headers_p,
                             int *need_8bit_cte_p);
-void load_ref_decorations(int flags);
+void load_ref_decorations(struct decoration_filter *filter, int flags);
 
 #define FORMAT_PATCH_NAME_MAX 64
 void fmt_output_commit(struct strbuf *, struct commit *, struct rev_info *);
index d00b274381e7fff7efd2b38f4328764105d9d7af..a4c280dfc78e943ec541f83ccb0b39921ccdf2b2 100644 (file)
@@ -2082,7 +2082,7 @@ int merge_recursive(struct merge_options *o,
                /* if there is no common ancestor, use an empty tree */
                struct tree *tree;
 
-               tree = lookup_tree(&empty_tree_oid);
+               tree = lookup_tree(the_hash_algo->empty_tree);
                merged_common_ancestors = make_virtual_commit(tree, "ancestor");
        }
 
index 4a83b0ebd5ce8b24da0b32820f5666571b099ecf..0f6573cb17cbbbc2219453bdca424fd7ebc156dc 100644 (file)
@@ -595,7 +595,7 @@ int notes_merge(struct notes_merge_options *o,
        bases = get_merge_bases(local, remote);
        if (!bases) {
                base_oid = &null_oid;
-               base_tree_oid = &empty_tree_oid;
+               base_tree_oid = the_hash_algo->empty_tree;
                if (o->verbosity >= 4)
                        printf("No merge base found; doing history-less merge\n");
        } else if (!bases->next) {
index 2f6b0ae6c1486660bb37442b991cb1140a9f2bb6..f7ce4902301490d73bdd79bd396cf7bbe5f893ea 100644 (file)
--- a/pretty.c
+++ b/pretty.c
@@ -1186,11 +1186,11 @@ static size_t format_commit_one(struct strbuf *sb, /* in UTF-8 */
                strbuf_addstr(sb, get_revision_mark(NULL, commit));
                return 1;
        case 'd':
-               load_ref_decorations(DECORATE_SHORT_REFS);
+               load_ref_decorations(NULL, DECORATE_SHORT_REFS);
                format_decorations(sb, commit, c->auto_color);
                return 1;
        case 'D':
-               load_ref_decorations(DECORATE_SHORT_REFS);
+               load_ref_decorations(NULL, DECORATE_SHORT_REFS);
                format_decorations_extended(sb, commit, c->auto_color, "", ", ", "");
                return 1;
        case 'g':               /* reflog info */
index 289678d43d801411dbe56b8090a2e1a18a158499..5f87f4568f196a9d4ba531da1d0e3098629c7da2 100644 (file)
@@ -34,7 +34,6 @@ struct progress {
        unsigned total;
        unsigned last_percent;
        unsigned delay;
-       unsigned delayed_percent_threshold;
        struct throughput *throughput;
        uint64_t start_ns;
 };
@@ -83,20 +82,8 @@ static int display(struct progress *progress, unsigned n, const char *done)
 {
        const char *eol, *tp;
 
-       if (progress->delay) {
-               if (!progress_update || --progress->delay)
-                       return 0;
-               if (progress->total) {
-                       unsigned percent = n * 100 / progress->total;
-                       if (percent > progress->delayed_percent_threshold) {
-                               /* inhibit this progress report entirely */
-                               clear_progress_signal();
-                               progress->delay = -1;
-                               progress->total = 0;
-                               return 0;
-                       }
-               }
-       }
+       if (progress->delay && (!progress_update || --progress->delay))
+               return 0;
 
        progress->last_value = n;
        tp = (progress->throughput) ? progress->throughput->display.buf : "";
@@ -206,7 +193,7 @@ int display_progress(struct progress *progress, unsigned n)
 }
 
 static struct progress *start_progress_delay(const char *title, unsigned total,
-                                            unsigned percent_threshold, unsigned delay)
+                                            unsigned delay)
 {
        struct progress *progress = malloc(sizeof(*progress));
        if (!progress) {
@@ -219,7 +206,6 @@ static struct progress *start_progress_delay(const char *title, unsigned total,
        progress->total = total;
        progress->last_value = -1;
        progress->last_percent = -1;
-       progress->delayed_percent_threshold = percent_threshold;
        progress->delay = delay;
        progress->throughput = NULL;
        progress->start_ns = getnanotime();
@@ -229,12 +215,12 @@ static struct progress *start_progress_delay(const char *title, unsigned total,
 
 struct progress *start_delayed_progress(const char *title, unsigned total)
 {
-       return start_progress_delay(title, total, 0, 2);
+       return start_progress_delay(title, total, 2);
 }
 
 struct progress *start_progress(const char *title, unsigned total)
 {
-       return start_progress_delay(title, total, 0, 0);
+       return start_progress_delay(title, total, 0);
 }
 
 void stop_progress(struct progress **p_progress)
diff --git a/refs.c b/refs.c
index 339d4318ee4500ffeb26426bdf9976979ecf739a..20ba82b4343ff2ef72cea32deec8a8d7fbd6def7 100644 (file)
--- a/refs.c
+++ b/refs.c
@@ -242,6 +242,50 @@ int ref_exists(const char *refname)
        return !!resolve_ref_unsafe(refname, RESOLVE_REF_READING, NULL, NULL);
 }
 
+static int match_ref_pattern(const char *refname,
+                            const struct string_list_item *item)
+{
+       int matched = 0;
+       if (item->util == NULL) {
+               if (!wildmatch(item->string, refname, 0))
+                       matched = 1;
+       } else {
+               const char *rest;
+               if (skip_prefix(refname, item->string, &rest) &&
+                   (!*rest || *rest == '/'))
+                       matched = 1;
+       }
+       return matched;
+}
+
+int ref_filter_match(const char *refname,
+                    const struct string_list *include_patterns,
+                    const struct string_list *exclude_patterns)
+{
+       struct string_list_item *item;
+
+       if (exclude_patterns && exclude_patterns->nr) {
+               for_each_string_list_item(item, exclude_patterns) {
+                       if (match_ref_pattern(refname, item))
+                               return 0;
+               }
+       }
+
+       if (include_patterns && include_patterns->nr) {
+               int found = 0;
+               for_each_string_list_item(item, include_patterns) {
+                       if (match_ref_pattern(refname, item)) {
+                               found = 1;
+                               break;
+                       }
+               }
+
+               if (!found)
+                       return 0;
+       }
+       return 1;
+}
+
 static int filter_refs(const char *refname, const struct object_id *oid,
                           int flags, void *data)
 {
@@ -369,6 +413,27 @@ int head_ref_namespaced(each_ref_fn fn, void *cb_data)
        return ret;
 }
 
+void normalize_glob_ref(struct string_list_item *item, const char *prefix,
+                       const char *pattern)
+{
+       struct strbuf normalized_pattern = STRBUF_INIT;
+
+       if (*pattern == '/')
+               BUG("pattern must not start with '/'");
+
+       if (prefix) {
+               strbuf_addstr(&normalized_pattern, prefix);
+       }
+       else if (!starts_with(pattern, "refs/"))
+               strbuf_addstr(&normalized_pattern, "refs/");
+       strbuf_addstr(&normalized_pattern, pattern);
+       strbuf_strip_suffix(&normalized_pattern, "/");
+
+       item->string = strbuf_detach(&normalized_pattern, NULL);
+       item->util = has_glob_specials(pattern) ? NULL : item->string;
+       strbuf_release(&normalized_pattern);
+}
+
 int for_each_glob_ref_in(each_ref_fn fn, const char *pattern,
        const char *prefix, void *cb_data)
 {
diff --git a/refs.h b/refs.h
index 18582a408c60b44ed0b74e6d6c762c7d4d93f0e9..01be5ae32fb01298ff6c0738ac4adfe42643b682 100644 (file)
--- a/refs.h
+++ b/refs.h
@@ -312,6 +312,30 @@ int for_each_namespaced_ref(each_ref_fn fn, void *cb_data);
 int refs_for_each_rawref(struct ref_store *refs, each_ref_fn fn, void *cb_data);
 int for_each_rawref(each_ref_fn fn, void *cb_data);
 
+/*
+ * Normalizes partial refs to their fully qualified form.
+ * Will prepend <prefix> to the <pattern> if it doesn't start with 'refs/'.
+ * <prefix> will default to 'refs/' if NULL.
+ *
+ * item.string will be set to the result.
+ * item.util will be set to NULL if <pattern> contains glob characters, or
+ * non-NULL if it doesn't.
+ */
+void normalize_glob_ref(struct string_list_item *item, const char *prefix,
+                       const char *pattern);
+
+/*
+ * Returns 0 if refname matches any of the exclude_patterns, or if it doesn't
+ * match any of the include_patterns. Returns 1 otherwise.
+ *
+ * If pattern list is NULL or empty, matching against that list is skipped.
+ * This has the effect of matching everything by default, unless the user
+ * specifies rules otherwise.
+ */
+int ref_filter_match(const char *refname,
+                    const struct string_list *include_patterns,
+                    const struct string_list *exclude_patterns);
+
 static inline const char *has_glob_specials(const char *pattern)
 {
        return strpbrk(pattern, "?*[");
index bb2fae5446b7ea8d2bfac87faa30c165f714d121..998413b8bb8deaddef76d93f67be4a1435c9e3a7 100644 (file)
@@ -5,7 +5,7 @@
 
 /* The main repository */
 static struct repository the_repo = {
-       NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &the_index, 0, 0
+       NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &the_index, NULL, 0, 0
 };
 struct repository *the_repository = &the_repo;
 
@@ -64,6 +64,11 @@ void repo_set_gitdir(struct repository *repo, const char *path)
        free(old_gitdir);
 }
 
+void repo_set_hash_algo(struct repository *repo, int hash_algo)
+{
+       repo->hash_algo = &hash_algos[hash_algo];
+}
+
 /*
  * Attempt to resolve and set the provided 'gitdir' for repository 'repo'.
  * Return 0 upon success and a non-zero value upon failure.
@@ -136,6 +141,8 @@ int repo_init(struct repository *repo, const char *gitdir, const char *worktree)
        if (read_and_verify_repository_format(&format, repo->commondir))
                goto error;
 
+       repo_set_hash_algo(repo, format.hash_algo);
+
        if (worktree)
                repo_set_worktree(repo, worktree);
 
index 7f5e24a0a24011393e9b1b9986895ebe8b3f10ab..0329e40c7f5e72dad3ba46328a8e3d6c29ed8e58 100644 (file)
@@ -4,6 +4,7 @@
 struct config_set;
 struct index_state;
 struct submodule_cache;
+struct git_hash_algo;
 
 struct repository {
        /* Environment */
@@ -67,6 +68,9 @@ struct repository {
         */
        struct index_state *index;
 
+       /* Repository's current hash algorithm, as serialized on disk. */
+       const struct git_hash_algo *hash_algo;
+
        /* Configurations */
        /*
         * Bit used during initialization to indicate if repository state (like
@@ -86,6 +90,7 @@ extern struct repository *the_repository;
 
 extern void repo_set_gitdir(struct repository *repo, const char *path);
 extern void repo_set_worktree(struct repository *repo, const char *path);
+extern void repo_set_hash_algo(struct repository *repo, int algo);
 extern int repo_init(struct repository *repo, const char *gitdir, const char *worktree);
 extern int repo_submodule_init(struct repository *submodule,
                               struct repository *superproject,
index e2e691dd5a48087da0b476cf4d6cded645f23d6e..f6a3da5cd969765ada5ef536f08fb0cf4846cd39 100644 (file)
@@ -1832,7 +1832,7 @@ static int handle_revision_opt(struct rev_info *revs, int argc, const char **arg
                revs->simplify_by_decoration = 1;
                revs->limited = 1;
                revs->prune = 1;
-               load_ref_decorations(DECORATE_SHORT_REFS);
+               load_ref_decorations(NULL, DECORATE_SHORT_REFS);
        } else if (!strcmp(arg, "--date-order")) {
                revs->sort_order = REV_SORT_BY_COMMIT_DATE;
                revs->topo_order = 1;
index fa94ed652d2ce87fddf824aa516456b5f42735e7..e90bc316bb7a232a40c332c6d1add255d3893869 100644 (file)
@@ -347,7 +347,7 @@ static int read_oneliner(struct strbuf *buf,
 
 static struct tree *empty_tree(void)
 {
-       return lookup_tree(&empty_tree_oid);
+       return lookup_tree(the_hash_algo->empty_tree);
 }
 
 static int error_dirty_index(struct replay_opts *opts)
@@ -706,7 +706,7 @@ static int is_original_commit_empty(struct commit *commit)
                                oid_to_hex(&parent->object.oid));
                ptree_oid = &parent->tree->object.oid;
        } else {
-               ptree_oid = &empty_tree_oid; /* commit is root */
+               ptree_oid = the_hash_algo->empty_tree; /* commit is root */
        }
 
        return !oidcmp(ptree_oid, &commit->tree->object.oid);
@@ -959,7 +959,7 @@ static int do_pick_commit(enum todo_command command, struct commit *commit,
        } else {
                unborn = get_oid("HEAD", &head);
                if (unborn)
-                       oidcpy(&head, &empty_tree_oid);
+                       oidcpy(&head, the_hash_algo->empty_tree);
                if (index_differs_from(unborn ? EMPTY_TREE_SHA1_HEX : "HEAD",
                                       NULL, 0))
                        return error_dirty_index(opts);
diff --git a/setup.c b/setup.c
index 94768512b7913c4e46b90fc8226c183cbd7239d7..50c6b2ab11fa3579a17079c16a4fb7241df9b875 100644 (file)
--- a/setup.c
+++ b/setup.c
@@ -434,16 +434,15 @@ static int check_repo_format(const char *var, const char *value, void *vdata)
        return 0;
 }
 
-static int check_repository_format_gently(const char *gitdir, int *nongit_ok)
+static int check_repository_format_gently(const char *gitdir, struct repository_format *candidate, int *nongit_ok)
 {
        struct strbuf sb = STRBUF_INIT;
        struct strbuf err = STRBUF_INIT;
-       struct repository_format candidate;
        int has_common;
 
        has_common = get_common_dir(&sb, gitdir);
        strbuf_addstr(&sb, "/config");
-       read_repository_format(&candidate, sb.buf);
+       read_repository_format(candidate, sb.buf);
        strbuf_release(&sb);
 
        /*
@@ -451,10 +450,10 @@ static int check_repository_format_gently(const char *gitdir, int *nongit_ok)
         * we treat a missing config as a silent "ok", even when nongit_ok
         * is unset.
         */
-       if (candidate.version < 0)
+       if (candidate->version < 0)
                return 0;
 
-       if (verify_repository_format(&candidate, &err) < 0) {
+       if (verify_repository_format(candidate, &err) < 0) {
                if (nongit_ok) {
                        warning("%s", err.buf);
                        strbuf_release(&err);
@@ -464,21 +463,21 @@ static int check_repository_format_gently(const char *gitdir, int *nongit_ok)
                die("%s", err.buf);
        }
 
-       repository_format_precious_objects = candidate.precious_objects;
-       string_list_clear(&candidate.unknown_extensions, 0);
+       repository_format_precious_objects = candidate->precious_objects;
+       string_list_clear(&candidate->unknown_extensions, 0);
        if (!has_common) {
-               if (candidate.is_bare != -1) {
-                       is_bare_repository_cfg = candidate.is_bare;
+               if (candidate->is_bare != -1) {
+                       is_bare_repository_cfg = candidate->is_bare;
                        if (is_bare_repository_cfg == 1)
                                inside_work_tree = -1;
                }
-               if (candidate.work_tree) {
+               if (candidate->work_tree) {
                        free(git_work_tree_cfg);
-                       git_work_tree_cfg = candidate.work_tree;
+                       git_work_tree_cfg = candidate->work_tree;
                        inside_work_tree = -1;
                }
        } else {
-               free(candidate.work_tree);
+               free(candidate->work_tree);
        }
 
        return 0;
@@ -489,6 +488,7 @@ int read_repository_format(struct repository_format *format, const char *path)
        memset(format, 0, sizeof(*format));
        format->version = -1;
        format->is_bare = -1;
+       format->hash_algo = GIT_HASH_SHA1;
        string_list_init(&format->unknown_extensions, 1);
        git_config_from_file(check_repo_format, path, format);
        return format->version;
@@ -625,6 +625,7 @@ const char *read_gitfile_gently(const char *path, int *return_error_code)
 
 static const char *setup_explicit_git_dir(const char *gitdirenv,
                                          struct strbuf *cwd,
+                                         struct repository_format *repo_fmt,
                                          int *nongit_ok)
 {
        const char *work_tree_env = getenv(GIT_WORK_TREE_ENVIRONMENT);
@@ -650,7 +651,7 @@ static const char *setup_explicit_git_dir(const char *gitdirenv,
                die("Not a git repository: '%s'", gitdirenv);
        }
 
-       if (check_repository_format_gently(gitdirenv, nongit_ok)) {
+       if (check_repository_format_gently(gitdirenv, repo_fmt, nongit_ok)) {
                free(gitfile);
                return NULL;
        }
@@ -723,9 +724,10 @@ static const char *setup_explicit_git_dir(const char *gitdirenv,
 
 static const char *setup_discovered_git_dir(const char *gitdir,
                                            struct strbuf *cwd, int offset,
+                                           struct repository_format *repo_fmt,
                                            int *nongit_ok)
 {
-       if (check_repository_format_gently(gitdir, nongit_ok))
+       if (check_repository_format_gently(gitdir, repo_fmt, nongit_ok))
                return NULL;
 
        /* --work-tree is set without --git-dir; use discovered one */
@@ -737,7 +739,7 @@ static const char *setup_discovered_git_dir(const char *gitdir,
                        gitdir = to_free = real_pathdup(gitdir, 1);
                if (chdir(cwd->buf))
                        die_errno("Could not come back to cwd");
-               ret = setup_explicit_git_dir(gitdir, cwd, nongit_ok);
+               ret = setup_explicit_git_dir(gitdir, cwd, repo_fmt, nongit_ok);
                free(to_free);
                return ret;
        }
@@ -769,11 +771,12 @@ static const char *setup_discovered_git_dir(const char *gitdir,
 
 /* #16.1, #17.1, #20.1, #21.1, #22.1 (see t1510) */
 static const char *setup_bare_git_dir(struct strbuf *cwd, int offset,
+                                     struct repository_format *repo_fmt,
                                      int *nongit_ok)
 {
        int root_len;
 
-       if (check_repository_format_gently(".", nongit_ok))
+       if (check_repository_format_gently(".", repo_fmt, nongit_ok))
                return NULL;
 
        setenv(GIT_IMPLICIT_WORK_TREE_ENVIRONMENT, "0", 1);
@@ -785,7 +788,7 @@ static const char *setup_bare_git_dir(struct strbuf *cwd, int offset,
                gitdir = offset == cwd->len ? "." : xmemdupz(cwd->buf, offset);
                if (chdir(cwd->buf))
                        die_errno("Could not come back to cwd");
-               return setup_explicit_git_dir(gitdir, cwd, nongit_ok);
+               return setup_explicit_git_dir(gitdir, cwd, repo_fmt, nongit_ok);
        }
 
        inside_git_dir = 1;
@@ -1026,6 +1029,7 @@ const char *setup_git_directory_gently(int *nongit_ok)
        static struct strbuf cwd = STRBUF_INIT;
        struct strbuf dir = STRBUF_INIT, gitdir = STRBUF_INIT;
        const char *prefix;
+       struct repository_format repo_fmt;
 
        /*
         * We may have read an incomplete configuration before
@@ -1053,18 +1057,18 @@ const char *setup_git_directory_gently(int *nongit_ok)
                prefix = NULL;
                break;
        case GIT_DIR_EXPLICIT:
-               prefix = setup_explicit_git_dir(gitdir.buf, &cwd, nongit_ok);
+               prefix = setup_explicit_git_dir(gitdir.buf, &cwd, &repo_fmt, nongit_ok);
                break;
        case GIT_DIR_DISCOVERED:
                if (dir.len < cwd.len && chdir(dir.buf))
                        die(_("Cannot change to '%s'"), dir.buf);
                prefix = setup_discovered_git_dir(gitdir.buf, &cwd, dir.len,
-                                                 nongit_ok);
+                                                 &repo_fmt, nongit_ok);
                break;
        case GIT_DIR_BARE:
                if (dir.len < cwd.len && chdir(dir.buf))
                        die(_("Cannot change to '%s'"), dir.buf);
-               prefix = setup_bare_git_dir(&cwd, dir.len, nongit_ok);
+               prefix = setup_bare_git_dir(&cwd, dir.len, &repo_fmt, nongit_ok);
                break;
        case GIT_DIR_HIT_CEILING:
                prefix = setup_nongit(cwd.buf, nongit_ok);
@@ -1110,6 +1114,8 @@ const char *setup_git_directory_gently(int *nongit_ok)
                        repo_set_gitdir(the_repository, gitdir);
                        setup_git_env();
                }
+               if (startup_info->have_repository)
+                       repo_set_hash_algo(the_repository, repo_fmt.hash_algo);
        }
 
        strbuf_release(&dir);
@@ -1171,7 +1177,8 @@ int git_config_perm(const char *var, const char *value)
 
 void check_repository_format(void)
 {
-       check_repository_format_gently(get_git_dir(), NULL);
+       struct repository_format repo_fmt;
+       check_repository_format_gently(get_git_dir(), &repo_fmt, NULL);
        startup_info->have_repository = 1;
 }
 
index afe4b90f6ee0e6c00af3e57c7c92ac5245bd1792..3da70ac650a8cdeca6ef8a6a424a7740d38267d5 100644 (file)
@@ -39,6 +39,64 @@ const struct object_id empty_blob_oid = {
        EMPTY_BLOB_SHA1_BIN_LITERAL
 };
 
+static void git_hash_sha1_init(void *ctx)
+{
+       git_SHA1_Init((git_SHA_CTX *)ctx);
+}
+
+static void git_hash_sha1_update(void *ctx, const void *data, size_t len)
+{
+       git_SHA1_Update((git_SHA_CTX *)ctx, data, len);
+}
+
+static void git_hash_sha1_final(unsigned char *hash, void *ctx)
+{
+       git_SHA1_Final(hash, (git_SHA_CTX *)ctx);
+}
+
+static void git_hash_unknown_init(void *ctx)
+{
+       die("trying to init unknown hash");
+}
+
+static void git_hash_unknown_update(void *ctx, const void *data, size_t len)
+{
+       die("trying to update unknown hash");
+}
+
+static void git_hash_unknown_final(unsigned char *hash, void *ctx)
+{
+       die("trying to finalize unknown hash");
+}
+
+const struct git_hash_algo hash_algos[GIT_HASH_NALGOS] = {
+       {
+               NULL,
+               0x00000000,
+               0,
+               0,
+               0,
+               git_hash_unknown_init,
+               git_hash_unknown_update,
+               git_hash_unknown_final,
+               NULL,
+               NULL,
+       },
+       {
+               "sha-1",
+               /* "sha1", big-endian */
+               0x73686131,
+               sizeof(git_SHA_CTX),
+               GIT_SHA1_RAWSZ,
+               GIT_SHA1_HEXSZ,
+               git_hash_sha1_init,
+               git_hash_sha1_update,
+               git_hash_sha1_final,
+               &empty_tree_oid,
+               &empty_blob_oid,
+       },
+};
+
 /*
  * This is meant to hold a *small* number of objects that you would
  * want read_sha1_file() to be able to return, but yet you do not want
@@ -1906,7 +1964,6 @@ int for_each_file_in_obj_subdir(unsigned int subdir_nr,
        origlen = path->len;
        strbuf_complete(path, '/');
        strbuf_addf(path, "%02x", subdir_nr);
-       baselen = path->len;
 
        dir = opendir(path->buf);
        if (!dir) {
@@ -1917,15 +1974,18 @@ int for_each_file_in_obj_subdir(unsigned int subdir_nr,
        }
 
        oid.hash[0] = subdir_nr;
+       strbuf_addch(path, '/');
+       baselen = path->len;
 
        while ((de = readdir(dir))) {
+               size_t namelen;
                if (is_dot_or_dotdot(de->d_name))
                        continue;
 
+               namelen = strlen(de->d_name);
                strbuf_setlen(path, baselen);
-               strbuf_addf(path, "/%s", de->d_name);
-
-               if (strlen(de->d_name) == GIT_SHA1_HEXSZ - 2 &&
+               strbuf_add(path, de->d_name, namelen);
+               if (namelen == GIT_SHA1_HEXSZ - 2 &&
                    !hex_to_bytes(oid.hash + 1, de->d_name,
                                  GIT_SHA1_RAWSZ - 1)) {
                        if (obj_cb) {
@@ -1944,7 +2004,7 @@ int for_each_file_in_obj_subdir(unsigned int subdir_nr,
        }
        closedir(dir);
 
-       strbuf_setlen(path, baselen);
+       strbuf_setlen(path, baselen - 1);
        if (!r && subdir_cb)
                r = subdir_cb(subdir_nr, path->buf, data);
 
index 0a74acb2369ac26cb56b05a953171330c3abe652..14c8c10d66b9aaa2d8f0c109cf0dd668701cb2eb 100644 (file)
--- a/strbuf.h
+++ b/strbuf.h
@@ -480,15 +480,6 @@ extern int strbuf_normalize_path(struct strbuf *sb);
  */
 extern void strbuf_stripspace(struct strbuf *buf, int skip_comments);
 
-/**
- * Temporary alias until all topic branches have switched to use
- * strbuf_stripspace directly.
- */
-static inline void stripspace(struct strbuf *buf, int skip_comments)
-{
-       strbuf_stripspace(buf, skip_comments);
-}
-
 static inline int strbuf_strip_suffix(struct strbuf *sb, const char *suffix)
 {
        if (strip_suffix_mem(sb->buf, &sb->len, suffix)) {
index 95e6aff2bb74e1374d22997d1918ed190c6edafc..fa25888783aa9ba7ce5b290ba64ec3c1b7a87cec 100644 (file)
@@ -587,7 +587,7 @@ void show_submodule_inline_diff(struct diff_options *o, const char *path,
                struct object_id *one, struct object_id *two,
                unsigned dirty_submodule)
 {
-       const struct object_id *old = &empty_tree_oid, *new = &empty_tree_oid;
+       const struct object_id *old = the_hash_algo->empty_tree, *new = the_hash_algo->empty_tree;
        struct commit *left = NULL, *right = NULL;
        struct commit_list *merge_bases = NULL;
        struct child_process cp = CHILD_PROCESS_INIT;
index 4b079e4494d9324f0b03dfe8f714b3717292c0b6..b3f7b449c366c2d7d7afd12139a54b7a588f9747 100644 (file)
--- a/t/README
+++ b/t/README
@@ -332,13 +332,10 @@ Writing Tests
 -------------
 
 The test script is written as a shell script.  It should start
-with the standard "#!/bin/sh" with copyright notices, and an
+with the standard "#!/bin/sh", and an
 assignment to variable 'test_description', like this:
 
        #!/bin/sh
-       #
-       # Copyright (c) 2005 Junio C Hamano
-       #
 
        test_description='xxx test (option --frotz)
 
@@ -677,6 +674,11 @@ library for your script to use.
    <expected> file.  This behaves like "cmp" but produces more
    helpful output when the test is run with "-v" option.
 
+ - test_cmp_rev <expected> <actual>
+
+   Check whether the <expected> rev points to the same commit as the
+   <actual> rev.
+
  - test_line_count (= | -lt | -ge | ...) <length> <file>
 
    Check whether a file has the length it is expected to.
@@ -808,6 +810,18 @@ use these, and "test_set_prereq" for how to define your own.
    Git was compiled with support for PCRE. Wrap any tests
    that use git-grep --perl-regexp or git-grep -P in these.
 
+ - LIBPCRE1
+
+   Git was compiled with PCRE v1 support via
+   USE_LIBPCRE1=YesPlease. Wrap any PCRE using tests that for some
+   reason need v1 of the PCRE library instead of v2 in these.
+
+ - LIBPCRE2
+
+   Git was compiled with PCRE v2 support via
+   USE_LIBPCRE2=YesPlease. Wrap any PCRE using tests that for some
+   reason need v2 of the PCRE library instead of v1 in these.
+
  - CASE_INSENSITIVE_FS
 
    Test is run on a case insensitive file system.
index e0ed05907c7277def1e9fcda15bd1e1fe98ae6cc..392bcc0e51f8ad907916851016157b12ea134835 100755 (executable)
@@ -35,4 +35,8 @@ test_perf 'git log --oneline --raw --parents' '
        git log --oneline --raw --parents >/dev/null
 '
 
+test_perf 'git log --oneline --raw --parents -1000' '
+       git log --oneline --raw --parents -1000 >/dev/null
+'
+
 test_done
index 8f155da7a50a657db9fd092e24639f67cd03cd24..25b1f8cc73bc35bedaaffeacbb75a1329d725c3b 100755 (executable)
@@ -737,6 +737,107 @@ test_expect_success 'log.decorate configuration' '
 
 '
 
+test_expect_success 'decorate-refs with glob' '
+       cat >expect.decorate <<-\EOF &&
+       Merge-tag-reach
+       Merge-tags-octopus-a-and-octopus-b
+       seventh
+       octopus-b (octopus-b)
+       octopus-a (octopus-a)
+       reach
+       EOF
+       git log -n6 --decorate=short --pretty="tformat:%f%d" \
+               --decorate-refs="heads/octopus*" >actual &&
+       test_cmp expect.decorate actual
+'
+
+test_expect_success 'decorate-refs without globs' '
+       cat >expect.decorate <<-\EOF &&
+       Merge-tag-reach
+       Merge-tags-octopus-a-and-octopus-b
+       seventh
+       octopus-b
+       octopus-a
+       reach (tag: reach)
+       EOF
+       git log -n6 --decorate=short --pretty="tformat:%f%d" \
+               --decorate-refs="tags/reach" >actual &&
+       test_cmp expect.decorate actual
+'
+
+test_expect_success 'multiple decorate-refs' '
+       cat >expect.decorate <<-\EOF &&
+       Merge-tag-reach
+       Merge-tags-octopus-a-and-octopus-b
+       seventh
+       octopus-b (octopus-b)
+       octopus-a (octopus-a)
+       reach (tag: reach)
+       EOF
+       git log -n6 --decorate=short --pretty="tformat:%f%d" \
+               --decorate-refs="heads/octopus*" \
+               --decorate-refs="tags/reach" >actual &&
+    test_cmp expect.decorate actual
+'
+
+test_expect_success 'decorate-refs-exclude with glob' '
+       cat >expect.decorate <<-\EOF &&
+       Merge-tag-reach (HEAD -> master)
+       Merge-tags-octopus-a-and-octopus-b
+       seventh (tag: seventh)
+       octopus-b (tag: octopus-b)
+       octopus-a (tag: octopus-a)
+       reach (tag: reach, reach)
+       EOF
+       git log -n6 --decorate=short --pretty="tformat:%f%d" \
+               --decorate-refs-exclude="heads/octopus*" >actual &&
+       test_cmp expect.decorate actual
+'
+
+test_expect_success 'decorate-refs-exclude without globs' '
+       cat >expect.decorate <<-\EOF &&
+       Merge-tag-reach (HEAD -> master)
+       Merge-tags-octopus-a-and-octopus-b
+       seventh (tag: seventh)
+       octopus-b (tag: octopus-b, octopus-b)
+       octopus-a (tag: octopus-a, octopus-a)
+       reach (reach)
+       EOF
+       git log -n6 --decorate=short --pretty="tformat:%f%d" \
+               --decorate-refs-exclude="tags/reach" >actual &&
+       test_cmp expect.decorate actual
+'
+
+test_expect_success 'multiple decorate-refs-exclude' '
+       cat >expect.decorate <<-\EOF &&
+       Merge-tag-reach (HEAD -> master)
+       Merge-tags-octopus-a-and-octopus-b
+       seventh (tag: seventh)
+       octopus-b (tag: octopus-b)
+       octopus-a (tag: octopus-a)
+       reach (reach)
+       EOF
+       git log -n6 --decorate=short --pretty="tformat:%f%d" \
+               --decorate-refs-exclude="heads/octopus*" \
+               --decorate-refs-exclude="tags/reach" >actual &&
+       test_cmp expect.decorate actual
+'
+
+test_expect_success 'decorate-refs and decorate-refs-exclude' '
+       cat >expect.decorate <<-\EOF &&
+       Merge-tag-reach (master)
+       Merge-tags-octopus-a-and-octopus-b
+       seventh
+       octopus-b
+       octopus-a
+       reach (reach)
+       EOF
+       git log -n6 --decorate=short --pretty="tformat:%f%d" \
+               --decorate-refs="heads/*" \
+               --decorate-refs-exclude="heads/oc*" >actual &&
+       test_cmp expect.decorate actual
+'
+
 test_expect_success 'log.decorate config parsing' '
        git log --oneline --decorate=full >expect.full &&
        git log --oneline --decorate=short >expect.short &&
index c02ca735b9e31952811bfbb19048081dc546bd8e..1797f632a388d16f23a47c7693c7a3f0f0deabf6 100755 (executable)
@@ -1131,6 +1131,12 @@ test_expect_success PCRE 'grep -P pattern' '
        test_cmp expected actual
 '
 
+test_expect_success LIBPCRE2 "grep -P with (*NO_JIT) doesn't error out" '
+       git grep -P "(*NO_JIT)\p{Ps}.*?\p{Pe}" hello.c >actual &&
+       test_cmp expected actual
+
+'
+
 test_expect_success !PCRE 'grep -P pattern errors without PCRE' '
        test_must_fail git grep -P "foo.*bar"
 '
index 116bd6a70cf727f8dff496b9340b85146208e778..e7065df2bb028aff76f3169d84873a1a3d789571 100644 (file)
@@ -1028,6 +1028,8 @@ test -z "$NO_PERL" && test_set_prereq PERL
 test -z "$NO_PTHREADS" && test_set_prereq PTHREADS
 test -z "$NO_PYTHON" && test_set_prereq PYTHON
 test -n "$USE_LIBPCRE1$USE_LIBPCRE2" && test_set_prereq PCRE
+test -n "$USE_LIBPCRE1" && test_set_prereq LIBPCRE1
+test -n "$USE_LIBPCRE2" && test_set_prereq LIBPCRE2
 test -z "$NO_GETTEXT" && test_set_prereq GETTEXT
 
 # Can we rely on git's output in the C locale?