Merge branch 'dt/http-range'
authorJunio C Hamano <gitster@pobox.com>
Thu, 5 Nov 2015 23:24:27 +0000 (15:24 -0800)
committerJunio C Hamano <gitster@pobox.com>
Thu, 5 Nov 2015 23:24:27 +0000 (15:24 -0800)
A Range: request can be responded with a full response and when
asked properly libcurl knows how to strip the result down to the
requested range. However, we were hand-crafting a range request
and it did not kick in.

* dt/http-range:
http: use off_t to store partial file size
http.c: use CURLOPT_RANGE for range requests

21 files changed:
Documentation/RelNotes/2.6.3.txt [new file with mode: 0644]
Documentation/RelNotes/2.7.0.txt
Documentation/git.txt
Documentation/technical/api-run-command.txt
builtin/blame.c
builtin/show-branch.c
daemon.c
git-difftool.perl
mailinfo.c
ref-filter.c
run-command.c
run-command.h
submodule.c
t/README
t/t3203-branch-output.sh
t/t7060-wtstatus.sh
t/t7800-difftool.sh
t/t8009-blame-vs-topicbranches.sh [new file with mode: 0755]
t/test-lib-functions.sh
wrap-for-bin.sh
wt-status.c
diff --git a/Documentation/RelNotes/2.6.3.txt b/Documentation/RelNotes/2.6.3.txt
new file mode 100644 (file)
index 0000000..fc6fe17
--- /dev/null
@@ -0,0 +1,111 @@
+Git v2.6.3 Release Notes
+========================
+
+Fixes since v2.6.2
+------------------
+
+ * The error message from "git blame --contents --reverse" incorrectly
+   talked about "--contents --children".
+
+ * "git merge-file" tried to signal how many conflicts it found, which
+   obviously would not work well when there are too many of them.
+
+ * The name-hash subsystem that is used to cope with case insensitive
+   filesystems keeps track of directories and their on-filesystem
+   cases for all the paths in the index by holding a pointer to a
+   randomly chosen cache entry that is inside the directory (for its
+   ce->ce_name component).  This pointer was not updated even when the
+   cache entry was removed from the index, leading to use after free.
+   This was fixed by recording the path for each directory instead of
+   borrowing cache entries and restructuring the API somewhat.
+
+ * When the "git am" command was reimplemented in C, "git am -3" had a
+   small regression where it is aborted in its error handling codepath
+   when underlying merge-recursive failed in some ways.
+
+ * The synopsis text and the usage string of subcommands that read
+   list of things from the standard input are often shown as if they
+   only take input from a file on a filesystem, which was misleading.
+
+ * A couple of commands still showed "[options]" in their usage string
+   to note where options should come on their command line, but we
+   spell that "[<options>]" in most places these days.
+
+ * The submodule code has been taught to work better with separate
+   work trees created via "git worktree add".
+
+ * When "git gc --auto" is backgrounded, its diagnosis message is
+   lost.  It now is saved to a file in $GIT_DIR and is shown next time
+   the "gc --auto" is run.
+
+ * Work around "git p4" failing when the P4 depot records the contents
+   in UTF-16 without UTF-16 BOM.
+
+ * Recent update to "rebase -i" that tries to sanity check the edited
+   insn sheet before it uses it has become too picky on Windows where
+   CRLF left by the editor is turned into a trailing CR on the line
+   read via the "read" built-in command.
+
+ * "git clone --dissociate" runs a big "git repack" process at the
+   end, and it helps to close file descriptors that are open on the
+   packs and their idx files before doing so on filesystems that
+   cannot remove a file that is still open.
+
+ * Correct "git p4 --detect-labels" so that it does not fail to create
+   a tag that points at a commit that is also being imported.
+
+ * The internal stripspace() function has been moved to where it
+   logically belongs to, i.e. strbuf API, and the command line parser
+   of "git stripspace" has been updated to use the parse_options API.
+
+ * Prepare for Git on-disk repository representation to undergo
+   backward incompatible changes by introducing a new repository
+   format version "1", with an extension mechanism.
+
+ * "git gc" used to barf when a symbolic ref has gone dangling
+   (e.g. the branch that used to be your upstream's default when you
+   cloned from it is now gone, and you did "fetch --prune").
+
+ * The normalize_ceiling_entry() function does not muck with the end
+   of the path it accepts, and the real world callers do rely on that,
+   but a test insisted that the function drops a trailing slash.
+
+ * "git gc" is safe to run anytime only because it has the built-in
+   grace period to protect young objects.  In order to run with no
+   grace period, the user must make sure that the repository is
+   quiescent.
+
+ * A recent "filter-branch --msg-filter" broke skipping of the commit
+   object header, which is fixed.
+
+ * "git --literal-pathspecs add -u/-A" without any command line
+   argument misbehaved ever since Git 2.0.
+
+ * Merging a branch that removes a path and another that changes the
+   mode bits on the same path should have conflicted at the path, but
+   it didn't and silently favoured the removal.
+
+ * "git imap-send" did not compile well with older version of cURL library.
+
+ * The linkage order of libraries was wrong in places around libcurl.
+
+ * It was not possible to use a repository-lookalike created by "git
+   worktree add" as a local source of "git clone".
+
+ * When "git send-email" wanted to talk over Net::SMTP::SSL,
+   Net::Cmd::datasend() did not like to be fed too many bytes at the
+   same time and failed to send messages.  Send the payload one line
+   at a time to work around the problem.
+
+ * We peek objects from submodule's object store by linking it to the
+   list of alternate object databases, but the code to do so forgot to
+   correctly initialize the list.
+
+ * "git status --branch --short" accessed beyond the constant string
+   "HEAD", which has been corrected.
+
+ * "git daemon" uses "run_command()" without "finish_command()", so it
+   needs to release resources itself, which it forgot to do.
+
+Also contains typofixes, documentation updates and trivial code
+clean-ups.
index 239fe9f6b79a178d548cbb56195e5352553eef92..7facc02e0b00759f7d4190e704b11f7aa59ae226 100644 (file)
@@ -58,6 +58,9 @@ UI, Workflows & Features
  * "git clone --dissociate" learned that it can be used even when
    "--reference" was not used at the same time.
 
