Merge branch 'lt/setup' into __/setup-n-mv
authorJunio C Hamano <junkio@cox.net>
Sat, 29 Jul 2006 08:54:54 +0000 (01:54 -0700)
committerJunio C Hamano <junkio@cox.net>
Sat, 29 Jul 2006 08:54:54 +0000 (01:54 -0700)
This merges the new built-in calling convention code into Johannes's
builtin-mv topic in order to resolve their conflicts early on.

Signed-off-by: Junio C Hamano <junkio@cox.net>
1  2 
Makefile
builtin-add.c
builtin-mv.c
builtin.h
git.c
diff --combined Makefile
index 73733e9025ac40708e70a2daa092744cef138708,8349e3defacca69ae48c477ff99be527b9af3b77..6ecf9ddee2c169662983c0397290928921d404d2
+++ b/Makefile
@@@ -151,7 -151,7 +151,7 @@@ SCRIPT_PERL = 
        git-archimport.perl git-cvsimport.perl git-relink.perl \
        git-shortlog.perl git-rerere.perl \
        git-annotate.perl git-cvsserver.perl \
 -      git-svnimport.perl git-mv.perl git-cvsexportcommit.perl \
 +      git-svnimport.perl git-cvsexportcommit.perl \
        git-send-email.perl git-svn.perl
  
  SCRIPT_PYTHON = \
@@@ -192,7 -192,7 +192,7 @@@ BUILT_INS = git-log$X git-whatchanged$
        git-read-tree$X git-commit-tree$X git-write-tree$X \
        git-apply$X git-show-branch$X git-diff-files$X git-update-index$X \
        git-diff-index$X git-diff-stages$X git-diff-tree$X git-cat-file$X \
 -      git-fmt-merge-msg$X git-prune$X
 +      git-fmt-merge-msg$X git-prune$X git-mv$X
  
  # what 'all' will build and 'install' will install, in gitexecdir
  ALL_PROGRAMS = $(PROGRAMS) $(SIMPLE_PROGRAMS) $(SCRIPTS)
@@@ -221,7 -221,7 +221,7 @@@ LIB_H = 
        blob.h cache.h commit.h csum-file.h delta.h \
        diff.h object.h pack.h pkt-line.h quote.h refs.h \
        run-command.h strbuf.h tag.h tree.h git-compat-util.h revision.h \
 -      tree-walk.h log-tree.h dir.h
 +      tree-walk.h log-tree.h dir.h path-list.h
  
  DIFF_OBJS = \
        diff.o diff-lib.o diffcore-break.o diffcore-order.o \
@@@ -236,7 -236,7 +236,7 @@@ LIB_OBJS = 
        server-info.o setup.o sha1_file.o sha1_name.o strbuf.o \
        tag.o tree.o usage.o config.o environment.o ctype.o copy.o \
        fetch-clone.o revision.o pager.o tree-walk.o xdiff-interface.o \
 -      alloc.o merge-file.o $(DIFF_OBJS)
 +      alloc.o merge-file.o path-list.o $(DIFF_OBJS)
  
  BUILTIN_OBJS = \
        builtin-log.o builtin-help.o builtin-count.o builtin-diff.o builtin-push.o \
        builtin-apply.o builtin-show-branch.o builtin-diff-files.o \
        builtin-diff-index.o builtin-diff-stages.o builtin-diff-tree.o \
        builtin-cat-file.o builtin-mailsplit.o builtin-stripspace.o \
 -      builtin-update-ref.o builtin-fmt-merge-msg.o builtin-prune.o
 +      builtin-update-ref.o builtin-fmt-merge-msg.o builtin-prune.o \
 +      builtin-mv.o
  
  GITLIBS = $(LIB_FILE) $(XDIFF_LIB)
  LIBS = $(GITLIBS) -lz
@@@ -615,6 -614,8 +615,8 @@@ $(SIMPLE_PROGRAMS) : git-%$X : %.
        $(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) \
                $(LIB_FILE) $(SIMPLE_LIB)
  
+ ssh-pull.o: ssh-fetch.c
+ ssh-push.o: ssh-upload.c
  git-local-fetch$X: fetch.o
  git-ssh-fetch$X: rsh.o fetch.o
  git-ssh-upload$X: rsh.o
