Skip to contentSkip to conversation

'add -u' doesn't work from untracked subdir

BUG In review SZEDER Gábor 7 participants 35 messages Jun 15, 2016 Documentation

lore
Share & tools
lore
#0 lore raw

Hi,

As the subject says, 'git add -u' does not work from an untracked subdir, because it doesn't add modified files to the index. The following script reproduces the issue:

mkdir repo
cd repo
git init
echo 1 >foo
git add foo
git commit -m first
echo 2 >foo
mkdir untracked_subdir
cd untracked_subdir
git add -u
git diff

It worked in the initial 'git add -u' implementation (dfdac5d, git-add -u: match the index with working tree, 2007-04-20), but 2ed2c222 (git-add -u paths... now works from subdirectory, 2007-08-16) broke it later, and is broken ever since.

Regards,
Gábor

#1 lore raw
Quoted 16 lines · SZEDER Gábor

As the subject says, 'git add -u' does not work from an untracked subdir, because it doesn't add modified files to the index. The following script reproduces the issue:

mkdir repo
cd repo
git init
echo 1 >foo
git add foo
git commit -m first
echo 2 >foo
mkdir untracked_subdir
cd untracked_subdir
git add -u
git diff

Quoted 4 lines

It worked in the initial 'git add -u' implementation (dfdac5d, git-add -u: match the index with working tree, 2007-04-20), but 2ed2c222 (git-add -u paths... now works from subdirectory, 2007-08-16) broke it later, and is broken ever since.

It is not just untracked subdirs. Try:

mkdir repo && cd repo && git init
echo 1 >foo
mkdir subdir
echo 1 >subdir/bar
git add . && git commit -m first
echo 2 >foo
echo 2 >subdir/bar
cd subdir
git add -u
git diff ;# still shows foo/1 in index git diff --cached ;# shows subdir/bar was updated

While I have sometimes found the behavior a bit annoying[1], I always assumed that was the intended behavior.

And indeed, in modern builtin-add.c, we find this:

        if ((addremove || take_worktree_changes) && !argc) {
                static const char *here[2] = { ".", NULL };
                argc = 1;
                argv = here;
        }

which seems pretty explicit.

-Peff

[1] I would prefer "git add -u ." to add only the current directory, and "git add -u" to touch everything. But then, I am one of the people who turn off status.relativepaths, so I think I may be in the minority in always wanting to think of the project as a whole.

#2 lore raw
Quoted 2 lines · Jeff King

[1] I would prefer "git add -u ." to add only the current directory, and "git add -u" to touch everything.

FWIW, I feel the same way. And there is no easy way to do that now. (cd git rev-parse --show-cdup; git add -u) ?

Quoted 3 lines

But then, I am one of the people who
turn off status.relativepaths, so I think I may be in the minority in always wanting to think of the project as a whole.

That mindset is one of git's greatest strengths IMO.

Clemens

#3 lore raw
Quoted 7 lines · Clemens Buchacher
Quoted 2 lines · Jeff King

[1] I would prefer "git add -u ." to add only the current directory, and "git add -u" to touch everything.

FWIW, I feel the same way. And there is no easy way to do that now. (cd git rev-parse --show-cdup; git add -u) ?

I suspect it is too late to change it due to compatibility issues. OTOH, I think the intent of v1.7.0 is to allow a few small breakages like these. You could always write an RFC patch and generate some discussion; I'm not 100% sure that there are enough people that agree with us to change the default.

I guess we could add a "git add --absolute" option, though it is slightly annoying, because I generally do not realize that I needed to use such an option until several minutes after running "git add".

I would be fine with a "be absolute, not relative" config option such as what we have for status (in fact, a global "be absolute, not relative" option to cover all commands might be handy). The only obstacle is that I think "git add" is often used as plumbing in scripts (arguably, they should be using update-index, but "git add ." is just so convenient).

-Peff

#4 lore raw
Quoted 5 lines · Jeff King

I suspect it is too late to change it due to compatibility issues. OTOH, I think the intent of v1.7.0 is to allow a few small breakages like these. You could always write an RFC patch and generate some discussion; I'm not 100% sure that there are enough people that agree with us to change the default.

The intent of 1.7.0 is to fix usability glitches and warts that everybody has long agreed are problematic. People have *just started* discussing about this---it is not remotely close to "everybody has long agreed are problematic" criteria. It is too late for 1.7.0.

I agree that there are parts of git that is very whole tree oriented, and the later "usability" part that are cwd centric. "add -u" and "grep" are examples of the latter.

I personally find "add -u" that defaults to the current directory more natural than always going to the root; same preference for "grep". Besides, "add -u subdir" must add subdir relative to the cwd, without going to the root. Why should "add -u" sans argument behave drastically differently?

Speaking of cwd-ness, I sometimes find ls-tree irritating, but I think this is in "if we had known better we would have designed it differently, but because we didn't, because many scripts already depend on the current behaviour, and because we have an --full-name escape hatch, we are not likely to change it, ever" category.

If "git add -u ../.." (I mean "the grand parent directory", not "an unnamed subdirectory") did not work, it would be unexcusable and we would want to devise an migration path, but otherwise I do not think it is such a big deal. I would say the commands that are used to incrementally build towards the next commit should be friendly to the practice of limiting the scope of the work by chdir, i.e. they should be cwd centric. On the other hand, the commands that are used to review the next commit as a whole, e.g. diff and patch, should be whole-tree oriented.

Oh, "git grep -e foo ../..", however, does not seem to work. That might be something people may want to tackle.

#5 lore raw
Quoted 4 lines · Junio C Hamano

The intent of 1.7.0 is to fix usability glitches and warts that everybody has long agreed are problematic. People have *just started* discussing about this---it is not remotely close to "everybody has long agreed are problematic" criteria. It is too late for 1.7.0.

What about a config option that could change the behavior? True, the time-frame for discussion is much shorter, but we are not proposing to make a change that would affect users who do not agree to it. And I think the point of giving a long time-frame for discussion is to let people decide whether a change that users do not agree to may affect them in a bad way.

The real danger here is that users of the config option may be breaking an interface that is used by scripts. But I feel that 1.7.0 is probably the best time in the forseeable future to do that, as script-writers already must be wary of the version change.

Quoted 5 lines

I personally find "add -u" that defaults to the current directory more natural than always going to the root; same preference for "grep". Besides, "add -u subdir" must add subdir relative to the cwd, without going to the root. Why should "add -u" sans argument behave drastically differently?

I agree that there is a certain consistency to the current behavior. But I also find it terribly annoying, because I _always_ want it to do the other thing, and it silently accepts the command without even telling me, leaving me to find out ten minutes later that what I thought was added was not ("git add", by contrast, yells at you in the same situation).

I also happen to prefer the other behavior because it is easy to switch the two options: "git add -u" versus "git add -u .", whereas with current behavior I am stuck calculating (and typing) the correct number of "../" markers.

