Merge branch 'tr/die_errno'
authorJunio C Hamano <gitster@pobox.com>
Mon, 6 Jul 2009 16:39:46 +0000 (09:39 -0700)
committerJunio C Hamano <gitster@pobox.com>
Mon, 6 Jul 2009 16:39:46 +0000 (09:39 -0700)
* tr/die_errno:
Use die_errno() instead of die() when checking syscalls
Convert existing die(..., strerror(errno)) to die_errno()
die_errno(): double % in strerror() output just in case
Introduce die_errno() that appends strerror(errno) to die()

22 files changed:
1  2 
bisect.c
builtin-add.c
builtin-apply.c
builtin-clone.c
builtin-fsck.c
builtin-log.c
builtin-merge.c
builtin-mv.c
builtin-pack-objects.c
builtin-rev-parse.c
builtin-send-pack.c
builtin-tag.c
builtin-unpack-objects.c
daemon.c
diff.c
git-compat-util.h
git.c
index-pack.c
ll-merge.c
merge-recursive.c
sha1_file.c
transport.c
diff --combined bisect.c
index 52220df751aaacec08792c01ad83f2a1b27aae5f,281e16ad19a0b7959f8b5a83c5ba90543d8651b1..7f20acb4b9e391bd383597ec554ec58b70979fe5
+++ b/bisect.c
@@@ -7,7 -7,6 +7,7 @@@
  #include "quote.h"
  #include "sha1-lookup.h"
  #include "run-command.h"
 +#include "log-tree.h"
  #include "bisect.h"
  
  struct sha1_array {
@@@ -28,6 -27,7 +28,6 @@@ struct argv_array 
        int argv_alloc;
  };
  
 -static const char *argv_diff_tree[] = {"diff-tree", "--pretty", NULL, NULL};
  static const char *argv_checkout[] = {"checkout", "-q", NULL, "--", NULL};
  static const char *argv_show_branch[] = {"show-branch", NULL, NULL};
  
@@@ -454,14 -454,14 +454,14 @@@ static int read_bisect_refs(void
        return for_each_ref_in("refs/bisect/", register_ref, NULL);
  }
  
 -void read_bisect_paths(struct argv_array *array)
 +static void read_bisect_paths(struct argv_array *array)
  {
        struct strbuf str = STRBUF_INIT;
        const char *filename = git_path("BISECT_NAMES");
        FILE *fp = fopen(filename, "r");
  
        if (!fp)
-               die("Could not open file '%s': %s", filename, strerror(errno));
+               die_errno("Could not open file '%s'", filename);
  
        while (strbuf_getline(&str, fp, '\n') != EOF) {
                char *quoted;
@@@ -521,34 -521,14 +521,34 @@@ static char *join_sha1_array_hex(struc
        return strbuf_detach(&joined_hexs, NULL);
  }
  
 +/*
 + * In this function, passing a not NULL skipped_first is very special.
 + * It means that we want to know if the first commit in the list is
 + * skipped because we will want to test a commit away from it if it is
 + * indeed skipped.
 + * So if the first commit is skipped, we cannot take the shortcut to
 + * just "return list" when we find the first non skipped commit, we
 + * have to return a fully filtered list.
 + *
 + * We use (*skipped_first == -1) to mean "it has been found that the
 + * first commit is not skipped". In this case *skipped_first is set back
 + * to 0 just before the function returns.
 + */
  struct commit_list *filter_skipped(struct commit_list *list,
                                   struct commit_list **tried,
 -                                 int show_all)
 +                                 int show_all,
 +                                 int *count,
 +                                 int *skipped_first)
  {
        struct commit_list *filtered = NULL, **f = &filtered;
  
        *tried = NULL;
  
 +      if (skipped_first)
 +              *skipped_first = 0;
 +      if (count)
 +              *count = 0;
 +
        if (!skipped_revs.sha1_nr)
                return list;
  
                list->next = NULL;
                if (0 <= lookup_sha1_array(&skipped_revs,
                                           list->item->object.sha1)) {
 +                      if (skipped_first && !*skipped_first)
 +                              *skipped_first = 1;
                        /* Move current to tried list */
                        *tried = list;
                        tried = &list->next;
                } else {
 -                      if (!show_all)
 -                              return list;
 +                      if (!show_all) {
 +                              if (!skipped_first || !*skipped_first)
 +                                      return list;
 +                      } else if (skipped_first && !*skipped_first) {
 +                              /* This means we know it's not skipped */
 +                              *skipped_first = -1;
 +                      }
                        /* Move current to filtered list */
                        *f = list;
                        f = &list->next;
 +                      if (count)
 +                              (*count)++;
                }
                list = next;
        }
  
 +      if (skipped_first && *skipped_first == -1)
 +              *skipped_first = 0;
 +
        return filtered;
  }
  
 +#define PRN_MODULO 32768
 +
 +/*
 + * This is a pseudo random number generator based on "man 3 rand".
 + * It is not used properly because the seed is the argument and it
 + * is increased by one between each call, but that should not matter
 + * for this application.
 + */
 +int get_prn(int count) {
 +      count = count * 1103515245 + 12345;
 +      return ((unsigned)(count/65536) % PRN_MODULO);
 +}
 +
 +/*
 + * Custom integer square root from
 + * http://en.wikipedia.org/wiki/Integer_square_root
 + */
 +static int sqrti(int val)
 +{
 +      float d, x = val;
 +
 +      if (val == 0)
 +              return 0;
 +
 +      do {
 +              float y = (x + (float)val / x) / 2;
 +              d = (y > x) ? y - x : x - y;
 +              x = y;
 +      } while (d >= 0.5);
 +
 +      return (int)x;
 +}
 +
 +static struct commit_list *skip_away(struct commit_list *list, int count)
 +{
 +      struct commit_list *cur, *previous;
 +      int prn, index, i;
 +
 +      prn = get_prn(count);
 +      index = (count * prn / PRN_MODULO) * sqrti(prn) / sqrti(PRN_MODULO);
 +
 +      cur = list;
 +      previous = NULL;
 +
 +      for (i = 0; cur; cur = cur->next, i++) {
 +              if (i == index) {
 +                      if (hashcmp(cur->item->object.sha1, current_bad_sha1))
 +                              return cur;
 +                      if (previous)
 +                              return previous;
 +                      return list;
 +              }
 +              previous = cur;
 +      }
 +
 +      return list;
 +}
 +
 +static struct commit_list *managed_skipped(struct commit_list *list,
 +                                         struct commit_list **tried)
 +{
 +      int count, skipped_first;
 +
 +      *tried = NULL;
 +
 +      if (!skipped_revs.sha1_nr)
 +              return list;
 +
 +      list = filter_skipped(list, tried, 0, &count, &skipped_first);
 +
 +      if (!skipped_first)
 +              return list;
 +
 +      return skip_away(list, count);
 +}
 +
  static void bisect_rev_setup(struct rev_info *revs, const char *prefix,
                             const char *bad_format, const char *good_format,
                             int read_paths)
