From: John Keeping <hidden> Date: 2016-06-15 22:58:43
The first patch is the important one here, the second one I noticed
while checking if any other commands fail to handle submodule paths with
a trailing slash and is just a simplification.
John Keeping (2):
reset: handle submodule with trailing slash
rm: re-use parse_pathspec's trailing-slash removal
builtin/reset.c | 5 +++++
builtin/rm.c | 20 ++++----------------
t/t7400-submodule-basic.sh | 6 ++++--
3 files changed, 13 insertions(+), 18 deletions(-)
--
1.8.2
From: John Keeping <hidden> Date: 2016-06-15 22:58:43
When using tab-completion, a directory path will often end with a
trailing slash which currently confuses "git rm" when dealing with
submodules. Now that we have parse_pathspec we can easily handle this
by simply adding the PATHSPEC_STRIP_SUBMODULE_SLASH_CHEAP flag.
Signed-off-by: John Keeping <redacted>
---
builtin/reset.c | 5 +++++
t/t7400-submodule-basic.sh | 6 ++++--
2 files changed, 9 insertions(+), 2 deletions(-)
@@ -481,7 +481,7 @@ test_expect_success 'do not add files from a submodule' ''-test_expect_success'gracefully add submodule with a trailing slash''+test_expect_success'gracefully add/reset submodule with a trailing slash''gitreset--hard&&gitcommit-m"commit subproject"init&&
@@ -495,7 +495,9 @@ test_expect_success 'gracefully add submodule with a trailing slash' 'gitaddinit/&&test_must_failgitdiff--exit-code--cachedinit&&test$commit=$(gitls-files--stage|-sed-n"s/^160000 \([^ ]*\).*/\1/p")+sed-n"s/^160000 \([^ ]*\).*/\1/p")&&+gitresetinit/&&+gitdiff--exit-code--cachedinit'
When using tab-completion, a directory path will often end with a
trailing slash which currently confuses "git rm" when dealing with
I think you meant to say "git reset" in the line above. Apart from
that I'm all for it.
quoted hunk
submodules. Now that we have parse_pathspec we can easily handle this
by simply adding the PATHSPEC_STRIP_SUBMODULE_SLASH_CHEAP flag.
Signed-off-by: John Keeping <redacted>
---
builtin/reset.c | 5 +++++
t/t7400-submodule-basic.sh | 6 ++++--
2 files changed, 9 insertions(+), 2 deletions(-)
@@ -481,7 +481,7 @@ test_expect_success 'do not add files from a submodule' ''-test_expect_success'gracefully add submodule with a trailing slash''+test_expect_success'gracefully add/reset submodule with a trailing slash''gitreset--hard&&gitcommit-m"commit subproject"init&&
@@ -495,7 +495,9 @@ test_expect_success 'gracefully add submodule with a trailing slash' 'gitaddinit/&&test_must_failgitdiff--exit-code--cachedinit&&test$commit=$(gitls-files--stage|-sed-n"s/^160000 \([^ ]*\).*/\1/p")+sed-n"s/^160000 \([^ ]*\).*/\1/p")&&+gitresetinit/&&+gitdiff--exit-code--cachedinit'
From: John Keeping <hidden> Date: 2016-06-15 22:58:43
On Tue, Sep 10, 2013 at 09:37:45PM +0200, Jens Lehmann wrote:
Am 10.09.2013 21:13, schrieb John Keeping:
quoted
When using tab-completion, a directory path will often end with a
trailing slash which currently confuses "git rm" when dealing with
I think you meant to say "git reset" in the line above. Apart from
that I'm all for it.
Yeah, you're right - I obviously got confused between the two patches :-(.
I'll wait for more feedback before submitting a re-roll.
quoted
submodules. Now that we have parse_pathspec we can easily handle this
by simply adding the PATHSPEC_STRIP_SUBMODULE_SLASH_CHEAP flag.
Signed-off-by: John Keeping <redacted>
---
builtin/reset.c | 5 +++++
t/t7400-submodule-basic.sh | 6 ++++--
2 files changed, 9 insertions(+), 2 deletions(-)
@@ -481,7 +481,7 @@ test_expect_success 'do not add files from a submodule' ''-test_expect_success'gracefully add submodule with a trailing slash''+test_expect_success'gracefully add/reset submodule with a trailing slash''gitreset--hard&&gitcommit-m"commit subproject"init&&
@@ -495,7 +495,9 @@ test_expect_success 'gracefully add submodule with a trailing slash' 'gitaddinit/&&test_must_failgitdiff--exit-code--cachedinit&&test$commit=$(gitls-files--stage|-sed-n"s/^160000 \([^ ]*\).*/\1/p")+sed-n"s/^160000 \([^ ]*\).*/\1/p")&&+gitresetinit/&&+gitdiff--exit-code--cachedinit'
From: Johannes Sixt <hidden> Date: 2016-06-15 22:58:43
Am 10.09.2013 21:13, schrieb John Keeping:
quoted hunk
When using tab-completion, a directory path will often end with a
trailing slash which currently confuses "git rm" when dealing with
submodules. Now that we have parse_pathspec we can easily handle this
by simply adding the PATHSPEC_STRIP_SUBMODULE_SLASH_CHEAP flag.
Signed-off-by: John Keeping <redacted>
---
builtin/reset.c | 5 +++++
t/t7400-submodule-basic.sh | 6 ++++--
2 files changed, 9 insertions(+), 2 deletions(-)
@@ -481,7 +481,7 @@ test_expect_success 'do not add files from a submodule' ''-test_expect_success'gracefully add submodule with a trailing slash''+test_expect_success'gracefully add/reset submodule with a trailing slash''gitreset--hard&&gitcommit-m"commit subproject"init&&
@@ -495,7 +495,9 @@ test_expect_success 'gracefully add submodule with a trailing slash' 'gitaddinit/&&test_must_failgitdiff--exit-code--cachedinit&&test$commit=$(gitls-files--stage|-sed-n"s/^160000 \([^ ]*\).*/\1/p")+sed-n"s/^160000 \([^ ]*\).*/\1/p")&&+gitresetinit/&&+gitdiff--exit-code--cachedinit'
I notice that _CHEAP implementation and the removed code are not
exactly the same. But I think they have the same purpose so it's
probably ok even there are some subtle behavioral changes.
You may want to improve _CHEAP to remove consecutive trailing slashes
(i.e. foo//// -> foo) too. And maybe is is_dir_sep() instead of
explicit == '/' comparison in there.
From: John Keeping <hidden> Date: 2016-06-15 22:58:43
On Wed, Sep 11, 2013 at 08:05:44AM +0200, Johannes Sixt wrote:
Am 10.09.2013 21:13, schrieb John Keeping:
quoted
When using tab-completion, a directory path will often end with a
trailing slash which currently confuses "git rm" when dealing with
submodules. Now that we have parse_pathspec we can easily handle this
by simply adding the PATHSPEC_STRIP_SUBMODULE_SLASH_CHEAP flag.
Signed-off-by: John Keeping <redacted>
---
builtin/reset.c | 5 +++++
t/t7400-submodule-basic.sh | 6 ++++--
2 files changed, 9 insertions(+), 2 deletions(-)
@@ -143,7 +143,6 @@ static int read_from_tree(const struct pathspec *pathspec,opt.output_format=DIFF_FORMAT_CALLBACK;opt.format_callback=update_index_from_diff;-read_cache();if(do_diff_cache(tree_sha1,&opt))return1;diffcore_std(&opt);
@@ -169,7 +168,7 @@ static void set_reflog_message(struct strbuf *sb, const char *action,staticvoiddie_if_unmerged_cache(intreset_type){-if(is_merge()||read_cache()<0||unmerged_cache())+if(is_merge()||unmerged_cache())die(_("Cannot do a %s reset in the middle of a merge."),_(reset_type_names[reset_type]));
I notice that _CHEAP implementation and the removed code are not
exactly the same. But I think they have the same purpose so it's
probably ok even there are some subtle behavioral changes.
Providing that there's only one trailing slash, the user-visible effect
should be the same since the only case affected by that is submodules.
In fact _CHEAP does better in the case where the submodule does not
exist in the working tree.
You may want to improve _CHEAP to remove consecutive trailing slashes
(i.e. foo//// -> foo) too. And maybe is is_dir_sep() instead of
explicit == '/' comparison in there.
On Wed, Sep 11, 2013 at 3:20 PM, John Keeping [off-list ref] wrote:
quoted hunk
On Wed, Sep 11, 2013 at 08:05:44AM +0200, Johannes Sixt wrote:
quoted
Am 10.09.2013 21:13, schrieb John Keeping:
quoted
When using tab-completion, a directory path will often end with a
trailing slash which currently confuses "git rm" when dealing with
submodules. Now that we have parse_pathspec we can easily handle this
by simply adding the PATHSPEC_STRIP_SUBMODULE_SLASH_CHEAP flag.
Signed-off-by: John Keeping <redacted>
---
builtin/reset.c | 5 +++++
t/t7400-submodule-basic.sh | 6 ++++--
2 files changed, 9 insertions(+), 2 deletions(-)
@@ -143,7 +143,6 @@ static int read_from_tree(const struct pathspec *pathspec,opt.output_format=DIFF_FORMAT_CALLBACK;opt.format_callback=update_index_from_diff;-read_cache();if(do_diff_cache(tree_sha1,&opt))return1;diffcore_std(&opt);
@@ -169,7 +168,7 @@ static void set_reflog_message(struct strbuf *sb, const char *action,staticvoiddie_if_unmerged_cache(intreset_type){-if(is_merge()||read_cache()<0||unmerged_cache())+if(is_merge()||unmerged_cache())die(_("Cannot do a %s reset in the middle of a merge."),_(reset_type_names[reset_type]));
reset --soft does not go through these code paths (i.e. it does not
need index at all). If we fail to load index index in "reset --soft" I
think it's ok to die(). Corrupt index is fatal anyway. But "reset
--soft" now has to pay the cost to load index, which could be slow
when the index is big. Assuming nobody does "reset --soft" that often
I think this is OK.
Alternatively we could load index lazily in _CHEAP code only when we
see trailing slashes, then replace these read_cache() with
read_cache_unless_its_already_loaded_earlier() or something.
--
Duy
From: John Keeping <hidden> Date: 2016-06-15 22:58:43
On Wed, Sep 11, 2013 at 05:54:48PM +0700, Duy Nguyen wrote:
On Wed, Sep 11, 2013 at 3:20 PM, John Keeping [off-list ref] wrote:
quoted
On Wed, Sep 11, 2013 at 08:05:44AM +0200, Johannes Sixt wrote:
quoted
Am 10.09.2013 21:13, schrieb John Keeping:
quoted
When using tab-completion, a directory path will often end with a
trailing slash which currently confuses "git rm" when dealing with
submodules. Now that we have parse_pathspec we can easily handle this
by simply adding the PATHSPEC_STRIP_SUBMODULE_SLASH_CHEAP flag.
Signed-off-by: John Keeping <redacted>
---
builtin/reset.c | 5 +++++
t/t7400-submodule-basic.sh | 6 ++++--
2 files changed, 9 insertions(+), 2 deletions(-)
@@ -143,7 +143,6 @@ static int read_from_tree(const struct pathspec *pathspec,opt.output_format=DIFF_FORMAT_CALLBACK;opt.format_callback=update_index_from_diff;-read_cache();if(do_diff_cache(tree_sha1,&opt))return1;diffcore_std(&opt);
@@ -169,7 +168,7 @@ static void set_reflog_message(struct strbuf *sb, const char *action,staticvoiddie_if_unmerged_cache(intreset_type){-if(is_merge()||read_cache()<0||unmerged_cache())+if(is_merge()||unmerged_cache())die(_("Cannot do a %s reset in the middle of a merge."),_(reset_type_names[reset_type]));
reset --soft does not go through these code paths (i.e. it does not
need index at all). If we fail to load index index in "reset --soft" I
think it's ok to die(). Corrupt index is fatal anyway. But "reset
--soft" now has to pay the cost to load index, which could be slow
when the index is big. Assuming nobody does "reset --soft" that often
I think this is OK.
Alternatively we could load index lazily in _CHEAP code only when we
see trailing slashes, then replace these read_cache() with
read_cache_unless_its_already_loaded_earlier() or something.
read_cache() already has an early return if the index is already loaded
so I don't think we need to worry about a special function for that.
I'm not sure it's worth optimizing this case too heavily, but it might
be a nice change to make parse_pathspec() not rely on the index being
loaded before it is called with certain flags.
@@ -143,7 +143,6 @@ static int read_from_tree(const struct pathspec *pathspec,opt.output_format=DIFF_FORMAT_CALLBACK;opt.format_callback=update_index_from_diff;-read_cache();if(do_diff_cache(tree_sha1,&opt))return1;diffcore_std(&opt);
@@ -169,7 +168,7 @@ static void set_reflog_message(struct strbuf *sb, const char *action,staticvoiddie_if_unmerged_cache(intreset_type){-if(is_merge()||read_cache()<0||unmerged_cache())+if(is_merge()||unmerged_cache())die(_("Cannot do a %s reset in the middle of a merge."),_(reset_type_names[reset_type]));
reset --soft does not go through these code paths (i.e. it does not
need index at all). If we fail to load index index in "reset --soft" I
think it's ok to die(). Corrupt index is fatal anyway. But "reset
--soft" now has to pay the cost to load index, which could be slow
when the index is big. Assuming nobody does "reset --soft" that often
I think this is OK.
Alternatively we could load index lazily in _CHEAP code only when we
see trailing slashes, then replace these read_cache() with
read_cache_unless_its_already_loaded_earlier() or something.
read_cache() already has an early return if the index is already loaded
so I don't think we need to worry about a special function for that.
I'm not sure it's worth optimizing this case too heavily, but it might
be a nice change to make parse_pathspec() not rely on the index being
loaded before it is called with certain flags.
Yeah I ddin't check. I agree putting read_cache() in _CHEAP code
sounds nice. We won't need to worry about forgotten read_cache()
elsewhere.
--
Duy
From: John Keeping <hidden> Date: 2016-06-15 22:58:44
Changes since v1:
* Improvements to existing pathspec code to use is_dir_sep instead of
comparing against '/' and handle multiple trailing slashes
* Remove calls to read_cache() made redundant by a new call in
builtin/reset.c::parse_args()
John Keeping (4):
pathspec: use is_dir_sep() to check for trailing slashes
pathspec: strip multiple trailing slashes from submodules
rm: re-use parse_pathspec's trailing-slash removal
reset: handle submodule with trailing slash
builtin/reset.c | 8 ++++++--
builtin/rm.c | 20 ++++----------------
pathspec.c | 30 +++++++++++++++++++-----------
t/t7400-submodule-basic.sh | 6 ++++--
4 files changed, 33 insertions(+), 31 deletions(-)
--
1.8.4.277.gfbd6843.dirty
From: John Keeping <hidden> Date: 2016-06-15 22:58:44
This allows us to correctly removing trailing backslashes on Windows
when checking for submodules.
Signed-off-by: John Keeping <redacted>
---
pathspec.c | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
From: John Keeping <hidden> Date: 2016-06-15 22:58:44
This allows us to replace the submodule path trailing slash removal in
builtin/rm.c with the PATHSPEC_STRIP_SUBMODULE_SLASH_CHEAP flag to
parse_pathspec() without changing the behaviour with respect to multiple
trailing slashes.
Signed-off-by: John Keeping <redacted>
---
pathspec.c | 27 +++++++++++++++++----------
1 file changed, 17 insertions(+), 10 deletions(-)
From: John Keeping <hidden> Date: 2016-06-15 22:58:44
When using tab-completion, a directory path will often end with a
trailing slash which currently confuses "git reset" when dealing with
submodules. Now that we have parse_pathspec we can easily handle this
by simply adding the PATHSPEC_STRIP_SUBMODULE_SLASH_CHEAP flag.
To do this, we need to move the read_cache() call before the
parse_pathspec() call. All of the existing paths through cmd_reset()
that do not die early already call read_cache() at some point, so there
is no performance impact to doing this in the common case.
Signed-off-by: John Keeping <redacted>
---
builtin/reset.c | 8 ++++++--
t/t7400-submodule-basic.sh | 6 ++++--
2 files changed, 10 insertions(+), 4 deletions(-)
@@ -143,7 +143,6 @@ static int read_from_tree(const struct pathspec *pathspec,opt.output_format=DIFF_FORMAT_CALLBACK;opt.format_callback=update_index_from_diff;-read_cache();if(do_diff_cache(tree_sha1,&opt))return1;diffcore_std(&opt);
@@ -169,7 +168,7 @@ static void set_reflog_message(struct strbuf *sb, const char *action,staticvoiddie_if_unmerged_cache(intreset_type){-if(is_merge()||read_cache()<0||unmerged_cache())+if(is_merge()||unmerged_cache())die(_("Cannot do a %s reset in the middle of a merge."),_(reset_type_names[reset_type]));
@@ -481,7 +481,7 @@ test_expect_success 'do not add files from a submodule' ''-test_expect_success'gracefully add submodule with a trailing slash''+test_expect_success'gracefully add/reset submodule with a trailing slash''gitreset--hard&&gitcommit-m"commit subproject"init&&
@@ -495,7 +495,9 @@ test_expect_success 'gracefully add submodule with a trailing slash' 'gitaddinit/&&test_must_failgitdiff--exit-code--cachedinit&&test$commit=$(gitls-files--stage|-sed-n"s/^160000 \([^ ]*\).*/\1/p")+sed-n"s/^160000 \([^ ]*\).*/\1/p")&&+gitresetinit/&&+gitdiff--exit-code--cachedinit'
From: Johannes Sixt <hidden> Date: 2016-06-15 22:58:44
Am 12.09.2013 21:24, schrieb John Keeping:
quoted hunk
This allows us to correctly removing trailing backslashes on Windows
when checking for submodules.
Signed-off-by: John Keeping <redacted>
---
pathspec.c | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
A design decisions to keep in mind:
Paths in the index *ALWAYS* use the slash, even on Windows. On Windows,
pathspec that are user input must undergo backslash-to-slash
transformation at a very early stage so that later processing that
compares the user input to index contents need not do it on the fly. The
backslash-to-slash transformation used to happen in get_pathspec() via
prefix_path() and normalize_path_copy().
If, at this point, the contents of 'match' is still being parsed for
pathspec magic, then it is likely correct to use is_dir_sep().
On the other hand, if at this point the contents of 'match' are used to
execute pathspec magic, then it is not correct to use is_dir_sep(); the
conversion of backslash to slash should have happened earlier, and no
backslashes should be present anymore.
(Yes, this means that on Windows we cannot escape glob characters
because, e.g., 'a\*.c' was turned into 'a/*.c'.)
-- Hannes