But I respect the fact that even if we had infinite time for discussion, there would be people who prefer it the opposite way to me. So how about that config option?

Quoted 5 lines

Speaking of cwd-ness, I sometimes find ls-tree irritating, but I think this is in "if we had known better we would have designed it differently, but because we didn't, because many scripts already depend on the current behaviour, and because we have an --full-name escape hatch, we are not likely to change it, ever" category.

I assume you mean "ls-files". I have every once in a while been annoyed by that, but given how infrequently I run ls-files, it is not a big deal. :)

Quoted 4 lines

If "git add -u ../.." (I mean "the grand parent directory", not "an unnamed subdirectory") did not work, it would be unexcusable and we would want to devise an migration path, but otherwise I do not think it is such a big deal. I would say the commands that are used to incrementally build

As I mentioned above, not only is that annoying to use, but the real problem is that I _expect_ the other behavior and it silently does the opposite of what I want. You can argue that my brain is defective (for not remembering, I mean -- we _know_ it's defective in other ways), but certainly a config option would be useful to me.

Quoted 2 lines

Oh, "git grep -e foo ../..", however, does not seem to work. That might be something people may want to tackle.

Thanks for mentioning "git grep"; I had forgotten that I have been bitten by expecting full-tree behavior from that in the past, too. A config option should cover that, too. ;)

-Peff

#6 lore raw
Quoted 5 lines · Jeff King

As I mentioned above, not only is that annoying to use, but the real problem is that I _expect_ the other behavior and it silently does the opposite of what I want. You can argue that my brain is defective (for not remembering, I mean -- we _know_ it's defective in other ways), but certainly a config option would be useful to me.

Bah. Even after this long thread, I _still_ forgot. I just now typed "git add -u" from t/ and got annoyed that my changes in the root weren't added.

-Peff

#7 lore raw
In reply to Jeff King
Quoted 3 lines · Jeff King

I assume you mean "ls-files". I have every once in a while been annoyed by that, but given how infrequently I run ls-files, it is not a big deal. :)

I did mean ls-tree, but I misspelled the name of the escape hatch.

Try this:

    $ cd Documentation
    $ git ls-tree HEAD

If I were designing this as a proper plumbing command from scratch, I wouldn't have given it a cwd behaviour. ls-files is somewhat more understandable, as it has other cruft relating the work tree, but ls-tree is worse:

    $ cd Documentation
    $ git ls-tree origin/html

Whoa??? Yes, it tried to do what "git ls-tree origin/html:Documentation" would have done if it were unaware of cwd. It's just crazy.

Quoted 10 lines
Quoted 4 lines

If "git add -u ../.." (I mean "the grand parent directory", not "an unnamed subdirectory") did not work, it would be unexcusable and we would want to devise an migration path, but otherwise I do not think it is such a big deal. I would say the commands that are used to incrementally build

As I mentioned above, not only is that annoying to use, but the real problem is that I _expect_ the other behavior and it silently does the opposite of what I want. You can argue that my brain is defective (for not remembering, I mean -- we _know_ it's defective in other ways), but certainly a config option would be useful to me.

At this moment (as my brain is not quite functioning), I can only say we agreed to disagree what feels more natural here.

#8 lore raw
Quoted 7 lines · Junio C Hamano
Quoted 3 lines · Jeff King

I assume you mean "ls-files". I have every once in a while been annoyed by that, but given how infrequently I run ls-files, it is not a big deal. :)

I did mean ls-tree, but I misspelled the name of the escape hatch.

Oh, I never noticed that behavior before. For "ls-files", I think it is at least a little sane, but it makes no sense whatsoever for ls-tree.

Quoted 2 lines

At this moment (as my brain is not quite functioning), I can only say we agreed to disagree what feels more natural here.

I agree that we agreed to disagree. But there is still one open
question: would you take a patch for a "full-tree" config variable that would impact add (and probably grep) for 1.7.0? You can sleep on it if you want. ;)

-Peff

#9 lore raw
Quoted 3 lines · Jeff King

I agree that we agreed to disagree. But there is still one open
question: would you take a patch for a "full-tree" config variable that would impact add (and probably grep) for 1.7.0?

Unless there is a simple and sane way for script writers (and by "script", I do not mean "Porcelain that is supposed to be written using only the plumbing", but things like scripts you would give to "git bisect run", which would freely use Porcelains like "git reset" etc.) to defeat the configuration without much pain, I am fairly negative on adding any configuration variable of that nature.

We could probably declare "In 1.X.0 everything will be relative to the root and you have to give an explicit '.' if you mean the cwd".

Three questions:

#1 What are the commands that will be affected, other than "add -u" and
"grep"? Are there others?

#2 Do all the commands in the answer to #1 currently behave exactly the
same when run without any path parameter and when run with a single '.'?

#3 Do all the commands that are already relative to the root currently
limit their action to the cwd when run with a single '.'?

If the number of commands in the answer to #1 is not too excessive, it is a plus, but even if it is more than just several, we will be getting consistency and sanity if #2 and #3 hold. However, if there are even a single violator in #2 and #3, we would need to fix them first before we can proceed. And the transition clock starts ticking after everything is fixed (if such a fix is indeed needed). As usual, I'd prefer to keep the clock running for at least 6 months, preferrably longer, and during that time, we may need the usual "You invoked me without any paths, but this command will start behaving differently in 1.X.0, you have been warned."

A command line option to explicitly ask full-tree can be added anytime without waiting for 1.7.0. I do not think it will be ready for 1.6.5 but we can always have 1.6.6 if needed.

#10 lore raw
Quoted 2 lines · Junio C Hamano

#1 What are the commands that will be affected, other than "add -u" and
"grep"? Are there others?

There are "ls-tree", "ls-files" and "clean". I can't find anything else.

Quoted 3 lines

#2 Do all the commands in the answer to #1 currently behave exactly the
same when run without any path parameter and when run with a single '.'?

Yes. But "ls-tree" and "ls-files" do not accept superdirectories in their path specs.

Quoted 2 lines

#3 Do all the commands that are already relative to the root currently
limit their action to the cwd when run with a single '.'?

I can't think of one that doesn't.

Clemens

#11 lore raw
In reply to Junio C Hamano

Quoting Junio C Hamano <[email protected]>

Quoted 11 lines

We could probably declare "In 1.X.0 everything will be relative to the root and you have to give an explicit '.' if you mean the cwd".

Three questions:

#1 What are the commands that will be affected, other than "add -u" and
"grep"? Are there others?

#2 Do all the commands in the answer to #1 currently behave exactly the
same when run without any path parameter and when run with a single '.'?

'git-archive' behaves relative to your current directory.

http://thread.gmane.org/gmane.comp.version-control.git/41300/focus=44125

You can limit it to the current directory with a dot.

Signature · 2 lines
Nanako Shiraishi
http://ivory.ap.teacup.com/nanako3/
#12 lore raw
Quoted 14 lines · Nanako Shiraishi

Quoting Junio C Hamano <[email protected]>

