Merge branch 'ar/unconfuse-three-dots'
authorJunio C Hamano <gitster@pobox.com>
Tue, 19 Dec 2017 19:33:58 +0000 (11:33 -0800)
committerJunio C Hamano <gitster@pobox.com>
Tue, 19 Dec 2017 19:33:58 +0000 (11:33 -0800)
Ancient part of codebase still shows dots after an abbreviated
object name just to show that it is not a full object name, but
these ellipses are confusing to people who newly discovered Git
who are used to seeing abbreviated object names and find them
confusing with the range syntax.

* ar/unconfuse-three-dots:
t2020: test variations that matter
t4013: test new output from diff --abbrev --raw
diff: diff_aligned_abbrev: remove ellipsis after abbreviated SHA-1 value
t4013: prepare for upcoming "diff --raw --abbrev" output format change
checkout: describe_detached_head: remove ellipsis after committish
print_sha1_ellipsis: introduce helper
Documentation: user-manual: limit usage of ellipsis
Documentation: revisions: fix typo: "three dot" ---> "three-dot" (in line with "two-dot").

1  2 
Documentation/git.txt
builtin/checkout.c
cache.h
diff.c
environment.c
diff --combined Documentation/git.txt
index e75db104e3a33dde93a98cc09de97f4d4f0bc5eb,6ec871b91057869801f48e9a07c3f027b9383db2..3f4161a799300c55e17fec86e2debe503e6ec903
@@@ -522,10 -522,11 +522,10 @@@ othe
        If either of these environment variables is set then 'git fetch'
        and 'git push' will use the specified command instead of 'ssh'
        when they need to connect to a remote system.
 -      The command will be given exactly two or four arguments: the
 -      'username@host' (or just 'host') from the URL and the shell
 -      command to execute on that remote system, optionally preceded by
 -      `-p` (literally) and the 'port' from the URL when it specifies
 -      something other than the default SSH port.
 +      The command-line parameters passed to the configured command are
 +      determined by the ssh variant.  See `ssh.variant` option in
 +      linkgit:git-config[1] for details.
 +
  +
  `$GIT_SSH_COMMAND` takes precedence over `$GIT_SSH`, and is interpreted
  by the shell, which allows additional arguments to be included.
@@@ -594,10 -595,6 +594,10 @@@ into it
  Unsetting the variable, or setting it to empty, "0" or
  "false" (case insensitive) disables trace messages.
  
 +`GIT_TRACE_FSMONITOR`::
 +      Enables trace messages for the filesystem monitor extension.
 +      See `GIT_TRACE` for available trace output options.
 +
  `GIT_TRACE_PACK_ACCESS`::
        Enables trace messages for all accesses to any packs. For each
        access, the pack file name and an offset in the pack is
@@@ -704,12 -701,6 +704,12 @@@ of clones and fetches
        which feed potentially-untrusted URLS to git commands.  See
        linkgit:git-config[1] for more details.
  
 +`GIT_PROTOCOL`::
 +      For internal use only.  Used in handshaking the wire protocol.
 +      Contains a colon ':' separated list of keys with optional values
 +      'key[=value]'.  Presence of unknown keys and values must be
 +      ignored.
 +
  `GIT_OPTIONAL_LOCKS`::
        If set to `0`, Git will complete any requested operation without
        performing any optional sub-operations that require taking a lock.
        the background which do not want to cause lock contention with
        other operations on the repository.  Defaults to `1`.
  
 +`GIT_REDIRECT_STDIN`::
 +`GIT_REDIRECT_STDOUT`::
 +`GIT_REDIRECT_STDERR`::
 +      Windows-only: allow redirecting the standard input/output/error
 +      handles to paths specified by the environment variables. This is
 +      particularly useful in multi-threaded applications where the
 +      canonical way to pass standard handles via `CreateProcess()` is
 +      not an option because it would require the handles to be marked
 +      inheritable (and consequently *every* spawned process would
 +      inherit them, possibly blocking regular Git operations). The
 +      primary intended use case is to use named pipes for communication
 +      (e.g. `\\.\pipe\my-git-stdin-123`).
 ++
 +Two special values are supported: `off` will simply close the
 +corresponding standard handle, and if `GIT_REDIRECT_STDERR` is
 +`2>&1`, standard error will be redirected to the same handle as
 +standard output.
 +
+ `GIT_PRINT_SHA1_ELLIPSIS` (deprecated)::
+       If set to `yes`, print an ellipsis following an
+       (abbreviated) SHA-1 value.  This affects indications of
+       detached HEADs (linkgit:git-checkout[1]) and the raw
+       diff output (linkgit:git-diff[1]).  Printing an
+       ellipsis in the cases mentioned is no longer considered
+       adequate and support for it is likely to be removed in the
+       foreseeable future (along with the variable).
  Discussion[[Discussion]]
  ------------------------
  
diff --combined builtin/checkout.c
index 9b886356bff5005a2775e5d2cbe998df1d3d5cf1,6a6f5bcb2af2c7abe644bddeeb752e5955d878d7..f9f3797e1191291c48609b01cf5c388ff86d0def
@@@ -1,6 -1,5 +1,6 @@@
  #include "builtin.h"
  #include "config.h"
 +#include "checkout.h"
  #include "lockfile.h"
  #include "parse-options.h"
  #include "refs.h"
