git.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* git rev-parse --show-toplevel inside `.git` returns 0 and prints nothing
@ 2019-11-18 22:26 Anthony Sottile
  2019-11-19  2:52 ` Junio C Hamano
  0 siblings, 1 reply; 6+ messages in thread
From: Anthony Sottile @ 2019-11-18 22:26 UTC (permalink / raw)
  To: Git Mailing List

I would expect it to either:
- exit nonzero
- produce the full path to the root of the repository

would a patch be accepted which changes it to do one of those two
things? I'd be happy to contribute such a patch

Anthony

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: git rev-parse --show-toplevel inside `.git` returns 0 and prints nothing
  2019-11-18 22:26 git rev-parse --show-toplevel inside `.git` returns 0 and prints nothing Anthony Sottile
@ 2019-11-19  2:52 ` Junio C Hamano
  2019-11-19  3:33   ` Jeff King
  0 siblings, 1 reply; 6+ messages in thread
From: Junio C Hamano @ 2019-11-19  2:52 UTC (permalink / raw)
  To: Anthony Sottile; +Cc: Git Mailing List

Anthony Sottile <asottile@umich.edu> writes:

> I would expect it to either:
> - exit nonzero
> - produce the full path to the root of the repository
>
> would a patch be accepted which changes it to do one of those two
> things? I'd be happy to contribute such a patch

The most important invariant for the "--show-toplevel" and the
"--show-prefix" options was that when they are concatenated the
result matches the current directory in a working tree.  So I think
the result is undefined when you are not anywhere in the working
tree.

Having said that, as scripts that want to know if they are inside
.git directory (either directly in it, or in its subdirectories)
should not be relying on the behaviour, and instead be using the
"--is-inside-git-dir" option, I suspect that it won't be too
disruptive to change the behaviour after all these years.  

But it is no longer year 2007 and with widespread use of Git, it is
almost guaranteed to break somebody's script ;-)

If I were designing the feature today, with today's rest-of-git in
mind, I would say

 - In a bare repository, exit with non-zero status after giving an
   error message "no working tree".

 - In a repository that has a single associated working tree, show
   the path to the top-level of that working tree and exit with zero
   status.

In a repository that has more than one working trees (which is one
of the things "todasy's rest-of-git" has that did not exist back
when --show-prefix/--show-toplevel etc. were invented), then what?
Would it make sense to show the primary working tree?  What if the
worktree(s) were made off of a bare repository, in which case nobody
is the primary?

If we were changing "--show-toplevel", we may need to make changes
to "--show-prefix" to things consistent, but I am not sure what it
should say when run outside a working tree.  It should continue to
give nothing; it may make sense to exit with non-zero status, but
I'd rather let sleeping dogs lie.  Nobody is hurting by the command
exiting with zero status (the same question applies to the
"--show-toplevel" option, for that matter, though), when the result
is undefined.

So...  I dunno.




^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: git rev-parse --show-toplevel inside `.git` returns 0 and prints nothing
  2019-11-19  2:52 ` Junio C Hamano
