Merge branch 'maint-1.5.1' into maint
authorJunio C Hamano <junkio@cox.net>
Sat, 26 May 2007 08:30:40 +0000 (01:30 -0700)
committerJunio C Hamano <junkio@cox.net>
Sat, 26 May 2007 08:30:40 +0000 (01:30 -0700)
* maint-1.5.1:
Fix git-svn to handle svn not reporting the md5sum of a file, and test.
More echo "$user_message" fixes.
Add tests for the last two fixes.
git-commit: use printf '%s\n' instead of echo on user-supplied strings
git-am: use printf instead of echo on user-supplied strings
Documentation: Add definition of "evil merge" to GIT Glossary
Replace the last 'dircache's by 'index'
Documentation: Clean up links in GIT Glossary

1  2 
Documentation/git-ls-files.txt
diff.c
git-commit.sh
git-merge.sh
index 076cebca1747ed8e35b71aefa2cae9d428a0d1e4,b7c8ab5f7a3f4a494af4f1d9350e511653bfe67f..43e0d2266c04e6039095dbee709d736275b02838
@@@ -42,8 -42,8 +42,8 @@@ OPTION
        Show other files in the output
  
  -i|--ignored::
 -      Show ignored files in the output
 -      Note the this also reverses any exclude list present.
 +      Show ignored files in the output.
 +      Note that this also reverses any exclude list present.
  
  -s|--stage::
        Show stage files in the output
@@@ -124,7 -124,7 +124,7 @@@ which case it outputs
  detailed information on unmerged paths.
  
  For an unmerged path, instead of recording a single mode/SHA1 pair,
- the dircache records up to three such pairs; one from tree O in stage
+ the index records up to three such pairs; one from tree O in stage
  1, A in stage 2, and B in stage 3.  This information can be used by
  the user (or the porcelain) to see what should eventually be recorded at the
  path. (see git-read-tree for more information on state)
diff --combined diff.c
index b23e1906783664103cf9b363a93a35f7d043c8ee,487168be40d6cf68e3b3f0fbd713cd36ced8f1ed..af282ddd8818aacdc516ff6f9dff4d84097cbab0
--- 1/diff.c
--- 2/diff.c
+++ b/diff.c
@@@ -8,7 -8,6 +8,7 @@@
  #include "delta.h"
  #include "xdiff-interface.h"
  #include "color.h"
 +#include "attr.h"
  
  #ifdef NO_FAST_WORKING_DIRECTORY
  #define FAST_WORKING_DIRECTORY 0
@@@ -16,6 -15,8 +16,6 @@@
  #define FAST_WORKING_DIRECTORY 1
  #endif
  
 -static int use_size_cache;
 -
  static int diff_detect_rename_default;
  static int diff_rename_limit_default = -1;
  static int diff_use_color_default;