@@@ -401,10 -400,16 +401,16 @@@ static void show_local_changes(struct o
  static void describe_detached_head(const char *msg, struct commit *commit)
  {
        struct strbuf sb = STRBUF_INIT;
        if (!parse_commit(commit))
                pp_commit_easy(CMIT_FMT_ONELINE, commit, &sb);
-       fprintf(stderr, "%s %s... %s\n", msg,
-               find_unique_abbrev(commit->object.oid.hash, DEFAULT_ABBREV), sb.buf);
+       if (print_sha1_ellipsis()) {
+               fprintf(stderr, "%s %s... %s\n", msg,
+                       find_unique_abbrev(commit->object.oid.hash, DEFAULT_ABBREV), sb.buf);
+       } else {
+               fprintf(stderr, "%s %s %s\n", msg,
+                       find_unique_abbrev(commit->object.oid.hash, DEFAULT_ABBREV), sb.buf);
+       }
        strbuf_release(&sb);
  }
  
@@@ -515,7 -520,7 +521,7 @@@ static int merge_working_tree(const str
                }
                tree = parse_tree_indirect(old->commit ?
                                           &old->commit->object.oid :
 -                                         &empty_tree_oid);
 +                                         the_hash_algo->empty_tree);
                init_tree_desc(&trees[0], tree->buffer, tree->size);
                tree = parse_tree_indirect(&new->commit->object.oid);
                init_tree_desc(&trees[1], tree->buffer, tree->size);