diff --combined builtin-add.c
index 72d2853176f9c6d8b7c678bce64f5f482c2c5345,0fa7dc1f11001373e512da469d4dd4d55e18919a..f548b8007de79d66f7ed3fad0d96bce75c6bbf57
@@@ -82,13 -82,51 +82,12 @@@ static void fill_directory(struct dir_s
                prune_directory(dir, pathspec, baselen);
  }
  
 -static int add_file_to_index(const char *path, int verbose)
 -{
 -      int size, namelen;
 -      struct stat st;
 -      struct cache_entry *ce;
 -
 -      if (lstat(path, &st))
 -              die("%s: unable to stat (%s)", path, strerror(errno));
 -
 -      if (!S_ISREG(st.st_mode) && !S_ISLNK(st.st_mode))
 -              die("%s: can only add regular files or symbolic links", path);
 -
 -      namelen = strlen(path);
 -      size = cache_entry_size(namelen);
 -      ce = xcalloc(1, size);
 -      memcpy(ce->name, path, namelen);
 -      ce->ce_flags = htons(namelen);
 -      fill_stat_cache_info(ce, &st);
 -
 -      ce->ce_mode = create_ce_mode(st.st_mode);
 -      if (!trust_executable_bit) {
 -              /* If there is an existing entry, pick the mode bits
 -               * from it.
 -               */
 -              int pos = cache_name_pos(path, namelen);
 -              if (pos >= 0)
 -                      ce->ce_mode = active_cache[pos]->ce_mode;
 -      }
 -
 -      if (index_path(ce->sha1, path, &st, 1))
 -              die("unable to index file %s", path);
 -      if (add_cache_entry(ce, ADD_CACHE_OK_TO_ADD))
 -              die("unable to add %s to index",path);
 -      if (verbose)
 -              printf("add '%s'\n", path);
 -      cache_tree_invalidate_path(active_cache_tree, path);
 -      return 0;
 -}
 -
  static struct lock_file lock_file;
  
- int cmd_add(int argc, const char **argv, char **envp)
+ int cmd_add(int argc, const char **argv, const char *prefix)
  {
        int i, newfd;
        int verbose = 0, show_only = 0;
-       const char *prefix = setup_git_directory();
        const char **pathspec;
        struct dir_struct dir;
  
                }
                die(builtin_add_usage);
        }
 -      git_config(git_default_config);
        pathspec = get_pathspec(prefix, argv + i);
  
        fill_directory(&dir, pathspec);
diff --combined builtin-mv.c
index 42c2e39b2105db553b469f13da1d4211233d018e,0000000000000000000000000000000000000000..62ae937cb13f43f871bf2ec3543f7db37f9e87b6
mode 100644,000000..100644
--- /dev/null
@@@ -1,298 -1,0 +1,297 @@@
- int cmd_mv(int argc, const char **argv, char **envp)
 +/*
 + * "git mv" builtin command
 + *
 + * Copyright (C) 2006 Johannes Schindelin
 + */
 +#include <fnmatch.h>
 +
 +#include "cache.h"
 +#include "builtin.h"
 +#include "dir.h"
 +#include "cache-tree.h"
 +#include "path-list.h"
 +
 +static const char builtin_mv_usage[] =
 +"git-mv [-n] [-f] (<source> <destination> | [-k] <source>... <destination>)";
 +
 +static const char **copy_pathspec(const char *prefix, const char **pathspec,
 +                                int count, int base_name)
 +{
 +      const char **result = xmalloc((count + 1) * sizeof(const char *));
 +      memcpy(result, pathspec, count * sizeof(const char *));
 +      result[count] = NULL;
 +      if (base_name) {
 +              int i;
 +              for (i = 0; i < count; i++) {
 +                      const char *last_slash = strrchr(result[i], '/');
 +                      if (last_slash)
 +                              result[i] = last_slash + 1;
 +              }
 +      }
 +      return get_pathspec(prefix, result);
 +}
 +
 +static void show_list(const char *label, struct path_list *list)
 +{
 +      if (list->nr > 0) {
 +              int i;
 +              printf("%s", label);
 +              for (i = 0; i < list->nr; i++)
 +                      printf("%s%s", i > 0 ? ", " : "", list->items[i].path);
 +              putchar('\n');
 +      }
 +}
 +
 +static const char *add_slash(const char *path)
 +{
 +      int len = strlen(path);
 +      if (path[len - 1] != '/') {
 +              char *with_slash = xmalloc(len + 2);
 +              memcpy(with_slash, path, len);
 +              strcat(with_slash + len, "/");
 +              return with_slash;
 +      }
 +      return path;
 +}
 +
 +static struct lock_file lock_file;
 +