@@@ -740,8 -632,7 +740,7 @@@ static void mark_expected_rev(char *bis
        int fd = open(filename, O_CREAT | O_TRUNC | O_WRONLY, 0600);
  
        if (fd < 0)
-               die("could not create file '%s': %s",
-                   filename, strerror(errno));
+               die_errno("could not create file '%s'", filename);
  
        bisect_rev_hex[len] = '\n';
        write_or_die(fd, bisect_rev_hex, len + 1);
@@@ -808,7 -699,7 +807,7 @@@ static void handle_bad_merge_base(void
        exit(1);
  }
  
 -void handle_skipped_merge_base(const unsigned char *mb)
 +static void handle_skipped_merge_base(const unsigned char *mb)
  {
        char *mb_hex = sha1_to_hex(mb);
        char *bad_hex = sha1_to_hex(current_bad_sha1);
@@@ -879,7 -770,7 +878,7 @@@ static int check_ancestors(const char *
        /* Clean up objects used, as they will be reused. */
        for (i = 0; i < pending_copy.nr; i++) {
                struct object *o = pending_copy.objects[i].item;
 -              unparse_commit((struct commit *)o);
 +              clear_commit_marks((struct commit *)o, ALL_REV_FLAGS);
        }
  
        return res;
@@@ -923,31 -814,6 +922,31 @@@ static void check_good_are_ancestors_of
                close(fd);
  }
  
 +/*
 + * This does "git diff-tree --pretty COMMIT" without one fork+exec.
 + */
 +static void show_diff_tree(const char *prefix, struct commit *commit)
 +{
 +      struct rev_info opt;
 +
 +      /* diff-tree init */
 +      init_revisions(&opt, prefix);
 +      git_config(git_diff_basic_config, NULL); /* no "diff" UI options */
 +      opt.abbrev = 0;
 +      opt.diff = 1;
 +
 +      /* This is what "--pretty" does */
 +      opt.verbose_header = 1;
 +      opt.use_terminator = 0;
 +      opt.commit_format = CMIT_FMT_DEFAULT;
 +
 +      /* diff-tree init */
 +      if (!opt.diffopt.output_format)
 +              opt.diffopt.output_format = DIFF_FORMAT_RAW;
 +
 +      log_tree_commit(&opt, commit);
 +}
 +
  /*
   * We use the convention that exiting with an exit code 10 means that
   * the bisection process finished successfully.
@@@ -973,7 -839,7 +972,7 @@@ int bisect_next_all(const char *prefix
  
        revs.commits = find_bisection(revs.commits, &reaches, &all,
                                       !!skipped_revs.sha1_nr);
 -      revs.commits = filter_skipped(revs.commits, &tried, 0);
 +      revs.commits = managed_skipped(revs.commits, &tried);
  
        if (!revs.commits) {
                /*
        if (!hashcmp(bisect_rev, current_bad_sha1)) {
                exit_if_skipped_commits(tried, current_bad_sha1);
                printf("%s is first bad commit\n", bisect_rev_hex);
 -              argv_diff_tree[2] = bisect_rev_hex;
 -              run_command_v_opt(argv_diff_tree, RUN_GIT_CMD);
 +              show_diff_tree(prefix, revs.commits->item);
                /* This means the bisection process succeeded. */
                exit(10);
        }
diff --combined builtin-add.c
index 4e44148e05843e03befc167f6bdf3a1567d3f8ad,8f651c137a9d5e0f19e266d73c58f785c0e36af7..78989dad8cb07dee00054c3ea98d16eb493a05c9
@@@ -189,7 -189,7 +189,7 @@@ int interactive_add(int argc, const cha
        return status;
  }
  
 -int edit_patch(int argc, const char **argv, const char *prefix)
 +static int edit_patch(int argc, const char **argv, const char *prefix)
  {
        char *file = xstrdup(git_path("ADD_EDIT.patch"));
        const char *apply_argv[] = { "apply", "--recount", "--cached",
        launch_editor(file, NULL, NULL);
  
        if (stat(file, &st))
-               die("Could not stat '%s'", file);
+               die_errno("Could not stat '%s'", file);
        if (!st.st_size)
                die("Empty patch. Aborted.");
  
@@@ -298,8 -298,6 +298,8 @@@ int cmd_add(int argc, const char **argv
        int add_new_files;
        int require_pathspec;
  
 +      git_config(add_config, NULL);
 +
        argc = parse_options(argc, argv, prefix, builtin_add_options,
                          builtin_add_usage, PARSE_OPT_KEEP_ARGV0);
        if (patch_interactive)
        if (add_interactive)
                exit(interactive_add(argc - 1, argv + 1, prefix));
  
 -      git_config(add_config, NULL);
 -
        if (edit_interactive)
                return(edit_patch(argc, argv, prefix));
        argc--;
diff --combined builtin-apply.c
index 4cf819c7905d5997a6ce2a89b4ecce1176a4b045,dbc7f2165d5e8e700a7d7cff527eb6a99ef07184..dc0ff5e08ae73f2832fd4451cce2e849c88be5a8
@@@ -280,7 -280,7 +280,7 @@@ static void say_patch_name(FILE *output
  static void read_patch_file(struct strbuf *sb, int fd)
  {
        if (strbuf_read(sb, fd, 0) < 0)
-               die("git apply: read returned %s", strerror(errno));
+               die_errno("git apply: failed to read");
  
        /*
         * Make sure that we have some slop in the buffer
@@@ -2614,7 -2614,7 +2614,7 @@@ static int get_current_sha1(const char 
  static void build_fake_ancestor(struct patch *list, const char *filename)
  {
        struct patch *patch;
 -      struct index_state result = { 0 };
 +      struct index_state result = { NULL };
        int fd;
  
        /* Once we start supporting the reverse patch, it may be
@@@ -2823,8 -2823,8 +2823,8 @@@ static void add_index_file(const char *
        } else {
                if (!cached) {
                        if (lstat(path, &st) < 0)
-                               die("unable to stat newly created file %s",
-                                   path);
+                               die_errno("unable to stat newly created file '%s'",
+                                         path);
                        fill_stat_cache_info(ce, &st);
                }
                if (write_sha1_file(buf, size, blob_type, ce->sha1) < 0)
@@@ -2864,7 -2864,7 +2864,7 @@@ static int try_create_file(const char *
        strbuf_release(&nbuf);
  
        if (close(fd) < 0)
-               die("closing file %s: %s", path, strerror(errno));
+               die_errno("closing file '%s'", path);
        return 0;
  }
  
@@@ -2913,7 -2913,7 +2913,7 @@@ static void create_one_file(char *path
                        ++nr;
                }
        }
-       die("unable to write file %s mode %o", path, mode);
+       die_errno("unable to write file '%s' mode %o", path, mode);
  }
  
  static void create_file(struct patch *patch)
@@@ -3277,11 -3277,9 +3277,11 @@@ int cmd_apply(int argc, const char **ar
                OPT_BOOLEAN(0, "stat", &diffstat,
                        "instead of applying the patch, output diffstat for the input"),
                { OPTION_BOOLEAN, 0, "allow-binary-replacement", &binary,
 -                NULL, "old option, now no-op", PARSE_OPT_HIDDEN },
 +                NULL, "old option, now no-op",
 +                PARSE_OPT_HIDDEN | PARSE_OPT_NOARG },
                { OPTION_BOOLEAN, 0, "binary", &binary,
 -                NULL, "old option, now no-op", PARSE_OPT_HIDDEN },
 +                NULL, "old option, now no-op",
 +                PARSE_OPT_HIDDEN | PARSE_OPT_NOARG },
                OPT_BOOLEAN(0, "numstat", &numstat,
                        "shows number of added and deleted lines in decimal notation"),
                OPT_BOOLEAN(0, "summary", &summary,
  
                fd = open(arg, O_RDONLY);
                if (fd < 0)
-                       die("can't open patch '%s': %s", arg, strerror(errno));
+                       die_errno("can't open patch '%s'", arg);
                read_stdin = 0;
                set_default_whitespace_mode(whitespace_option);
                errs |= apply_patch(fd, arg, options);
diff --combined builtin-clone.c
index 2ceacb7b3f34c78e64ed047833d8af5a061f065f,d2b0757e538b9fbbcc20e48174886bf4f8b036d9..32dea74d78381ca1dffdac7f88e45a89a9825104
@@@ -141,7 -141,7 +141,7 @@@ static char *guess_dir_name(const char 
        if (is_bare) {
                struct strbuf result = STRBUF_INIT;
                strbuf_addf(&result, "%.*s.git", (int)(end - start), start);
 -              dir = strbuf_detach(&result, 0);
 +              dir = strbuf_detach(&result, NULL);
        } else
                dir = xstrndup(start, end - start);
        /*
@@@ -220,13 -220,13 +220,13 @@@ static void copy_or_link_directory(stru
  
        dir = opendir(src->buf);
        if (!dir)
-               die("failed to open %s", src->buf);
+               die_errno("failed to open '%s'", src->buf);
  
        if (mkdir(dest->buf, 0777)) {
                if (errno != EEXIST)
-                       die("failed to create directory %s", dest->buf);
+                       die_errno("failed to create directory '%s'", dest->buf);
                else if (stat(dest->buf, &buf))
-                       die("failed to stat %s", dest->buf);
+                       die_errno("failed to stat '%s'", dest->buf);
                else if (!S_ISDIR(buf.st_mode))
                        die("%s exists and is not a directory", dest->buf);
        }
                }
  
                if (unlink(dest->buf) && errno != ENOENT)
-                       die("failed to unlink %s: %s",
-                           dest->buf, strerror(errno));
+                       die_errno("failed to unlink '%s'", dest->buf);
                if (!option_no_hardlinks) {
                        if (!link(src->buf, dest->buf))
                                continue;
                        if (option_local)
-                               die("failed to create link %s", dest->buf);
+                               die_errno("failed to create link '%s'", dest->buf);
                        option_no_hardlinks = 1;
                }
                if (copy_file(dest->buf, src->buf, 0666))
-                       die("failed to copy file to %s", dest->buf);
+                       die_errno("failed to copy file to '%s'", dest->buf);
        }
        closedir(dir);
  }
@@@ -420,11 -419,11 +419,11 @@@ int cmd_clone(int argc, const char **ar
        if (!option_bare) {
                junk_work_tree = work_tree;
                if (safe_create_leading_directories_const(work_tree) < 0)
-                       die("could not create leading directories of '%s': %s",
-                                       work_tree, strerror(errno));
+                       die_errno("could not create leading directories of '%s'",
+                                 work_tree);
                if (!dest_exists && mkdir(work_tree, 0755))
-                       die("could not create work tree dir '%s': %s.",
-                                       work_tree, strerror(errno));
+                       die_errno("could not create work tree dir '%s'.",
+                                 work_tree);
                set_git_work_tree(work_tree);
        }
        junk_git_dir = git_dir;
diff --combined builtin-fsck.c
index e077e72dea94892e2f74ddd6be528b02bc6ccea4,d0f48cdd2aed47b9ef124b8f925a7a7d1621c850..b3d38fa277b3d0024b9c46a62cf15bc2448cc1e7
@@@ -104,7 -104,7 +104,7 @@@ static int mark_object(struct object *o
  
  static void mark_object_reachable(struct object *obj)
  {
 -      mark_object(obj, OBJ_ANY, 0);
 +      mark_object(obj, OBJ_ANY, NULL);
  }
  
  static int traverse_one_object(struct object *obj, struct object *parent)
@@@ -217,7 -217,7 +217,7 @@@ static void check_unreachable_object(st
                                return;
                        }
                        if (!(f = fopen(filename, "w")))
-                               die("Could not open %s", filename);
+                               die_errno("Could not open '%s'", filename);
                        if (obj->type == OBJ_BLOB) {
                                enum object_type type;
                                unsigned long size;
                                                &type, &size);
                                if (buf) {
                                        if (fwrite(buf, size, 1, f) != 1)
-                                               die("Could not write %s: %s",
-                                                   filename, strerror(errno));
+                                               die_errno("Could not write '%s'",
+                                                         filename);
                                        free(buf);
                                }
                        } else
                                fprintf(f, "%s\n", sha1_to_hex(obj->sha1));
                        if (fclose(f))
-                               die("Could not finish %s: %s",
-                                   filename, strerror(errno));
+                               die_errno("Could not finish '%s'",
+                                         filename);
                }
                return;
        }
@@@ -292,7 -292,7 +292,7 @@@ static int fsck_sha1(const unsigned cha
                fprintf(stderr, "Checking %s %s\n",
                        typename(obj->type), sha1_to_hex(obj->sha1));
  
 -      if (fsck_walk(obj, mark_used, 0))
 +      if (fsck_walk(obj, mark_used, NULL))
                objerror(obj, "broken links");
        if (fsck_object(obj, check_strict, fsck_error_func))
                return -1;
diff --combined builtin-log.c
index 44f9a27daec612db6d0f0e502c99d5e5ecaaf842,750957cfa9d84eb499b3d53687b832d639a72a42..0c2fa0ae2dc3f23cd52d2e8d765805b07262a7d6
@@@ -94,7 -94,7 +94,7 @@@ static void show_early_header(struct re
        printf("Final output: %d %s\n", nr, stage);
  }
  
 -struct itimerval early_output_timer;
 +static struct itimerval early_output_timer;
  
  static void log_show_early(struct rev_info *revs, struct commit_list *list)
  {
@@@ -977,7 -977,7 +977,7 @@@ int cmd_format_patch(int argc, const ch
                strbuf_addch(&buf, '\n');
        }
  
 -      rev.extra_headers = strbuf_detach(&buf, 0);
 +      rev.extra_headers = strbuf_detach(&buf, NULL);
  
        if (start_number < 0)
                start_number = 1;
                if (use_stdout)
                        die("standard output, or directory, which one?");
                if (mkdir(output_directory, 0777) < 0 && errno != EEXIST)
-                       die("Could not create directory %s",
-                           output_directory);
+                       die_errno("Could not create directory '%s'",
+                                 output_directory);
        }
  
        if (rev.pending.nr == 1) {
diff --combined builtin-merge.c
index af9adab300de98026b23a58b1d8b40f9395ff11a,82335b09ede674d93d9ea7200a2c5a6ab2980505..82b546689c500649285ea2c7825171f572c3758e
@@@ -268,7 -268,7 +268,7 @@@ static void squash_message(void
        printf("Squash commit -- not updating HEAD\n");
        fd = open(git_path("SQUASH_MSG"), O_WRONLY | O_CREAT, 0666);
        if (fd < 0)
-               die("Could not write to %s", git_path("SQUASH_MSG"));
+               die_errno("Could not write to '%s'", git_path("SQUASH_MSG"));
  
        init_revisions(&rev, NULL);
        rev.ignore_merges = 1;
                        NULL, NULL, rev.date_mode, 0);
        }
        if (write(fd, out.buf, out.len) < 0)
-               die("Writing SQUASH_MSG: %s", strerror(errno));
+               die_errno("Writing SQUASH_MSG");
        if (close(fd))
-               die("Finishing SQUASH_MSG: %s", strerror(errno));
+               die_errno("Finishing SQUASH_MSG");
        strbuf_release(&out);
  }
  
@@@ -370,7 -370,7 +370,7 @@@ static void merge_name(const char *remo
  
        strbuf_addstr(&buf, "refs/heads/");
        strbuf_addstr(&buf, remote);
 -      resolve_ref(buf.buf, branch_head, 0, 0);
 +      resolve_ref(buf.buf, branch_head, 0, NULL);
  
        if (!hashcmp(remote_head->sha1, branch_head)) {
                strbuf_addf(msg, "%s\t\tbranch '%s' of .\n",
                strbuf_addstr(&truname, "refs/heads/");
                strbuf_addstr(&truname, remote);
                strbuf_setlen(&truname, truname.len - len);
 -              if (resolve_ref(truname.buf, buf_sha, 0, 0)) {
 +              if (resolve_ref(truname.buf, buf_sha, 0, NULL)) {
                        strbuf_addf(msg,
                                    "%s\t\tbranch '%s'%s of .\n",
                                    sha1_to_hex(remote_head->sha1),
  
                fp = fopen(git_path("FETCH_HEAD"), "r");
                if (!fp)
-                       die("could not open %s for reading: %s",
-                               git_path("FETCH_HEAD"), strerror(errno));
+                       die_errno("could not open '%s' for reading",
+                                 git_path("FETCH_HEAD"));
                strbuf_getline(&line, fp, '\n');
                fclose(fp);
                ptr = strstr(line.buf, "\tnot-for-merge\t");
@@@ -764,7 -764,8 +764,8 @@@ static int suggest_conflicts(void
  
        fp = fopen(git_path("MERGE_MSG"), "a");
        if (!fp)
-               die("Could not open %s for writing", git_path("MERGE_MSG"));
+               die_errno("Could not open '%s' for writing",
+                         git_path("MERGE_MSG"));
        fprintf(fp, "\nConflicts:\n");
        for (pos = 0; pos < active_nr; pos++) {
                struct cache_entry *ce = active_cache[pos];
@@@ -836,11 -837,8 +837,11 @@@ int cmd_merge(int argc, const char **ar
        struct commit_list **remotes = &remoteheads;
  
        setup_work_tree();
 +      if (file_exists(git_path("MERGE_HEAD")))
 +              die("You have not concluded your merge. (MERGE_HEAD exists)");
        if (read_cache_unmerged())
 -              die("You are in the middle of a conflicted merge.");
 +              die("You are in the middle of a conflicted merge."
 +                              " (index unmerged)");
  
        /*
         * Check if we are _not_ on a detached HEAD, i.e. if there is a
                                sha1_to_hex(j->item->object.sha1));
                fd = open(git_path("MERGE_HEAD"), O_WRONLY | O_CREAT, 0666);
                if (fd < 0)
-                       die("Could open %s for writing",
-                               git_path("MERGE_HEAD"));
+                       die_errno("Could not open '%s' for writing",
+                                 git_path("MERGE_HEAD"));
                if (write_in_full(fd, buf.buf, buf.len) != buf.len)
-                       die("Could not write to %s", git_path("MERGE_HEAD"));
+                       die_errno("Could not write to '%s'", git_path("MERGE_HEAD"));
                close(fd);
                strbuf_addch(&merge_msg, '\n');
                fd = open(git_path("MERGE_MSG"), O_WRONLY | O_CREAT, 0666);
                if (fd < 0)
-                       die("Could open %s for writing", git_path("MERGE_MSG"));
+                       die_errno("Could not open '%s' for writing",
+                                 git_path("MERGE_MSG"));
                if (write_in_full(fd, merge_msg.buf, merge_msg.len) !=
                        merge_msg.len)
-                       die("Could not write to %s", git_path("MERGE_MSG"));
+                       die_errno("Could not write to '%s'", git_path("MERGE_MSG"));
                close(fd);
                fd = open(git_path("MERGE_MODE"), O_WRONLY | O_CREAT | O_TRUNC, 0666);
                if (fd < 0)
-                       die("Could open %s for writing", git_path("MERGE_MODE"));
+                       die_errno("Could not open '%s' for writing",
+                                 git_path("MERGE_MODE"));
                strbuf_reset(&buf);
                if (!allow_fast_forward)
                        strbuf_addf(&buf, "no-ff");
                if (write_in_full(fd, buf.buf, buf.len) != buf.len)
-                       die("Could not write to %s", git_path("MERGE_MODE"));
+                       die_errno("Could not write to '%s'", git_path("MERGE_MODE"));
                close(fd);
        }
  
diff --combined builtin-mv.c
index 68f47384dc1cc6404d4db73b6dbea8bceab38df9,024dfebf7e3ee6966c59010e1ec9193bc2fce8d3..b592c367b2cc016a50db6d49948e9efbbf0e8f2f
@@@ -24,10 -24,14 +24,10 @@@ static const char **copy_pathspec(cons
        result[count] = NULL;
        for (i = 0; i < count; i++) {
                int length = strlen(result[i]);
 -              if (length > 0 && result[i][length - 1] == '/') {
 +              if (length > 0 && is_dir_sep(result[i][length - 1]))
                        result[i] = xmemdupz(result[i], length - 1);
 -              }
 -              if (base_name) {
 -                      const char *last_slash = strrchr(result[i], '/');
 -                      if (last_slash)
 -                              result[i] = last_slash + 1;
 -              }
 +              if (base_name)
 +                      result[i] = basename((char *)result[i]);
        }
        return get_pathspec(prefix, result);
  }
@@@ -205,7 -209,7 +205,7 @@@ int cmd_mv(int argc, const char **argv
                        printf("Renaming %s to %s\n", src, dst);
                if (!show_only && mode != INDEX &&
                                rename(src, dst) < 0 && !ignore_errors)
-                       die ("renaming %s failed: %s", src, strerror(errno));
+                       die_errno ("renaming '%s' failed", src);
  
                if (mode == WORKING_DIRECTORY)
                        continue;
diff --combined builtin-pack-objects.c
index 941cc2d73cf5ee6791a0cee8c409dcdb9756b448,60355d41fdb97546ead3420eb461758e45658cb5..a27c2f6277cd55951cec5d9b5b207df426ed9ff0
@@@ -536,11 -536,9 +536,9 @@@ static void write_pack_file(void
                                 base_name, sha1_to_hex(sha1));
                        free_pack_by_name(tmpname);
                        if (adjust_perm(pack_tmp_name, mode))
-                               die("unable to make temporary pack file readable: %s",
-                                   strerror(errno));
+                               die_errno("unable to make temporary pack file readable");
                        if (rename(pack_tmp_name, tmpname))
-                               die("unable to rename temporary pack file: %s",
-                                   strerror(errno));
+                               die_errno("unable to rename temporary pack file");
  
                        /*
                         * Packs are runtime accessed in their mtime
                        snprintf(tmpname, sizeof(tmpname), "%s-%s.idx",
                                 base_name, sha1_to_hex(sha1));
                        if (adjust_perm(idx_tmp_name, mode))
-                               die("unable to make temporary index file readable: %s",
-                                   strerror(errno));
+                               die_errno("unable to make temporary index file readable");
                        if (rename(idx_tmp_name, tmpname))
-                               die("unable to rename temporary index file: %s",
-                                   strerror(errno));
+                               die_errno("unable to rename temporary index file");
  
                        free(idx_tmp_name);
                        free(pack_tmp_name);
@@@ -653,7 -649,8 +649,7 @@@ static void rehash_objects(void
  
  static unsigned name_hash(const char *name)
  {
 -      unsigned char c;
 -      unsigned hash = 0;
 +      unsigned c, hash = 0;
  
        if (!name)
                return 0;
@@@ -1879,7 -1876,7 +1875,7 @@@ static void read_object_list_from_stdin
                        if (!ferror(stdin))
                                die("fgets returned NULL, not EOF, not error!");
                        if (errno != EINTR)
-                               die("fgets: %s", strerror(errno));
+                               die_errno("fgets");
                        clearerr(stdin);
                        continue;
                }
diff --combined builtin-rev-parse.c
index 5ea7518b0f868c0cfb58840addeb360c15835c01,da26dbc020996a5e60430b6b09f70e2326352dc1..45bead65451e87a4b564e59fed3518a4de9198e9
@@@ -301,7 -301,7 +301,7 @@@ static const char *skipspaces(const cha
  
  static int cmd_parseopt(int argc, const char **argv, const char *prefix)
  {
 -      static int keep_dashdash = 0;
 +      static int keep_dashdash = 0, stop_at_non_option = 0;
        static char const * const parseopt_usage[] = {
                "git rev-parse --parseopt [options] -- [<args>...]",
                NULL
        static struct option parseopt_opts[] = {
                OPT_BOOLEAN(0, "keep-dashdash", &keep_dashdash,
                                        "keep the `--` passed as an arg"),
 +              OPT_BOOLEAN(0, "stop-at-non-option", &stop_at_non_option,
 +                                      "stop parsing after the "
 +                                      "first non-option argument"),
                OPT_END(),
        };
  
        ALLOC_GROW(opts, onb + 1, osz);
        memset(opts + onb, 0, sizeof(opts[onb]));
        argc = parse_options(argc, argv, prefix, opts, usage,
 -                           keep_dashdash ? PARSE_OPT_KEEP_DASHDASH : 0);
 +                      keep_dashdash ? PARSE_OPT_KEEP_DASHDASH : 0 |
 +                      stop_at_non_option ? PARSE_OPT_STOP_AT_NON_OPTION : 0);
  
        strbuf_addf(&parsed, " --");
        sq_quote_argv(&parsed, argv, 0);
@@@ -596,7 -592,7 +596,7 @@@ int cmd_rev_parse(int argc, const char 
                                        continue;
                                }
                                if (!getcwd(cwd, PATH_MAX))
-                                       die("unable to get current working directory");
+                                       die_errno("unable to get current working directory");
                                printf("%s/.git\n", cwd);
                                continue;
                        }
diff --combined builtin-send-pack.c
index c375a3dbde0a75af592c8881965f255f66b599d1,8fe5ab90b6a9d1c49cb370d4ecb4fecb8be329b8..47fb9f7baa9ad9c070e1a6d9c245300ba2402ce5
@@@ -59,7 -59,7 +59,7 @@@ static int pack_objects(int fd, struct 
        po.out = fd;
        po.git_cmd = 1;
        if (start_command(&po))
-               die("git pack-objects failed (%s)", strerror(errno));
+               die_errno("git pack-objects failed");
  
        /*
         * We feed the pack-objects we just spawned with revision
@@@ -473,7 -473,7 +473,7 @@@ int cmd_send_pack(int argc, const char 
        int fd[2];
        struct child_process *conn;
        struct extra_have_objects extra_have;
 -      struct ref *remote_refs, **remote_tail, *local_refs;
 +      struct ref *remote_refs, *local_refs;
        int ret;
        int send_all = 0;
        const char *receivepack = "git-receive-pack";
                flags |= MATCH_REFS_MIRROR;
  
        /* match them up */
 -      remote_tail = &remote_refs;
 -      while (*remote_tail)
 -              remote_tail = &((*remote_tail)->next);
 -      if (match_refs(local_refs, remote_refs, &remote_tail,
 -                     nr_refspecs, refspecs, flags)) {
 +      if (match_refs(local_refs, &remote_refs, nr_refspecs, refspecs, flags))
                return -1;
 -      }
  
        ret = send_pack(&args, fd, conn, remote_refs, &extra_have);
  
diff --combined builtin-tag.c
index 080e04a8fc6fc1fc3f10f59a4c1f1aa067b81aa1,165bec3069cbb31025258a0c20d61158482025ed..a51a6d1ea21412f151238e48984bc13110fcbc6c
@@@ -308,8 -308,7 +308,7 @@@ static void create_tag(const unsigned c
                path = git_pathdup("TAG_EDITMSG");
                fd = open(path, O_CREAT | O_TRUNC | O_WRONLY, 0600);
                if (fd < 0)
-                       die("could not create file '%s': %s",
-                                               path, strerror(errno));
+                       die_errno("could not create file '%s'", path);
  
                if (!is_null_sha1(prev))
                        write_tag_body(fd, prev);
@@@ -376,8 -375,8 +375,8 @@@ int cmd_tag(int argc, const char **argv
        struct commit_list *with_commit = NULL;
        struct option options[] = {
                OPT_BOOLEAN('l', NULL, &list, "list tag names"),
 -              { OPTION_INTEGER, 'n', NULL, &lines, NULL,
 -                              "print n lines of each tag message",
 +              { OPTION_INTEGER, 'n', NULL, &lines, "n",
 +                              "print <n> lines of each tag message",
                                PARSE_OPT_OPTARG, NULL, 1 },
                OPT_BOOLEAN('d', NULL, &delete, "delete tags"),
                OPT_BOOLEAN('v', NULL, &verify, "verify tags"),
                else {
                        if (!strcmp(msgfile, "-")) {
                                if (strbuf_read(&buf, 0, 1024) < 0)
-                                       die("cannot read %s", msgfile);
+                                       die_errno("cannot read '%s'", msgfile);
                        } else {
                                if (strbuf_read_file(&buf, msgfile, 1024) < 0)
-                                       die("could not open or read '%s': %s",
-                                               msgfile, strerror(errno));
+                                       die_errno("could not open or read '%s'",
+                                               msgfile);
                        }
                }
        }
diff --combined builtin-unpack-objects.c
index 7e3ea73006ecdc74c03580ac7297be4ebee174b3,41e9ac526cbe5f20929272ae1f7143ce66dc758e..557148a693c058f51222cb3d996c309791d43d8b
@@@ -68,7 -68,7 +68,7 @@@ static void *fill(int min
                if (ret <= 0) {
                        if (!ret)
                                die("early EOF");
-                       die("read error on input: %s", strerror(errno));
+                       die_errno("read error on input");
                }
                len += ret;
        } while (len < min);
@@@ -158,7 -158,7 +158,7 @@@ struct obj_info 
  #define FLAG_WRITTEN (1u<<21)
  
  static struct obj_info *obj_list;
 -unsigned nr_objects;
 +static unsigned nr_objects;
  
  /*
   * Called only from check_object() after it verified this object
@@@ -200,7 -200,7 +200,7 @@@ static int check_object(struct object *
  
        if (fsck_object(obj, 1, fsck_error_function))
                die("Error in object");
 -      if (!fsck_walk(obj, check_object, 0))
 +      if (!fsck_walk(obj, check_object, NULL))
                die("Error on reachable objects of %s", sha1_to_hex(obj->sha1));
        write_cached_object(obj);
        return 1;
@@@ -210,7 -210,7 +210,7 @@@ static void write_rest(void
  {
        unsigned i;
        for (i = 0; i < nr_objects; i++)
 -              check_object(obj_list[i].obj, OBJ_ANY, 0);
 +              check_object(obj_list[i].obj, OBJ_ANY, NULL);
  }
  
  static void added_object(unsigned nr, enum object_type type,
@@@ -422,8 -422,8 +422,8 @@@ static void unpack_delta_entry(enum obj
  static void unpack_one(unsigned nr)
  {
        unsigned shift;
 -      unsigned char *pack, c;
 -      unsigned long size;
 +      unsigned char *pack;
 +      unsigned long size, c;
        enum object_type type;
  
        obj_list[nr].offset = consumed_bytes;
diff --combined daemon.c
index 76a400557d0e8c615d6cceae511e3c7684131f04,0c2f32635ae38a979ada2c7968f8a3c535931c9e..1b5ada6648da66d14dec6c399898916920582852
+++ b/daemon.c
@@@ -1,8 -1,6 +1,8 @@@
  #include "cache.h"
  #include "pkt-line.h"
  #include "exec_cmd.h"
 +#include "run-command.h"
 +#include "strbuf.h"
  
  #include <syslog.h>
  
@@@ -345,66 -343,28 +345,66 @@@ static int run_service(char *dir, struc
        return service->fn();
  }
  
 +static void copy_to_log(int fd)
 +{
 +      struct strbuf line = STRBUF_INIT;
 +      FILE *fp;
 +
 +      fp = fdopen(fd, "r");
 +      if (fp == NULL) {
 +              logerror("fdopen of error channel failed");
 +              close(fd);
 +              return;
 +      }
 +
 +      while (strbuf_getline(&line, fp, '\n') != EOF) {
 +              logerror("%s", line.buf);
 +              strbuf_setlen(&line, 0);
 +      }
 +
 +      strbuf_release(&line);
 +      fclose(fp);
 +}
 +
 +static int run_service_command(const char **argv)
 +{
 +      struct child_process cld;
 +
 +      memset(&cld, 0, sizeof(cld));
 +      cld.argv = argv;
 +      cld.git_cmd = 1;
 +      cld.err = -1;
 +      if (start_command(&cld))
 +              return -1;
 +
 +      close(0);
 +      close(1);
 +
 +      copy_to_log(cld.err);
 +
 +      return finish_command(&cld);
 +}
 +
  static int upload_pack(void)
  {
        /* Timeout as string */
        char timeout_buf[64];
 +      const char *argv[] = { "upload-pack", "--strict", timeout_buf, ".", NULL };
  
        snprintf(timeout_buf, sizeof timeout_buf, "--timeout=%u", timeout);
 -
 -      /* git-upload-pack only ever reads stuff, so this is safe */
 -      execl_git_cmd("upload-pack", "--strict", timeout_buf, ".", NULL);
 -      return -1;
 +      return run_service_command(argv);
  }
  
  static int upload_archive(void)
  {
 -      execl_git_cmd("upload-archive", ".", NULL);
 -      return -1;
 +      static const char *argv[] = { "upload-archive", ".", NULL };
 +      return run_service_command(argv);
  }
  
  static int receive_pack(void)
  {
 -      execl_git_cmd("receive-pack", ".", NULL);
 -      return -1;
 +      static const char *argv[] = { "receive-pack", ".", NULL };
 +      return run_service_command(argv);
  }
  
  static struct daemon_service daemon_service[] = {
@@@ -493,7 -453,7 +493,7 @@@ static void parse_host_arg(char *extra_
                memset(&hints, 0, sizeof(hints));
                hints.ai_flags = AI_CANONNAME;
  
 -              gai = getaddrinfo(hostname, 0, &hints, &ai);
 +              gai = getaddrinfo(hostname, NULL, &hints, &ai);
                if (!gai) {
                        struct sockaddr_in *sin_addr = (void *)ai->ai_addr;
  
@@@ -902,7 -862,7 +902,7 @@@ static int service_loop(int socknum, in
                                        case ECONNABORTED:
                                                continue;
                                        default:
-                                               die("accept returned %s", strerror(errno));
+                                               die_errno("accept returned");
                                        }
                                }
                                handle(incoming, (struct sockaddr *)&ss, sslen);
@@@ -918,7 -878,7 +918,7 @@@ static void sanitize_stdfds(void
        while (fd != -1 && fd < 2)
                fd = dup(fd);
        if (fd == -1)
-               die("open /dev/null or dup failed: %s", strerror(errno));
+               die_errno("open /dev/null or dup failed");
        if (fd > 2)
                close(fd);
  }
@@@ -929,12 -889,12 +929,12 @@@ static void daemonize(void
                case 0:
                        break;
                case -1:
-                       die("fork failed: %s", strerror(errno));
+                       die_errno("fork failed");
                default:
                        exit(0);
        }
        if (setsid() == -1)
-               die("setsid failed: %s", strerror(errno));
+               die_errno("setsid failed");
        close(0);
        close(1);
        close(2);
@@@ -945,9 -905,9 +945,9 @@@ static void store_pid(const char *path
  {
        FILE *f = fopen(path, "w");
        if (!f)
-               die("cannot open pid file %s: %s", path, strerror(errno));
+               die_errno("cannot open pid file '%s'", path);
        if (fprintf(f, "%"PRIuMAX"\n", (uintmax_t) getpid()) < 0 || fclose(f) != 0)
-               die("failed to write pid file %s: %s", path, strerror(errno));
+               die_errno("failed to write pid file '%s'", path);
  }
  
  static int serve(char *listen_addr, int listen_port, struct passwd *pass, gid_t gid)
@@@ -1147,8 -1107,7 +1147,7 @@@ int main(int argc, char **argv
                socklen_t slen = sizeof(ss);
  
                if (!freopen("/dev/null", "w", stderr))
-                       die("failed to redirect stderr to /dev/null: %s",
-                           strerror(errno));
+                       die_errno("failed to redirect stderr to /dev/null");
  
                if (getpeername(0, peer, &slen))
                        peer = NULL;
diff --combined diff.c
index 43835d756c2c2c7ec579e1c38804fe33a706944f,aec613f85a567c6a3f28f4d79d134ee72b53510b..0a020ffab4dcfbd88fbee31bb3c84e336a67b17c
--- 1/diff.c
--- 2/diff.c
+++ b/diff.c
@@@ -1975,14 -1975,14 +1975,14 @@@ static void prep_temp_blob(const char *
        fd = git_mkstemps(temp->tmp_path, PATH_MAX, template.buf,
                        strlen(base) + 1);
        if (fd < 0)
-               die("unable to create temp-file: %s", strerror(errno));
+               die_errno("unable to create temp-file");
        if (convert_to_working_tree(path,
                        (const char *)blob, (size_t)size, &buf)) {
                blob = buf.buf;
                size = buf.len;
        }
        if (write_in_full(fd, blob, size) != size)
-               die("unable to write temp-file");
+               die_errno("unable to write temp-file");
        close(fd);
        temp->name = temp->tmp_path;
        strcpy(temp->hex, sha1_to_hex(sha1));
@@@ -2021,12 -2021,12 +2021,12 @@@ static struct diff_tempfile *prepare_te
                if (lstat(name, &st) < 0) {
                        if (errno == ENOENT)
                                goto not_a_valid_file;
-                       die("stat(%s): %s", name, strerror(errno));
+                       die_errno("stat(%s)", name);
                }
                if (S_ISLNK(st.st_mode)) {
                        struct strbuf sb = STRBUF_INIT;
                        if (strbuf_readlink(&sb, name, st.st_size) < 0)
-                               die("readlink(%s)", name);
+                               die_errno("readlink(%s)", name);
                        prep_temp_blob(name, temp, sb.buf, sb.len,
                                       (one->sha1_valid ?
                                        one->sha1 : null_sha1),
@@@ -2219,7 -2219,7 +2219,7 @@@ static void diff_fill_sha1_info(struct 
                                return;
                        }
                        if (lstat(one->path, &st) < 0)
-                               die("stat %s", one->path);
+                               die_errno("stat '%s'", one->path);
                        if (index_path(one->sha1, one->path, &st, 0))
                                die("cannot hash %s", one->path);
                }
@@@ -3596,7 -3596,6 +3596,7 @@@ static char *run_textconv(const char *p
        if (start_command(&child) != 0 ||
            strbuf_read(&buf, child.out, 0) < 0 ||
            finish_command(&child) != 0) {
 +              strbuf_release(&buf);
                remove_tempfile();
                error("error running textconv command '%s'", pgm);
                return NULL;
diff --combined git-compat-util.h
index 919b7f1ade9cab3c4ba907f9506e3cb518fb9e7f,0366cde05cef3c6323d21e92b4f8596eb6a34a84..9609eaa77f1dad589700bda222e0a81ad4f4d1ee
@@@ -7,7 -7,7 +7,7 @@@
  /*
   * See if our compiler is known to support flexible array members.
   */
 -#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)
 +#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) && (!defined(__SUNPRO_C) || (__SUNPRO_C > 0x580))
  # define FLEX_ARRAY /* empty */
  #elif defined(__GNUC__)
  # if (__GNUC__ >= 3)
  /* Approximation of the length of the decimal representation of this type. */
  #define decimal_length(x)     ((int)(sizeof(x) * 2.56 + 0.5) + 1)
  
 -#if !defined(__APPLE__) && !defined(__FreeBSD__)  && !defined(__USLC__) && !defined(_M_UNIX)
 +#if defined(__sun__)
 + /*
 +  * On Solaris, when _XOPEN_EXTENDED is set, its header file
 +  * forces the programs to be XPG4v2, defeating any _XOPEN_SOURCE
 +  * setting to say we are XPG5 or XPG6.  Also on Solaris,
 +  * XPG6 programs must be compiled with a c99 compiler, while
 +  * non XPG6 programs must be compiled with a pre-c99 compiler.
 +  */
 +# if __STDC_VERSION__ - 0 >= 199901L
 +# define _XOPEN_SOURCE 600
 +# else
 +# define _XOPEN_SOURCE 500
 +# endif
 +#elif !defined(__APPLE__) && !defined(__FreeBSD__)  && !defined(__USLC__) && !defined(_M_UNIX)
  #define _XOPEN_SOURCE 600 /* glibc2 and AIX 5.3L need 500, OpenBSD needs 600 for S_ISLNK() */
  #ifndef __sun__
  #define _XOPEN_SOURCE_EXTENDED 1 /* AIX 5.3L needs this */
@@@ -175,6 -162,7 +175,7 @@@ extern char *gitbasename(char *)
  /* General helper functions */
  extern void usage(const char *err) NORETURN;
  extern void die(const char *err, ...) NORETURN __attribute__((format (printf, 1, 2)));
+ extern void die_errno(const char *err, ...) NORETURN __attribute__((format (printf, 1, 2)));
  extern int error(const char *err, ...) __attribute__((format (printf, 1, 2)));
  extern void warning(const char *err, ...) __attribute__((format (printf, 1, 2)));
  
diff --combined git.c
index f4d53f40deb152db15f05460860af74b00ad9619,b035676e9392931655a97900d1aa2aef53facaf4..9acce91850d32a6829fd7119e6b7830796624628
--- 1/git.c
--- 2/git.c
+++ b/git.c
@@@ -188,9 -188,10 +188,9 @@@ static int handle_alias(int *argcp, con
                                  alias_command);
  
                new_argv = xrealloc(new_argv, sizeof(char *) *
 -                                  (count + *argcp + 1));
 +                                  (count + *argcp));
                /* insert after command name */
                memcpy(new_argv + count, *argv + 1, sizeof(char *) * *argcp);
 -              new_argv[count+*argcp] = NULL;
  
                *argv = new_argv;
                *argcp += count - 1;
        }
  
        if (subdir && chdir(subdir))
-               die("Cannot change to %s: %s", subdir, strerror(errno));
+               die_errno("Cannot change to '%s'", subdir);
  
        errno = saved_errno;
  
@@@ -256,11 -257,11 +256,11 @@@ static int run_builtin(struct cmd_struc
  
        /* Check for ENOSPC and EIO errors.. */
        if (fflush(stdout))
-               die("write failure on standard output: %s", strerror(errno));
+               die_errno("write failure on standard output");
        if (ferror(stdout))
                die("unknown write failure on standard output");
        if (fclose(stdout))
-               die("close failed on standard output: %s", strerror(errno));
+               die_errno("close failed on standard output");
        return 0;
  }
  
diff --combined index-pack.c
index c72cbd406a7880361f262f43daff62a9f453628d,cf6446fc43e008437ab03eb79f2186af3970df3d..340074fc793e8e7534bb168784a7051af6d81b34
@@@ -143,7 -143,7 +143,7 @@@ static void *fill(int min
                if (ret <= 0) {
                        if (!ret)
                                die("early EOF");
-                       die("read error on input: %s", strerror(errno));
+                       die_errno("read error on input");
                }
                input_len += ret;
                if (from_stdin)
@@@ -178,13 -178,12 +178,12 @@@ static char *open_pack_file(char *pack_
                } else
                        output_fd = open(pack_name, O_CREAT|O_EXCL|O_RDWR, 0600);
                if (output_fd < 0)
-                       die("unable to create %s: %s", pack_name, strerror(errno));
+                       die_errno("unable to create '%s'", pack_name);
                pack_fd = output_fd;
        } else {
                input_fd = open(pack_name, O_RDONLY);
                if (input_fd < 0)
-                       die("cannot open packfile '%s': %s",
-                           pack_name, strerror(errno));
+                       die_errno("cannot open packfile '%s'", pack_name);
                output_fd = -1;
                pack_fd = input_fd;
        }
@@@ -293,8 -292,8 +292,8 @@@ static void *unpack_entry_data(unsigne
  
  static void *unpack_raw_entry(struct object_entry *obj, union delta_base *delta_base)
  {
 -      unsigned char *p, c;
 -      unsigned long size;
 +      unsigned char *p;
 +      unsigned long size, c;
        off_t base_offset;
        unsigned shift;
        void *data;
                p = fill(1);
                c = *p;
                use(1);
 -              size += (c & 0x7fUL) << shift;
 +              size += (c & 0x7f) << shift;
                shift += 7;
        }
        obj->size = size;
@@@ -370,7 -369,7 +369,7 @@@ static void *get_data_from_pack(struct 
        do {
                ssize_t n = pread(pack_fd, data + rdy, len - rdy, from + rdy);
                if (n < 0)
-                       die("cannot pread pack file: %s", strerror(errno));
+                       die_errno("cannot pread pack file");
                if (!n)
                        die("premature end of pack file, %lu bytes missing",
                            len - rdy);
@@@ -469,7 -468,7 +468,7 @@@ static void sha1_object(const void *dat
                                die("invalid %s", typename(type));
                        if (fsck_object(obj, 1, fsck_error_function))
                                die("Error in object");
 -                      if (fsck_walk(obj, mark_link, 0))
 +                      if (fsck_walk(obj, mark_link, NULL))
                                die("Not all child objects of %s are reachable", sha1_to_hex(obj->sha1));
  
                        if (obj->type == OBJ_TREE) {
@@@ -631,7 -630,7 +630,7 @@@ static void parse_pack_objects(unsigne
  
        /* If input_fd is a file, we should have reached its end now. */
        if (fstat(input_fd, &st))
-               die("cannot fstat packfile: %s", strerror(errno));
+               die_errno("cannot fstat packfile");
        if (S_ISREG(st.st_mode) &&
                        lseek(input_fd, 0, SEEK_CUR) - input_len != st.st_size)
                die("pack has junk at the end");
@@@ -788,7 -787,7 +787,7 @@@ static void final(const char *final_pac
                fsync_or_die(output_fd, curr_pack_name);
                err = close(output_fd);
                if (err)
-                       die("error while closing pack file: %s", strerror(errno));
+                       die_errno("error while closing pack file");
        }
  
        if (keep_msg) {
  
                if (keep_fd < 0) {
                        if (errno != EEXIST)
-                               die("cannot write keep file '%s' (%s)",
-                                   keep_name, strerror(errno));
+                               die_errno("cannot write keep file '%s'",
+                                         keep_name);
                } else {
                        if (keep_msg_len > 0) {
                                write_or_die(keep_fd, keep_msg, keep_msg_len);
                                write_or_die(keep_fd, "\n", 1);
                        }
                        if (close(keep_fd) != 0)
-                               die("cannot close written keep file '%s' (%s)",
-                                   keep_name, strerror(errno));
+                               die_errno("cannot close written keep file '%s'",
+                                   keep_name);
                        report = "keep";
                }
        }
diff --combined ll-merge.c
index a2c13c4c087f7b4961f0507783d34d19ff4b2921,caf22be92723f3a00a70a0b8ce7aab05dc235dcb..0571564ddfb336247c8268fbdecd8674d8bacd3e
@@@ -55,7 -55,7 +55,7 @@@ static int ll_binary_merge(const struc
  
  static int ll_xdl_merge(const struct ll_merge_driver *drv_unused,
                        mmbuffer_t *result,
 -                      const char *path_unused,
 +                      const char *path,
                        mmfile_t *orig,
                        mmfile_t *src1, const char *name1,
                        mmfile_t *src2, const char *name2,
        if (buffer_is_binary(orig->ptr, orig->size) ||
            buffer_is_binary(src1->ptr, src1->size) ||
            buffer_is_binary(src2->ptr, src2->size)) {
 -              warning("Cannot merge binary files: %s vs. %s\n",
 -                      name1, name2);
 +              warning("Cannot merge binary files: %s (%s vs. %s)\n",
 +                      path, name1, name2);
                return ll_binary_merge(drv_unused, result,
 -                                     path_unused,
 +                                     path,
                                       orig, src1, name1,
                                       src2, name2,
                                       virtual_ancestor);
@@@ -152,7 -152,7 +152,7 @@@ static void create_temp(mmfile_t *src, 
        strcpy(path, ".merge_file_XXXXXX");
        fd = xmkstemp(path);
        if (write_in_full(fd, src->ptr, src->size) != src->size)
-               die("unable to write temp-file");
+               die_errno("unable to write temp-file");
        close(fd);
  }
  
@@@ -175,7 -175,8 +175,7 @@@ static int ll_ext_merge(const struct ll
                { "B", temp[2] },
                { NULL }
        };
 -      struct child_process child;
 -      const char *args[20];
 +      const char *args[] = { "sh", "-c", NULL, NULL };
        int status, fd, i;
        struct stat st;
  
  
        strbuf_expand(&cmd, fn->cmdline, strbuf_expand_dict_cb, &dict);
  
 -      memset(&child, 0, sizeof(child));
 -      child.argv = args;
 -      args[0] = "sh";
 -      args[1] = "-c";
        args[2] = cmd.buf;
 -      args[3] = NULL;
 -
 -      status = run_command(&child);
 +      status = run_command_v_opt(args, 0);
        if (status < -ERR_RUN_COMMAND_FORK)
                ; /* failure in run-command */
        else
@@@ -231,7 -238,7 +231,7 @@@ static int read_merge_config(const cha
  
        if (!strcmp(var, "merge.default")) {
                if (value)
 -                      default_ll_merge = strdup(value);
 +                      default_ll_merge = xstrdup(value);
                return 0;
        }
  
        if (!strcmp("name", ep)) {
                if (!value)
                        return error("%s: lacks value", var);
 -              fn->description = strdup(value);
 +              fn->description = xstrdup(value);
                return 0;
        }
  
                 * file named by %A, and signal that it has done with zero exit
                 * status.
                 */
 -              fn->cmdline = strdup(value);
 +              fn->cmdline = xstrdup(value);
                return 0;
        }
  
        if (!strcmp("recursive", ep)) {
                if (!value)
                        return error("%s: lacks value", var);
 -              fn->recursive = strdup(value);
 +              fn->recursive = xstrdup(value);
                return 0;
        }
  
diff --combined merge-recursive.c
index 53cad9605bf1bb599b9c0ceb14788afa719dd5ac,5d9140b8d615825c2da344be43d5731992198e7f..d415c4188d181fbdc765fff90fbbc4897ced53ad
@@@ -38,7 -38,7 +38,7 @@@ static struct tree *shift_tree_object(s
   * A virtual commit has (const char *)commit->util set to the name.
   */
  
 -struct commit *make_virtual_commit(struct tree *tree, const char *comment)
 +static struct commit *make_virtual_commit(struct tree *tree, const char *comment)
  {
        struct commit *commit = xcalloc(1, sizeof(struct commit));
        commit->tree = tree;
@@@ -438,7 -438,7 +438,7 @@@ static void flush_buffer(int fd, const 
                        /* Ignore epipe */
                        if (errno == EPIPE)
                                break;
-                       die("merge-recursive: %s", strerror(errno));
+                       die_errno("merge-recursive");
                } else if (!ret) {
                        die("merge-recursive: disk full?");
                }
@@@ -554,7 -554,7 +554,7 @@@ static void update_file_flags(struct me
                                mode = 0666;
                        fd = open(path, O_WRONLY | O_TRUNC | O_CREAT, mode);
                        if (fd < 0)
-                               die("failed to open %s: %s", path, strerror(errno));
+                               die_errno("failed to open '%s'", path);
                        flush_buffer(fd, buf, size);
                        close(fd);
                } else if (S_ISLNK(mode)) {
                        safe_create_leading_directories_const(path);
                        unlink(path);
                        if (symlink(lnk, path))
-                               die("failed to symlink %s: %s", path, strerror(errno));
+                               die_errno("failed to symlink '%s'", path);
                        free(lnk);
                } else
                        die("do not know what to do with %06o %s '%s'",
@@@ -622,13 -622,8 +622,13 @@@ static int merge_3way(struct merge_opti
        char *name1, *name2;
        int merge_status;
  
 -      name1 = xstrdup(mkpath("%s:%s", branch1, a->path));
 -      name2 = xstrdup(mkpath("%s:%s", branch2, b->path));
 +      if (strcmp(a->path, b->path)) {
 +              name1 = xstrdup(mkpath("%s:%s", branch1, a->path));
 +              name2 = xstrdup(mkpath("%s:%s", branch2, b->path));
 +      } else {
 +              name1 = xstrdup(mkpath("%s", branch1));
 +              name2 = xstrdup(mkpath("%s", branch2));
 +      }
  
        fill_mm(one->sha1, &orig);
        fill_mm(a->sha1, &src1);
diff --combined sha1_file.c
index 8f5fe62d545ace21c338cd554c76bac5d5acb431,1964a6d39b87fe0153bf40d8d72a19cb0aea7fe7..4576ff77f3ceec7231b14261f7386abb2289cd5c
@@@ -1162,7 -1162,8 +1162,7 @@@ unsigned long unpack_object_header_buff
                unsigned long len, enum object_type *type, unsigned long *sizep)
  {
        unsigned shift;
 -      unsigned char c;
 -      unsigned long size;
 +      unsigned long size, c;
        unsigned long used = 0;
  
        c = buf[used++];
@@@ -2286,7 -2287,7 +2286,7 @@@ static void close_sha1_file(int fd
        if (fsync_object_files)
                fsync_or_die(fd, "sha1 file");
        if (close(fd) != 0)
-               die("error when closing sha1 file (%s)", strerror(errno));
+               die_errno("error when closing sha1 file");
  }
  
  /* Size of directory component, including the ending '/' */
diff --combined transport.c
index 501a77b2418c4c5f5ca49a9fdecba3165129c1b2,8decd663f1a5de98146f6a2590b8b1eb9ddf1b5b..ccf788de8b59b825abc369911d1a913fd3fe42c3
@@@ -158,7 -158,7 +158,7 @@@ static struct ref *get_refs_via_rsync(s
  
        strbuf_addstr(&temp_dir, git_path("rsync-refs-XXXXXX"));
        if (!mkdtemp(temp_dir.buf))
-               die ("Could not make temporary directory");
+               die_errno ("Could not make temporary directory");
        temp_dir_len = temp_dir.len;
  
        strbuf_addstr(&buf, rsync_url(transport->url));
@@@ -321,7 -321,7 +321,7 @@@ static int rsync_transport_push(struct 
  
        strbuf_addstr(&temp_dir, git_path("rsync-refs-XXXXXX"));
        if (!mkdtemp(temp_dir.buf))
-               die ("Could not make temporary directory");
+               die_errno ("Could not make temporary directory");
        strbuf_addch(&temp_dir, '/');
  
        if (flags & TRANSPORT_PUSH_ALL) {
@@@ -439,7 -439,9 +439,7 @@@ static struct ref *get_refs_via_curl(st
        char *ref_name;
        char *refs_url;
        int i = 0;
 -
 -      struct active_request_slot *slot;
 -      struct slot_results results;
 +      int http_ret;
  
        struct ref *refs = NULL;
        struct ref *ref = NULL;
        refs_url = xmalloc(strlen(transport->url) + 11);
        sprintf(refs_url, "%s/info/refs", transport->url);
  
 -      slot = get_active_slot();
 -      slot->results = &results;
 -      curl_easy_setopt(slot->curl, CURLOPT_FILE, &buffer);
 -      curl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION, fwrite_buffer);
 -      curl_easy_setopt(slot->curl, CURLOPT_URL, refs_url);
 -      curl_easy_setopt(slot->curl, CURLOPT_HTTPHEADER, NULL);
 -
 -      if (start_active_slot(slot)) {
 -              run_active_slot(slot);
 -              if (results.curl_result != CURLE_OK) {
 -                      strbuf_release(&buffer);
 -                      if (missing_target(&results))
 -                              die("%s not found: did you run git update-server-info on the server?", refs_url);
 -                      else
 -                              die("%s download error - %s", refs_url, curl_errorstr);
 -              }
 -      } else {
 -              strbuf_release(&buffer);
 -              die("Unable to start HTTP request");
 +      http_ret = http_get_strbuf(refs_url, &buffer, HTTP_NO_CACHE);
 +      switch (http_ret) {
 +      case HTTP_OK:
 +              break;
 +      case HTTP_MISSING_TARGET:
 +              die("%s not found: did you run git update-server-info on the"
 +                  " server?", refs_url);
 +      default:
 +              http_error(refs_url, http_ret);
 +              die("HTTP request failed");
        }
  
        data = buffer.buf;
                free(ref);
        }
  
 +      strbuf_release(&buffer);
 +      free(refs_url);
        return refs;
  }
  
@@@ -994,6 -1003,7 +994,6 @@@ int transport_push(struct transport *tr
        if (transport->push_refs) {
                struct ref *remote_refs =
                        transport->get_refs_list(transport, 1);
 -              struct ref **remote_tail;
                struct ref *local_refs = get_local_heads();
                int match_flags = MATCH_REFS_NONE;
                int verbose = flags & TRANSPORT_PUSH_VERBOSE;
                if (flags & TRANSPORT_PUSH_MIRROR)
                        match_flags |= MATCH_REFS_MIRROR;
  
 -              remote_tail = &remote_refs;
 -              while (*remote_tail)
 -                      remote_tail = &((*remote_tail)->next);
 -              if (match_refs(local_refs, remote_refs, &remote_tail,
 +              if (match_refs(local_refs, &remote_refs,
                               refspec_nr, refspec, match_flags)) {
                        return -1;
                }