+ * "git blame" learnt to take "--first-parent" and "--reverse" at the
+   same time when it makes sense.
+
 
 Performance, Internal Implementation, Development Support etc.
 
@@ -107,6 +110,9 @@ Performance, Internal Implementation, Development Support etc.
  * The implementation of "git mailinfo" was refactored so that a
    mailinfo() function can be directly called from inside a process.
 
+ * With a "debug" helper, debugging of a single "git" invocation in
+   our test scripts has become a lot easier.
+
 
 Also contains various documentation updates and code clean-ups.
 
@@ -304,6 +310,27 @@ notes for details).
    argument misbehaved ever since Git 2.0.
    (merge 29abb33 jc/add-u-A-default-to-top later to maint).
 
+ * "git daemon" uses "run_command()" without "finish_command()", so it
+   needs to release resources itself, which it forgot to do.
+   (merge b1b49ff rs/daemon-plug-child-leak later to maint).
+
+ * "git status --branch --short" accessed beyond the constant string
+   "HEAD", which has been corrected.
+   (merge c72b49d rs/wt-status-detached-branch-fix later to maint).
+
+ * We peek objects from submodule's object store by linking it to the
+   list of alternate object databases, but the code to do so forgot to
+   correctly initialize the list.
+   (merge 9a6e4f0 jk/initialization-fix-to-add-submodule-odb later to maint).
+
+ * The code to prepare the working tree side of temporary directory
+   for the "dir-diff" feature forgot that symbolic links need not be
+   copied (or symlinked) to the temporary area, as the code already
+   special cases and overwrites them.  Besides, it was wrong to try
+   computing the object name of the target of symbolic link, which may
+   not even exist or may be a directory.
+   (merge cfe2d4b da/difftool later to maint).
+
  * Code clean-up, minor fixes etc.
    (merge 15ed07d jc/rerere later to maint).
    (merge e7a7401 pt/pull-builtin later to maint).
@@ -321,3 +348,4 @@ notes for details).
    (merge b2af482 xf/user-manual-ff later to maint).
    (merge e510ab8 rs/pop-commit later to maint).
    (merge fdcdb77 js/misc-fixes later to maint).
