{"thread":{"id":"5034","subject":"Re: log and diff family: honor config even from subdirectories","startedAt":"2006-07-29T01:17:25Z","lastAt":"2006-07-29T16:52:20Z","messageCount":8,"participants":["Linus Torvalds","Junio C Hamano"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"24321","messageId":"Pine.LNX.4.64.0607281811580.4168@g5.osdl.org","threadId":"5034","inReplyTo":null,"subject":"Re: log and diff family: honor config even from subdirectories","fromName":"Linus Torvalds","fromEmail":"torvalds@osdl.org","sentAt":"2006-07-29T01:17:25Z","receivedAt":"2006-07-29T01:17:25Z","isPatch":false,"sender":{"key":"torvalds@linux-foundation.org","avatar":"https://avatars.githubusercontent.com/u/1024025?v=4"},"body":"\nJunio,\n I think your patch is fine as a band-aid, but I wonder if we shouldn't \njust move the \"setup_git_directory()\" call out of init_revisions(), and \npass it as an argument to init_revision(). Some of the callers have \nalready done setup_git_directory() earlier for their own reasons anyway.\n\nAnd from a quick look it looks like you missed the same bug happening in \ncmd_format_patch(), which calls git_config(git_format_config) before \nhaving done the setup.\n\nI'd actually _like_ to do the setup unconditionally inside the git wrapper \n(early - to make sure that we don't have this bug), but some things (at \nleast \"init-db\", \"clone\" and \"ls-remote\") are obviously not supposed to do \nit, since they work outside of a git directory. So either we need to do it \nin each builtin command separately, or we'd need to add a flag in the \ncommand descriptor array.\n\nAny clever ideas?\n\n\t\tLinus\n"},{"id":"24322","messageId":"7v3bclkwfj.fsf@assigned-by-dhcp.cox.net","threadId":"5034","inReplyTo":"Pine.LNX.4.64.0607281811580.4168@g5.osdl.org","subject":"Re: log and diff family: honor config even from subdirectories","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2006-07-29T01:54:24Z","receivedAt":"2006-07-29T01:54:24Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Linus Torvalds <torvalds@osdl.org> writes:\n\n> I'd actually _like_ to do the setup unconditionally inside the git wrapper \n> (early - to make sure that we don't have this bug), but some things (at \n> least \"init-db\", \"clone\" and \"ls-remote\") are obviously not supposed to do \n> it, since they work outside of a git directory. So either we need to do it \n> in each builtin command separately, or we'd need to add a flag in the \n> command descriptor array.\n>\n> Any clever ideas?\n>\n> \t\tLinus\n\nNo clever ideas, but I agree it would be _very_ nice if we could\ndo the setup unconditionally and early.  Some commands that call\nsetup want to know prefix, so we would need to introduce a\nglobal to hold the prefix for them.\n\nI do not do this myself, but it is conceivable that you might\nwant to be able to set GIT_DIR to point at somewhere outside\nyour working tree hierarchy, _and_ still work in a subdirectory.\nThe current setup does not allow you to do that; we could\nintroduce GIT_PROJECT_ROOT environment variable, and when\nGIT_PROJECT_ROOT exists difference between getcwd() and the\nproject root could become the value of prefix.\n"},{"id":"24329","messageId":"Pine.LNX.4.64.0607282118230.4168@g5.osdl.org","threadId":"5034","inReplyTo":"7v3bclkwfj.fsf@assigned-by-dhcp.cox.net","subject":"Call setup_git_directory() early","fromName":"Linus Torvalds","fromEmail":"torvalds@osdl.org","sentAt":"2006-07-29T04:21:48Z","receivedAt":"2006-07-29T04:21:48Z","isPatch":false,"sender":{"key":"torvalds@linux-foundation.org","avatar":"https://avatars.githubusercontent.com/u/1024025?v=4"},"body":"\nAny git command that expects to work in a subdirectory of a project, and \nthat reads the git config files (which is just about all of them) needs to \nmake sure that it does the \"setup_git_directory()\" call before it tries to \nread the config file.\n\nThis means, among other things, that we need to move the call out of \n\"init_revisions()\", and into the caller.\n\nThis does the mostly trivial conversion to do that.\n\nSigned-off-by: Linus Torvalds <torvalds@osdl.org>\n----\n\n\nOn Fri, 28 Jul 2006, Junio C Hamano wrote:\n> \n> No clever ideas, but I agree it would be _very_ nice if we could\n> do the setup unconditionally and early.  Some commands that call\n> setup want to know prefix, so we would need to introduce a\n> global to hold the prefix for them.\n\nHo humm. In the meantime, how about this? It fixes the places I noticed, \nbut is mostly just a totally mindless conversion to move the call to \n\"setup_git_directory()\" into the caller.\n\ndiff --git a/blame.c b/blame.c\nindex b04b8f5..76712b5 100644\n--- a/blame.c\n+++ b/blame.c\n@@ -834,7 +834,7 @@ int main(int argc, const char **argv)\n \t}\n \n \n-\tinit_revisions(&rev);\n+\tinit_revisions(&rev, setup_git_directory());\n \trev.remove_empty_trees = 1;\n \trev.topo_order = 1;\n \trev.prune_fn = simplify_commit;\ndiff --git a/builtin-diff-files.c b/builtin-diff-files.c\nindex 2e10118..ea2936a 100644\n--- a/builtin-diff-files.c\n+++ b/builtin-diff-files.c\n@@ -18,7 +18,7 @@ int cmd_diff_files(int argc, const char \n \tstruct rev_info rev;\n \tint silent = 0;\n \n-\tinit_revisions(&rev);\n+\tinit_revisions(&rev, setup_git_directory());\n \tgit_config(git_default_config); /* no \"diff\" UI options */\n \trev.abbrev = 0;\n \ndiff --git a/builtin-diff-index.c b/builtin-diff-index.c\nindex dc52c05..eeeee93 100644\n--- a/builtin-diff-index.c\n+++ b/builtin-diff-index.c\n@@ -15,7 +15,7 @@ int cmd_diff_index(int argc, const char \n \tint cached = 0;\n \tint i;\n \n-\tinit_revisions(&rev);\n+\tinit_revisions(&rev, setup_git_directory());\n \tgit_config(git_default_config); /* no \"diff\" UI options */\n \trev.abbrev = 0;\n \ndiff --git a/builtin-diff-tree.c b/builtin-diff-tree.c\nindex 8957b45..f8215ea 100644\n--- a/builtin-diff-tree.c\n+++ b/builtin-diff-tree.c\n@@ -67,7 +67,7 @@ int cmd_diff_tree(int argc, const char *\n \tstatic struct rev_info *opt = &log_tree_opt;\n \tint read_stdin = 0;\n \n-\tinit_revisions(opt);\n+\tinit_revisions(opt, setup_git_directory());\n \tgit_config(git_default_config); /* no \"diff\" UI options */\n \tnr_sha1 = 0;\n \topt->abbrev = 0;\ndiff --git a/builtin-diff.c b/builtin-diff.c\nindex 7d5ad62..7965c2c 100644\n--- a/builtin-diff.c\n+++ b/builtin-diff.c\n@@ -227,7 +227,7 @@ int cmd_diff(int argc, const char **argv\n \tstruct rev_info rev;\n \tstruct object_array_entry ent[100];\n \tint ents = 0, blobs = 0, paths = 0;\n-\tconst char *path = NULL;\n+\tconst char *path = NULL, *prefix;\n \tstruct blobinfo blob[2];\n \n \t/*\n@@ -250,9 +250,9 @@ int cmd_diff(int argc, const char **argv\n \t * Other cases are errors.\n \t */\n \n-\tinit_revisions(&rev);\n+\tprefix = setup_git_directory();\n \tgit_config(git_diff_ui_config);\n-\tdiff_setup(&rev.diffopt);\n+\tinit_revisions(&rev, prefix);\n \n \targc = setup_revisions(argc, argv, &rev, NULL);\n \tif (!rev.diffopt.output_format) {\ndiff --git a/builtin-fmt-merge-msg.c b/builtin-fmt-merge-msg.c\nindex f20b27b..338f209 100644\n--- a/builtin-fmt-merge-msg.c\n+++ b/builtin-fmt-merge-msg.c\n@@ -250,6 +250,7 @@ int cmd_fmt_merge_msg(int argc, char **a\n \tconst char *sep = \"\";\n \tunsigned char head_sha1[20];\n \tconst char *head, *current_branch;\n+\tconst char *prefix = setup_git_directory();\n \n \tgit_config(fmt_merge_msg_config);\n \n@@ -342,7 +343,7 @@ int cmd_fmt_merge_msg(int argc, char **a\n \t\tstruct rev_info rev;\n \n \t\thead = lookup_commit(head_sha1);\n-\t\tinit_revisions(&rev);\n+\t\tinit_revisions(&rev, prefix);\n \t\trev.commit_format = CMIT_FMT_ONELINE;\n \t\trev.ignore_merges = 1;\n \t\trev.limited = 1;\ndiff --git a/builtin-log.c b/builtin-log.c\nindex 88c835a..52064cd 100644\n--- a/builtin-log.c\n+++ b/builtin-log.c\n@@ -48,10 +48,10 @@ static int cmd_log_walk(struct rev_info \n int cmd_whatchanged(int argc, const char **argv, char **envp)\n {\n \tstruct rev_info rev;\n+\tconst char *prefix = setup_git_directory();\n \n-\tinit_revisions(&rev);\n \tgit_config(git_diff_ui_config);\n-\tdiff_setup(&rev.diffopt);\n+\tinit_revisions(&rev, prefix);\n \trev.diff = 1;\n \trev.diffopt.recursive = 1;\n \trev.simplify_history = 0;\n@@ -64,10 +64,10 @@ int cmd_whatchanged(int argc, const char\n int cmd_show(int argc, const char **argv, char **envp)\n {\n \tstruct rev_info rev;\n+\tconst char *prefix = setup_git_directory();\n \n-\tinit_revisions(&rev);\n \tgit_config(git_diff_ui_config);\n-\tdiff_setup(&rev.diffopt);\n+\tinit_revisions(&rev, prefix);\n \trev.diff = 1;\n \trev.diffopt.recursive = 1;\n \trev.combine_merges = 1;\n@@ -82,10 +82,10 @@ int cmd_show(int argc, const char **argv\n int cmd_log(int argc, const char **argv, char **envp)\n {\n \tstruct rev_info rev;\n+\tconst char *prefix = setup_git_directory();\n \n-\tinit_revisions(&rev);\n \tgit_config(git_diff_ui_config);\n-\tdiff_setup(&rev.diffopt);\n+\tinit_revisions(&rev, prefix);\n \trev.always_show_header = 1;\n \tcmd_log_init(argc, argv, envp, &rev);\n \treturn cmd_log_walk(&rev);\n@@ -188,6 +188,7 @@ static void get_patch_ids(struct rev_inf\n \tstruct object *o1, *o2;\n \tunsigned flags1, flags2;\n \tunsigned char sha1[20];\n+\tconst char *prefix = setup_git_directory();\n \n \tif (rev->pending.nr != 2)\n \t\tdie(\"Need exactly one range.\");\n@@ -206,7 +207,7 @@ static void get_patch_ids(struct rev_inf\n \t\tdie(\"diff_setup_done failed\");\n \n \t/* given a range a..b get all patch ids for b..a */\n-\tinit_revisions(&check_rev);\n+\tinit_revisions(&check_rev, prefix);\n \to1->flags ^= UNINTERESTING;\n \to2->flags ^= UNINTERESTING;\n \tadd_pending_object(&check_rev, o1, \"o1\");\n@@ -260,9 +261,10 @@ int cmd_format_patch(int argc, const cha\n \tchar *add_signoff = NULL;\n \tchar message_id[1024];\n \tchar ref_message_id[1024];\n+\tconst char *prefix = setup_git_directory();\n \n \tgit_config(git_format_config);\n-\tinit_revisions(&rev);\n+\tinit_revisions(&rev, prefix);\n \trev.commit_format = CMIT_FMT_EMAIL;\n \trev.verbose_header = 1;\n \trev.diff = 1;\ndiff --git a/builtin-prune.c b/builtin-prune.c\nindex d196c41..4ed1e1b 100644\n--- a/builtin-prune.c\n+++ b/builtin-prune.c\n@@ -234,7 +234,7 @@ int cmd_prune(int argc, const char **arg\n \t * Set up revision parsing, and mark us as being interested\n \t * in all object types, not just commits.\n \t */\n-\tinit_revisions(&revs);\n+\tinit_revisions(&revs, setup_git_directory());\n \trevs.tag_objects = 1;\n \trevs.blob_objects = 1;\n \trevs.tree_objects = 1;\ndiff --git a/builtin-rev-list.c b/builtin-rev-list.c\nindex 8f32871..2b6691c 100644\n--- a/builtin-rev-list.c\n+++ b/builtin-rev-list.c\n@@ -311,7 +311,7 @@ int cmd_rev_list(int argc, const char **\n \tstruct commit_list *list;\n \tint i;\n \n-\tinit_revisions(&revs);\n+\tinit_revisions(&revs, setup_git_directory());\n \trevs.abbrev = 0;\n \trevs.commit_format = CMIT_FMT_UNSPECIFIED;\n \targc = setup_revisions(argc, argv, &revs, NULL);\ndiff --git a/http-push.c b/http-push.c\nindex 4768619..4021e7d 100644\n--- a/http-push.c\n+++ b/http-push.c\n@@ -2521,7 +2521,7 @@ int main(int argc, char **argv)\n \t\t\tcommit_argv[3] = old_sha1_hex;\n \t\t\tcommit_argc++;\n \t\t}\n-\t\tinit_revisions(&revs);\n+\t\tinit_revisions(&revs, setup_git_directory());\n \t\tsetup_revisions(commit_argc, commit_argv, &revs, NULL);\n \t\tfree(new_sha1_hex);\n \t\tif (old_sha1_hex) {\ndiff --git a/revision.c b/revision.c\nindex 874e349..a58257a 100644\n--- a/revision.c\n+++ b/revision.c\n@@ -509,7 +509,7 @@ static int add_parents_only(struct rev_i\n \treturn 1;\n }\n \n-void init_revisions(struct rev_info *revs)\n+void init_revisions(struct rev_info *revs, const char *prefix)\n {\n \tmemset(revs, 0, sizeof(*revs));\n \n@@ -521,7 +521,7 @@ void init_revisions(struct rev_info *rev\n \trevs->pruning.change = file_change;\n \trevs->lifo = 1;\n \trevs->dense = 1;\n-\trevs->prefix = setup_git_directory();\n+\trevs->prefix = prefix;\n \trevs->max_age = -1;\n \trevs->min_age = -1;\n \trevs->max_count = -1;\ndiff --git a/revision.h b/revision.h\nindex e23ec8f..0c3b8d9 100644\n--- a/revision.h\n+++ b/revision.h\n@@ -87,7 +87,7 @@ #define REV_TREE_DIFFERENT\t2\n extern int rev_same_tree_as_empty(struct rev_info *, struct tree *t1);\n extern int rev_compare_tree(struct rev_info *, struct tree *t1, struct tree *t2);\n \n-extern void init_revisions(struct rev_info *revs);\n+extern void init_revisions(struct rev_info *revs, const char *prefix);\n extern int setup_revisions(int argc, const char **argv, struct rev_info *revs, const char *def);\n extern void prepare_revision_walk(struct rev_info *revs);\n extern struct commit *get_revision(struct rev_info *revs);\n"},{"id":"24331","messageId":"7vslklja3v.fsf_-_@assigned-by-dhcp.cox.net","threadId":"5034","inReplyTo":"Pine.LNX.4.64.0607282118230.4168@g5.osdl.org","subject":"An alternative: call setup_git_directory() early","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2006-07-29T04:41:56Z","receivedAt":"2006-07-29T04:41:56Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"We classify built-in commands into three classes: ones that\nrequire to know where the .git directory is, ones that could use\nthe knowledge of where the .git directory is but can operate\nwithout, and ones that should not attempt any .git discovery.\n\nMost of the commands fall within the first category.\napply, mailsplit and mailinfo falls within the second category\n(e.g. patches can be applied to non-git files without --index),\nand the last category includes init-db (which should never do\na discovery).\n\nSigned-off-by: Junio C Hamano <junkio@cox.net>\n---\n\n> On Fri, 28 Jul 2006, Junio C Hamano wrote:\n>> \n>> No clever ideas, but I agree it would be _very_ nice if we could\n>> do the setup unconditionally and early.  Some commands that call\n>> setup want to know prefix, so we would need to introduce a\n>> global to hold the prefix for them.\n>\n> Ho humm. In the meantime, how about this? It fixes the places I noticed, \n> but is mostly just a totally mindless conversion to move the call to \n> \"setup_git_directory()\" into the caller.\n\nI guess our mails crossed.  This seems to pass all the tests but\nour test do not cover subdirectory operation that much.\n\n\ndiff --git a/builtin-add.c b/builtin-add.c\nindex 3a73a17..07a29bc 100644\n--- a/builtin-add.c\n+++ b/builtin-add.c\n@@ -127,7 +127,7 @@ int cmd_add(int argc, const char **argv,\n {\n \tint i, newfd;\n \tint verbose = 0, show_only = 0;\n-\tconst char *prefix = setup_git_directory();\n+\tconst char *prefix = git_prefix;\n \tconst char **pathspec;\n \tstruct dir_struct dir;\n \ndiff --git a/builtin-apply.c b/builtin-apply.c\nindex d4381d9..fb06cc3 100644\n--- a/builtin-apply.c\n+++ b/builtin-apply.c\n@@ -2370,7 +2370,7 @@ int cmd_apply(int argc, const char **arg\n \t\t}\n \n \t\tif (check_index && prefix_length < 0) {\n-\t\t\tprefix = setup_git_directory();\n+\t\t\tprefix = git_prefix;\n \t\t\tprefix_length = prefix ? strlen(prefix) : 0;\n \t\t\tgit_config(git_apply_config);\n \t\t\tif (!whitespace_option && apply_default_whitespace)\ndiff --git a/builtin-cat-file.c b/builtin-cat-file.c\nindex 4d36817..53b15ef 100644\n--- a/builtin-cat-file.c\n+++ b/builtin-cat-file.c\n@@ -102,7 +102,6 @@ int cmd_cat_file(int argc, const char **\n \tunsigned long size;\n \tint opt;\n \n-\tsetup_git_directory();\n \tgit_config(git_default_config);\n \tif (argc != 3)\n \t\tusage(\"git-cat-file [-t|-s|-e|-p|<type>] <sha1>\");\ndiff --git a/builtin-commit-tree.c b/builtin-commit-tree.c\nindex ec082bf..cae544b 100644\n--- a/builtin-commit-tree.c\n+++ b/builtin-commit-tree.c\n@@ -88,8 +88,6 @@ int cmd_commit_tree(int argc, const char\n \tunsigned int size;\n \n \tsetup_ident();\n-\tsetup_git_directory();\n-\n \tgit_config(git_default_config);\n \n \tif (argc < 2)\ndiff --git a/builtin-diff-stages.c b/builtin-diff-stages.c\nindex 9c62702..9630a37 100644\n--- a/builtin-diff-stages.c\n+++ b/builtin-diff-stages.c\n@@ -58,7 +58,7 @@ static void diff_stages(int stage1, int \n int cmd_diff_stages(int ac, const char **av, char **envp)\n {\n \tint stage1, stage2;\n-\tconst char *prefix = setup_git_directory();\n+\tconst char *prefix = git_prefix;\n \tconst char **pathspec = NULL;\n \n \tgit_config(git_default_config); /* no \"diff\" UI options */\ndiff --git a/builtin-grep.c b/builtin-grep.c\nindex a79bac3..713cca1 100644\n--- a/builtin-grep.c\n+++ b/builtin-grep.c\n@@ -926,7 +926,7 @@ int cmd_grep(int argc, const char **argv\n \tint seen_dashdash = 0;\n \tstruct grep_opt opt;\n \tstruct object_array list = { 0, 0, NULL };\n-\tconst char *prefix = setup_git_directory();\n+\tconst char *prefix = git_prefix;\n \tconst char **paths = NULL;\n \tint i;\n \ndiff --git a/builtin-ls-files.c b/builtin-ls-files.c\nindex 8dae9f7..49e848e 100644\n--- a/builtin-ls-files.c\n+++ b/builtin-ls-files.c\n@@ -329,7 +329,7 @@ int cmd_ls_files(int argc, const char **\n \tstruct dir_struct dir;\n \n \tmemset(&dir, 0, sizeof(dir));\n-\tprefix = setup_git_directory();\n+\tprefix = git_prefix;\n \tif (prefix)\n \t\tprefix_offset = strlen(prefix);\n \tgit_config(git_default_config);\ndiff --git a/builtin-ls-tree.c b/builtin-ls-tree.c\nindex b8d0d88..5cd4964 100644\n--- a/builtin-ls-tree.c\n+++ b/builtin-ls-tree.c\n@@ -90,7 +90,7 @@ int cmd_ls_tree(int argc, const char **a\n \tunsigned char sha1[20];\n \tstruct tree *tree;\n \n-\tprefix = setup_git_directory();\n+\tprefix = git_prefix;\n \tgit_config(git_default_config);\n \tif (prefix && *prefix)\n \t\tchomp_prefix = strlen(prefix);\ndiff --git a/builtin-read-tree.c b/builtin-read-tree.c\nindex 122b6f1..375347d 100644\n--- a/builtin-read-tree.c\n+++ b/builtin-read-tree.c\n@@ -882,7 +882,6 @@ int cmd_read_tree(int argc, const char *\n \tstate.quiet = 1;\n \tstate.refresh_cache = 1;\n \n-\tsetup_git_directory();\n \tgit_config(git_default_config);\n \n \tnewfd = hold_lock_file_for_update(&lock_file, get_index_file());\ndiff --git a/builtin-rev-parse.c b/builtin-rev-parse.c\nindex b3e4386..cca9b05 100644\n--- a/builtin-rev-parse.c\n+++ b/builtin-rev-parse.c\n@@ -213,7 +213,7 @@ int cmd_rev_parse(int argc, const char *\n {\n \tint i, as_is = 0, verify = 0;\n \tunsigned char sha1[20];\n-\tconst char *prefix = setup_git_directory();\n+\tconst char *prefix = git_prefix;\n \n \tgit_config(git_default_config);\n \ndiff --git a/builtin-rm.c b/builtin-rm.c\nindex bb810ba..25d0da3 100644\n--- a/builtin-rm.c\n+++ b/builtin-rm.c\n@@ -47,7 +47,7 @@ int cmd_rm(int argc, const char **argv, \n {\n \tint i, newfd;\n \tint verbose = 0, show_only = 0, force = 0;\n-\tconst char *prefix = setup_git_directory();\n+\tconst char *prefix = git_prefix;\n \tconst char **pathspec;\n \tchar *seen;\n \ndiff --git a/builtin-show-branch.c b/builtin-show-branch.c\nindex 82f75b7..43ab1f8 100644\n--- a/builtin-show-branch.c\n+++ b/builtin-show-branch.c\n@@ -573,7 +573,6 @@ int cmd_show_branch(int ac, const char *\n \tint topics = 0;\n \tint dense = 1;\n \n-\tsetup_git_directory();\n \tgit_config(git_show_branch_config);\n \n \t/* If nothing is specified, try the default first */\ndiff --git a/builtin-tar-tree.c b/builtin-tar-tree.c\nindex e5aaded..3e6b736 100644\n--- a/builtin-tar-tree.c\n+++ b/builtin-tar-tree.c\n@@ -319,7 +319,6 @@ static int generate_tar(int argc, const \n \tcurrent_path.alloc = PATH_MAX;\n \tcurrent_path.len = current_path.eof = 0;\n \n-\tsetup_git_directory();\n \tgit_config(git_tar_config);\n \n \tswitch (argc) {\ndiff --git a/builtin-update-index.c b/builtin-update-index.c\nindex 1a4200d..c64506b 100644\n--- a/builtin-update-index.c\n+++ b/builtin-update-index.c\n@@ -481,7 +481,7 @@ int cmd_update_index(int argc, const cha\n \tint i, newfd, entries, has_errors = 0, line_termination = '\\n';\n \tint allow_options = 1;\n \tint read_from_stdin = 0;\n-\tconst char *prefix = setup_git_directory();\n+\tconst char *prefix = git_prefix;\n \tint prefix_length = prefix ? strlen(prefix) : 0;\n \tchar set_executable_bit = 0;\n \tunsigned int refresh_flags = 0;\ndiff --git a/builtin-update-ref.c b/builtin-update-ref.c\nindex 83094ab..8138eba 100644\n--- a/builtin-update-ref.c\n+++ b/builtin-update-ref.c\n@@ -13,7 +13,6 @@ int cmd_update_ref(int argc, const char \n \tint i;\n \n \tsetup_ident();\n-\tsetup_git_directory();\n \tgit_config(git_default_config);\n \n \tfor (i = 1; i < argc; i++) {\ndiff --git a/builtin-write-tree.c b/builtin-write-tree.c\nindex 449a4d1..d987d0b 100644\n--- a/builtin-write-tree.c\n+++ b/builtin-write-tree.c\n@@ -66,8 +66,6 @@ int cmd_write_tree(int argc, const char \n \tconst char *prefix = NULL;\n \tunsigned char sha1[20];\n \n-\tsetup_git_directory();\n-\n \twhile (1 < argc) {\n \t\tconst char *arg = argv[1];\n \t\tif (!strcmp(arg, \"--missing-ok\"))\ndiff --git a/cache.h b/cache.h\nindex eee5fc9..6c008f9 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -130,6 +130,8 @@ extern char *get_graft_file(void);\n \n #define ALTERNATE_DB_ENVIRONMENT \"GIT_ALTERNATE_OBJECT_DIRECTORIES\"\n \n+extern int gitdir_not_found;\n+extern const char *git_prefix;\n extern const char **get_pathspec(const char *prefix, const char **pathspec);\n extern const char *setup_git_directory_gently(int *);\n extern const char *setup_git_directory(void);\ndiff --git a/environment.c b/environment.c\nindex 42f39d6..2fb978d 100644\n--- a/environment.c\n+++ b/environment.c\n@@ -23,6 +23,8 @@ int shared_repository = PERM_UMASK;\n const char *apply_default_whitespace = NULL;\n int zlib_compression_level = Z_DEFAULT_COMPRESSION;\n int pager_in_use;\n+int gitdir_not_found;\n+const char *git_prefix;\n \n static char *git_dir, *git_object_dir, *git_index_file, *git_refs_dir,\n \t*git_graft_file;\ndiff --git a/git.c b/git.c\nindex 885e1ce..a9d6340 100644\n--- a/git.c\n+++ b/git.c\n@@ -220,45 +220,50 @@ static void handle_internal_command(int \n \tstatic struct cmd_struct {\n \t\tconst char *cmd;\n \t\tint (*fn)(int, const char **, char **);\n+\t\tenum use_gitdir {\n+\t\t\tGITDIR_OPTIONAL,\n+\t\t\tGITDIR_REQUIRED,\n+\t\t\tGITDIR_DONTCARE,\n+\t\t} use_gitdir;\n \t} commands[] = {\n-\t\t{ \"version\", cmd_version },\n-\t\t{ \"help\", cmd_help },\n-\t\t{ \"log\", cmd_log },\n-\t\t{ \"whatchanged\", cmd_whatchanged },\n-\t\t{ \"show\", cmd_show },\n-\t\t{ \"push\", cmd_push },\n-\t\t{ \"format-patch\", cmd_format_patch },\n-\t\t{ \"count-objects\", cmd_count_objects },\n-\t\t{ \"diff\", cmd_diff },\n-\t\t{ \"grep\", cmd_grep },\n-\t\t{ \"rm\", cmd_rm },\n-\t\t{ \"add\", cmd_add },\n-\t\t{ \"rev-list\", cmd_rev_list },\n-\t\t{ \"init-db\", cmd_init_db },\n-\t\t{ \"get-tar-commit-id\", cmd_get_tar_commit_id },\n-\t\t{ \"upload-tar\", cmd_upload_tar },\n-\t\t{ \"check-ref-format\", cmd_check_ref_format },\n-\t\t{ \"ls-files\", cmd_ls_files },\n-\t\t{ \"ls-tree\", cmd_ls_tree },\n-\t\t{ \"tar-tree\", cmd_tar_tree },\n-\t\t{ \"read-tree\", cmd_read_tree },\n-\t\t{ \"commit-tree\", cmd_commit_tree },\n-\t\t{ \"apply\", cmd_apply },\n-\t\t{ \"show-branch\", cmd_show_branch },\n-\t\t{ \"diff-files\", cmd_diff_files },\n-\t\t{ \"diff-index\", cmd_diff_index },\n-\t\t{ \"diff-stages\", cmd_diff_stages },\n-\t\t{ \"diff-tree\", cmd_diff_tree },\n-\t\t{ \"cat-file\", cmd_cat_file },\n-\t\t{ \"rev-parse\", cmd_rev_parse },\n-\t\t{ \"write-tree\", cmd_write_tree },\n-\t\t{ \"mailsplit\", cmd_mailsplit },\n-\t\t{ \"mailinfo\", cmd_mailinfo },\n-\t\t{ \"stripspace\", cmd_stripspace },\n-\t\t{ \"update-index\", cmd_update_index },\n-\t\t{ \"update-ref\", cmd_update_ref },\n-\t\t{ \"fmt-merge-msg\", cmd_fmt_merge_msg },\n-\t\t{ \"prune\", cmd_prune },\n+\t\t{ \"version\", cmd_version, GITDIR_DONTCARE },\n+\t\t{ \"help\", cmd_help, GITDIR_DONTCARE },\n+\t\t{ \"log\", cmd_log, GITDIR_REQUIRED },\n+\t\t{ \"whatchanged\", cmd_whatchanged, GITDIR_REQUIRED },\n+\t\t{ \"show\", cmd_show, GITDIR_REQUIRED },\n+\t\t{ \"push\", cmd_push, GITDIR_REQUIRED },\n+\t\t{ \"format-patch\", cmd_format_patch, GITDIR_REQUIRED },\n+\t\t{ \"count-objects\", cmd_count_objects, GITDIR_REQUIRED },\n+\t\t{ \"diff\", cmd_diff, GITDIR_REQUIRED },\n+\t\t{ \"grep\", cmd_grep, GITDIR_REQUIRED },\n+\t\t{ \"rm\", cmd_rm, GITDIR_REQUIRED },\n+\t\t{ \"add\", cmd_add, GITDIR_REQUIRED },\n+\t\t{ \"rev-list\", cmd_rev_list, GITDIR_REQUIRED },\n+\t\t{ \"init-db\", cmd_init_db, GITDIR_DONTCARE },\n+\t\t{ \"get-tar-commit-id\", cmd_get_tar_commit_id, GITDIR_REQUIRED },\n+\t\t{ \"upload-tar\", cmd_upload_tar, GITDIR_REQUIRED },\n+\t\t{ \"check-ref-format\", cmd_check_ref_format, GITDIR_DONTCARE },\n+\t\t{ \"ls-files\", cmd_ls_files, GITDIR_REQUIRED },\n+\t\t{ \"ls-tree\", cmd_ls_tree, GITDIR_REQUIRED },\n+\t\t{ \"tar-tree\", cmd_tar_tree, GITDIR_REQUIRED },\n+\t\t{ \"read-tree\", cmd_read_tree, GITDIR_REQUIRED },\n+\t\t{ \"commit-tree\", cmd_commit_tree, GITDIR_REQUIRED },\n+\t\t{ \"apply\", cmd_apply, GITDIR_OPTIONAL },\n+\t\t{ \"show-branch\", cmd_show_branch, GITDIR_REQUIRED },\n+\t\t{ \"diff-files\", cmd_diff_files, GITDIR_REQUIRED },\n+\t\t{ \"diff-index\", cmd_diff_index, GITDIR_REQUIRED },\n+\t\t{ \"diff-stages\", cmd_diff_stages, GITDIR_REQUIRED },\n+\t\t{ \"diff-tree\", cmd_diff_tree, GITDIR_REQUIRED },\n+\t\t{ \"cat-file\", cmd_cat_file, GITDIR_REQUIRED },\n+\t\t{ \"rev-parse\", cmd_rev_parse, GITDIR_REQUIRED },\n+\t\t{ \"write-tree\", cmd_write_tree, GITDIR_REQUIRED },\n+\t\t{ \"mailsplit\", cmd_mailsplit, GITDIR_OPTIONAL },\n+\t\t{ \"mailinfo\", cmd_mailinfo, GITDIR_OPTIONAL },\n+\t\t{ \"stripspace\", cmd_stripspace, GITDIR_OPTIONAL },\n+\t\t{ \"update-index\", cmd_update_index, GITDIR_REQUIRED },\n+\t\t{ \"update-ref\", cmd_update_ref, GITDIR_REQUIRED },\n+\t\t{ \"fmt-merge-msg\", cmd_fmt_merge_msg, GITDIR_DONTCARE },\n+\t\t{ \"prune\", cmd_prune, GITDIR_REQUIRED },\n \t};\n \tint i;\n \n@@ -284,6 +289,18 @@ static void handle_internal_command(int \n \t\t\tfflush(stderr);\n \t\t}\n \n+\t\tgitdir_not_found = 0;\n+\t\tswitch (p->use_gitdir) {\n+\t\tcase GITDIR_REQUIRED:\n+\t\t\tgit_prefix = setup_git_directory();\n+\t\t\tbreak;\n+\t\tcase GITDIR_OPTIONAL:\n+\t\t\tgit_prefix =\n+\t\t\t\tsetup_git_directory_gently(&gitdir_not_found);\n+\t\t\tbreak;\n+\t\tcase GITDIR_DONTCARE:\n+\t\t\tbreak;\n+\t\t}\n \t\texit(p->fn(argc, argv, envp));\n \t}\n }\ndiff --git a/t/trash/path0 b/t/trash/path0\ndeleted file mode 100644\nindex f87290f..0000000\n--- a/t/trash/path0\n+++ /dev/null\n@@ -1 +0,0 @@\n-hello path0\ndiff --git a/t/trash/path0sym b/t/trash/path0sym\ndeleted file mode 120000\nindex 15a9843..0000000\n--- a/t/trash/path0sym\n+++ /dev/null\n@@ -1 +0,0 @@\n-hello path0\n\\ No newline at end of file\ndiff --git a/t/trash/path2/file2 b/t/trash/path2/file2\ndeleted file mode 100644\nindex 3feff94..0000000\n--- a/t/trash/path2/file2\n+++ /dev/null\n@@ -1 +0,0 @@\n-hello path2/file2\ndiff --git a/t/trash/path2/file2sym b/t/trash/path2/file2sym\ndeleted file mode 120000\nindex d8ce161..0000000\n--- a/t/trash/path2/file2sym\n+++ /dev/null\n@@ -1 +0,0 @@\n-hello path2/file2\n\\ No newline at end of file\ndiff --git a/t/trash/path3/file3 b/t/trash/path3/file3\ndeleted file mode 100644\nindex 0aa34ca..0000000\n--- a/t/trash/path3/file3\n+++ /dev/null\n@@ -1 +0,0 @@\n-hello path3/file3\ndiff --git a/t/trash/path3/file3sym b/t/trash/path3/file3sym\ndeleted file mode 120000\nindex 8599103..0000000\n--- a/t/trash/path3/file3sym\n+++ /dev/null\n@@ -1 +0,0 @@\n-hello path3/file3\n\\ No newline at end of file\ndiff --git a/t/trash/path3/subp3/file3 b/t/trash/path3/subp3/file3\ndeleted file mode 100644\nindex 00fb590..0000000\n--- a/t/trash/path3/subp3/file3\n+++ /dev/null\n@@ -1 +0,0 @@\n-hello path3/subp3/file3\ndiff --git a/t/trash/path3/subp3/file3sym b/t/trash/path3/subp3/file3sym\ndeleted file mode 120000\nindex 6649a1e..0000000\n--- a/t/trash/path3/subp3/file3sym\n+++ /dev/null\n@@ -1 +0,0 @@\n-hello path3/subp3/file3\n\\ No newline at end of file\n"},{"id":"24332","messageId":"7vodv9j8yg.fsf@assigned-by-dhcp.cox.net","threadId":"5034","inReplyTo":"Pine.LNX.4.64.0607282118230.4168@g5.osdl.org","subject":"Re: Call setup_git_directory() early","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2006-07-29T05:06:47Z","receivedAt":"2006-07-29T05:06:47Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Sorry for the earlier crapoid.  The diffs contained there for\nt/trash stuff were due to my earlier version that marked init-db\nto be GITDIR_OPTIONAL -- which caused the \"optional\" discovery\nto find the .git/ directory two levels up (relative to t/trash)\nand contaminating the primary index file by mistake (Yuck).\n\nYour patch makes a lot of sense.\n"},{"id":"24333","messageId":"Pine.LNX.4.64.0607282223320.4168@g5.osdl.org","threadId":"5034","inReplyTo":"7vodv9j8yg.fsf@assigned-by-dhcp.cox.net","subject":"Re: Call setup_git_directory() early","fromName":"Linus Torvalds","fromEmail":"torvalds@osdl.org","sentAt":"2006-07-29T05:44:25Z","receivedAt":"2006-07-29T05:44:25Z","isPatch":false,"sender":{"key":"torvalds@linux-foundation.org","avatar":"https://avatars.githubusercontent.com/u/1024025?v=4"},"body":"\n\nOn Fri, 28 Jul 2006, Junio C Hamano wrote:\n> \n> Your patch makes a lot of sense.\n\nI don't think they are mutually incompatible.\n\nMy patch moves the call to \"setup_git_directory()\" a _bit_ earlier, and if \nwe just keep doing it, we'll end up with at least a subset of your patch. \n\nAnyway, this was what I came up with when I did that \"incremental\" thing. \nIt's a bit like your patch, but a lot more invasive because it changes the \ncalling convention for the builtin commands (but it's cleaner because of \nit, I think).\n\nThis is on top of my previous patch. What do you think? It does delete \nmore lines than it adds..\n\n\t\tLinus\n\n---\n 35 files changed, 109 insertions(+), 114 deletions(-)\n\n\ndiff --git a/builtin-add.c b/builtin-add.c\nindex 3a73a17..0fa7dc1 100644\n--- a/builtin-add.c\n+++ b/builtin-add.c\n@@ -123,11 +123,10 @@ static int add_file_to_index(const char \n \n static struct lock_file lock_file;\n \n-int cmd_add(int argc, const char **argv, char **envp)\n+int cmd_add(int argc, const char **argv, const char *prefix)\n {\n \tint i, newfd;\n \tint verbose = 0, show_only = 0;\n-\tconst char *prefix = setup_git_directory();\n \tconst char **pathspec;\n \tstruct dir_struct dir;\n \ndiff --git a/builtin-apply.c b/builtin-apply.c\nindex d924ac3..c1ba99e 100644\n--- a/builtin-apply.c\n+++ b/builtin-apply.c\n@@ -2222,7 +2222,7 @@ static int git_apply_config(const char *\n }\n \n \n-int cmd_apply(int argc, const char **argv, char **envp)\n+int cmd_apply(int argc, const char **argv, const char *prefix)\n {\n \tint i;\n \tint read_stdin = 1;\ndiff --git a/builtin-cat-file.c b/builtin-cat-file.c\nindex 4d36817..d796431 100644\n--- a/builtin-cat-file.c\n+++ b/builtin-cat-file.c\n@@ -94,7 +94,7 @@ static int pprint_tag(const unsigned cha\n \treturn 0;\n }\n \n-int cmd_cat_file(int argc, const char **argv, char **envp)\n+int cmd_cat_file(int argc, const char **argv, const char *prefix)\n {\n \tunsigned char sha1[20];\n \tchar type[20];\ndiff --git a/builtin-check-ref-format.c b/builtin-check-ref-format.c\nindex 4a23936..701de43 100644\n--- a/builtin-check-ref-format.c\n+++ b/builtin-check-ref-format.c\n@@ -6,7 +6,7 @@ #include \"cache.h\"\n #include \"refs.h\"\n #include \"builtin.h\"\n \n-int cmd_check_ref_format(int argc, const char **argv, char **envp)\n+int cmd_check_ref_format(int argc, const char **argv, const char *prefix)\n {\n \tif (argc != 2)\n \t\tusage(\"git check-ref-format refname\");\ndiff --git a/builtin-commit-tree.c b/builtin-commit-tree.c\nindex ec082bf..e6fb16d 100644\n--- a/builtin-commit-tree.c\n+++ b/builtin-commit-tree.c\n@@ -77,7 +77,7 @@ static int new_parent(int idx)\n \treturn 1;\n }\n \n-int cmd_commit_tree(int argc, const char **argv, char **envp)\n+int cmd_commit_tree(int argc, const char **argv, const char *prefix)\n {\n \tint i;\n \tint parents = 0;\ndiff --git a/builtin-count.c b/builtin-count.c\nindex 5ee72df..1d3729a 100644\n--- a/builtin-count.c\n+++ b/builtin-count.c\n@@ -67,7 +67,7 @@ static void count_objects(DIR *d, char *\n \t}\n }\n \n-int cmd_count_objects(int ac, const char **av, char **ep)\n+int cmd_count_objects(int ac, const char **av, const char *prefix)\n {\n \tint i;\n \tint verbose = 0;\ndiff --git a/builtin-diff-files.c b/builtin-diff-files.c\nindex ea2936a..da51284 100644\n--- a/builtin-diff-files.c\n+++ b/builtin-diff-files.c\n@@ -13,7 +13,7 @@ static const char diff_files_usage[] =\n \"git-diff-files [-q] [-0/-1/2/3 |-c|--cc] [<common diff options>] [<path>...]\"\n COMMON_DIFF_OPTIONS_HELP;\n \n-int cmd_diff_files(int argc, const char **argv, char **envp)\n+int cmd_diff_files(int argc, const char **argv, const char *prefix)\n {\n \tstruct rev_info rev;\n \tint silent = 0;\ndiff --git a/builtin-diff-index.c b/builtin-diff-index.c\nindex eeeee93..bedb90c 100644\n--- a/builtin-diff-index.c\n+++ b/builtin-diff-index.c\n@@ -9,7 +9,7 @@ static const char diff_cache_usage[] =\n \"[<common diff options>] <tree-ish> [<path>...]\"\n COMMON_DIFF_OPTIONS_HELP;\n \n-int cmd_diff_index(int argc, const char **argv, char **envp)\n+int cmd_diff_index(int argc, const char **argv, const char *prefix)\n {\n \tstruct rev_info rev;\n \tint cached = 0;\ndiff --git a/builtin-diff-stages.c b/builtin-diff-stages.c\nindex 9c62702..5960e08 100644\n--- a/builtin-diff-stages.c\n+++ b/builtin-diff-stages.c\n@@ -55,10 +55,9 @@ static void diff_stages(int stage1, int \n \t}\n }\n \n-int cmd_diff_stages(int ac, const char **av, char **envp)\n+int cmd_diff_stages(int ac, const char **av, const char *prefix)\n {\n \tint stage1, stage2;\n-\tconst char *prefix = setup_git_directory();\n \tconst char **pathspec = NULL;\n \n \tgit_config(git_default_config); /* no \"diff\" UI options */\ndiff --git a/builtin-diff-tree.c b/builtin-diff-tree.c\nindex f8215ea..816946b 100644\n--- a/builtin-diff-tree.c\n+++ b/builtin-diff-tree.c\n@@ -59,7 +59,7 @@ static const char diff_tree_usage[] =\n \"  --root        include the initial commit as diff against /dev/null\\n\"\n COMMON_DIFF_OPTIONS_HELP;\n \n-int cmd_diff_tree(int argc, const char **argv, char **envp)\n+int cmd_diff_tree(int argc, const char **argv, const char *prefix)\n {\n \tint nr_sha1;\n \tchar line[1000];\ndiff --git a/builtin-diff.c b/builtin-diff.c\nindex 7965c2c..4a592e6 100644\n--- a/builtin-diff.c\n+++ b/builtin-diff.c\n@@ -221,13 +221,13 @@ void add_head(struct rev_info *revs)\n \tadd_pending_object(revs, obj, \"HEAD\");\n }\n \n-int cmd_diff(int argc, const char **argv, char **envp)\n+int cmd_diff(int argc, const char **argv, const char *prefix)\n {\n \tint i;\n \tstruct rev_info rev;\n \tstruct object_array_entry ent[100];\n \tint ents = 0, blobs = 0, paths = 0;\n-\tconst char *path = NULL, *prefix;\n+\tconst char *path = NULL;\n \tstruct blobinfo blob[2];\n \n \t/*\n@@ -250,7 +250,6 @@ int cmd_diff(int argc, const char **argv\n \t * Other cases are errors.\n \t */\n \n-\tprefix = setup_git_directory();\n \tgit_config(git_diff_ui_config);\n \tinit_revisions(&rev, prefix);\n \ndiff --git a/builtin-fmt-merge-msg.c b/builtin-fmt-merge-msg.c\nindex 338f209..c84224e 100644\n--- a/builtin-fmt-merge-msg.c\n+++ b/builtin-fmt-merge-msg.c\n@@ -242,7 +242,7 @@ static void shortlog(const char *name, u\n \tfree_list(&subjects);\n }\n \n-int cmd_fmt_merge_msg(int argc, char **argv, char **envp)\n+int cmd_fmt_merge_msg(int argc, char **argv, const char *prefix)\n {\n \tint limit = 20, i = 0;\n \tchar line[1024];\n@@ -250,7 +250,6 @@ int cmd_fmt_merge_msg(int argc, char **a\n \tconst char *sep = \"\";\n \tunsigned char head_sha1[20];\n \tconst char *head, *current_branch;\n-\tconst char *prefix = setup_git_directory();\n \n \tgit_config(fmt_merge_msg_config);\n \ndiff --git a/builtin-grep.c b/builtin-grep.c\nindex a79bac3..69b7c48 100644\n--- a/builtin-grep.c\n+++ b/builtin-grep.c\n@@ -919,14 +919,13 @@ static const char emsg_missing_context_l\n static const char emsg_missing_argument[] =\n \"option requires an argument -%s\";\n \n-int cmd_grep(int argc, const char **argv, char **envp)\n+int cmd_grep(int argc, const char **argv, const char *prefix)\n {\n \tint hit = 0;\n \tint cached = 0;\n \tint seen_dashdash = 0;\n \tstruct grep_opt opt;\n \tstruct object_array list = { 0, 0, NULL };\n-\tconst char *prefix = setup_git_directory();\n \tconst char **paths = NULL;\n \tint i;\n \ndiff --git a/builtin-help.c b/builtin-help.c\nindex 335fe5f..7f7701e 100644\n--- a/builtin-help.c\n+++ b/builtin-help.c\n@@ -221,13 +221,13 @@ static void show_man_page(const char *gi\n \texeclp(\"man\", \"man\", page, NULL);\n }\n \n-int cmd_version(int argc, const char **argv, char **envp)\n+int cmd_version(int argc, const char **argv, const char *prefix)\n {\n \tprintf(\"git version %s\\n\", git_version_string);\n \treturn 0;\n }\n \n-int cmd_help(int argc, const char **argv, char **envp)\n+int cmd_help(int argc, const char **argv, const char *prefix)\n {\n \tconst char *help_cmd = argv[1];\n \tif (!help_cmd)\ndiff --git a/builtin-init-db.c b/builtin-init-db.c\nindex 7fdd2fa..52473ed 100644\n--- a/builtin-init-db.c\n+++ b/builtin-init-db.c\n@@ -250,7 +250,7 @@ static const char init_db_usage[] =\n  * On the other hand, it might just make lookup slower and messier. You\n  * be the judge.  The default case is to have one DB per managed directory.\n  */\n-int cmd_init_db(int argc, const char **argv, char **envp)\n+int cmd_init_db(int argc, const char **argv, const char *prefix)\n {\n \tconst char *git_dir;\n \tconst char *sha1_dir;\ndiff --git a/builtin-log.c b/builtin-log.c\nindex 52064cd..82c69d1 100644\n--- a/builtin-log.c\n+++ b/builtin-log.c\n@@ -16,7 +16,7 @@ #include <sys/time.h>\n /* this is in builtin-diff.c */\n void add_head(struct rev_info *revs);\n \n-static void cmd_log_init(int argc, const char **argv, char **envp,\n+static void cmd_log_init(int argc, const char **argv, const char *prefix,\n \t\t      struct rev_info *rev)\n {\n \trev->abbrev = DEFAULT_ABBREV;\n@@ -45,26 +45,24 @@ static int cmd_log_walk(struct rev_info \n \treturn 0;\n }\n \n-int cmd_whatchanged(int argc, const char **argv, char **envp)\n+int cmd_whatchanged(int argc, const char **argv, const char *prefix)\n {\n \tstruct rev_info rev;\n-\tconst char *prefix = setup_git_directory();\n \n \tgit_config(git_diff_ui_config);\n \tinit_revisions(&rev, prefix);\n \trev.diff = 1;\n \trev.diffopt.recursive = 1;\n \trev.simplify_history = 0;\n-\tcmd_log_init(argc, argv, envp, &rev);\n+\tcmd_log_init(argc, argv, prefix, &rev);\n \tif (!rev.diffopt.output_format)\n \t\trev.diffopt.output_format = DIFF_FORMAT_RAW;\n \treturn cmd_log_walk(&rev);\n }\n \n-int cmd_show(int argc, const char **argv, char **envp)\n+int cmd_show(int argc, const char **argv, const char *prefix)\n {\n \tstruct rev_info rev;\n-\tconst char *prefix = setup_git_directory();\n \n \tgit_config(git_diff_ui_config);\n \tinit_revisions(&rev, prefix);\n@@ -75,19 +73,18 @@ int cmd_show(int argc, const char **argv\n \trev.always_show_header = 1;\n \trev.ignore_merges = 0;\n \trev.no_walk = 1;\n-\tcmd_log_init(argc, argv, envp, &rev);\n+\tcmd_log_init(argc, argv, prefix, &rev);\n \treturn cmd_log_walk(&rev);\n }\n \n-int cmd_log(int argc, const char **argv, char **envp)\n+int cmd_log(int argc, const char **argv, const char *prefix)\n {\n \tstruct rev_info rev;\n-\tconst char *prefix = setup_git_directory();\n \n \tgit_config(git_diff_ui_config);\n \tinit_revisions(&rev, prefix);\n \trev.always_show_header = 1;\n-\tcmd_log_init(argc, argv, envp, &rev);\n+\tcmd_log_init(argc, argv, prefix, &rev);\n \treturn cmd_log_walk(&rev);\n }\n \n@@ -181,14 +178,13 @@ static int get_patch_id(struct commit *c\n \treturn diff_flush_patch_id(options, sha1);\n }\n \n-static void get_patch_ids(struct rev_info *rev, struct diff_options *options)\n+static void get_patch_ids(struct rev_info *rev, struct diff_options *options, const char *prefix)\n {\n \tstruct rev_info check_rev;\n \tstruct commit *commit;\n \tstruct object *o1, *o2;\n \tunsigned flags1, flags2;\n \tunsigned char sha1[20];\n-\tconst char *prefix = setup_git_directory();\n \n \tif (rev->pending.nr != 2)\n \t\tdie(\"Need exactly one range.\");\n@@ -244,7 +240,7 @@ static void gen_message_id(char *dest, u\n \t\t (int)(email_end - email_start - 1), email_start + 1);\n }\n \n-int cmd_format_patch(int argc, const char **argv, char **envp)\n+int cmd_format_patch(int argc, const char **argv, const char *prefix)\n {\n \tstruct commit *commit;\n \tstruct commit **list = NULL;\n@@ -261,7 +257,6 @@ int cmd_format_patch(int argc, const cha\n \tchar *add_signoff = NULL;\n \tchar message_id[1024];\n \tchar ref_message_id[1024];\n-\tconst char *prefix = setup_git_directory();\n \n \tgit_config(git_format_config);\n \tinit_revisions(&rev, prefix);\n@@ -368,7 +363,7 @@ int cmd_format_patch(int argc, const cha\n \t}\n \n \tif (ignore_if_in_upstream)\n-\t\tget_patch_ids(&rev, &patch_id_opts);\n+\t\tget_patch_ids(&rev, &patch_id_opts, prefix);\n \n \tif (!use_stdout)\n \t\trealstdout = fdopen(dup(1), \"w\");\ndiff --git a/builtin-ls-files.c b/builtin-ls-files.c\nindex 8dae9f7..e906c81 100644\n--- a/builtin-ls-files.c\n+++ b/builtin-ls-files.c\n@@ -322,7 +322,7 @@ static const char ls_files_usage[] =\n \t\"[ --exclude-per-directory=<filename> ] [--full-name] [--abbrev] \"\n \t\"[--] [<file>]*\";\n \n-int cmd_ls_files(int argc, const char **argv, char** envp)\n+int cmd_ls_files(int argc, const char **argv, const char *prefix)\n {\n \tint i;\n \tint exc_given = 0;\ndiff --git a/builtin-ls-tree.c b/builtin-ls-tree.c\nindex b8d0d88..d31efe9 100644\n--- a/builtin-ls-tree.c\n+++ b/builtin-ls-tree.c\n@@ -18,7 +18,7 @@ static int abbrev = 0;\n static int ls_options = 0;\n static const char **pathspec;\n static int chomp_prefix = 0;\n-static const char *prefix;\n+static const char *ls_tree_prefix;\n \n static const char ls_tree_usage[] =\n \t\"git-ls-tree [-d] [-r] [-t] [-z] [--name-only] [--name-status] [--full-name] [--abbrev[=<n>]] <tree-ish> [path...]\";\n@@ -71,7 +71,7 @@ static int show_tree(const unsigned char\n \t\treturn 0;\n \n \tif (chomp_prefix &&\n-\t    (baselen < chomp_prefix || memcmp(prefix, base, chomp_prefix)))\n+\t    (baselen < chomp_prefix || memcmp(ls_tree_prefix, base, chomp_prefix)))\n \t\treturn 0;\n \n \tif (!(ls_options & LS_NAME_ONLY))\n@@ -85,13 +85,14 @@ static int show_tree(const unsigned char\n \treturn retval;\n }\n \n-int cmd_ls_tree(int argc, const char **argv, char **envp)\n+int cmd_ls_tree(int argc, const char **argv, const char *prefix)\n {\n \tunsigned char sha1[20];\n \tstruct tree *tree;\n \n \tprefix = setup_git_directory();\n \tgit_config(git_default_config);\n+\tls_tree_prefix = prefix;\n \tif (prefix && *prefix)\n \t\tchomp_prefix = strlen(prefix);\n \twhile (1 < argc && argv[1][0] == '-') {\ndiff --git a/builtin-mailinfo.c b/builtin-mailinfo.c\nindex 05dc1bf..24a4fc6 100644\n--- a/builtin-mailinfo.c\n+++ b/builtin-mailinfo.c\n@@ -836,7 +836,7 @@ int mailinfo(FILE *in, FILE *out, int ks\n static const char mailinfo_usage[] =\n \t\"git-mailinfo [-k] [-u | --encoding=<encoding>] msg patch <mail >info\";\n \n-int cmd_mailinfo(int argc, const char **argv, char **envp)\n+int cmd_mailinfo(int argc, const char **argv, const char *prefix)\n {\n \t/* NEEDSWORK: might want to do the optional .git/ directory\n \t * discovery\ndiff --git a/builtin-mailsplit.c b/builtin-mailsplit.c\nindex e2a0058..91a699d 100644\n--- a/builtin-mailsplit.c\n+++ b/builtin-mailsplit.c\n@@ -138,7 +138,7 @@ out:\n \tfree(name);\n \treturn ret;\n }\n-int cmd_mailsplit(int argc, const char **argv, char **envp)\n+int cmd_mailsplit(int argc, const char **argv, const char *prefix)\n {\n \tint nr = 0, nr_prec = 4, ret;\n \tint allow_bare = 0;\ndiff --git a/builtin-prune.c b/builtin-prune.c\nindex 4ed1e1b..15bb650 100644\n--- a/builtin-prune.c\n+++ b/builtin-prune.c\n@@ -217,7 +217,7 @@ static void add_cache_refs(void)\n \t\tadd_cache_tree(active_cache_tree);\n }\n \n-int cmd_prune(int argc, const char **argv, char **envp)\n+int cmd_prune(int argc, const char **argv, const char *prefix)\n {\n \tint i;\n \ndiff --git a/builtin-push.c b/builtin-push.c\nindex 31cbfd7..a824171 100644\n--- a/builtin-push.c\n+++ b/builtin-push.c\n@@ -270,7 +270,7 @@ static int do_push(const char *repo)\n \treturn 0;\n }\n \n-int cmd_push(int argc, const char **argv, char **envp)\n+int cmd_push(int argc, const char **argv, const char *prefix)\n {\n \tint i;\n \tconst char *repo = \"origin\";\t/* default repository */\ndiff --git a/builtin-read-tree.c b/builtin-read-tree.c\nindex 122b6f1..25ca69c 100644\n--- a/builtin-read-tree.c\n+++ b/builtin-read-tree.c\n@@ -870,7 +870,7 @@ static const char read_tree_usage[] = \"g\n \n static struct lock_file lock_file;\n \n-int cmd_read_tree(int argc, const char **argv, char **envp)\n+int cmd_read_tree(int argc, const char **argv, const char *prefix)\n {\n \tint i, newfd, stage = 0;\n \tunsigned char sha1[20];\ndiff --git a/builtin-rev-list.c b/builtin-rev-list.c\nindex 2b6691c..65b4d0c 100644\n--- a/builtin-rev-list.c\n+++ b/builtin-rev-list.c\n@@ -306,7 +306,7 @@ static void mark_edges_uninteresting(str\n \t}\n }\n \n-int cmd_rev_list(int argc, const char **argv, char **envp)\n+int cmd_rev_list(int argc, const char **argv, const char *prefix)\n {\n \tstruct commit_list *list;\n \tint i;\ndiff --git a/builtin-rev-parse.c b/builtin-rev-parse.c\nindex b3e4386..aca4a36 100644\n--- a/builtin-rev-parse.c\n+++ b/builtin-rev-parse.c\n@@ -209,11 +209,10 @@ static int try_difference(const char *ar\n \treturn 0;\n }\n \n-int cmd_rev_parse(int argc, const char **argv, char **envp)\n+int cmd_rev_parse(int argc, const char **argv, const char *prefix)\n {\n \tint i, as_is = 0, verify = 0;\n \tunsigned char sha1[20];\n-\tconst char *prefix = setup_git_directory();\n \n \tgit_config(git_default_config);\n \ndiff --git a/builtin-rm.c b/builtin-rm.c\nindex bb810ba..92d205a 100644\n--- a/builtin-rm.c\n+++ b/builtin-rm.c\n@@ -43,11 +43,10 @@ static int remove_file(const char *name)\n \n static struct lock_file lock_file;\n \n-int cmd_rm(int argc, const char **argv, char **envp)\n+int cmd_rm(int argc, const char **argv, const char *prefix)\n {\n \tint i, newfd;\n \tint verbose = 0, show_only = 0, force = 0;\n-\tconst char *prefix = setup_git_directory();\n \tconst char **pathspec;\n \tchar *seen;\n \ndiff --git a/builtin-show-branch.c b/builtin-show-branch.c\nindex 82f75b7..9c7f9f6 100644\n--- a/builtin-show-branch.c\n+++ b/builtin-show-branch.c\n@@ -550,7 +550,7 @@ static int omit_in_dense(struct commit *\n \treturn 0;\n }\n \n-int cmd_show_branch(int ac, const char **av, char **envp)\n+int cmd_show_branch(int ac, const char **av, const char *prefix)\n {\n \tstruct commit *rev[MAX_REVS], *commit;\n \tstruct commit_list *list = NULL, *seen = NULL;\ndiff --git a/builtin-stripspace.c b/builtin-stripspace.c\nindex 2ce1264..09cc910 100644\n--- a/builtin-stripspace.c\n+++ b/builtin-stripspace.c\n@@ -54,7 +54,7 @@ void stripspace(FILE *in, FILE *out)\n \t\tfputc('\\n', out);\n }\n \n-int cmd_stripspace(int argc, const char **argv, char **envp)\n+int cmd_stripspace(int argc, const char **argv, const char *prefix)\n {\n \tstripspace(stdin, stdout);\n \treturn 0;\ndiff --git a/builtin-tar-tree.c b/builtin-tar-tree.c\nindex e5aaded..637d22e 100644\n--- a/builtin-tar-tree.c\n+++ b/builtin-tar-tree.c\n@@ -308,7 +308,7 @@ int git_tar_config(const char *var, cons\n \treturn git_default_config(var, value);\n }\n \n-static int generate_tar(int argc, const char **argv, char** envp)\n+static int generate_tar(int argc, const char **argv, const char *prefix)\n {\n \tunsigned char sha1[20], tree_sha1[20];\n \tstruct commit *commit;\n@@ -402,19 +402,19 @@ static int remote_tar(int argc, const ch\n \treturn !!ret;\n }\n \n-int cmd_tar_tree(int argc, const char **argv, char **envp)\n+int cmd_tar_tree(int argc, const char **argv, const char *prefix)\n {\n \tif (argc < 2)\n \t\tusage(tar_tree_usage);\n \tif (!strncmp(\"--remote=\", argv[1], 9))\n \t\treturn remote_tar(argc, argv);\n-\treturn generate_tar(argc, argv, envp);\n+\treturn generate_tar(argc, argv, prefix);\n }\n \n /* ustar header + extended global header content */\n #define HEADERSIZE (2 * RECORDSIZE)\n \n-int cmd_get_tar_commit_id(int argc, const char **argv, char **envp)\n+int cmd_get_tar_commit_id(int argc, const char **argv, const char *prefix)\n {\n \tchar buffer[HEADERSIZE];\n \tstruct ustar_header *header = (struct ustar_header *)buffer;\ndiff --git a/builtin-update-index.c b/builtin-update-index.c\nindex 1a4200d..24dca47 100644\n--- a/builtin-update-index.c\n+++ b/builtin-update-index.c\n@@ -476,12 +476,11 @@ static int do_reupdate(int ac, const cha\n \treturn 0;\n }\n \n-int cmd_update_index(int argc, const char **argv, char **envp)\n+int cmd_update_index(int argc, const char **argv, const char *prefix)\n {\n \tint i, newfd, entries, has_errors = 0, line_termination = '\\n';\n \tint allow_options = 1;\n \tint read_from_stdin = 0;\n-\tconst char *prefix = setup_git_directory();\n \tint prefix_length = prefix ? strlen(prefix) : 0;\n \tchar set_executable_bit = 0;\n \tunsigned int refresh_flags = 0;\ndiff --git a/builtin-update-ref.c b/builtin-update-ref.c\nindex 83094ab..acdf39a 100644\n--- a/builtin-update-ref.c\n+++ b/builtin-update-ref.c\n@@ -5,7 +5,7 @@ #include \"builtin.h\"\n static const char git_update_ref_usage[] =\n \"git-update-ref <refname> <value> [<oldval>] [-m <reason>]\";\n \n-int cmd_update_ref(int argc, const char **argv, char **envp)\n+int cmd_update_ref(int argc, const char **argv, const char *prefix)\n {\n \tconst char *refname=NULL, *value=NULL, *oldval=NULL, *msg=NULL;\n \tstruct ref_lock *lock;\ndiff --git a/builtin-upload-tar.c b/builtin-upload-tar.c\nindex d4fa7b5..7b401bb 100644\n--- a/builtin-upload-tar.c\n+++ b/builtin-upload-tar.c\n@@ -15,7 +15,7 @@ static int nak(const char *reason)\n \treturn 1;\n }\n \n-int cmd_upload_tar(int argc, const char **argv, char **envp)\n+int cmd_upload_tar(int argc, const char **argv, const char *prefix)\n {\n \tint len;\n \tconst char *dir = argv[1];\ndiff --git a/builtin-write-tree.c b/builtin-write-tree.c\nindex 449a4d1..0f2dd7c 100644\n--- a/builtin-write-tree.c\n+++ b/builtin-write-tree.c\n@@ -60,7 +60,7 @@ int write_tree(unsigned char *sha1, int \n \treturn 0;\n }\n \n-int cmd_write_tree(int argc, const char **argv, char **envp)\n+int cmd_write_tree(int argc, const char **argv, const char *unused_prefix)\n {\n \tint missing_ok = 0, ret;\n \tconst char *prefix = NULL;\ndiff --git a/builtin.h b/builtin.h\nindex 5339d86..de244cd 100644\n--- a/builtin.h\n+++ b/builtin.h\n@@ -15,53 +15,53 @@ #ifdef __GNUC__\n #endif\n \t;\n \n-extern int cmd_help(int argc, const char **argv, char **envp);\n-extern int cmd_version(int argc, const char **argv, char **envp);\n+extern int cmd_help(int argc, const char **argv, const char *prefix);\n+extern int cmd_version(int argc, const char **argv, const char *prefix);\n \n-extern int cmd_whatchanged(int argc, const char **argv, char **envp);\n-extern int cmd_show(int argc, const char **argv, char **envp);\n-extern int cmd_log(int argc, const char **argv, char **envp);\n-extern int cmd_diff(int argc, const char **argv, char **envp);\n-extern int cmd_format_patch(int argc, const char **argv, char **envp);\n-extern int cmd_count_objects(int argc, const char **argv, char **envp);\n+extern int cmd_whatchanged(int argc, const char **argv, const char *prefix);\n+extern int cmd_show(int argc, const char **argv, const char *prefix);\n+extern int cmd_log(int argc, const char **argv, const char *prefix);\n+extern int cmd_diff(int argc, const char **argv, const char *prefix);\n+extern int cmd_format_patch(int argc, const char **argv, const char *prefix);\n+extern int cmd_count_objects(int argc, const char **argv, const char *prefix);\n \n-extern int cmd_prune(int argc, const char **argv, char **envp);\n+extern int cmd_prune(int argc, const char **argv, const char *prefix);\n \n-extern int cmd_push(int argc, const char **argv, char **envp);\n-extern int cmd_grep(int argc, const char **argv, char **envp);\n-extern int cmd_rm(int argc, const char **argv, char **envp);\n-extern int cmd_add(int argc, const char **argv, char **envp);\n-extern int cmd_rev_list(int argc, const char **argv, char **envp);\n-extern int cmd_check_ref_format(int argc, const char **argv, char **envp);\n-extern int cmd_init_db(int argc, const char **argv, char **envp);\n-extern int cmd_tar_tree(int argc, const char **argv, char **envp);\n-extern int cmd_upload_tar(int argc, const char **argv, char **envp);\n-extern int cmd_get_tar_commit_id(int argc, const char **argv, char **envp);\n-extern int cmd_ls_files(int argc, const char **argv, char **envp);\n-extern int cmd_ls_tree(int argc, const char **argv, char **envp);\n-extern int cmd_read_tree(int argc, const char **argv, char **envp);\n-extern int cmd_commit_tree(int argc, const char **argv, char **envp);\n-extern int cmd_apply(int argc, const char **argv, char **envp);\n-extern int cmd_show_branch(int argc, const char **argv, char **envp);\n-extern int cmd_diff_files(int argc, const char **argv, char **envp);\n-extern int cmd_diff_index(int argc, const char **argv, char **envp);\n-extern int cmd_diff_stages(int argc, const char **argv, char **envp);\n-extern int cmd_diff_tree(int argc, const char **argv, char **envp);\n-extern int cmd_cat_file(int argc, const char **argv, char **envp);\n-extern int cmd_rev_parse(int argc, const char **argv, char **envp);\n-extern int cmd_update_index(int argc, const char **argv, char **envp);\n-extern int cmd_update_ref(int argc, const char **argv, char **envp);\n-extern int cmd_fmt_merge_msg(int argc, const char **argv, char **envp);\n+extern int cmd_push(int argc, const char **argv, const char *prefix);\n+extern int cmd_grep(int argc, const char **argv, const char *prefix);\n+extern int cmd_rm(int argc, const char **argv, const char *prefix);\n+extern int cmd_add(int argc, const char **argv, const char *prefix);\n+extern int cmd_rev_list(int argc, const char **argv, const char *prefix);\n+extern int cmd_check_ref_format(int argc, const char **argv, const char *prefix);\n+extern int cmd_init_db(int argc, const char **argv, const char *prefix);\n+extern int cmd_tar_tree(int argc, const char **argv, const char *prefix);\n+extern int cmd_upload_tar(int argc, const char **argv, const char *prefix);\n+extern int cmd_get_tar_commit_id(int argc, const char **argv, const char *prefix);\n+extern int cmd_ls_files(int argc, const char **argv, const char *prefix);\n+extern int cmd_ls_tree(int argc, const char **argv, const char *prefix);\n+extern int cmd_read_tree(int argc, const char **argv, const char *prefix);\n+extern int cmd_commit_tree(int argc, const char **argv, const char *prefix);\n+extern int cmd_apply(int argc, const char **argv, const char *prefix);\n+extern int cmd_show_branch(int argc, const char **argv, const char *prefix);\n+extern int cmd_diff_files(int argc, const char **argv, const char *prefix);\n+extern int cmd_diff_index(int argc, const char **argv, const char *prefix);\n+extern int cmd_diff_stages(int argc, const char **argv, const char *prefix);\n+extern int cmd_diff_tree(int argc, const char **argv, const char *prefix);\n+extern int cmd_cat_file(int argc, const char **argv, const char *prefix);\n+extern int cmd_rev_parse(int argc, const char **argv, const char *prefix);\n+extern int cmd_update_index(int argc, const char **argv, const char *prefix);\n+extern int cmd_update_ref(int argc, const char **argv, const char *prefix);\n+extern int cmd_fmt_merge_msg(int argc, const char **argv, const char *prefix);\n \n-extern int cmd_write_tree(int argc, const char **argv, char **envp);\n+extern int cmd_write_tree(int argc, const char **argv, const char *prefix);\n extern int write_tree(unsigned char *sha1, int missing_ok, const char *prefix);\n \n-extern int cmd_mailsplit(int argc, const char **argv, char **envp);\n+extern int cmd_mailsplit(int argc, const char **argv, const char *prefix);\n extern int split_mbox(const char **mbox, const char *dir, int allow_bare, int nr_prec, int skip);\n \n-extern int cmd_mailinfo(int argc, const char **argv, char **envp);\n+extern int cmd_mailinfo(int argc, const char **argv, const char *prefix);\n extern int mailinfo(FILE *in, FILE *out, int ks, const char *encoding, const char *msg, const char *patch);\n \n-extern int cmd_stripspace(int argc, const char **argv, char **envp);\n+extern int cmd_stripspace(int argc, const char **argv, const char *prefix);\n extern void stripspace(FILE *in, FILE *out);\n #endif\ndiff --git a/git.c b/git.c\nindex ee5a0e8..e810d5c 100644\n--- a/git.c\n+++ b/git.c\n@@ -157,25 +157,28 @@ static int handle_alias(int *argcp, cons\n \n const char git_version_string[] = GIT_VERSION;\n \n+#define NEEDS_PREFIX 1\n+\n static void handle_internal_command(int argc, const char **argv, char **envp)\n {\n \tconst char *cmd = argv[0];\n \tstatic struct cmd_struct {\n \t\tconst char *cmd;\n-\t\tint (*fn)(int, const char **, char **);\n+\t\tint (*fn)(int, const char **, const char *);\n+\t\tint prefix;\n \t} commands[] = {\n \t\t{ \"version\", cmd_version },\n \t\t{ \"help\", cmd_help },\n-\t\t{ \"log\", cmd_log },\n-\t\t{ \"whatchanged\", cmd_whatchanged },\n-\t\t{ \"show\", cmd_show },\n+\t\t{ \"log\", cmd_log, NEEDS_PREFIX },\n+\t\t{ \"whatchanged\", cmd_whatchanged, NEEDS_PREFIX },\n+\t\t{ \"show\", cmd_show, NEEDS_PREFIX },\n \t\t{ \"push\", cmd_push },\n-\t\t{ \"format-patch\", cmd_format_patch },\n+\t\t{ \"format-patch\", cmd_format_patch, NEEDS_PREFIX },\n \t\t{ \"count-objects\", cmd_count_objects },\n-\t\t{ \"diff\", cmd_diff },\n-\t\t{ \"grep\", cmd_grep },\n-\t\t{ \"rm\", cmd_rm },\n-\t\t{ \"add\", cmd_add },\n+\t\t{ \"diff\", cmd_diff, NEEDS_PREFIX },\n+\t\t{ \"grep\", cmd_grep, NEEDS_PREFIX },\n+\t\t{ \"rm\", cmd_rm, NEEDS_PREFIX },\n+\t\t{ \"add\", cmd_add, NEEDS_PREFIX },\n \t\t{ \"rev-list\", cmd_rev_list },\n \t\t{ \"init-db\", cmd_init_db },\n \t\t{ \"get-tar-commit-id\", cmd_get_tar_commit_id },\n@@ -190,17 +193,17 @@ static void handle_internal_command(int \n \t\t{ \"show-branch\", cmd_show_branch },\n \t\t{ \"diff-files\", cmd_diff_files },\n \t\t{ \"diff-index\", cmd_diff_index },\n-\t\t{ \"diff-stages\", cmd_diff_stages },\n+\t\t{ \"diff-stages\", cmd_diff_stages, NEEDS_PREFIX },\n \t\t{ \"diff-tree\", cmd_diff_tree },\n \t\t{ \"cat-file\", cmd_cat_file },\n-\t\t{ \"rev-parse\", cmd_rev_parse },\n+\t\t{ \"rev-parse\", cmd_rev_parse, NEEDS_PREFIX },\n \t\t{ \"write-tree\", cmd_write_tree },\n \t\t{ \"mailsplit\", cmd_mailsplit },\n \t\t{ \"mailinfo\", cmd_mailinfo },\n \t\t{ \"stripspace\", cmd_stripspace },\n-\t\t{ \"update-index\", cmd_update_index },\n+\t\t{ \"update-index\", cmd_update_index, NEEDS_PREFIX },\n \t\t{ \"update-ref\", cmd_update_ref },\n-\t\t{ \"fmt-merge-msg\", cmd_fmt_merge_msg },\n+\t\t{ \"fmt-merge-msg\", cmd_fmt_merge_msg, NEEDS_PREFIX },\n \t\t{ \"prune\", cmd_prune },\n \t};\n \tint i;\n@@ -213,9 +216,13 @@ static void handle_internal_command(int \n \n \tfor (i = 0; i < ARRAY_SIZE(commands); i++) {\n \t\tstruct cmd_struct *p = commands+i;\n+\t\tconst char *prefix;\n \t\tif (strcmp(p->cmd, cmd))\n \t\t\tcontinue;\n \n+\t\tprefix = NULL;\n+\t\tif (p->prefix)\n+\t\t\tprefix = setup_git_directory();\n \t\tif (getenv(\"GIT_TRACE\")) {\n \t\t\tint i;\n \t\t\tfprintf(stderr, \"trace: built-in: git\");\n@@ -227,7 +234,7 @@ static void handle_internal_command(int \n \t\t\tfflush(stderr);\n \t\t}\n \n-\t\texit(p->fn(argc, argv, envp));\n+\t\texit(p->fn(argc, argv, prefix));\n \t}\n }\n \n"},{"id":"24335","messageId":"7vzmesg4g3.fsf@assigned-by-dhcp.cox.net","threadId":"5034","inReplyTo":"Pine.LNX.4.64.0607282223320.4168@g5.osdl.org","subject":"Re: Call setup_git_directory() early","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2006-07-29T09:12:28Z","receivedAt":"2006-07-29T09:12:28Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Linus Torvalds <torvalds@osdl.org> writes:\n\n> On Fri, 28 Jul 2006, Junio C Hamano wrote:\n>> \n>> Your patch makes a lot of sense.\n>\n> I don't think they are mutually incompatible.\n\nI agree.  I was apologizing for the crap under t/trash in the\nprevious patch -- the rest were more or less in the same spirit\nas yours.\n\n> This is on top of my previous patch. What do you think? It does delete \n> more lines than it adds..\n\nLet me understand what is going on here.\n\n> +#define NEEDS_PREFIX 1\n>...\n>  \t\t{ \"init-db\", cmd_init_db },\n\nThis is an oddball that wants to always use $GIT_DIR environment\nor \"./.git\" if $GIT_DIR is not exported, and should never go\nlooking for GIT_DIR, so we should not give NEEDS_PREFIX, ever.\n\n>  \t\t{ \"stripspace\", cmd_stripspace },\n>  \t\t{ \"mailsplit\", cmd_mailsplit },\n>  \t\t{ \"get-tar-commit-id\", cmd_get_tar_commit_id },\n\nThese are the other extreme -- they really do not care about\noperating in a git context.\n\n  \t\t{ \"push\", cmd_push },\n  \t\t{ \"count-objects\", cmd_count_objects },\n\t\t{ \"check-ref-format\", cmd_check_ref_format },\n\nOne rule seems to be that the commands that work at the while\nrepository level do not have NEEDS_PREFIX -- they will never\nwork from a subdirectory.\n\nThere is no technical reason not to let count-objects find\n$GIT_DIR on its own, but the current implementation does not do\nthat and you are keeping the behaviour bug-to-bug compatible.\n\n> +\t\t{ \"diff\", cmd_diff, NEEDS_PREFIX },\n> +\t\t{ \"grep\", cmd_grep, NEEDS_PREFIX },\n> +\t\t{ \"rm\", cmd_rm, NEEDS_PREFIX },\n> +\t\t{ \"add\", cmd_add, NEEDS_PREFIX },\n> +\t\t{ \"update-index\", cmd_update_index, NEEDS_PREFIX },\n> +\t\t{ \"rev-parse\", cmd_rev_parse, NEEDS_PREFIX },\n> +\t\t{ \"fmt-merge-msg\", cmd_fmt_merge_msg, NEEDS_PREFIX },\n\nAnother rule: porcelain-ish should work from subdirectories, and\nthey do not have to call setup_git_directory() on their own.\n\n>  \t\t{ \"rev-list\", cmd_rev_list },\n\nI think we should mark this with NEEDS_PREFIX, and lose the call\nto setup_git_directory() it has here:\n\n        ...\n         int cmd_rev_list(int argc, const char **argv, const char *prefix)\n         {\n                 struct commit_list *list;\n                 int i;\n\n        -        init_revisions(&revs, setup_git_directory());\n        +        init_revisions(&revs, prefix);\n        ...\n\n>  \t\t{ \"diff-files\", cmd_diff_files },\n>  \t\t{ \"diff-index\", cmd_diff_index },\n>  \t\t{ \"diff-tree\", cmd_diff_tree },\n>  \t\t{ \"prune\", cmd_prune },\n\t\t{ \"ls-files\", cmd_ls_files },\n\t\t{ \"ls-tree\", cmd_ls_tree },\n\t\t{ \"tar-tree\", cmd_tar_tree },\n\t\t{ \"read-tree\", cmd_read_tree },\n\t\t{ \"commit-tree\", cmd_commit_tree },\n\nLikewise with the above group.\n\n>  \t\t{ \"show-branch\", cmd_show_branch },\n>  \t\t{ \"cat-file\", cmd_cat_file },\n>  \t\t{ \"write-tree\", cmd_write_tree },\n>  \t\t{ \"update-ref\", cmd_update_ref },\n\nThese call setup_git_directory() on their own and discard the\nresulting prefix; they do want to know where $GIT_DIR is to find\nobjects and refs, so maybe we would want to mark these with\nNEEDS_PREFIX and lose their own setup_git_directory(), like the\nprevious group.  Perhaps you were thinking about splitting\nsetup_git_directory() into two independent functions, one for\nfinding out GIT_DIR, another for finding prefix and cd'ing up to\nthe project root?\n\nSome of the above take configuration options, so even they are\nnot interested in finding out prefix they do need to know where\n$GIT_DIR is (e.g. show-branch, update-ref, mailinfo).\n\n>  \t\t{ \"mailinfo\", cmd_mailinfo },\n\t\t{ \"apply\", cmd_apply },\n\nThese are tricky.  On the one hand, there is no strong reason to\nforbid use of mailinfo or apply outside git context, but they do\nwant to use some configuration items when available (commitencoding\nfor mailinfo, whitespace for apply).\n\nSo here is on top of your two patches to reflect the above\ncomments.  Again it seems to pass our tests, so I'll put it in\n\"next\" tonight.\n\n--\n builtin-cat-file.c    |    1 -\n builtin-commit-tree.c |    2 --\n builtin-diff-files.c  |    2 +-\n builtin-diff-index.c  |    2 +-\n builtin-diff-tree.c   |    2 +-\n builtin-ls-files.c    |    1 -\n builtin-ls-tree.c     |    1 -\n builtin-prune.c       |    2 +-\n builtin-read-tree.c   |    1 -\n builtin-rev-list.c    |    2 +-\n builtin-show-branch.c |    1 -\n builtin-tar-tree.c    |    1 -\n builtin-update-ref.c  |    1 -\n builtin-write-tree.c  |    2 --\n git.c                 |   28 ++++++++++++++--------------\n 15 files changed, 19 insertions(+), 30 deletions(-)\n\ndiff --git a/builtin-cat-file.c b/builtin-cat-file.c\nindex d796431..814fb07 100644\n--- a/builtin-cat-file.c\n+++ b/builtin-cat-file.c\n@@ -102,7 +102,6 @@ int cmd_cat_file(int argc, const char **\n \tunsigned long size;\n \tint opt;\n \n-\tsetup_git_directory();\n \tgit_config(git_default_config);\n \tif (argc != 3)\n \t\tusage(\"git-cat-file [-t|-s|-e|-p|<type>] <sha1>\");\ndiff --git a/builtin-commit-tree.c b/builtin-commit-tree.c\nindex e6fb16d..9c98796 100644\n--- a/builtin-commit-tree.c\n+++ b/builtin-commit-tree.c\n@@ -88,8 +88,6 @@ int cmd_commit_tree(int argc, const char\n \tunsigned int size;\n \n \tsetup_ident();\n-\tsetup_git_directory();\n-\n \tgit_config(git_default_config);\n \n \tif (argc < 2)\ndiff --git a/builtin-diff-files.c b/builtin-diff-files.c\nindex da51284..ac13db7 100644\n--- a/builtin-diff-files.c\n+++ b/builtin-diff-files.c\n@@ -18,7 +18,7 @@ int cmd_diff_files(int argc, const char \n \tstruct rev_info rev;\n \tint silent = 0;\n \n-\tinit_revisions(&rev, setup_git_directory());\n+\tinit_revisions(&rev, prefix);\n \tgit_config(git_default_config); /* no \"diff\" UI options */\n \trev.abbrev = 0;\n \ndiff --git a/builtin-diff-index.c b/builtin-diff-index.c\nindex bedb90c..95a3db1 100644\n--- a/builtin-diff-index.c\n+++ b/builtin-diff-index.c\n@@ -15,7 +15,7 @@ int cmd_diff_index(int argc, const char \n \tint cached = 0;\n \tint i;\n \n-\tinit_revisions(&rev, setup_git_directory());\n+\tinit_revisions(&rev, prefix);\n \tgit_config(git_default_config); /* no \"diff\" UI options */\n \trev.abbrev = 0;\n \ndiff --git a/builtin-diff-tree.c b/builtin-diff-tree.c\nindex 816946b..24cb2d7 100644\n--- a/builtin-diff-tree.c\n+++ b/builtin-diff-tree.c\n@@ -67,7 +67,7 @@ int cmd_diff_tree(int argc, const char *\n \tstatic struct rev_info *opt = &log_tree_opt;\n \tint read_stdin = 0;\n \n-\tinit_revisions(opt, setup_git_directory());\n+\tinit_revisions(opt, prefix);\n \tgit_config(git_default_config); /* no \"diff\" UI options */\n \tnr_sha1 = 0;\n \topt->abbrev = 0;\ndiff --git a/builtin-ls-files.c b/builtin-ls-files.c\nindex e906c81..79ffe8f 100644\n--- a/builtin-ls-files.c\n+++ b/builtin-ls-files.c\n@@ -329,7 +329,6 @@ int cmd_ls_files(int argc, const char **\n \tstruct dir_struct dir;\n \n \tmemset(&dir, 0, sizeof(dir));\n-\tprefix = setup_git_directory();\n \tif (prefix)\n \t\tprefix_offset = strlen(prefix);\n \tgit_config(git_default_config);\ndiff --git a/builtin-ls-tree.c b/builtin-ls-tree.c\nindex d31efe9..261147f 100644\n--- a/builtin-ls-tree.c\n+++ b/builtin-ls-tree.c\n@@ -90,7 +90,6 @@ int cmd_ls_tree(int argc, const char **a\n \tunsigned char sha1[20];\n \tstruct tree *tree;\n \n-\tprefix = setup_git_directory();\n \tgit_config(git_default_config);\n \tls_tree_prefix = prefix;\n \tif (prefix && *prefix)\ndiff --git a/builtin-prune.c b/builtin-prune.c\nindex 15bb650..6a86eb5 100644\n--- a/builtin-prune.c\n+++ b/builtin-prune.c\n@@ -234,7 +234,7 @@ int cmd_prune(int argc, const char **arg\n \t * Set up revision parsing, and mark us as being interested\n \t * in all object types, not just commits.\n \t */\n-\tinit_revisions(&revs, setup_git_directory());\n+\tinit_revisions(&revs, prefix);\n \trevs.tag_objects = 1;\n \trevs.blob_objects = 1;\n \trevs.tree_objects = 1;\ndiff --git a/builtin-read-tree.c b/builtin-read-tree.c\nindex 25ca69c..49c10bf 100644\n--- a/builtin-read-tree.c\n+++ b/builtin-read-tree.c\n@@ -882,7 +882,6 @@ int cmd_read_tree(int argc, const char *\n \tstate.quiet = 1;\n \tstate.refresh_cache = 1;\n \n-\tsetup_git_directory();\n \tgit_config(git_default_config);\n \n \tnewfd = hold_lock_file_for_update(&lock_file, get_index_file());\ndiff --git a/builtin-rev-list.c b/builtin-rev-list.c\nindex 65b4d0c..0dee173 100644\n--- a/builtin-rev-list.c\n+++ b/builtin-rev-list.c\n@@ -311,7 +311,7 @@ int cmd_rev_list(int argc, const char **\n \tstruct commit_list *list;\n \tint i;\n \n-\tinit_revisions(&revs, setup_git_directory());\n+\tinit_revisions(&revs, prefix);\n \trevs.abbrev = 0;\n \trevs.commit_format = CMIT_FMT_UNSPECIFIED;\n \targc = setup_revisions(argc, argv, &revs, NULL);\ndiff --git a/builtin-show-branch.c b/builtin-show-branch.c\nindex 9c7f9f6..2a1b848 100644\n--- a/builtin-show-branch.c\n+++ b/builtin-show-branch.c\n@@ -573,7 +573,6 @@ int cmd_show_branch(int ac, const char *\n \tint topics = 0;\n \tint dense = 1;\n \n-\tsetup_git_directory();\n \tgit_config(git_show_branch_config);\n \n \t/* If nothing is specified, try the default first */\ndiff --git a/builtin-tar-tree.c b/builtin-tar-tree.c\nindex 637d22e..7c48db9 100644\n--- a/builtin-tar-tree.c\n+++ b/builtin-tar-tree.c\n@@ -319,7 +319,6 @@ static int generate_tar(int argc, const \n \tcurrent_path.alloc = PATH_MAX;\n \tcurrent_path.len = current_path.eof = 0;\n \n-\tsetup_git_directory();\n \tgit_config(git_tar_config);\n \n \tswitch (argc) {\ndiff --git a/builtin-update-ref.c b/builtin-update-ref.c\nindex acdf39a..5bd7182 100644\n--- a/builtin-update-ref.c\n+++ b/builtin-update-ref.c\n@@ -13,7 +13,6 @@ int cmd_update_ref(int argc, const char \n \tint i;\n \n \tsetup_ident();\n-\tsetup_git_directory();\n \tgit_config(git_default_config);\n \n \tfor (i = 1; i < argc; i++) {\ndiff --git a/builtin-write-tree.c b/builtin-write-tree.c\nindex 0f2dd7c..0289f59 100644\n--- a/builtin-write-tree.c\n+++ b/builtin-write-tree.c\n@@ -66,8 +66,6 @@ int cmd_write_tree(int argc, const char \n \tconst char *prefix = NULL;\n \tunsigned char sha1[20];\n \n-\tsetup_git_directory();\n-\n \twhile (1 < argc) {\n \t\tconst char *arg = argv[1];\n \t\tif (!strcmp(arg, \"--missing-ok\"))\ndiff --git a/git.c b/git.c\nindex 34328c0..79db43e 100644\n--- a/git.c\n+++ b/git.c\n@@ -236,32 +236,32 @@ static void handle_internal_command(int \n \t\t{ \"grep\", cmd_grep, NEEDS_PREFIX },\n \t\t{ \"rm\", cmd_rm, NEEDS_PREFIX },\n \t\t{ \"add\", cmd_add, NEEDS_PREFIX },\n-\t\t{ \"rev-list\", cmd_rev_list },\n+\t\t{ \"rev-list\", cmd_rev_list, NEEDS_PREFIX },\n \t\t{ \"init-db\", cmd_init_db },\n \t\t{ \"get-tar-commit-id\", cmd_get_tar_commit_id },\n \t\t{ \"upload-tar\", cmd_upload_tar },\n \t\t{ \"check-ref-format\", cmd_check_ref_format },\n-\t\t{ \"ls-files\", cmd_ls_files },\n-\t\t{ \"ls-tree\", cmd_ls_tree },\n-\t\t{ \"tar-tree\", cmd_tar_tree },\n-\t\t{ \"read-tree\", cmd_read_tree },\n-\t\t{ \"commit-tree\", cmd_commit_tree },\n+\t\t{ \"ls-files\", cmd_ls_files, NEEDS_PREFIX },\n+\t\t{ \"ls-tree\", cmd_ls_tree, NEEDS_PREFIX },\n+\t\t{ \"tar-tree\", cmd_tar_tree, NEEDS_PREFIX },\n+\t\t{ \"read-tree\", cmd_read_tree, NEEDS_PREFIX },\n+\t\t{ \"commit-tree\", cmd_commit_tree, NEEDS_PREFIX },\n \t\t{ \"apply\", cmd_apply },\n-\t\t{ \"show-branch\", cmd_show_branch },\n-\t\t{ \"diff-files\", cmd_diff_files },\n-\t\t{ \"diff-index\", cmd_diff_index },\n+\t\t{ \"show-branch\", cmd_show_branch, NEEDS_PREFIX },\n+\t\t{ \"diff-files\", cmd_diff_files, NEEDS_PREFIX },\n+\t\t{ \"diff-index\", cmd_diff_index, NEEDS_PREFIX },\n \t\t{ \"diff-stages\", cmd_diff_stages, NEEDS_PREFIX },\n-\t\t{ \"diff-tree\", cmd_diff_tree },\n-\t\t{ \"cat-file\", cmd_cat_file },\n+\t\t{ \"diff-tree\", cmd_diff_tree, NEEDS_PREFIX },\n+\t\t{ \"cat-file\", cmd_cat_file, NEEDS_PREFIX },\n \t\t{ \"rev-parse\", cmd_rev_parse, NEEDS_PREFIX },\n-\t\t{ \"write-tree\", cmd_write_tree },\n+\t\t{ \"write-tree\", cmd_write_tree, NEEDS_PREFIX },\n \t\t{ \"mailsplit\", cmd_mailsplit },\n \t\t{ \"mailinfo\", cmd_mailinfo },\n \t\t{ \"stripspace\", cmd_stripspace },\n \t\t{ \"update-index\", cmd_update_index, NEEDS_PREFIX },\n-\t\t{ \"update-ref\", cmd_update_ref },\n+\t\t{ \"update-ref\", cmd_update_ref, NEEDS_PREFIX },\n \t\t{ \"fmt-merge-msg\", cmd_fmt_merge_msg, NEEDS_PREFIX },\n-\t\t{ \"prune\", cmd_prune },\n+\t\t{ \"prune\", cmd_prune, NEEDS_PREFIX },\n \t};\n \tint i;\n \n"},{"id":"24344","messageId":"Pine.LNX.4.64.0607290943550.4168@g5.osdl.org","threadId":"5034","inReplyTo":"7vzmesg4g3.fsf@assigned-by-dhcp.cox.net","subject":"Re: Call setup_git_directory() early","fromName":"Linus Torvalds","fromEmail":"torvalds@osdl.org","sentAt":"2006-07-29T16:52:20Z","receivedAt":"2006-07-29T16:52:20Z","isPatch":false,"sender":{"key":"torvalds@linux-foundation.org","avatar":"https://avatars.githubusercontent.com/u/1024025?v=4"},"body":"\n\nOn Sat, 29 Jul 2006, Junio C Hamano wrote:\n> \n> > +#define NEEDS_PREFIX 1\n> >...\n> >  \t\t{ \"init-db\", cmd_init_db },\n> \n> This is an oddball that wants to always use $GIT_DIR environment\n> or \"./.git\" if $GIT_DIR is not exported, and should never go\n> looking for GIT_DIR, so we should not give NEEDS_PREFIX, ever.\n\nWell, the way I did things, each command _can_ still decide to call \n\"setup_git_directory()\" on their own, and we don't actually say up front \nwhether they will or not.\n\nSo some commands will just choose to let the git.c wrapper do it for them, \nand others can do it their own way, which leaves the maximum of \nflexibility, and doesn't mean that odd-balls like \"init-db\" really have to \neven be an issue.\n\n> >  \t\t{ \"stripspace\", cmd_stripspace },\n> >  \t\t{ \"mailsplit\", cmd_mailsplit },\n> >  \t\t{ \"get-tar-commit-id\", cmd_get_tar_commit_id },\n> \n> These are the other extreme -- they really do not care about\n> operating in a git context.\n\nRight.\n\n>   \t\t{ \"push\", cmd_push },\n>   \t\t{ \"count-objects\", cmd_count_objects },\n> \t\t{ \"check-ref-format\", cmd_check_ref_format },\n> \n> One rule seems to be that the commands that work at the while\n> repository level do not have NEEDS_PREFIX -- they will never\n> work from a subdirectory.\n\nWell, maybe we will make them do so, and maybe we won't. \n\nThe way I chose the NEED_PREFIX ones was actually really simple and \ntotally automated: I changed every builtin function to first _not_ have \nNEEDS_PREFIX, but changed the prototype to take \"const char *prefix\" \ninstead of the \"char **envp\" that nobody actually used.\n\nI then compiled them, and for each function that _already_ had a \"prefix\" \nin their existing implementation (which the compiler warned about), I \njust removed the old \"prefix = setup_git_directory()\", and added the \nNEEDS_PREFIX flag for that command.\n\n> There is no technical reason not to let count-objects find\n> $GIT_DIR on its own, but the current implementation does not do\n> that and you are keeping the behaviour bug-to-bug compatible.\n\nExactly. My conversions (both the first smaller one, and the second thing) \nwere really totally mindless translations, nothing fancy. I fixed a few \nbugs as I hit them (ie the first one moved the \"setup_git_directory()\" \ncall earlier over some \"git_config()\" calls), but other than those kinds \nof local changes, I tried to keep not just the patch, but very much the \nprocess of me creating it, very straightforward.\n\n> >  \t\t{ \"rev-list\", cmd_rev_list },\n> \n> I think we should mark this with NEEDS_PREFIX, and lose the call\n> to setup_git_directory() it has here:\n\nI think you're right, and the above explanation of how the patch was \nmindlessly created explains why my patch didn't do it that way ;)\n\nWhen I do re-organizations, I like doing them in two stages: the \n\"mindless\" stage that does the bulk of the syntactic stuff and the \nmovement of code, but that pretty much by definition should not introduce \nany new bugs, and then the second stage is the \"ok, now we have the new \norganization, we can clean up and fix problems\".\n\n\t\t\tLinus\n"}]}