Merge branch 'rs/ring-buffer-wraparound' into maint
authorJunio C Hamano <gitster@pobox.com>
Tue, 29 Nov 2016 21:27:55 +0000 (13:27 -0800)
committerJunio C Hamano <gitster@pobox.com>
Tue, 29 Nov 2016 21:27:55 +0000 (13:27 -0800)
The code that we have used for the past 10+ years to cycle
4-element ring buffers turns out to be not quite portable in
theoretical world.

* rs/ring-buffer-wraparound:
hex: make wraparound of the index into ring-buffer explicit

59 files changed:
.travis.yml
Documentation/RelNotes/2.10.2.txt
Documentation/config.txt
Documentation/git-commit.txt
Documentation/git-merge-base.txt
Documentation/git-submodule.txt
Documentation/git-tag.txt
Documentation/git.txt
Documentation/gitmodules.txt
Documentation/howto/revert-a-faulty-merge.txt
Documentation/pretty-formats.txt
GIT-VERSION-GEN
Makefile
builtin/am.c
builtin/clone.c
builtin/fetch.c
builtin/fmt-merge-msg.c
builtin/merge-base.c
builtin/merge.c
builtin/reset.c
builtin/submodule--helper.c
cache.h
configure.ac
contrib/coccinelle/.gitignore [new file with mode: 0644]
contrib/coccinelle/free.cocci [new file with mode: 0644]
contrib/coccinelle/object_id.cocci
contrib/coccinelle/strbuf.cocci [new file with mode: 0644]
contrib/coccinelle/xstrdup_or_null.cocci [new file with mode: 0644]
contrib/completion/git-completion.bash
diff.c
fetch-pack.c
git-compat-util.h
git.c
http.c
imap-send.c
mailmap.c
merge-recursive.c
parse-options-cb.c
perl/Git.pm
pretty.c
refs.c
refs/files-backend.c
remote.c
send-pack.c
sha1_file.c
submodule.c
t/README
t/perf/p5550-fetch-tags.sh [new file with mode: 0755]
t/t0040-parse-options.sh
t/t1503-rev-parse-verify.sh
t/t2025-worktree-add.sh
t/t3700-add.sh
t/t6010-merge-base.sh
t/t9000/test.pl
t/t9001-send-email.sh
t/test-lib.sh
trailer.c
worktree.c
wt-status.c
index 37a1e1fb6d48935aa22a384797ce82a39340b2ed..9a65514d829987eb8a0274c12f094381d90e87be 100644 (file)
@@ -31,7 +31,7 @@ env:
     - LINUX_GIT_LFS_VERSION="1.2.0"
     - DEFAULT_TEST_TARGET=prove
     - GIT_PROVE_OPTS="--timer --jobs 3 --state=failed,slow,save"
-    - GIT_TEST_OPTS="--verbose --tee"
+    - GIT_TEST_OPTS="--verbose-log"
     - GIT_TEST_HTTPD=true
     - GIT_TEST_CLONE_2GB=YesPlease
     # t9810 occasionally fails on Travis CI OS X
index ed2de0dc20098441e67d069aeac81bb7e5f33860..c4d4397023de1360b77e7c91dc9316eb16973465 100644 (file)
@@ -41,5 +41,71 @@ Fixes since v2.10.1
    that were detected without dying itself, but under some conditions
    it didn't and died instead, which has been fixed.
 
+ * When "git fetch" tries to find where the history of the repository
+   it runs in has diverged from what the other side has, it has a
+   mechanism to avoid digging too deep into irrelevant side branches.
+   This however did not work well over the "smart-http" transport due
+   to a design bug, which has been fixed.
+
+ * When we started cURL to talk to imap server when a new enough
+   version of cURL library is available, we forgot to explicitly add
+   imap(s):// before the destination.  To some folks, that didn't work
+   and the library tried to make HTTP(s) requests instead.
+
+ * The ./configure script generated from configure.ac was taught how
+   to detect support of SSL by libcurl better.
+
+ * http.emptyauth configuration is a way to allow an empty username to
+   pass when attempting to authenticate using mechanisms like
+   Kerberos.  We took an unspecified (NULL) username and sent ":"
+   (i.e. no username, no password) to CURLOPT_USERPWD, but did not do
+   the same when the username is explicitly set to an empty string.
+
+ * "git clone" of a local repository can be done at the filesystem
+   level, but the codepath did not check errors while copying and
+   adjusting the file that lists alternate object stores.
+
+ * Documentation for "git commit" was updated to clarify that "commit
+   -p <paths>" adds to the current contents of the index to come up
+   with what to commit.
+
+ * A stray symbolic link in $GIT_DIR/refs/ directory could make name
+   resolution loop forever, which has been corrected.
+
+ * The "submodule.<name>.path" stored in .gitmodules is never copied
+   to .git/config and such a key in .git/config has no meaning, but
+   the documentation described it and submodule.<name>.url next to
+   each other as if both belong to .git/config.  This has been fixed.
+
+ * Recent git allows submodule.<name>.branch to use a special token
+   "." instead of the branch name; the documentation has been updated
+   to describe it.
+
+ * In a worktree connected to a repository elsewhere, created via "git
+   worktree", "git checkout" attempts to protect users from confusion
+   by refusing to check out a branch that is already checked out in
+   another worktree.  However, this also prevented checking out a
+   branch, which is designated as the primary branch of a bare
+   reopsitory, in a worktree that is connected to the bare
+   repository.  The check has been corrected to allow it.
+
+ * "git rebase" immediately after "git clone" failed to find the fork
+   point from the upstream.
+
+ * When fetching from a remote that has many tags that are irrelevant
+   to branches we are following, we used to waste way too many cycles
+   when checking if the object pointed at by a tag (that we are not
+   going to fetch!) exists in our repository too carefully.
+
+ * The Travis CI configuration we ship ran the tests with --verbose
+   option but this risks non-TAP output that happens to be "ok" to be
+   misinterpreted as TAP signalling a test that passed.  This resulted
+   in unnecessary failure.  This has been corrected by introducing a
+   new mode to run our tests in the test harness to send the verbose
+   output separately to the log file.
+
+ * Some AsciiDoc formatter mishandles a displayed illustration with
+   tabs in it.  Adjust a few of them in merge-base documentation to
+   work around them.
 
 Also contains minor documentation updates and code clean-ups.
index a077c64ef0a142c8fc61755e0e1274283fcb9425..21fdddf24001c020061ed33c759b2eacde8d7c30 100644 (file)
@@ -2805,12 +2805,13 @@ stash.showStat::
        option will show diffstat of the stash.  Defaults to true.
        See description of 'show' command in linkgit:git-stash[1].
 
-submodule.<name>.path::
 submodule.<name>.url::
-       The path within this project and URL for a submodule. These
-       variables are initially populated by 'git submodule init'. See
-       linkgit:git-submodule[1] and linkgit:gitmodules[5] for
-       details.
+       The URL for a submodule. This variable is copied from the .gitmodules
+       file to the git config via 'git submodule init'. The user can change
+       the configured URL before obtaining the submodule via 'git submodule
+       update'. After obtaining the submodule, the presence of this variable
+       is used as a sign whether the submodule is of interest to git commands.
+       See linkgit:git-submodule[1] and linkgit:gitmodules[5] for details.
 
 submodule.<name>.update::
        The default update procedure for a submodule. This variable
index b0a294d3b5e13b853f6c2c60201c2458788d4f00..f2ab0ee2e7d1ff0f79c09cbd27e745f5f08d139d 100644 (file)
@@ -29,7 +29,8 @@ The content to be added can be specified in several ways:
 2. by using 'git rm' to remove files from the working tree
    and the index, again before using the 'commit' command;
 
-3. by listing files as arguments to the 'commit' command, in which
+3. by listing files as arguments to the 'commit' command
+   (without --interactive or --patch switch), in which
    case the commit will ignore changes staged in the index, and instead
    record the current content of the listed files (which must already
    be known to Git);
@@ -41,7 +42,8 @@ The content to be added can be specified in several ways:
    actual commit;
 
 5. by using the --interactive or --patch switches with the 'commit' command
-   to decide one by one which files or hunks should be part of the commit,
+   to decide one by one which files or hunks should be part of the commit
+   in addition to contents in the index,
    before finalizing the operation. See the ``Interactive Mode'' section of
    linkgit:git-add[1] to learn how to operate these modes.
 
index 808426faac5b9b607810777a718113e77b836715..b968b64c380b4fbe2663da42355fc9e8fdd24679 100644 (file)
@@ -80,8 +80,8 @@ which is reachable from both 'A' and 'B' through the parent relationship.
 
 For example, with this topology:
 
-                o---o---o---B
-               /
+                o---o---o---B
+               /
        ---o---1---o---o---o---A
 
 the merge base between 'A' and 'B' is '1'.
@@ -116,11 +116,11 @@ the best common ancestor of all commits.
 When the history involves criss-cross merges, there can be more than one
 'best' common ancestor for two commits.  For example, with this topology:
 
-       ---1---o---A
-          \ /
-           X
-          / \
-       ---2---o---o---B
+       ---1---o---A
+           \ /
+            X
+           / \
+       ---2---o---o---B
 
 both '1' and '2' are merge-bases of A and B.  Neither one is better than
 the other (both are 'best' merge bases).  When the `--all` option is not given,