Quoted 11 lines

We could probably declare "In 1.X.0 everything will be relative to the root and you have to give an explicit '.' if you mean the cwd".

Three questions:

#1 What are the commands that will be affected, other than "add -u" and
"grep"? Are there others?

#2 Do all the commands in the answer to #1 currently behave exactly the
same when run without any path parameter and when run with a single '.'?

Quoted 5 lines

'git-archive' behaves relative to your current directory.

http://thread.gmane.org/gmane.comp.version-control.git/41300/focus=44125

You can limit it to the current directory with a dot.

Thanks.

If you want to make a tarball of the Documentation directory from your work tree, you do this:

    $ cd Documentation
    $ tar cf - . >/tmp/docs.tar

If you want to do the same but from your committed content, you do this:

    $ cd Documentation
    $ git archive HEAD >/tmp/docs.tar

and you do not have to say:

    $ cd Documentation
    $ git archive HEAD . >/tmp/docs.tar

So in that sense it does make sense to archive the current directory. It matches what the users expect from their archivers.

The traditional archivers may not default to "." but we do. That is about giving a sensible default [*1*]. Perhaps defaulting to the cwd behaviour for one command may seem a sensible thing when looking at that particular command alone; archive and grep fall into that category.

But as this "add -u" discussion showed us [*2*], people may expect different "sensible default", and as a suite of commands as the whole, it becomes messy. People have to remember which ones obey cwd, and to some people the choice is not intuitive.

To avoid confusion, I am beginning to agree with people who said in the thread that it is a good idea to consistently default to the root of the contents. When we use "everything" as the default due to lack of command line pathspec, we would use "everything from root" no matter where you are, regardless of what command we are talking about. That would make the rule easier to remember [*3*].

This changes the way how "git (add -u|grep|clean|archive)" without pathspec and "git (add -u|grep|clean|archive) ." with an explicit dot work. The former (adds all changed files in, finds hits in, removes untracked paths in, creates a tarball for) the whole tree, while the latter limits the operation explicitly to the current directory.

If this were going to happen as a list concensus, I am very tempted to suggest that we at least _consider_ applying the same rule even to ls-files and ls-tree. That would impact scripts, so we need to be extra careful, though.

Also this takes us to a tangent.

If we try to give a sensible default to make it easier for the user, perhaps we should also default to HEAD when the user did not specify which tree-ish to archive from. This is a topic in a separate thread.

[Footnote]

*1* Actually we don't allow "git archive HEAD ..", which I think is a bug. Also we do not have --full-tree workaround, which makes it slightly cumbersome to use.

*2* And the thread you quoted shows us that the argument applies equally to "git archive" as well; you see me complaining that it is unintuitive for me to care about "archive", and the counterargument was that ls-tree does so. I however think it is more important for archive to behave in a way that is easier for the users to understand, than mimick the historical mistake in a plumbing command.

*3* Command line pathspec of course should honor cwd as before. When you say "git distim Makefile" inside t/ directory, we distim t/Makefile, not the toplevel Makefile. This discussion is only about the case where the user didn't give us any pathspec.

#13 lore raw
Quoted 4 lines · Junio C Hamano

If this were going to happen as a list concensus, I am very tempted to suggest that we at least _consider_ applying the same rule even to ls-files and ls-tree. That would impact scripts, so we need to be extra careful, though.

I originally thought those commands should be consistent with plain "ls", simply because of their name. However, ls-files is already inconsistent because "ls-files <subdir>" lists files relative to the current directory, as opposed to "ls <subdir>", which does so relative to <subdir>. And ls-tree is even more different from "ls".

So I don't think users are tempted to associate those commands with the behavior they are used from "ls". From that perspective it would therefore be ok to traverse the entire tree by default. To me that seems perfectly natural, especially for ls-tree.

In case of ls-files, I don't know. Its current behavior certainly did not bother me so far. But the same arguments as for "add -u" apply if you think of doing something like "git ls-files -u | cut -f2 | xargs git add", for example.

I can't really speak for the impact on scripts. But that is certainly an issue, more so than with "add -u" or "grep", which are more typically used interactively.

Quoted 3 lines

If we try to give a sensible default to make it easier for the user, perhaps we should also default to HEAD when the user did not specify which tree-ish to archive from. This is a topic in a separate thread.

I don't see why not.

Quoted 1 line

*3* Command line pathspec of course should honor cwd as before.

No argument there.

Clemens

#14 lore raw

PATCH 1/2 grep: accept relative paths outside current working directory

In reply to Junio C Hamano
Quoted 2 lines · Junio C Hamano
Quoted 2 lines
Quoted 2 lines

If "git add -u ../.." (I mean "the grand parent directory", not "an unnamed subdirectory") did not work

I just noticed that this doesn't work with grep. In git.git:

$ cd t
$ git grep addremove -- ../
fatal: git grep: cannot generate relative filenames containing '..'

So here's a fix for that. And a configurable solution for add and grep's scope as a follow-up. I did not look at any other commands yet.

Clemens

--o<--
Previously, "git grep" would bark at relative paths pointing outside the current working directory (or subdirectories thereof). We already have quote_path_relative(), which can handle such cases just fine. So use that instead.

---
 builtin-grep.c |   44 ++++++++++++++------------------------------
 grep.h         |    1 +
 2 files changed, 15 insertions(+), 30 deletions(-)
builtin-grep.c +14 -30
index ad0e0a5..f6af3d4 100644
@@ -13,6 +13,7 @@
 #include "parse-options.h"
 #include "userdiff.h"
 #include "grep.h"
+#include "quote.h"
 
 #ifndef NO_EXTERNAL_GREP
 #ifdef __unix__
@@ -152,40 +153,27 @@ static int pathspec_matches(const char **paths, const char *name, int max_depth)
 	return 0;
 }
 
-static int grep_sha1(struct grep_opt *opt, const unsigned char *sha1, const char *name, int tree_name_len)
+static int grep_sha1(struct grep_opt *opt, const unsigned char *sha1, const char *path, int tree_name_len)
 {
 	unsigned long size;
 	char *data;
 	enum object_type type;
-	char *to_free = NULL;
 	int hit;
+	struct strbuf pathbuf = STRBUF_INIT;
 
 	data = read_sha1_file(sha1, &type, &size);
 	if (!data) {
-		error("'%s': unable to read %s", name, sha1_to_hex(sha1));
+		error("'%s': unable to read %s", path, sha1_to_hex(sha1));
 		return 0;
 	}
 	if (opt->relative && opt->prefix_length) {
-		static char name_buf[PATH_MAX];
-		char *cp;
-		int name_len = strlen(name) - opt->prefix_length + 1;
-
-		if (!tree_name_len)
-			name += opt->prefix_length;
-		else {
-			if (ARRAY_SIZE(name_buf) <= name_len)
-				cp = to_free = xmalloc(name_len);
-			else
-				cp = name_buf;
-			memcpy(cp, name, tree_name_len);
-			strcpy(cp + tree_name_len,
-			       name + tree_name_len + opt->prefix_length);
-			name = cp;
-		}
+		quote_path_relative(path + tree_name_len, -1, &pathbuf, opt->prefix);
+		strbuf_insert(&pathbuf, 0, path, tree_name_len);
+		path = pathbuf.buf;
 	}
-	hit = grep_buffer(opt, name, data, size);
+	hit = grep_buffer(opt, path, data, size);
+	strbuf_release(&pathbuf);
 	free(data);
-	free(to_free);
 	return hit;
 }
 