+   (merge c949b00 rs/show-branch-argv-array later to maint).
index 4585103f996c0e68753520ad5064a1a9879054c8..c2e2a94e754fb0f831f1604634901d4c155784af 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.6.2/git.html[documentation for release 2.6.2]
+* link:v2.6.3/git.html[documentation for release 2.6.3]
 
 * release notes for
+  link:RelNotes/2.6.3.txt[2.6.3],
   link:RelNotes/2.6.2.txt[2.6.2],
   link:RelNotes/2.6.1.txt[2.6.1],
   link:RelNotes/2.6.0.txt[2.6].
index a9fdb45b93e514962716401cb22d9d079b107e40..8bf3e37f5375584e5c9f4543523a40377e08686f 100644 (file)
@@ -46,6 +46,13 @@ Functions
        The argument dir corresponds the member .dir. The argument env
        corresponds to the member .env.
 
+`child_process_clear`::
+
+       Release the memory associated with the struct child_process.
+       Most users of the run-command API don't need to call this
+       function explicitly because `start_command` invokes it on
+       failure and `finish_command` calls it automatically already.
+
 The functions above do the following:
 
 . If a system call failed, errno is set and -1 is returned. A diagnostic
index 3b80e8fd75cc0743035642cb82a284271925c865..83612f5b646f1db7232cf69cf5a2ea6b30a6e833 100644 (file)
@@ -2402,16 +2402,11 @@ static struct commit *fake_working_tree_commit(struct diff_options *opt,
        return commit;
 }
 
-static char *prepare_final(struct scoreboard *sb)
+static struct object_array_entry *find_single_final(struct rev_info *revs)
 {
        int i;
-       const char *final_commit_name = NULL;
-       struct rev_info *revs = sb->revs;
+       struct object_array_entry *found = NULL;
 
-       /*
-        * There must be one and only one positive commit in the
-        * revs->pending array.
-        */
        for (i = 0; i < revs->pending.nr; i++) {
                struct object *obj = revs->pending.objects[i].item;
                if (obj->flags & UNINTERESTING)
@@ -2420,14 +2415,24 @@ static char *prepare_final(struct scoreboard *sb)
                        obj = deref_tag(obj, NULL, 0);
                if (obj->type != OBJ_COMMIT)
                        die("Non commit %s?", revs->pending.objects[i].name);
-               if (sb->final)
+               if (found)
                        die("More than one commit to dig from %s and %s?",
                            revs->pending.objects[i].name,
-                           final_commit_name);
-               sb->final = (struct commit *) obj;
-               final_commit_name = revs->pending.objects[i].name;
+                           found->name);
+               found = &(revs->pending.objects[i]);
+       }
+       return found;
+}
+
+static char *prepare_final(struct scoreboard *sb)
+{
+       struct object_array_entry *found = find_single_final(sb->revs);
+       if (found) {
+               sb->final = (struct commit *) found->item;
+               return xstrdup(found->name);
+       } else {
+               return NULL;
        }
-       return xstrdup_or_null(final_commit_name);
 }
 
 static char *prepare_initial(struct scoreboard *sb)
@@ -2503,6 +2508,7 @@ int cmd_blame(int argc, const char **argv, const char *prefix)
        long dashdash_pos, lno;
        char *final_commit_name = NULL;
        enum object_type type;
+       struct commit *final_commit = NULL;
 
        static struct string_list range_list;
        static int output_option = 0, opt = 0;
@@ -2692,11 +2698,11 @@ int cmd_blame(int argc, const char **argv, const char *prefix)
        }
        else if (contents_from)
                die("--contents and --reverse do not blend well.");
