Merge git://git.bogomips.org/git-svn
authorJunio C Hamano <gitster@pobox.com>
Mon, 30 Apr 2012 00:00:42 +0000 (17:00 -0700)
committerJunio C Hamano <gitster@pobox.com>
Mon, 30 Apr 2012 00:00:42 +0000 (17:00 -0700)
By Matthijs Kooijman
via Eric Wong
* git://git.bogomips.org/git-svn:
git-svn: use platform specific auth providers

14 files changed:
Documentation/RelNotes/1.7.11.txt
builtin/fmt-merge-msg.c
builtin/merge.c
builtin/revert.c
http.c
revision.c
revision.h
sequencer.c
setup.c
t/t5550-http-fetch.sh
t/t6028-merge-up-to-date.sh
t/t7602-merge-octopus-many.sh
t/t7603-merge-reduce-heads.sh
t/t9300-fast-import.sh
index 7ab069aab7ac49c11be98dfeda0502f2338c47c2..af736591d2581e11d9d20f3c9ec092befb3f3612 100644 (file)
@@ -86,6 +86,30 @@ Unless otherwise noted, all the fixes since v1.7.10 in the maintenance
 releases are contained in this release (see release notes to them for
 details).
 
+ * Octopus merge strategy did not reduce heads that are recorded in the
+   final commit correctly.
+   (merge 5802f81 jc/merge-reduce-parents-early later to maint).
+
+ * In the older days, the header "Conflicts:" in "cherry-pick" and
+   "merge" was separated by a blank line from the list of paths that
+   follow for readability, but when "merge" was rewritten in C, we lost
+   it by mistake. Remove the newline from "cherry-pick" to make them
+   match again.
+   (merge 5112068 rt/cherry-revert-conflict-summary later to maint).
+
+ * The filesystem boundary was not correctly reported when .git
+   directory discovery stopped at a mount point.
+   (merge 2565b43 cb/maint-report-mount-point-correctly-in-setup later to maint).
+
+ * The command line parser choked "git cherry-pick $name" when $name
+   can be both revision name and a pathname, even though $name can
+   never be a path in the context of the command.
+   (merge 6d5b93f cb/cherry-pick-rev-path-confusion later to maint).
+
+ * HTTP transport that requires authentication did not work correctly
+   when multiple connections are used simultaneously.
+   (merge 6f4c347 cb/http-multi-curl-auth later to maint).
+
  * The i18n of error message "git stash save" was not properly done.
    (merge ed3c400 rl/maint-stash-i18n-save-error later to maint).
 
index 1bc6b8b8c3a4f4ab174841f3c8507d784f237a1f..a517f1794a1c1bcc0939ad8b81d482356c20d2ba 100644 (file)
@@ -55,7 +55,48 @@ static void init_src_data(struct src_data *data)
 static struct string_list srcs = STRING_LIST_INIT_DUP;
 static struct string_list origins = STRING_LIST_INIT_DUP;
 
-static int handle_line(char *line)
+struct merge_parents {
+       int alloc, nr;
+       struct merge_parent {
+               unsigned char given[20];
+               unsigned char commit[20];
+               unsigned char used;
+       } *item;
+};
+
+/*
+ * I know, I know, this is inefficient, but you won't be pulling and merging
+ * hundreds of heads at a time anyway.
+ */
+static struct merge_parent *find_merge_parent(struct merge_parents *table,
+                                             unsigned char *given,
+                                             unsigned char *commit)
+{
+       int i;
+       for (i = 0; i < table->nr; i++) {
+               if (given && hashcmp(table->item[i].given, given))
+                       continue;
+               if (commit && hashcmp(table->item[i].commit, commit))
+                       continue;
+               return &table->item[i];
+       }
+       return NULL;
+}
+
+static void add_merge_parent(struct merge_parents *table,
+                            unsigned char *given,
+                            unsigned char *commit)
+{
+       if (table->nr && find_merge_parent(table, given, commit))
+               return;
+       ALLOC_GROW(table->item, table->nr + 1, table->alloc);
+       hashcpy(table->item[table->nr].given, given);
+       hashcpy(table->item[table->nr].commit, commit);
+       table->item[table->nr].used = 0;
+       table->nr++;
+}
+
+static int handle_line(char *line, struct merge_parents *merge_parents)
 {
        int i, len = strlen(line);
        struct origin_data *origin_data;
@@ -63,6 +104,7 @@ static int handle_line(char *line)
        struct src_data *src_data;
        struct string_list_item *item;
        int pulling_head = 0;
+       unsigned char sha1[20];
 
        if (len < 43 || line[40] != '\t')
                return 1;
@@ -73,14 +115,15 @@ static int handle_line(char *line)
        if (line[41] != '\t')
                return 2;
 
-       line[40] = 0;
-       origin_data = xcalloc(1, sizeof(struct origin_data));
-       i = get_sha1(line, origin_data->sha1);
-       line[40] = '\t';
-       if (i) {
-               free(origin_data);
+       i = get_sha1_hex(line, sha1);
+       if (i)
                return 3;
-       }
+
+       if (!find_merge_parent(merge_parents, sha1, NULL))
+               return 0; /* subsumed by other parents */
+
+       origin_data = xcalloc(1, sizeof(struct origin_data));
+       hashcpy(origin_data->sha1, sha1);
 
        if (line[len - 1] == '\n')
                line[len - 1] = 0;
@@ -472,6 +515,67 @@ static void fmt_merge_msg_sigs(struct strbuf *out)
        strbuf_release(&tagbuf);
 }
 