@@@ -50,49 -51,6 +50,49 @@@ static int parse_diff_color_slot(const 
        die("bad config variable '%s'", var);
  }
  
 +static struct ll_diff_driver {
 +      const char *name;
 +      struct ll_diff_driver *next;
 +      char *cmd;
 +} *user_diff, **user_diff_tail;
 +
 +/*
 + * Currently there is only "diff.<drivername>.command" variable;
 + * because there are "diff.color.<slot>" variables, we are parsing
 + * this in a bit convoluted way to allow low level diff driver
 + * called "color".
 + */
 +static int parse_lldiff_command(const char *var, const char *ep, const char *value)
 +{
 +      const char *name;
 +      int namelen;
 +      struct ll_diff_driver *drv;
 +
 +      name = var + 5;
 +      namelen = ep - name;
 +      for (drv = user_diff; drv; drv = drv->next)
 +              if (!strncmp(drv->name, name, namelen) && !drv->name[namelen])
 +                      break;
 +      if (!drv) {
 +              char *namebuf;
 +              drv = xcalloc(1, sizeof(struct ll_diff_driver));
 +              namebuf = xmalloc(namelen + 1);
 +              memcpy(namebuf, name, namelen);
 +              namebuf[namelen] = 0;
 +              drv->name = namebuf;
 +              drv->next = NULL;
 +              if (!user_diff_tail)
 +                      user_diff_tail = &user_diff;
 +              *user_diff_tail = drv;
 +              user_diff_tail = &(drv->next);
 +      }
 +
 +      if (!value)
 +              return error("%s: lacks value", var);
 +      drv->cmd = strdup(value);
 +      return 0;
 +}
 +
  /*
   * These are to give UI layer defaults.
   * The core-level commands such as git-diff-files should
@@@ -119,18 -77,11 +119,18 @@@ int git_diff_ui_config(const char *var
                        diff_detect_rename_default = DIFF_DETECT_RENAME;
                return 0;
        }
 +      if (!prefixcmp(var, "diff.")) {
 +              const char *ep = strrchr(var, '.');
 +
 +              if (ep != var + 4 && !strcmp(ep, ".command"))
 +                      return parse_lldiff_command(var, ep, value);
 +      }
        if (!prefixcmp(var, "diff.color.") || !prefixcmp(var, "color.diff.")) {
                int slot = parse_diff_color_slot(var, 11);
                color_parse(value, var, diff_colors[slot]);
                return 0;
        }
 +
        return git_default_config(var, value);
  }
  
@@@ -858,12 -809,7 +858,12 @@@ static void show_stats(struct diffstat_
  
                if (data->files[i]->is_binary) {
                        show_name(prefix, name, len, reset, set);
 -                      printf("  Bin\n");
 +                      printf("  Bin ");
 +                      printf("%s%d%s", del_c, deleted, reset);
 +                      printf(" -> ");
 +                      printf("%s%d%s", add_c, added, reset);
 +                      printf(" bytes");
 +                      printf("\n");
                        goto free_diffstat_file;
                }
                else if (data->files[i]->is_unmerged) {
@@@ -1098,39 -1044,13 +1098,39 @@@ static void emit_binary_diff(mmfile_t *
        emit_binary_diff_body(two, one);
  }
  
 +static void setup_diff_attr_check(struct git_attr_check *check)
 +{
 +      static struct git_attr *attr_diff;
 +
 +      if (!attr_diff)
 +              attr_diff = git_attr("diff", 4);
 +      check->attr = attr_diff;
 +}
 +
  #define FIRST_FEW_BYTES 8000
 -static int mmfile_is_binary(mmfile_t *mf)
 +static int file_is_binary(struct diff_filespec *one)
  {
 -      long sz = mf->size;
 +      unsigned long sz;
 +      struct git_attr_check attr_diff_check;
 +
 +      setup_diff_attr_check(&attr_diff_check);
 +      if (!git_checkattr(one->path, 1, &attr_diff_check)) {
 +              const char *value = attr_diff_check.value;
 +              if (ATTR_TRUE(value))
 +                      return 0;
 +              else if (ATTR_FALSE(value))
 +                      return 1;
 +      }
 +
 +      if (!one->data) {
 +              if (!DIFF_FILE_VALID(one))
 +                      return 0;
 +              diff_populate_filespec(one, 0);
 +      }
 +      sz = one->size;
        if (FIRST_FEW_BYTES < sz)
                sz = FIRST_FEW_BYTES;
 -      return !!memchr(mf->ptr, 0, sz);
 +      return !!memchr(one->data, 0, sz);
  }
  
  static void builtin_diff(const char *name_a,
        if (fill_mmfile(&mf1, one) < 0 || fill_mmfile(&mf2, two) < 0)
                die("unable to read files to diff");
  
 -      if (!o->text && (mmfile_is_binary(&mf1) || mmfile_is_binary(&mf2))) {
 +      if (!o->text && (file_is_binary(one) || file_is_binary(two))) {
                /* Quite common confusing case */
                if (mf1.size == mf2.size &&
                    !memcmp(mf1.ptr, mf2.ptr, mf1.size))
        }
  
   free_ab_and_return:
 +      diff_free_filespec_data(one);
 +      diff_free_filespec_data(two);
        free(a_one);
        free(b_two);
        return;
@@@ -1260,16 -1178,14 +1260,16 @@@ static void builtin_diffstat(const cha
                diff_populate_filespec(two, 0);
                data->deleted = count_lines(one->data, one->size);
                data->added = count_lines(two->data, two->size);
 -              return;
 +              goto free_and_return;
        }
        if (fill_mmfile(&mf1, one) < 0 || fill_mmfile(&mf2, two) < 0)
                die("unable to read files to diff");
  
 -      if (mmfile_is_binary(&mf1) || mmfile_is_binary(&mf2))
 +      if (file_is_binary(one) || file_is_binary(two)) {
                data->is_binary = 1;
 -      else {
 +              data->added = mf2.size;
 +              data->deleted = mf1.size;
 +      } else {
                /* Crazy xdl interfaces.. */
                xpparam_t xpp;
                xdemitconf_t xecfg;
                ecb.priv = diffstat;
                xdl_diff(&mf1, &mf2, &xpp, &xecfg, &ecb);
        }
 +
 + free_and_return:
 +      diff_free_filespec_data(one);
 +      diff_free_filespec_data(two);
  }
  
  static void builtin_checkdiff(const char *name_a, const char *name_b,
        if (fill_mmfile(&mf1, one) < 0 || fill_mmfile(&mf2, two) < 0)
                die("unable to read files to diff");
  
 -      if (mmfile_is_binary(&mf2))
 -              return;
 +      if (file_is_binary(two))
 +              goto free_and_return;
        else {
                /* Crazy xdl interfaces.. */
                xpparam_t xpp;
                ecb.priv = &data;
                xdl_diff(&mf1, &mf2, &xpp, &xecfg, &ecb);
        }
 + free_and_return:
 +      diff_free_filespec_data(one);
 +      diff_free_filespec_data(two);
  }
  
  struct diff_filespec *alloc_filespec(const char *path)