-       else if (revs.first_parent_only)
-               die("combining --first-parent and --reverse is not supported");
        else {
                final_commit_name = prepare_initial(&sb);
                sb.commits.compare = compare_commits_by_reverse_commit_date;
+               if (revs.first_parent_only)
+                       revs.children.name = NULL;
        }
 
        if (!sb.final) {
@@ -2713,6 +2719,14 @@ int cmd_blame(int argc, const char **argv, const char *prefix)
        else if (contents_from)
                die("Cannot use --contents with final commit object name");
 
+       if (reverse && revs.first_parent_only) {
+               struct object_array_entry *entry = find_single_final(sb.revs);
+               if (!entry)
+                       die("--reverse and --first-parent together require specified latest commit");
+               else
+                       final_commit = (struct commit*) entry->item;
+       }
+
        /*
         * If we have bottom, this will mark the ancestors of the
         * bottom commits we would reach while traversing as
@@ -2721,6 +2735,25 @@ int cmd_blame(int argc, const char **argv, const char *prefix)
        if (prepare_revision_walk(&revs))
                die(_("revision walk setup failed"));
 
+       if (reverse && revs.first_parent_only) {
+               struct commit *c = final_commit;
+
+               sb.revs->children.name = "children";
+               while (c->parents &&
+                      hashcmp(c->object.sha1, sb.final->object.sha1)) {
+                       struct commit_list *l = xcalloc(1, sizeof(*l));
+
+                       l->item = c;
+                       if (add_decoration(&sb.revs->children,
+                                          &c->parents->item->object, l))
+                               die("BUG: not unique item in first-parent chain");
+                       c = c->parents->item;
+               }
+
+               if (hashcmp(c->object.sha1, sb.final->object.sha1))
+                       die("--reverse --first-parent together require range along first-parent chain");
+       }
+
        if (is_null_sha1(sb.final->object.sha1)) {
                o = sb.final->util;
                sb.final_buf = xmemdupz(o->file.ptr, o->file.size);
index ac5141df80dffaf7adc42f76989698a5a90cb677..e17744bc0dad37b75865b5da8c8c3037bcc02167 100644 (file)
@@ -3,6 +3,7 @@
 #include "refs.h"
 #include "builtin.h"
 #include "color.h"
+#include "argv-array.h"
 #include "parse-options.h"
 
 static const char* show_branch_usage[] = {
@@ -16,9 +17,7 @@ static const char* show_branch_usage[] = {
 
 static int showbranch_use_color = -1;
 
-static int default_num;
-static int default_alloc;
-static const char **default_arg;
+static struct argv_array default_args = ARGV_ARRAY_INIT;
 
 #define UNINTERESTING  01
 
@@ -556,16 +555,9 @@ static int git_show_branch_config(const char *var, const char *value, void *cb)
                 * default_arg is now passed to parse_options(), so we need to
                 * mimic the real argv a bit better.
                 */
-               if (!default_num) {
-                       default_alloc = 20;
-                       default_arg = xcalloc(default_alloc, sizeof(*default_arg));
-                       default_arg[default_num++] = "show-branch";
-               } else if (default_alloc <= default_num + 1) {
-                       default_alloc = default_alloc * 3 / 2 + 20;
-                       REALLOC_ARRAY(default_arg, default_alloc);
-               }
-               default_arg[default_num++] = xstrdup(value);
-               default_arg[default_num] = NULL;
+               if (!default_args.argc)
+                       argv_array_push(&default_args, "show-branch");
+               argv_array_push(&default_args, value);
                return 0;
        }
 
@@ -685,9 +677,9 @@ int cmd_show_branch(int ac, const char **av, const char *prefix)
        git_config(git_show_branch_config, NULL);
 
        /* If nothing is specified, try the default first */
