Merge branch 'jk/no-optional-locks'
authorJunio C Hamano <gitster@pobox.com>
Tue, 3 Oct 2017 06:42:48 +0000 (15:42 +0900)
committerJunio C Hamano <gitster@pobox.com>
Tue, 3 Oct 2017 06:42:49 +0000 (15:42 +0900)
Some commands (most notably "git status") makes an opportunistic
update when performing a read-only operation to help optimize later
operations in the same repository. The new "--no-optional-locks"
option can be passed to Git to disable them.

* jk/no-optional-locks:
git: add --no-optional-locks option

1  2 
builtin/commit.c
cache.h
environment.c
git.c
diff --combined builtin/commit.c
index 0f8ddb6866b3d14c4e6b84f019110387c7f77319,a8ef73d9caeabb72632c7a63152b33aa71c55abc..d75b3805ea7fe3475564f337bf660d8155909445
@@@ -195,6 -195,7 +195,6 @@@ static void determine_whence(struct wt_
  static void status_init_config(struct wt_status *s, config_fn_t fn)
  {
        wt_status_prepare(s);
 -      gitmodules_config();
        git_config(fn, s);
        determine_whence(s);
        init_diff_ui_defaults();
@@@ -335,7 -336,7 +335,7 @@@ static void refresh_cache_or_die(int re
  static const char *prepare_index(int argc, const char **argv, const char *prefix,
                                 const struct commit *current_head, int is_status)
  {
 -      struct string_list partial;
 +      struct string_list partial = STRING_LIST_INIT_DUP;
        struct pathspec pathspec;
        int refresh_flags = REFRESH_QUIET;
        const char *ret;
                        warning(_("Failed to update main cache tree"));
  
                commit_style = COMMIT_NORMAL;
 -              return get_lock_file_path(&index_lock);
 +              ret = get_lock_file_path(&index_lock);
 +              goto out;
        }
  
        /*
                if (write_locked_index(&the_index, &index_lock, CLOSE_LOCK))
                        die(_("unable to write new_index file"));
                commit_style = COMMIT_NORMAL;
 -              return get_lock_file_path(&index_lock);
 +              ret = get_lock_file_path(&index_lock);
 +              goto out;
        }
  
        /*
                        rollback_lock_file(&index_lock);
                }
                commit_style = COMMIT_AS_IS;
 -              return get_index_file();
 +              ret = get_index_file();
 +              goto out;
        }
  
        /*
                        die(_("cannot do a partial commit during a cherry-pick."));
        }
  
 -      string_list_init(&partial, 1);
        if (list_paths(&partial, !current_head ? NULL : "HEAD", prefix, &pathspec))
                exit(1);
  
        discard_cache();
        ret = get_lock_file_path(&false_lock);
        read_cache_from(ret);
 +out:
 +      string_list_clear(&partial, 0);
 +      clear_pathspec(&pathspec);
        return ret;
  }
  
@@@ -514,7 -510,7 +514,7 @@@ static int run_status(FILE *fp, const c
        s->index_file = index_file;
        s->fp = fp;
        s->nowarn = nowarn;
 -      s->is_initial = get_sha1(s->reference, oid.hash) ? 1 : 0;
 +      s->is_initial = get_oid(s->reference, &oid) ? 1 : 0;
        if (!s->is_initial)
                hashcpy(s->sha1_commit, oid.hash);
        s->status_format = status_format;
@@@ -895,7 -891,7 +895,7 @@@ static int prepare_to_commit(const cha
                if (amend)
                        parent = "HEAD^1";
  
 -              if (get_sha1(parent, oid.hash)) {
 +              if (get_oid(parent, &oid)) {
                        int i, ita_nr = 0;
  
                        for (i = 0; i < active_nr; i++)
                return 0;
        }
  
 -      /*
 -       * Re-read the index as pre-commit hook could have updated it,
 -       * and write it out as a tree.  We must do this before we invoke
 -       * the editor and after we invoke run_status above.
 -       */
 -      discard_cache();
 +      if (!no_verify && find_hook("pre-commit")) {
 +              /*
 +               * Re-read the index as pre-commit hook could have updated it,
 +               * and write it out as a tree.  We must do this before we invoke
 +               * the editor and after we invoke run_status above.
 +               */
 +              discard_cache();
 +      }
        read_cache_from(index_file);
 +
        if (update_main_cache_tree(0)) {
                error(_("Error building trees"));
                return 0;
@@@ -1392,9 -1385,12 +1392,12 @@@ int cmd_status(int argc, const char **a
        read_cache_preload(&s.pathspec);
        refresh_index(&the_index, REFRESH_QUIET|REFRESH_UNMERGED, &s.pathspec, NULL, NULL);
  
-       fd = hold_locked_index(&index_lock, 0);
+       if (use_optional_locks())
+               fd = hold_locked_index(&index_lock, 0);
+       else
+               fd = -1;
  
 -      s.is_initial = get_sha1(s.reference, oid.hash) ? 1 : 0;
 +      s.is_initial = get_oid(s.reference, &oid) ? 1 : 0;
        if (!s.is_initial)
                hashcpy(s.sha1_commit, oid.hash);
  
@@@ -1436,6 -1432,7 +1439,6 @@@ static void print_summary(const char *p
        struct rev_info rev;
        struct commit *commit;
        struct strbuf format = STRBUF_INIT;
 -      struct object_id junk_oid;
        const char *head;
        struct pretty_print_context pctx = {0};
        struct strbuf author_ident = STRBUF_INIT;
        rev.diffopt.break_opt = 0;
        diff_setup_done(&rev.diffopt);
  
 -      head = resolve_ref_unsafe("HEAD", 0, junk_oid.hash, NULL);
 +      head = resolve_ref_unsafe("HEAD", 0, NULL, NULL);
        if (!strcmp(head, "HEAD"))
                head = _("detached HEAD");
        else
@@@ -1663,7 -1660,7 +1666,7 @@@ int cmd_commit(int argc, const char **a
        status_format = STATUS_FORMAT_NONE; /* Ignore status.short */
        s.colopts = 0;
  
 -      if (get_sha1("HEAD", oid.hash))
 +      if (get_oid("HEAD", &oid))
                current_head = NULL;
        else {
                current_head = lookup_commit_or_die(&oid, "HEAD");
        if (!quiet)
                print_summary(prefix, &oid, !current_head);
  
 -      strbuf_release(&err);
 +      UNLEAK(err);
 +      UNLEAK(sb);
        return 0;
  }
diff --combined cache.h
index ea6c236e0fa5e895d89a0029349ea54f9afabd07,56053cf39b106b3df3481717014040633bf8af3a..6440e2bf21f5800db98f82fcedff46478188674e
+++ b/cache.h
@@@ -4,7 -4,6 +4,7 @@@
  #include "git-compat-util.h"
  #include "strbuf.h"
  #include "hashmap.h"
 +#include "mru.h"
  #include "advice.h"
  #include "gettext.h"
  #include "convert.h"
@@@ -418,6 -417,7 +418,6 @@@ static inline enum object_type object_t
  #define GIT_WORK_TREE_ENVIRONMENT "GIT_WORK_TREE"
  #define GIT_PREFIX_ENVIRONMENT "GIT_PREFIX"
  #define GIT_SUPER_PREFIX_ENVIRONMENT "GIT_INTERNAL_SUPER_PREFIX"
 -#define GIT_TOPLEVEL_PREFIX_ENVIRONMENT "GIT_INTERNAL_TOPLEVEL_PREFIX"
  #define DEFAULT_GIT_DIR_ENVIRONMENT ".git"
  #define DB_ENVIRONMENT "GIT_OBJECT_DIRECTORY"
  #define INDEX_ENVIRONMENT "GIT_INDEX_FILE"
  #define GITATTRIBUTES_FILE ".gitattributes"
  #define INFOATTRIBUTES_FILE "info/attributes"
  #define ATTRIBUTE_MACRO_PREFIX "[attr]"
 +#define GITMODULES_FILE ".gitmodules"
  #define GIT_NOTES_REF_ENVIRONMENT "GIT_NOTES_REF"
  #define GIT_NOTES_DEFAULT_REF "refs/notes/commits"
  #define GIT_NOTES_DISPLAY_REF_ENVIRONMENT "GIT_NOTES_DISPLAY_REF"
  #define GIT_NOGLOB_PATHSPECS_ENVIRONMENT "GIT_NOGLOB_PATHSPECS"
  #define GIT_ICASE_PATHSPECS_ENVIRONMENT "GIT_ICASE_PATHSPECS"
  #define GIT_QUARANTINE_ENVIRONMENT "GIT_QUARANTINE_PATH"
+ #define GIT_OPTIONAL_LOCKS_ENVIRONMENT "GIT_OPTIONAL_LOCKS"
  
  /*
   * This environment variable is expected to contain a boolean indicating
@@@ -685,8 -685,8 +686,8 @@@ extern int ie_modified(const struct ind
  
  #define HASH_WRITE_OBJECT 1
  #define HASH_FORMAT_CHECK 2
 -extern int index_fd(unsigned char *sha1, int fd, struct stat *st, enum object_type type, const char *path, unsigned flags);
 -extern int index_path(unsigned char *sha1, const char *path, struct stat *st, unsigned flags);
 +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);
  
  /*
   * Record to sd the data from st that we use to check whether a file
@@@ -783,6 -783,11 +784,11 @@@ extern int protect_ntfs
   */
  extern int ref_paranoia;
  
+ /*
+  * Returns the boolean value of $GIT_OPTIONAL_LOCKS (or the default value).
+  */
+ int use_optional_locks(void);
  /*
   * The character that begins a commented line in user-editable file
   * that is subject to stripspace.
@@@ -903,6 -908,20 +909,6 @@@ extern void check_repository_format(voi
   */
  extern const char *sha1_file_name(const unsigned char *sha1);
  
 -/*
 - * Return the name of the (local) packfile with the specified sha1 in
 - * its name.  The return value is a pointer to memory that is
 - * overwritten each time this function is called.
 - */
 -extern char *sha1_pack_name(const unsigned char *sha1);
 -
 -/*
 - * Return the name of the (local) pack index file with the specified
 - * sha1 in its name.  The return value is a pointer to memory that is
 - * overwritten each time this function is called.
 - */
 -extern char *sha1_pack_index_name(const unsigned char *sha1);
 -
  /*
   * Return an abbreviated sha1 unique within this repository's object database.
   * The result will be at least `len` characters long, and will be NUL
@@@ -1179,7 -1198,7 +1185,7 @@@ static inline const unsigned char *look
  extern int sha1_object_info(const unsigned char *, unsigned long *);
  extern int hash_sha1_file(const void *buf, unsigned long len, const char *type, unsigned char *sha1);
  extern int write_sha1_file(const void *buf, unsigned long len, const char *type, unsigned char *return_sha1);
 -extern int hash_sha1_file_literally(const void *buf, unsigned long len, const char *type, unsigned char *sha1, unsigned flags);
 +extern int hash_sha1_file_literally(const void *buf, unsigned long len, const char *type, struct object_id *oid, unsigned flags);
  extern int pretend_sha1_file(void *, unsigned long, enum object_type, unsigned char *);
  extern int force_object_loose(const unsigned char *sha1, time_t mtime);
  extern int git_open_cloexec(const char *name, int flags);
@@@ -1188,10 -1207,15 +1194,10 @@@ extern void *map_sha1_file(const unsign
  extern int unpack_sha1_header(git_zstream *stream, unsigned char *map, unsigned long mapsize, void *buffer, unsigned long bufsiz);
  extern int parse_sha1_header(const char *hdr, unsigned long *sizep);
  
 -/* global flag to enable extra checks when accessing packed objects */
 -extern int do_check_packed_object_crc;
 -
  extern int check_sha1_signature(const unsigned char *sha1, void *buf, unsigned long size, const char *type);
  
  extern int finalize_object_file(const char *tmpfile, const char *filename);
  
 -extern int has_sha1_pack(const unsigned char *sha1);
 -
  /*
   * Open the loose object at path, check its sha1, and return the contents,
   * type, and size. If the object is a blob, then "contents" may return NULL,
@@@ -1227,6 -1251,8 +1233,6 @@@ extern int has_object_file_with_flags(c
   */
  extern int has_loose_object_nonlocal(const unsigned char *sha1);
  
 -extern int has_pack_index(const unsigned char *sha1);
 -
  extern void assert_sha1_type(const unsigned char *sha1, enum object_type expect);
  
  /* Helper to check and "touch" a file */
@@@ -1244,8 -1270,8 +1250,8 @@@ static inline unsigned int hexval(unsig
   */
  static inline int hex2chr(const char *s)
  {
 -      int val = hexval(s[0]);
 -      return (val < 0) ? val : (val << 4) | hexval(s[1]);
 +      unsigned int val = hexval(s[0]);
 +      return (val & ~0xf) ? val : (val << 4) | hexval(s[1]);
  }
  
  /* Convert to/from hex/sha1 representation */
@@@ -1264,37 -1290,38 +1270,37 @@@ struct object_context 
         */
        struct strbuf symlink_path;
        /*
 -       * If GET_SHA1_RECORD_PATH is set, this will record path (if any)
 +       * If GET_OID_RECORD_PATH is set, this will record path (if any)
         * found when resolving the name. The caller is responsible for
         * releasing the memory.
         */
        char *path;
  };
  
 -#define GET_SHA1_QUIETLY           01
 -#define GET_SHA1_COMMIT            02
 -#define GET_SHA1_COMMITTISH        04
 -#define GET_SHA1_TREE             010
 -#define GET_SHA1_TREEISH          020
 -#define GET_SHA1_BLOB             040
 -#define GET_SHA1_FOLLOW_SYMLINKS 0100
 -#define GET_SHA1_RECORD_PATH     0200
 -#define GET_SHA1_ONLY_TO_DIE    04000
 -
 -#define GET_SHA1_DISAMBIGUATORS \
 -      (GET_SHA1_COMMIT | GET_SHA1_COMMITTISH | \
 -      GET_SHA1_TREE | GET_SHA1_TREEISH | \
 -      GET_SHA1_BLOB)
 -
 -extern int get_sha1(const char *str, unsigned char *sha1);
 -extern int get_sha1_commit(const char *str, unsigned char *sha1);
 -extern int get_sha1_committish(const char *str, unsigned char *sha1);
 -extern int get_sha1_tree(const char *str, unsigned char *sha1);
 -extern int get_sha1_treeish(const char *str, unsigned char *sha1);
 -extern int get_sha1_blob(const char *str, unsigned char *sha1);
 -extern void maybe_die_on_misspelt_object_name(const char *name, const char *prefix);
 -extern int get_sha1_with_context(const char *str, unsigned flags, unsigned char *sha1, struct object_context *oc);
 +#define GET_OID_QUIETLY           01
 +#define GET_OID_COMMIT            02
 +#define GET_OID_COMMITTISH        04
 +#define GET_OID_TREE             010
 +#define GET_OID_TREEISH          020
 +#define GET_OID_BLOB             040
 +#define GET_OID_FOLLOW_SYMLINKS 0100
 +#define GET_OID_RECORD_PATH     0200
 +#define GET_OID_ONLY_TO_DIE    04000
 +
 +#define GET_OID_DISAMBIGUATORS \
 +      (GET_OID_COMMIT | GET_OID_COMMITTISH | \
 +      GET_OID_TREE | GET_OID_TREEISH | \
 +      GET_OID_BLOB)
  
  extern int get_oid(const char *str, struct object_id *oid);
 +extern int get_oid_commit(const char *str, struct object_id *oid);
 +extern int get_oid_committish(const char *str, struct object_id *oid);
 +extern int get_oid_tree(const char *str, struct object_id *oid);
 +extern int get_oid_treeish(const char *str, struct object_id *oid);
 +extern int get_oid_blob(const char *str, struct object_id *oid);
 +extern void maybe_die_on_misspelt_object_name(const char *name, const char *prefix);
 +extern int get_oid_with_context(const char *str, unsigned flags, struct object_id *oid, struct object_context *oc);
 +
  
  typedef int each_abbrev_fn(const struct object_id *oid, void *);
  extern int for_each_abbrev(const char *prefix, each_abbrev_fn, void *);
@@@ -1590,7 -1617,8 +1596,7 @@@ extern struct packed_git 
   * A most-recently-used ordered version of the packed_git list, which can
   * be iterated instead of packed_git (and marked via mru_mark).
   */
 -struct mru;
 -extern struct mru *packed_git_mru;
 +extern struct mru packed_git_mru;
  
  struct pack_entry {
        off_t offset;
        struct packed_git *p;
  };
  
 -extern struct packed_git *parse_pack_index(unsigned char *sha1, const char *idx_path);
 -
 -/* A hook to report invalid files in pack directory */
 -#define PACKDIR_FILE_PACK 1
 -#define PACKDIR_FILE_IDX 2
 -#define PACKDIR_FILE_GARBAGE 4
 -extern void (*report_garbage)(unsigned seen_bits, const char *path);
 -
 -extern void prepare_packed_git(void);
 -extern void reprepare_packed_git(void);
 -extern void install_packed_git(struct packed_git *pack);
 -
 -/*
 - * Give a rough count of objects in the repository. This sacrifices accuracy
 - * for speed.
 - */
 -unsigned long approximate_object_count(void);
 -
 -extern struct packed_git *find_sha1_pack(const unsigned char *sha1,
 -                                       struct packed_git *packs);
 -
 -extern void pack_report(void);
 -
  /*
   * Create a temporary file rooted in the object database directory, or
   * die on failure. The filename is taken from "pattern", which should have the
   */
  extern int odb_mkstemp(struct strbuf *template, const char *pattern);
  
 -/*
 - * Generate the filename to be used for a pack file with checksum "sha1" and
 - * extension "ext". The result is written into the strbuf "buf", overwriting
 - * any existing contents. A pointer to buf->buf is returned as a convenience.
 - *
 - * Example: odb_pack_name(out, sha1, "idx") => ".git/objects/pack/pack-1234..idx"
 - */
 -extern char *odb_pack_name(struct strbuf *buf, const unsigned char *sha1, const char *ext);
 -
  /*
   * Create a pack .keep file named "name" (which should generally be the output
   * of odb_pack_name). Returns a file descriptor opened for writing, or -1 on
   */
  extern int odb_pack_keep(const char *name);
  
 -/*
 - * mmap the index file for the specified packfile (if it is not
 - * already mmapped).  Return 0 on success.
 - */
 -extern int open_pack_index(struct packed_git *);
 -
 -/*
 - * munmap the index file for the specified packfile (if it is
 - * currently mmapped).
 - */
 -extern void close_pack_index(struct packed_git *);
 -
 -extern unsigned char *use_pack(struct packed_git *, struct pack_window **, off_t, unsigned long *);
 -extern void close_pack_windows(struct packed_git *);
 -extern void close_all_packs(void);
 -extern void unuse_pack(struct pack_window **);
 -extern void clear_delta_base_cache(void);
 -extern struct packed_git *add_packed_git(const char *path, size_t path_len, int local);
 -
 -/*
 - * Make sure that a pointer access into an mmap'd index file is within bounds,
 - * and can provide at least 8 bytes of data.
 - *
 - * Note that this is only necessary for variable-length segments of the file
 - * (like the 64-bit extended offset table), as we compare the size to the
 - * fixed-length parts when we open the file.
 - */
 -extern void check_pack_index_ptr(const struct packed_git *p, const void *ptr);
 -
 -/*
 - * Return the SHA-1 of the nth object within the specified packfile.
 - * Open the index if it is not already open.  The return value points
 - * at the SHA-1 within the mmapped index.  Return NULL if there is an
 - * error.
 - */
 -extern const unsigned char *nth_packed_object_sha1(struct packed_git *, uint32_t n);
 -/*
 - * Like nth_packed_object_sha1, but write the data into the object specified by
 - * the the first argument.  Returns the first argument on success, and NULL on
 - * error.
 - */
 -extern const struct object_id *nth_packed_object_oid(struct object_id *, struct packed_git *, uint32_t n);
 -
 -/*
 - * Return the offset of the nth object within the specified packfile.
 - * The index must already be opened.
 - */
 -extern off_t nth_packed_object_offset(const struct packed_git *, uint32_t n);
 -
 -/*
 - * If the object named sha1 is present in the specified packfile,
 - * return its offset within the packfile; otherwise, return 0.
 - */
 -extern off_t find_pack_entry_one(const unsigned char *sha1, struct packed_git *);
 -
 -extern int is_pack_valid(struct packed_git *);
 -extern void *unpack_entry(struct packed_git *, off_t, enum object_type *, unsigned long *);
 -extern unsigned long unpack_object_header_buffer(const unsigned char *buf, unsigned long len, enum object_type *type, unsigned long *sizep);
 -extern unsigned long get_size_from_delta(struct packed_git *, struct pack_window **, off_t);
 -extern int unpack_object_header(struct packed_git *, struct pack_window **, off_t *, unsigned long *);
 -
  /*
   * Iterate over the files in the loose-object parts of the object
   * directory "path", triggering the following callbacks:
@@@ -1662,12 -1783,17 +1668,12 @@@ int for_each_loose_file_in_objdir_buf(s
                                      void *data);
  
  /*
 - * Iterate over loose and packed objects in both the local
 + * Iterate over loose objects in both the local
   * repository and any alternates repositories (unless the
   * LOCAL_ONLY flag is set).
   */
  #define FOR_EACH_OBJECT_LOCAL_ONLY 0x1
 -typedef int each_packed_object_fn(const struct object_id *oid,
 -                                struct packed_git *pack,
 -                                uint32_t pos,
 -                                void *data);
  extern int for_each_loose_object(each_loose_object_fn, void *, unsigned flags);
 -extern int for_each_packed_object(each_packed_object_fn, void *, unsigned flags);
  
  struct object_info {
        /* Request */
  /* Do not retry packed storage after checking packed and loose storage */
  #define OBJECT_INFO_QUICK 8
  extern int sha1_object_info_extended(const unsigned char *, struct object_info *, unsigned flags);
 -extern int packed_object_info(struct packed_git *pack, off_t offset, struct object_info *);
  
  /* Dumb servers support */
  extern int update_server_info(int);
@@@ -1835,8 -1962,6 +1841,8 @@@ void shift_tree_by(const struct object_
  #define WS_TRAILING_SPACE      (WS_BLANK_AT_EOL|WS_BLANK_AT_EOF)
  #define WS_DEFAULT_RULE (WS_TRAILING_SPACE|WS_SPACE_BEFORE_TAB|8)
  #define WS_TAB_WIDTH_MASK        077
 +/* All WS_* -- when extended, adapt diff.c emit_symbol */
 +#define WS_RULE_MASK           07777
  extern unsigned whitespace_rule_cfg;
  extern unsigned whitespace_rule(const char *);
  extern unsigned parse_whitespace_rule(const char *);
diff --combined environment.c
index f1f934b6fddd101191a17b1bc1883da287793319,68823598d32a6ee1a9eb26daa68a916504cecc84..8289c25b44d74a0f054f9fe3eaf44c5fdcf0b3d2
@@@ -97,7 -97,7 +97,7 @@@ int ignore_untracked_cache_config
  /* This is set by setup_git_dir_gently() and/or git_default_config() */
  char *git_work_tree_cfg;
  
 -static const char *namespace;
 +static char *namespace;
  
  static const char *super_prefix;
  
@@@ -152,10 -152,8 +152,10 @@@ void setup_git_env(void
        if (getenv(NO_REPLACE_OBJECTS_ENVIRONMENT))
                check_replace_refs = 0;
        replace_ref_base = getenv(GIT_REPLACE_REF_BASE_ENVIRONMENT);
 +      free(git_replace_ref_base);
        git_replace_ref_base = xstrdup(replace_ref_base ? replace_ref_base
                                                          : "refs/replace/");
 +      free(namespace);
        namespace = expand_namespace(getenv(GIT_NAMESPACE_ENVIRONMENT));
        shallow_file = getenv(GIT_SHALLOW_FILE_ENVIRONMENT);
        if (shallow_file)
@@@ -338,3 -336,8 +338,8 @@@ void reset_shared_repository(void
  {
        need_shared_repository_from_config = 1;
  }
+ int use_optional_locks(void)
+ {
+       return git_env_bool(GIT_OPTIONAL_LOCKS_ENVIRONMENT, 1);
+ }
diff --combined git.c
index f31dca69620ac244e87e04f1d508ee23cf2f92cf,21a3c9872ccca88ead8e01af3fd93a4e067cc941..9e96dd409017c643e8a9bebbc41281728978b0b8
--- 1/git.c
--- 2/git.c
+++ b/git.c
@@@ -182,6 -182,10 +182,10 @@@ static int handle_options(const char **
                        setenv(GIT_ICASE_PATHSPECS_ENVIRONMENT, "1", 1);
                        if (envchanged)
                                *envchanged = 1;
+               } else if (!strcmp(cmd, "--no-optional-locks")) {
+                       setenv(GIT_OPTIONAL_LOCKS_ENVIRONMENT, "0", 1);
+                       if (envchanged)
+                               *envchanged = 1;
                } else if (!strcmp(cmd, "--shallow-file")) {
                        (*argv)++;
                        (*argc)--;
@@@ -404,7 -408,7 +408,7 @@@ static struct cmd_struct commands[] = 
        { "fsck-objects", cmd_fsck, RUN_SETUP },
        { "gc", cmd_gc, RUN_SETUP },
        { "get-tar-commit-id", cmd_get_tar_commit_id },
 -      { "grep", cmd_grep, RUN_SETUP_GENTLY | SUPPORT_SUPER_PREFIX },
 +      { "grep", cmd_grep, RUN_SETUP_GENTLY },
        { "hash-object", cmd_hash_object },
        { "help", cmd_help },
        { "index-pack", cmd_index_pack, RUN_SETUP_GENTLY },