@@ -195,6 +183,7 @@ static int grep_file(struct grep_opt *opt, const char *filename)
 	int i;
 	char *data;
 	size_t sz;
+	struct strbuf buf = STRBUF_INIT;
 
 	if (lstat(filename, &st) < 0) {
 	err_ret:
@@ -219,8 +208,9 @@ static int grep_file(struct grep_opt *opt, const char *filename)
 	}
 	close(i);
 	if (opt->relative && opt->prefix_length)
-		filename += opt->prefix_length;
+		filename = quote_path_relative(filename, -1, &buf, opt->prefix);
 	i = grep_buffer(opt, filename, data, sz);
+	strbuf_release(&buf);
 	free(data);
 	return i;
 }
@@ -798,6 +788,7 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
 	};
 
 	memset(&opt, 0, sizeof(opt));
+	opt.prefix = prefix;
 	opt.prefix_length = (prefix && *prefix) ? strlen(prefix) : 0;
 	opt.relative = 1;
 	opt.pathname = 1;
@@ -868,15 +859,8 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
 			verify_filename(prefix, argv[j]);
 	}
 
-	if (i < argc) {
+	if (i < argc)
 		paths = get_pathspec(prefix, argv + i);
-		if (opt.prefix_length && opt.relative) {
-			/* Make sure we do not get outside of paths */
-			for (i = 0; paths[i]; i++)
-				if (strncmp(prefix, paths[i], opt.prefix_length))
-					die("git grep: cannot generate relative filenames containing '..'");
-		}
-	}
 	else if (prefix) {
 		paths = xcalloc(2, sizeof(const char *));
 		paths[0] = prefix;
grep.h +1 -0
index 28e6b2a..f6eecc6 100644
@@ -59,6 +59,7 @@ struct grep_opt {
 	struct grep_pat *pattern_list;
 	struct grep_pat **pattern_tail;
 	struct grep_expr *pattern_expression;
+	const char *prefix;
 	int prefix_length;
 	regex_t regexp;
 	int linenum;
Signature · 1 line
1.6.4.2.264.g79b4f
#15 lore raw

PATCH 2/2 add 'scope' config option

Documentation/config.txt says it all.

---
 Documentation/config.txt |    6 ++++++
 builtin-add.c            |    2 +-
 builtin-grep.c           |    2 +-
 cache.h                  |    1 +
 config.c                 |    8 ++++++++
 environment.c            |    1 +
 6 files changed, 18 insertions(+), 2 deletions(-)
Documentation/config.txt +6 -0
index 5256c7f..f587cf1 100644
@@ -439,6 +439,12 @@ On some file system/operating system combinations, this is unreliable.
 Set this config setting to 'rename' there; However, This will remove the
 check that makes sure that existing object files will not get overwritten.
 
+core.scope::
+	By default, the commands 'git add -u', 'git add -A' and 'git grep'
+	are limited to files below the current working directory
+	(scope='workdir'). Set this variable to scope='global' to make these
+	commands act on the whole tree instead.
+
 add.ignore-errors::
 	Tells 'git-add' to continue adding files when some files cannot be
 	added due to indexing errors. Equivalent to the '--ignore-errors'
builtin-add.c +1 -1
index 006fd08..33ea3e4 100644
@@ -285,7 +285,7 @@ int cmd_add(int argc, const char **argv, const char *prefix)
 
 	if (addremove && take_worktree_changes)
 		die("-A and -u are mutually incompatible");
-	if ((addremove || take_worktree_changes) && !argc) {
+	if (!scope_global && (addremove || take_worktree_changes) && !argc) {
 		static const char *here[2] = { ".", NULL };
 		argc = 1;
 		argv = here;
builtin-grep.c +1 -1
index f6af3d4..447b195 100644
@@ -861,7 +861,7 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
 
 	if (i < argc)
 		paths = get_pathspec(prefix, argv + i);
-	else if (prefix) {
+	else if (!scope_global && prefix) {
 		paths = xcalloc(2, sizeof(const char *));
 		paths[0] = prefix;
 		paths[1] = NULL;
cache.h +1 -0
index 5fad24c..85c5fee 100644
@@ -523,6 +523,7 @@ extern int auto_crlf;
 extern int read_replace_refs;
 extern int fsync_object_files;
 extern int core_preload_index;
+extern int scope_global;
 
 enum safe_crlf {
 	SAFE_CRLF_FALSE = 0,
config.c +8 -0
index e87edea..8dec019 100644
@@ -503,6 +503,14 @@ static int git_default_core_config(const char *var, const char *value)
 		return 0;
 	}
 
+	if (!strcmp(var, "core.scope")) {
+		if (!strcasecmp(value, "global"))
+			scope_global = 1;
+		if (!strcasecmp(value, "worktree"))
+			scope_global = 0;
+		return 0;
+	}
+
 	/* Add other config variables here and to Documentation/config.txt. */
 	return 0;
 }
environment.c +1 -0
index 5de6837..4d1c6e1 100644
@@ -50,6 +50,7 @@ enum push_default_type push_default = PUSH_DEFAULT_MATCHING;
 #endif
 enum object_creation_mode object_creation_mode = OBJECT_CREATION_MODE;
 int grafts_replace_parents = 1;
+int scope_global = 0;
 
 /* Parallel index stat data preload? */
 int core_preload_index = 0;
Signature · 1 line
1.6.4.2.264.g79b4f
#16 lore raw

PATCH v2 2/2 add 'scope' config option

Review

Quoted 5 lines · Clemens Buchacher
(quoted diff) +1 -1
-	if ((addremove || take_worktree_changes) && !argc) {
+	if (!scope_global && (addremove || take_worktree_changes) && !argc) {
 		static const char *here[2] = { ".", NULL };
 		argc = 1;
 		argv = here;

Ok, scrape that. Seems validate_pathspec does that implicitly already. So this code was redundant. The attached patch should now work (I tested it this time...).

It also seems that "git add -A" doesn't work without a pathspec any more? Was that intentional?

Clemens

--o<--

---
 Documentation/config.txt |    6 ++++++
 builtin-add.c            |   12 +++++-------
 builtin-grep.c           |    2 +-
 cache.h                  |    1 +
 config.c                 |    8 ++++++++
 environment.c            |    1 +
 6 files changed, 22 insertions(+), 8 deletions(-)
Documentation/config.txt +6 -0
index 5256c7f..f587cf1 100644
@@ -439,6 +439,12 @@ On some file system/operating system combinations, this is unreliable.
 Set this config setting to 'rename' there; However, This will remove the
 check that makes sure that existing object files will not get overwritten.
 
+core.scope::
+	By default, the commands 'git add -u', 'git add -A' and 'git grep'
+	are limited to files below the current working directory
+	(scope='workdir'). Set this variable to scope='global' to make these
+	commands act on the whole tree instead.
+
 add.ignore-errors::
 	Tells 'git-add' to continue adding files when some files cannot be
 	added due to indexing errors. Equivalent to the '--ignore-errors'
builtin-add.c +5 -7
index 006fd08..737b155 100644
@@ -285,14 +285,9 @@ int cmd_add(int argc, const char **argv, const char *prefix)
 
 	if (addremove && take_worktree_changes)
 		die("-A and -u are mutually incompatible");
-	if ((addremove || take_worktree_changes) && !argc) {
-		static const char *here[2] = { ".", NULL };
-		argc = 1;
-		argv = here;
-	}
 
 	add_new_files = !take_worktree_changes && !refresh_only;
-	require_pathspec = !take_worktree_changes;
+	require_pathspec = !addremove && !take_worktree_changes;
 
 	newfd = hold_locked_index(&lock_file, 1);
 
@@ -308,7 +303,10 @@ int cmd_add(int argc, const char **argv, const char *prefix)
 		fprintf(stderr, "Maybe you wanted to say 'git add .'?\n");
 		return 0;
 	}
-	pathspec = validate_pathspec(argc, argv, prefix);
+	if (scope_global && !argc)
+		pathspec = NULL;
+	else
+		pathspec = validate_pathspec(argc, argv, prefix);
 
 	if (read_cache() < 0)
 		die("index file corrupt");
builtin-grep.c +1 -1
index f6af3d4..447b195 100644
@@ -861,7 +861,7 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
 
 	if (i < argc)
 		paths = get_pathspec(prefix, argv + i);
-	else if (prefix) {
+	else if (!scope_global && prefix) {
 		paths = xcalloc(2, sizeof(const char *));
 		paths[0] = prefix;
 		paths[1] = NULL;
cache.h +1 -0
index 5fad24c..85c5fee 100644
@@ -523,6 +523,7 @@ extern int auto_crlf;
 extern int read_replace_refs;
 extern int fsync_object_files;
 extern int core_preload_index;
+extern int scope_global;
 
 enum safe_crlf {
 	SAFE_CRLF_FALSE = 0,
config.c +8 -0
index e87edea..8dec019 100644
@@ -503,6 +503,14 @@ static int git_default_core_config(const char *var, const char *value)
 		return 0;
 	}
 
+	if (!strcmp(var, "core.scope")) {
+		if (!strcasecmp(value, "global"))
+			scope_global = 1;
+		if (!strcasecmp(value, "worktree"))
+			scope_global = 0;
+		return 0;
+	}
+
 	/* Add other config variables here and to Documentation/config.txt. */
 	return 0;
 }
environment.c +1 -0
index 5de6837..4d1c6e1 100644
@@ -50,6 +50,7 @@ enum push_default_type push_default = PUSH_DEFAULT_MATCHING;
 #endif
 enum object_creation_mode object_creation_mode = OBJECT_CREATION_MODE;
 int grafts_replace_parents = 1;
+int scope_global = 0;
 
 /* Parallel index stat data preload? */
 int core_preload_index = 0;
Signature · 1 line
1.6.4.2.266.gbaa17
#17 lore raw

Re: [PATCH 1/2] grep: accept relative paths outside current working directory

In reply to Clemens Buchacher
Quoted 4 lines · Clemens Buchacher
Quoted 2 lines · Junio C Hamano
Quoted 2 lines
Quoted 2 lines

If "git add -u ../.." (I mean "the grand parent directory", not "an unnamed subdirectory") did not work

Quoted 8 lines

In git.git:

$ cd t
$ git grep addremove -- ../
fatal: git grep: cannot generate relative filenames containing '..'

So here's a fix for that. And a configurable solution for add and grep's scope as a follow-up. I did not look at any other commands yet.

Thanks. This was oa breakage I pointed out in an earlier message in this discussion, and it is worth fixing.

Your patch is queued in 'pu', but it seems to break the exit status in a strange way with my limited test.

Here is a non-broken behaviour without the "look in uplevel":

: git.git/cb/maint-1.6.3-grep-relative-up; ./git grep adddelete .
: git.git/cb/maint-1.6.3-grep-relative-up; ./git grep adddelete .; echo $? 1
: git.git/cb/maint-1.6.3-grep-relative-up; ./git grep adddelete . >/dev/null; echo $? 1

Now we go down, and grep from an uplevel:

: git.git/cb/maint-1.6.3-grep-relative-up; cd t
: t/cb/maint-1.6.3-grep-relative-up; ../git grep adddelete ..
: t/cb/maint-1.6.3-grep-relative-up; ../git grep adddelete .. ; echo $? 1
: t/cb/maint-1.6.3-grep-relative-up; ../git grep adddelete .. >/dev/null; echo $? 0

The command should not give different exit status depending on the destination of standard output stream.

#18 lore raw

PATCH 1/1 grep: fix exit status if external_grep() returns error

Quoted 2 lines · Junio C Hamano

Your patch is queued in 'pu', but it seems to break the exit status in a strange way with my limited test.

[...]

Quoted 2 lines

The command should not give different exit status depending on the destination of standard output stream.

I could also reproduce this in master using

	:~/git/t$ git grep --no-color not-going-to-match .; echo $?

The problem is a small bug in grep_cache(), which is triggered here because external_grep() cannot deal with relative paths (not sure why that's the case though). Fix below.

Clemens
--o<--

If external_grep() is called and returns an error, grep_cache() mistakenly reported a hit, even if there were none. The bug can be triggered by calling "git grep --no-color" from a subdirectory.

---
 builtin-grep.c |    6 +++---
 1 files changed, 3 insertions(+), 3 deletions(-)
builtin-grep.c +3 -3
index ad0e0a5..b577738 100644
@@ -500,9 +500,9 @@ static int grep_cache(struct grep_opt *opt, const char **paths, int cached,
 	 * be a lot more optimized
 	 */
 	if (!cached && external_grep_allowed) {
-		hit = external_grep(opt, paths, cached);
-		if (hit >= 0)
-			return hit;
+		int ret = external_grep(opt, paths, cached);
+		if (ret >= 0)
+			return ret;
 	}
 #endif
 
Signature · 1 line
1.6.4.2.266.gbaa17
#19 lore raw

Re: [PATCH] grep: fix exit status if external_grep() returns error

Quoted 5 lines · Clemens Buchacher
builtin-grep.c +0 -0
index ad0e0a5..b577738 100644

builtin-grep.c static int grep_cache(struct grep_opt *opt, const char **paths, int cached, · line 505

Quoted 9 lines
builtin-grep.c +3 -3
@@ -500,9 +500,9 @@ static int grep_cache(struct grep_opt *opt, const char **paths, int cached,
 	 * be a lot more optimized
 	 */
 	if (!cached && external_grep_allowed) {
-		hit = external_grep(opt, paths, cached);
-		if (hit >= 0)
-			return hit;
+		int ret = external_grep(opt, paths, cached);
+		if (ret >= 0)
+			return ret;

Well caught, and this deserves to go to maint.

An alternative would be to reset hit to zero if we decide to use the internal one after this conditional.

Thanks.

#20 lore raw
In reply to Junio C Hamano
Quoted 5 lines · Junio C Hamano

I personally find "add -u" that defaults to the current directory more natural than always going to the root; same preference for "grep". Besides, "add -u subdir" must add subdir relative to the cwd, without going to the root. Why should "add -u" sans argument behave drastically differently?

Sorry for stating the obvious here, but the following commands affect the entire repository, even though they limit themselves to the current directory, if passed a '.'.

git commit
git log
git diff
git checkout
git reset

Due to the frequent use of these commands, I believe many users (myself included) expect "git add" and "git grep" to do the same. AFAICT the following commands are the only non-plumbing ones that behave differently:

git add -u
git add -A
git grep

So I argue that _that_ is the real inconsistency.

Quoted 8 lines

If "git add -u ../.." (I mean "the grand parent directory", not "an unnamed subdirectory") did not work, it would be unexcusable and we would want to devise an migration path, but otherwise I do not think it is such a big deal.

I would say the commands that are used to incrementally build towards the next commit should be friendly to the practice of limiting the scope of the work by chdir.

"git add -u ." is friendly enough. Just like "git commit ." versus "git commit -a", which is exactly the same concept and should therefore have the same behavior.

You are assuming that people are in a subdirectory because they want to limit the scope. But I am usually in a subdirectory for totally versioning-unrelated reasons. Like running tests in git.git:t/ . I mistakenly use "git add -u" in there all the time, because I think I don't have to worry about which directory I'm in. Except in this instance I do.

In any case, I think it is better to have consistent behavior than to try and read users' minds with defaults.

Clemens

#21 lore raw
Quoted 7 lines · Clemens Buchacher

"git add -u ." is friendly enough. Just like "git commit ." versus "git commit -a", which is exactly the same concept and should therefore have the same behavior.

You are assuming that people are in a subdirectory because they want to limit the scope. But I am usually in a subdirectory for totally versioning-unrelated reasons.

Limit the scope of what you see in "ls" (no argument) output, shorten the paths you must type to non-git commands. They are the kind of "limit the scope" I meant, and they are totally versioning-unrelated. In other words, cwd-centric default helps the users (especially the new ones) by making git behave consistently with other commands.

So if anything, I personally think it would be much less surprising if all git commands worked relative to the cwd (not whole tree root) when run without path argument, at least from the newbie's point of view [*1*].

But notice that the above is qualified with "personally". An alternative would be to declare that in 1.8.0, all commands run without path argument will work on the whole tree and you have to give an explicit '.' when you want to limit their effect to the cwd.

This may be slightly less intuitive to newbies than the "relative to cwd", but nevertheless that is the course I would suggest us taking, because of the following observations:

(1) if the commands work on the whole tree when run without paths, it is easy to limit to the cwd with "git frotz ." when you want to.

(2) if the commands work on the cwd when run without paths, you have to always be aware how deep you are, and say "git frotz ../../.." when you want to extend their effects to the whole tree.

The latter is much more irritating.

Please also see:

    Message-ID: <[email protected]> ($gmane/127795)

think about the three questions there, and help us move the discussion forward.

The first part of the message has some comments related to your patch, by the way.

[Footnote]

*1* Except for the ones that cannot make any sense to limit their operation to a subdirectory you happen to be in (e.g. it would be insane if "git am" run to accept somebody's patch ignored paths outside your cwd).

#22 lore raw
Quoted 10 lines · Junio C Hamano
Quoted 7 lines · Clemens Buchacher

"git add -u ." is friendly enough. Just like "git commit ." versus "git commit -a", which is exactly the same concept and should therefore have the same behavior.

You are assuming that people are in a subdirectory because they want to limit the scope. But I am usually in a subdirectory for totally versioning-unrelated reasons.

Quoted 5 lines

Limit the scope of what you see in "ls" (no argument) output, shorten the paths you must type to non-git commands. They are the kind of "limit the scope" I meant, and they are totally versioning-unrelated. In other words, cwd-centric default helps the users (especially the new ones) by making git behave consistently with other commands.

Well, there is still complication that some commands are considered whole-tree in absence of pathspec, like "git commit".

Quoted 4 lines

So if anything, I personally think it would be much less surprising if all git commands worked relative to the cwd (not whole tree root) when run without path argument, at least from the newbie's point of view [*1*].

I think it would be very suprising if "git commit" in subdirectory was limited to changes affecting given subdirectory...

Quoted 10 lines

But notice that the above is qualified with "personally". An alternative would be to declare that in 1.8.0, all commands run without path argument will work on the whole tree and you have to give an explicit '.' when you want to limit their effect to the cwd.

This may be slightly less intuitive to newbies than the "relative to cwd", but nevertheless that is the course I would suggest us taking, because of the following observations:

Quoted 8 lines

(1) if the commands work on the whole tree when run without paths, it is easy to limit to the cwd with "git frotz ." when you want to.

(2) if the commands work on the cwd when run without paths, you have to always be aware how deep you are, and say "git frotz ../../.." when you want to extend their effects to the whole tree.

The latter is much more irritating.

Well, we can always invent some magic notation meaning either "up to top directory", e.g. make

  $ git frotz ...

more or less equivalent to

  $ git frotz "$(git rev-parse --show-cdup)"

(The other solution of having "git frotz /" to refer to top directory is slightly worse, because there are git commands that work without git repository, and "/" is legitimate parameter, like e.g. for "git diff --no-index").

Signature · 3 lines
Jakub Narebski
Poland
ShadeHawk on #git
#23 lore raw
In reply to Junio C Hamano
Quoted 4 lines · Junio C Hamano

But notice that the above is qualified with "personally". An alternative would be to declare that in 1.8.0, all commands run without path argument will work on the whole tree and you have to give an explicit '.' when you want to limit their effect to the cwd.

That's fine by me.

[...]

Quoted 7 lines

Please also see:

    Message-ID: <[email protected]> ($gmane/127795)

think about the three questions there, and help us move the discussion forward.

The patch is my way of saying that I'm not just whining, but that I'm willing to put some effort into getting this done. I am aware of the issues you raised in the above message and I was hoping that my patch would help us as a starting point to move the discussion forward.

Quoted 2 lines

The first part of the message has some comments related to your patch, by the way.

I can only guess that you mean the "sane way for script writers to defeat the configuration without much pain" part. But I'm not sure how that's a problem. If you want the script to continue to work as before you either configure "workdir scope", or you add a '.' to the affected commands.

Clemens

#24 lore raw

Re: 'add -u' without path is relative to cwd

Quoted 4 lines · Clemens Buchacher

I can only guess that you mean the "sane way for script writers to defeat the configuration without much pain" part. But I'm not sure how that's a problem. If you want the script to continue to work as before you either configure "workdir scope", or you add a '.' to the affected commands.

One who writes the script and lends it to you may be using different scope from what the recipient uses, so that is not an escape hatch at all.

One crudest form of workaround may be for your code to notice an environment variable to override that scope configuration setting, so that you can advise the script writers to set it in their script. But that is so ugly I'd rather not go there if we do not absolutely have to.

That is why in general we should be very careful and avoid any magic that makes the same command behave completely differently depending on how a repository is configured.

#25 lore raw
In reply to Clemens Buchacher

Quoting Clemens Buchacher <[email protected]>

Quoted 14 lines

Sorry for stating the obvious here, but the following commands affect the entire repository, even though they limit themselves to the current directory, if passed a '.'.

git commit
git log
git diff
git checkout
git reset

Due to the frequent use of these commands, I believe many users (myself included) expect "git add" and "git grep" to do the same. AFAICT the following commands are the only non-plumbing ones that behave differently:

Quoted 5 lines

git add -u
git add -A
git grep

So I argue that _that_ is the real inconsistency.

The default behavior for 'git-grep' has already been discussed in length, and I don't think it is likely to change. See

http://thread.gmane.org/gmane.comp.version-control.git/111519/focus=111717

The original design for the other two in your list was to be a whole tree operation. This commit broke it.

2ed2c22 "git-add -u paths... now works from subdirectory".

'git-add -u' in a subdirectory without any other argument used to work on the entire working tree before that commit, but it didn't prefix the current directory in front of the paths... arguments.

That commit 2ed2c22 fixed 'git-add -u paths...' by prepending the prefix to the arguments, but it broke 'git-add -u' to always limit the updates to the current directory.

I think it is a good idea to fix this as an old regression in the maint branch. You don't have to introduce "git add -a". In fact the -a option was explicitly rejected when "git add -A" option was added with this commit.

  3ba1f11 "git-add --all: add all files"

because "git commit -a" will never include new files and it will be inconsistent if "git add -a" did so.

Signature · 2 lines
Nanako Shiraishi
http://ivory.ap.teacup.com/nanako3/
#26 lore raw
Quoted 4 lines · Nanako Shiraishi

The default behavior for 'git-grep' has already been discussed in length, and I don't think it is likely to change. See

http://thread.gmane.org/gmane.comp.version-control.git/111519/focus=111717

Actually, most responded with the request for a command or config option, and did not refuse the idea outright. One was not even aware that this is how "git grep" behaves. And neither was I until a few days ago.

And that is kind of dangerous with this command. You expect it to behave analogously to other git commands, but it doesn't. And because grep simply does not search superdirectories, you may think that there are in fact no matches so you don't even notice that behavior!

Quoted 8 lines

I think it is a good idea to fix this as an old regression in the maint branch. You don't have to introduce "git add -a". In fact the -a option was explicitly rejected when "git add -A" option was added with this commit.

  3ba1f11 "git-add --all: add all files"

because "git commit -a" will never include new files and it will be inconsistent if "git add -a" did so.

I certainly don't mind fixing "git add -u". But I was not suggesting "git add -a" instead of "git add -A". The idea was to introduce it instead of "git add -u" (which can be deprecated later), so that the following are exactly the same.

"git add -a; git commit"
"git commit -a"

That way, scripts are not silently broken.

OTOH, "git add --all" is already inconsistent with "git commit --all". And we would still need a new command for 'global' "add -A". *sigh*

Clemens

#27 lore raw
In reply to Nanako Shiraishi

Nanako Shiraishi <[email protected]> writes:

[jc: sometimes but not always your messages have looooooooooooooong lines. please line-wrap for readability. I learned to type W Q so often I do not complain but other people would find them irritating.]

Quoted 4 lines

The default behavior for 'git-grep' has already been discussed in length, and I don't think it is likely to change. See

http://thread.gmane.org/gmane.comp.version-control.git/111519/focus=111717

Interesting.

The first message in that thread lists things we have scheduled for 1.7.0 but it has another item. It is an off-topic for the thread, but we might want to resurrect the "core.quotepath defaults to false" proposal, before it gets too late for 1.7.0.

As to "grep", I am open to the proposal to make git commands consistent by letting them operate on everything when no path argument is given, if grep is really the single odd-man out remaining after changing the "add -u" and "add -A" to work on the whole tree from subdirectories when given no paths.

Quoted 9 lines

The original design for the other two in your list was to be a whole tree operation. This commit broke it.

2ed2c22 "git-add -u paths... now works from subdirectory".
...
I think it is a good idea to fix this as an old regression in the maint branch. You don't have to introduce "git add -a". In fact the -a option was explicitly rejected when "git add -A" option was added with this commit.

Geez, you are good at digging things up.

It is very tempting to follow the suggestion above, but I suspect that, even though it may be a regression from historical point of view, some people who are used to the current behaviour may look at the corrected one as a regression. We've had the change by 2ed2c22 for a long time.

I dunno.

#28 lore raw
In reply to Clemens Buchacher
Quoted 12 lines · Clemens Buchacher
Quoted 5 lines · Junio C Hamano

I personally find "add -u" that defaults to the current directory more natural than always going to the root; same preference for "grep". Besides, "add -u subdir" must add subdir relative to the cwd, without going to the root. Why should "add -u" sans argument behave drastically differently?

Sorry for stating the obvious here, but the following commands affect the entire repository, even though they limit themselves to the current directory, if passed a '.'.

Quoted 5 lines

git commit
git log
git diff
git checkout
git reset

You have to add "git add -e", "git add -i" and "git add -p" here.

I completely agree that "git add -u" should have been a full-tree oriented command, just like other "git add" variants and other Git commands, from the beginning.

Now, I'm unconfortable with both a behavior change and a config option. Someone used to the cwd-limited behavior typing "git add -u" on a machine configured to git the full-tree behavior could be really annoyed (not even mentionning scripts).

I think it has already been proposed to introduce "git add -a" doing what "git add -u" do, but for the full tree. The "-a" option here being analogous to the one of "git commit": roughly, "git add -a; git commit" would be equivalent to "git commit -a". This would allow a long deprecation period for "git add -u". I find the proposal sensible, but IIRC it has already been rejected.

Signature · 2 lines
Matthieu Moy
http://www-verimag.imag.fr/~moy/
#29 lore raw
Quoted 2 lines · Matthieu Moy

I think it has already been proposed to introduce "git add -a" doing what "git add -u" do, but for the full tree.

I like that, actually. AFAICT it's completely analogous to "git commit -a". We also need something for "git add -A" though.

Do you feel the same way about changing the behavior of "git grep"? I don't really want to change the command's name.

Clemens

#30 lore raw
Quoted 9 lines · Clemens Buchacher
Quoted 2 lines · Matthieu Moy

I think it has already been proposed to introduce "git add -a" doing what "git add -u" do, but for the full tree.

I like that, actually. AFAICT it's completely analogous to "git commit -a". We also need something for "git add -A" though.

Do you feel the same way about changing the behavior of "git grep"? I don't really want to change the command's name.

I don't have particular feeling about "git grep", probably because I don't use it much. One argument in favour of keeping the current behavior is the consistancy with plain "grep".

Signature · 2 lines
Matthieu Moy
http://www-verimag.imag.fr/~moy/
#31 lore raw
Quoted 9 lines · Matthieu Moy
Quoted 7 lines · Clemens Buchacher
Quoted 2 lines · Matthieu Moy

I think it has already been proposed to introduce "git add -a" doing what "git add -u" do, but for the full tree.

I like that, actually. AFAICT it's completely analogous to "git commit -a". We also need something for "git add -A" though.

Quoted 6 lines
Quoted 2 lines

Do you feel the same way about changing the behavior of "git grep"? I don't really want to change the command's name.

I don't have particular feeling about "git grep", probably because I don't use it much. One argument in favour of keeping the current behavior is the consistancy with plain "grep".

I'm not sure how important should be the consistency with plain grep in this case. After all, plain grep does not work without pathspec at all (ok, it searches stdin, but it's completely different thing), while git grep does. And plain grep is not recursive by default, while git grep is. And plain 'grep -r foo .' searches all files in the current directory and below, while 'git grep foo .' does not search in untracked files.

Regards,
Gábor

#32 lore raw
Quoted 7 lines · SZEDER Gábor
Quoted 3 lines

I don't have particular feeling about "git grep", probably because I don't use it much. One argument in favour of keeping the current behavior is the consistancy with plain "grep".

I'm not sure how important should be the consistency with plain grep in this case. After all, plain grep does not work without pathspec at all

Yes, right, forget what I wrote, except the "I don't have particular feeling about 'git grep'" part ;-).

Signature · 2 lines
Matthieu Moy
http://www-verimag.imag.fr/~moy/
#33 lore raw
In reply to Junio C Hamano
Quoted 8 lines · Junio C Hamano
Quoted 5 lines · Jeff King

I suspect it is too late to change it due to compatibility issues. OTOH, I think the intent of v1.7.0 is to allow a few small breakages like these. You could always write an RFC patch and generate some discussion; I'm not 100% sure that there are enough people that agree with us to change the default.

Quoted 4 lines

The intent of 1.7.0 is to fix usability glitches and warts that everybody has long agreed are problematic. People have *just started* discussing about this---it is not remotely close to "everybody has long agreed are problematic" criteria. It is too late for 1.7.0.

I just wanted to see if I am being fair. Here are the topics that we may have in 1.7.0.

* jc/1.7.0-push-safety

Prevents gremlin updates from sideways to a repository with a work tree, that confused countless new people. I've resisted this change for a long time on the backward compatiblity ground, but it is very fair to say that it was long agreed that the benefit from the change far outweigh the donesides of having to say "I do want the old behaviour" by setting an configuration variable or two.

* jc/1.7.0-send-email-no-thread-default

Defaults multi-message send-email to thread shallowly. This change was requested by kernel folks for a long time ago, and discussion on-list resulted in a declaration that unless nobody objects 1.6.2 release notes will say the default will change in 1.6.3. We did not hear any objection, but the switchover did not happen ;-).

* jc/1.7.0-status

Everybody hated that "status $args" being "commit --dry-run $args" since 1.4.0 days. We will give "commit --dry-run $args" in 1.6.5.

* jc/1.7.0-diff-whitespace-only-status

We said "diff -w" only affects the appearance but not the exit code, so "diff -w --exit-code" never returned success if there were only whitespace changes. It was noticed to be illogical since day one of the introduction of --exit-code, but we simply did not bother to fix the implementation of -b and -w, since the combination of these two options were thought to be unlikely, and we were simply lazy ;-)

I think the first three are clearly 1.7.0 candidates, judging from the benefit/downside perspective and also from the escape-hatch perspective, The last one is probably less so, but on the other hand it is of far lessor impact that we could even roll it out as a bugfix on 'maint'.

#34 lore raw
In reply to Jeff King

[Oops, I 've just noticed that my reply to Jeff didn't made it to the git list, because I hit 'reply' instead of 'reply to all'...]

Hi Jeff,

thanks for your quick reply.

Quoted 45 lines · Jeff King
Quoted 16 lines · SZEDER Gábor

As the subject says, 'git add -u' does not work from an untracked subdir, because it doesn't add modified files to the index. The following script reproduces the issue:

mkdir repo
cd repo
git init
echo 1 >foo
git add foo
git commit -m first
echo 2 >foo
mkdir untracked_subdir
cd untracked_subdir
git add -u
git diff

Quoted 6 lines

It worked in the initial 'git add -u' implementation (dfdac5d, git-add
-u: match the index with working tree, 2007-04-20), but 2ed2c222 (git-add -u paths... now works from subdirectory, 2007-08-16) broke it
later, and is broken ever since.

It is not just untracked subdirs. Try:

mkdir repo && cd repo && git init
echo 1 >foo
mkdir subdir
echo 1 >subdir/bar
git add . && git commit -m first
echo 2 >foo
echo 2 >subdir/bar
cd subdir
git add -u
git diff ;# still shows foo/1 in index git diff --cached ;# shows subdir/bar was updated

While I have sometimes found the behavior a bit annoying[1], I always
assumed that was the intended behavior.

And indeed, in modern builtin-add.c, we find this:

Quoted 7 lines
        if ((addremove || take_worktree_changes) && !argc) {
                static const char *here[2] = { ".", NULL };
                argc = 1;
                argv = here;
        }

which seems pretty explicit.

Since then I looked at the man page (I should have done that right away ;), and it says under the description of -u that "If no paths are specified, all tracked files in the current directory and its subdirectories are updated." So this is indeed the intended behaviour, but I was just not aware of it. Oh well, sorry for the noise.

Quoted 7 lines

[1] I would prefer "git add -u ." to add only the current directory, and
"git add -u" to touch everything. But then, I am one of the people who
turn off status.relativepaths, so I think I may be in the minority in
always wanting to think of the project as a whole.

I don't really know which would I prefer.

I was updating some Javadoc documentation in Eclipse, and checking the generated docs in terminal, deep down in an untracked subdir, and performed some 'add -u ; commit --amend' from there (and was rather surprised after the fifth amend to see all the changes still in the worktree). Doing perform the desired add -u from there I should have run 'git add -u ../../../../../..', what doesn't seem very convenient. But since this was the first time I've done that since 2007-08-16, I guess it's not a very common use case.

Gábor