@@ -154,13 +154,13 @@ topic origin/master`, the history of remote-tracking branch
 `origin/master` may have been rewound and rebuilt, leading to a
 history of this shape:
 
-                        o---B1
-                       /
+                        o---B1
+                       /
        ---o---o---B2--o---o---o---B (origin/master)
-               \
-                B3
-                 \
-                  Derived (topic)
+               \
+                B3
+                 \
+                  Derived (topic)
 
 where `origin/master` used to point at commits B3, B2, B1 and now it
 points at B, and your `topic` branch was started on top of it back
index bf3bb372ee51397b362266d275cd557781585861..d8415734753e0d03f3f6d37bd4b76369d37f5fb0 100644 (file)
@@ -259,7 +259,9 @@ OPTIONS
 --branch::
        Branch of repository to add as submodule.
        The name of the branch is recorded as `submodule.<name>.branch` in
-       `.gitmodules` for `update --remote`.
+       `.gitmodules` for `update --remote`.  A special value of `.` is used to
+       indicate that the name of the branch in the submodule should be the
+       same name as the current branch in the current repository.
 
 -f::
 --force::
index 7ecca8e247c57befb08050b66dc07bb9fba9a890..80019c584b11b35b2b14da83a31f326634bc6708 100644 (file)
@@ -253,9 +253,8 @@ On Automatic following
 ~~~~~~~~~~~~~~~~~~~~~~
 
 If you are following somebody else's tree, you are most likely
-using remote-tracking branches (`refs/heads/origin` in traditional
-layout, or `refs/remotes/origin/master` in the separate-remote
-layout).  You usually want the tags from the other end.
+using remote-tracking branches (eg. `refs/remotes/origin/master`).
+You usually want the tags from the other end.
 
 On the other hand, if you are fetching because you would want a
 one-shot merge from somebody else, you typically do not want to
index b8bec711f47918ad3dc7e05d318525819f3a51ab..ed717e4336060e06ccf698c515cf9be5f85bae2c 100644 (file)
@@ -43,9 +43,10 @@ unreleased) version of Git, that is available from the 'master'
 branch of the `git.git` repository.
 Documentation for older releases are available here:
 
-* link:v2.10.1/git.html[documentation for release 2.10.1]
+* link:v2.10.2/git.html[documentation for release 2.10.2]
 
 * release notes for
+  link:RelNotes/2.10.2.txt[2.10.2],
   link:RelNotes/2.10.1.txt[2.10.1],
   link:RelNotes/2.10.0.txt[2.10].
 
index 10dcc08ff9977ecd0803915aade4b58a27495bbf..8f7c50f330f36f625951db7f4cc4657a31fa7113 100644 (file)
@@ -50,8 +50,11 @@ submodule.<name>.update::
 
 submodule.<name>.branch::
        A remote branch name for tracking updates in the upstream submodule.
-       If the option is not specified, it defaults to 'master'.  See the
-       `--remote` documentation in linkgit:git-submodule[1] for details.
+       If the option is not specified, it defaults to 'master'.  A special
+       value of `.` is used to indicate that the name of the branch in the
+       submodule should be the same name as the current branch in the
+       current repository.  See the `--remote` documentation in
+       linkgit:git-submodule[1] for details.
 
 submodule.<name>.fetchRecurseSubmodules::
        This option can be used to control recursive fetching of this
index 462255ed5d8053cbb4dadeec224cb81d14c4ada6..19f59cc88808a1751296af80a0b9700ccec54396 100644 (file)
@@ -30,7 +30,7 @@ The history immediately after the "revert of the merge" would look like
 this:
 
  ---o---o---o---M---x---x---W
-              /
+               /
        ---A---B
 
 where A and B are on the side development that was not so good, M is the
@@ -47,7 +47,7 @@ After the developers of the side branch fix their mistakes, the history
 may look like this:
 
  ---o---o---o---M---x---x---W---x
-              /
+               /
        ---A---B-------------------C---D
 
 where C and D are to fix what was broken in A and B, and you may already
@@ -81,7 +81,7 @@ In such a situation, you would want to first revert the previous revert,
 which would make the history look like this:
 
  ---o---o---o---M---x---x---W---x---Y
-              /
+               /
        ---A---B-------------------C---D
 
 where Y is the revert of W.  Such a "revert of the revert" can be done
@@ -93,14 +93,14 @@ This history would (ignoring possible conflicts between what W and W..Y
 changed) be equivalent to not having W or Y at all in the history:
 
  ---o---o---o---M---x---x-------x----
-              /
+               /
        ---A---B-------------------C---D
 
 and merging the side branch again will not have conflict arising from an
 earlier revert and revert of the revert.
 
  ---o---o---o---M---x---x-------x-------*
-              /                       /
+               /                       /
        ---A---B-------------------C---D
 
 Of course the changes made in C and D still can conflict with what was
@@ -111,13 +111,13 @@ faulty A and B, and redone the changes on top of the updated mainline
 after the revert, the history would have looked like this:
 
  ---o---o---o---M---x---x---W---x---x
-              /                 \
+               /                 \
        ---A---B                   A'--B'--C'
 
 If you reverted the revert in such a case as in the previous example:
 
  ---o---o---o---M---x---x---W---x---x---Y---*
-              /                 \         /
+               /                 \         /
        ---A---B                   A'--B'--C'
 
 where Y is the revert of W, A' and B' are rerolled A and B, and there may
@@ -129,7 +129,7 @@ lot of overlapping changes that result in conflicts.  So do not do "revert
 of revert" blindly without thinking..
 
  ---o---o---o---M---x---x---W---x---x
-              /                 \
+               /                 \
        ---A---B                   A'--B'--C'
 
 In the history with rebased side branch, W (and M) are behind the merge
index a942d57f73a8502903b888d65d09a677816a5f0f..69c289dd0cdb2b344b7051d25c4889b824e21f9c 100644 (file)
@@ -166,7 +166,8 @@ endif::git-rev-list[]
 - '%Cgreen': switch color to green
 - '%Cblue': switch color to blue
 - '%Creset': reset color
-- '%C(...)': color specification, as described in color.branch.* config option;
+- '%C(...)': color specification, as described under Values in the
+  "CONFIGURATION FILE" section of linkgit:git-config[1];
   adding `auto,` at the beginning will emit color only when colors are
   enabled for log output (by `color.diff`, `color.ui`, or `--color`, and
   respecting the `auto` settings of the former if we are going to a
index 7d5c4771b4b3ef1af6cbde504c149a06ce173378..153c17c34ab98f04e76fc3b91c9673e1152606ca 100755 (executable)
@@ -1,7 +1,7 @@
 #!/bin/sh
 
 GVF=GIT-VERSION-FILE
-DEF_VER=v2.10.1
+DEF_VER=v2.10.2
 
 LF='
 '
index 7a36af86659b549fb32a18c9d364936437fccc9e..ddd1bdfc2de8a383f9bd625de6e5c26cb6f62237 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -462,6 +462,7 @@ CURL_CONFIG = curl-config
 PTHREAD_LIBS = -lpthread
 PTHREAD_CFLAGS =
 GCOV = gcov
+SPATCH = spatch
 
 export TCL_PATH TCLTK_PATH
 
@@ -2308,6 +2309,18 @@ check: common-cmds.h
                exit 1; \
        fi
 
+C_SOURCES = $(patsubst %.o,%.c,$(C_OBJ))
+%.cocci.patch: %.cocci $(C_SOURCES)
+       @echo '    ' SPATCH $<; \
+       for f in $(C_SOURCES); do \
+               $(SPATCH) --sp-file $< $$f; \
+       done >$@ 2>$@.log; \
+       if test -s $@; \
+       then \
+               echo '    ' SPATCH result: $@; \
+       fi
+coccicheck: $(patsubst %.cocci,%.cocci.patch,$(wildcard contrib/coccinelle/*.cocci))
+
 ### Installation rules
 
 ifneq ($(filter /%,$(firstword $(template_dir))),)
@@ -2499,6 +2512,7 @@ clean: profile-clean coverage-clean
        $(RM) -r $(GIT_TARNAME) .doc-tmp-dir
        $(RM) $(GIT_TARNAME).tar.gz git-core_$(GIT_VERSION)-*.tar.gz
        $(RM) $(htmldocs).tar.gz $(manpages).tar.gz
+       $(RM) contrib/coccinelle/*.cocci.patch*
        $(MAKE) -C Documentation/ clean
 ifndef NO_PERL
        $(MAKE) -C gitweb clean
index 9e2ae5cba40ece7fa8c489a18ba610ab2f4f6e2f..9daeb27225c04c28e33adc7b8e9071d825a490de 100644 (file)
@@ -28,6 +28,7 @@
 #include "rerere.h"
 #include "prompt.h"
 #include "mailinfo.h"
+#include "string-list.h"
 
 /**
  * Returns 1 if the file is empty or does not exist, 0 otherwise.
@@ -258,38 +259,29 @@ static int read_state_file(struct strbuf *sb, const struct am_state *state,
 }
 
 /**
- * Reads a KEY=VALUE shell variable assignment from `fp`, returning the VALUE
- * as a newly-allocated string. VALUE must be a quoted string, and the KEY must
- * match `key`. Returns NULL on failure.
- *
- * This is used by read_author_script() to read the GIT_AUTHOR_* variables from
- * the author-script.
+ * Take a series of KEY='VALUE' lines where VALUE part is
+ * sq-quoted, and append <KEY, VALUE> at the end of the string list
  */
-static char *read_shell_var(FILE *fp, const char *key)
+static int parse_key_value_squoted(char *buf, struct string_list *list)
 {
-       struct strbuf sb = STRBUF_INIT;
-       const char *str;
-
-       if (strbuf_getline_lf(&sb, fp))
-               goto fail;
-
-       if (!skip_prefix(sb.buf, key, &str))
-               goto fail;
-
-       if (!skip_prefix(str, "=", &str))
-               goto fail;
-
-       strbuf_remove(&sb, 0, str - sb.buf);
-
-       str = sq_dequote(sb.buf);
-       if (!str)
-               goto fail;
-
-       return strbuf_detach(&sb, NULL);
-
-fail:
-       strbuf_release(&sb);
-       return NULL;
+       while (*buf) {
+               struct string_list_item *item;
+               char *np;
+               char *cp = strchr(buf, '=');
+               if (!cp)
+                       return -1;
+               np = strchrnul(cp, '\n');
+               *cp++ = '\0';
+               item = string_list_append(list, buf);
+
+               buf = np + (*np == '\n');
+               *np = '\0';
+               cp = sq_dequote(cp);
+               if (!cp)
+                       return -1;
+               item->util = xstrdup(cp);
+       }
+       return 0;
 }
 
 /**
@@ -311,44 +303,39 @@ static char *read_shell_var(FILE *fp, const char *key)
 static int read_author_script(struct am_state *state)
 {
        const char *filename = am_path(state, "author-script");
-       FILE *fp;
+       struct strbuf buf = STRBUF_INIT;
+       struct string_list kv = STRING_LIST_INIT_DUP;
+       int retval = -1; /* assume failure */
+       int fd;
 
        assert(!state->author_name);
        assert(!state->author_email);
        assert(!state->author_date);
 
-       fp = fopen(filename, "r");
-       if (!fp) {
+       fd = open(filename, O_RDONLY);
+       if (fd < 0) {
                if (errno == ENOENT)
                        return 0;
                die_errno(_("could not open '%s' for reading"), filename);
        }
+       strbuf_read(&buf, fd, 0);
+       close(fd);
+       if (parse_key_value_squoted(buf.buf, &kv))
+               goto finish;
 
-       state->author_name = read_shell_var(fp, "GIT_AUTHOR_NAME");
-       if (!state->author_name) {
-               fclose(fp);
-               return -1;
-       }
-
-       state->author_email = read_shell_var(fp, "GIT_AUTHOR_EMAIL");
-       if (!state->author_email) {
-               fclose(fp);
-               return -1;
-       }
-
-       state->author_date = read_shell_var(fp, "GIT_AUTHOR_DATE");
-       if (!state->author_date) {
-               fclose(fp);
-               return -1;
-       }
-
-       if (fgetc(fp) != EOF) {
-               fclose(fp);
-               return -1;
-       }
-
-       fclose(fp);
-       return 0;
+       if (kv.nr != 3 ||
+           strcmp(kv.items[0].string, "GIT_AUTHOR_NAME") ||
+           strcmp(kv.items[1].string, "GIT_AUTHOR_EMAIL") ||
+           strcmp(kv.items[2].string, "GIT_AUTHOR_DATE"))
+               goto finish;
+       state->author_name = kv.items[0].util;
+       state->author_email = kv.items[1].util;
+       state->author_date = kv.items[2].util;
+       retval = 0;
+finish:
+       string_list_clear(&kv, !!retval);
+       strbuf_release(&buf);
+       return retval;
 }
 
 /**
index f044a8c27f542c94c0b7f2458de1590e0d02fae2..a35d62293a9c84abb1473a1962c7af1540ed5017 100644 (file)
@@ -355,8 +355,11 @@ static void copy_alternates(struct strbuf *src, struct strbuf *dst,
                        continue;
                }
                abs_path = mkpathdup("%s/objects/%s", src_repo, line.buf);
-               normalize_path_copy(abs_path, abs_path);
-               add_to_alternates_file(abs_path);
+               if (!normalize_path_copy(abs_path, abs_path))
+                       add_to_alternates_file(abs_path);
+               else
+                       warning("skipping invalid relative alternate: %s/%s",
+                               src_repo, line.buf);
                free(abs_path);
        }
        strbuf_release(&line);
index 164623bb6f2eb3ffad3eac59b8ec440b9cf60d9c..cd7e3cefe62b98786097de9a6a456589060c7ebd 100644 (file)
@@ -233,9 +233,10 @@ static void find_non_local_tags(struct transport *transport,
                 * as one to ignore by setting util to NULL.
                 */
                if (ends_with(ref->name, "^{}")) {
-                       if (item && !has_object_file(&ref->old_oid) &&
+                       if (item &&
+                           !has_object_file_with_flags(&ref->old_oid, HAS_SHA1_QUICK) &&
                            !will_fetch(head, ref->old_oid.hash) &&
-                           !has_sha1_file(item->util) &&
+                           !has_sha1_file_with_flags(item->util, HAS_SHA1_QUICK) &&
                            !will_fetch(head, item->util))
                                item->util = NULL;
                        item = NULL;
@@ -248,7 +249,8 @@ static void find_non_local_tags(struct transport *transport,
                 * to check if it is a lightweight tag that we want to
                 * fetch.
                 */
-               if (item && !has_sha1_file(item->util) &&
+               if (item &&
+                   !has_sha1_file_with_flags(item->util, HAS_SHA1_QUICK) &&
                    !will_fetch(head, item->util))
                        item->util = NULL;
 
@@ -268,7 +270,8 @@ static void find_non_local_tags(struct transport *transport,
         * We may have a final lightweight tag that needs to be
         * checked to see if it needs fetching.
         */
-       if (item && !has_sha1_file(item->util) &&
+       if (item &&
+           !has_sha1_file_with_flags(item->util, HAS_SHA1_QUICK) &&
            !will_fetch(head, item->util))
                item->util = NULL;
 
index ac84e99f3a6c073409ab7514aacdad7e722c6255..dc2e9e420d6beb47f0e04184dfb7429b6559a789 100644 (file)
@@ -395,7 +395,7 @@ static void shortlog(const char *name,
 
        for (i = 0; i < subjects.nr; i++)
                if (i >= limit)
-                       strbuf_addf(out, "  ...\n");
+                       strbuf_addstr(out, "  ...\n");
                else
                        strbuf_addf(out, "  %s\n", subjects.items[i].string);
 
index c0d1822eb3ad371b9ab0b830aed2cc2741a978bd..b572a37c2611b2a8c20b1db7edac68623d371a38 100644 (file)
@@ -173,6 +173,9 @@ static int handle_fork_point(int argc, const char **argv)
        revs.initial = 1;
        for_each_reflog_ent(refname, collect_one_reflog_ent, &revs);
 
+       if (!revs.nr && !get_sha1(refname, sha1))
+               add_one_commit(sha1, &revs);
+
        for (i = 0; i < revs.nr; i++)
                revs.commit[i]->object.flags &= ~TMP_MARK;
 
index 0ae099f746680e5c2fcc55dff56624da1619f2f1..a8b57c7d9856518fdcd4c3819f0656544eadf022 100644 (file)
@@ -940,7 +940,7 @@ static void write_merge_state(struct commit_list *remoteheads)
 
        strbuf_reset(&buf);
        if (fast_forward == FF_NO)
-               strbuf_addf(&buf, "no-ff");
+               strbuf_addstr(&buf, "no-ff");
        write_file_buf(git_path_merge_mode(), buf.buf, buf.len);
 }
 
index 9020ec66c81de0185244d478e588d4a05c2a4f1d..9400acce070c8870d6aab8b9a4cb361460488fb6 100644 (file)
@@ -24,7 +24,7 @@
 
 static const char * const git_reset_usage[] = {
        N_("git reset [--mixed | --soft | --hard | --merge | --keep] [-q] [<commit>]"),
-       N_("git reset [-q] <tree-ish> [--] <paths>..."),
+       N_("git reset [-q] [<tree-ish>] [--] <paths>..."),
        N_("git reset --patch [<tree-ish>] [--] [<paths>...]"),
        NULL
 };
index e79790f0bdc9f19cb9d9773d1a9bdb10044bbb8d..dbe5699fe688faeec3bdad899f229746b96be57f 100644 (file)
@@ -637,7 +637,7 @@ static int prepare_to_clone_next_submodule(const struct cache_entry *ce,
                if (suc->recursive_prefix)
                        strbuf_addf(&sb, "%s/%s", suc->recursive_prefix, ce->name);
                else
-                       strbuf_addf(&sb, "%s", ce->name);
+                       strbuf_addstr(&sb, ce->name);
                strbuf_addf(out, _("Skipping unmerged submodule %s"), sb.buf);
                strbuf_addch(out, '\n');
                goto cleanup;
@@ -749,8 +749,9 @@ static int update_clone_get_next_task(struct child_process *child,
                ce = suc->failed_clones[index];
                if (!prepare_to_clone_next_submodule(ce, child, suc, err)) {
                        suc->current ++;
-                       strbuf_addf(err, "BUG: submodule considered for cloning,"
-                                   "doesn't need cloning any more?\n");
+                       strbuf_addstr(err, "BUG: submodule considered for "
+                                          "cloning, doesn't need cloning "
+                                          "any more?\n");
                        return 0;
                }
                p = xmalloc(sizeof(*p));
diff --git a/cache.h b/cache.h
index 4cba08ecb1096dfdbcaae0eb82adad4a7825d35d..1ec9021a70083ea40ee21add8ba766ea9b9c5e25 100644 (file)
--- a/cache.h
+++ b/cache.h
@@ -1123,6 +1123,7 @@ static inline int has_sha1_file(const unsigned char *sha1)
 
 /* Same as the above, except for struct object_id. */
 extern int has_object_file(const struct object_id *oid);
+extern int has_object_file_with_flags(const struct object_id *oid, int flags);
 
 /*
  * Return true iff an alternate object database has a loose object
index aa9c91d20d86fad78c6e2f85d281ad417975a189..0b15f04b1089e48f20353cf068d7d37587b8d966 100644 (file)
@@ -528,16 +528,6 @@ AC_CHECK_LIB([curl], [curl_global_init],
 [NO_CURL=],
 [NO_CURL=YesPlease])
 
-if test -z "${NO_CURL}" && test -z "${NO_OPENSSL}"; then
-
-AC_CHECK_LIB([curl], [Curl_ssl_init],
-[NEEDS_SSL_WITH_CURL=YesPlease],
-[NEEDS_SSL_WITH_CURL=])
-
-GIT_CONF_SUBST([NEEDS_SSL_WITH_CURL])
-
-fi
-
 GIT_UNSTASH_FLAGS($CURLDIR)
 
 GIT_CONF_SUBST([NO_CURL])
@@ -550,6 +540,17 @@ AC_CHECK_PROG([CURL_CONFIG], [curl-config],
 
 if test $CURL_CONFIG != no; then
     GIT_CONF_SUBST([CURL_CONFIG])
+    if test -z "${NO_OPENSSL}"; then
+      AC_MSG_CHECKING([if Curl supports SSL])
+      if test $(curl-config --features|grep SSL) = SSL; then
+         NEEDS_SSL_WITH_CURL=YesPlease
+         AC_MSG_RESULT([yes])
+      else
+         NEEDS_SSL_WITH_CURL=
+         AC_MSG_RESULT([no])
+      fi
+      GIT_CONF_SUBST([NEEDS_SSL_WITH_CURL])
+    fi
 fi
 
 fi
@@ -835,9 +836,10 @@ AC_CHECK_TYPE([struct addrinfo],[
 ])
 GIT_CONF_SUBST([NO_IPV6])
 #
-# Define NO_REGEX if you have no or inferior regex support in your C library.
-AC_CACHE_CHECK([whether the platform regex can handle null bytes],
- [ac_cv_c_excellent_regex], [
+# Define NO_REGEX if your C library lacks regex support with REG_STARTEND
+# feature.
+AC_CACHE_CHECK([whether the platform regex supports REG_STARTEND],
+ [ac_cv_c_regex_with_reg_startend], [
 AC_EGREP_CPP(yippeeyeswehaveit,
        AC_LANG_PROGRAM([AC_INCLUDES_DEFAULT
 #include <regex.h>
@@ -846,10 +848,10 @@ AC_EGREP_CPP(yippeeyeswehaveit,
 yippeeyeswehaveit
 #endif
 ]),
-       [ac_cv_c_excellent_regex=yes],
-       [ac_cv_c_excellent_regex=no])
+       [ac_cv_c_regex_with_reg_startend=yes],
+       [ac_cv_c_regex_with_reg_startend=no])
 ])
-if test $ac_cv_c_excellent_regex = yes; then
+if test $ac_cv_c_regex_with_reg_startend = yes; then
        NO_REGEX=
 else
        NO_REGEX=YesPlease
diff --git a/contrib/coccinelle/.gitignore b/contrib/coccinelle/.gitignore
new file mode 100644 (file)
index 0000000..d3f2964
--- /dev/null
@@ -0,0 +1 @@
+*.patch*
diff --git a/contrib/coccinelle/free.cocci b/contrib/coccinelle/free.cocci
new file mode 100644 (file)
index 0000000..e282131
--- /dev/null
@@ -0,0 +1,5 @@
+@@
+expression E;
+@@
+- if (E)
+  free(E);
index 8ccdbb5666cbc89cf85ce90f63d357b86c37bd30..0307624a03fc4c4fd5642d2b4ad853cfba5b6905 100644 (file)
@@ -23,16 +23,16 @@ expression E1;
 + oid_to_hex(E1)
 
 @@
-expression E1;
+expression E1, E2;
 @@
-- sha1_to_hex_r(E1.hash)
-+ oid_to_hex_r(&E1)
+- sha1_to_hex_r(E1, E2.hash)
++ oid_to_hex_r(E1, &E2)
 
 @@
-expression E1;
+expression E1, E2;
 @@
-- sha1_to_hex_r(E1->hash)
-+ oid_to_hex_r(E1)
+- sha1_to_hex_r(E1, E2->hash)
++ oid_to_hex_r(E1, E2)
 
 @@
 expression E1;
diff --git a/contrib/coccinelle/strbuf.cocci b/contrib/coccinelle/strbuf.cocci
new file mode 100644 (file)
index 0000000..63995f2
--- /dev/null
@@ -0,0 +1,40 @@
+@ 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 @
+@@
+- strbuf_addf
++ strbuf_addstr
+  (E,
+(
+  fmt
+|
+  _(fmt)
+)
+  );
+
+@@
+expression E1, E2;
+@@
+- strbuf_addf(E1, "%s", E2);
++ strbuf_addstr(E1, E2);
+
+@@
+expression E1, E2, E3;
+@@
+- strbuf_addstr(E1, find_unique_abbrev(E2, E3));
++ strbuf_add_unique_abbrev(E1, E2, E3);
diff --git a/contrib/coccinelle/xstrdup_or_null.cocci b/contrib/coccinelle/xstrdup_or_null.cocci
new file mode 100644 (file)
index 0000000..3fceef1
--- /dev/null
@@ -0,0 +1,7 @@
+@@
+expression E;
+expression V;
+@@
+- if (E)
+-    V = xstrdup(E);
++ V = xstrdup_or_null(E);
index 9c8f7380d0f1ad76f0163209e5005adfe46ec916..21016bf8dfe87572fb53a05488ba05bb3c08ed97 100644 (file)
@@ -338,7 +338,7 @@ __git_tags ()
 __git_refs ()
 {
        local i hash dir="$(__gitdir "${1-}")" track="${2-}"
-       local format refs
+       local format refs pfx
        if [ -d "$dir" ]; then
                case "$cur" in
                refs|refs/*)
@@ -347,14 +347,15 @@ __git_refs ()
                        track=""
                        ;;
                *)
+                       [[ "$cur" == ^* ]] && pfx="^"
                        for i in HEAD FETCH_HEAD ORIG_HEAD MERGE_HEAD; do
-                               if [ -e "$dir/$i" ]; then echo $i; fi
+                               if [ -e "$dir/$i" ]; then echo $pfx$i; fi
                        done
                        format="refname:short"
                        refs="refs/tags refs/heads refs/remotes"
                        ;;
                esac
-               git --git-dir="$dir" for-each-ref --format="%($format)" \
+               git --git-dir="$dir" for-each-ref --format="$pfx%($format)" \
                        $refs
                if [ -n "$track" ]; then
                        # employ the heuristic used by git checkout
diff --git a/diff.c b/diff.c
index 7a4309397cb7fd6819d6f643b259c2bc3abe202f..fe6f59160fd70a6dc801d3a67c61484dda521fb1 100644 (file)
--- a/diff.c
+++ b/diff.c
@@ -3076,7 +3076,7 @@ static void fill_metainfo(struct strbuf *msg,
                }
                strbuf_addf(msg, "%s%sindex %s..", line_prefix, set,
                            find_unique_abbrev(one->oid.hash, abbrev));
-               strbuf_addstr(msg, find_unique_abbrev(two->oid.hash, abbrev));
+               strbuf_add_unique_abbrev(msg, two->oid.hash, abbrev);
                if (one->mode == two->mode)
                        strbuf_addf(msg, " %06o", one->mode);
                strbuf_addf(msg, "%s\n", reset);
@@ -4089,7 +4089,8 @@ void diff_free_filepair(struct diff_filepair *p)
        free(p);
 }
 
-/* This is different from find_unique_abbrev() in that
+/*
+ * This is different from find_unique_abbrev() in that
  * it stuffs the result with dots for alignment.
  */
 const char *diff_unique_abbrev(const unsigned char *sha1, int len)
@@ -4101,6 +4102,26 @@ const char *diff_unique_abbrev(const unsigned char *sha1, int len)
 
        abbrev = find_unique_abbrev(sha1, len);
        abblen = strlen(abbrev);
+
+       /*
+        * In well-behaved cases, where the abbbreviated result is the
+        * same as the requested length, append three dots after the
+        * abbreviation (hence the whole logic is limited to the case
+        * where abblen < 37); when the actual abbreviated result is a
+        * bit longer than the requested length, we reduce the number
+        * of dots so that they match the well-behaved ones.  However,
+        * if the actual abbreviation is longer than the requested
+        * length by more than three, we give up on aligning, and add
+        * three dots anyway, to indicate that the output is not the
+        * full object name.  Yes, this may be suboptimal, but this
+        * appears only in "diff --raw --abbrev" output and it is not
+        * worth the effort to change it now.  Note that this would
+        * likely to work fine when the automatic sizing of default
+        * abbreviation length is used--we would be fed -1 in "len" in
+        * that case, and will end up always appending three-dots, but
+        * the automatic sizing is supposed to give abblen that ensures
+        * uniqueness across all objects (statistically speaking).
+        */
        if (abblen < 37) {
                static char hex[41];
                if (len < abblen && abblen <= len + 2)
index 85e77af61d05b492d6448fd4ad33abc2c348eaf1..413937e7404d163883d5d0456ebefc4e1504cd87 100644 (file)
@@ -428,10 +428,17 @@ static int find_common(struct fetch_pack_args *args,
                                                const char *hex = sha1_to_hex(result_sha1);
                                                packet_buf_write(&req_buf, "have %s\n", hex);
                                                state_len = req_buf.len;
-                                       }
+                                               /*
+                                                * Reset in_vain because an ack
+                                                * for this commit has not been
+                                                * seen.
+                                                */
+                                               in_vain = 0;
+                                       } else if (!args->stateless_rpc
+                                                  || ack != ACK_common)
+                                               in_vain = 0;
                                        mark_common(commit, 0, 1);
                                        retval = 0;
-                                       in_vain = 0;
                                        got_continue = 1;
                                        if (ack == ACK_ready) {
                                                clear_prio_queue(&rev_list);
index aec8cc98909237a17afde7809372389000a35a7e..b4d9c2aa58d6351f6a8684495d1f019ee368b275 100644 (file)
@@ -848,11 +848,14 @@ static inline void copy_array(void *dst, const void *src, size_t n, size_t size)
  * times, and it must be assignable as an lvalue.
  */
 #define FLEX_ALLOC_MEM(x, flexname, buf, len) do { \
-       (x) = NULL; /* silence -Wuninitialized for offset calculation */ \
-       (x) = xalloc_flex(sizeof(*(x)), (char *)(&((x)->flexname)) - (char *)(x), (buf), (len)); \
+       size_t flex_array_len_ = (len); \
+       (x) = xcalloc(1, st_add3(sizeof(*(x)), flex_array_len_, 1)); \
+       memcpy((void *)(x)->flexname, (buf), flex_array_len_); \
 } while (0)
 #define FLEXPTR_ALLOC_MEM(x, ptrname, buf, len) do { \
-       (x) = xalloc_flex(sizeof(*(x)), sizeof(*(x)), (buf), (len)); \
+       size_t flex_array_len_ = (len); \
+       (x) = xcalloc(1, st_add3(sizeof(*(x)), flex_array_len_, 1)); \
+       memcpy((x) + 1, (buf), flex_array_len_); \
        (x)->ptrname = (void *)((x)+1); \
 } while(0)
 #define FLEX_ALLOC_STR(x, flexname, str) \
@@ -860,14 +863,6 @@ static inline void copy_array(void *dst, const void *src, size_t n, size_t size)
 #define FLEXPTR_ALLOC_STR(x, ptrname, str) \
        FLEXPTR_ALLOC_MEM((x), ptrname, (str), strlen(str))
 
-static inline void *xalloc_flex(size_t base_len, size_t offset,
-                               const void *src, size_t src_len)
-{
-       unsigned char *ret = xcalloc(1, st_add3(base_len, src_len, 1));
-       memcpy(ret + offset, src, src_len);
-       return ret;
-}
-
 static inline char *xstrdup_or_null(const char *str)
 {
        return str ? xstrdup(str) : NULL;
diff --git a/git.c b/git.c
index 0f1937fd0c23da7c316540b8f9a6b05746011506..f914490e149bc10806c78cf47ee82b81b122d84f 100644 (file)
--- a/git.c
+++ b/git.c
@@ -35,8 +35,7 @@ static void save_env_before_alias(void)
        orig_cwd = xgetcwd();
        for (i = 0; i < ARRAY_SIZE(env_names); i++) {
                orig_env[i] = getenv(env_names[i]);
-               if (orig_env[i])
-                       orig_env[i] = xstrdup(orig_env[i]);
+               orig_env[i] = xstrdup_or_null(orig_env[i]);
        }
 }
 
diff --git a/http.c b/http.c
index 82ed54269059c38e1698b7ffc1af0d1000e5bfec..bd0dba23a037bfff48ea88b916c8f5a650c08176 100644 (file)
--- a/http.c
+++ b/http.c
@@ -351,7 +351,7 @@ static int http_options(const char *var, const char *value, void *cb)
 
 static void init_curl_http_auth(CURL *result)
 {
-       if (!http_auth.username) {
+       if (!http_auth.username || !*http_auth.username) {
                if (curl_empty_auth)
                        curl_easy_setopt(result, CURLOPT_USERPWD, ":");
                return;
index 0f5f4760e90de236757924683478c7f25cdb653f..5c7e27a89459a9a63018cc469262c82891c6f7b7 100644 (file)
@@ -1082,10 +1082,8 @@ static struct imap_store *imap_open_store(struct imap_server_conf *srvc, char *f
                        cred.protocol = xstrdup(srvc->use_ssl ? "imaps" : "imap");
                        cred.host = xstrdup(srvc->host);
 
-                       if (srvc->user)
-                               cred.username = xstrdup(srvc->user);
-                       if (srvc->pass)
-                               cred.password = xstrdup(srvc->pass);
+                       cred.username = xstrdup_or_null(srvc->user);
+                       cred.password = xstrdup_or_null(srvc->pass);
 
                        credential_fill(&cred);
 
@@ -1410,6 +1408,7 @@ static CURL *setup_curl(struct imap_server_conf *srvc)
        curl_easy_setopt(curl, CURLOPT_USERNAME, server.user);
        curl_easy_setopt(curl, CURLOPT_PASSWORD, server.pass);
 
+       strbuf_addstr(&path, server.use_ssl ? "imaps://" : "imap://");
        strbuf_addstr(&path, server.host);
        if (!path.len || path.buf[path.len - 1] != '/')
                strbuf_addch(&path, '/');
index b5c521fdea8b0bfc577795b172010dfc2b8bf8ff..c1a79c100c9a71083a58401081fb2929420ce361 100644 (file)
--- a/mailmap.c
+++ b/mailmap.c
@@ -103,10 +103,8 @@ static void add_mapping(struct string_list *map,
        } else {
                struct mailmap_info *mi = xcalloc(1, sizeof(struct mailmap_info));
                debug_mm("mailmap: adding (complex) entry for '%s'\n", old_email);
-               if (new_name)
-                       mi->name = xstrdup(new_name);
-               if (new_email)
-                       mi->email = xstrdup(new_email);
+               mi->name = xstrdup_or_null(new_name);
+               mi->email = xstrdup_or_null(new_email);
                string_list_insert(&me->namemap, old_name)->util = mi;
        }
 
index e34912683ca106524616673f96fff538af8447ed..aa92e30f639027b5e4a661d3691493be5713f631 100644 (file)
@@ -202,11 +202,11 @@ static void output_commit_title(struct merge_options *o, struct commit *commit)
                strbuf_addf(&o->obuf, "virtual %s\n",
                        merge_remote_util(commit)->name);
        else {
-               strbuf_addf(&o->obuf, "%s ",
-                       find_unique_abbrev(commit->object.oid.hash,
-                               DEFAULT_ABBREV));
+               strbuf_add_unique_abbrev(&o->obuf, commit->object.oid.hash,
+                                        DEFAULT_ABBREV);
+               strbuf_addch(&o->obuf, ' ');
                if (parse_commit(commit) != 0)
-                       strbuf_addf(&o->obuf, _("(bad commit)\n"));
+                       strbuf_addstr(&o->obuf, _("(bad commit)\n"));
                else {
                        const char *title;
                        const char *msg = get_commit_buffer(commit, NULL);
index 9667bc75a08e8b64290f5f44c92b0bac35d1d0fa..16818830e97e099286f3aa259378de1b8e9fc322 100644 (file)
@@ -199,8 +199,7 @@ int parse_opt_passthru(const struct option *opt, const char *arg, int unset)
        if (recreate_opt(&sb, opt, arg, unset) < 0)
                return -1;
 
-       if (*opt_value)
-               free(*opt_value);
+       free(*opt_value);
 
        *opt_value = strbuf_detach(&sb, NULL);
 
index ce7e4e8da3947bb2c527c49d6d09e1e49b0392c3..864123fe8e61f7469b58fef06a04edeb561edd53 100644 (file)
@@ -871,6 +871,8 @@ sub ident_person {
 
 =cut
 
+# Very close to Mail::Address's parser, but we still have minor
+# differences in some cases (see t9000 for examples).
 sub parse_mailboxes {
        my $re_comment = qr/\((?:[^)]*)\)/;
        my $re_quote = qr/"(?:[^\"\\]|\\.)*"/;
@@ -879,6 +881,7 @@ sub parse_mailboxes {
        # divide the string in tokens of the above form
        my $re_token = qr/(?:$re_quote|$re_word|$re_comment|\S)/;
        my @tokens = map { $_ =~ /\s*($re_token)\s*/g } @_;
+       my $end_of_addr_seen = 0;
 
        # add a delimiter to simplify treatment for the last mailbox
        push @tokens, ",";
@@ -888,10 +891,10 @@ sub parse_mailboxes {
                if ($token =~ /^[,;]$/) {
                        # if buffer still contains undeterminated strings
                        # append it at the end of @address or @phrase
-                       if (@address) {
-                               push @address, @buffer;
-                       } else {
+                       if ($end_of_addr_seen) {
                                push @phrase, @buffer;
+                       } else {
+                               push @address, @buffer;
                        }
 
                        my $str_phrase = join ' ', @phrase;
@@ -915,16 +918,16 @@ sub parse_mailboxes {
                        push @addr_list, $str_mailbox if ($str_mailbox);
 
                        @phrase = @address = @comment = @buffer = ();
+                       $end_of_addr_seen = 0;
                } elsif ($token =~ /^\(/) {
                        push @comment, $token;
                } elsif ($token eq "<") {
                        push @phrase, (splice @address), (splice @buffer);
                } elsif ($token eq ">") {
+                       $end_of_addr_seen = 1;
                        push @address, (splice @buffer);
-               } elsif ($token eq "@") {
+               } elsif ($token eq "@" && !$end_of_addr_seen) {
                        push @address, (splice @buffer), "@";
-               } elsif ($token eq ".") {
-                       push @address, (splice @buffer), ".";
                } else {
                        push @buffer, $token;
                }
index 9788bd8f3f0ece03a6b87778a2d43bfaf3c14a9d..0c3149524059bd46c3c6d70bd774df0aaa65f976 100644 (file)
--- a/pretty.c
+++ b/pretty.c
@@ -544,15 +544,13 @@ static void add_merge_info(const struct pretty_print_context *pp,
        strbuf_addstr(sb, "Merge:");
 
        while (parent) {
-               struct commit *p = parent->item;
-               const char *hex = NULL;
+               struct object_id *oidp = &parent->item->object.oid;
+               strbuf_addch(sb, ' ');
                if (pp->abbrev)
-                       hex = find_unique_abbrev(p->object.oid.hash, pp->abbrev);
-               if (!hex)
-                       hex = oid_to_hex(&p->object.oid);
+                       strbuf_add_unique_abbrev(sb, oidp->hash, pp->abbrev);
+               else
+                       strbuf_addstr(sb, oid_to_hex(oidp));
                parent = parent->next;
-
-               strbuf_addf(sb, " %s", hex);
        }
        strbuf_addch(sb, '\n');
 }
@@ -1072,6 +1070,8 @@ static size_t format_commit_one(struct strbuf *sb, /* in UTF-8 */
        case 'C':
                if (starts_with(placeholder + 1, "(auto)")) {
                        c->auto_color = want_color(c->pretty_ctx->color);
+                       if (c->auto_color && sb->len)
+                               strbuf_addstr(sb, GIT_COLOR_RESET);
                        return 7; /* consumed 7 bytes, "C(auto)" */
                } else {
                        int ret = parse_color(sb, placeholder, c);
diff --git a/refs.c b/refs.c
index b4e7cac7b26d0903c4ab7361430c38232c1d5e82..62055ab09103acd8301ce8c70e7d903da3fc9439 100644 (file)
--- a/refs.c
+++ b/refs.c
@@ -791,8 +791,7 @@ struct ref_update *ref_transaction_add_update(
                hashcpy(update->new_sha1, new_sha1);
        if (flags & REF_HAVE_OLD)
                hashcpy(update->old_sha1, old_sha1);
-       if (msg)
-               update->msg = xstrdup(msg);
+       update->msg = xstrdup_or_null(msg);
        return update;
 }
 
index 12290d249643b5aaab18961ca91637910d0d7261..2455564352e1dafd5a95cd25b7279ead69b24660 100644 (file)
@@ -1451,6 +1451,7 @@ int read_raw_ref(const char *refname, unsigned char *sha1,
        int fd;
        int ret = -1;
        int save_errno;
+       int remaining_retries = 3;
 
        *type = 0;
        strbuf_reset(&sb_path);
@@ -1466,8 +1467,14 @@ int read_raw_ref(const char *refname, unsigned char *sha1,
         * <-> symlink) between the lstat() and reading, then
         * we don't want to report that as an error but rather
         * try again starting with the lstat().
+        *
+        * We'll keep a count of the retries, though, just to avoid
+        * any confusing situation sending us into an infinite loop.
         */
 
+       if (remaining_retries-- <= 0)
+               goto out;
+
        if (lstat(path, &st) < 0) {
                if (errno != ENOENT)
                        goto out;
@@ -1496,6 +1503,11 @@ int read_raw_ref(const char *refname, unsigned char *sha1,
                        ret = 0;
                        goto out;
                }
+               /*
+                * It doesn't look like a refname; fall through to just
+                * treating it like a non-symlink, and reading whatever it
+                * points to.
+                */
        }
 
        /* Is it a directory? */
@@ -1519,7 +1531,7 @@ int read_raw_ref(const char *refname, unsigned char *sha1,
         */
        fd = open(path, O_RDONLY);
        if (fd < 0) {
-               if (errno == ENOENT)
+               if (errno == ENOENT && !S_ISLNK(st.st_mode))
                        /* inconsistent with lstat; retry */
                        goto stat_ref;
                else
index d29850a81cdb09b41da5dc3e7284106672d85a4c..ad6c5424edab2ae15ac17bfcf12ac4ee93b5aa3f 100644 (file)
--- a/remote.c
+++ b/remote.c
@@ -2073,7 +2073,7 @@ int format_tracking_info(struct branch *branch, struct strbuf *sb)
                        _("Your branch is based on '%s', but the upstream is gone.\n"),
                        base);
                if (advice_status_hints)
-                       strbuf_addf(sb,
+                       strbuf_addstr(sb,
                                _("  (use \"git branch --unset-upstream\" to fixup)\n"));
        } else if (!ours && !theirs) {
                strbuf_addf(sb,
@@ -2086,7 +2086,7 @@ int format_tracking_info(struct branch *branch, struct strbuf *sb)
                           ours),
                        base, ours);
                if (advice_status_hints)
-                       strbuf_addf(sb,
+                       strbuf_addstr(sb,
                                _("  (use \"git push\" to publish your local commits)\n"));
        } else if (!ours) {
                strbuf_addf(sb,
@@ -2097,7 +2097,7 @@ int format_tracking_info(struct branch *branch, struct strbuf *sb)
                           theirs),
                        base, theirs);
                if (advice_status_hints)
-                       strbuf_addf(sb,
+                       strbuf_addstr(sb,
                                _("  (use \"git pull\" to update your local branch)\n"));
        } else {
                strbuf_addf(sb,
@@ -2110,7 +2110,7 @@ int format_tracking_info(struct branch *branch, struct strbuf *sb)
                           ours + theirs),
                        base, ours, theirs);
                if (advice_status_hints)
-                       strbuf_addf(sb,
+                       strbuf_addstr(sb,
                                _("  (use \"git pull\" to merge the remote branch into yours)\n"));
        }
        free(base);
index 90f2ac51a741f14cecab51177120cc7c3f063096..6195b43e9abacf346f52b6bbb758c9ca7b617d4e 100644 (file)
@@ -181,8 +181,7 @@ static int receive_status(int in, struct ref *refs)
                        hint->status = REF_STATUS_REMOTE_REJECT;
                        ret = -1;
                }
-               if (msg)
-                       hint->remote_status = xstrdup(msg);
+               hint->remote_status = xstrdup_or_null(msg);
                /* start our next search from the next ref */
                hint = hint->next;
        }
index 7a4f8f8661a94ed9381e1297118c0de9e90c8c97..727a9769fb7549e365e66f4ecb65f8e665898a96 100644 (file)
@@ -3231,6 +3231,11 @@ int has_object_file(const struct object_id *oid)
        return has_sha1_file(oid->hash);
 }
 
+int has_object_file_with_flags(const struct object_id *oid, int flags)
+{
+       return has_sha1_file_with_flags(oid->hash, flags);
+}
+
 static void check_tree(const void *buf, size_t size)
 {
        struct tree_desc desc;
index e8258f061ac5726d8001a5b207886b3191745eaa..9d8d91c207e7a2c09bdf997ba05c67b1262d8091 100644 (file)
@@ -370,11 +370,10 @@ void show_submodule_summary(FILE *f, const char *path,
                return;
        }
 
-       strbuf_addf(&sb, "%s%sSubmodule %s %s..", line_prefix, meta, path,
-                       find_unique_abbrev(one, DEFAULT_ABBREV));
-       if (!fast_backward && !fast_forward)
-               strbuf_addch(&sb, '.');
-       strbuf_addf(&sb, "%s", find_unique_abbrev(two, DEFAULT_ABBREV));
+       strbuf_addf(&sb, "%s%sSubmodule %s ", line_prefix, meta, path);
+       strbuf_add_unique_abbrev(&sb, one, DEFAULT_ABBREV);
+       strbuf_addstr(&sb, (fast_backward || fast_forward) ? ".." : "...");
+       strbuf_add_unique_abbrev(&sb, two, DEFAULT_ABBREV);
        if (message)
                strbuf_addf(&sb, " %s%s\n", message, reset);
        else
index 0f764c0aef7aaa842299abde05effb73a0def9f4..4982d1c5216c10b7d44e66eace34e40d49cb5b2f 100644 (file)
--- a/t/README
+++ b/t/README
@@ -153,6 +153,12 @@ appropriately before running "make".
        As the names depend on the tests' file names, it is safe to
        run the tests with this option in parallel.
 
+--verbose-log::
+       Write verbose output to the same logfile as `--tee`, but do
+       _not_ write it to stdout. Unlike `--tee --verbose`, this option
+       is safe to use when stdout is being consumed by a TAP parser
+       like `prove`. Implies `--tee` and `--verbose`.
+
 --with-dashes::
        By default tests are run without dashed forms of
        commands (like git-commit) in the PATH (it only uses
diff --git a/t/perf/p5550-fetch-tags.sh b/t/perf/p5550-fetch-tags.sh
new file mode 100755 (executable)
index 0000000..a5dc39f
--- /dev/null
@@ -0,0 +1,99 @@
+#!/bin/sh
+
+test_description='performance of tag-following with many tags
+
+This tests a fairly pathological case, so rather than rely on a real-world
+case, we will construct our own repository. The situation is roughly as
+follows.
+
+The parent repository has a large number of tags which are disconnected from
+the rest of history. That makes them candidates for tag-following, but we never
+actually grab them (and thus they will impact each subsequent fetch).
+
+The child repository is a clone of parent, without the tags, and is at least
+one commit behind the parent (meaning that we will fetch one object and then
+examine the tags to see if they need followed). Furthermore, it has a large
+number of packs.
+
+The exact values of "large" here are somewhat arbitrary; I picked values that
+start to show a noticeable performance problem on my machine, but without
+taking too long to set up and run the tests.
+'
+. ./perf-lib.sh
+
+# make a long nonsense history on branch $1, consisting of $2 commits, each
+# with a unique file pointing to the blob at $2.
+create_history () {
+       perl -le '
+               my ($branch, $n, $blob) = @ARGV;
+               for (1..$n) {
+                       print "commit refs/heads/$branch";
+                       print "committer nobody <nobody@example.com> now";
+                       print "data 4";
+                       print "foo";
+                       print "M 100644 $blob $_";
+               }
+       ' "$@" |
+       git fast-import --date-format=now
+}
+
+# make a series of tags, one per commit in the revision range given by $@
+create_tags () {
+       git rev-list "$@" |
+       perl -lne 'print "create refs/tags/$. $_"' |
+       git update-ref --stdin
+}
+
+# create $1 nonsense packs, each with a single blob
+create_packs () {
+       perl -le '
+               my ($n) = @ARGV;
+               for (1..$n) {
+                       print "blob";
+                       print "data <<EOF";
+                       print "$_";
+                       print "EOF";
+               }
+       ' "$@" |
+       git fast-import &&
+
+       git cat-file --batch-all-objects --batch-check='%(objectname)' |
+       while read sha1
+       do
+               echo $sha1 | git pack-objects .git/objects/pack/pack
+       done
+}
+
+test_expect_success 'create parent and child' '
+       git init parent &&
+       git -C parent commit --allow-empty -m base &&
+       git clone parent child &&
+       git -C parent commit --allow-empty -m trigger-fetch
+'
+
+test_expect_success 'populate parent tags' '
+       (
+               cd parent &&
+               blob=$(echo content | git hash-object -w --stdin) &&
+               create_history cruft 3000 $blob &&
+               create_tags cruft &&
+               git branch -D cruft
+       )
+'
+
+test_expect_success 'create child packs' '
+       (
+               cd child &&
+               git config gc.auto 0 &&
+               git config gc.autopacklimit 0 &&
+               create_packs 500
+       )
+'
+
+test_perf 'fetch' '
+       # make sure there is something to fetch on each iteration
+       git -C child update-ref -d refs/remotes/origin/master &&
+       git -C child fetch
+'
+
+test_done
index db5f60d0c5882fc491ca571eb6385554148bbf3a..74d2cd76fe56bf6d6fab5d44834999b55d3220de 100755 (executable)
@@ -208,32 +208,15 @@ test_expect_success 'unambiguously abbreviated option' '
 '
 
 test_expect_success 'unambiguously abbreviated option with "="' '
-       test-parse-options --int=2 >output 2>output.err &&
-       test_must_be_empty output.err &&
-       test_cmp expect output
+       test-parse-options --expect="integer: 2" --int=2
 '
 
 test_expect_success 'ambiguously abbreviated option' '
        test_expect_code 129 test-parse-options --strin 123
 '
 
-cat >expect <<\EOF
-boolean: 0
-integer: 0
-magnitude: 0
-timestamp: 0
-string: 123
-abbrev: 7
-verbose: -1
-quiet: 0
-dry run: no
-file: (not set)
-EOF
-
 test_expect_success 'non ambiguous option (after two options it abbreviates)' '
-       test-parse-options --st 123 >output 2>output.err &&
-       test_must_be_empty output.err &&
-       test_cmp expect output
+       test-parse-options --expect="string: 123" --st 123
 '
 
 cat >typo.err <<\EOF
@@ -256,24 +239,8 @@ test_expect_success 'detect possible typos' '
        test_cmp typo.err output.err
 '
 
-cat >expect <<\EOF
-boolean: 0
-integer: 0
-magnitude: 0
-timestamp: 0
-string: (not set)
-abbrev: 7
-verbose: -1
-quiet: 0
-dry run: no
-file: (not set)
-arg 00: --quux
-EOF
-
 test_expect_success 'keep some options as arguments' '
-       test-parse-options --quux >output 2>output.err &&
-       test_must_be_empty output.err &&
-       test_cmp expect output
+       test-parse-options --expect="arg 00: --quux" --quux
 '
 
 cat >expect <<\EOF
@@ -350,54 +317,20 @@ test_expect_success 'OPT_NEGBIT() and OPT_SET_INT() work' '
        test_cmp expect output
 '
 
-cat >expect <<\EOF
-boolean: 6
-integer: 0
-magnitude: 0
-timestamp: 0
-string: (not set)
-abbrev: 7
-verbose: -1
-quiet: 0
-dry run: no
-file: (not set)
-EOF
-
 test_expect_success 'OPT_BIT() works' '
-       test-parse-options -bb --or4 >output 2>output.err &&
-       test_must_be_empty output.err &&
-       test_cmp expect output
+       test-parse-options --expect="boolean: 6" -bb --or4
 '
 
 test_expect_success 'OPT_NEGBIT() works' '
-       test-parse-options -bb --no-neg-or4 >output 2>output.err &&
-       test_must_be_empty output.err &&
-       test_cmp expect output
+       test-parse-options --expect="boolean: 6" -bb --no-neg-or4
 '
 
 test_expect_success 'OPT_COUNTUP() with PARSE_OPT_NODASH works' '
-       test-parse-options + + + + + + >output 2>output.err &&
-       test_must_be_empty output.err &&
-       test_cmp expect output
+       test-parse-options --expect="boolean: 6" + + + + + +
 '
 
-cat >expect <<\EOF
-boolean: 0
-integer: 12345
-magnitude: 0
-timestamp: 0
-string: (not set)
-abbrev: 7
-verbose: -1
-quiet: 0
-dry run: no
-file: (not set)
-EOF
-
 test_expect_success 'OPT_NUMBER_CALLBACK() works' '
-       test-parse-options -12345 >output 2>output.err &&
-       test_must_be_empty output.err &&
-       test_cmp expect output
+       test-parse-options --expect="integer: 12345" -12345
 '
 
 cat >expect <<\EOF
@@ -435,118 +368,28 @@ test_expect_success '--no-list resets list' '
        test_cmp expect output
 '
 
-cat >expect <<\EOF
-boolean: 0
-integer: 0
-magnitude: 0
-timestamp: 0
-string: (not set)
-abbrev: 7
-verbose: -1
-quiet: 3
-dry run: no
-file: (not set)
-EOF
-
 test_expect_success 'multiple quiet levels' '
-       test-parse-options -q -q -q >output 2>output.err &&
-       test_must_be_empty output.err &&
-       test_cmp expect output
+       test-parse-options --expect="quiet: 3" -q -q -q
 '
 
-cat >expect <<\EOF
-boolean: 0
-integer: 0
-magnitude: 0
-timestamp: 0
-string: (not set)
-abbrev: 7
-verbose: 3
-quiet: 0
-dry run: no
-file: (not set)
-EOF
-
 test_expect_success 'multiple verbose levels' '
-       test-parse-options -v -v -v >output 2>output.err &&
-       test_must_be_empty output.err &&
-       test_cmp expect output
+       test-parse-options --expect="verbose: 3" -v -v -v
 '
 
-cat >expect <<\EOF
-boolean: 0
-integer: 0
-magnitude: 0
-timestamp: 0
-string: (not set)
-abbrev: 7
-verbose: -1
-quiet: 0
-dry run: no
-file: (not set)
-EOF
-
 test_expect_success '--no-quiet sets --quiet to 0' '
-       test-parse-options --no-quiet >output 2>output.err &&
-       test_must_be_empty output.err &&
-       test_cmp expect output
+       test-parse-options --expect="quiet: 0" --no-quiet
 '
 
-cat >expect <<\EOF
-boolean: 0
-integer: 0
-magnitude: 0
-timestamp: 0
-string: (not set)
-abbrev: 7
-verbose: -1
-quiet: 0
-dry run: no
-file: (not set)
-EOF
-
 test_expect_success '--no-quiet resets multiple -q to 0' '
-       test-parse-options -q -q -q --no-quiet >output 2>output.err &&
-       test_must_be_empty output.err &&
-       test_cmp expect output
+       test-parse-options --expect="quiet: 0" -q -q -q --no-quiet
 '
 
-cat >expect <<\EOF
-boolean: 0
-integer: 0
-magnitude: 0
-timestamp: 0
-string: (not set)
-abbrev: 7
-verbose: 0
-quiet: 0
-dry run: no
-file: (not set)
-EOF
-
 test_expect_success '--no-verbose sets verbose to 0' '
-       test-parse-options --no-verbose >output 2>output.err &&
-       test_must_be_empty output.err &&
-       test_cmp expect output
+       test-parse-options --expect="verbose: 0" --no-verbose
 '
 
-cat >expect <<\EOF
-boolean: 0
-integer: 0
-magnitude: 0
-timestamp: 0
-string: (not set)
-abbrev: 7
-verbose: 0
-quiet: 0
-dry run: no
-file: (not set)
-EOF
-
 test_expect_success '--no-verbose resets multiple verbose to 0' '
-       test-parse-options -v -v -v --no-verbose >output 2>output.err &&
-       test_must_be_empty output.err &&
-       test_cmp expect output
+       test-parse-options --expect="verbose: 0" -v -v -v --no-verbose
 '
 
 test_done
index ab27d0db5c5577a23e1053b58eefa63015526d0c..492edffa9cfb626b4747ead04251fc33b0502ac9 100755 (executable)
@@ -139,4 +139,9 @@ test_expect_success 'master@{n} for various n' '
        test_must_fail git rev-parse --verify master@{$Np1}
 '
 
+test_expect_success SYMLINKS 'ref resolution not confused by broken symlinks' '
+       ln -s does-not-exist .git/refs/heads/broken &&
+       test_must_fail git rev-parse --verify broken
+'
+
 test_done
index 4bcc335a19f9d7864560945ed0f430728d0f1986..b618d6be21ff8926cb0d9dff1881c6e5e9eeb35a 100755 (executable)
@@ -138,6 +138,14 @@ test_expect_success 'checkout from a bare repo without "add"' '
        )
 '
 
+test_expect_success '"add" default branch of a bare repo' '
+       (
+               git clone --bare . bare2 &&
+               cd bare2 &&
+               git worktree add ../there3 master
+       )
+'
+
 test_expect_success 'checkout with grafts' '
        test_when_finished rm .git/info/grafts &&
        test_commit abc &&
index 924a26612681817156e54f4c1bc4a89e7cb5e8de..53c0cb6dea686ac872c219b746a0c24b3d505416 100755 (executable)
@@ -350,6 +350,7 @@ test_expect_success POSIXPERM,SYMLINKS 'git add --chmod=+x with symlinks' '
 '
 
 test_expect_success 'git add --chmod=[+-]x changes index with already added file' '
+       rm -f foo3 xfoo3 &&
        echo foo >foo3 &&
        git add foo3 &&
        git add --chmod=+x foo3 &&
index e0c5f44cac0290c6e15c5360b0cc7c1f4d486614..31db7b5f9125ed346450d7bfe29d8bb5fac0460a 100755 (executable)
@@ -260,6 +260,12 @@ test_expect_success 'using reflog to find the fork point' '
        test_cmp expect3 actual
 '
 
+test_expect_success '--fork-point works with empty reflog' '
+       git -c core.logallrefupdates=false branch no-reflog base &&
+       git merge-base --fork-point no-reflog derived &&
+       test_cmp expect3 actual
+'
+
 test_expect_success 'merge-base --octopus --all for complex tree' '
        # Best common ancestor for JE, JAA and JDD is JC
        #             JE
index 2d05d3eeab3f801fcf74a93c9305d067ac628937..dfeaa9c6550eac1f9beeca64682cecfebfe2c7d3 100755 (executable)
        q["Jane\" Doe" <jdoe@example.com>],
        q[Doe, jane <jdoe@example.com>],
        q["Jane Doe <jdoe@example.com>],
-       q['Jane 'Doe' <jdoe@example.com>]);
+       q['Jane 'Doe' <jdoe@example.com>],
+       q[Jane@:;\.,()<>Doe <jdoe@example.com>],
+       q[Jane <jdoe@example.com> Doe],
+       q[<jdoe@example.com> Jane Doe]);
 
 my @known_failure_list = (q[Jane\ Doe <jdoe@example.com>],
        q["Doe, Ja"ne <jdoe@example.com>],
        q["Doe, Katarina" Jane <jdoe@example.com>],
-       q[Jane@:;\.,()<>Doe <jdoe@example.com>],
        q[Jane jdoe@example.com],
-       q[<jdoe@example.com> Jane Doe],
-       q[Jane <jdoe@example.com> Doe],
        q["Jane "Kat"a" ri"na" ",Doe" <jdoe@example.com>],
        q[Jane Doe],
        q[Jane "Doe <jdoe@example.com>"],
index b3355d2c7016e55e99a465414f230569c3807230..3dc4a3454d223d37e85de6fa4ae8656046370e99 100755 (executable)
@@ -140,6 +140,35 @@ test_expect_success $PREREQ 'Verify commandline' '
        test_cmp expected commandline1
 '
 
+test_expect_success $PREREQ 'setup expect for cc trailer' "
+cat >expected-cc <<\EOF
+!recipient@example.com!
+!author@example.com!
+!one@example.com!
+!two@example.com!
+!three@example.com!
+!four@example.com!
+!five@example.com!
+EOF
+"
+
+test_expect_success $PREREQ 'cc trailer with various syntax' '
+       test_commit cc-trailer &&
+       test_when_finished "git reset --hard HEAD^" &&
+       git commit --amend -F - <<-EOF &&
+       Test Cc: trailers.
+
+       Cc: one@example.com
+       Cc: <two@example.com> # this is part of the name
+       Cc: <three@example.com>, <four@example.com> # not.five@example.com
+       Cc: "Some # Body" <five@example.com> [part.of.name.too]
+       EOF
+       clean_fake_sendmail &&
+       git send-email -1 --to=recipient@example.com \
+               --smtp-server="$(pwd)/fake.sendmail" &&
+       test_cmp expected-cc commandline1
+'
+
 test_expect_success $PREREQ 'setup expect' "
 cat >expected-show-all-headers <<\EOF
 0001-Second.patch
index ac56512a1c5e4fde4af33cedcbb1cab11487d29a..21e4aa2e542a1d7806f33c33e97aa46b104af38d 100644 (file)
@@ -54,12 +54,22 @@ case "$GIT_TEST_TEE_STARTED, $* " in
 done,*)
        # do not redirect again
        ;;
-*' --tee '*|*' --va'*)
+*' --tee '*|*' --va'*|*' --verbose-log '*)
        mkdir -p "$TEST_OUTPUT_DIRECTORY/test-results"
        BASE="$TEST_OUTPUT_DIRECTORY/test-results/$(basename "$0" .sh)"
+
+       # Make this filename available to the sub-process in case it is using
+       # --verbose-log.
+       GIT_TEST_TEE_OUTPUT_FILE=$BASE.out
+       export GIT_TEST_TEE_OUTPUT_FILE
+
+       # Truncate before calling "tee -a" to get rid of the results
+       # from any previous runs.
+       >"$GIT_TEST_TEE_OUTPUT_FILE"
+
        (GIT_TEST_TEE_STARTED=done ${SHELL_PATH} "$0" "$@" 2>&1;
-        echo $? > $BASE.exit) | tee $BASE.out
-       test "$(cat $BASE.exit)" = 0
+        echo $? >"$BASE.exit") | tee -a "$GIT_TEST_TEE_OUTPUT_FILE"
+       test "$(cat "$BASE.exit")" = 0
        exit
        ;;
 esac
@@ -246,6 +256,9 @@ do
                trace=t
                verbose=t
                shift ;;
+       --verbose-log)
+               verbose_log=t
+               shift ;;
        *)
                echo "error: unknown test option '$1'" >&2; exit 1 ;;
        esac
@@ -308,6 +321,16 @@ say () {
        say_color info "$*"
 }
 
+if test -n "$HARNESS_ACTIVE"
+then
+       if test "$verbose" = t || test -n "$verbose_only"
+       then
+               printf 'Bail out! %s\n' \
+                'verbose mode forbidden under TAP harness; try --verbose-log'
+               exit 1
+       fi
+fi
+
 test "${test_description}" != "" ||
 error "Test script did not set test_description."
 
@@ -319,7 +342,10 @@ fi
 
 exec 5>&1
 exec 6<&0
-if test "$verbose" = "t"
+if test "$verbose_log" = "t"
+then
+       exec 3>>"$GIT_TEST_TEE_OUTPUT_FILE" 4>&3
+elif test "$verbose" = "t"
 then
        exec 4>&2 3>&1
 else
index c6ea9ac64d75292021919ad54462a3e4b782b080..aecaf9232a92fcab4996037fc779e0165750fb36 100644 (file)
--- a/trailer.c
+++ b/trailer.c
@@ -428,12 +428,9 @@ static int set_if_missing(struct conf_info *item, const char *value)
 static void duplicate_conf(struct conf_info *dst, struct conf_info *src)
 {
        *dst = *src;
-       if (src->name)
-               dst->name = xstrdup(src->name);
-       if (src->key)
-               dst->key = xstrdup(src->key);
-       if (src->command)
-               dst->command = xstrdup(src->command);
+       dst->name = xstrdup_or_null(src->name);
+       dst->key = xstrdup_or_null(src->key);
+       dst->command = xstrdup_or_null(src->command);
 }
 
 static struct trailer_item *get_conf_item(const char *name)
index 5acfe4cd64967d86462f3958433f3d2f844ead51..f7869f8d6072c98c3e9be3387a9a3c19508e13ea 100644 (file)
@@ -345,6 +345,8 @@ const struct worktree *find_shared_symref(const char *symref,
 
        for (i = 0; worktrees[i]; i++) {
                struct worktree *wt = worktrees[i];
+               if (wt->is_bare)
+                       continue;
 
                if (wt->is_detached && !strcmp(symref, "HEAD")) {
                        if (is_worktree_being_rebased(wt, target)) {
index 6225a2d89f2c38bea6ed64295a28e7e07d19522c..7004a2d588769b76e95c07c8471569b2d6bf6c56 100644 (file)
@@ -367,11 +367,11 @@ static void wt_status_print_change_data(struct wt_status *s,
                if (d->new_submodule_commits || d->dirty_submodule) {
                        strbuf_addstr(&extra, " (");
                        if (d->new_submodule_commits)
-                               strbuf_addf(&extra, _("new commits, "));
+                               strbuf_addstr(&extra, _("new commits, "));
                        if (d->dirty_submodule & DIRTY_SUBMODULE_MODIFIED)
-                               strbuf_addf(&extra, _("modified content, "));
+                               strbuf_addstr(&extra, _("modified content, "));
                        if (d->dirty_submodule & DIRTY_SUBMODULE_UNTRACKED)
-                               strbuf_addf(&extra, _("untracked content, "));
+                               strbuf_addstr(&extra, _("untracked content, "));
                        strbuf_setlen(&extra, extra.len - 2);
                        strbuf_addch(&extra, ')');
                }
@@ -1053,7 +1053,6 @@ static void abbrev_sha1_in_line(struct strbuf *line)
        split = strbuf_split_max(line, ' ', 3);
        if (split[0] && split[1]) {
                unsigned char sha1[20];
-               const char *abbrev;
 
                /*
                 * strbuf_split_max left a space. Trim it and re-add
@@ -1061,9 +1060,10 @@ static void abbrev_sha1_in_line(struct strbuf *line)
                 */
                strbuf_trim(split[1]);
                if (!get_sha1(split[1]->buf, sha1)) {
-                       abbrev = find_unique_abbrev(sha1, DEFAULT_ABBREV);
                        strbuf_reset(split[1]);
-                       strbuf_addf(split[1], "%s ", abbrev);
+                       strbuf_add_unique_abbrev(split[1], sha1,
+                                                DEFAULT_ABBREV);
+                       strbuf_addch(split[1], ' ');
                        strbuf_reset(line);
                        for (i = 0; split[i]; i++)
                                strbuf_addbuf(line, split[i]);
@@ -1286,10 +1286,8 @@ static char *get_branch(const struct worktree *wt, const char *path)
        else if (starts_with(sb.buf, "refs/"))
                ;
        else if (!get_sha1_hex(sb.buf, sha1)) {
-               const char *abbrev;
-               abbrev = find_unique_abbrev(sha1, DEFAULT_ABBREV);
                strbuf_reset(&sb);
-               strbuf_addstr(&sb, abbrev);
+               strbuf_add_unique_abbrev(&sb, sha1, DEFAULT_ABBREV);
        } else if (!strcmp(sb.buf, "detached HEAD")) /* rebase */
                goto got_nothing;
        else                    /* bisect */
@@ -1326,8 +1324,7 @@ static int grab_1st_switch(unsigned char *osha1, unsigned char *nsha1,
        if (!strcmp(cb->buf.buf, "HEAD")) {
                /* HEAD is relative. Resolve it to the right reflog entry. */
                strbuf_reset(&cb->buf);
-               strbuf_addstr(&cb->buf,
-                             find_unique_abbrev(nsha1, DEFAULT_ABBREV));
+               strbuf_add_unique_abbrev(&cb->buf, nsha1, DEFAULT_ABBREV);
        }
        return 1;
 }