@ 2019-11-19  3:33   ` Jeff King
  2019-11-19  4:13     ` Anthony Sottile
  2019-11-19  8:05     ` Jeff King
  0 siblings, 2 replies; 6+ messages in thread
From: Jeff King @ 2019-11-19  3:33 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Anthony Sottile, Git Mailing List

On Tue, Nov 19, 2019 at 11:52:54AM +0900, Junio C Hamano wrote:

> If I were designing the feature today, with today's rest-of-git in
> mind, I would say
> 
>  - In a bare repository, exit with non-zero status after giving an
>    error message "no working tree".
> 
>  - In a repository that has a single associated working tree, show
>    the path to the top-level of that working tree and exit with zero
>    status.

Do you mean to do this even in when the cwd is inside .git?

I think that's confusing, because you don't actually have a working tree
at all. E.g.:

  $ git rev-parse --show-toplevel
  /home/peff/tmp
  $ git status -b --short
  ## No commits yet on master

  $ cd .git
  $ git rev-parse --show-toplevel
  $ git status -b --short
  fatal: this operation must be run in a work tree

So internal commands like status accept that we have no working tree in
this situation. But "--show-toplevel" just prints nothing. I'd amend
your second point to be "If we are in the working tree of a repository,
show the path to the top-level of that working tree and exit with zero
status".

And then that leaves another case: we are not in the working tree of the
repository. In which case I think it should be the same as the bare
repository.

And from that, your multi-working-tree case falls out naturally:

> In a repository that has more than one working trees (which is one
> of the things "todasy's rest-of-git" has that did not exist back
> when --show-prefix/--show-toplevel etc. were invented), then what?
> Would it make sense to show the primary working tree?  What if the
> worktree(s) were made off of a bare repository, in which case nobody
> is the primary?

There may be multiple working trees, but we can only be in one of them
at a time. So that's the one that we show.

And the only real change here is that "--show-toplevel" prints an error
and exits non-zero when we won't have a working tree. Something like:

diff --git a/builtin/rev-parse.c b/builtin/rev-parse.c
index 3857fd1b8a..81161f2dfb 100644
--- a/builtin/rev-parse.c
+++ b/builtin/rev-parse.c
@@ -805,6 +805,8 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix)
 				const char *work_tree = get_git_work_tree();
 				if (work_tree)
 					puts(work_tree);
+				else
+					die("this operation must be run in a work tree");
 				continue;
 			}
 			if (!strcmp(arg, "--show-superproject-working-tree")) {


I think the reason this hasn't come up until now is callers are expected
to use require_work_tree() or "rev-parse --is-inside-work-tree" first.

It would probably make sense for the rev-parse documentation to also
clarify what "the top-level directory" is.

-Peff

^ permalink raw reply related	[flat|nested] 6+ messages in thread

* Re: git rev-parse --show-toplevel inside `.git` returns 0 and prints nothing
  2019-11-19  3:33   ` Jeff King
@ 2019-11-19  4:13     ` Anthony Sottile
  2019-11-19  7:37       ` Jeff King
  2019-11-19  8:05     ` Jeff King
  1 sibling, 1 reply; 6+ messages in thread
From: Anthony Sottile @ 2019-11-19  4:13 UTC (permalink / raw)
  To: Jeff King; +Cc: Junio C Hamano, Git Mailing List

On Mon, Nov 18, 2019 at 7:33 PM Jeff King <peff@peff.net> wrote:
>
> On Tue, Nov 19, 2019 at 11:52:54AM +0900, Junio C Hamano wrote:
>
> > If I were designing the feature today, with today's rest-of-git in
> > mind, I would say
> >
> >  - In a bare repository, exit with non-zero status after giving an
> >    error message "no working tree".
> >
> >  - In a repository that has a single associated working tree, show
> >    the path to the top-level of that working tree and exit with zero
> >    status.
>
> Do you mean to do this even in when the cwd is inside .git?
>
> I think that's confusing, because you don't actually have a working tree
> at all. E.g.:
>
>   $ git rev-parse --show-toplevel
>   /home/peff/tmp
>   $ git status -b --short
>   ## No commits yet on master
>
>   $ cd .git
>   $ git rev-parse --show-toplevel
>   $ git status -b --short
>   fatal: this operation must be run in a work tree
>
> So internal commands like status accept that we have no working tree in
> this situation. But "--show-toplevel" just prints nothing. I'd amend
> your second point to be "If we are in the working tree of a repository,
> show the path to the top-level of that working tree and exit with zero
> status".
>
> And then that leaves another case: we are not in the working tree of the
> repository. In which case I think it should be the same as the bare
> repository.
>
> And from that, your multi-working-tree case falls out naturally:
>
> > In a repository that has more than one working trees (which is one
> > of the things "todasy's rest-of-git" has that did not exist back
> > when --show-prefix/--show-toplevel etc. were invented), then what?
> > Would it make sense to show the primary working tree?  What if the
> > worktree(s) were made off of a bare repository, in which case nobody
> > is the primary?
>
> There may be multiple working trees, but we can only be in one of them
> at a time. So that's the one that we show.
>
> And the only real change here is that "--show-toplevel" prints an error
> and exits non-zero when we won't have a working tree. Something like:
>
> diff --git a/builtin/rev-parse.c b/builtin/rev-parse.c
> index 3857fd1b8a..81161f2dfb 100644
> --- a/builtin/rev-parse.c
> +++ b/builtin/rev-parse.c
> @@ -805,6 +805,8 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix)
>                                 const char *work_tree = get_git_work_tree();
>                                 if (work_tree)
>                                         puts(work_tree);
> +                               else
> +                                       die("this operation must be run in a work tree");
>                                 continue;
>                         }
>                         if (!strcmp(arg, "--show-superproject-working-tree")) {
>
>
> I think the reason this hasn't come up until now is callers are expected
> to use require_work_tree() or "rev-parse --is-inside-work-tree" first.
>
> It would probably make sense for the rev-parse documentation to also
> clarify what "the top-level directory" is.
>
> -Peff

I realize I forgot to include the X to my Y :) -- this was a totally
silly case that I got as a bug report:
https://github.com/pre-commit/pre-commit/issues/1219

I *expected* an error case but didn't get one

Anthony

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: git rev-parse --show-toplevel inside `.git` returns 0 and prints nothing
  2019-11-19  4:13     ` Anthony Sottile