-       const char *prefix = setup_git_directory();
++int cmd_mv(int argc, const char **argv, const char *prefix)
 +{
 +      int i, newfd, count;
 +      int verbose = 0, show_only = 0, force = 0, ignore_errors = 0;
 +      const char **source, **destination, **dest_path;
 +      enum update_mode { BOTH = 0, WORKING_DIRECTORY, INDEX } *modes;
 +      struct stat st;
 +      struct path_list overwritten = {NULL, 0, 0, 0};
 +      struct path_list src_for_dst = {NULL, 0, 0, 0};
 +      struct path_list added = {NULL, 0, 0, 0};
 +      struct path_list deleted = {NULL, 0, 0, 0};
 +      struct path_list changed = {NULL, 0, 0, 0};
 +
 +      git_config(git_default_config);
 +
 +      newfd = hold_lock_file_for_update(&lock_file, get_index_file());
 +      if (newfd < 0)
 +              die("unable to create new index file");
 +
 +      if (read_cache() < 0)
 +              die("index file corrupt");
 +
 +      for (i = 1; i < argc; i++) {
 +              const char *arg = argv[i];
 +
 +              if (arg[0] != '-')
 +                      break;
 +              if (!strcmp(arg, "--")) {
 +                      i++;
 +                      break;
 +              }
 +              if (!strcmp(arg, "-n")) {
 +                      show_only = 1;
 +                      continue;
 +              }
 +              if (!strcmp(arg, "-f")) {
 +                      force = 1;
 +                      continue;
 +              }
 +              if (!strcmp(arg, "-k")) {
 +                      ignore_errors = 1;
 +                      continue;
 +              }
 +              die(builtin_mv_usage);
 +      }
 +      count = argc - i - 1;
 +      if (count < 1)
 +              usage(builtin_mv_usage);
 +
 +      source = copy_pathspec(prefix, argv + i, count, 0);
 +      modes = xcalloc(count, sizeof(enum update_mode));
 +      dest_path = copy_pathspec(prefix, argv + argc - 1, 1, 0);
 +
 +      if (!lstat(dest_path[0], &st) &&
 +                      S_ISDIR(st.st_mode)) {
 +              dest_path[0] = add_slash(dest_path[0]);
 +              destination = copy_pathspec(dest_path[0], argv + i, count, 1);
 +      } else {
 +              if (count != 1)
 +                      usage(builtin_mv_usage);
 +              destination = dest_path;
 +      }
 +
 +      /* Checking */
 +      for (i = 0; i < count; i++) {
 +              const char *bad = NULL;
 +
 +              if (show_only)
 +                      printf("Checking rename of '%s' to '%s'\n",
 +                              source[i], destination[i]);
 +
 +              if (lstat(source[i], &st) < 0)
 +                      bad = "bad source";
 +
 +              if (S_ISDIR(st.st_mode)) {
 +                      const char *dir = source[i], *dest_dir = destination[i];
 +                      int first, last, len = strlen(dir);
 +
 +                      if (lstat(dest_dir, &st) == 0) {
 +                              bad = "cannot move directory over file";
 +                              goto next;
 +                      }
 +
 +                      modes[i] = WORKING_DIRECTORY;
 +
 +                      first = cache_name_pos(source[i], len);
 +                      if (first >= 0)
 +                              die ("Huh? %s/ is in index?", dir);
 +
 +                      first = -1 - first;
 +                      for (last = first; last < active_nr; last++) {
 +                              const char *path = active_cache[last]->name;
 +                              if (strncmp(path, dir, len) || path[len] != '/')
 +                                      break;
 +                      }
 +
 +                      if (last - first < 1)
 +                              bad = "source directory is empty";
 +                      else if (!bad) {
 +                              int j, dst_len = strlen(dest_dir);
 +
 +                              if (last - first > 0) {
 +                                      source = realloc(source,
 +                                                      (count + last - first)
 +                                                      * sizeof(char *));
 +                                      destination = realloc(destination,
 +                                                      (count + last - first)
 +                                                      * sizeof(char *));
 +                                      modes = realloc(modes,
 +                                                      (count + last - first)
 +                                                      * sizeof(enum update_mode));
 +                              }
 +
 +                              dest_dir = add_slash(dest_dir);
 +
 +                              for (j = 0; j < last - first; j++) {
 +                                      const char *path =
 +                                              active_cache[first + j]->name;
 +                                      source[count + j] = path;
 +                                      destination[count + j] =
 +                                              prefix_path(dest_dir, dst_len,
 +                                                      path + len);
 +                                      modes[count + j] = INDEX;
 +                              }
 +                              count += last - first;
 +                      }
 +
 +                      goto next;
 +              }
 +
 +              if (!bad && lstat(destination[i], &st) == 0) {
 +                      bad = "destination exists";
 +                      if (force) {
 +                              /*
 +                               * only files can overwrite each other:
 +                               * check both source and destination
 +                               */
 +                              if (S_ISREG(st.st_mode)) {
 +                                      fprintf(stderr, "Warning: %s;"
 +                                                      " will overwrite!\n",
 +                                                      bad);
 +                                      bad = NULL;
 +                                      path_list_insert(destination[i],
 +                                                      &overwritten);
 +                              } else
 +                                      bad = "Cannot overwrite";
 +                      }
 +              }
 +
 +              if (!bad &&
 +                  !strncmp(destination[i], source[i], strlen(source[i])))
 +                      bad = "can not move directory into itself";
 +
 +              if (!bad && cache_name_pos(source[i], strlen(source[i])) < 0)
 +                      bad = "not under version control";
 +
 +              if (!bad) {
 +                      if (path_list_has_path(&src_for_dst, destination[i]))
 +                              bad = "multiple sources for the same target";
 +                      else
 +                              path_list_insert(destination[i], &src_for_dst);
 +              }
 +
 +next:
 +              if (bad) {
 +                      if (ignore_errors) {
 +                              if (--count > 0) {
 +                                      memmove(source + i, source + i + 1,
 +                                              (count - i) * sizeof(char *));
 +                                      memmove(destination + i,
 +                                              destination + i + 1,
 +                                              (count - i) * sizeof(char *));
 +                              }
 +                      } else
 +                              die ("%s, source=%s, destination=%s",
 +                                   bad, source[i], destination[i]);
 +              }
 +      }
 +
 +      for (i = 0; i < count; i++) {
 +              if (show_only || verbose)
 +                      printf("Renaming %s to %s\n",
 +                             source[i], destination[i]);
 +              if (!show_only && modes[i] != INDEX &&
 +                  rename(source[i], destination[i]) < 0 &&
 +                  !ignore_errors)
 +                      die ("renaming %s failed: %s",
 +                           source[i], strerror(errno));
 +
 +              if (modes[i] == WORKING_DIRECTORY)
 +                      continue;
 +
 +              if (cache_name_pos(source[i], strlen(source[i])) >= 0) {
 +                      path_list_insert(source[i], &deleted);
 +
 +                      /* destination can be a directory with 1 file inside */
 +                      if (path_list_has_path(&overwritten, destination[i]))
 +                              path_list_insert(destination[i], &changed);
 +                      else
 +                              path_list_insert(destination[i], &added);
 +              } else
 +                      path_list_insert(destination[i], &added);
 +      }
 +
 +        if (show_only) {
 +              show_list("Changed  : ", &changed);
 +              show_list("Adding   : ", &added);
 +              show_list("Deleting : ", &deleted);
 +      } else {
 +              for (i = 0; i < changed.nr; i++) {
 +                      const char *path = changed.items[i].path;
 +                      int i = cache_name_pos(path, strlen(path));
 +                      struct cache_entry *ce = active_cache[i];
 +
 +                      if (i < 0)
 +                              die ("Huh? Cache entry for %s unknown?", path);
 +                      refresh_cache_entry(ce, 0);
 +              }
 +
 +              for (i = 0; i < added.nr; i++) {
 +                      const char *path = added.items[i].path;
 +                      add_file_to_index(path, verbose);
 +              }
 +
 +              for (i = 0; i < deleted.nr; i++) {
 +                      const char *path = deleted.items[i].path;
 +                      remove_file_from_cache(path);
 +              }
 +
 +              if (active_cache_changed) {
 +                      if (write_cache(newfd, active_cache, active_nr) ||
 +                          close(newfd) ||
 +                          commit_lock_file(&lock_file))
 +                              die("Unable to write new index file");
 +              }
 +      }
 +
 +      return 0;
 +}