@@@ -1349,7 -1258,7 +1349,7 @@@ void fill_filespec(struct diff_filespe
  }
  
  /*
-  * Given a name and sha1 pair, if the dircache tells us the file in
+  * Given a name and sha1 pair, if the index tells us the file in
   * the work tree has that object contents, return true, so that
   * prepare_temp_file() does not have to inflate and extract.
   */
@@@ -1404,12 -1313,61 +1404,12 @@@ static int reuse_worktree_file(const ch
        return 1;
  }
  
 -static struct sha1_size_cache {
 -      unsigned char sha1[20];
 -      unsigned long size;
 -} **sha1_size_cache;
 -static int sha1_size_cache_nr, sha1_size_cache_alloc;
 -
 -static struct sha1_size_cache *locate_size_cache(unsigned char *sha1,
 -                                               int find_only,
 -                                               unsigned long size)
 -{
 -      int first, last;
 -      struct sha1_size_cache *e;
 -
 -      first = 0;
 -      last = sha1_size_cache_nr;
 -      while (last > first) {
 -              int cmp, next = (last + first) >> 1;
 -              e = sha1_size_cache[next];
 -              cmp = hashcmp(e->sha1, sha1);
 -              if (!cmp)
 -                      return e;
 -              if (cmp < 0) {
 -                      last = next;
 -                      continue;
 -              }
 -              first = next+1;
 -      }
 -      /* not found */
 -      if (find_only)
 -              return NULL;
 -      /* insert to make it at "first" */
 -      if (sha1_size_cache_alloc <= sha1_size_cache_nr) {
 -              sha1_size_cache_alloc = alloc_nr(sha1_size_cache_alloc);
 -              sha1_size_cache = xrealloc(sha1_size_cache,
 -                                         sha1_size_cache_alloc *
 -                                         sizeof(*sha1_size_cache));
 -      }
 -      sha1_size_cache_nr++;
 -      if (first < sha1_size_cache_nr)
 -              memmove(sha1_size_cache + first + 1, sha1_size_cache + first,
 -                      (sha1_size_cache_nr - first - 1) *
 -                      sizeof(*sha1_size_cache));
 -      e = xmalloc(sizeof(struct sha1_size_cache));
 -      sha1_size_cache[first] = e;
 -      hashcpy(e->sha1, sha1);
 -      e->size = size;
 -      return e;
 -}
 -
  static int populate_from_stdin(struct diff_filespec *s)
  {
  #define INCREMENT 1024
        char *buf;
        unsigned long size;
 -      int got;
 +      ssize_t got;
  
        size = 0;
        buf = NULL;
        return 0;
  }
  
 +static int diff_populate_gitlink(struct diff_filespec *s, int size_only)
 +{
 +      int len;
 +      char *data = xmalloc(100);
 +      len = snprintf(data, 100,
 +              "Subproject commit %s\n", sha1_to_hex(s->sha1));
 +      s->data = data;
 +      s->size = len;
 +      s->should_free = 1;
 +      if (size_only) {
 +              s->data = NULL;
 +              free(data);
 +      }
 +      return 0;
 +}
 +
  /*
   * While doing rename detection and pickaxe operation, we may need to
   * grab the data for the blob (or file) for our own in-core comparison.
@@@ -1459,15 -1401,11 +1459,15 @@@ int diff_populate_filespec(struct diff_
        if (S_ISDIR(s->mode))
                return -1;
  
 -      if (!use_size_cache)
 -              size_only = 0;
 -
        if (s->data)
 -              return err;
 +              return 0;
 +
 +      if (size_only && 0 < s->size)
 +              return 0;
 +
 +      if (S_ISDIRLNK(s->mode))
 +              return diff_populate_gitlink(s, size_only);
 +
        if (!s->sha1_valid ||
            reuse_worktree_file(s->path, s->sha1, 0)) {
                struct stat st;
                /*
                 * Convert from working tree format to canonical git format
                 */
 -              buf = s->data;
                size = s->size;
 -              if (convert_to_git(s->path, &buf, &size)) {
 +              buf = convert_to_git(s->path, s->data, &size);
 +              if (buf) {
                        munmap(s->data, s->size);
                        s->should_munmap = 0;
                        s->data = buf;
        }
        else {
                enum object_type type;
 -              struct sha1_size_cache *e;
 -
 -              if (size_only && use_size_cache &&
 -                  (e = locate_size_cache(s->sha1, 1, 0)) != NULL) {
 -                      s->size = e->size;
 -                      return 0;
 -              }
 -
 -              if (size_only) {
 +              if (size_only)
                        type = sha1_object_info(s->sha1, &s->size);
 -                      if (use_size_cache && 0 < type)
 -                              locate_size_cache(s->sha1, 0, s->size);
 -              }
                else {
                        s->data = read_sha1_file(s->sha1, &type, &s->size);
                        s->should_free = 1;
@@@ -1542,11 -1491,8 +1542,11 @@@ void diff_free_filespec_data(struct dif
                free(s->data);
        else if (s->should_munmap)
                munmap(s->data, s->size);
 -      s->should_free = s->should_munmap = 0;
 -      s->data = NULL;
 +
 +      if (s->should_free || s->should_munmap) {
 +              s->should_free = s->should_munmap = 0;
 +              s->data = NULL;
 +      }
        free(s->cnt_data);
        s->cnt_data = NULL;
  }
@@@ -1746,30 -1692,6 +1746,30 @@@ static void run_external_diff(const cha
        }
  }
  
 +static const char *external_diff_attr(const char *name)
 +{
 +      struct git_attr_check attr_diff_check;
 +
 +      setup_diff_attr_check(&attr_diff_check);
 +      if (!git_checkattr(name, 1, &attr_diff_check)) {
 +              const char *value = attr_diff_check.value;
 +              if (!ATTR_TRUE(value) &&
 +                  !ATTR_FALSE(value) &&
 +                  !ATTR_UNSET(value)) {
 +                      struct ll_diff_driver *drv;
 +
 +                      if (!user_diff_tail) {
 +                              user_diff_tail = &user_diff;
 +                              git_config(git_diff_ui_config);
 +                      }
 +                      for (drv = user_diff; drv; drv = drv->next)
 +                              if (!strcmp(drv->name, value))
 +                                      return drv->cmd;
 +              }
 +      }
 +      return NULL;
 +}
 +
  static void run_diff_cmd(const char *pgm,
                         const char *name,
                         const char *other,
                         struct diff_options *o,
                         int complete_rewrite)
  {
 +      if (!o->allow_external)
 +              pgm = NULL;
 +      else {
 +              const char *cmd = external_diff_attr(name);
 +              if (cmd)
 +                      pgm = cmd;
 +      }
 +
        if (pgm) {
                run_external_diff(pgm, name, other, one, two, xfrm_msg,
                                  complete_rewrite);
@@@ -1883,8 -1797,8 +1883,8 @@@ static void run_diff(struct diff_filepa
  
                if (o->binary) {
                        mmfile_t mf;
 -                      if ((!fill_mmfile(&mf, one) && mmfile_is_binary(&mf)) ||
 -                          (!fill_mmfile(&mf, two) && mmfile_is_binary(&mf)))
 +                      if ((!fill_mmfile(&mf, one) && file_is_binary(one)) ||
 +                          (!fill_mmfile(&mf, two) && file_is_binary(two)))
                                abbrev = 40;
                }
                len += snprintf(msg + len, sizeof(msg) - len,
@@@ -2038,6 -1952,8 +2038,6 @@@ int diff_setup_done(struct diff_option
                         */
                        read_cache();
        }
 -      if (options->setup & DIFF_SETUP_USE_SIZE_CACHE)
 -              use_size_cache = 1;
        if (options->abbrev <= 0 || 40 < options->abbrev)
                options->abbrev = 40; /* full */
  
@@@ -2777,7 -2693,7 +2777,7 @@@ static int diff_get_patch_id(struct dif
                        return error("unable to read files to diff");
  
                /* Maybe hash p->two? into the patch id? */
 -              if (mmfile_is_binary(&mf2))
 +              if (file_is_binary(p->two))
                        continue;
  
                len1 = remove_space(p->one->path, strlen(p->one->path));
diff --combined git-commit.sh
index f28fc242241d3f0f5c88b287da0c59417667a013,a1884fed25792684a6a54450ba2f445c061118e7..e8b60f70497c71bd66b96115b9bba78cee523a8c
@@@ -370,18 -370,18 +370,18 @@@ t,
                # the same way.
                if test -z "$initial_commit"
                then
 -                      cp "$THIS_INDEX" "$TMP_INDEX"
 -                      GIT_INDEX_FILE="$TMP_INDEX" git-read-tree -i -m HEAD
 +                      GIT_INDEX_FILE="$THIS_INDEX" \
 +                      git-read-tree --index-output="$TMP_INDEX" -i -m HEAD
                else
                        rm -f "$TMP_INDEX"
                fi || exit
  
-               echo "$commit_only" |
+               printf '%s\n' "$commit_only" |
                GIT_INDEX_FILE="$TMP_INDEX" \
                git-update-index --add --remove --stdin &&
  
                save_index &&
-               echo "$commit_only" |
+               printf '%s\n' "$commit_only" |
                (
                        GIT_INDEX_FILE="$NEXT_INDEX"
                        export GIT_INDEX_FILE
@@@ -432,7 -432,7 +432,7 @@@ f
  
  if test "$log_message" != ''
  then
-       echo "$log_message"
+       printf '%s\n' "$log_message"
  elif test "$logfile" != ""
  then
        if test "$logfile" = -
@@@ -475,7 -475,7 +475,7 @@@ if test -f "$GIT_DIR/MERGE_HEAD" && tes
        echo "#"
        echo "# It looks like you may be committing a MERGE."
        echo "# If this is not correct, please remove the file"
-       echo "# $GIT_DIR/MERGE_HEAD"
+       printf '%s\n' "#        $GIT_DIR/MERGE_HEAD"
        echo "# and try again"
        echo "#"
  fi >>"$GIT_DIR"/COMMIT_EDITMSG
@@@ -649,9 -649,8 +649,9 @@@ the
        fi
        if test -z "$quiet"
        then
 +              commit=`git-diff-tree --always --shortstat --pretty="format:%h: %s"\
 +                     --summary --root HEAD --`
                echo "Created${initial_commit:+ initial} commit $commit"
 -              git-diff-tree --shortstat --summary --root --no-commit-id HEAD --
        fi
  fi
  
diff --combined git-merge.sh
index 7ebbce4bdbaf243a7a5612c024216b8ccf8eae44,bf1fd4f06b42ca7c07d7a64fba7921c48d6fd72f..b2f8a2acd398b7c61b68a59c6d3631ca84be0727
@@@ -16,10 -16,10 +16,10 @@@ test -z "$(git ls-files -u)" |
  LF='
  '
  
 -all_strategies='recur recursive octopus resolve stupid ours'
 +all_strategies='recur recursive octopus resolve stupid ours subtree'
  default_twohead_strategies='recursive'
  default_octopus_strategies='octopus'
 -no_trivial_merge_strategies='ours'
 +no_trivial_merge_strategies='ours subtree'
  use_strategies=
  
  index_merge=t
@@@ -328,7 -328,7 +328,7 @@@ f,*
                then
                        echo "Wonderful."
                        result_commit=$(
-                               echo "$merge_msg" |
+                               printf '%s\n' "$merge_msg" |
                                git-commit-tree $result_tree -p HEAD -p "$1"
                        ) || exit
                        finish "$result_commit" "In-index merge"
@@@ -433,7 -433,7 +433,7 @@@ don
  if test '' != "$result_tree"
  then
      parents=$(git-show-branch --independent "$head" "$@" | sed -e 's/^/-p /')
-     result_commit=$(echo "$merge_msg" | git-commit-tree $result_tree $parents) || exit
+     result_commit=$(printf '%s\n' "$merge_msg" | git-commit-tree $result_tree $parents) || exit
      finish "$result_commit" "Merge made by $wt_strategy."
      dropsave
      exit 0
@@@ -472,7 -472,7 +472,7 @@@ els
        do
                echo $remote
        done >"$GIT_DIR/MERGE_HEAD"
-       echo "$merge_msg" >"$GIT_DIR/MERGE_MSG"
+       printf '%s\n' "$merge_msg" >"$GIT_DIR/MERGE_MSG"
  fi
  
  if test "$merge_was_ok" = t