+static void find_merge_parents(struct merge_parents *result,
+                              struct strbuf *in, unsigned char *head)
+{
+       struct commit_list *parents, *next;
+       struct commit *head_commit;
+       int pos = 0, i, j;
+
+       parents = NULL;
+       while (pos < in->len) {
+               int len;
+               char *p = in->buf + pos;
+               char *newline = strchr(p, '\n');
+               unsigned char sha1[20];
+               struct commit *parent;
+               struct object *obj;
+
+               len = newline ? newline - p : strlen(p);
+               pos += len + !!newline;
+
+               if (len < 43 ||
+                   get_sha1_hex(p, sha1) ||
+                   p[40] != '\t' ||
+                   p[41] != '\t')
+                       continue; /* skip not-for-merge */
+               /*
+                * Do not use get_merge_parent() here; we do not have
+                * "name" here and we do not want to contaminate its
+                * util field yet.
+                */
+               obj = parse_object(sha1);
+               parent = (struct commit *)peel_to_type(NULL, 0, obj, OBJ_COMMIT);
+               if (!parent)
+                       continue;
+               commit_list_insert(parent, &parents);
+               add_merge_parent(result, obj->sha1, parent->object.sha1);
+       }
+       head_commit = lookup_commit(head);
+       if (head_commit)
+               commit_list_insert(head_commit, &parents);
+       parents = reduce_heads(parents);
+
+       while (parents) {
+               for (i = 0; i < result->nr; i++)
+                       if (!hashcmp(result->item[i].commit,
+                                    parents->item->object.sha1))
+                               result->item[i].used = 1;
+               next = parents->next;
+               free(parents);
+               parents = next;
+       }
+
+       for (i = j = 0; i < result->nr; i++) {
+               if (result->item[i].used) {
+                       if (i != j)
+                               result->item[j] = result->item[i];
+                       j++;
+               }
+       }
+       result->nr = j;
+}
+
 int fmt_merge_msg(struct strbuf *in, struct strbuf *out,
                  struct fmt_merge_msg_opts *opts)
 {
@@ -479,6 +583,9 @@ int fmt_merge_msg(struct strbuf *in, struct strbuf *out,
        unsigned char head_sha1[20];
        const char *current_branch;
        void *current_branch_to_free;
+       struct merge_parents merge_parents;
+
+       memset(&merge_parents, 0, sizeof(merge_parents));
 
        /* get current branch */
        current_branch = current_branch_to_free =
@@ -488,6 +595,8 @@ int fmt_merge_msg(struct strbuf *in, struct strbuf *out,
        if (!prefixcmp(current_branch, "refs/heads/"))
                current_branch += 11;
 
+       find_merge_parents(&merge_parents, in, head_sha1);
+
        /* get a line */
        while (pos < in->len) {
                int len;
@@ -498,7 +607,7 @@ int fmt_merge_msg(struct strbuf *in, struct strbuf *out,
                pos += len + !!newline;
                i++;
                p[len] = 0;
-               if (handle_line(p))
+               if (handle_line(p, &merge_parents))
                        die ("Error in line %d: %.*s", i, len, p);
        }
 
@@ -529,6 +638,7 @@ int fmt_merge_msg(struct strbuf *in, struct strbuf *out,
 
        strbuf_complete_line(out);
        free(current_branch_to_free);
+       free(merge_parents.item);
        return 0;
 }
 
index 08e01e8a60d7d7f9c60e9e7a3a2f8b4d66c12ce3..470fc57c5d6ceabedbd866a5db35d3123a764af0 100644 (file)
@@ -52,7 +52,6 @@ static int fast_forward_only, option_edit = -1;
 static int allow_trivial = 1, have_message;
 static int overwrite_ignore = 1;
 static struct strbuf merge_msg = STRBUF_INIT;
-static struct commit_list *remoteheads;
 static struct strategy **use_strategies;
 static size_t use_strategies_nr, use_strategies_alloc;
 static const char **xopts;
@@ -318,7 +317,7 @@ static void finish_up_to_date(const char *msg)
        drop_save();
 }
 
-static void squash_message(struct commit *commit)
+static void squash_message(struct commit *commit, struct commit_list *remoteheads)
 {
        struct rev_info rev;
        struct strbuf out = STRBUF_INIT;
@@ -366,6 +365,7 @@ static void squash_message(struct commit *commit)
 }
 
 static void finish(struct commit *head_commit,
+                  struct commit_list *remoteheads,
                   const unsigned char *new_head, const char *msg)
 {
        struct strbuf reflog_message = STRBUF_INIT;
@@ -380,7 +380,7 @@ static void finish(struct commit *head_commit,
                        getenv("GIT_REFLOG_ACTION"), msg);
        }
        if (squash) {
-               squash_message(head_commit);
+               squash_message(head_commit, remoteheads);
        } else {
                if (verbosity >= 0 && !merge_msg.len)
                        printf(_("No merge message -- not updating HEAD\n"));
@@ -683,6 +683,7 @@ int try_merge_command(const char *strategy, size_t xopts_nr,
 }
 
 static int try_merge_strategy(const char *strategy, struct commit_list *common,
+                             struct commit_list *remoteheads,
                              struct commit *head, const char *head_arg)
 {
        int index_fd;
@@ -876,14 +877,14 @@ static void read_merge_msg(struct strbuf *msg)
                die_errno(_("Could not read from '%s'"), filename);
 }
 
-static void write_merge_state(void);
-static void abort_commit(const char *err_msg)
+static void write_merge_state(struct commit_list *);
+static void abort_commit(struct commit_list *remoteheads, const char *err_msg)
 {
        if (err_msg)
                error("%s", err_msg);
        fprintf(stderr,
                _("Not committing merge; use 'git commit' to complete the merge.\n"));
-       write_merge_state();
+       write_merge_state(remoteheads);
        exit(1);
 }
 
@@ -894,7 +895,7 @@ N_("Please enter a commit message to explain why this merge is necessary,\n"
    "Lines starting with '#' will be ignored, and an empty message aborts\n"
    "the commit.\n");
 
-static void prepare_to_commit(void)
+static void prepare_to_commit(struct commit_list *remoteheads)
 {
        struct strbuf msg = STRBUF_INIT;
        const char *comment = _(merge_editor_comment);
@@ -907,18 +908,18 @@ static void prepare_to_commit(void)
                 git_path("MERGE_MSG"), "merge", NULL, NULL);
        if (0 < option_edit) {
                if (launch_editor(git_path("MERGE_MSG"), NULL, NULL))
-                       abort_commit(NULL);
+                       abort_commit(remoteheads, NULL);
        }
        read_merge_msg(&msg);
        stripspace(&msg, 0 < option_edit);
        if (!msg.len)
-               abort_commit(_("Empty commit message."));
+               abort_commit(remoteheads, _("Empty commit message."));
        strbuf_release(&merge_msg);
        strbuf_addbuf(&merge_msg, &msg);
        strbuf_release(&msg);
 }
 
-static int merge_trivial(struct commit *head)
+static int merge_trivial(struct commit *head, struct commit_list *remoteheads)
 {
        unsigned char result_tree[20], result_commit[20];
        struct commit_list *parent = xmalloc(sizeof(*parent));
@@ -929,45 +930,37 @@ static int merge_trivial(struct commit *head)
        parent->next = xmalloc(sizeof(*parent->next));
        parent->next->item = remoteheads->item;
        parent->next->next = NULL;
-       prepare_to_commit();
+       prepare_to_commit(remoteheads);
        if (commit_tree(&merge_msg, result_tree, parent, result_commit, NULL,
                        sign_commit))
                die(_("failed to write commit object"));
-       finish(head, result_commit, "In-index merge");
+       finish(head, remoteheads, result_commit, "In-index merge");
        drop_save();
        return 0;
 }
 
 static int finish_automerge(struct commit *head,
+                           int head_subsumed,
                            struct commit_list *common,
+                           struct commit_list *remoteheads,
                            unsigned char *result_tree,
                            const char *wt_strategy)
 {
-       struct commit_list *parents = NULL, *j;
+       struct commit_list *parents = NULL;
        struct strbuf buf = STRBUF_INIT;
        unsigned char result_commit[20];
 
        free_commit_list(common);
-       if (allow_fast_forward) {
-               parents = remoteheads;
+       parents = remoteheads;
+       if (!head_subsumed || !allow_fast_forward)
                commit_list_insert(head, &parents);
-               parents = reduce_heads(parents);
-       } else {
-               struct commit_list **pptr = &parents;
-
-               pptr = &commit_list_insert(head,
-                               pptr)->next;
-               for (j = remoteheads; j; j = j->next)
-                       pptr = &commit_list_insert(j->item, pptr)->next;
-       }
        strbuf_addch(&merge_msg, '\n');
-       prepare_to_commit();
-       free_commit_list(remoteheads);
+       prepare_to_commit(remoteheads);
        if (commit_tree(&merge_msg, result_tree, parents, result_commit,
                        NULL, sign_commit))
                die(_("failed to write commit object"));
        strbuf_addf(&buf, "Merge made by the '%s' strategy.", wt_strategy);
-       finish(head, result_commit, buf.buf);
+       finish(head, remoteheads, result_commit, buf.buf);
        strbuf_release(&buf);
        drop_save();
        return 0;
@@ -1072,7 +1065,7 @@ static int setup_with_upstream(const char ***argv)
        return i;
 }
 
-static void write_merge_state(void)
+static void write_merge_state(struct commit_list *remoteheads)
 {
        const char *filename;
        int fd;
@@ -1137,6 +1130,39 @@ static int default_edit_option(void)
                st_stdin.st_mode == st_stdout.st_mode);
 }
 
+static struct commit_list *collect_parents(struct commit *head_commit,
+                                          int *head_subsumed,
+                                          int argc, const char **argv)
+{
+       int i;
+       struct commit_list *remoteheads = NULL, *parents, *next;
+       struct commit_list **remotes = &remoteheads;
+
+       if (head_commit)
+               remotes = &commit_list_insert(head_commit, remotes)->next;
+       for (i = 0; i < argc; i++) {
+               struct commit *commit = get_merge_parent(argv[i]);
+               if (!commit)
+                       die(_("%s - not something we can merge"), argv[i]);
+               remotes = &commit_list_insert(commit, remotes)->next;
+       }
+       *remotes = NULL;
+
+       parents = reduce_heads(remoteheads);
+
+       *head_subsumed = 1; /* we will flip this to 0 when we find it */
+       for (remoteheads = NULL, remotes = &remoteheads;
+            parents;
+            parents = next) {
+               struct commit *commit = parents->item;
+               next = parents->next;
+               if (commit == head_commit)
+                       *head_subsumed = 0;
+               else
+                       remotes = &commit_list_insert(commit, remotes)->next;
+       }
+       return remoteheads;
+}
 
 int cmd_merge(int argc, const char **argv, const char *prefix)
 {
@@ -1146,11 +1172,11 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
        struct commit *head_commit;
        struct strbuf buf = STRBUF_INIT;
        const char *head_arg;
-       int flag, i, ret = 0;
+       int flag, i, ret = 0, head_subsumed;
        int best_cnt = -1, merge_was_ok = 0, automerge_was_ok = 0;
        struct commit_list *common = NULL;
        const char *best_strategy = NULL, *wt_strategy = NULL;
-       struct commit_list **remotes = &remoteheads;
+       struct commit_list *remoteheads, *p;
        void *branch_to_free;
 
        if (argc == 2 && !strcmp(argv[1], "-h"))
@@ -1255,6 +1281,7 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
                head_arg = argv[1];
                argv += 2;
                argc -= 2;
+               remoteheads = collect_parents(head_commit, &head_subsumed, argc, argv);
        } else if (!head_commit) {
                struct commit *remote_head;
                /*
@@ -1270,7 +1297,8 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
                if (!allow_fast_forward)
                        die(_("Non-fast-forward commit does not make sense into "
                            "an empty head"));
-               remote_head = get_merge_parent(argv[0]);
+               remoteheads = collect_parents(head_commit, &head_subsumed, argc, argv);
+               remote_head = remoteheads->item;
                if (!remote_head)
                        die(_("%s - not something we can merge"), argv[0]);
                read_empty(remote_head->object.sha1, 0);
@@ -1288,8 +1316,9 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
                 * the standard merge summary message to be appended
                 * to the given message.
                 */
-               for (i = 0; i < argc; i++)
-                       merge_name(argv[i], &merge_names);
+               remoteheads = collect_parents(head_commit, &head_subsumed, argc, argv);
+               for (p = remoteheads; p; p = p->next)
+                       merge_name(merge_remote_util(p->item)->name, &merge_names);
 
                if (!have_message || shortlog_len) {
                        struct fmt_merge_msg_opts opts;
@@ -1308,19 +1337,16 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
                        builtin_merge_options);
 
        strbuf_addstr(&buf, "merge");
-       for (i = 0; i < argc; i++)
-               strbuf_addf(&buf, " %s", argv[i]);
+       for (p = remoteheads; p; p = p->next)
+               strbuf_addf(&buf, " %s", merge_remote_util(p->item)->name);
        setenv("GIT_REFLOG_ACTION", buf.buf, 0);
        strbuf_reset(&buf);
 
-       for (i = 0; i < argc; i++) {
-               struct commit *commit = get_merge_parent(argv[i]);
-               if (!commit)
-                       die(_("%s - not something we can merge"), argv[i]);
-               remotes = &commit_list_insert(commit, remotes)->next;
+       for (p = remoteheads; p; p = p->next) {
+               struct commit *commit = p->item;
                strbuf_addf(&buf, "GITHEAD_%s",
                            sha1_to_hex(commit->object.sha1));
-               setenv(buf.buf, argv[i], 1);
+               setenv(buf.buf, merge_remote_util(commit)->name, 1);
                strbuf_reset(&buf);
                if (!fast_forward_only &&
                    merge_remote_util(commit) &&
@@ -1333,7 +1359,9 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
                option_edit = default_edit_option();
 
        if (!use_strategies) {
-               if (!remoteheads->next)
+               if (!remoteheads)
+                       ; /* already up-to-date */
+               else if (!remoteheads->next)
                        add_strategies(pull_twohead, DEFAULT_TWOHEAD);
                else
                        add_strategies(pull_octopus, DEFAULT_OCTOPUS);
@@ -1346,7 +1374,9 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
                        allow_trivial = 0;
        }
 
-       if (!remoteheads->next)
+       if (!remoteheads)
+               ; /* already up-to-date */
+       else if (!remoteheads->next)
                common = get_merge_bases(head_commit, remoteheads->item, 1);
        else {
                struct commit_list *list = remoteheads;
@@ -1358,10 +1388,11 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
        update_ref("updating ORIG_HEAD", "ORIG_HEAD", head_commit->object.sha1,
                   NULL, 0, DIE_ON_ERR);
 
-       if (!common)
+       if (remoteheads && !common)
                ; /* No common ancestors found. We need a real merge. */
-       else if (!remoteheads->next && !common->next &&
-                       common->item == remoteheads->item) {
+       else if (!remoteheads ||
+                (!remoteheads->next && !common->next &&
+                 common->item == remoteheads->item)) {
                /*
                 * If head can reach all the merge then we are up to date.
                 * but first the most common case of merging one remote.
@@ -1399,7 +1430,7 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
                        goto done;
                }
 
-               finish(head_commit, commit->object.sha1, msg.buf);
+               finish(head_commit, remoteheads, commit->object.sha1, msg.buf);
                drop_save();
                goto done;
        } else if (!remoteheads->next && common->next)
@@ -1421,7 +1452,7 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
                        if (!read_tree_trivial(common->item->object.sha1,
                                               head_commit->object.sha1,
                                               remoteheads->item->object.sha1)) {
-                               ret = merge_trivial(head_commit);
+                               ret = merge_trivial(head_commit, remoteheads);
                                goto done;
                        }
                        printf(_("Nope.\n"));
@@ -1492,7 +1523,8 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
                wt_strategy = use_strategies[i]->name;
 
                ret = try_merge_strategy(use_strategies[i]->name,
-                                        common, head_commit, head_arg);
+                                        common, remoteheads,
+                                        head_commit, head_arg);
                if (!option_commit && !ret) {
                        merge_was_ok = 1;
                        /*
@@ -1534,8 +1566,9 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
         * auto resolved the merge cleanly.
         */
        if (automerge_was_ok) {
-               ret = finish_automerge(head_commit, common, result_tree,
-                                      wt_strategy);
+               ret = finish_automerge(head_commit, head_subsumed,
+                                      common, remoteheads,
+                                      result_tree, wt_strategy);
                goto done;
        }
 
@@ -1560,13 +1593,14 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
                restore_state(head_commit->object.sha1, stash);
                printf(_("Using the %s to prepare resolving by hand.\n"),
                        best_strategy);
-               try_merge_strategy(best_strategy, common, head_commit, head_arg);
+               try_merge_strategy(best_strategy, common, remoteheads,
+                                  head_commit, head_arg);
        }
 
        if (squash)
-               finish(head_commit, NULL, NULL);
+               finish(head_commit, remoteheads, NULL, NULL);
        else
-               write_merge_state();
+               write_merge_state(remoteheads);
 
        if (merge_was_ok)
                fprintf(stderr, _("Automatic merge went well; "
index e4ed0239ca7cbc0f33f2cf02d6287e681ca535bf..5462e676e2151452adae8fe5b0cb42b1a5edff31 100644 (file)
@@ -182,12 +182,15 @@ static void parse_args(int argc, const char **argv, struct replay_opts *opts)
        if (opts->subcommand != REPLAY_NONE) {
                opts->revs = NULL;
        } else {
+               struct setup_revision_opt s_r_opt;
                opts->revs = xmalloc(sizeof(*opts->revs));
                init_revisions(opts->revs, NULL);
                opts->revs->no_walk = 1;
                if (argc < 2)
                        usage_with_options(usage_str, options);
-               argc = setup_revisions(argc, argv, opts->revs, NULL);
+               memset(&s_r_opt, 0, sizeof(s_r_opt));
+               s_r_opt.assume_dashdash = 1;
+               argc = setup_revisions(argc, argv, opts->revs, &s_r_opt);
        }
 
        if (argc > 1)
diff --git a/http.c b/http.c
index f3f83d70cd2e13a774d208206af20181dd39d8af..2ec37891f36693b278b095b51331531a23d96d36 100644 (file)
--- a/http.c
+++ b/http.c
@@ -210,14 +210,23 @@ static int http_options(const char *var, const char *value, void *cb)
 
 static void init_curl_http_auth(CURL *result)
 {
-       if (http_auth.username) {
-               struct strbuf up = STRBUF_INIT;
-               credential_fill(&http_auth);
+       if (!http_auth.username)
+               return;
+
+       credential_fill(&http_auth);
+
+#if LIBCURL_VERSION_NUM >= 0x071301
+       curl_easy_setopt(result, CURLOPT_USERNAME, http_auth.username);
+       curl_easy_setopt(result, CURLOPT_PASSWORD, http_auth.password);
+#else
+       {
+               static struct strbuf up = STRBUF_INIT;
+               strbuf_reset(&up);
                strbuf_addf(&up, "%s:%s",
                            http_auth.username, http_auth.password);
-               curl_easy_setopt(result, CURLOPT_USERPWD,
-                                strbuf_detach(&up, NULL));
+               curl_easy_setopt(result, CURLOPT_USERPWD, up.buf);
        }
+#endif
 }
 
 static int has_cert_password(void)
@@ -494,6 +503,8 @@ struct active_request_slot *get_active_slot(void)
        curl_easy_setopt(slot->curl, CURLOPT_POSTFIELDS, NULL);
        curl_easy_setopt(slot->curl, CURLOPT_UPLOAD, 0);
        curl_easy_setopt(slot->curl, CURLOPT_HTTPGET, 1);
+       if (http_auth.password)
+               init_curl_http_auth(slot->curl);
 
        return slot;
 }
index edb225d1fa2e572cacf467f1706f203ee02ddda7..e0e80f13ef12c28e7f791e4c7ca9519e3c5aecc0 100644 (file)
@@ -1715,17 +1715,21 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, struct s
                submodule = opt->submodule;
 
        /* First, search for "--" */
-       seen_dashdash = 0;
-       for (i = 1; i < argc; i++) {
-               const char *arg = argv[i];
-               if (strcmp(arg, "--"))
-                       continue;
-               argv[i] = NULL;
-               argc = i;
-               if (argv[i + 1])
-                       append_prune_data(&prune_data, argv + i + 1);
+       if (opt && opt->assume_dashdash) {
                seen_dashdash = 1;
-               break;
+       } else {
+               seen_dashdash = 0;
+               for (i = 1; i < argc; i++) {
+                       const char *arg = argv[i];
+                       if (strcmp(arg, "--"))
+                               continue;
+                       argv[i] = NULL;
+                       argc = i;
+                       if (argv[i + 1])
+                               append_prune_data(&prune_data, argv + i + 1);
+                       seen_dashdash = 1;
+                       break;
+               }
        }
 
        /* Second, deal with arguments and options */
index eb87fd1e2f5d16032cb92d96c4bae9e2397f2978..863f4f64543bd9f9e830e7c9567def23e906c7d9 100644 (file)
@@ -183,6 +183,7 @@ struct setup_revision_opt {
        const char *def;
        void (*tweak)(struct rev_info *, struct setup_revision_opt *);
        const char *submodule;
+       int assume_dashdash;
 };
 
 extern void init_revisions(struct rev_info *revs, const char *prefix);
index 4307364b261bcbe7a2e97116aa631aa7aa35613c..cd11e340dda2d3905df84d9187f70226affef08f 100644 (file)
@@ -234,7 +234,7 @@ static int do_recursive_merge(struct commit *base, struct commit *next,
 
        if (!clean) {
                int i;
-               strbuf_addstr(msgbuf, "\nConflicts:\n\n");
+               strbuf_addstr(msgbuf, "\nConflicts:\n");
                for (i = 0; i < active_nr;) {
                        struct cache_entry *ce = active_cache[i++];
                        if (ce_stage(ce)) {
diff --git a/setup.c b/setup.c
index 7a3618fab774c0c26a99c6e23b4fcf726e5dc1ad..731851a4a85161af49a38c481672615a6ac0bbc9 100644 (file)
--- a/setup.c
+++ b/setup.c
@@ -569,13 +569,15 @@ static const char *setup_nongit(const char *cwd, int *nongit_ok)
        return NULL;
 }
 
-static dev_t get_device_or_die(const char *path, const char *prefix)
+static dev_t get_device_or_die(const char *path, const char *prefix, int prefix_len)
 {
        struct stat buf;
-       if (stat(path, &buf))
-               die_errno("failed to stat '%s%s%s'",
+       if (stat(path, &buf)) {
+               die_errno("failed to stat '%*s%s%s'",
+                               prefix_len,
                                prefix ? prefix : "",
                                prefix ? "/" : "", path);
+       }
        return buf.st_dev;
 }
 
@@ -589,7 +591,7 @@ static const char *setup_git_directory_gently_1(int *nongit_ok)
        static char cwd[PATH_MAX+1];
        const char *gitdirenv, *ret;
        char *gitfile;
-       int len, offset, ceil_offset;
+       int len, offset, offset_parent, ceil_offset;
        dev_t current_device = 0;
        int one_filesystem = 1;
 
@@ -631,7 +633,7 @@ static const char *setup_git_directory_gently_1(int *nongit_ok)
         */
        one_filesystem = !git_env_bool("GIT_DISCOVERY_ACROSS_FILESYSTEM", 0);
        if (one_filesystem)
-               current_device = get_device_or_die(".", NULL);
+               current_device = get_device_or_die(".", NULL, 0);
        for (;;) {
                gitfile = (char*)read_gitfile(DEFAULT_GIT_DIR_ENVIRONMENT);
                if (gitfile)
@@ -653,11 +655,12 @@ static const char *setup_git_directory_gently_1(int *nongit_ok)
                if (is_git_directory("."))
                        return setup_bare_git_dir(cwd, offset, len, nongit_ok);
 
-               while (--offset > ceil_offset && cwd[offset] != '/');
-               if (offset <= ceil_offset)
+               offset_parent = offset;
+               while (--offset_parent > ceil_offset && cwd[offset_parent] != '/');
+               if (offset_parent <= ceil_offset)
                        return setup_nongit(cwd, nongit_ok);
                if (one_filesystem) {
-                       dev_t parent_device = get_device_or_die("..", cwd);
+                       dev_t parent_device = get_device_or_die("..", cwd, offset);
                        if (parent_device != current_device) {
                                if (nongit_ok) {
                                        if (chdir(cwd))
@@ -666,7 +669,7 @@ static const char *setup_git_directory_gently_1(int *nongit_ok)
                                        return NULL;
                                }
                                cwd[offset] = '\0';
-                               die("Not a git repository (or any parent up to mount parent %s)\n"
+                               die("Not a git repository (or any parent up to mount point %s)\n"
                                "Stopping at filesystem boundary (GIT_DISCOVERY_ACROSS_FILESYSTEM not set).", cwd);
                        }
                }
@@ -674,6 +677,7 @@ static const char *setup_git_directory_gently_1(int *nongit_ok)
                        cwd[offset] = '\0';
                        die_errno("Cannot change to '%s/..'", cwd);
                }
+               offset = offset_parent;
        }
 }
 
index e5e6b8f643206c2d4fd01e3ad71ca50a43f3da19..b06f817af32483631b3ec297246e156400bc6b93 100755 (executable)
@@ -13,17 +13,22 @@ LIB_HTTPD_PORT=${LIB_HTTPD_PORT-'5550'}
 start_httpd
 
 test_expect_success 'setup repository' '
-       echo content >file &&
+       echo content1 >file &&
        git add file &&
        git commit -m one
+       echo content2 >file &&
+       git add file &&
+       git commit -m two
 '
 
-test_expect_success 'create http-accessible bare repository' '
-       mkdir "$HTTPD_DOCUMENT_ROOT_PATH/repo.git" &&
+test_expect_success 'create http-accessible bare repository with loose objects' '
+       cp -a .git "$HTTPD_DOCUMENT_ROOT_PATH/repo.git" &&
        (cd "$HTTPD_DOCUMENT_ROOT_PATH/repo.git" &&
-        git --bare init &&
+        git config core.bare true &&
+        mkdir -p hooks &&
         echo "exec git update-server-info" >hooks/post-update &&
-        chmod +x hooks/post-update
+        chmod +x hooks/post-update &&
+        hooks/post-update
        ) &&
        git remote add public "$HTTPD_DOCUMENT_ROOT_PATH/repo.git" &&
        git push public master:master
index a91644e3b2ac3490cfe49d5e67c9736197cd56a1..c518e9c30ccbb12c504d25aa965f8941a3989d8d 100755 (executable)
@@ -16,7 +16,12 @@ test_expect_success setup '
        test_tick &&
        git commit -m second &&
        git tag c1 &&
-       git branch test
+       git branch test &&
+       echo third >file &&
+       git add file &&
+       test_tick &&
+       git commit -m third &&
+       git tag c2
 '
 
 test_expect_success 'merge -s recursive up-to-date' '
@@ -74,4 +79,14 @@ test_expect_success 'merge -s subtree up-to-date' '
 
 '
 
+test_expect_success 'merge fast-forward octopus' '
+
+       git reset --hard c0 &&
+       test_tick &&
+       git merge c1 c2
+       expect=$(git rev-parse c2) &&
+       current=$(git rev-parse HEAD) &&
+       test "$expect" = "$current"
+'
+
 test_done
index bce0bd37cb6006f29b9c8c532863947c44509486..3b72c097ee0c9538d4e8003639ab7c44126c49d6 100755 (executable)
@@ -70,16 +70,14 @@ test_expect_success 'merge output uses pretty names' '
 '
 
 cat >expected <<\EOF
-Already up-to-date with c4
-Trying simple merge with c5
-Merge made by the 'octopus' strategy.
+Merge made by the 'recursive' strategy.
  c5.c |    1 +
  1 file changed, 1 insertion(+)
  create mode 100644 c5.c
 EOF
 
-test_expect_success 'merge up-to-date output uses pretty names' '
-       git merge c4 c5 >actual &&
+test_expect_success 'merge reduces irrelevant remote heads' '
+       GIT_MERGE_VERBOSITY=0 git merge c4 c5 >actual &&
        test_i18ncmp expected actual
 '
 
index 7e17eb490d4b1f4ac275a7033562aaa6693181ab..98948955ae507ef007dc541f7e981d06bf7b49ab 100755 (executable)
@@ -57,7 +57,36 @@ test_expect_success 'merge c1 with c2, c3, c4, c5' '
        test -f c2.c &&
        test -f c3.c &&
        test -f c4.c &&
-       test -f c5.c
+       test -f c5.c &&
+       git show --format=%s -s >actual &&
+       ! grep c1 actual &&
+       grep c2 actual &&
+       grep c3 actual &&
+       ! grep c4 actual &&
+       grep c5 actual
+'
+
+test_expect_success 'pull c2, c3, c4, c5 into c1' '
+       git reset --hard c1 &&
+       git pull . c2 c3 c4 c5 &&
+       test "$(git rev-parse c1)" != "$(git rev-parse HEAD)" &&
+       test "$(git rev-parse c1)" = "$(git rev-parse HEAD^1)" &&
+       test "$(git rev-parse c2)" = "$(git rev-parse HEAD^2)" &&
+       test "$(git rev-parse c3)" = "$(git rev-parse HEAD^3)" &&
+       test "$(git rev-parse c5)" = "$(git rev-parse HEAD^4)" &&
+       git diff --exit-code &&
+       test -f c0.c &&
+       test -f c1.c &&
+       test -f c2.c &&
+       test -f c3.c &&
+       test -f c4.c &&
+       test -f c5.c &&
+       git show --format=%s -s >actual &&
+       ! grep c1 actual &&
+       grep c2 actual &&
+       grep c3 actual &&
+       ! grep c4 actual &&
+       grep c5 actual
 '
 
 test_expect_success 'setup' '
@@ -113,4 +142,23 @@ test_expect_success 'verify merge result' '
        test $(git rev-parse HEAD^1) = $(git rev-parse E2) &&
        test $(git rev-parse HEAD^2) = $(git rev-parse I2)
 '
+
+test_expect_success 'fast-forward to redundant refs' '
+       git reset --hard c0 &&
+       git merge c4 c5
+'
+
+test_expect_success 'verify merge result' '
+       test $(git rev-parse HEAD) = $(git rev-parse c5)
+'
+
+test_expect_success 'merge up-to-date redundant refs' '
+       git reset --hard c5 &&
+       git merge c0 c4
+'
+
+test_expect_success 'verify merge result' '
+       test $(git rev-parse HEAD) = $(git rev-parse c5)
+'
+
 test_done
index 924c8848608719183e1e402796ff038ca43784d3..7da0e8da7bfd68c0ac4e0b987664c7340078eb99 100755 (executable)
@@ -24,6 +24,13 @@ head_c () {
        ' - "$1"
 }
 
+verify_packs () {
+       for p in .git/objects/pack/*.pack
+       do
+               git verify-pack "$@" "$p" || return
+       done
+}
+
 file2_data='file2
 second line of EOF'
 
@@ -105,9 +112,10 @@ test_expect_success \
     'A: create pack from stdin' \
     'git fast-import --export-marks=marks.out <input &&
         git whatchanged master'
-test_expect_success \
-       'A: verify pack' \
-       'for p in .git/objects/pack/*.pack;do git verify-pack $p||exit;done'
+
+test_expect_success 'A: verify pack' '
+       verify_packs
+'
 
 cat >expect <<EOF
 author $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
@@ -252,9 +260,11 @@ test_expect_success \
        'A: verify marks import does not crash' \
        'git fast-import --import-marks=marks.out <input &&
         git whatchanged verify--import-marks'
-test_expect_success \
-       'A: verify pack' \
-       'for p in .git/objects/pack/*.pack;do git verify-pack $p||exit;done'
+
+test_expect_success 'A: verify pack' '
+       verify_packs
+'
+
 cat >expect <<EOF
 :000000 100755 0000000000000000000000000000000000000000 7123f7f44e39be127c5eb701e5968176ee9d78b1 A     copy-of-file2
 EOF
@@ -514,9 +524,11 @@ test_expect_success \
     'C: incremental import create pack from stdin' \
     'git fast-import <input &&
         git whatchanged branch'
-test_expect_success \
-       'C: verify pack' \
-       'for p in .git/objects/pack/*.pack;do git verify-pack $p||exit;done'
+
+test_expect_success 'C: verify pack' '
+       verify_packs
+'
+
 test_expect_success \
        'C: validate reuse existing blob' \
        'test $newf = `git rev-parse --verify branch:file2/newf` &&
@@ -572,9 +584,10 @@ test_expect_success \
     'D: inline data in commit' \
     'git fast-import <input &&
         git whatchanged branch'
-test_expect_success \
-       'D: verify pack' \
-       'for p in .git/objects/pack/*.pack;do git verify-pack $p||exit;done'
+
+test_expect_success 'D: verify pack' '
+       verify_packs
+'
 
 cat >expect <<EOF
 :000000 100755 0000000000000000000000000000000000000000 35a59026a33beac1569b1c7f66f3090ce9c09afc A     newdir/exec.sh
@@ -618,9 +631,10 @@ test_expect_success 'E: rfc2822 date, --date-format=raw' '
 test_expect_success \
     'E: rfc2822 date, --date-format=rfc2822' \
     'git fast-import --date-format=rfc2822 <input'
-test_expect_success \
-       'E: verify pack' \
-       'for p in .git/objects/pack/*.pack;do git verify-pack $p||exit;done'
+
+test_expect_success 'E: verify pack' '
+       verify_packs
+'
 
 cat >expect <<EOF
 author $GIT_AUTHOR_NAME <$GIT_AUTHOR_EMAIL> 1170778938 -0500
@@ -669,9 +683,10 @@ test_expect_success \
                fi
         fi
        '
-test_expect_success \
-       'F: verify pack' \
-       'for p in .git/objects/pack/*.pack;do git verify-pack $p||exit;done'
+
+test_expect_success 'F: verify pack' '
+       verify_packs
+'
 
 cat >expect <<EOF
 tree `git rev-parse branch~1^{tree}`
@@ -705,9 +720,11 @@ INPUT_END
 test_expect_success \
     'G: non-fast-forward update forced' \
     'git fast-import --force <input'
-test_expect_success \
-       'G: verify pack' \
-       'for p in .git/objects/pack/*.pack;do git verify-pack $p||exit;done'
+
+test_expect_success 'G: verify pack' '
+       verify_packs
+'
+
 test_expect_success \
        'G: branch changed, but logged' \
        'test $old_branch != `git rev-parse --verify branch^0` &&
@@ -742,9 +759,10 @@ test_expect_success \
     'H: deletall, add 1' \
     'git fast-import <input &&
         git whatchanged H'
-test_expect_success \
-       'H: verify pack' \
-       'for p in .git/objects/pack/*.pack;do git verify-pack $p||exit;done'
+
+test_expect_success 'H: verify pack' '
+       verify_packs
+'
 
 cat >expect <<EOF
 :100755 000000 f1fb5da718392694d0076d677d6d0e364c79b0bc 0000000000000000000000000000000000000000 D     file2/newf
@@ -1857,9 +1875,10 @@ test_expect_success \
        'Q: commit notes' \
        'git fast-import <input &&
         git whatchanged notes-test'
-test_expect_success \
-       'Q: verify pack' \
-       'for p in .git/objects/pack/*.pack;do git verify-pack $p||exit;done'
+
+test_expect_success 'Q: verify pack' '
+       verify_packs
+'
 
 commit1=$(git rev-parse notes-test~2)
 commit2=$(git rev-parse notes-test^)
@@ -2616,13 +2635,14 @@ test_expect_success \
        'R: blob bigger than threshold' \
        'test_create_repo R &&
         git --git-dir=R/.git fast-import --big-file-threshold=1 <input'
-test_expect_success \
-       'R: verify created pack' \
-       ': >verify &&
-        for p in R/.git/objects/pack/*.pack;
-        do
-          git verify-pack -v $p >>verify || exit;
-        done'
+
+test_expect_success 'R: verify created pack' '
+       (
+               cd R &&
+               verify_packs -v > ../verify
+       )
+'
+
 test_expect_success \
        'R: verify written objects' \
        'git --git-dir=R/.git cat-file blob big-file:big1 >actual &&