Teach git to change to a given directory using -C option
PATCH v3 1/1 Teach git to change to a given directory using -C option
Quoted 11 lines · Eric Sunshine
No wish to bike-shed, however, I find "effective directory" somewhat difficult to digest due to its jargony feel. It also seems ambiguous (to me) since "previous effective directory" may mean "directory when git was run" or "directory set by most recent -C". My earlier suggestion
When multiple -C options are given, each subsequent non-absolute -C <path> is interpreted relative to the preceding -C <path>.
avoided jargon and left no room for ambiguity.
Quoted 8 lines
However, perhaps the examples are clear enough to make excessive prose explanation unnecessary, thus:
Run as if git was started in <path> instead of the current working directory. Multiple -C options are allowed and acted upon in the order given, thus "-C /usr -C src" is equivalent to "-C
/usr/src", and "-C src -C /usr" is equivalent to "C /usr". This option affects ...
I did feel that the explanation is becoming wordy. I'll take the former as it is terser. I've split the part that explain the effects on other options that take path argument into a separate paragraph.
Quoted 5 lines
It's curious that this test uses a variable ($expected) to avoid repeating literal "initial in dir1/dir2", however, the previous test repeats its literal "initial in dir1". (IMHO, the repeated literal actually makes the test a bit easier to read, and it's not likely to be a maintenance burden.)
Fixed.
Quoted 2 lines
It is suggested in t/README that, for Windows (MSYS bash) compatibility, you should use $(pwd) rather than $PWD.
Fixed.
Thanks for another round of review!
nazri
-- >8 --
Subject: [PATCH] Teach git to change to a given directory using -C option
This is similar in spirit to to "make -C dir ..." and "tar -C dir ...".
Currently it takes more effort (keypresses) to invoke git command in a different directory than the current one without leaving the current directory:
1. (cd ~/foo && git status)
git --git-dir=~/foo/.git --work-dir=~/foo status GIT_DIR=~/foo/.git GIT_WORK_TREE=~/foo git status
2. (cd ../..; git grep foo)
3. for d in d1 d2 d3; do (cd $d && git svn rebase); done
While doable the methods shown above are arguably more suitable for scripting than quick command line invocations.
With this new option, the above can be done with fewer keystrokes:
1. git -C ~/foo status
2. git -C ../.. grep foo
3. for d in d1 d2 d3; do git -C $d svn rebase; done
A new test script is added to verify the behavior of this option with other path-related options like --git-dir and --work-tree.
--- Documentation/git.txt | 16 +++++++++- git.c | 15 ++++++++-- t/t0056-git-C.sh | 82 +++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 110 insertions(+), 3 deletions(-) create mode 100755 t/t0056-git-C.sh
Documentation/git.txt +15 -1
@@ -9,7 +9,7 @@ git - the stupid content tracker SYNOPSIS -------- [verse] -'git' [--version] [--help] [-c <name>=<value>] +'git' [--version] [--help] [-C <path>] [-c <name>=<value>] [--exec-path[=<path>]] [--html-path] [--man-path] [--info-path] [-p|--paginate|--no-pager] [--no-replace-objects] [--bare] [--git-dir=<path>] [--work-tree=<path>] [--namespace=<name>]
@@ -395,6 +395,20 @@ displayed. See linkgit:git-help[1] for more information, because `git --help ...` is converted internally into `git help ...`. +-C <path>:: + Run as if git was started in <path> instead of the current working + directory. When multiple -C options are given, each subsequent + non-absolute "-C <path>" is interpreted relative to the preceding "-C + <path>". + + This option affects options that expect path name like --git-dir and + --work-tree in that their interpretations of the path names would be + made relative to the working directory caused by the -C option. For + example the following invocations are equivalent: + + git --git-dir=a.git --work-tree=b -C c status + git --git-dir=c/a.git --work-tree=c/b status + -c <name>=<value>:: Pass a configuration parameter to the command. The value given will override values from configuration files.
git.c +13 -2
@@ -7,7 +7,7 @@#include "commit.h" const char git_usage_string[] = -"git [--version] [--help] [-c name=value]\n" +"git [--version] [--help] [-C <path>] [-c name=value]\n" " [--exec-path[=<path>]] [--html-path] [--man-path] [--info-path]\n" " [-p|--paginate|--no-pager] [--no-replace-objects] [--bare]\n" " [--git-dir=<path>] [--work-tree=<path>] [--namespace=<name>]\n"
@@ -54,7 +54,18 @@ static int handle_options(const char ***argv, int *argc, int *envchanged)/* * Check remaining flags. */ -if (!prefixcmp (cmd,"--exec-path" )) { +if (!strcmp (cmd,"-C" )) { +if (*argc <2 ) { +fprintf (stderr,"No directory given for -C.\n" ); +usage (git_usage_string); + } +if (chdir ((*argv)[1 ])) +die_errno ("Cannot change to '%s'" , (*argv)[1 ]); +if (envchanged) + *envchanged =1 ; + (*argv)++; + (*argc)--; + }else if (!prefixcmp (cmd,"--exec-path" )) { cmd +=11 ;if (*cmd =='=' )git_set_argv_exec_path (cmd +1 );
t/t0056-git-C.sh new file +82 -0
82 lines not on this page · raw message
Signature · 1 line
1.8.4.22.g38647a4
Quoted 24 lines · Nazri Ramliy
-- >8 --
Subject: [PATCH] Teach git to change to a given directory using -C optionThis is similar in spirit to to "make -C dir ..." and "tar -C dir ...".
Currently it takes more effort (keypresses) to invoke git command in a different directory than the current one without leaving the current directory:
1. (cd ~/foo && git status)
git --git-dir=~/foo/.git --work-dir=~/foo status GIT_DIR=~/foo/.git GIT_WORK_TREE=~/foo git status
2. (cd ../..; git grep foo)
3. for d in d1 d2 d3; do (cd $d && git svn rebase); doneWhile doable the methods shown above are arguably more suitable for scripting than quick command line invocations.
With this new option, the above can be done with fewer keystrokes:
1. git -C ~/foo status
2. git -C ../.. grep foo
3. for d in d1 d2 d3; do git -C $d svn rebase; done
Quoted 5 lines
A new test script is added to verify the behavior of this option with other path-related options like --git-dir and --work-tree.
Signed-off-by Nazri Ramliy <[email protected]>---
Thanks; will tentatively queue on 'pu' with some rephrasing of the log message, but I have a few comments.
Quoted 11 lines
Documentation/git.txt | 16 +++++++++- git.c | 15 ++++++++-- t/t0056-git-C.sh | 82 +++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 110 insertions(+), 3 deletions(-) create mode 100755 t/t0056-git-C.shDocumentation/git.txt +0
-0
Documentation/git.txt git - the stupid content tracker · line 12
Quoted 5 lines
Documentation/git.txt +1
-1@@ -9,7 +9,7 @@ git - the stupid content tracker SYNOPSIS -------- [verse] -'git' [--version] [--help] [-c <name>=<value>] +'git' [--version] [--help] [-C <path>] [-c <name>=<value>]
I do not care too deeply either way, but I am curious if there was a reason why you changed the earlier <directory> to <path>? Somehow, when we _know_ a path has to be a directory, I find it easier on the readers to spell that out, instead of saying "this is a path", implying that it could be a directory, a regular file, or even non-existent.
Quoted 11 lines
Documentation/git.txt +4
-0[--exec-path[=<path>]] [--html-path] [--man-path] [--info-path] [-p|--paginate|--no-pager] [--no-replace-objects] [--bare] [--git-dir=<path>] [--work-tree=<path>] [--namespace=<name>]@@ -395,6 +395,20 @@ displayed. See linkgit:git-help[1] for more information, because `git --help ...` is converted internally into `git help ...`. +-C <path>:: + Run as if git was started in <path> instead of the current working + directory. When multiple -C options are given, each subsequent + non-absolute "-C <path>" is interpreted relative to the preceding "-C
Documentation/git.txt displayed. See linkgit:git-help[1] for more information, · line 411
Quoted 10 lines
Documentation/git.txt +10
-0+ <path>". + + This option affects options that expect path name like --git-dir and + --work-tree in that their interpretations of the path names would be + made relative to the working directory caused by the -C option. For + example the following invocations are equivalent: + + git --git-dir=a.git --work-tree=b -C c status + git --git-dir=c/a.git --work-tree=c/b status +
Does the above format correctly without the usual "second and subsequent paragraphs are not indented, but has '+' in place of a blank line"?
Quoted 20 lines
git.c +3
-2@@ -7,7 +7,7 @@#include "commit.h" const char git_usage_string[] = -"git [--version] [--help] [-c name=value]\n" +"git [--version] [--help] [-C <path>] [-c name=value]\n" " [--exec-path[=<path>]] [--html-path] [--man-path] [--info-path]\n" " [-p|--paginate|--no-pager] [--no-replace-objects] [--bare]\n" " [--git-dir=<path>] [--work-tree=<path>] [--namespace=<name>]\n" @@ -54,7 +54,18 @@ static int handle_options(const char ***argv, int *argc, int *envchanged)/* * Check remaining flags. */ -if (!prefixcmp (cmd,"--exec-path" )) { +if (!strcmp (cmd,"-C" )) { +if (*argc <2 ) {
git.c static int handle_options(const char ***argv, int *argc, int *envchanged) · line 68
Quoted 10 lines
git.c +10
-0+fprintf (stderr,"No directory given for -C.\n" ); +usage (git_usage_string); + } +if (chdir ((*argv)[1 ])) +die_errno ("Cannot change to '%s'" , (*argv)[1 ]); +if (envchanged) + *envchanged =1 ; + (*argv)++; + (*argc)--; + }else if (!prefixcmp (cmd,"--exec-path" )) {
We usually do not prepend to an existing if/else if/ chain unless there is a very good reason (e.g. the new "if" condition is very often triggered and we are better off checking it early) exactly because doing so would make a patch that is ugly like the above. You are not touching the codepath that deal with --exec-path, but the resulting patch makes it appear as if you are doing something to it.
Quoted 6 lines · Junio C Hamano
I do not care too deeply either way, but I am curious if there was a reason why you changed the earlier <directory> to <path>? Somehow, when we _know_ a path has to be a directory, I find it easier on the readers to spell that out, instead of saying "this is a path", implying that it could be a directory, a regular file, or even non-existent.
Eric made me do it :). Personally I prefer the non-ambiguous "directory" over "path". In fact, "directory" is used in the error message spat out by git:
$ git --work-tree
No directory given for --work-tree.
... $ git --git-dir
No directory given for --git-dir.
...
$I think changing "<path>" to "<directory>" wherever appropriate in git.txt would be an improvement. Tangent: <dir> is shorter but that might not be easy on the translators.
Quoted 10 lines
Quoted 10 lines
+-C <path>::
Documentation/git.txt +9
-0+ Run as if git was started in <path> instead of the current working + directory. When multiple -C options are given, each subsequent + non-absolute "-C <path>" is interpreted relative to the preceding "-C + <path>". + + This option affects options that expect path name like --git-dir and + --work-tree in that their interpretations of the path names would be + made relative to the working directory caused by the -C option. For + example the following invocations are equivalent:
Quoted 8 lines
Documentation/git.txt displayed. See linkgit:git-help[1] for more information, · line 411
Quoted 4 lines
Documentation/git.txt +4
-0+ + git --git-dir=a.git --work-tree=b -C c status + git --git-dir=c/a.git --work-tree=c/b status +Does the above format correctly without the usual "second and subsequent paragraphs are not indented, but has '+' in place of a blank line"?
No it doesn't. I'll fix it in the next reroll.
Quoted 14 lines
git.c static int handle_options(const char ***argv, int *argc, int *envchanged) · line 68
Quoted 13 lines
git.c +12
-1-if (!prefixcmp (cmd,"--exec-path" )) { +if (!strcmp (cmd,"-C" )) { +if (*argc <2 ) { +fprintf (stderr,"No directory given for -C.\n" ); +usage (git_usage_string); + } +if (chdir ((*argv)[1 ])) +die_errno ("Cannot change to '%s'" , (*argv)[1 ]); +if (envchanged) + *envchanged =1 ; + (*argv)++; + (*argc)--; + }else if (!prefixcmp (cmd,"--exec-path" )) {
Quoted 7 lines
We usually do not prepend to an existing if/else if/ chain unless there is a very good reason (e.g. the new "if" condition is very often triggered and we are better off checking it early) exactly because doing so would make a patch that is ugly like the above. You are not touching the codepath that deal with --exec-path, but the resulting patch makes it appear as if you are doing something to it.
I agree with you here. I'll send the reroll later.
nazri
Quoted 29 lines · Nazri Ramliy
Quoted 3 lines · Junio C Hamano
Does the above format correctly without the usual "second and subsequent paragraphs are not indented, but has '+' in place of a blank line"?
No it doesn't. I'll fix it in the next reroll.
Quoted 14 lines
Review
Quoted 13 lines
(quoted diff) +12
-1- if (!prefixcmp(cmd, "--exec-path")) { + if (!strcmp(cmd, "-C")) { + if (*argc < 2) { + fprintf(stderr, "No directory given for -C.\n" ); + usage(git_usage_string); + } + if (chdir((*argv)[1])) + die_errno("Cannot change to '%s'", (*argv)[1]); + if (envchanged) + *envchanged = 1; + (*argv)++; + (*argc)--; + } else if (!prefixcmp(cmd, "--exec-path")) {Quoted 7 lines
We usually do not prepend to an existing if/else if/ chain unless there is a very good reason (e.g. the new "if" condition is very often triggered and we are better off checking it early) exactly because doing so would make a patch that is ugly like the above. You are not touching the codepath that deal with --exec-path, but the resulting patch makes it appear as if you are doing something to it.
Quoted 1 line
I agree with you here. I'll send the reroll later.
Here it is.
Eric: Care to give your "Reviewed-by:" stamp?
nazri
-- >8 --
Subject: git: run in a directory given with -C option
This is similar in spirit to to "make -C dir ..." and "tar -C dir ...".
It takes more keypresses to invoke git command in a different directory than the current one without leaving the current directory:
1. (cd ~/foo && git status)
git --git-dir=~/foo/.git --work-dir=~/foo status GIT_DIR=~/foo/.git GIT_WORK_TREE=~/foo git status
2. (cd ../..; git grep foo)
3. for d in d1 d2 d3; do (cd $d && git svn rebase); done
While doable the methods shown above are arguably more suitable for scripting than quick command line invocations.
With this new option, the above can be done with fewer keystrokes:
1. git -C ~/foo status
2. git -C ../.. grep foo
3. for d in d1 d2 d3; do git -C $d svn rebase; done
A new test script is added to verify the behavior of this option with other path-related options like --git-dir and --work-tree.
--- Documentation/git.txt | 16 +++++++++- git.c | 13 +++++++- t/t0056-git-C.sh | 82 +++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 109 insertions(+), 2 deletions(-) create mode 100755 t/t0056-git-C.sh
Documentation/git.txt +15 -1
@@ -9,7 +9,7 @@ git - the stupid content tracker SYNOPSIS -------- [verse] -'git' [--version] [--help] [-c <name>=<value>] +'git' [--version] [--help] [-C <path>] [-c <name>=<value>] [--exec-path[=<path>]] [--html-path] [--man-path] [--info-path] [-p|--paginate|--no-pager] [--no-replace-objects] [--bare] [--git-dir=<path>] [--work-tree=<path>] [--namespace=<name>]
@@ -395,6 +395,20 @@ displayed. See linkgit:git-help[1] for more information, because `git --help ...` is converted internally into `git help ...`. +-C <path>:: + Run as if git was started in <path> instead of the current working + directory. When multiple -C options are given, each subsequent + non-absolute "-C <path>" is interpreted relative to the preceding "-C + <path>". ++ +This option affects options that expect path name like --git-dir and +--work-tree in that their interpretations of the path names would be +made relative to the working directory caused by the -C option. For +example the following invocations are equivalent: + + git --git-dir=a.git --work-tree=b -C c status + git --git-dir=c/a.git --work-tree=c/b status + -c <name>=<value>:: Pass a configuration parameter to the command. The value given will override values from configuration files.
git.c +12 -1
@@ -7,7 +7,7 @@#include "commit.h" const char git_usage_string[] = -"git [--version] [--help] [-c name=value]\n" +"git [--version] [--help] [-C <path>] [-c name=value]\n" " [--exec-path[=<path>]] [--html-path] [--man-path] [--info-path]\n" " [-p|--paginate|--no-pager] [--no-replace-objects] [--bare]\n" " [--git-dir=<path>] [--work-tree=<path>] [--namespace=<name>]\n"
@@ -153,6 +153,17 @@ static int handle_options(const char ***argv, int *argc, int *envchanged)set_alternate_shallow_file ((*argv)[0 ]);if (envchanged) *envchanged =1 ; + }else if (!strcmp (cmd,"-C" )) { +if (*argc <2 ) { +fprintf (stderr,"No directory given for -C.\n" ); +usage (git_usage_string); + } +if (chdir ((*argv)[1 ])) +die_errno ("Cannot change to '%s'" , (*argv)[1 ]); +if (envchanged) + *envchanged =1 ; + (*argv)++; + (*argc)--; }else {fprintf (stderr,"Unknown option: %s\n" , cmd);usage (git_usage_string);
t/t0056-git-C.sh new file +82 -0
82 lines not on this page · raw message
Signature · 1 line
1.8.4.22.g38647a4
Quoted 9 lines · Nazri Ramliy
Subject: git: run in a directory given with -C option
This is similar in spirit to to "make -C dir ..." and "tar -C dir ...".
---Documentation/git.txt +0
-0
Documentation/git.txt displayed. See linkgit:git-help[1] for more information, · line 402
Quoted 8 lines
Documentation/git.txt +5
-0@@ -395,6 +395,20 @@ displayed. See linkgit:git-help[1] for more information, because `git --help ...` is converted internally into `git help ...`. +-C <path>:: + Run as if git was started in <path> instead of the current working + directory. When multiple -C options are given, each subsequent + non-absolute "-C <path>" is interpreted relative to the preceding "-C + <path>".
For consistency with existing formatting in git.txt, you may want to squash in the following fixes (sans gmail whitespace damage):
--- >8 ---
Documentation/git.txt +7 -7
@@ -396,14 +396,14 @@ because `git --help ...` is converted internally into `git help ...`. -C <path>:: - Run as if git was started in <path> instead of the current working - directory. When multiple -C options are given, each subsequent - non-absolute "-C <path>" is interpreted relative to the preceding "-C - <path>". + Run as if git was started in '<path>' instead of the current working + directory. When multiple '-C' options are given, each subsequent + non-absolute `-C <path>` is interpreted relative to the preceding `-C + <path>`. + -This option affects options that expect path name like --git-dir and ---work-tree in that their interpretations of the path names would be -made relative to the working directory caused by the -C option. For +This option affects options that expect path name like '--git-dir' and +'--work-tree' in that their interpretations of the path names would be +made relative to the working directory caused by the '-C' option. For example the following invocations are equivalent: git --git-dir=a.git --work-tree=b -C c status
--- >8 ---
Documentation/git.txt displayed. See linkgit:git-help[1] for more information, · line 409
Quoted 7 lines
Documentation/git.txt +7
-0+This option affects options that expect path name like --git-dir and +--work-tree in that their interpretations of the path names would be +made relative to the working directory caused by the -C option. For +example the following invocations are equivalent: + + git --git-dir=a.git --work-tree=b -C c status + git --git-dir=c/a.git --work-tree=c/b status
Is the interaction of -C with --work-tree and --git-dir desirable or useful? (I'm genuinely curious.) Do you have use-cases in mind? Would mentioning them in the commit message help to justify the interaction?
Quoted 4 lines · Eric Sunshine
For consistency with existing formatting in git.txt, you may want to squash in the following fixes (sans gmail whitespace damage):
--- >8 ---
[ diff snipped ]
Quoted 1 line
--- >8 ---
Thanks. I'll submit a reroll later.
Quoted 11 lines
Review
Quoted 7 lines
(quoted diff) +7
-0+This option affects options that expect path name like --git-dir and +--work-tree in that their interpretations of the path names would be +made relative to the working directory caused by the -C option. For +example the following invocations are equivalent: + + git --git-dir=a.git --work-tree=b -C c status + git --git-dir=c/a.git --work-tree=c/b statusIs the interaction of -C with --work-tree and --git-dir desirable or useful? (I'm genuinely curious.) Do you have use-cases in mind? Would mentioning them in the commit message help to justify the interaction?
The example is meant to clarify the effect of the -C option, rather than a proposed usage with the --work-tree and --git-dir options. The example came out due to the following discussions from an earlier version of this patch [1]:
Quoted 9 lines · Jeff King
Quoted 8 lines · Nazri Ramliy
Documentation/git.txt +0
-0@@ -379,6 +379,9 @@ displayed. See linkgit:git-help[1] for more information, because `git --help ...` is converted internally into `git help ...`.
Quoted 8 lines
Documentation/git.txt displayed. See linkgit:git-help[1] for more information, · line 384
Quoted 3 lines
Documentation/git.txt +3
-0+-C <directory>:: + Change to given directory before doing anything else. +It might make sense to clarify this as "...anything else, including determining the location of the git repository directory". If you think hard about it, doing anything else would not really make much sense, but spelling it out makes it clear what the option can be used for.
and [2]:
Quoted 5 lines · Jonathan Nieder
All that said, I don't mind -C terribly as long as it can maintain itself, which means including thorough documentation that covers the purpose and how pathname parameters and envvars interact with the new option and including tests under t/ to ensure it continues to work correctly in the future.
nazri
[1] http://article.gmane.org/gmane.comp.version-control.git/221766
[2] http://article.gmane.org/gmane.comp.version-control.git/221878
Quoted 13 lines · Nazri Ramliy
Quoted 11 lines · Eric Sunshine
Review
Quoted 7 lines
(quoted diff) +7
-0+This option affects options that expect path name like --git-dir and +--work-tree in that their interpretations of the path names would be +made relative to the working directory caused by the -C option. For +example the following invocations are equivalent: + + git --git-dir=a.git --work-tree=b -C c status + git --git-dir=c/a.git --work-tree=c/b statusIs the interaction of -C with --work-tree and --git-dir desirable or useful? (I'm genuinely curious.) Do you have use-cases in mind? Would mentioning them in the commit message help to justify the interaction?
Quoted 4 lines
The example is meant to clarify the effect of the -C option, rather than a proposed usage with the --work-tree and --git-dir options. The example came out due to the following discussions from an earlier version of this patch [1]:
[1] http://article.gmane.org/gmane.comp.version-control.git/221766
Thanks for the reference. I did read that thread earlier. It doesn't really answer my question, but perhaps it's not terribly important since the interaction is documented. I was mainly asking if the choice of locking in one particular interpretation was deliberate even though other potentially valid (and perhaps more intuitive) interpretations exists. More below TL;DR if you care to read on.
TL;DR
I was interested in knowing whether the exact interaction between -C and --work-tree and --git-dir was intentional (and desirable) or an "accident of implementation". I can see it going either way.
As implemented by the patch, -C is acted upon immediately (via chdir()), whereas --work-tree and --git-dir have a delayed effect, so:
git -C foo --work-tree=bar -C baz --git-dir=moo
means:
work-tree = foo/baz/bar
git-dir = foo/baz/moo
However, it would be equally valid for a user to expect the options to be evaluated sequentially such that the above command line would mean:
work-tree = foo/bar
git-dir = foo/baz/moo
Is the former interpretation better than the latter possibly more intuitive interpretation? This is a genuine question. I'm not suggesting that one interpretation is better than the other, and it's possible that it won't matter in practice [1], but it might be good to know that alternate interpretations have been taken into consideration before locking in a particular behavior.
This is why I was asking if you had particular use-cases in mind where the former made more sense than the latter (or some other [2]) interpretation. Since there are multiple potential interpretations, it might make sense to explain in the commit message why the one was chosen over the other(s), and such use-cases could help solidify that explanation.
[1]: Mixing of -C, --work-tree, and --git-dir may be sufficiently unlikely that the reason the patch's behavior was chosen becomes immaterial. Since the behavior is documented, a person can choose to avoid -C if it doesn't work in a way suitable to his situation.
[2]: For example, a user might reasonably expect -C to be relative to --work-tree or GIT_WORK_TREE rather than the other way around. So, "git --work-tree=foo -C bar" or "git -C bar --work-tree=foo" would chdir("foo/bar") before performing the git operation, and --git-dir would be unaffected. Yet another possibility is that -C would impact neither --work-tree nor --git-dir.
Quoted 7 lines · Eric Sunshine
On Sun, Sep 8, 2013 at 9:49 PM, Nazri Ramliy <[email protected]> wrote:
Thanks for the reference. I did read that thread earlier. It doesn't really answer my question, but perhaps it's not terribly important since the interaction is documented. I was mainly asking if the choice of locking in one particular interpretation was deliberate even though other potentially valid (and perhaps more intuitive) interpretations exists. More below TL;DR if you care to read on.
Thanks for the clarification. Reroll of the patch to fix the documentation is at the end of this mail.
Quoted 5 lines
TL;DR
I was interested in knowing whether the exact interaction between -C and --work-tree and --git-dir was intentional (and desirable) or an "accident of implementation". I can see it going either way.
The implementation was the simplest one that I could think of for achieving what I wanted -C to do. I can agree that the side effects with any other options that handles path argument are "accident of implementation" and there might be room for improvements, at the expense of complexity.
Quoted 13 lines
However, it would be equally valid for a user to expect the options to be evaluated sequentially such that the above command line would mean:
work-tree = foo/bar
git-dir = foo/baz/mooIs the former interpretation better than the latter possibly more intuitive interpretation? This is a genuine question. I'm not suggesting that one interpretation is better than the other, and it's possible that it won't matter in practice [1], but it might be good to know that alternate interpretations have been taken into consideration before locking in a particular behavior.
Quoted 7 lines
This is why I was asking if you had particular use-cases in mind where the former made more sense than the latter (or some other [2]) interpretation. Since there are multiple potential interpretations, it might make sense to explain in the commit message why the one was chosen over the other(s), and such use-cases could help solidify that explanation.
When I first experimented the interaction of -C with --git-dir and --work-tree, I did feel its counter-intuitiveness side effect due to the implementation. Consider -C's interaction with format-patch:
$ git -C foo format-patch HEAD~3..
Based on the current implementation, the patch files generated by the above would in the directory "foo" instead of where git was started from.
Is it worth the complexity to ensure that subsequent git options, builtin options, or builtins be aware of where git was started from vs. the effective "new" directory that it chdir'd into due to the -C option? I'm not sure about that at the moment. I foresee that it might not be that simple to get that to work.
I took a look at GNU tar's -C implementation and it seems that for the equivalent case,:
$ tar Ccf foo/ foo.tar bar.txt baz.txt
GNU tar is aware of where it was called from and created the file foo.tar there (instead of in foo/).
Tangent: This now reminds me of a feature that I wished git-grep had - when run on a non-bare repository, I'd like git-grep to show me the "usable" path from the point of view of where I started it from, assuming $PWD is $HOME and my non-bare clone of git.git is in $HOME/src:
$ git -C src/git grep main git.c
src/git/git.c: * Check remaining flags.
src/git/git.c:int main(int argc, char **av)instead of the what we have in the current behavior:
$ git -C src/git grep main git.c
git.c: * Check remaining flags.
git.c:int main(int argc, char **av)Nazri
-- >8 --
Subject: git: run in a directory given with -C option
This is similar in spirit to to "make -C dir ..." and "tar -C dir ...".
It takes more keypresses to invoke git command in a different directory than the current one without leaving the current directory:
1. (cd ~/foo && git status)
git --git-dir=~/foo/.git --work-dir=~/foo status GIT_DIR=~/foo/.git GIT_WORK_TREE=~/foo git status
2. (cd ../..; git grep foo)
3. for d in d1 d2 d3; do (cd $d && git svn rebase); done
While doable the methods shown above are arguably more suitable for scripting than quick command line invocations.
With this new option, the above can be done with fewer keystrokes:
1. git -C ~/foo status
2. git -C ../.. grep foo
3. for d in d1 d2 d3; do git -C $d svn rebase; done
A new test script is added to verify the behavior of this option with other path-related options like --git-dir and --work-tree.
--- Documentation/git.txt | 16 +++++++++- git.c | 13 +++++++- t/t0056-git-C.sh | 82 +++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 109 insertions(+), 2 deletions(-) create mode 100755 t/t0056-git-C.sh
Documentation/git.txt +15 -1
@@ -9,7 +9,7 @@ git - the stupid content tracker SYNOPSIS -------- [verse] -'git' [--version] [--help] [-c <name>=<value>] +'git' [--version] [--help] [-C <path>] [-c <name>=<value>] [--exec-path[=<path>]] [--html-path] [--man-path] [--info-path] [-p|--paginate|--no-pager] [--no-replace-objects] [--bare] [--git-dir=<path>] [--work-tree=<path>] [--namespace=<name>]
@@ -395,6 +395,20 @@ displayed. See linkgit:git-help[1] for more information, because `git --help ...` is converted internally into `git help ...`. +-C <path>:: + Run as if git was started in '<path>' instead of the current working + directory. When multiple '-C' options are given, each subsequent + non-absolute `-C <path>` is interpreted relative to the preceding `-C + <path>`. ++ +This option affects options that expect path name like '--git-dir' and +'--work-tree' in that their interpretations of the path names would be +made relative to the working directory caused by the '-C' option. For +example the following invocations are equivalent: + + git --git-dir=a.git --work-tree=b -C c status + git --git-dir=c/a.git --work-tree=c/b status + -c <name>=<value>:: Pass a configuration parameter to the command. The value given will override values from configuration files.
git.c +12 -1
@@ -7,7 +7,7 @@#include "commit.h" const char git_usage_string[] = -"git [--version] [--help] [-c name=value]\n" +"git [--version] [--help] [-C <path>] [-c name=value]\n" " [--exec-path[=<path>]] [--html-path] [--man-path] [--info-path]\n" " [-p|--paginate|--no-pager] [--no-replace-objects] [--bare]\n" " [--git-dir=<path>] [--work-tree=<path>] [--namespace=<name>]\n"
@@ -153,6 +153,17 @@ static int handle_options(const char ***argv, int *argc, int *envchanged)set_alternate_shallow_file ((*argv)[0 ]);if (envchanged) *envchanged =1 ; + }else if (!strcmp (cmd,"-C" )) { +if (*argc <2 ) { +fprintf (stderr,"No directory given for -C.\n" ); +usage (git_usage_string); + } +if (chdir ((*argv)[1 ])) +die_errno ("Cannot change to '%s'" , (*argv)[1 ]); +if (envchanged) + *envchanged =1 ; + (*argv)++; + (*argc)--; }else {fprintf (stderr,"Unknown option: %s\n" , cmd);usage (git_usage_string);
t/t0056-git-C.sh new file +82 -0
82 lines not on this page · raw message
Signature · 1 line
1.8.4.100.gd06f3e9
Quoted 3 lines · Nazri Ramliy
Subject: git: run in a directory given with -C option
This is similar in spirit to to "make -C dir ..." and "tar -C dir ...".
The doubled-"to to" which I locally fixed when I queued the last one (together with other rewording to make it more agreeable and easier to read) somehow came back ;-) Will fix locally again.
Documentation/git.txt displayed. See linkgit:git-help[1] for more information, · line 400
Quoted 3 lines
+-C <path>::
Documentation/git.txt +2
-0+ Run as if git was started in '<path>' instead of the current working + directory. When multiple '-C' options are given, each subsequent
I think this should be -C to typeset it as "typed literally".
Documentation/git.txt displayed. See linkgit:git-help[1] for more information, · line 405
Quoted 5 lines
Documentation/git.txt +5
-0+ non-absolute `-C <path>` is interpreted relative to the preceding `-C + <path>`. ++ +This option affects options that expect path name like '--git-dir' and +'--work-tree' in that their interpretations of the path names would be
Likewise for --git-dir and --work-tree.
Quoted 1 line
+made relative to the working directory caused by the '-C' option. For
and here.
Quoted 6 lines
t/t0056-git-C.sh new file +0
-0
t/t0056-git-C.sh line 10
Quoted 10 lines
t/t0056-git-C.sh new file +10
-0@@ -0,0 +1,82 @@ +#!/bin/sh + +test_description='"-C <path>" option and its effects on other path-related options' + +. ./test-lib.sh + +test_expect_success '"git -C <path>" runs git from the directory <path>' ' + test_create_repo dir1 && + echo 1 >dir1/a.txt && + (cd dir1 && git add a.txt && git commit -m "initial in dir1") &&
Curious why this does not use -C here.
t/t0056-git-C.sh line 19
Quoted 9 lines
t/t0056-git-C.sh new file +9
-0+ echo "initial in dir1" >expected && + git -C dir1 log --format=%s >actual && + test_cmp expected actual +' + +test_expect_success 'Multiple -C options: "-C dir1 -C dir2" is equivalent to "-C dir1/dir2"' ' + test_create_repo dir1/dir2 && + echo 1 >dir1/dir2/a.txt && + git -C dir1/dir2 add a.txt &&
Because "a.txt" exists in both dir1 and dir1/dir2, this has less chance of catching a bug (if somebody breaks the feature to run it in dir1 not dir1/dir2, "add" will happily say "Oh, I found something to add", instead of saying "Huh? there is no such path".
If you used b.txt instead, you would catch such a breakage.
Remember, tests are not about demonstrating how cool the new feature is and/or how well it works in an expected setting. Imagine ways other people can break your spiffy new feature in later patches, and design tests that are more likely to catch them.
The same comment applies throughout the remainder of this script.
t/t0056-git-C.sh line 21
Quoted 2 lines
t/t0056-git-C.sh new file +2
-0+ echo "initial in dir1/dir2" >expected && + git -C dir1/dir2 commit -m "initial in dir1/dir2" &&
to reduce possibilities of breaking this test in the future due to typos (e.g. somebody may want to say "initial commit in dir1/dir2"), doing this may be a better idea:
msg="initial in dir1/dir2" &&
echo "$msg" >expected &&
git -C dir1/dir2 commit -m "$msg" &&The same comment applies to the previous one.
Quoted 16 lines · Junio C Hamano
Documentation/git.txt displayed. See linkgit:git-help[1] for more information, · line 400
Quoted 5 lines · Nazri Ramliy
Subject: git: run in a directory given with -C option
+-C <path>::
Documentation/git.txt +2
-0+ Run as if git was started in '<path>' instead of the current working + directory. When multiple '-C' options are given, each subsequentI think this should be
-Cto typeset it as "typed literally".Documentation/git.txt displayed. See linkgit:git-help[1] for more information, · line 405
Quoted 5 lines
Documentation/git.txt +5
-0+ non-absolute `-C <path>` is interpreted relative to the preceding `-C + <path>`. ++ +This option affects options that expect path name like '--git-dir' and +'--work-tree' in that their interpretations of the path names would be
Quoted 5 lines
Likewise for
--git-dirand--work-tree.Quoted 1 line
+made relative to the working directory caused by the '-C' option. For
and here.
I agree with all of the above, however, the unfortunate typesetting in these cases was chosen deliberately to be consistent with the immediately surrounding text. A separate typesetting normalization patch, either before or after this patch, would not be unwelcome. (I forgot to make such a suggestion in [1].)
[1]: http://thread.gmane.org/gmane.comp.version-control.git/233719/focus=234234
Quoted 23 lines · Eric Sunshine
Quoted 16 lines · Junio C Hamano
Documentation/git.txt displayed. See linkgit:git-help[1] for more information, · line 400
Quoted 5 lines · Nazri Ramliy
Subject: git: run in a directory given with -C option
+-C <path>::
Documentation/git.txt +2
-0+ Run as if git was started in '<path>' instead of the current working + directory. When multiple '-C' options are given, each subsequentI think this should be
-Cto typeset it as "typed literally".Documentation/git.txt displayed. See linkgit:git-help[1] for more information, · line 405
Quoted 5 lines
Documentation/git.txt +5
-0+ non-absolute `-C <path>` is interpreted relative to the preceding `-C + <path>`. ++ +This option affects options that expect path name like '--git-dir' and +'--work-tree' in that their interpretations of the path names would beQuoted 5 lines
Likewise for
--git-dirand--work-tree.Quoted 1 line
+made relative to the working directory caused by the '-C' option. For
and here.
Quoted 7 lines
I agree with all of the above, however, the unfortunate typesetting in these cases was chosen deliberately to be consistent with the immediately surrounding text. A separate typesetting normalization patch, either before or after this patch, would not be unwelcome. (I forgot to make such a suggestion in [1].)
[1]: http://thread.gmane.org/gmane.comp.version-control.git/233719/focus=234234
OK, thanks for clarification.
Quoted 7 lines · Junio C Hamano
t/t0056-git-C.sh line 21
Quoted 2 lines
t/t0056-git-C.sh new file +2
-0+ echo "initial in dir1/dir2" >expected && + git -C dir1/dir2 commit -m "initial in dir1/dir2" &&to reduce possibilities of breaking this test in the future due to typos (e.g. somebody may want to say "initial commit in dir1/dir2"), doing this may be a better idea:
Quoted 5 lines
msg="initial in dir1/dir2" && echo "$msg" >expected && git -C dir1/dir2 commit -m "$msg" &&The same comment applies to the previous one.
In his original submission, Nazri actually had it the way you suggest for this test (though not the preceding test), but changed it in response to a silly parenthetical "IMHO" in my review [1].
[1]: http://thread.gmane.org/gmane.comp.version-control.git/233636/focus=233704
Quoted 16 lines · Nazri Ramliy
Quoted 6 lines · Junio C Hamano
I do not care too deeply either way, but I am curious if there was a reason why you changed the earlier <directory> to <path>? Somehow, when we _know_ a path has to be a directory, I find it easier on the readers to spell that out, instead of saying "this is a path", implying that it could be a directory, a regular file, or even non-existent.
Eric made me do it :). Personally I prefer the non-ambiguous "directory" over "path". In fact, "directory" is used in the error message spat out by git:
$ git --work-tree No directory given for --work-tree. ...
Quoted 8 lines
$ git --git-dir No directory given for --git-dir. ... $I think changing "<path>" to "<directory>" wherever appropriate in git.txt would be an improvement. Tangent: <dir> is shorter but that might not be easy on the translators.
Such a terminology change is orthogonal to the patch adding -C support, so if you do pursue it, the terminology change should be a separate patch (either preparatory or follow-up to the -C patch).
Quoted 12 lines · Junio C Hamano
Quoted 10 lines · Nazri Ramliy
-- >8 --
Documentation/git.txt +0
-1@@ -9,7 +9,7 @@ git - the stupid content tracker SYNOPSIS -------- [verse] -'git' [--version] [--help] [-c <name>=<value>]
Quoted 8 lines
Documentation/git.txt git - the stupid content tracker · line 12
Quoted 1 line
Documentation/git.txt +1
-0+'git' [--version] [--help] [-C <path>] [-c <name>=<value>]I do not care too deeply either way, but I am curious if there was a reason why you changed the earlier <directory> to <path>? Somehow, when we _know_ a path has to be a directory, I find it easier on the readers to spell that out, instead of saying "this is a path", implying that it could be a directory, a regular file, or even non-existent.
That change was in response to my review [1] in which I mentioned:
Other options which accept a directory, such as --git-dir and --work-tree, are documented as accepting <path>, but -C is inconsistently documented as accepting <directory>.
Quoted 3 lines
Documentation/git.txt git - the stupid content tracker · line 15
Quoted 3 lines
Documentation/git.txt +0
-0[--exec-path[=<path>]] [--html-path] [--man-path] [--info-path] [-p|--paginate|--no-pager] [--no-replace-objects] [--bare] [--git-dir=<path>] [--work-tree=<path>] [--namespace=<name>]
Thus <directory> was inconsistent with existing text in git.txt, such as what is visible here for --git-dir and --work-tree, as well as later in git.txt where --git-dir and --work-tree are described in more detail (also using <path>).
[1]: http://thread.gmane.org/gmane.comp.version-control.git/233441/focus=233564