$ git init abc
$ cd abc
$ mkdir def
$ echo 'gitdir: blah blah' >def/.git
$ git ls-files -o
fatal: Not a git repository: def/blah blah
If some directory looks like a submodule but turns out not, that's not
a fatal error. The stack trace is something like this. I suspect
do_submodule_path should use the gently version..
#1 0x0000000000588a78 in die
#2 0x0000000000558ded in read_gitfile_gently
#3 0x000000000051e2f6 in do_submodule_path
#4 0x000000000051e484 in git_pathdup_submodule
#5 0x00000000005340ac in resolve_gitlink_ref_recursive
#6 0x00000000005342cf in resolve_gitlink_ref
#7 0x00000000004dd20d in treat_directory
#8 0x00000000004dd760 in treat_one_path
#9 0x00000000004dd971 in treat_path
#10 0x00000000004de038 in read_directory_recursive
--
Duy
From: Jeff King <hidden> Date: 2016-06-15 23:07:51
On Fri, Jan 22, 2016 at 04:17:29PM +0700, Duy Nguyen wrote:
$ git init abc
$ cd abc
$ mkdir def
$ echo 'gitdir: blah blah' >def/.git
$ git ls-files -o
fatal: Not a git repository: def/blah blah
If some directory looks like a submodule but turns out not, that's not
a fatal error. The stack trace is something like this. I suspect
do_submodule_path should use the gently version..
#1 0x0000000000588a78 in die
#2 0x0000000000558ded in read_gitfile_gently
#3 0x000000000051e2f6 in do_submodule_path
#4 0x000000000051e484 in git_pathdup_submodule
#5 0x00000000005340ac in resolve_gitlink_ref_recursive
#6 0x00000000005342cf in resolve_gitlink_ref
#7 0x00000000004dd20d in treat_directory
#8 0x00000000004dd760 in treat_one_path
#9 0x00000000004dd971 in treat_path
#10 0x00000000004de038 in read_directory_recursive
Here it is. I think this is the right fix, based on the previous attempt
by Andreas and my comments. Sorry for stealing your topic, but I hope
the perf numbers in the second patch will brighten your day. :)
[1/2]: clean: make is_git_repository a public function
[2/2]: resolve_gitlink_ref: ignore non-repository paths
-Peff
From: Jeff King <hidden> Date: 2016-06-15 23:07:51
We have always had is_git_directory(), for looking at a
specific directory to see if it contains a git repo. In
0179ca7 (clean: improve performance when removing lots of
directories, 2015-06-15), we added is_git_repository() which
checks for a non-bare repository by looking at its ".git"
entry.
However, the fix in 0179ca7 needs to be applied other
places, too. Let's make this new helper globally available.
We need to give it a better name, though, to avoid confusion
with is_git_directory(). This patch does that, documents
both functions with a comment to reduce confusion, and
removes the clean-specific references in the comments.
Based-on-a-patch-by: Andreas Krey [off-list ref]
Signed-off-by: Jeff King <redacted>
---
builtin/clean.c | 26 +-------------------------
cache.h | 20 +++++++++++++++++++-
setup.c | 17 +++++++++++++++++
3 files changed, 37 insertions(+), 26 deletions(-)
@@ -147,30 +147,6 @@ static int exclude_cb(const struct option *opt, const char *arg, int unset)return0;}-/*-*Return1ifthegivenpathistherootofagitrepositoryor-*submoduleelse0.Willnotreturn1forbarerepositorieswiththe-*exceptionofcreatingabarerepositoryin"foo/.git"andcalling-*is_git_repository("foo").-*/-staticintis_git_repository(structstrbuf*path)-{-intret=0;-intgitfile_error;-size_torig_path_len=path->len;-assert(orig_path_len!=0);-strbuf_complete(path,'/');-strbuf_addstr(path,".git");-if(read_gitfile_gently(path->buf,&gitfile_error)||is_git_directory(path->buf))-ret=1;-if(gitfile_error==READ_GITFILE_ERR_OPEN_FAILED||-gitfile_error==READ_GITFILE_ERR_READ_FAILED)-ret=1;/* This could be a real .git file, take the-*safeoptionandavoidcleaning*/-strbuf_setlen(path,orig_path_len);-returnret;-}-staticintremove_dirs(structstrbuf*path,constchar*prefix,intforce_flag,intdry_run,intquiet,int*dir_gone){
@@ -182,7 +158,7 @@ static int remove_dirs(struct strbuf *path, const char *prefix, int force_flag,*dir_gone=1;-if((force_flag&REMOVE_DIR_KEEP_NESTED_GIT)&&is_git_repository(path)){+if((force_flag&REMOVE_DIR_KEEP_NESTED_GIT)&&is_nonbare_repository_dir(path)){if(!quiet){quote_path_relative(path->buf,prefix,"ed);printf(dry_run?_(msg_would_skip_git_dir):_(msg_skip_git_dir),
From: Jeff King <hidden> Date: 2016-06-15 23:07:51
When we want to look up a submodule ref, we use
get_ref_cache(path) to find or auto-create its ref cache.
But if we feed a path that isn't actually a git repository,
we blindly create the ref cache, and then may die deeper in
the code when we try to access it. This is a problem because
many callers speculatively feed us a path that looks vaguely
like a repository, and expect us to tell them when it is
not.
This patch teaches resolve_gitlink_ref to reject
non-repository paths without creating a ref_cache. This
avoids the die(), and also performs better if you have a
large number of these faux-submodule directories (because
the ref_cache lookup is linear, under the assumption that
there won't be a large number of submodules).
To accomplish this, we also break get_ref_cache into two
pieces: the lookup and auto-creation (the latter is lumped
into create_ref_cache). This lets us first cheaply ask our
cache "is it a submodule we know about?" If so, we can avoid
repeating our filesystem lookup. So lookups of real
submodules are not penalized; they examine the submodule's
.git directory only once.
The test in t3000 demonstrates a case where this improves
correctness (we used to just die). The new perf case in
p7300 shows off the speed improvement in an admittedly
pathological repository:
Test HEAD^ HEAD
----------------------------------------------------------------
7300.4: ls-files -o 66.97(66.15+0.87) 0.33(0.08+0.24) -99.5%
Signed-off-by: Jeff King <redacted>
---
refs/files-backend.c | 46 ++++++++++++++++++++++++++++++++--------------
t/perf/p7300-clean.sh | 4 ++++
t/t3000-ls-files-others.sh | 7 +++++++
3 files changed, 43 insertions(+), 14 deletions(-)
BTW, I scratched my head about why I was able to use "expected1" here
without having to add "not-a-submodule" to it. But the answer is that
the directory itself does not get mentioned (it is not a file!), and we
seem to always exclude ".git" paths entirely.
I'm not sure if that's the best thing in every case (what if you have
precious content in a ".git" file?), but this does behave exactly as a
valid ".git" would with an empty HEAD ref. So I think it's a reasonable
behavior in practice.
-Peff
From: Stefan Beller <hidden> Date: 2016-06-15 23:07:51
Impressive performance improvements. :)
On Fri, Jan 22, 2016 at 2:31 PM, Jeff King [off-list ref] wrote:
BTW, what if you have
precious content in a ".git" file?
I'd kindly ask to use a different version control in that case.
Q: What can you use Git for?
A: Everything including version control, backup, deploying software,
except when there is a file named .git with precious content.
;)
From: Jeff King <hidden> Date: 2016-06-15 23:07:51
On Fri, Jan 22, 2016 at 02:36:54PM -0800, Stefan Beller wrote:
Impressive performance improvements. :)
"Accidentally quadratic" bugs are some of my favorites, because it's
usually easy to show off the results. Of course, the repo in p7300 is
pretty ridiculous, and most people won't see any speedup. I'll be
curious to hear about Andreas's case, as it is a real-world one which
may see some improvement.
quoted
BTW, what if you have
precious content in a ".git" file?
I'd kindly ask to use a different version control in that case.
Q: What can you use Git for?
A: Everything including version control, backup, deploying software,
except when there is a file named .git with precious content.
;)
Yeah, I think that is my attitude as well. Just because your ".git" file
is not actually a real gitfile does not make it a good idea. We do not
list it in "ls-files -o", but it is not like you could commit it,
either; we explicitly prevent it from being added to the index.
-Peff
From: Andreas Krey <hidden> Date: 2016-06-15 23:07:53
On Fri, 22 Jan 2016 17:26:50 +0000, Jeff King wrote:
...
Here it is. I think this is the right fix, based on the previous attempt
by Andreas and my comments. Sorry for stealing your topic,
This seems to keep happening with things I try to patch. :-)
but I hope
the perf numbers in the second patch will brighten your day. :)
The patches are 'quadratically' improving my case as well,
many thanks for completing this. (I was just mustering
the steam for another round of work on this.)
Andreas
--
"Totally trivial. Famous last words."
From: Linus Torvalds <torvalds@*.org>
Date: Fri, 22 Jan 2010 07:29:21 -0800