-       if (ac == 1 && default_num) {
-               ac = default_num;
-               av = default_arg;
+       if (ac == 1 && default_args.argc) {
+               ac = default_args.argc;
+               av = default_args.argv;
        }
 
        ac = parse_options(ac, av, prefix, builtin_show_branch_options,
index 56679a15fee533a29168b92ecc0f18f68f919085..be70cd4da09ccab8850be41e19b0fc4b9a10f502 100644 (file)
--- a/daemon.c
+++ b/daemon.c
@@ -802,6 +802,7 @@ static void check_dead_children(void)
                        /* remove the child */
                        *cradle = blanket->next;
                        live_children--;
+                       child_process_clear(&blanket->cld);
                        free(blanket);
                } else
                        cradle = &blanket->next;
index 7df7c8a9a7c889fbf5f0b2d6e67be66bf6fea6b1..488d14b153e50f69fcfb0c732cc8c23cf4b643de 100755 (executable)
@@ -70,9 +70,7 @@ sub use_wt_file
        my ($repo, $workdir, $file, $sha1) = @_;
        my $null_sha1 = '0' x 40;
 
-       if (! -e "$workdir/$file") {
-               # If the file doesn't exist in the working tree, we cannot
-               # use it.
+       if (-l "$workdir/$file" || ! -e _) {
                return (0, $null_sha1);
        }
 
index e157ca6eb5a078f950d9bd6c746698be22fa651c..f289941f7e516be2f6265326188b3d8da70ef3aa 100644 (file)
@@ -1009,7 +1009,7 @@ void setup_mailinfo(struct mailinfo *mi)
        mi->header_stage = 1;
        mi->use_inbody_headers = 1;
        mi->content_top = mi->content;
-       git_config(git_mailinfo_config, &mi);
+       git_config(git_mailinfo_config, mi);
 }
 
 void clear_mailinfo(struct mailinfo *mi)
index 1194f10ed60f2bb476e1d95d0cc11b4ad4265c7f..e205dd2f689ee5aeafe6ea66343fd01b85d2e354 100644 (file)
@@ -1457,7 +1457,7 @@ static int cmp_ref_sorting(struct ref_sorting *s, struct ref_array_item *a, stru
                if (va->ul < vb->ul)
                        cmp = -1;
                else if (va->ul == vb->ul)
-                       cmp = 0;
+                       cmp = strcmp(a->refname, b->refname);
                else
                        cmp = 1;
        }
index e17e456cdaef63d3fa587b8e216bf1fe5c372317..13fa452e8c3d5a5e20e24a969d53ce7ade4019bf 100644 (file)
@@ -11,6 +11,12 @@ void child_process_init(struct child_process *child)
        argv_array_init(&child->env_array);
 }
 
+void child_process_clear(struct child_process *child)
+{
+       argv_array_clear(&child->args);
+       argv_array_clear(&child->env_array);
+}
+
 struct child_to_clean {
        pid_t pid;
        struct child_to_clean *next;
@@ -327,8 +333,7 @@ int start_command(struct child_process *cmd)
 fail_pipe:
                        error("cannot create %s pipe for %s: %s",
                                str, cmd->argv[0], strerror(failed_errno));
-                       argv_array_clear(&cmd->args);
-                       argv_array_clear(&cmd->env_array);
+                       child_process_clear(cmd);
                        errno = failed_errno;
                        return -1;
                }
@@ -513,8 +518,7 @@ int start_command(struct child_process *cmd)
                        close_pair(fderr);
                else if (cmd->err)
                        close(cmd->err);
-               argv_array_clear(&cmd->args);
-               argv_array_clear(&cmd->env_array);
+               child_process_clear(cmd);
                errno = failed_errno;
                return -1;
        }
@@ -540,8 +544,7 @@ int start_command(struct child_process *cmd)
 int finish_command(struct child_process *cmd)
 {
        int ret = wait_or_whine(cmd->pid, cmd->argv[0], 0);
-       argv_array_clear(&cmd->args);
-       argv_array_clear(&cmd->env_array);
+       child_process_clear(cmd);
        return ret;
 }
 
index 5428b048e2c49dec3e322ac2a46ffddd012e4c8d..12bb26c2a6155750203babfec47b08e8bde0ad27 100644 (file)
@@ -47,6 +47,7 @@ struct child_process {
 
 #define CHILD_PROCESS_INIT { NULL, ARGV_ARRAY_INIT, ARGV_ARRAY_INIT }
 void child_process_init(struct child_process *);
+void child_process_clear(struct child_process *);
 
 int start_command(struct child_process *);
 int finish_command(struct child_process *);
index 5879cfb158f0b581a54a56de5de44af5c2d0a700..88af54c633851d440f46e21d65b1362b6360d2bb 100644 (file)
@@ -130,6 +130,7 @@ static int add_submodule_odb(const char *path)
                goto done;
        }
        /* avoid adding it twice */
