Code

Merge branch 'gb/maint-submodule-env'
authorJunio C Hamano <gitster@pobox.com>
Sun, 7 Mar 2010 20:47:17 +0000 (12:47 -0800)
committerJunio C Hamano <gitster@pobox.com>
Sun, 7 Mar 2010 20:47:17 +0000 (12:47 -0800)
* gb/maint-submodule-env:
  is_submodule_modified(): clear environment properly
  submodules: ensure clean environment when operating in a submodule
  shell setup: clear_local_git_env() function
  rev-parse: --local-env-vars option
  Refactor list of of repo-local env vars

1  2 
Documentation/git-rev-parse.txt
builtin-rev-parse.c
cache.h
connect.c
git-sh-setup.sh
git-submodule.sh

index 1a613aa108d649c199c30d0d8a29623243631a7c,33092a33739feb59cb1c5912c7f3a221a88ff9ec..8db600f6ba01bcb7f85be6c6606795a0034822b2
@@@ -101,14 -101,15 +101,14 @@@ OPTION
        abbreviation mode.
  
  --all::
 -      Show all refs found in `$GIT_DIR/refs`.
 +      Show all refs found in `refs/`.
  
  --branches[=pattern]::
  --tags[=pattern]::
  --remotes[=pattern]::
        Show all branches, tags, or remote-tracking branches,
 -      respectively (i.e., refs found in `$GIT_DIR/refs/heads`,
 -      `$GIT_DIR/refs/tags`, or `$GIT_DIR/refs/remotes`,
 -      respectively).
 +      respectively (i.e., refs found in `refs/heads`,
 +      `refs/tags`, or `refs/remotes`, respectively).
  +
  If a `pattern` is given, only refs matching the given shell glob are
  shown.  If the pattern does not contain a globbing character (`?`,
  --is-bare-repository::
        When the repository is bare print "true", otherwise "false".
  
+ --local-env-vars::
+       List the GIT_* environment variables that are local to the
+       repository (e.g. GIT_DIR or GIT_WORK_TREE, but not GIT_EDITOR).
+       Only the names of the variables are listed, not their value,
+       even if they are set.
  --short::
  --short=number::
        Instead of outputting the full SHA1 values of object names try to
@@@ -188,7 -195,7 +194,7 @@@ blobs contained in a commit
    `g`, and an abbreviated object name.
  
  * A symbolic ref name.  E.g. 'master' typically means the commit
 -  object referenced by $GIT_DIR/refs/heads/master.  If you
 +  object referenced by refs/heads/master.  If you
    happen to have both heads/master and tags/master, you can
    explicitly say 'heads/master' to tell git which one you mean.
    When ambiguous, a `<name>` is disambiguated by taking the
    . if `$GIT_DIR/<name>` exists, that is what you mean (this is usually
      useful only for `HEAD`, `FETCH_HEAD`, `ORIG_HEAD` and `MERGE_HEAD`);
  
 -  . otherwise, `$GIT_DIR/refs/<name>` if exists;
 +  . otherwise, `refs/<name>` if exists;
  
 -  . otherwise, `$GIT_DIR/refs/tags/<name>` if exists;
 +  . otherwise, `refs/tags/<name>` if exists;
  
 -  . otherwise, `$GIT_DIR/refs/heads/<name>` if exists;
 +  . otherwise, `refs/heads/<name>` if exists;
  
 -  . otherwise, `$GIT_DIR/refs/remotes/<name>` if exists;
 +  . otherwise, `refs/remotes/<name>` if exists;
  
 -  . otherwise, `$GIT_DIR/refs/remotes/<name>/HEAD` if exists.
 +  . otherwise, `refs/remotes/<name>/HEAD` if exists.
  +
  HEAD names the commit your changes in the working tree is based on.
  FETCH_HEAD records the branch you fetched from a remote repository
@@@ -216,9 -223,6 +222,9 @@@ you can change the tip of the branch ba
  them easily.
  MERGE_HEAD records the commit(s) you are merging into your branch
  when you run 'git merge'.
 ++
 +Note that any of the `refs/*` cases above may come either from
 +the `$GIT_DIR/refs` directory or from the `$GIT_DIR/packed-refs` file.
  
  * A ref followed by the suffix '@' with a date specification
    enclosed in a brace
diff --combined builtin-rev-parse.c
index 88bad9af3caae741653e7836a0d53df9563e557c,b76f205e62f29a21fc4b0fedb4a981488ec7cb7f..8fbf9d0db6f40aa8c7cb61d72d0f44446de46826
@@@ -455,6 -455,13 +455,13 @@@ int cmd_rev_parse(int argc, const char 
        if (argc > 1 && !strcmp("--sq-quote", argv[1]))
                return cmd_sq_quote(argc - 2, argv + 2);
  
+       if (argc == 2 && !strcmp("--local-env-vars", argv[1])) {
+               int i;
+               for (i = 0; local_repo_env[i]; i++)
+                       printf("%s\n", local_repo_env[i]);
+               return 0;
+       }
        if (argc > 1 && !strcmp("-h", argv[1]))
                usage(builtin_rev_parse_usage);
  
                        if (!strcmp(arg, "--git-dir")) {
                                const char *gitdir = getenv(GIT_DIR_ENVIRONMENT);
                                static char cwd[PATH_MAX];
 +                              int len;
                                if (gitdir) {
                                        puts(gitdir);
                                        continue;
                                }
                                if (!getcwd(cwd, PATH_MAX))
                                        die_errno("unable to get current working directory");
 -                              printf("%s/.git\n", cwd);
 +                              len = strlen(cwd);
 +                              printf("%s%s.git\n", cwd, len && cwd[len-1] != '/' ? "/" : "");
                                continue;
                        }
                        if (!strcmp(arg, "--is-inside-git-dir")) {
diff --combined cache.h
index c286310ded0628fba4706f81b77708559d759c29,58209adbd6f0c7e72b1e29c36af31c82e842c9ac..89f6a40d1a1011bca4d546c5979d66d44b408ece
+++ b/cache.h
@@@ -388,6 -388,15 +388,15 @@@ static inline enum object_type object_t
  #define GIT_NOTES_REF_ENVIRONMENT "GIT_NOTES_REF"
  #define GIT_NOTES_DEFAULT_REF "refs/notes/commits"
  
+ /*
+  * Repository-local GIT_* environment variables
+  * The array is NULL-terminated to simplify its usage in contexts such
+  * environment creation or simple walk of the list.
+  * The number of non-NULL entries is available as a macro.
+  */
+ #define LOCAL_REPO_ENV_SIZE 8
+ extern const char *const local_repo_env[LOCAL_REPO_ENV_SIZE + 1];
  extern int is_bare_repository_cfg;
  extern int is_bare_repository(void);
  extern int is_inside_git_dir(void);
@@@ -641,10 -650,6 +650,10 @@@ int git_mkstemp(char *path, size_t n, c
  
  int git_mkstemps(char *path, size_t n, const char *template, int suffix_len);
  
 +/* set default permissions by passing mode arguments to open(2) */
 +int git_mkstemps_mode(char *pattern, int suffix_len, int mode);
 +int git_mkstemp_mode(char *pattern, int mode);
 +
  /*
   * NOTE NOTE NOTE!!
   *
@@@ -679,7 -684,6 +688,7 @@@ int normalize_path_copy(char *dst, cons
  int longest_ancestor_length(const char *path, const char *prefix_list);
  char *strip_path_suffix(const char *path, const char *suffix);
  int daemon_avoid_alias(const char *path);
 +int offset_1st_component(const char *path);
  
  /* Read and unpack a sha1 file into memory, write memory to a sha1 file */
  extern int sha1_object_info(const unsigned char *, unsigned long *);
@@@ -780,7 -784,7 +789,7 @@@ extern const char *git_committer_info(i
  extern const char *fmt_ident(const char *name, const char *email, const char *date_str, int);
  extern const char *fmt_name(const char *name, const char *email);
  extern const char *git_editor(void);
 -extern const char *git_pager(void);
 +extern const char *git_pager(int stdout_is_tty);
  
  struct checkout {
        const char *base_dir;
diff --combined connect.c
index 9f39038f6f0f0cd4faca81a9451623466f197318,24ce2fc70edd1945b5e7b51a9a02afba668eb9ff..323a771b699cd1b35cc93fc408a1bbf6c9119abf
+++ b/connect.c
@@@ -152,28 -152,6 +152,28 @@@ static enum protocol get_protocol(cons
  #define STR_(s)       # s
  #define STR(s)        STR_(s)
  
 +static void get_host_and_port(char **host, const char **port)
 +{
 +      char *colon, *end;
 +
 +      if (*host[0] == '[') {
 +              end = strchr(*host + 1, ']');
 +              if (end) {
 +                      *end = 0;
 +                      end++;
 +                      (*host)++;
 +              } else
 +                      end = *host;
 +      } else
 +              end = *host;
 +      colon = strchr(end, ':');
 +
 +      if (colon) {
 +              *colon = 0;
 +              *port = colon + 1;
 +      }
 +}
 +
  #ifndef NO_IPV6
  
  static const char *ai_name(const struct addrinfo *ai)
  static int git_tcp_connect_sock(char *host, int flags)
  {
        int sockfd = -1, saved_errno = 0;
 -      char *colon, *end;
        const char *port = STR(DEFAULT_GIT_PORT);
        struct addrinfo hints, *ai0, *ai;
        int gai;
        int cnt = 0;
  
 -      if (host[0] == '[') {
 -              end = strchr(host + 1, ']');
 -              if (end) {
 -                      *end = 0;
 -                      end++;
 -                      host++;
 -              } else
 -                      end = host;
 -      } else
 -              end = host;
 -      colon = strchr(end, ':');
 -
 -      if (colon) {
 -              *colon = 0;
 -              port = colon + 1;
 -              if (!*port)
 -                      port = "<none>";
 -      }
 +      get_host_and_port(&host, &port);
 +      if (!*port)
 +              port = "<none>";
  
        memset(&hints, 0, sizeof(hints));
        hints.ai_socktype = SOCK_STREAM;
  static int git_tcp_connect_sock(char *host, int flags)
  {
        int sockfd = -1, saved_errno = 0;
 -      char *colon, *end;
 -      char *port = STR(DEFAULT_GIT_PORT), *ep;
 +      const char *port = STR(DEFAULT_GIT_PORT);
 +      char *ep;
        struct hostent *he;
        struct sockaddr_in sa;
        char **ap;
        unsigned int nport;
        int cnt;
  
 -      if (host[0] == '[') {
 -              end = strchr(host + 1, ']');
 -              if (end) {
 -                      *end = 0;
 -                      end++;
 -                      host++;
 -              } else
 -                      end = host;
 -      } else
 -              end = host;
 -      colon = strchr(end, ':');
 -
 -      if (colon) {
 -              *colon = 0;
 -              port = colon + 1;
 -      }
 +      get_host_and_port(&host, &port);
  
        if (flags & CONNECT_VERBOSE)
                fprintf(stderr, "Looking up %s ... ", host);
@@@ -397,10 -406,26 +397,10 @@@ static int git_use_proxy(const char *ho
  static void git_proxy_connect(int fd[2], char *host)
  {
        const char *port = STR(DEFAULT_GIT_PORT);
 -      char *colon, *end;
        const char *argv[4];
        struct child_process proxy;
  
 -      if (host[0] == '[') {
 -              end = strchr(host + 1, ']');
 -              if (end) {
 -                      *end = 0;
 -                      end++;
 -                      host++;
 -              } else
 -                      end = host;
 -      } else
 -              end = host;
 -      colon = strchr(end, ':');
 -
 -      if (colon) {
 -              *colon = 0;
 -              port = colon + 1;
 -      }
 +      get_host_and_port(&host, &port);
  
        argv[0] = git_proxy_command;
        argv[1] = host;
@@@ -479,7 -504,7 +479,7 @@@ struct child_process *git_connect(int f
  
        /*
         * Don't do destructive transforms with git:// as that
 -       * protocol code does '[]' dewrapping of its own.
 +       * protocol code does '[]' unwrapping of its own.
         */
        if (host[0] == '[') {
                end = strchr(host + 1, ']');
                *arg++ = host;
        }
        else {
-               /* remove these from the environment */
-               const char *env[] = {
-                       ALTERNATE_DB_ENVIRONMENT,
-                       DB_ENVIRONMENT,
-                       GIT_DIR_ENVIRONMENT,
-                       GIT_WORK_TREE_ENVIRONMENT,
-                       GRAFT_ENVIRONMENT,
-                       INDEX_ENVIRONMENT,
-                       NO_REPLACE_OBJECTS_ENVIRONMENT,
-                       NULL
-               };
-               conn->env = env;
+               /* remove repo-local variables from the environment */
+               conn->env = local_repo_env;
                conn->use_shell = 1;
        }
        *arg++ = cmd.buf;
diff --combined git-sh-setup.sh
index 7a095665d71f153a970243a9d03d919ddef29c88,cf864a62738292cdd27d4461221369ef034516c5..6131670860514c215a6b9b7417dd05c3124e81b4
mode 100644,100755..100644
@@@ -107,19 -107,6 +107,19 @@@ git_editor() 
        eval "$GIT_EDITOR" '"$@"'
  }
  
 +git_pager() {
 +      if test -t 1
 +      then
 +              GIT_PAGER=$(git var GIT_PAGER)
 +      else
 +              GIT_PAGER=cat
 +      fi
 +      : ${LESS=-FRSX}
 +      export LESS
 +
 +      eval "$GIT_PAGER" '"$@"'
 +}
 +
  sane_grep () {
        GREP_OPTIONS= LC_ALL=C grep "$@"
  }
@@@ -141,7 -128,7 +141,7 @@@ cd_to_toplevel () 
  }
  
  require_work_tree () {
 -      test $(git rev-parse --is-inside-work-tree) = true ||
 +      test "$(git rev-parse --is-inside-work-tree 2>/dev/null)" = true ||
        die "fatal: $0 cannot be used without a working tree."
  }
  
@@@ -172,6 -159,13 +172,13 @@@ get_author_ident_from_commit () 
        LANG=C LC_ALL=C sed -ne "$pick_author_script"
  }
  
+ # Clear repo-local GIT_* environment variables. Useful when switching to
+ # another repository (e.g. when entering a submodule). See also the env
+ # list in git_connect()
+ clear_local_git_env() {
+       unset $(git rev-parse --local-env-vars)
+ }
  # Make sure we are in a valid repository of a vintage we understand,
  # if we require to be in a git repository.
  if test -z "$NONGIT_OK"
diff --combined git-submodule.sh
index 383dc451191fef4e078e9f46aaf3fdb3190ebc9a,e2082fd1492fe34e69c59f0a46cbaf7ddd2e2a8e..f21d0bfce7020edeaed8c0066760e5f55e7facb9
@@@ -222,7 -222,7 +222,7 @@@ cmd_add(
  
                module_clone "$path" "$realrepo" "$reference" || exit
                (
-                       unset GIT_DIR
+                       clear_local_git_env
                        cd "$path" &&
                        # ash fails to wordsplit ${branch:+-b "$branch"...}
                        case "$branch" in
@@@ -278,7 -278,7 +278,7 @@@ cmd_foreach(
                        name=$(module_name "$path")
                        (
                                prefix="$prefix$path/"
-                               unset GIT_DIR
+                               clear_local_git_env
                                cd "$path" &&
                                eval "$@" &&
                                if test -n "$recursive"
@@@ -434,7 -434,7 +434,7 @@@ cmd_update(
                        module_clone "$path" "$url" "$reference"|| exit
                        subsha1=
                else
-                       subsha1=$(unset GIT_DIR; cd "$path" &&
+                       subsha1=$(clear_local_git_env; cd "$path" &&
                                git rev-parse --verify HEAD) ||
                        die "Unable to find current revision in submodule path '$path'"
                fi
  
                        if test -z "$nofetch"
                        then
-                               (unset GIT_DIR; cd "$path" &&
+                               (clear_local_git_env; cd "$path" &&
                                        git-fetch) ||
                                die "Unable to fetch in submodule path '$path'"
                        fi
                                ;;
                        esac
  
-                       (unset GIT_DIR; cd "$path" && $command "$sha1") ||
+                       (clear_local_git_env; cd "$path" && $command "$sha1") ||
                        die "Unable to $action '$sha1' in submodule path '$path'"
                        say "Submodule path '$path': $msg '$sha1'"
                fi
  
                if test -n "$recursive"
                then
-                       (unset GIT_DIR; cd "$path" && cmd_update $orig_args) ||
+                       (clear_local_git_env; cd "$path" && cmd_update $orig_args) ||
                        die "Failed to recurse into submodule path '$path'"
                fi
        done
  
  set_name_rev () {
        revname=$( (
-               unset GIT_DIR
+               clear_local_git_env
                cd "$1" && {
                        git describe "$2" 2>/dev/null ||
                        git describe --tags "$2" 2>/dev/null ||
@@@ -553,15 -553,12 +553,15 @@@ cmd_summary() 
  
        test $summary_limit = 0 && return
  
 -      if rev=$(git rev-parse -q --verify "$1^0")
 +      if rev=$(git rev-parse -q --verify --default HEAD ${1+"$1"})
        then
                head=$rev
 -              shift
 +              test $# = 0 || shift
 +      elif test -z "$1" -o "$1" = "HEAD"
 +      then
 +              return
        else
 -              head=HEAD
 +              head="HEAD"
        fi
  
        if [ -n "$files" ]
@@@ -760,7 -757,7 +760,7 @@@ cmd_status(
                else
                        if test -z "$cached"
                        then
-                               sha1=$(unset GIT_DIR; cd "$path" && git rev-parse --verify HEAD)
+                               sha1=$(clear_local_git_env; cd "$path" && git rev-parse --verify HEAD)
                                set_name_rev "$path" "$sha1"
                        fi
                        say "+$sha1 $displaypath$revname"
                then
                        (
                                prefix="$displaypath/"
-                               unset GIT_DIR
+                               clear_local_git_env
                                cd "$path" &&
                                cmd_status $orig_args
                        ) ||
@@@ -821,7 -818,7 +821,7 @@@ cmd_sync(
                if test -e "$path"/.git
                then
                (
-                       unset GIT_DIR
+                       clear_local_git_env
                        cd "$path"
                        remote=$(get_default_remote)
                        say "Synchronizing submodule url for '$name'"