@@@ -664,7 -669,7 +670,7 @@@ static void update_refs_for_switch(cons
                /* Nothing to do. */
        } else if (opts->force_detach || !new->path) {  /* No longer on any branch. */
                update_ref(msg.buf, "HEAD", &new->commit->object.oid, NULL,
 -                         REF_NODEREF, UPDATE_REFS_DIE_ON_ERR);
 +                         REF_NO_DEREF, UPDATE_REFS_DIE_ON_ERR);
                if (!opts->quiet) {
                        if (old->path &&
                            advice_detached_head && !opts->force_detach)
@@@ -873,6 -878,46 +879,6 @@@ static int git_checkout_config(const ch
        return git_xmerge_config(var, value, NULL);
  }
  
 -struct tracking_name_data {
 -      /* const */ char *src_ref;
 -      char *dst_ref;
 -      struct object_id *dst_oid;
 -      int unique;
 -};
 -
 -static int check_tracking_name(struct remote *remote, void *cb_data)
 -{
 -      struct tracking_name_data *cb = cb_data;
 -      struct refspec query;
 -      memset(&query, 0, sizeof(struct refspec));
 -      query.src = cb->src_ref;
 -      if (remote_find_tracking(remote, &query) ||
 -          get_oid(query.dst, cb->dst_oid)) {
 -              free(query.dst);
 -              return 0;
 -      }
 -      if (cb->dst_ref) {
 -              free(query.dst);
 -              cb->unique = 0;
 -              return 0;
 -      }
 -      cb->dst_ref = query.dst;
 -      return 0;
 -}
 -
 -static const char *unique_tracking_name(const char *name, struct object_id *oid)
 -{
 -      struct tracking_name_data cb_data = { NULL, NULL, NULL, 1 };
 -      cb_data.src_ref = xstrfmt("refs/heads/%s", name);
 -      cb_data.dst_oid = oid;
 -      for_each_remote(check_tracking_name, &cb_data);
 -      free(cb_data.src_ref);
 -      if (cb_data.unique)
 -              return cb_data.dst_ref;
 -      free(cb_data.dst_ref);
 -      return NULL;
 -}
 -
  static int parse_branchname_arg(int argc, const char **argv,
                                int dwim_new_local_branch_ok,
                                struct branch_info *new,
@@@ -1248,11 -1293,11 +1254,11 @@@ int cmd_checkout(int argc, const char *
        if (opts.new_branch) {
                struct strbuf buf = STRBUF_INIT;
  
 -              opts.branch_exists =
 -                      validate_new_branchname(opts.new_branch, &buf,
 -                                              !!opts.new_branch_force,
 -                                              !!opts.new_branch_force);
 -
 +              if (opts.new_branch_force)
 +                      opts.branch_exists = validate_branchname(opts.new_branch, &buf);
 +              else
 +                      opts.branch_exists =
 +                              validate_new_branchname(opts.new_branch, &buf, 0);
                strbuf_release(&buf);
        }
  
diff --combined cache.h
index d3e240228c9c488f78ee9be06c9d151f1d2325b2,100317823e03b517db8c809f85cbd58dcb90f06c..3d00d03d92bc205fea39bb147b51c69f35faa307
+++ b/cache.h
@@@ -14,7 -14,6 +14,7 @@@
  #include "hash.h"
  #include "path.h"
  #include "sha1-array.h"
 +#include "repository.h"
  
  #ifndef platform_SHA_CTX
  /*
@@@ -78,8 -77,6 +78,8 @@@ struct object_id 
        unsigned char hash[GIT_MAX_RAWSZ];
  };
  
 +#define the_hash_algo the_repository->hash_algo
 +
  #if defined(DT_UNKNOWN) && !defined(NO_D_TYPE_IN_DIRENT)
  #define DTYPE(de)     ((de)->d_type)
  #else
@@@ -207,7 -204,6 +207,7 @@@ struct cache_entry 
  #define CE_ADDED             (1 << 19)
  
  #define CE_HASHED            (1 << 20)
 +#define CE_FSMONITOR_VALID   (1 << 21)
  #define CE_WT_REMOVE         (1 << 22) /* remove in work directory */
  #define CE_CONFLICTED        (1 << 23)
  
@@@ -331,7 -327,6 +331,7 @@@ static inline unsigned int canon_mode(u
  #define CACHE_TREE_CHANGED    (1 << 5)
  #define SPLIT_INDEX_ORDERED   (1 << 6)
  #define UNTRACKED_CHANGED     (1 << 7)
 +#define FSMONITOR_CHANGED     (1 << 8)
  
  struct split_index;
  struct untracked_cache;
@@@ -350,8 -345,6 +350,8 @@@ struct index_state 
        struct hashmap dir_hash;
        unsigned char sha1[20];
        struct untracked_cache *untracked;
 +      uint64_t fsmonitor_last_update;
 +      struct ewah_bitmap *fsmonitor_dirty;
  };
  
  extern struct index_state the_index;
@@@ -453,16 -446,6 +453,16 @@@ static inline enum object_type object_t
  #define GIT_QUARANTINE_ENVIRONMENT "GIT_QUARANTINE_PATH"
  #define GIT_OPTIONAL_LOCKS_ENVIRONMENT "GIT_OPTIONAL_LOCKS"
  
 +/*
 + * Environment variable used in handshaking the wire protocol.
 + * Contains a colon ':' separated list of keys with optional values
 + * 'key[=value]'.  Presence of unknown keys and values must be
 + * ignored.
 + */
 +#define GIT_PROTOCOL_ENVIRONMENT "GIT_PROTOCOL"
 +/* HTTP header used to handshake the wire protocol */
 +#define GIT_PROTOCOL_HEADER "Git-Protocol"
 +
  /*
   * This environment variable is expected to contain a boolean indicating
   * whether we should or should not treat:
@@@ -717,14 -700,11 +717,14 @@@ extern void *read_blob_data_from_index(
  #define CE_MATCH_IGNORE_MISSING               0x08
  /* enable stat refresh */
  #define CE_MATCH_REFRESH              0x10
 -extern int ie_match_stat(const struct index_state *, const struct cache_entry *, struct stat *, unsigned int);
 -extern int ie_modified(const struct index_state *, const struct cache_entry *, struct stat *, unsigned int);
 +/* don't refresh_fsmonitor state or do stat comparison even if CE_FSMONITOR_VALID is true */
 +#define CE_MATCH_IGNORE_FSMONITOR 0X20
 +extern int ie_match_stat(struct index_state *, const struct cache_entry *, struct stat *, unsigned int);
 +extern int ie_modified(struct index_state *, const struct cache_entry *, struct stat *, unsigned int);
  
  #define HASH_WRITE_OBJECT 1
  #define HASH_FORMAT_CHECK 2
 +#define HASH_RENORMALIZE  4
  extern int index_fd(struct object_id *oid, int fd, struct stat *st, enum object_type type, const char *path, unsigned flags);
  extern int index_path(struct object_id *oid, const char *path, struct stat *st, unsigned flags);
  
@@@ -765,7 -745,6 +765,7 @@@ extern int hold_locked_index(struct loc
  extern void set_alternate_index_output(const char *);
  
  extern int verify_index_checksum;
 +extern int verify_ce_order;
  
  /* Environment bits from configuration mechanism */
  extern int trust_executable_bit;
@@@ -819,7 -798,6 +819,7 @@@ extern int core_apply_sparse_checkout
  extern int precomposed_unicode;
  extern int protect_hfs;
  extern int protect_ntfs;
 +extern const char *core_fsmonitor;
  
  /*
   * Include broken refs in all ref iterations, which will
@@@ -910,7 -888,6 +910,7 @@@ struct repository_format 
        int version;
        int precious_objects;
        int is_bare;
 +      int hash_algo;
        char *work_tree;
        struct string_list unknown_extensions;
  };
@@@ -1043,22 -1020,22 +1043,22 @@@ extern const struct object_id empty_blo
  
  static inline int is_empty_blob_sha1(const unsigned char *sha1)
  {
 -      return !hashcmp(sha1, EMPTY_BLOB_SHA1_BIN);
 +      return !hashcmp(sha1, the_hash_algo->empty_blob->hash);
  }
  
  static inline int is_empty_blob_oid(const struct object_id *oid)
  {
 -      return !hashcmp(oid->hash, EMPTY_BLOB_SHA1_BIN);
 +      return !oidcmp(oid, the_hash_algo->empty_blob);
  }
  
  static inline int is_empty_tree_sha1(const unsigned char *sha1)
  {
 -      return !hashcmp(sha1, EMPTY_TREE_SHA1_BIN);
 +      return !hashcmp(sha1, the_hash_algo->empty_tree->hash);
  }
  
  static inline int is_empty_tree_oid(const struct object_id *oid)
  {
 -      return !hashcmp(oid->hash, EMPTY_TREE_SHA1_BIN);
 +      return !oidcmp(oid, the_hash_algo->empty_tree);
  }
  
  /* set default permissions by passing mode arguments to open(2) */
@@@ -1363,13 -1340,6 +1363,13 @@@ extern int set_disambiguate_hint_config
  extern int get_sha1_hex(const char *hex, unsigned char *sha1);
  extern int get_oid_hex(const char *hex, struct object_id *sha1);
  
 +/*
 + * Read `len` pairs of hexadecimal digits from `hex` and write the
 + * values to `binary` as `len` bytes. Return 0 on success, or -1 if
 + * the input does not consist of hex digits).
 + */
 +extern int hex_to_bytes(unsigned char *binary, const char *hex, size_t len);
 +
  /*
   * Convert a binary sha1 to its hex equivalent. The `_r` variant is reentrant,
   * and writes the NUL-terminated output to the buffer `out`, which must be at
@@@ -1972,4 -1942,10 +1972,10 @@@ void sleep_millisec(int millisec)
   */
  void safe_create_dir(const char *dir, int share);
  
+ /*
+  * Should we print an ellipsis after an abbreviated SHA-1 value
+  * when doing diff-raw output or indicating a detached HEAD?
+  */
+ extern int print_sha1_ellipsis(void);
  #endif /* CACHE_H */
diff --combined diff.c
index 516f68dbb42298d1c8bb509397f6c2eb6dfc93cb,8c2bf97cb71fc4ab76329836242e4d131b82a266..3fb445a54d94f5f48aabed0fcfd06c378bee6719
--- 1/diff.c
--- 2/diff.c
+++ b/diff.c
@@@ -124,18 -124,18 +124,18 @@@ static int parse_dirstat_params(struct 
        for (i = 0; i < params.nr; i++) {
                const char *p = params.items[i].string;
                if (!strcmp(p, "changes")) {
 -                      DIFF_OPT_CLR(options, DIRSTAT_BY_LINE);
 -                      DIFF_OPT_CLR(options, DIRSTAT_BY_FILE);
 +                      options->flags.dirstat_by_line = 0;
 +                      options->flags.dirstat_by_file = 0;
                } else if (!strcmp(p, "lines")) {
 -                      DIFF_OPT_SET(options, DIRSTAT_BY_LINE);
 -                      DIFF_OPT_CLR(options, DIRSTAT_BY_FILE);
 +                      options->flags.dirstat_by_line = 1;
 +                      options->flags.dirstat_by_file = 0;
                } else if (!strcmp(p, "files")) {
 -                      DIFF_OPT_CLR(options, DIRSTAT_BY_LINE);
 -                      DIFF_OPT_SET(options, DIRSTAT_BY_FILE);
 +                      options->flags.dirstat_by_line = 0;
 +                      options->flags.dirstat_by_file = 1;
                } else if (!strcmp(p, "noncumulative")) {
 -                      DIFF_OPT_CLR(options, DIRSTAT_CUMULATIVE);
 +                      options->flags.dirstat_cumulative = 0;
                } else if (!strcmp(p, "cumulative")) {
 -                      DIFF_OPT_SET(options, DIRSTAT_CUMULATIVE);
 +                      options->flags.dirstat_cumulative = 1;
                } else if (isdigit(*p)) {
                        char *end;
                        int permille = strtoul(p, &end, 10) * 10;
@@@ -1412,7 -1412,7 +1412,7 @@@ static void emit_rewrite_diff(const cha
        struct emit_callback ecbdata;
        struct strbuf out = STRBUF_INIT;
  
 -      if (diff_mnemonic_prefix && DIFF_OPT_TST(o, REVERSE_DIFF)) {
 +      if (diff_mnemonic_prefix && o->flags.reverse_diff) {
                a_prefix = o->b_prefix;
                b_prefix = o->a_prefix;
        } else {
@@@ -2660,7 -2660,7 +2660,7 @@@ static void show_dirstat(struct diff_op
        dir.alloc = 0;
        dir.nr = 0;
        dir.permille = options->dirstat_permille;
 -      dir.cumulative = DIFF_OPT_TST(options, DIRSTAT_CUMULATIVE);
 +      dir.cumulative = options->flags.dirstat_cumulative;
  
        changed = 0;
        for (i = 0; i < q->nr; i++) {
                        goto found_damage;
                }
  
 -              if (DIFF_OPT_TST(options, DIRSTAT_BY_FILE)) {
 +              if (options->flags.dirstat_by_file) {
                        /*
                         * In --dirstat-by-file mode, we don't really need to
                         * look at the actual file contents at all.
@@@ -2761,7 -2761,7 +2761,7 @@@ static void show_dirstat_by_line(struc
        dir.alloc = 0;
        dir.nr = 0;
        dir.permille = options->dirstat_permille;
 -      dir.cumulative = DIFF_OPT_TST(options, DIRSTAT_CUMULATIVE);
 +      dir.cumulative = options->flags.dirstat_cumulative;
  
        changed = 0;
        for (i = 0; i < data->nr; i++) {
@@@ -3048,7 -3048,7 +3048,7 @@@ static void builtin_diff(const char *na
        const char *line_prefix = diff_line_prefix(o);
  
        diff_set_mnemonic_prefix(o, "a/", "b/");
 -      if (DIFF_OPT_TST(o, REVERSE_DIFF)) {
 +      if (o->flags.reverse_diff) {
                a_prefix = o->b_prefix;
                b_prefix = o->a_prefix;
        } else {
                return;
        }
  
 -      if (DIFF_OPT_TST(o, ALLOW_TEXTCONV)) {
 +      if (o->flags.allow_textconv) {
                textconv_one = get_textconv(one);
                textconv_two = get_textconv(two);
        }
                                 header.len, 0);
                strbuf_reset(&header);
                goto free_ab_and_return;
 -      } else if (!DIFF_OPT_TST(o, TEXT) &&
 +      } else if (!o->flags.text &&
            ( (!textconv_one && diff_filespec_is_binary(one)) ||
              (!textconv_two && diff_filespec_is_binary(two)) )) {
                struct strbuf sb = STRBUF_INIT;
                if (!one->data && !two->data &&
                    S_ISREG(one->mode) && S_ISREG(two->mode) &&
 -                  !DIFF_OPT_TST(o, BINARY)) {
 +                  !o->flags.binary) {
                        if (!oidcmp(&one->oid, &two->oid)) {
                                if (must_show_header)
                                        emit_diff_symbol(o, DIFF_SYMBOL_HEADER,
                }
                emit_diff_symbol(o, DIFF_SYMBOL_HEADER, header.buf, header.len, 0);
                strbuf_reset(&header);
 -              if (DIFF_OPT_TST(o, BINARY))
 +              if (o->flags.binary)
                        emit_binary_diff(o, &mf1, &mf2);
                else {
                        strbuf_addf(&sb, "%sBinary files %s and %s differ\n",
                ecbdata.opt = o;
                ecbdata.header = header.len ? &header : NULL;
                xpp.flags = o->xdl_opts;
 +              xpp.anchors = o->anchors;
 +              xpp.anchors_nr = o->anchors_nr;
                xecfg.ctxlen = o->context;
                xecfg.interhunkctxlen = o->interhunkcontext;
                xecfg.flags = XDL_EMIT_FUNCNAMES;
 -              if (DIFF_OPT_TST(o, FUNCCONTEXT))
 +              if (o->flags.funccontext)
                        xecfg.flags |= XDL_EMIT_FUNCCONTEXT;
                if (pe)
                        xdiff_set_find_func(&xecfg, pe->pattern, pe->cflags);
@@@ -3304,8 -3302,6 +3304,8 @@@ static void builtin_diffstat(const cha
                memset(&xpp, 0, sizeof(xpp));
                memset(&xecfg, 0, sizeof(xecfg));
                xpp.flags = o->xdl_opts;
 +              xpp.anchors = o->anchors;
 +              xpp.anchors_nr = o->anchors_nr;
                xecfg.ctxlen = o->context;
                xecfg.interhunkctxlen = o->interhunkcontext;
                if (xdi_diff_outf(&mf1, &mf2, diffstat_consume, diffstat,
@@@ -3382,7 -3378,7 +3382,7 @@@ static void builtin_checkdiff(const cha
        diff_free_filespec_data(one);
        diff_free_filespec_data(two);
        if (data.status)
 -              DIFF_OPT_SET(o, CHECK_FAILED);
 +              o->flags.check_failed = 1;
  }
  
  struct diff_filespec *alloc_filespec(const char *path)
@@@ -3549,12 -3545,14 +3549,12 @@@ int diff_populate_filespec(struct diff_
                int fd;
  
                if (lstat(s->path, &st) < 0) {
 -                      if (errno == ENOENT) {
 -                      err_empty:
 -                              err = -1;
 -                      empty:
 -                              s->data = (char *)"";
 -                              s->size = 0;
 -                              return err;
 -                      }
 +              err_empty:
 +                      err = -1;
 +              empty:
 +                      s->data = (char *)"";
 +                      s->size = 0;
 +                      return err;
                }
                s->size = xsize_t(st.st_size);
                if (!s->size)
@@@ -3874,9 -3872,9 +3874,9 @@@ static void fill_metainfo(struct strbu
                *must_show_header = 0;
        }
        if (one && two && oidcmp(&one->oid, &two->oid)) {
 -              int abbrev = DIFF_OPT_TST(o, FULL_INDEX) ? 40 : DEFAULT_ABBREV;
 +              int abbrev = o->flags.full_index ? 40 : DEFAULT_ABBREV;
  
 -              if (DIFF_OPT_TST(o, BINARY)) {
 +              if (o->flags.binary) {
                        mmfile_t mf;
                        if ((!fill_mmfile(&mf, one) && diff_filespec_is_binary(one)) ||
                            (!fill_mmfile(&mf, two) && diff_filespec_is_binary(two)))
@@@ -3906,7 -3904,7 +3906,7 @@@ static void run_diff_cmd(const char *pg
        int must_show_header = 0;
  
  
 -      if (DIFF_OPT_TST(o, ALLOW_EXTERNAL)) {
 +      if (o->flags.allow_external) {
                struct userdiff_driver *drv = userdiff_find_by_path(attr_path);
                if (drv && drv->external)
                        pgm = drv->external;
@@@ -3986,7 -3984,7 +3986,7 @@@ static void run_diff(struct diff_filepa
        if (o->prefix_length)
                strip_prefix(o->prefix_length, &name, &other);
  
 -      if (!DIFF_OPT_TST(o, ALLOW_EXTERNAL))
 +      if (!o->flags.allow_external)
                pgm = NULL;
  
        if (DIFF_PAIR_UNMERGED(p)) {
@@@ -4085,7 -4083,7 +4085,7 @@@ void diff_setup(struct diff_options *op
        options->context = diff_context_default;
        options->interhunkcontext = diff_interhunk_context_default;
        options->ws_error_highlight = ws_error_highlight_default;
 -      DIFF_OPT_SET(options, RENAME_EMPTY);
 +      options->flags.rename_empty = 1;
  
        /* pathchange left =NULL by default */
        options->change = diff_change;
@@@ -4133,15 -4131,17 +4133,15 @@@ void diff_setup_done(struct diff_option
         * inside contents.
         */
  
 -      if (DIFF_XDL_TST(options, IGNORE_WHITESPACE) ||
 -          DIFF_XDL_TST(options, IGNORE_WHITESPACE_CHANGE) ||
 -          DIFF_XDL_TST(options, IGNORE_WHITESPACE_AT_EOL))
 -              DIFF_OPT_SET(options, DIFF_FROM_CONTENTS);
 +      if ((options->xdl_opts & XDF_WHITESPACE_FLAGS))
 +              options->flags.diff_from_contents = 1;
        else
 -              DIFF_OPT_CLR(options, DIFF_FROM_CONTENTS);
 +              options->flags.diff_from_contents = 0;
  
 -      if (DIFF_OPT_TST(options, FIND_COPIES_HARDER))
 +      if (options->flags.find_copies_harder)
                options->detect_rename = DIFF_DETECT_COPY;
  
 -      if (!DIFF_OPT_TST(options, RELATIVE_NAME))
 +      if (!options->flags.relative_name)
                options->prefix = NULL;
        if (options->prefix)
                options->prefix_length = strlen(options->prefix);
                                      DIFF_FORMAT_DIRSTAT |
                                      DIFF_FORMAT_SUMMARY |
                                      DIFF_FORMAT_CHECKDIFF))
 -              DIFF_OPT_SET(options, RECURSIVE);
 +              options->flags.recursive = 1;
        /*
         * Also pickaxe would not work very well if you do not say recursive
         */
        if (options->pickaxe)
 -              DIFF_OPT_SET(options, RECURSIVE);
 +              options->flags.recursive = 1;
        /*
         * When patches are generated, submodules diffed against the work tree
         * must be checked for dirtiness too so it can be shown in the output
         */
        if (options->output_format & DIFF_FORMAT_PATCH)
 -              DIFF_OPT_SET(options, DIRTY_SUBMODULES);
 +              options->flags.dirty_submodules = 1;
  
        if (options->detect_rename && options->rename_limit < 0)
                options->rename_limit = diff_rename_limit_default;
         * to have found.  It does not make sense not to return with
         * exit code in such a case either.
         */
 -      if (DIFF_OPT_TST(options, QUICK)) {
 +      if (options->flags.quick) {
                options->output_format = DIFF_FORMAT_NO_OUTPUT;
 -              DIFF_OPT_SET(options, EXIT_WITH_STATUS);
 +              options->flags.exit_with_status = 1;
        }
  
        options->diff_path_counter = 0;
  
 -      if (DIFF_OPT_TST(options, FOLLOW_RENAMES) && options->pathspec.nr != 1)
 +      if (options->flags.follow_renames && options->pathspec.nr != 1)
                die(_("--follow requires exactly one pathspec"));
  
        if (!options->use_color || external_diff())
@@@ -4561,7 -4561,7 +4561,7 @@@ int diff_opt_parse(struct diff_options 
        else if (starts_with(arg, "-C") || starts_with(arg, "--find-copies=") ||
                 !strcmp(arg, "--find-copies")) {
                if (options->detect_rename == DIFF_DETECT_COPY)
 -                      DIFF_OPT_SET(options, FIND_COPIES_HARDER);
 +                      options->flags.find_copies_harder = 1;
                if ((options->rename_score = diff_scoreopt_parse(arg)) == -1)
                        return error("invalid argument to -C: %s", arg+2);
                options->detect_rename = DIFF_DETECT_COPY;
        else if (!strcmp(arg, "--no-renames"))
                options->detect_rename = 0;
        else if (!strcmp(arg, "--rename-empty"))
 -              DIFF_OPT_SET(options, RENAME_EMPTY);
 +              options->flags.rename_empty = 1;
        else if (!strcmp(arg, "--no-rename-empty"))
 -              DIFF_OPT_CLR(options, RENAME_EMPTY);
 +              options->flags.rename_empty = 0;
        else if (!strcmp(arg, "--relative"))
 -              DIFF_OPT_SET(options, RELATIVE_NAME);
 +              options->flags.relative_name = 1;
        else if (skip_prefix(arg, "--relative=", &arg)) {
 -              DIFF_OPT_SET(options, RELATIVE_NAME);
 +              options->flags.relative_name = 1;
                options->prefix = arg;
        }
  
                DIFF_XDL_SET(options, IGNORE_WHITESPACE_CHANGE);
        else if (!strcmp(arg, "--ignore-space-at-eol"))
                DIFF_XDL_SET(options, IGNORE_WHITESPACE_AT_EOL);
 +      else if (!strcmp(arg, "--ignore-cr-at-eol"))
 +              DIFF_XDL_SET(options, IGNORE_CR_AT_EOL);
        else if (!strcmp(arg, "--ignore-blank-lines"))
                DIFF_XDL_SET(options, IGNORE_BLANK_LINES);
        else if (!strcmp(arg, "--indent-heuristic"))
                DIFF_XDL_SET(options, INDENT_HEURISTIC);
        else if (!strcmp(arg, "--no-indent-heuristic"))
                DIFF_XDL_CLR(options, INDENT_HEURISTIC);
 -      else if (!strcmp(arg, "--patience"))
 +      else if (!strcmp(arg, "--patience")) {
 +              int i;
                options->xdl_opts = DIFF_WITH_ALG(options, PATIENCE_DIFF);
 -      else if (!strcmp(arg, "--histogram"))
 +              /*
 +               * Both --patience and --anchored use PATIENCE_DIFF
 +               * internally, so remove any anchors previously
 +               * specified.
 +               */
 +              for (i = 0; i < options->anchors_nr; i++)
 +                      free(options->anchors[i]);
 +              options->anchors_nr = 0;
 +      } else if (!strcmp(arg, "--histogram"))
                options->xdl_opts = DIFF_WITH_ALG(options, HISTOGRAM_DIFF);
        else if ((argcount = parse_long_opt("diff-algorithm", av, &optarg))) {
                long value = parse_algorithm_value(optarg);
                options->xdl_opts &= ~XDF_DIFF_ALGORITHM_MASK;
                options->xdl_opts |= value;
                return argcount;
 +      } else if (skip_prefix(arg, "--anchored=", &arg)) {
 +              options->xdl_opts = DIFF_WITH_ALG(options, PATIENCE_DIFF);
 +              ALLOC_GROW(options->anchors, options->anchors_nr + 1,
 +                         options->anchors_alloc);
 +              options->anchors[options->anchors_nr++] = xstrdup(arg);
        }
  
        /* flags options */
        else if (!strcmp(arg, "--binary")) {
                enable_patch_output(&options->output_format);
 -              DIFF_OPT_SET(options, BINARY);
 +              options->flags.binary = 1;
        }
        else if (!strcmp(arg, "--full-index"))
 -              DIFF_OPT_SET(options, FULL_INDEX);
 +              options->flags.full_index = 1;
        else if (!strcmp(arg, "-a") || !strcmp(arg, "--text"))
 -              DIFF_OPT_SET(options, TEXT);
 +              options->flags.text = 1;
        else if (!strcmp(arg, "-R"))
 -              DIFF_OPT_SET(options, REVERSE_DIFF);
 +              options->flags.reverse_diff = 1;
        else if (!strcmp(arg, "--find-copies-harder"))
 -              DIFF_OPT_SET(options, FIND_COPIES_HARDER);
 +              options->flags.find_copies_harder = 1;
        else if (!strcmp(arg, "--follow"))
 -              DIFF_OPT_SET(options, FOLLOW_RENAMES);
 +              options->flags.follow_renames = 1;
        else if (!strcmp(arg, "--no-follow")) {
 -              DIFF_OPT_CLR(options, FOLLOW_RENAMES);
 -              DIFF_OPT_CLR(options, DEFAULT_FOLLOW_RENAMES);
 +              options->flags.follow_renames = 0;
 +              options->flags.default_follow_renames = 0;
        } else if (!strcmp(arg, "--color"))
                options->use_color = 1;
        else if (skip_prefix(arg, "--color=", &arg)) {
                return argcount;
        }
        else if (!strcmp(arg, "--exit-code"))
 -              DIFF_OPT_SET(options, EXIT_WITH_STATUS);
 +              options->flags.exit_with_status = 1;
        else if (!strcmp(arg, "--quiet"))
 -              DIFF_OPT_SET(options, QUICK);
 +              options->flags.quick = 1;
        else if (!strcmp(arg, "--ext-diff"))
 -              DIFF_OPT_SET(options, ALLOW_EXTERNAL);
 +              options->flags.allow_external = 1;
        else if (!strcmp(arg, "--no-ext-diff"))
 -              DIFF_OPT_CLR(options, ALLOW_EXTERNAL);
 -      else if (!strcmp(arg, "--textconv"))
 -              DIFF_OPT_SET(options, ALLOW_TEXTCONV);
 -      else if (!strcmp(arg, "--no-textconv"))
 -              DIFF_OPT_CLR(options, ALLOW_TEXTCONV);
 +              options->flags.allow_external = 0;
 +      else if (!strcmp(arg, "--textconv")) {
 +              options->flags.allow_textconv = 1;
 +              options->flags.textconv_set_via_cmdline = 1;
 +      } else if (!strcmp(arg, "--no-textconv"))
 +              options->flags.allow_textconv = 0;
        else if (!strcmp(arg, "--ignore-submodules")) {
 -              DIFF_OPT_SET(options, OVERRIDE_SUBMODULE_CONFIG);
 +              options->flags.override_submodule_config = 1;
                handle_ignore_submodules_arg(options, "all");
        } else if (skip_prefix(arg, "--ignore-submodules=", &arg)) {
 -              DIFF_OPT_SET(options, OVERRIDE_SUBMODULE_CONFIG);
 +              options->flags.override_submodule_config = 1;
                handle_ignore_submodules_arg(options, arg);
        } else if (!strcmp(arg, "--submodule"))
                options->submodule_format = DIFF_SUBMODULE_LOG;
                         &options->interhunkcontext))
                ;
        else if (!strcmp(arg, "-W"))
 -              DIFF_OPT_SET(options, FUNCCONTEXT);
 +              options->flags.funccontext = 1;
        else if (!strcmp(arg, "--function-context"))
 -              DIFF_OPT_SET(options, FUNCCONTEXT);
 +              options->flags.funccontext = 1;
        else if (!strcmp(arg, "--no-function-context"))
 -              DIFF_OPT_CLR(options, FUNCCONTEXT);
 +              options->flags.funccontext = 0;
        else if ((argcount = parse_long_opt("output", av, &optarg))) {
                char *path = prefix_filename(prefix, optarg);
                options->file = xfopen(path, "w");
@@@ -4920,14 -4903,20 +4920,20 @@@ const char *diff_aligned_abbrev(const s
        int abblen;
        const char *abbrev;
  
+       /* Do we want all 40 hex characters? */
        if (len == GIT_SHA1_HEXSZ)
                return oid_to_hex(oid);
  
+       /* An abbreviated value is fine, possibly followed by an ellipsis. */
        abbrev = diff_abbrev_oid(oid, len);
+       if (!print_sha1_ellipsis())
+               return abbrev;
        abblen = strlen(abbrev);
  
        /*
-        * In well-behaved cases, where the abbbreviated result is the
+        * In well-behaved cases, where the abbreviated result is the
         * same as the requested length, append three dots after the
         * abbreviation (hence the whole logic is limited to the case
         * where abblen < 37); when the actual abbreviated result is a
@@@ -5472,7 -5461,7 +5478,7 @@@ void diff_warn_rename_limit(const char 
                warning(_(rename_limit_warning));
        else
                return;
 -      if (0 < needed && needed < 32767)
 +      if (0 < needed)
                warning(_(rename_limit_advice), varname, needed);
  }
  
@@@ -5547,7 -5536,7 +5553,7 @@@ void diff_flush(struct diff_options *op
                separator++;
        }
  
 -      if (output_format & DIFF_FORMAT_DIRSTAT && DIFF_OPT_TST(options, DIRSTAT_BY_LINE))
 +      if (output_format & DIFF_FORMAT_DIRSTAT && options->flags.dirstat_by_line)
                dirstat_by_line = 1;
  
        if (output_format & (DIFF_FORMAT_DIFFSTAT|DIFF_FORMAT_SHORTSTAT|DIFF_FORMAT_NUMSTAT) ||
        }
  
        if (output_format & DIFF_FORMAT_NO_OUTPUT &&
 -          DIFF_OPT_TST(options, EXIT_WITH_STATUS) &&
 -          DIFF_OPT_TST(options, DIFF_FROM_CONTENTS)) {
 +          options->flags.exit_with_status &&
 +          options->flags.diff_from_contents) {
                /*
                 * run diff_flush_patch for the exit status. setting
                 * options->file to /dev/null should be safe, because we
@@@ -5631,11 -5620,11 +5637,11 @@@ free_queue
         * diff_addremove/diff_change does not set the bit when
         * DIFF_FROM_CONTENTS is in effect (e.g. with -w).
         */
 -      if (DIFF_OPT_TST(options, DIFF_FROM_CONTENTS)) {
 +      if (options->flags.diff_from_contents) {
                if (options->found_changes)
 -                      DIFF_OPT_SET(options, HAS_CHANGES);
 +                      options->flags.has_changes = 1;
                else
 -                      DIFF_OPT_CLR(options, HAS_CHANGES);
 +                      options->flags.has_changes = 0;
        }
  }
  
@@@ -5755,7 -5744,7 +5761,7 @@@ static void diffcore_skip_stat_unmatch(
                         * to determine how many paths were dirty only
                         * due to stat info mismatch.
                         */
 -                      if (!DIFF_OPT_TST(diffopt, NO_INDEX))
 +                      if (!diffopt->flags.no_index)
                                diffopt->skip_stat_unmatch++;
                        diff_free_filepair(p);
                }
@@@ -5804,10 -5793,10 +5810,10 @@@ void diffcore_std(struct diff_options *
                diff_resolve_rename_copy();
        diffcore_apply_filter(options);
  
 -      if (diff_queued_diff.nr && !DIFF_OPT_TST(options, DIFF_FROM_CONTENTS))
 -              DIFF_OPT_SET(options, HAS_CHANGES);
 +      if (diff_queued_diff.nr && !options->flags.diff_from_contents)
 +              options->flags.has_changes = 1;
        else
 -              DIFF_OPT_CLR(options, HAS_CHANGES);
 +              options->flags.has_changes = 0;
  
        options->found_follow = 0;
  }
@@@ -5819,23 -5808,23 +5825,23 @@@ int diff_result_code(struct diff_option
        diff_warn_rename_limit("diff.renameLimit",
                               opt->needed_rename_limit,
                               opt->degraded_cc_to_c);
 -      if (!DIFF_OPT_TST(opt, EXIT_WITH_STATUS) &&
 +      if (!opt->flags.exit_with_status &&
            !(opt->output_format & DIFF_FORMAT_CHECKDIFF))
                return status;
 -      if (DIFF_OPT_TST(opt, EXIT_WITH_STATUS) &&
 -          DIFF_OPT_TST(opt, HAS_CHANGES))
 +      if (opt->flags.exit_with_status &&
 +          opt->flags.has_changes)
                result |= 01;
        if ((opt->output_format & DIFF_FORMAT_CHECKDIFF) &&
 -          DIFF_OPT_TST(opt, CHECK_FAILED))
 +          opt->flags.check_failed)
                result |= 02;
        return result;
  }
  
  int diff_can_quit_early(struct diff_options *opt)
  {
 -      return (DIFF_OPT_TST(opt, QUICK) &&
 +      return (opt->flags.quick &&
                !opt->filter &&
 -              DIFF_OPT_TST(opt, HAS_CHANGES));
 +              opt->flags.has_changes);
  }
  
  /*
  static int is_submodule_ignored(const char *path, struct diff_options *options)
  {
        int ignored = 0;
 -      unsigned orig_flags = options->flags;
 -      if (!DIFF_OPT_TST(options, OVERRIDE_SUBMODULE_CONFIG))
 +      struct diff_flags orig_flags = options->flags;
 +      if (!options->flags.override_submodule_config)
                set_diffopt_flags_from_submodule_config(options, path);
 -      if (DIFF_OPT_TST(options, IGNORE_SUBMODULES))
 +      if (options->flags.ignore_submodules)
                ignored = 1;
        options->flags = orig_flags;
        return ignored;
@@@ -5879,7 -5868,7 +5885,7 @@@ void diff_addremove(struct diff_option
         * Before the final output happens, they are pruned after
         * merged into rename/copy pairs as appropriate.
         */
 -      if (DIFF_OPT_TST(options, REVERSE_DIFF))
 +      if (options->flags.reverse_diff)
                addremove = (addremove == '+' ? '-' :
                             addremove == '-' ? '+' : addremove);
  
        }
  
        diff_queue(&diff_queued_diff, one, two);
 -      if (!DIFF_OPT_TST(options, DIFF_FROM_CONTENTS))
 -              DIFF_OPT_SET(options, HAS_CHANGES);
 +      if (!options->flags.diff_from_contents)
 +              options->flags.has_changes = 1;
  }
  
  void diff_change(struct diff_options *options,
            is_submodule_ignored(concatpath, options))
                return;
  
 -      if (DIFF_OPT_TST(options, REVERSE_DIFF)) {
 +      if (options->flags.reverse_diff) {
                SWAP(old_mode, new_mode);
                SWAP(old_oid, new_oid);
                SWAP(old_oid_valid, new_oid_valid);
        two->dirty_submodule = new_dirty_submodule;
        p = diff_queue(&diff_queued_diff, one, two);
  
 -      if (DIFF_OPT_TST(options, DIFF_FROM_CONTENTS))
 +      if (options->flags.diff_from_contents)
                return;
  
 -      if (DIFF_OPT_TST(options, QUICK) && options->skip_stat_unmatch &&
 +      if (options->flags.quick && options->skip_stat_unmatch &&
            !diff_filespec_check_stat_unmatch(p))
                return;
  
 -      DIFF_OPT_SET(options, HAS_CHANGES);
 +      options->flags.has_changes = 1;
  }
  
  struct diff_filepair *diff_unmerge(struct diff_options *options, const char *path)
@@@ -6081,7 -6070,7 +6087,7 @@@ void setup_diff_pager(struct diff_optio
         * and because it is easy to find people oneline advising "git diff
         * --exit-code" in hooks and other scripts, we do not do so.
         */
 -      if (!DIFF_OPT_TST(opt, EXIT_WITH_STATUS) &&
 +      if (!opt->flags.exit_with_status &&
            check_pager_config("diff") != 0)
                setup_pager();
  }
diff --combined environment.c
index 8fa032f3074255541dc3f3d926fedf6b1991dd91,a3abdd3c586da99f0d48711a52fd0014f2699e85..63ac38a46f8f01ee3d09ed8e09bd93acba63b21a
@@@ -76,7 -76,6 +76,7 @@@ int protect_hfs = PROTECT_HFS_DEFAULT
  #define PROTECT_NTFS_DEFAULT 0
  #endif
  int protect_ntfs = PROTECT_NTFS_DEFAULT;
 +const char *core_fsmonitor;
  
  /*
   * The character that begins a commented line in user-editable file
@@@ -344,3 -343,18 +344,18 @@@ int use_optional_locks(void
  {
        return git_env_bool(GIT_OPTIONAL_LOCKS_ENVIRONMENT, 1);
  }
+ int print_sha1_ellipsis(void)
+ {
+       /*
+        * Determine if the calling environment contains the variable
+        * GIT_PRINT_SHA1_ELLIPSIS set to "yes".
+        */
+       static int cached_result = -1; /* unknown */
+       if (cached_result < 0) {
+               const char *v = getenv("GIT_PRINT_SHA1_ELLIPSIS");
+               cached_result = (v && !strcasecmp(v, "yes"));
+       }
+       return cached_result;
+ }