@ 2019-11-19  7:37       ` Jeff King
  0 siblings, 0 replies; 6+ messages in thread
From: Jeff King @ 2019-11-19  7:37 UTC (permalink / raw)
  To: Anthony Sottile; +Cc: Junio C Hamano, Git Mailing List

On Mon, Nov 18, 2019 at 08:13:02PM -0800, Anthony Sottile wrote:

> > I think the reason this hasn't come up until now is callers are expected
> > to use require_work_tree() or "rev-parse --is-inside-work-tree" first.
> >
> > It would probably make sense for the rev-parse documentation to also
> > clarify what "the top-level directory" is.
> >
> > -Peff
> 
> I realize I forgot to include the X to my Y :) -- this was a totally
> silly case that I got as a bug report:
> https://github.com/pre-commit/pre-commit/issues/1219
> 
> I *expected* an error case but didn't get one

Yes, and I do agree that an error is the right thing.

Would that have helped your pre-commit script? I guess it would have
barfed at that point. :) It sounds like it should be checking first that
it has a working tree.

-Peff

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: git rev-parse --show-toplevel inside `.git` returns 0 and prints nothing
  2019-11-19  3:33   ` Jeff King
  2019-11-19  4:13     ` Anthony Sottile
@ 2019-11-19  8:05     ` Jeff King
  1 sibling, 0 replies; 6+ messages in thread
From: Jeff King @ 2019-11-19  8:05 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Anthony Sottile, Git Mailing List

On Mon, Nov 18, 2019 at 10:33:11PM -0500, Jeff King wrote:

> And the only real change here is that "--show-toplevel" prints an error
> and exits non-zero when we won't have a working tree. Something like:
> 
> diff --git a/builtin/rev-parse.c b/builtin/rev-parse.c
> index 3857fd1b8a..81161f2dfb 100644
> --- a/builtin/rev-parse.c
> +++ b/builtin/rev-parse.c
> @@ -805,6 +805,8 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix)
>  				const char *work_tree = get_git_work_tree();
>  				if (work_tree)
>  					puts(work_tree);
> +				else
> +					die("this operation must be run in a work tree");
>  				continue;
>  			}
>  			if (!strcmp(arg, "--show-superproject-working-tree")) {
> 
> 
> I think the reason this hasn't come up until now is callers are expected
> to use require_work_tree() or "rev-parse --is-inside-work-tree" first.
> 
> It would probably make sense for the rev-parse documentation to also
> clarify what "the top-level directory" is.

Here it is wrapped up with a commit message, a test, and a documentation
fix. I have to admit I'm having second thoughts, though. It _is_
slightly confusing, and this is what I would do if we were designing
from scratch. But the current behavior, while weird, does let the caller
distinguish all cases. So another option would just be to document the
outcome more clearly. I'm on the fence.

-- >8 --
Subject: [PATCH] rev-parse: make --show-toplevel without a worktree an error

Ever since it was introduced in 7cceca5ccc (Add 'git rev-parse
--show-toplevel' option., 2010-01-12), the --show-toplevel option has
treated a missing working tree as a quiet success: it neither prints a
toplevel path, but nor does it report any kind of error.

While a caller could distinguish this case by looking for an empty
response, the behavior is rather confusing. We're better off complaining
that there is no working tree, as other internal commands would do in
similar cases (e.g., "git status" or any builtin with NEED_WORK_TREE set
would just die()). So let's do the same here.

While we're at it, let's clarify the documentation and add some tests,
both for the new behavior and for the more mundane case (which was not
covered).

Signed-off-by: Jeff King <peff@peff.net>
---
 Documentation/git-rev-parse.txt |  3 ++-
 builtin/rev-parse.c             |  2 ++
 t/t1500-rev-parse.sh            | 10 ++++++++++
 3 files changed, 14 insertions(+), 1 deletion(-)

diff --git a/Documentation/git-rev-parse.txt b/Documentation/git-rev-parse.txt
index 9985477efe..19b12b6d43 100644
--- a/Documentation/git-rev-parse.txt
+++ b/Documentation/git-rev-parse.txt
@@ -262,7 +262,8 @@ print a message to stderr and exit with nonzero status.
 	directory.
 
 --show-toplevel::
-	Show the absolute path of the top-level directory.
+	Show the absolute path of the top-level directory of the working
+	tree. If there is no working tree, report an error.
 
 --show-superproject-working-tree::
 	Show the absolute path of the root of the superproject's
diff --git a/builtin/rev-parse.c b/builtin/rev-parse.c
index 85ce2095bf..7a00da8203 100644
--- a/builtin/rev-parse.c
+++ b/builtin/rev-parse.c
@@ -803,6 +803,8 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix)
 				const char *work_tree = get_git_work_tree();
 				if (work_tree)
 					puts(work_tree);
+				else
+					die("this operation must be run in a work tree");
 				continue;
 			}
 			if (!strcmp(arg, "--show-superproject-working-tree")) {
diff --git a/t/t1500-rev-parse.sh b/t/t1500-rev-parse.sh
index 0177fd815c..603019b541 100755
--- a/t/t1500-rev-parse.sh
+++ b/t/t1500-rev-parse.sh
@@ -146,6 +146,16 @@ test_expect_success 'rev-parse --show-object-format in repo' '
 	grep "unknown mode for --show-object-format: squeamish-ossifrage" err
 '
 
+test_expect_success '--show-toplevel from subdir of working tree' '
+	pwd >expect &&
+	git -C sub/dir rev-parse --show-toplevel >actual &&
+	test_cmp expect actual
+'
+
+test_expect_success '--show-toplevel from inside .git' '
+	test_must_fail git -C .git rev-parse --show-toplevel
+'
+
 test_expect_success 'showing the superproject correctly' '
 	git rev-parse --show-superproject-working-tree >out &&
 	test_must_be_empty out &&
-- 
2.24.0.512.g217e13b85d


^ permalink raw reply related	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2019-11-19  8:05 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-11-18 22:26 git rev-parse --show-toplevel inside `.git` returns 0 and prints nothing Anthony Sottile
2019-11-19  2:52 ` Junio C Hamano
2019-11-19  3:33   ` Jeff King
2019-11-19  4:13     ` Anthony Sottile
2019-11-19  7:37       ` Jeff King
2019-11-19  8:05     ` Jeff King

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).