{"thread":{"id":"27002","subject":"Bug Report: git add","startedAt":"2011-04-05T23:18:54Z","lastAt":"2011-04-11T18:20:38Z","messageCount":13,"participants":["Darren Cook","Ramkumar Ramachandra","Jeff King","Junio C Hamano","Jakub Narebski"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"165234","messageId":"4D9BA35E.6040204@dcook.org","threadId":"27002","inReplyTo":null,"subject":"Bug Report: git add","fromName":"Darren Cook","fromEmail":"darren@dcook.org","sentAt":"2011-04-05T23:18:54Z","receivedAt":"2011-04-05T23:18:54Z","isPatch":false,"sender":{"key":"darren@dcook.org","avatar":null},"body":"(Apologies if there is a proper place to report bugs; but I could not\nfind one.)\n\nPROBLEM: \"git add\" adds sub-directories without checking to see if there\nis already a git repository already there.\n\nWHY BAD: This causes files to be in two repositories (leading to a mess\nif you don't notice for a while...)\n\nONE SOLUTION: When adding files from a directory (except root of the\nrepository, of course) look for a .git subdirectory, and complain if\nfound. Allow --force to override this.\n\nMORE SOPHISTICATED:\n 1. Offer to merge in all that history, followed by removing that old\n.git subdirectory.\n\n 2. Look inside the .git subdirectory to see if the file being added is\nactually under control there. If not, no need to complain.\n\n\nEXAMPLE OF PROBLEM\n\nThe problem can arise when people are just dipping their toe into git,\nand decide to try it on just one directory, then later expand its use to\nthe whole project.\n\n  mkdir test\n  cd test\n\n  mkdir settings\n  cd settings\n  git init\n  touch x\n  git add x\n  git commit -m \"xx\"\n\n  (time passes)\n\n  cd ..\n  git init\n  git add settings/\n   (should complain)\n\n\n\nThanks for taking the time to read this,\n\nDarren\n\n\n\n\n-- \nDarren Cook, Software Researcher/Developer\n\nhttp://dcook.org/work/ (About me and my work)\nhttp://dcook.org/blogs.html (My blogs and articles)\n"},{"id":"165249","messageId":"20110406055200.GA12547@kytes","threadId":"27002","inReplyTo":"4D9BA35E.6040204@dcook.org","subject":"Re: Bug Report: git add","fromName":"Ramkumar Ramachandra","fromEmail":"artagnon@gmail.com","sentAt":"2011-04-06T05:52:04Z","receivedAt":"2011-04-06T05:52:04Z","isPatch":false,"sender":{"key":"r@artagnon.com","avatar":"https://avatars.githubusercontent.com/u/37226?v=4"},"body":"Hi Darren,\n\nDarren Cook writes:\n> (Apologies if there is a proper place to report bugs; but I could not\n> find one.)\n\nThere is no bugtracker, so this is the right place to report it.\nThanks for reporting.\n\n> PROBLEM: \"git add\" adds sub-directories without checking to see if there\n> is already a git repository already there.\n> \n> WHY BAD: This causes files to be in two repositories (leading to a mess\n> if you don't notice for a while...)\n> \n> ONE SOLUTION: When adding files from a directory (except root of the\n> repository, of course) look for a .git subdirectory, and complain if\n> found. Allow --force to override this.\n\nThis is a good suggestion.  It already has a way to handle gitlinks\n(for submodules), so this seems like a very reasonable feature.\n\n> MORE SOPHISTICATED:\n>  1. Offer to merge in all that history, followed by removing that old\n> .git subdirectory.\n\nHm, I don't like this one -- there are too many ways to \"merge\" the\nhistory, and I can't see a sane default (or even a sane subset of\ndefaults).\n\n>  2. Look inside the .git subdirectory to see if the file being added is\n> actually under control there. If not, no need to complain.\n\nI don't like this one either.  Tangling up two Git repositories like\nthis is not a good idea -- the user should use submodules or similar.\n\nNext steps: Me (or someone else who has the time) will post a patch\nfixing this shortly.\n\n-- Ram\n"},{"id":"165327","messageId":"20110407005750.GC28813@sigill.intra.peff.net","threadId":"27002","inReplyTo":"4D9BA35E.6040204@dcook.org","subject":"Re: Bug Report: git add","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2011-04-07T00:57:50Z","receivedAt":"2011-04-07T00:57:50Z","isPatch":false,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Wed, Apr 06, 2011 at 08:18:54AM +0900, Darren Cook wrote:\n\n> PROBLEM: \"git add\" adds sub-directories without checking to see if there\n> is already a git repository already there.\n\nSort of...\n\n> EXAMPLE OF PROBLEM\n> \n> The problem can arise when people are just dipping their toe into git,\n> and decide to try it on just one directory, then later expand its use to\n> the whole project.\n> \n>   mkdir test\n>   cd test\n> \n>   mkdir settings\n>   cd settings\n>   git init\n>   touch x\n>   git add x\n>   git commit -m \"xx\"\n> \n>   (time passes)\n> \n>   cd ..\n>   git init\n>   git add settings/\n>    (should complain)\n\nIf you do \"git add settings\" (without the slash) it will add the\nrepository as a submodule.  Which is not the behavior you asked for, but\nis at least reasonable. So the real bug seems to me the fact that \"git\nadd settings/\" and \"git add settings\" behave differently.\n\n-Peff\n"},{"id":"165328","messageId":"7vbp0ihnou.fsf@alter.siamese.dyndns.org","threadId":"27002","inReplyTo":"20110407005750.GC28813@sigill.intra.peff.net","subject":"Re: Bug Report: git add","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2011-04-07T01:09:37Z","receivedAt":"2011-04-07T01:09:37Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Jeff King <peff@peff.net> writes:\n\n>>   mkdir settings\n>>   cd settings\n>>   git init\n>>   touch x\n>> ...\n>>   cd ..\n>>   git init\n>>   git add settings/\n>>    (should complain)\n>\n> If you do \"git add settings\" (without the slash) it will add the\n> repository as a submodule.  Which is not the behavior you asked for, but\n> is at least reasonable. So the real bug seems to me the fact that \"git\n> add settings/\" and \"git add settings\" behave differently.\n\nAlso if \"git add settings/x\" does not complain, that would be a bigger\nissue, whose solution would probably be in the same area.\n\nIt may finally be the time to rename has_symlink_leading_path() function\nand enhance its feature.  It happens to check leading symlinks, but its\nreal purpose is to check if the given path is outside the working tree,\nand a path that is in a subdirectory with its own .git repository\ncertainly is outside the working tree.  The callers should be able to say\nwhat check is being asked for by naming the _purpose_ of the test (\"is\nthis path outside the working tree?\"), not the mechanics (\"does the path\nhave a symlink that points outside?\").\n"},{"id":"165329","messageId":"20110407011240.GA4133@sigill.intra.peff.net","threadId":"27002","inReplyTo":"7vbp0ihnou.fsf@alter.siamese.dyndns.org","subject":"Re: Bug Report: git add","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2011-04-07T01:12:40Z","receivedAt":"2011-04-07T01:12:40Z","isPatch":false,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Wed, Apr 06, 2011 at 06:09:37PM -0700, Junio C Hamano wrote:\n\n> Jeff King <peff@peff.net> writes:\n> \n> >>   mkdir settings\n> >>   cd settings\n> >>   git init\n> >>   touch x\n> >> ...\n> >>   cd ..\n> >>   git init\n> >>   git add settings/\n> >>    (should complain)\n> >\n> > If you do \"git add settings\" (without the slash) it will add the\n> > repository as a submodule.  Which is not the behavior you asked for, but\n> > is at least reasonable. So the real bug seems to me the fact that \"git\n> > add settings/\" and \"git add settings\" behave differently.\n> \n> Also if \"git add settings/x\" does not complain, that would be a bigger\n> issue, whose solution would probably be in the same area.\n\nIt does not complain, and probably should. I'm unsure what \"settings/\"\nshould do: produce an error as \"settings/x\" does (or will do,\neventually, we hope), or behave as if \"settings\" was given.\n\nGenerally it is useful to collapse stray slashes for the user, but I\nwonder if there is some use to differentiate between \"settings\" and \"the\ncontents of the settings directory\", as rsync does.\n\n-Peff\n"},{"id":"165336","messageId":"20110407014819.GA12730@sigill.intra.peff.net","threadId":"27002","inReplyTo":"7vbp0ihnou.fsf@alter.siamese.dyndns.org","subject":"Re: Bug Report: git add","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2011-04-07T01:48:19Z","receivedAt":"2011-04-07T01:48:19Z","isPatch":false,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Wed, Apr 06, 2011 at 06:09:37PM -0700, Junio C Hamano wrote:\n\n> > If you do \"git add settings\" (without the slash) it will add the\n> > repository as a submodule.  Which is not the behavior you asked for, but\n> > is at least reasonable. So the real bug seems to me the fact that \"git\n> > add settings/\" and \"git add settings\" behave differently.\n> \n> Also if \"git add settings/x\" does not complain, that would be a bigger\n> issue, whose solution would probably be in the same area.\n> \n> It may finally be the time to rename has_symlink_leading_path() function\n> and enhance its feature.  It happens to check leading symlinks, but its\n> real purpose is to check if the given path is outside the working tree,\n> and a path that is in a subdirectory with its own .git repository\n> certainly is outside the working tree.  The callers should be able to say\n> what check is being asked for by naming the _purpose_ of the test (\"is\n> this path outside the working tree?\"), not the mechanics (\"does the path\n> have a symlink that points outside?\").\n\nSo here's a quick-and-dirty, \"this is the first time I've ever looked at\nthis code\" patch that catches this behavior. It doesn't do any renaming,\nand it does an ugly job of exposing the flag constants.\n\nInterestingly, builtin/add.c also has treat_gitlinks which specifically\nbails on trying to add something in a submodule. But it misses this\ncase, because its test is to check the index for gitlink entries.\n\ndiff --git a/builtin/add.c b/builtin/add.c\nindex 024aae4..5754863 100644\n--- a/builtin/add.c\n+++ b/builtin/add.c\n@@ -202,9 +202,15 @@ static const char **validate_pathspec(int argc, const char **argv, const char *p\n \tif (pathspec) {\n \t\tconst char **p;\n \t\tfor (p = pathspec; *p; p++) {\n-\t\t\tif (has_symlink_leading_path(*p, strlen(*p))) {\n+\t\t\tint r = has_symlink_leading_path(*p, strlen(*p));\n+\t\t\tif (r) {\n \t\t\t\tint len = prefix ? strlen(prefix) : 0;\n-\t\t\t\tdie(_(\"'%s' is beyond a symbolic link\"), *p + len);\n+\t\t\t\tif (r & FL_SYMLINK)\n+\t\t\t\t\tdie(_(\"'%s' is beyond a symbolic link\"), *p + len);\n+\t\t\t\telse if (r & FL_GITREPO)\n+\t\t\t\t\tdie(_(\"'%s' is inside a submodule\"), *p + len);\n+\t\t\t\tdie(\"BUG: '%s' ignored for unknown reason %d\",\n+\t\t\t\t    *p + len, r);\n \t\t\t}\n \t\t}\n \t}\ndiff --git a/cache.h b/cache.h\nindex 21bcc52..2784f67 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -880,6 +880,8 @@ struct cache_def {\n \tint prefix_len_stat_func;\n };\n \n+#define FL_SYMLINK  (1 << 2)\n+#define FL_GITREPO  (1 << 6)\n extern int has_symlink_leading_path(const char *name, int len);\n extern int threaded_has_symlink_leading_path(struct cache_def *, const char *, int);\n extern int check_leading_path(const char *name, int len);\ndiff --git a/symlinks.c b/symlinks.c\nindex 034943b..22152fd 100644\n--- a/symlinks.c\n+++ b/symlinks.c\n@@ -47,7 +47,6 @@ static inline void reset_lstat_cache(struct cache_def *cache)\n \n #define FL_DIR      (1 << 0)\n #define FL_NOENT    (1 << 1)\n-#define FL_SYMLINK  (1 << 2)\n #define FL_LSTATERR (1 << 3)\n #define FL_ERR      (1 << 4)\n #define FL_FULLPATH (1 << 5)\n@@ -92,7 +91,7 @@ static int lstat_cache_matchlen(struct cache_def *cache,\n \t\tmatch_len = last_slash =\n \t\t\tlongest_path_match(name, len, cache->path, cache->len,\n \t\t\t\t\t   &previous_slash);\n-\t\t*ret_flags = cache->flags & track_flags & (FL_NOENT|FL_SYMLINK);\n+\t\t*ret_flags = cache->flags & track_flags & (FL_NOENT|FL_SYMLINK|FL_GITREPO);\n \n \t\tif (!(track_flags & FL_FULLPATH) && match_len == len)\n \t\t\tmatch_len = last_slash = previous_slash;\n@@ -139,8 +138,21 @@ static int lstat_cache_matchlen(struct cache_def *cache,\n \t\t\tif (errno == ENOENT)\n \t\t\t\t*ret_flags |= FL_NOENT;\n \t\t} else if (S_ISDIR(st.st_mode)) {\n-\t\t\tlast_slash_dir = last_slash;\n-\t\t\tcontinue;\n+\t\t\tstruct stat junk;\n+\t\t\tstruct strbuf gitdir = STRBUF_INIT;\n+\t\t\tstrbuf_add(&gitdir, cache->path, match_len);\n+\t\t\tstrbuf_addstr(&gitdir, \"/.git\");\n+\t\t\tif (lstat(gitdir.buf, &junk) < 0) {\n+\t\t\t\tif (errno == ENOENT) {\n+\t\t\t\t\tlast_slash_dir = last_slash;\n+\t\t\t\t\tstrbuf_release(&gitdir);\n+\t\t\t\t\tcontinue;\n+\t\t\t\t}\n+\t\t\t\t*ret_flags = FL_LSTATERR;\n+\t\t\t}\n+\t\t\telse\n+\t\t\t\t*ret_flags = FL_GITREPO;\n+\t\t\tstrbuf_release(&gitdir);\n \t\t} else if (S_ISLNK(st.st_mode)) {\n \t\t\t*ret_flags = FL_SYMLINK;\n \t\t} else {\n@@ -154,7 +166,7 @@ static int lstat_cache_matchlen(struct cache_def *cache,\n \t * path types, FL_NOENT, FL_SYMLINK and FL_DIR, can be cached\n \t * for the moment!\n \t */\n-\tsave_flags = *ret_flags & track_flags & (FL_NOENT|FL_SYMLINK);\n+\tsave_flags = *ret_flags & track_flags & (FL_NOENT|FL_SYMLINK|FL_GITREPO);\n \tif (save_flags && last_slash > 0 && last_slash <= PATH_MAX) {\n \t\tcache->path[last_slash] = '\\0';\n \t\tcache->len = last_slash;\n@@ -197,7 +209,7 @@ static int lstat_cache(struct cache_def *cache, const char *name, int len,\n  */\n int threaded_has_symlink_leading_path(struct cache_def *cache, const char *name, int len)\n {\n-\treturn lstat_cache(cache, name, len, FL_SYMLINK|FL_DIR, USE_ONLY_LSTAT) & FL_SYMLINK;\n+\treturn lstat_cache(cache, name, len, FL_SYMLINK|FL_DIR|FL_GITREPO, USE_ONLY_LSTAT) & (FL_SYMLINK|FL_GITREPO);\n }\n \n /*\n"},{"id":"165342","messageId":"7vlizmfrl1.fsf@alter.siamese.dyndns.org","threadId":"27002","inReplyTo":"20110407014819.GA12730@sigill.intra.peff.net","subject":"Re: Bug Report: git add","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2011-04-07T07:28:26Z","receivedAt":"2011-04-07T07:28:26Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Jeff King <peff@peff.net> writes:\n\n> @@ -139,8 +138,21 @@ static int lstat_cache_matchlen(struct cache_def *cache,\n>  \t\t\tif (errno == ENOENT)\n>  \t\t\t\t*ret_flags |= FL_NOENT;\n>  \t\t} else if (S_ISDIR(st.st_mode)) {\n> -\t\t\tlast_slash_dir = last_slash;\n> -\t\t\tcontinue;\n> +\t\t\tstruct stat junk;\n> +\t\t\tstruct strbuf gitdir = STRBUF_INIT;\n> +\t\t\tstrbuf_add(&gitdir, cache->path, match_len);\n> +\t\t\tstrbuf_addstr(&gitdir, \"/.git\");\n> +\t\t\tif (lstat(gitdir.buf, &junk) < 0) {\n> +\t\t\t\tif (errno == ENOENT) {\n> +\t\t\t\t\tlast_slash_dir = last_slash;\n> +\t\t\t\t\tstrbuf_release(&gitdir);\n> +\t\t\t\t\tcontinue;\n> +\t\t\t\t}\n> +\t\t\t\t*ret_flags = FL_LSTATERR;\n> +\t\t\t}\n> +\t\t\telse\n> +\t\t\t\t*ret_flags = FL_GITREPO;\n\nThis only checks \"does the directory have .git in it?\".\n\nIt probably is sufficient, but setup.c:is_git_directory() may do a more\nappropriate check, I think.  That \".git\" thing could be a regular file\n(i.e. \"gitdir: path\"), so depending on the junk.st_mode, you may have to\ncall read_gitfile_gently() on it before checking with is_git_directory().\n\nAlternatively, resolve_gitlink_ref() might be usable, but because it is\nprimarily meant to deal with a submodule, there is a slight impedance\nmismatch with the test we are trying to do.  In this codepath, all we care\nabout is if the subdirectory is controlled by a separate git repository,\nand it does not matter if that is an untracked directory from the\nsuperproject's point of view, or if it is bound to the superproject as a\nsubmodule.\n\nAlso I suspect resolve_gitlink_ref() may not work for a submodule that\ndoes not have an initial commit but that is a separate issue.\n"},{"id":"165440","messageId":"20110408191554.GA6516@sigill.intra.peff.net","threadId":"27002","inReplyTo":"7vlizmfrl1.fsf@alter.siamese.dyndns.org","subject":"Re: Bug Report: git add","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2011-04-08T19:15:54Z","receivedAt":"2011-04-08T19:15:54Z","isPatch":false,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Thu, Apr 07, 2011 at 12:28:26AM -0700, Junio C Hamano wrote:\n\n> Jeff King <peff@peff.net> writes:\n> \n> > @@ -139,8 +138,21 @@ static int lstat_cache_matchlen(struct cache_def *cache,\n> >  \t\t\tif (errno == ENOENT)\n> >  \t\t\t\t*ret_flags |= FL_NOENT;\n> >  \t\t} else if (S_ISDIR(st.st_mode)) {\n> > -\t\t\tlast_slash_dir = last_slash;\n> > -\t\t\tcontinue;\n> > +\t\t\tstruct stat junk;\n> > +\t\t\tstruct strbuf gitdir = STRBUF_INIT;\n> > +\t\t\tstrbuf_add(&gitdir, cache->path, match_len);\n> > +\t\t\tstrbuf_addstr(&gitdir, \"/.git\");\n> > +\t\t\tif (lstat(gitdir.buf, &junk) < 0) {\n> > +\t\t\t\tif (errno == ENOENT) {\n> > +\t\t\t\t\tlast_slash_dir = last_slash;\n> > +\t\t\t\t\tstrbuf_release(&gitdir);\n> > +\t\t\t\t\tcontinue;\n> > +\t\t\t\t}\n> > +\t\t\t\t*ret_flags = FL_LSTATERR;\n> > +\t\t\t}\n> > +\t\t\telse\n> > +\t\t\t\t*ret_flags = FL_GITREPO;\n> \n> This only checks \"does the directory have .git in it?\".\n\nYeah. I was trying to keep the test as inexpensive as possible, since\nthis is a very frequently called codepath. But really, doing a more\nelaborate test shouldn't matter. The common case will be that the stat\nfails, and we do nothing else.\n\nI do worry about adding an extra lstat for each directory having\nnoticeable overhead. Maybe it doesn't matter because of the stat\ncaching, but I didn't measure.\n\n> It probably is sufficient, but setup.c:is_git_directory() may do a more\n> appropriate check, I think.  That \".git\" thing could be a regular file\n> (i.e. \"gitdir: path\"), so depending on the junk.st_mode, you may have to\n> call read_gitfile_gently() on it before checking with is_git_directory().\n\nI worry a little about the PATH_MAX check and die in is_git_directory. I\nwould hate for a deep hierarchy to start failing because of this extra\ncheck. OTOH, it is only 5 extra characters to append \".git\", so it is\nunlikely that a path was that close to PATH_MAX but not exceeding it.\n\nSimilarly, read_gitfile_gently is anything but gentle. It die()s if we\ncan't open the '.git' file or it is in an invalid format, which would be\na regression here.\n\n-Peff\n"},{"id":"165445","messageId":"20110408194650.GA15804@sigill.intra.peff.net","threadId":"27002","inReplyTo":"20110408191554.GA6516@sigill.intra.peff.net","subject":"Re: Bug Report: git add","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2011-04-08T19:46:51Z","receivedAt":"2011-04-08T19:46:51Z","isPatch":false,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Fri, Apr 08, 2011 at 03:15:54PM -0400, Jeff King wrote:\n\n> > This only checks \"does the directory have .git in it?\".\n> \n> Yeah. I was trying to keep the test as inexpensive as possible, since\n> this is a very frequently called codepath. But really, doing a more\n> elaborate test shouldn't matter. The common case will be that the stat\n> fails, and we do nothing else.\n> \n> I do worry about adding an extra lstat for each directory having\n> noticeable overhead. Maybe it doesn't matter because of the stat\n> caching, but I didn't measure.\n\nI just did some measurements on linux-2.6 (which is a fair bit more\ndirectory-heavy than something like git.git). The difference is\nmeasurable, but not significant.\n\nThe average for \"git add .\" (on a clean, warm-cache repository) over\nmany trials with the extra lstats is about 2-3% slower.  But the error\nmargin between trials is something like 3-4%. IOW, even though the\naverage was worse, the best trial for the new code was still faster than\nthe worst trial for the old.\n\nThis is on Linux, though. It would probably be worse on an OS with a\nslower stat.\n\n-Peff\n"},{"id":"165535","messageId":"m31v1a4keq.fsf@localhost.localdomain","threadId":"27002","inReplyTo":"20110406055200.GA12547@kytes","subject":"Re: Bug Report: git add","fromName":"Jakub Narebski","fromEmail":"jnareb@gmail.com","sentAt":"2011-04-10T07:48:49Z","receivedAt":"2011-04-10T07:48:49Z","isPatch":false,"sender":{"key":"jnareb@gmail.com","avatar":"https://avatars.githubusercontent.com/u/2706?v=4"},"body":"Ramkumar Ramachandra <artagnon@gmail.com> writes:\n> Darren Cook writes:\n\n> > PROBLEM: \"git add\" adds sub-directories without checking to see if there\n> > is already a git repository already there.\n> > \n> > WHY BAD: This causes files to be in two repositories (leading to a mess\n> > if you don't notice for a while...)\n> > \n> > ONE SOLUTION: When adding files from a directory (except root of the\n> > repository, of course) look for a .git subdirectory, and complain if\n> > found. Allow --force to override this.\n> \n> This is a good suggestion.  It already has a way to handle gitlinks\n> (for submodules), so this seems like a very reasonable feature.\n\nI just hope that a suboptimal workflow that I use won't stop working.\n\nCurrently I have TODO file in gitweb/ subdirectory, which is stored in\ngitweb/.git repository.  Still it doesn't prevent me from \"git add\"-ing\ne.g. 'gitweb/gitweb.perl' to git repository itself.\n\n-- \nJakub Narebski\nPoland\nShadeHawk on #git\n"},{"id":"165536","messageId":"20110410082916.GA31330@kytes","threadId":"27002","inReplyTo":"m31v1a4keq.fsf@localhost.localdomain","subject":"Re: Bug Report: git add","fromName":"Ramkumar Ramachandra","fromEmail":"artagnon@gmail.com","sentAt":"2011-04-10T08:29:21Z","receivedAt":"2011-04-10T08:29:21Z","isPatch":false,"sender":{"key":"r@artagnon.com","avatar":"https://avatars.githubusercontent.com/u/37226?v=4"},"body":"Hi Jakub,\n\nJakub Narebski writes:\n> Ramkumar Ramachandra <artagnon@gmail.com> writes:\n> > Darren Cook writes:\n> \n> > > PROBLEM: \"git add\" adds sub-directories without checking to see if there\n> > > is already a git repository already there.\n> > > \n> > > WHY BAD: This causes files to be in two repositories (leading to a mess\n> > > if you don't notice for a while...)\n> > > \n> > > ONE SOLUTION: When adding files from a directory (except root of the\n> > > repository, of course) look for a .git subdirectory, and complain if\n> > > found. Allow --force to override this.\n> > \n> > This is a good suggestion.  It already has a way to handle gitlinks\n> > (for submodules), so this seems like a very reasonable feature.\n> \n> I just hope that a suboptimal workflow that I use won't stop working.\n> \n> Currently I have TODO file in gitweb/ subdirectory, which is stored in\n> gitweb/.git repository.  Still it doesn't prevent me from \"git add\"-ing\n> e.g. 'gitweb/gitweb.perl' to git repository itself.\n\nIt shouldn't.  The idea is merely to make the porcelain show a\nfriendly warning, which can be overriden with a '--force'.\n\n-- Ram\n"},{"id":"165633","messageId":"7v1v18y8oc.fsf@alter.siamese.dyndns.org","threadId":"27002","inReplyTo":"m31v1a4keq.fsf@localhost.localdomain","subject":"Re: Bug Report: git add","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2011-04-11T17:55:31Z","receivedAt":"2011-04-11T17:55:31Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Jakub Narebski <jnareb@gmail.com> writes:\n\n> Currently I have TODO file in gitweb/ subdirectory, which is stored in\n> gitweb/.git repository.  Still it doesn't prevent me from \"git add\"-ing\n> e.g. 'gitweb/gitweb.perl' to git repository itself.\n\nI would have to say that it is somewhat a sensible thing to want to do\nfrom an individual contributor's point of view to keep track of personal\nnotes on a subpart of a project in a separate repository.\n\nIt however directly contradicts with the approach I suggested earlier,\nwhich resulted in Peff's patch\n\n  http://thread.gmane.org/gmane.comp.version-control.git/170937/focus=171040 \n\nand will be broken, I think.\n\nWe could skip the check for a directory D where there already is a path\nD/P (where P has one or more path components, e.g. \"file\", \"subdir/file\")\ntracked and check only if D/.git is a git directory when adding path in D\nif there is no other D/P is tracked (and perhaps require --force), if we\nreally wanted to keep supporting what you are doing.  But I do not think\nit is worth doing, considering the possibility that such a loophole would\nlead to even more confusing behaviour to new users.\n\nIf there is an equally easy way of keeping track of personal notes in a\nsubpart of a larger project like you do, without having an unrelated .git/\ndirectory in a worktree that is controlled by a project and mixing files\nin a single directory in such a way that some belong to the main project\nwhile others belong to the unrelated \"personal notes\" project, I would\nrather see us recommend such an approach, and declare that your use case\nis forbidden, as it would give us a far easier to explain rule: \"files in\none directory can be controlled only by one .git/ directory\".\n\nBesides, if the subpart of the project you are interested in and want to\nhave personal notes about were at the top-level of the project, you\nwouldn't be using the same workflow as you currently do, as you cannot\nobviously have two .git/ at the same level.\n"},{"id":"165637","messageId":"20110411182038.GA17928@sigill.intra.peff.net","threadId":"27002","inReplyTo":"7v1v18y8oc.fsf@alter.siamese.dyndns.org","subject":"Re: Bug Report: git add","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2011-04-11T18:20:38Z","receivedAt":"2011-04-11T18:20:38Z","isPatch":false,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Mon, Apr 11, 2011 at 10:55:31AM -0700, Junio C Hamano wrote:\n\n> Jakub Narebski <jnareb@gmail.com> writes:\n> \n> > Currently I have TODO file in gitweb/ subdirectory, which is stored in\n> > gitweb/.git repository.  Still it doesn't prevent me from \"git add\"-ing\n> > e.g. 'gitweb/gitweb.perl' to git repository itself.\n> \n> I would have to say that it is somewhat a sensible thing to want to do\n> from an individual contributor's point of view to keep track of personal\n> notes on a subpart of a project in a separate repository.\n> \n> It however directly contradicts with the approach I suggested earlier,\n> which resulted in Peff's patch\n> \n>   http://thread.gmane.org/gmane.comp.version-control.git/170937/focus=171040 \n> \n> and will be broken, I think.\n\nInterestingly, I came across a similar situation yesterday. I have a\nproject with asciidoc documentation, and I was looking at making the\nbuilt forms available on a separate ref (similar to how you do the\nhtml/man docs in git). One way I came up was to make a repo in\n\"Documentation/.git\" which ignored all of the \"*.txt\" sources (which\ntracked by the main repo) but track all of the built \"*.html\" files\n(which are ignored by the main repo).\n\nWhich is exactly the kind of setup my patch tries to declare invalid.\nBut then I decided that what I was considering was too gross and\nerror-prone, and maybe it _should_ be banned. :)\n\nIn particular, some flaws I considered are:\n\n  1. it is easy to get meta-files like \".gitignore\" mixed up\n     between the two repositories. And in fact, you have no way in the\n     sub-repository to ignore the files from the parent repository\n     except by using the non-tracked $GIT_DIR/info/exclude file. And\n     without that, you can never use \"git clean\" in the sub-repository.\n\n  2. When you want to add/commit files in the sub-directory to the main\n     repository, you must do so from _outside_ that directory. Otherwise\n     git will find the sub-repository's .git dir and you accidentally\n     add them to the sub-repository.\n\n> If there is an equally easy way of keeping track of personal notes in a\n> subpart of a larger project like you do, without having an unrelated .git/\n> directory in a worktree that is controlled by a project and mixing files\n> in a single directory in such a way that some belong to the main project\n> while others belong to the unrelated \"personal notes\" project, I would\n> rather see us recommend such an approach, and declare that your use case\n> is forbidden, as it would give us a far easier to explain rule: \"files in\n> one directory can be controlled only by one .git/ directory\".\n\nIt works fine if you just put the notes in their own directory, i.e.:\n\n  git init gitweb/local &&\n  $EDITOR gitweb/local/notes\n\nAnd if you have just the single-file case, you can always do:\n\n  ln -s local/notes gitweb/notes &&\n  echo gitweb/notes >.git/info/exclude\n\nto overlay it in the parent tree. You do have to chdir into the sub-repo\nto actually commit, but that is a _good_ thing, because it means you're\nnot accidentally commiting changes to \"gitweb.perl\" to the sub-repo.\n\nI do something similar with my config.mak, which I track in my own Meta\nsub-repo but symlink into place in the main git repository.\n\n-Peff\n"}]}