+       prepare_alt_odb();
        for (alt_odb = alt_odb_list; alt_odb; alt_odb = alt_odb->next)
                if (alt_odb->name - alt_odb->base == objects_directory.len &&
                                !strncmp(alt_odb->base, objects_directory.buf,
@@ -148,7 +149,6 @@ static int add_submodule_odb(const char *path)
 
        /* add possible alternates from the submodule */
        read_info_alternates(objects_directory.buf, 0);
-       prepare_alt_odb();
 done:
        strbuf_release(&objects_directory);
        return ret;
index 35438bca487337e73fcb3c4fd490072793d21900..1dc908e43a993502bed611023448aa76fc9da6ad 100644 (file)
--- a/t/README
+++ b/t/README
@@ -563,6 +563,11 @@ library for your script to use.
    argument.  This is primarily meant for use during the
    development of a new test script.
 
+ - debug <git-command>
+
+   Run a git command inside a debugger. This is primarily meant for
+   use when debugging a failing test script.
+
  - test_done
 
    Your test script must have test_done at the end.  Its purpose
index 9454423ca02af98ad50a089e0c0dc2bc1e952bd0..d3913f9088950a3ca848b8994abfddfecd3f6706 100755 (executable)
@@ -158,8 +158,8 @@ EOF
 
 test_expect_success 'git branch `--sort` option' '
        cat >expect <<-\EOF &&
-         branch-two
        * (HEAD detached from fromtag)
+         branch-two
          branch-one
          master
        EOF
index 32d81765cb53718e5d26092ccfe970a503edfa02..44bf1d84af574509c5a8f6f05721d7c4f9719439 100755 (executable)
@@ -213,5 +213,19 @@ EOF
        git checkout master
 '
 
+test_expect_success 'status --branch with detached HEAD' '
+       git reset --hard &&
+       git checkout master^0 &&
+       git status --branch --porcelain >actual &&
+       cat >expected <<-EOF &&
+       ## HEAD (no branch)
+       ?? .gitconfig
+       ?? actual
+       ?? expect
+       ?? expected
+       ?? mdconflict/
+       EOF
+       test_i18ncmp expected actual
+'
 
 test_done
index 48c6e2bc830e74ab8d242e49c08f38609b5ef585..ec8bc8c7656fd7f0fd03226b5491f5bc9d532dd7 100755 (executable)
@@ -504,4 +504,23 @@ test_expect_success PERL 'difftool properly honors gitlink and core.worktree' '
        )
 '
 
+test_expect_success PERL,SYMLINKS 'difftool --dir-diff symlinked directories' '
+       git init dirlinks &&
+       (
+               cd dirlinks &&
+               git config diff.tool checktrees &&
+               git config difftool.checktrees.cmd "echo good" &&
+               mkdir foo &&
+               : >foo/bar &&
+               git add foo/bar &&
+               test_commit symlink-one &&
+               ln -s foo link &&
+               git add link &&
+               test_commit symlink-two &&
+               echo good >expect &&
+               git difftool --tool=checktrees --dir-diff HEAD~ >actual &&
+               test_cmp expect actual
+       )
+'
+
 test_done
diff --git a/t/t8009-blame-vs-topicbranches.sh b/t/t8009-blame-vs-topicbranches.sh
new file mode 100755 (executable)
index 0000000..72596e3
--- /dev/null
@@ -0,0 +1,36 @@
+#!/bin/sh
+
+test_description='blaming trough history with topic branches'
+. ./test-lib.sh
+
+# Creates the history shown below. '*'s mark the first parent in the merges.
+# The only line of file.t is changed in commit B2
+#
+#        +---C1
+#       /      \
+# A0--A1--*A2--*A3
+#   \     /
+#    B1-B2
+#
+test_expect_success setup '
+       test_commit A0 file.t line0 &&
+       test_commit A1 &&
+       git reset --hard A0 &&
+       test_commit B1 &&
+       test_commit B2 file.t line0changed &&
+       git reset --hard A1 &&
+       test_merge A2 B2 &&
+       git reset --hard A1 &&
+       test_commit C1 &&
+       git reset --hard A2 &&
+       test_merge A3 C1
+       '
+
+test_expect_success 'blame --reverse --first-parent finds A1' '
+       git blame --porcelain --reverse --first-parent A0..A3 -- file.t >actual_full &&
+       head -n 1 <actual_full | sed -e "s/ .*//" >actual &&
+       git rev-parse A1 >expect &&
+       test_cmp expect actual
+       '
+
+test_done
index 6dffb8bcde83b82fa40b05dd8ee815f4e6a3cdd3..73e37a1f6c23d00371dbd3f10aee1648e8b947bc 100644 (file)
@@ -145,6 +145,14 @@ test_pause () {
        fi
 }
 
+# Wrap git in gdb. Adding this to a command can make it easier to
+# understand what is going on in a failing test.
+#
+# Example: "debug git checkout master".
+debug () {
+        GIT_TEST_GDB=1 "$@"
+}
+
 # Call test_commit with the arguments "<message> [<file> [<contents> [<tag>]]]"
 #
 # This will commit a file with the given contents and the given commit
index 701d2339b9f5014d78ff1d5c88cfd21a1accd0c2..db0ec6a7370fd56e4e11c49a4b9e5e15f461e1f9 100644 (file)
@@ -19,4 +19,10 @@ GIT_TEXTDOMAINDIR='@@BUILD_DIR@@/po/build/locale'
 PATH='@@BUILD_DIR@@/bin-wrappers:'"$PATH"
 export GIT_EXEC_PATH GITPERLLIB PATH GIT_TEXTDOMAINDIR
 
-exec "${GIT_EXEC_PATH}/@@PROG@@" "$@"
+if test -n "$GIT_TEST_GDB"
+then
+       unset GIT_TEST_GDB
+       exec gdb --args "${GIT_EXEC_PATH}/@@PROG@@" "$@"
+else
+       exec "${GIT_EXEC_PATH}/@@PROG@@" "$@"
+fi
index 3e3b8c098924d655bccb395e95cee832abb1d39f..435fc2806ec0a59acf390ee89ed2efc79f229a0e 100644 (file)
@@ -897,15 +897,15 @@ static void wt_status_print_verbose(struct wt_status *s)
 static void wt_status_print_tracking(struct wt_status *s)
 {
        struct strbuf sb = STRBUF_INIT;
-       const char *cp, *ep;
+       const char *cp, *ep, *branch_name;
        struct branch *branch;
        char comment_line_string[3];
        int i;
 
        assert(s->branch && !s->is_initial);
-       if (!starts_with(s->branch, "refs/heads/"))
+       if (!skip_prefix(s->branch, "refs/heads/", &branch_name))
                return;
-       branch = branch_get(s->branch + 11);
+       branch = branch_get(branch_name);
        if (!format_tracking_info(branch, &sb))
                return;
 
@@ -1268,6 +1268,7 @@ static char *read_and_strip_branch(const char *path)
 {
        struct strbuf sb = STRBUF_INIT;
        unsigned char sha1[20];
+       const char *branch_name;
 
        if (strbuf_read_file(&sb, git_path("%s", path), 0) <= 0)
                goto got_nothing;
@@ -1276,8 +1277,8 @@ static char *read_and_strip_branch(const char *path)
                strbuf_setlen(&sb, sb.len - 1);
        if (!sb.len)
                goto got_nothing;
-       if (starts_with(sb.buf, "refs/heads/"))
-               strbuf_remove(&sb,0, strlen("refs/heads/"));
+       if (skip_prefix(sb.buf, "refs/heads/", &branch_name))
+               strbuf_remove(&sb, 0, branch_name - sb.buf);
        else if (starts_with(sb.buf, "refs/"))
                ;
        else if (!get_sha1_hex(sb.buf, sha1)) {
@@ -1308,9 +1309,8 @@ static int grab_1st_switch(unsigned char *osha1, unsigned char *nsha1,
        struct grab_1st_switch_cbdata *cb = cb_data;
        const char *target = NULL, *end;
 
-       if (!starts_with(message, "checkout: moving from "))
+       if (!skip_prefix(message, "checkout: moving from ", &message))
                return 0;
-       message += strlen("checkout: moving from ");
        target = strstr(message, " to ");
        if (!target)
                return 0;
@@ -1348,14 +1348,10 @@ static void wt_status_get_detached_from(struct wt_status_state *state)
             /* perhaps sha1 is a tag, try to dereference to a commit */
             ((commit = lookup_commit_reference_gently(sha1, 1)) != NULL &&
              !hashcmp(cb.nsha1, commit->object.sha1)))) {
-               int ofs;
-               if (starts_with(ref, "refs/tags/"))
-                       ofs = strlen("refs/tags/");
-               else if (starts_with(ref, "refs/remotes/"))
-                       ofs = strlen("refs/remotes/");
-               else
-                       ofs = 0;
-               state->detached_from = xstrdup(ref + ofs);
+               const char *from = ref;
+               if (!skip_prefix(from, "refs/tags/", &from))
+                       skip_prefix(from, "refs/remotes/", &from);
+               state->detached_from = xstrdup(from);
        } else
                state->detached_from =
                        xstrdup(find_unique_abbrev(cb.nsha1, DEFAULT_ABBREV));
@@ -1442,9 +1438,7 @@ void wt_status_print(struct wt_status *s)
        if (s->branch) {
                const char *on_what = _("On branch ");
                const char *branch_name = s->branch;
-               if (starts_with(branch_name, "refs/heads/"))
-                       branch_name += 11;
-               else if (!strcmp(branch_name, "HEAD")) {
+               if (!strcmp(branch_name, "HEAD")) {
                        branch_status_color = color(WT_STATUS_NOBRANCH, s);
                        if (state.rebase_in_progress || state.rebase_interactive_in_progress) {
                                if (state.rebase_interactive_in_progress)
@@ -1462,7 +1456,8 @@ void wt_status_print(struct wt_status *s)
                                branch_name = "";
                                on_what = _("Not currently on any branch.");
                        }
-               }
+               } else
+                       skip_prefix(branch_name, "refs/heads/", &branch_name);
                status_printf(s, color(WT_STATUS_HEADER, s), "%s", "");
                status_printf_more(s, branch_status_color, "%s", on_what);
                status_printf_more(s, branch_color, "%s\n", branch_name);
@@ -1644,24 +1639,24 @@ static void wt_shortstatus_print_tracking(struct wt_status *s)
                return;
        branch_name = s->branch;
 
-       if (starts_with(branch_name, "refs/heads/"))
-               branch_name += 11;
-       else if (!strcmp(branch_name, "HEAD")) {
-               branch_name = _("HEAD (no branch)");
-               branch_color_local = color(WT_STATUS_NOBRANCH, s);
-       }
-
-       branch = branch_get(s->branch + 11);
        if (s->is_initial)
                color_fprintf(s->fp, header_color, _("Initial commit on "));
 
+       if (!strcmp(s->branch, "HEAD")) {
+               color_fprintf(s->fp, color(WT_STATUS_NOBRANCH, s), "%s",
+                             _("HEAD (no branch)"));
+               goto conclude;
+       }
+
+       skip_prefix(branch_name, "refs/heads/", &branch_name);
+
+       branch = branch_get(branch_name);
+
        color_fprintf(s->fp, branch_color_local, "%s", branch_name);
 
        if (stat_tracking_info(branch, &num_ours, &num_theirs, &base) < 0) {
-               if (!base) {
-                       fputc(s->null_termination ? '\0' : '\n', s->fp);
-                       return;
-               }
+               if (!base)
+                       goto conclude;
 
                upstream_is_gone = 1;
        }
@@ -1671,10 +1666,8 @@ static void wt_shortstatus_print_tracking(struct wt_status *s)
        color_fprintf(s->fp, branch_color_remote, "%s", base);
        free((char *)base);
 
-       if (!upstream_is_gone && !num_ours && !num_theirs) {
-               fputc(s->null_termination ? '\0' : '\n', s->fp);
-               return;
-       }
+       if (!upstream_is_gone && !num_ours && !num_theirs)
+               goto conclude;
 
 #define LABEL(string) (s->no_gettext ? (string) : _(string))
 
@@ -1695,6 +1688,7 @@ static void wt_shortstatus_print_tracking(struct wt_status *s)
        }
 
        color_fprintf(s->fp, header_color, "]");
+ conclude:
        fputc(s->null_termination ? '\0' : '\n', s->fp);
 }