Merge branch 'jk/diff-no-rename-empty'
authorJunio C Hamano <gitster@pobox.com>
Mon, 16 Apr 2012 19:41:49 +0000 (12:41 -0700)
committerJunio C Hamano <gitster@pobox.com>
Mon, 16 Apr 2012 19:41:49 +0000 (12:41 -0700)
Forbids rename detection logic from matching two empty files as renames
during merge-recursive to prevent mismerges.

By Jeff King
* jk/diff-no-rename-empty:
merge-recursive: don't detect renames of empty files
teach diffcore-rename to optionally ignore empty content
make is_empty_blob_sha1 available everywhere
drop casts from users EMPTY_TREE_SHA1_BIN

1  2 
cache.h
diff.c
diff.h
merge-recursive.c
diff --combined cache.h
index a8aceb5aee4fef0d7b06693921dea319690965d6,52805748012f97bb8ef3aa67ecc3b0d611d4cd3c..806bf2b76fbbf7b30b70bad65220d5255a67c69e
+++ b/cache.h
@@@ -708,6 -708,19 +708,19 @@@ static inline void hashclr(unsigned cha
  #define EMPTY_TREE_SHA1_BIN \
         ((const unsigned char *) EMPTY_TREE_SHA1_BIN_LITERAL)
  
+ #define EMPTY_BLOB_SHA1_HEX \
+       "e69de29bb2d1d6434b8b29ae775ad8c2e48c5391"
+ #define EMPTY_BLOB_SHA1_BIN_LITERAL \
+       "\xe6\x9d\xe2\x9b\xb2\xd1\xd6\x43\x4b\x8b" \
+       "\x29\xae\x77\x5a\xd8\xc2\xe4\x8c\x53\x91"
+ #define EMPTY_BLOB_SHA1_BIN \
+       ((const unsigned char *) EMPTY_BLOB_SHA1_BIN_LITERAL)
+ static inline int is_empty_blob_sha1(const unsigned char *sha1)
+ {
+       return !hashcmp(sha1, EMPTY_BLOB_SHA1_BIN);
+ }
  int git_mkstemp(char *path, size_t n, const char *template);
  
  int git_mkstemps(char *path, size_t n, const char *template, int suffix_len);
@@@ -928,22 -941,6 +941,22 @@@ extern const char *fmt_name(const char 
  extern const char *git_editor(void);
  extern const char *git_pager(int stdout_is_tty);
  
 +struct ident_split {
 +      const char *name_begin;
 +      const char *name_end;
 +      const char *mail_begin;
 +      const char *mail_end;
 +      const char *date_begin;
 +      const char *date_end;
 +      const char *tz_begin;
 +      const char *tz_end;
 +};
 +/*
 + * Signals an success with 0, but time part of the result may be NULL
 + * if the input lacks timestamp and zone
 + */
 +extern int split_ident_line(struct ident_split *, const char *, int);
 +
  struct checkout {
        const char *base_dir;
        int base_dir_len;
diff --combined diff.c
index b020c070cac15e7448178db67a480fc311f18ad9,0b70aadc4f973d66460b04cb300c632b61317961..5d6349feb3f8f9483c463961e526767e2f81e4c9
--- 1/diff.c
--- 2/diff.c
+++ b/diff.c
@@@ -989,74 -989,10 +989,74 @@@ static void diff_words_flush(struct emi
                diff_words_show(ecbdata->diff_words);
  }
  
 +static void diff_filespec_load_driver(struct diff_filespec *one)
 +{
 +      /* Use already-loaded driver */
 +      if (one->driver)
 +              return;
 +
 +      if (S_ISREG(one->mode))
 +              one->driver = userdiff_find_by_path(one->path);
 +
 +      /* Fallback to default settings */
 +      if (!one->driver)
 +              one->driver = userdiff_find_by_name("default");
 +}
 +
 +static const char *userdiff_word_regex(struct diff_filespec *one)
 +{
 +      diff_filespec_load_driver(one);
 +      return one->driver->word_regex;
 +}
 +
 +static void init_diff_words_data(struct emit_callback *ecbdata,
 +                               struct diff_options *orig_opts,
 +                               struct diff_filespec *one,
 +                               struct diff_filespec *two)
 +{
 +      int i;
 +      struct diff_options *o = xmalloc(sizeof(struct diff_options));
 +      memcpy(o, orig_opts, sizeof(struct diff_options));
 +
 +      ecbdata->diff_words =
 +              xcalloc(1, sizeof(struct diff_words_data));
 +      ecbdata->diff_words->type = o->word_diff;
 +      ecbdata->diff_words->opt = o;
 +      if (!o->word_regex)
 +              o->word_regex = userdiff_word_regex(one);
 +      if (!o->word_regex)
 +              o->word_regex = userdiff_word_regex(two);
 +      if (!o->word_regex)
 +              o->word_regex = diff_word_regex_cfg;
 +      if (o->word_regex) {
 +              ecbdata->diff_words->word_regex = (regex_t *)
 +                      xmalloc(sizeof(regex_t));
 +              if (regcomp(ecbdata->diff_words->word_regex,
 +                          o->word_regex,
 +                          REG_EXTENDED | REG_NEWLINE))
 +                      die ("Invalid regular expression: %s",
 +                           o->word_regex);
 +      }
 +      for (i = 0; i < ARRAY_SIZE(diff_words_styles); i++) {
 +              if (o->word_diff == diff_words_styles[i].type) {
 +                      ecbdata->diff_words->style =
 +                              &diff_words_styles[i];
 +                      break;
 +              }
 +      }
 +      if (want_color(o->use_color)) {
 +              struct diff_words_style *st = ecbdata->diff_words->style;
 +              st->old.color = diff_get_color_opt(o, DIFF_FILE_OLD);
 +              st->new.color = diff_get_color_opt(o, DIFF_FILE_NEW);
 +              st->ctx.color = diff_get_color_opt(o, DIFF_PLAIN);
 +      }
 +}
 +
  static void free_diff_words_data(struct emit_callback *ecbdata)
  {
        if (ecbdata->diff_words) {
                diff_words_flush(ecbdata);
 +              free (ecbdata->diff_words->opt);
                free (ecbdata->diff_words->minus.text.ptr);
                free (ecbdata->diff_words->minus.orig);
                free (ecbdata->diff_words->plus.text.ptr);
@@@ -2125,6 -2061,20 +2125,6 @@@ static void emit_binary_diff(FILE *file
        emit_binary_diff_body(file, two, one, prefix);
  }
  
 -static void diff_filespec_load_driver(struct diff_filespec *one)
 -{
 -      /* Use already-loaded driver */
 -      if (one->driver)
 -              return;
 -
 -      if (S_ISREG(one->mode))
 -              one->driver = userdiff_find_by_path(one->path);
 -
 -      /* Fallback to default settings */
 -      if (!one->driver)
 -              one->driver = userdiff_find_by_name("default");
 -}
 -
  int diff_filespec_is_binary(struct diff_filespec *one)
  {
        if (one->is_binary == -1) {
@@@ -2150,6 -2100,12 +2150,6 @@@ static const struct userdiff_funcname *
        return one->driver->funcname.pattern ? &one->driver->funcname : NULL;
  }
  
 -static const char *userdiff_word_regex(struct diff_filespec *one)
 -{
 -      diff_filespec_load_driver(one);
 -      return one->driver->word_regex;
 -}
 -
  void diff_set_mnemonic_prefix(struct diff_options *options, const char *a, const char *b)
  {
        if (!options->a_prefix)
@@@ -2336,8 -2292,42 +2336,8 @@@ static void builtin_diff(const char *na
                        xecfg.ctxlen = strtoul(diffopts + 10, NULL, 10);
                else if (!prefixcmp(diffopts, "-u"))
                        xecfg.ctxlen = strtoul(diffopts + 2, NULL, 10);
 -              if (o->word_diff) {
 -                      int i;
 -
 -                      ecbdata.diff_words =
 -                              xcalloc(1, sizeof(struct diff_words_data));
 -                      ecbdata.diff_words->type = o->word_diff;
 -                      ecbdata.diff_words->opt = o;
 -                      if (!o->word_regex)
 -                              o->word_regex = userdiff_word_regex(one);
 -                      if (!o->word_regex)
 -                              o->word_regex = userdiff_word_regex(two);
 -                      if (!o->word_regex)
 -                              o->word_regex = diff_word_regex_cfg;
 -                      if (o->word_regex) {
 -                              ecbdata.diff_words->word_regex = (regex_t *)
 -                                      xmalloc(sizeof(regex_t));
 -                              if (regcomp(ecbdata.diff_words->word_regex,
 -                                              o->word_regex,
 -                                              REG_EXTENDED | REG_NEWLINE))
 -                                      die ("Invalid regular expression: %s",
 -                                                      o->word_regex);
 -                      }
 -                      for (i = 0; i < ARRAY_SIZE(diff_words_styles); i++) {
 -                              if (o->word_diff == diff_words_styles[i].type) {
 -                                      ecbdata.diff_words->style =
 -                                              &diff_words_styles[i];
 -                                      break;
 -                              }
 -                      }
 -                      if (want_color(o->use_color)) {
 -                              struct diff_words_style *st = ecbdata.diff_words->style;
 -                              st->old.color = diff_get_color_opt(o, DIFF_FILE_OLD);
 -                              st->new.color = diff_get_color_opt(o, DIFF_FILE_NEW);
 -                              st->ctx.color = diff_get_color_opt(o, DIFF_PLAIN);
 -                      }
 -              }
 +              if (o->word_diff)
 +                      init_diff_words_data(&ecbdata, o, one, two);
                xdi_diff_outf(&mf1, &mf2, fn_out_consume, &ecbdata,
                              &xpp, &xecfg);
                if (o->word_diff)
@@@ -3146,6 -3136,7 +3146,7 @@@ void diff_setup(struct diff_options *op
        options->rename_limit = -1;
        options->dirstat_permille = diff_dirstat_permille_default;
        options->context = 3;
+       DIFF_OPT_SET(options, RENAME_EMPTY);
  
        options->change = diff_change;
        options->add_remove = diff_addremove;
@@@ -3516,6 -3507,10 +3517,10 @@@ int diff_opt_parse(struct diff_options 
        }
        else if (!strcmp(arg, "--no-renames"))
                options->detect_rename = 0;
+       else if (!strcmp(arg, "--rename-empty"))
+               DIFF_OPT_SET(options, RENAME_EMPTY);
+       else if (!strcmp(arg, "--no-rename-empty"))
+               DIFF_OPT_CLR(options, RENAME_EMPTY);
        else if (!strcmp(arg, "--relative"))
                DIFF_OPT_SET(options, RELATIVE_NAME);
        else if (!prefixcmp(arg, "--relative=")) {
        else if (!strcmp(arg, "--ignore-space-at-eol"))
                DIFF_XDL_SET(options, IGNORE_WHITESPACE_AT_EOL);
        else if (!strcmp(arg, "--patience"))
 -              DIFF_XDL_SET(options, PATIENCE_DIFF);
 +              options->xdl_opts = DIFF_WITH_ALG(options, PATIENCE_DIFF);
        else if (!strcmp(arg, "--histogram"))
 -              DIFF_XDL_SET(options, HISTOGRAM_DIFF);
 +              options->xdl_opts = DIFF_WITH_ALG(options, HISTOGRAM_DIFF);
  
        /* flags options */
        else if (!strcmp(arg, "--binary")) {
diff --combined diff.h
index e9e3d44c674a39bb1912ca366ca12512dfb4d2c7,dd48eca71ddf1a8709135f158520c8bb7cd5f8d1..870dc91db8fa1ff23c60135ebfc42106f4c0464e
--- 1/diff.h
--- 2/diff.h
+++ b/diff.h
@@@ -60,7 -60,7 +60,7 @@@ typedef struct strbuf *(*diff_prefix_fn
  #define DIFF_OPT_SILENT_ON_REMOVE    (1 <<  5)
  #define DIFF_OPT_FIND_COPIES_HARDER  (1 <<  6)
  #define DIFF_OPT_FOLLOW_RENAMES      (1 <<  7)
- /* (1 <<  8) unused */
+ #define DIFF_OPT_RENAME_EMPTY        (1 <<  8)
  /* (1 <<  9) unused */
  #define DIFF_OPT_HAS_CHANGES         (1 << 10)
  #define DIFF_OPT_QUICK               (1 << 11)
@@@ -91,8 -91,6 +91,8 @@@
  #define DIFF_XDL_SET(opts, flag)    ((opts)->xdl_opts |= XDF_##flag)
  #define DIFF_XDL_CLR(opts, flag)    ((opts)->xdl_opts &= ~XDF_##flag)
  
 +#define DIFF_WITH_ALG(opts, flag)   (((opts)->xdl_opts & ~XDF_DIFF_ALGORITHM_MASK) | XDF_##flag)
 +
  enum diff_words_type {
        DIFF_WORDS_NONE = 0,
        DIFF_WORDS_PORCELAIN,
diff --combined merge-recursive.c
index 857f03dc6112ed5bce6b77b7da9535330ea29015,0fb174359ac12ec9dc02078f870f750915557725..680937c39e2dacb7aaa008ee77b34eb9f7c208cb
@@@ -485,6 -485,7 +485,7 @@@ static struct string_list *get_renames(
        renames = xcalloc(1, sizeof(struct string_list));
        diff_setup(&opts);
        DIFF_OPT_SET(&opts, RECURSIVE);
+       DIFF_OPT_CLR(&opts, RENAME_EMPTY);
        opts.detect_rename = DIFF_DETECT_RENAME;
        opts.rename_limit = o->merge_rename_limit >= 0 ? o->merge_rename_limit :
                            o->diff_rename_limit >= 0 ? o->diff_rename_limit :
@@@ -1914,7 -1915,7 +1915,7 @@@ int merge_recursive(struct merge_option
                /* if there is no common ancestor, use an empty tree */
                struct tree *tree;
  
-               tree = lookup_tree((const unsigned char *)EMPTY_TREE_SHA1_BIN);
+               tree = lookup_tree(EMPTY_TREE_SHA1_BIN);
                merged_common_ancestors = make_virtual_commit(tree, "ancestor");
        }
  
@@@ -2068,9 -2069,9 +2069,9 @@@ int parse_merge_opt(struct merge_option
        else if (!prefixcmp(s, "subtree="))
                o->subtree_shift = s + strlen("subtree=");
        else if (!strcmp(s, "patience"))
 -              o->xdl_opts |= XDF_PATIENCE_DIFF;
 +              o->xdl_opts = DIFF_WITH_ALG(o, PATIENCE_DIFF);
        else if (!strcmp(s, "histogram"))
 -              o->xdl_opts |= XDF_HISTOGRAM_DIFF;
 +              o->xdl_opts = DIFF_WITH_ALG(o, HISTOGRAM_DIFF);
        else if (!strcmp(s, "ignore-space-change"))
                o->xdl_opts |= XDF_IGNORE_WHITESPACE_CHANGE;
        else if (!strcmp(s, "ignore-all-space"))