diff --combined builtin.h
index 6f3a43957c97677ae42a136dbfe292c0abeeba26,de244cdf65f106edf020ca034d9c09bb60d77285..1c8637ae22dc46961772b690d4218933725565d4
+++ b/builtin.h
@@@ -15,54 -15,53 +15,54 @@@ void cmd_usage(int show_all, const cha
  #endif
        ;
  
- extern int cmd_help(int argc, const char **argv, char **envp);
- extern int cmd_version(int argc, const char **argv, char **envp);
+ extern int cmd_help(int argc, const char **argv, const char *prefix);
+ extern int cmd_version(int argc, const char **argv, const char *prefix);
  
- extern int cmd_whatchanged(int argc, const char **argv, char **envp);
- extern int cmd_show(int argc, const char **argv, char **envp);
- extern int cmd_log(int argc, const char **argv, char **envp);
- extern int cmd_diff(int argc, const char **argv, char **envp);
- extern int cmd_format_patch(int argc, const char **argv, char **envp);
- extern int cmd_count_objects(int argc, const char **argv, char **envp);
+ extern int cmd_whatchanged(int argc, const char **argv, const char *prefix);
+ extern int cmd_show(int argc, const char **argv, const char *prefix);
+ extern int cmd_log(int argc, const char **argv, const char *prefix);
+ extern int cmd_diff(int argc, const char **argv, const char *prefix);
+ extern int cmd_format_patch(int argc, const char **argv, const char *prefix);
+ extern int cmd_count_objects(int argc, const char **argv, const char *prefix);
  
- extern int cmd_prune(int argc, const char **argv, char **envp);
+ extern int cmd_prune(int argc, const char **argv, const char *prefix);
  
- extern int cmd_push(int argc, const char **argv, char **envp);
- extern int cmd_grep(int argc, const char **argv, char **envp);
- extern int cmd_rm(int argc, const char **argv, char **envp);
- extern int cmd_add(int argc, const char **argv, char **envp);
- extern int cmd_rev_list(int argc, const char **argv, char **envp);
- extern int cmd_check_ref_format(int argc, const char **argv, char **envp);
- extern int cmd_init_db(int argc, const char **argv, char **envp);
- extern int cmd_tar_tree(int argc, const char **argv, char **envp);
- extern int cmd_upload_tar(int argc, const char **argv, char **envp);
- extern int cmd_get_tar_commit_id(int argc, const char **argv, char **envp);
- extern int cmd_ls_files(int argc, const char **argv, char **envp);
- extern int cmd_ls_tree(int argc, const char **argv, char **envp);
- extern int cmd_read_tree(int argc, const char **argv, char **envp);
- extern int cmd_commit_tree(int argc, const char **argv, char **envp);
- extern int cmd_apply(int argc, const char **argv, char **envp);
- extern int cmd_show_branch(int argc, const char **argv, char **envp);
- extern int cmd_diff_files(int argc, const char **argv, char **envp);
- extern int cmd_diff_index(int argc, const char **argv, char **envp);
- extern int cmd_diff_stages(int argc, const char **argv, char **envp);
- extern int cmd_diff_tree(int argc, const char **argv, char **envp);
- extern int cmd_cat_file(int argc, const char **argv, char **envp);
- extern int cmd_rev_parse(int argc, const char **argv, char **envp);
- extern int cmd_update_index(int argc, const char **argv, char **envp);
- extern int cmd_update_ref(int argc, const char **argv, char **envp);
- extern int cmd_fmt_merge_msg(int argc, const char **argv, char **envp);
- extern int cmd_mv(int argc, const char **argv, char **envp);
+ extern int cmd_push(int argc, const char **argv, const char *prefix);
+ extern int cmd_grep(int argc, const char **argv, const char *prefix);
+ extern int cmd_rm(int argc, const char **argv, const char *prefix);
+ extern int cmd_add(int argc, const char **argv, const char *prefix);
+ extern int cmd_rev_list(int argc, const char **argv, const char *prefix);
+ extern int cmd_check_ref_format(int argc, const char **argv, const char *prefix);
+ extern int cmd_init_db(int argc, const char **argv, const char *prefix);
+ extern int cmd_tar_tree(int argc, const char **argv, const char *prefix);
+ extern int cmd_upload_tar(int argc, const char **argv, const char *prefix);
+ extern int cmd_get_tar_commit_id(int argc, const char **argv, const char *prefix);
+ extern int cmd_ls_files(int argc, const char **argv, const char *prefix);
+ extern int cmd_ls_tree(int argc, const char **argv, const char *prefix);
+ extern int cmd_read_tree(int argc, const char **argv, const char *prefix);
+ extern int cmd_commit_tree(int argc, const char **argv, const char *prefix);
+ extern int cmd_apply(int argc, const char **argv, const char *prefix);
+ extern int cmd_show_branch(int argc, const char **argv, const char *prefix);
+ extern int cmd_diff_files(int argc, const char **argv, const char *prefix);
+ extern int cmd_diff_index(int argc, const char **argv, const char *prefix);
+ extern int cmd_diff_stages(int argc, const char **argv, const char *prefix);
+ extern int cmd_diff_tree(int argc, const char **argv, const char *prefix);
+ extern int cmd_cat_file(int argc, const char **argv, const char *prefix);
+ extern int cmd_rev_parse(int argc, const char **argv, const char *prefix);
+ extern int cmd_update_index(int argc, const char **argv, const char *prefix);
+ extern int cmd_update_ref(int argc, const char **argv, const char *prefix);
+ extern int cmd_fmt_merge_msg(int argc, const char **argv, const char *prefix);
++extern int cmd_mv(int argc, const char **argv, const char *prefix);
  
- extern int cmd_write_tree(int argc, const char **argv, char **envp);
+ extern int cmd_write_tree(int argc, const char **argv, const char *prefix);
  extern int write_tree(unsigned char *sha1, int missing_ok, const char *prefix);
  
- extern int cmd_mailsplit(int argc, const char **argv, char **envp);
+ extern int cmd_mailsplit(int argc, const char **argv, const char *prefix);
  extern int split_mbox(const char **mbox, const char *dir, int allow_bare, int nr_prec, int skip);
  
- extern int cmd_mailinfo(int argc, const char **argv, char **envp);
+ extern int cmd_mailinfo(int argc, const char **argv, const char *prefix);
  extern int mailinfo(FILE *in, FILE *out, int ks, const char *encoding, const char *msg, const char *patch);
  
- extern int cmd_stripspace(int argc, const char **argv, char **envp);
+ extern int cmd_stripspace(int argc, const char **argv, const char *prefix);
  extern void stripspace(FILE *in, FILE *out);
  #endif
diff --combined git.c
index d47e9d8db9503159b5655b22903758a05df3bf64,79db43e143b289d7e6857ee59cd8b68c7d656b49..452180e23af9250bbc7fcc8a9cca70b24129dc68
--- 1/git.c
--- 2/git.c
+++ b/git.c
@@@ -35,6 -35,59 +35,59 @@@ static void prepend_to_path(const char 
        setenv("PATH", path, 1);
  }
  
+ static int handle_options(const char*** argv, int* argc)
+ {
+       int handled = 0;
+       while (*argc > 0) {
+               const char *cmd = (*argv)[0];
+               if (cmd[0] != '-')
+                       break;
+               /*
+                * For legacy reasons, the "version" and "help"
+                * commands can be written with "--" prepended
+                * to make them look like flags.
+                */
+               if (!strcmp(cmd, "--help") || !strcmp(cmd, "--version"))
+                       break;
+               /*
+                * Check remaining flags.
+                */
+               if (!strncmp(cmd, "--exec-path", 11)) {
+                       cmd += 11;
+                       if (*cmd == '=')
+                               git_set_exec_path(cmd + 1);
+                       else {
+                               puts(git_exec_path());
+                               exit(0);
+                       }
+               } else if (!strcmp(cmd, "-p") || !strcmp(cmd, "--paginate")) {
+                       setup_pager();
+               } else if (!strcmp(cmd, "--git-dir")) {
+                       if (*argc < 1)
+                               return -1;
+                       setenv("GIT_DIR", (*argv)[1], 1);
+                       (*argv)++;
+                       (*argc)--;
+               } else if (!strncmp(cmd, "--git-dir=", 10)) {
+                       setenv("GIT_DIR", cmd + 10, 1);
+               } else if (!strcmp(cmd, "--bare")) {
+                       static char git_dir[1024];
+                       setenv("GIT_DIR", getcwd(git_dir, 1024), 1);
+               } else {
+                       fprintf(stderr, "Unknown option: %s\n", cmd);
+                       cmd_usage(0, NULL, NULL);
+               }
+               (*argv)++;
+               (*argc)--;
+               handled++;
+       }
+       return handled;
+ }
  static const char *alias_command;
  static char *alias_string = NULL;
  
@@@ -106,7 -159,7 +159,7 @@@ static int handle_alias(int *argcp, con
  
        subdir = setup_git_directory_gently(&nongit);
        if (!nongit) {
-               int count;
+               int count, option_count;
                const char** new_argv;
  
                alias_command = (*argv)[0];
                if (alias_string) {
  
                        count = split_cmdline(alias_string, &new_argv);
+                       option_count = handle_options(&new_argv, &count);
+                       memmove(new_argv - option_count, new_argv,
+                                       count * sizeof(char *));
+                       new_argv -= option_count;
  
                        if (count < 1)
                                die("empty alias for %s", alias_command);
  
  const char git_version_string[] = GIT_VERSION;
  
+ #define NEEDS_PREFIX 1
  static void handle_internal_command(int argc, const char **argv, char **envp)
  {
        const char *cmd = argv[0];
        static struct cmd_struct {
                const char *cmd;
-               int (*fn)(int, const char **, char **);
+               int (*fn)(int, const char **, const char *);
+               int prefix;
        } commands[] = {
                { "version", cmd_version },
                { "help", cmd_help },
-               { "log", cmd_log },
-               { "whatchanged", cmd_whatchanged },
-               { "show", cmd_show },
+               { "log", cmd_log, NEEDS_PREFIX },
+               { "whatchanged", cmd_whatchanged, NEEDS_PREFIX },
+               { "show", cmd_show, NEEDS_PREFIX },
                { "push", cmd_push },
-               { "format-patch", cmd_format_patch },
+               { "format-patch", cmd_format_patch, NEEDS_PREFIX },
                { "count-objects", cmd_count_objects },
-               { "diff", cmd_diff },
-               { "grep", cmd_grep },
-               { "rm", cmd_rm },
-               { "add", cmd_add },
-               { "rev-list", cmd_rev_list },
+               { "diff", cmd_diff, NEEDS_PREFIX },
+               { "grep", cmd_grep, NEEDS_PREFIX },
+               { "rm", cmd_rm, NEEDS_PREFIX },
+               { "add", cmd_add, NEEDS_PREFIX },
+               { "rev-list", cmd_rev_list, NEEDS_PREFIX },
                { "init-db", cmd_init_db },
                { "get-tar-commit-id", cmd_get_tar_commit_id },
                { "upload-tar", cmd_upload_tar },
                { "check-ref-format", cmd_check_ref_format },
-               { "ls-files", cmd_ls_files },
-               { "ls-tree", cmd_ls_tree },
-               { "tar-tree", cmd_tar_tree },
-               { "read-tree", cmd_read_tree },
-               { "commit-tree", cmd_commit_tree },
+               { "ls-files", cmd_ls_files, NEEDS_PREFIX },
+               { "ls-tree", cmd_ls_tree, NEEDS_PREFIX },
+               { "tar-tree", cmd_tar_tree, NEEDS_PREFIX },
+               { "read-tree", cmd_read_tree, NEEDS_PREFIX },
+               { "commit-tree", cmd_commit_tree, NEEDS_PREFIX },
                { "apply", cmd_apply },
-               { "show-branch", cmd_show_branch },
-               { "diff-files", cmd_diff_files },
-               { "diff-index", cmd_diff_index },
-               { "diff-stages", cmd_diff_stages },
-               { "diff-tree", cmd_diff_tree },
-               { "cat-file", cmd_cat_file },
-               { "rev-parse", cmd_rev_parse },
-               { "write-tree", cmd_write_tree },
+               { "show-branch", cmd_show_branch, NEEDS_PREFIX },
+               { "diff-files", cmd_diff_files, NEEDS_PREFIX },
+               { "diff-index", cmd_diff_index, NEEDS_PREFIX },
+               { "diff-stages", cmd_diff_stages, NEEDS_PREFIX },
+               { "diff-tree", cmd_diff_tree, NEEDS_PREFIX },
+               { "cat-file", cmd_cat_file, NEEDS_PREFIX },
+               { "rev-parse", cmd_rev_parse, NEEDS_PREFIX },
+               { "write-tree", cmd_write_tree, NEEDS_PREFIX },
                { "mailsplit", cmd_mailsplit },
                { "mailinfo", cmd_mailinfo },
                { "stripspace", cmd_stripspace },
-               { "update-index", cmd_update_index },
-               { "update-ref", cmd_update_ref },
-               { "fmt-merge-msg", cmd_fmt_merge_msg },
-               { "prune", cmd_prune },
-               { "mv", cmd_mv },
+               { "update-index", cmd_update_index, NEEDS_PREFIX },
+               { "update-ref", cmd_update_ref, NEEDS_PREFIX },
+               { "fmt-merge-msg", cmd_fmt_merge_msg, NEEDS_PREFIX },
+               { "prune", cmd_prune, NEEDS_PREFIX },
++              { "mv", cmd_mv, NEEDS_PREFIX },
        };
        int i;
  
  
        for (i = 0; i < ARRAY_SIZE(commands); i++) {
                struct cmd_struct *p = commands+i;
+               const char *prefix;
                if (strcmp(p->cmd, cmd))
                        continue;
  
+               prefix = NULL;
+               if (p->prefix)
+                       prefix = setup_git_directory();
                if (getenv("GIT_TRACE")) {
                        int i;
                        fprintf(stderr, "trace: built-in: git");
                        fflush(stderr);
                }
  
-               exit(p->fn(argc, argv, envp));
+               exit(p->fn(argc, argv, prefix));
        }
  }
  
@@@ -269,51 -332,19 +333,19 @@@ int main(int argc, const char **argv, c
                die("cannot handle %s internally", cmd);
        }
  
-       /* Default command: "help" */
-       cmd = "help";
        /* Look for flags.. */
-       while (argc > 1) {
-               cmd = *++argv;
-               argc--;
-               if (!strcmp(cmd, "-p") || !strcmp(cmd, "--paginate")) {
-                       setup_pager();
-                       continue;
-               }
-               if (strncmp(cmd, "--", 2))
-                       break;
-               cmd += 2;
-               /*
-                * For legacy reasons, the "version" and "help"
-                * commands can be written with "--" prepended
-                * to make them look like flags.
-                */
-               if (!strcmp(cmd, "help"))
-                       break;
-               if (!strcmp(cmd, "version"))
-                       break;
-               /*
-                * Check remaining flags (which by now must be
-                * "--exec-path", but maybe we will accept
-                * other arguments some day)
-                */
-               if (!strncmp(cmd, "exec-path", 9)) {
-                       cmd += 9;
-                       if (*cmd == '=') {
-                               git_set_exec_path(cmd + 1);
-                               continue;
-                       }
-                       puts(git_exec_path());
-                       exit(0);
-               }
-               cmd_usage(0, NULL, NULL);
+       argv++;
+       argc--;
+       handle_options(&argv, &argc);
+       if (argc > 0) {
+               if (!strncmp(argv[0], "--", 2))
+                       argv[0] += 2;
+       } else {
+               /* Default command: "help" */
+               argv[0] = "help";
+               argc = 1;
        }
-       argv[0] = cmd;
+       cmd = argv[0];
  
        /*
         * We search for git commands in the following order: