From: Jonas Fonseca <hidden> Date: 2016-06-15 22:43:15
Hello,
During a talk with madduck on #git today, we stumbled upon this
confusing error message:
$ mkdir repo
$ cd repo/
$ git init
Initialized empty Git repository in .git/
$ mkdir empty
$ git add empty/
The following paths are ignored by one of your .gitignore files:
empty/ (directory)
Use -f if you really want to add them.
$ git add -f empty/
fatal: unable to index file empty/
First, it misleads the user by assuming that something was added to
.gitignore or another exclude file, and the second error message is not
very helpful.
Looking at the code, I am not sure how this can be fixed. Simply
printing a warning when finding "some" empty directory might do, but it
is not the best way to help somebody new to git. Refusing to add
anything when finding an empty directory deep in some hierarchy is not a
good option either.
Git 1.4 silently did nothing, so 1.5 at least tries to be more clueful.
Anyway, I thought I would mention it and see what happens. ;)
--
Jonas Fonseca
From: Jeff King <hidden> Date: 2016-06-15 22:43:15
On Sun, Jun 10, 2007 at 10:46:48PM +0200, Jonas Fonseca wrote:
During a talk with madduck on #git today, we stumbled upon this
confusing error message:
$ mkdir repo
$ cd repo/
$ git init
Initialized empty Git repository in .git/
$ mkdir empty
$ git add empty/
The following paths are ignored by one of your .gitignore files:
empty/ (directory)
Use -f if you really want to add them.
$ git add -f empty/
fatal: unable to index file empty/
Urgh, that's ugly. The problem is that git-add sticks
assumed-to-be-ignored stuff back into the list of files found by
read_directory, but with some special ignored flags (which aren't used
anywhere else!). When the assumption is wrong (because the path is
_actually_ just empty), you get the bogus message, and when you try to
force it, you get an error from elsewhere in the code.
Patch series will be out momentarily.
-Peff
From: Jeff King <hidden> Date: 2016-06-15 22:43:15
When set, this option will cause read_directory to keep
track of which entries were ignored. While this shouldn't
effect functionality in most cases, it can make warning
messages to the user much more useful.
Signed-off-by: Jeff King <redacted>
---
dir.c | 12 ++++++++++++
dir.h | 5 ++++-
2 files changed, 16 insertions(+), 1 deletions(-)
From: Jeff King <hidden> Date: 2016-06-15 22:43:15
Previously, the code would always set up the excludes, and then manually
pick through the pathspec we were given, assuming that non-added but
existing paths were just ignored. This was mostly correct, but would
erroneously mark a totally empty directory as 'ignored'.
Instead, we now use the collect_ignored option of dir_struct, which
unambiguously tells us whether a path was ignored. This simplifies the
code, and means empty directories are now just not mentioned at all.
Furthermore, we now conditionally ask dir_struct to respect excludes,
depending on whether the '-f' flag has been set. This means we don't have
to pick through the result, checking for an 'ignored' flag; ignored entries
were either added or not in the first place.
We can safely get rid of the special 'ignored' flags to dir_entry, which
were not used anywhere else.
Signed-off-by: Jeff King <redacted>
---
builtin-add.c | 89 ++++++++++++++++++++++++++++++--------------------------
dir.c | 1 -
dir.h | 4 +--
3 files changed, 49 insertions(+), 45 deletions(-)
@@ -40,42 +57,29 @@ static void prune_directory(struct dir_struct *dir, const char **pathspec, int pdir->nr=dst-dir->entries;for(i=0;i<specs;i++){-structstatst;-constchar*match;-if(seen[i])-continue;--match=pathspec[i];-if(!match[0])-continue;--/* Existing file? We must have ignored it */-if(!lstat(match,&st)){-structdir_entry*ent;--ent=dir_add_name(dir,match,strlen(match));-ent->ignored=1;-if(S_ISDIR(st.st_mode))-ent->ignored_dir=1;-continue;-}-die("pathspec '%s' did not match any files",match);+if(!seen[i]&&!file_exists(pathspec[i]))+die("pathspec '%s' did not match any files",+pathspec[i]);}}-staticvoidfill_directory(structdir_struct*dir,constchar**pathspec)+staticvoidfill_directory(structdir_struct*dir,constchar**pathspec,+intignored_too){constchar*path,*base;intbaselen;/* Set up the default git porcelain excludes */memset(dir,0,sizeof(*dir));-dir->exclude_per_dir=".gitignore";-path=git_path("info/exclude");-if(!access(path,R_OK))-add_excludes_from_file(dir,path);-if(!access(excludes_file,R_OK))-add_excludes_from_file(dir,excludes_file);+if(!ignored_too){+dir->collect_ignored=1;+dir->exclude_per_dir=".gitignore";+path=git_path("info/exclude");+if(!access(path,R_OK))+add_excludes_from_file(dir,path);+if(!access(excludes_file,R_OK))+add_excludes_from_file(dir,excludes_file);+}/**Calculatecommonprefixforthepathspec,and
@@ -93,8 +97,10 @@ static void fill_directory(struct dir_struct *dir, const char **pathspec)/* Read the directory and prune it */read_directory(dir,path,base,baselen,pathspec);-if(pathspec)+if(pathspec){+prune_ignored(dir,pathspec);prune_directory(dir,pathspec,baselen);+}}staticvoidupdate_callback(structdiff_queue_struct*q,
@@ -237,25 +242,19 @@ int cmd_add(int argc, const char **argv, const char *prefix)if(read_cache()<0)die("index file corrupt");-if(!ignored_too){-inthas_ignored=0;-for(i=0;i<dir.nr;i++)-if(dir.entries[i]->ignored)-has_ignored=1;-if(has_ignored){-fprintf(stderr,ignore_warning);-for(i=0;i<dir.nr;i++){-if(!dir.entries[i]->ignored)-continue;-fprintf(stderr,"%s",dir.entries[i]->name);-if(dir.entries[i]->ignored_dir)-fprintf(stderr," (directory)");-fputc('\n',stderr);-}-fprintf(stderr,-"Use -f if you really want to add them.\n");-exit(1);+has_ignored=0;+for(i=0;i<dir.ignored_nr;i++){+if(dir.ignored[i])+has_ignored=1;+}+if(has_ignored){+fprintf(stderr,ignore_warning);+for(i=0;i<dir.ignored_nr;i++){+if(dir.ignored[i])+fprintf(stderr,"%s\n",dir.ignored[i]->name);}+fprintf(stderr,"Use -f if you really want to add them.\n");+exit(1);}for(i=0;i<dir.nr;i++)
From: Jeff King <hidden> Date: 2016-06-15 22:43:15
This is in preparation for keeping two entry lists in the
dir object.
This patch adds and uses the alloc_grow macro, which
implements the commonly used idiom of growing a dynamic
array using the alloc_nr function (not just in dir.c, but
everywhere).
We also move creation of a dir_entry to dir_entry_new.
Signed-off-by: Jeff King <redacted>
---
If we like the alloc_grow approach, there are a lot of places where we
can drop a 3-5 line conditional into a single line. I find it much more
readable, but others may disagree.
cache.h | 6 ++++++
dir.c | 23 +++++++++++------------
2 files changed, 17 insertions(+), 12 deletions(-)
From: Johannes Schindelin <hidden> Date: 2016-06-15 22:43:15
Hi,
On Mon, 11 Jun 2007, Jeff King wrote:
If we like the alloc_grow approach, there are a lot of places where we
can drop a 3-5 line conditional into a single line. I find it much more
readable, but others may disagree.
@@ -237,25 +242,19 @@ int cmd_add(int argc, const char **argv, const char *prefix)if(read_cache()<0)die("index file corrupt");-if(!ignored_too){-inthas_ignored=0;-for(i=0;i<dir.nr;i++)-if(dir.entries[i]->ignored)-has_ignored=1;-if(has_ignored){-fprintf(stderr,ignore_warning);-for(i=0;i<dir.nr;i++){-if(!dir.entries[i]->ignored)-continue;-fprintf(stderr,"%s",dir.entries[i]->name);-if(dir.entries[i]->ignored_dir)-fprintf(stderr," (directory)");-fputc('\n',stderr);-}-fprintf(stderr,-"Use -f if you really want to add them.\n");-exit(1);+has_ignored=0;+for(i=0;i<dir.ignored_nr;i++){+if(dir.ignored[i])+has_ignored=1;+}+if(has_ignored){+fprintf(stderr,ignore_warning);+for(i=0;i<dir.ignored_nr;i++){+if(dir.ignored[i])+fprintf(stderr,"%s\n",dir.ignored[i]->name);}+fprintf(stderr,"Use -f if you really want to add them.\n");+exit(1);}for(i=0;i<dir.nr;i++)
I think you could even get rid of has_ignored with something like this.
From: Jeff King <hidden> Date: 2016-06-15 22:43:15
On Mon, Jun 11, 2007 at 05:01:23PM +0200, Jonas Fonseca wrote:
Thanks for looking into this and making these patches. :)
No problem. I had run it across it before and it was on my "look into
this" list...thank you for providing a test case. :)
I think you could even get rid of has_ignored with something like this.
Nope, I had originally wanted to do that, but the dir_struct.ignored
list contains _all_ ignored items, not just those that were originally
in the pathspec. The prune_ignored call sets uninteresting ones to
NULL. That function could compact the list and re-set ignored_nr, but
it doesn't currently do so.
An even more elegant solution would be for read_directory to mark
whether an ignored file comes from a pathspec, or was found through
recursion. That would be more efficient, and it would remove the
prune_ignored thing, which is IMHO a little hack-ish.
I don't have time to work on it now, but I might look at it more tonight
or tomorrow (but please, if you are interested, take a crack at it).
-Peff
From: Jonas Fonseca <hidden> Date: 2016-06-15 22:43:15
Jeff King [off-list ref] wrote Mon, Jun 11, 2007:
On Mon, Jun 11, 2007 at 05:01:23PM +0200, Jonas Fonseca wrote:
quoted
I think you could even get rid of has_ignored with something like this.
Nope, I had originally wanted to do that, but the dir_struct.ignored
list contains _all_ ignored items, not just those that were originally
in the pathspec. The prune_ignored call sets uninteresting ones to
NULL. That function could compact the list and re-set ignored_nr, but
it doesn't currently do so.
Ah, I see.
An even more elegant solution would be for read_directory to mark
whether an ignored file comes from a pathspec, or was found through
recursion. That would be more efficient, and it would remove the
prune_ignored thing, which is IMHO a little hack-ish.
I don't have time to work on it now, but I might look at it more tonight
or tomorrow (but please, if you are interested, take a crack at it).
Yes, I think it might be nice for me to do if you don't mind. I would
like some more experience with the git code. Maybe even redo the whole
patch series to also fix the concerns about the alloc_grow macro.
--
Jonas Fonseca
From: Jeff King <hidden> Date: 2016-06-15 22:43:15
On Mon, Jun 11, 2007 at 09:15:54PM +0200, Jonas Fonseca wrote:
quoted
I don't have time to work on it now, but I might look at it more tonight
or tomorrow (but please, if you are interested, take a crack at it).
Yes, I think it might be nice for me to do if you don't mind. I would
like some more experience with the git code. Maybe even redo the whole
patch series to also fix the concerns about the alloc_grow macro.
Great, feel free to rework the series as you see fit. My "tonight"
timeframe was a bit optimistic anyway, as we have a new baby here. :)
-Peff
From: Jonas Fonseca <hidden> Date: 2016-06-15 22:43:16
From: Jeff King <redacted>
Previously, the code would always set up the excludes, and then manually
pick through the pathspec we were given, assuming that non-added but
existing paths were just ignored. This was mostly correct, but would
erroneously mark a totally empty directory as 'ignored'.
Instead, we now use the collect_ignored option of dir_struct, which
unambiguously tells us whether a path was ignored. This simplifies the
code, and means empty directories are now just not mentioned at all.
Furthermore, we now conditionally ask dir_struct to respect excludes,
depending on whether the '-f' flag has been set. This means we don't have
to pick through the result, checking for an 'ignored' flag; ignored entries
were either added or not in the first place.
We can safely get rid of the special 'ignored' flags to dir_entry, which
were not used anywhere else.
Signed-off-by: Jeff King <redacted>
Signed-off-by: Jonas Fonseca <redacted>
---
builtin-add.c | 69 +++++++++++++++++---------------------------------------
dir.c | 16 +++++++++++-
dir.h | 4 +--
3 files changed, 36 insertions(+), 53 deletions(-)
Jeff King [off-list ref] wrote Mon, Jun 11, 2007:
> On Mon, Jun 11, 2007 at 05:01:23PM +0200, Jonas Fonseca wrote:
> > I think you could even get rid of has_ignored with something like this.
>
> Nope, I had originally wanted to do that, but the dir_struct.ignored
> list contains _all_ ignored items, not just those that were originally
> in the pathspec. The prune_ignored call sets uninteresting ones to
> NULL. That function could compact the list and re-set ignored_nr, but
> it doesn't currently do so.
>
> An even more elegant solution would be for read_directory to mark
> whether an ignored file comes from a pathspec, or was found through
> recursion. That would be more efficient, and it would remove the
> prune_ignored thing, which is IMHO a little hack-ish.
OK, I tried to do this, however, I got a bit confused with the intended
behavior. Anyway, it passes the test suite, is silent for empty
directories and will only show exact matches of the pathspec (this was
the confusing part) as ignored items.
@@ -40,42 +40,29 @@ static void prune_directory(struct dir_struct *dir, const char **pathspec, int pdir->nr=dst-dir->entries;for(i=0;i<specs;i++){-structstatst;-constchar*match;-if(seen[i])-continue;--match=pathspec[i];-if(!match[0])-continue;--/* Existing file? We must have ignored it */-if(!lstat(match,&st)){-structdir_entry*ent;--ent=dir_add_name(dir,match,strlen(match));-ent->ignored=1;-if(S_ISDIR(st.st_mode))-ent->ignored_dir=1;-continue;-}-die("pathspec '%s' did not match any files",match);+if(!seen[i]&&!file_exists(pathspec[i]))+die("pathspec '%s' did not match any files",+pathspec[i]);}}-staticvoidfill_directory(structdir_struct*dir,constchar**pathspec)+staticvoidfill_directory(structdir_struct*dir,constchar**pathspec,+intignored_too){constchar*path,*base;intbaselen;/* Set up the default git porcelain excludes */memset(dir,0,sizeof(*dir));-dir->exclude_per_dir=".gitignore";-path=git_path("info/exclude");-if(!access(path,R_OK))-add_excludes_from_file(dir,path);-if(!access(excludes_file,R_OK))-add_excludes_from_file(dir,excludes_file);+if(!ignored_too){+dir->collect_ignored=1;+dir->exclude_per_dir=".gitignore";+path=git_path("info/exclude");+if(!access(path,R_OK))+add_excludes_from_file(dir,path);+if(!access(excludes_file,R_OK))+add_excludes_from_file(dir,excludes_file);+}/**Calculatecommonprefixforthepathspec,and
@@ -237,25 +222,13 @@ int cmd_add(int argc, const char **argv, const char *prefix)if(read_cache()<0)die("index file corrupt");-if(!ignored_too){-inthas_ignored=0;-for(i=0;i<dir.nr;i++)-if(dir.entries[i]->ignored)-has_ignored=1;-if(has_ignored){-fprintf(stderr,ignore_warning);-for(i=0;i<dir.nr;i++){-if(!dir.entries[i]->ignored)-continue;-fprintf(stderr,"%s",dir.entries[i]->name);-if(dir.entries[i]->ignored_dir)-fprintf(stderr," (directory)");-fputc('\n',stderr);-}-fprintf(stderr,-"Use -f if you really want to add them.\n");-exit(1);+if(dir.ignored_nr){+fprintf(stderr,ignore_warning);+for(i=0;i<dir.ignored_nr;i++){+fprintf(stderr,"%s\n",dir.ignored[i]->name);}+fprintf(stderr,"Use -f if you really want to add them.\n");+exit(1);}for(i=0;i<dir.nr;i++)