* [PATCH 0/4] @ 2018-12-07 23:54 Stefan Beller 2018-12-07 23:54 ` [PATCH 1/4] submodule update: add regression test with old style setups Stefan Beller ` (4 more replies) 0 siblings, 5 replies; 22+ messages in thread From: Stefan Beller @ 2018-12-07 23:54 UTC (permalink / raw) To: git; +Cc: Stefan Beller A couple days before the 2.19 release we had a bug report about broken submodules[1] and reverted[2] the commits leading up to them. The behavior of said bug fixed itself by taking a different approach[3], specifically by a weaker enforcement of having `core.worktree` set in a submodule [4]. The revert [2] was overly broad as we neared the release, such that we wanted to rather keep the known buggy behavior of always having `core.worktree` set, rather than figuring out how to fix the new bug of having 'git submodule update' not working in old style repository setups. This series re-introduces those reverted patches, with no changes in code, but with drastically changed commit messages, as those focus on why it is safe to re-introduce them instead of explaining the desire for the change. [1] https://public-inbox.org/git/2659750.rG6xLiZASK@twilight [2] f178c13fda (Revert "Merge branch 'sb/submodule-core-worktree'", 2018-09-07) [3] 4d6d6ef1fc (Merge branch 'sb/submodule-update-in-c', 2018-09-17) [4] 74d4731da1 (submodule--helper: replace connect-gitdir-workingtree by ensure-core-worktree, 2018-08-13) Stefan Beller (4): submodule update: add regression test with old style setups submodule: unset core.worktree if no working tree is present submodule--helper: fix BUG message in ensure_core_worktree submodule deinit: unset core.worktree builtin/submodule--helper.c | 4 +++- submodule.c | 14 ++++++++++++++ submodule.h | 2 ++ t/lib-submodule-update.sh | 5 +++-- t/t7400-submodule-basic.sh | 5 +++++ t/t7412-submodule-absorbgitdirs.sh | 7 ++++++- 6 files changed, 33 insertions(+), 4 deletions(-) -- 2.20.0.rc2.403.gdbc3b29805-goog ^ permalink raw reply [flat|nested] 22+ messages in thread
* [PATCH 1/4] submodule update: add regression test with old style setups 2018-12-07 23:54 [PATCH 0/4] Stefan Beller @ 2018-12-07 23:54 ` Stefan Beller 2018-12-09 0:11 ` Junio C Hamano 2018-12-07 23:54 ` [PATCH 2/4] submodule: unset core.worktree if no working tree is present Stefan Beller ` (3 subsequent siblings) 4 siblings, 1 reply; 22+ messages in thread From: Stefan Beller @ 2018-12-07 23:54 UTC (permalink / raw) To: git; +Cc: Stefan Beller As f178c13fda (Revert "Merge branch 'sb/submodule-core-worktree'", 2018-09-07) was produced shortly before a release, nobody asked for a regression test to be included. Add a regression test that makes sure that the invocation of `git submodule update` on old setups doesn't produce errors as pointed out in f178c13fda. The place to add such a regression test may look odd in t7412, but that is the best place as there we setup old style submodule setups explicitly. Signed-off-by: Stefan Beller <sbeller@google.com> --- t/t7412-submodule-absorbgitdirs.sh | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/t/t7412-submodule-absorbgitdirs.sh b/t/t7412-submodule-absorbgitdirs.sh index ce74c12da2..1cfa150768 100755 --- a/t/t7412-submodule-absorbgitdirs.sh +++ b/t/t7412-submodule-absorbgitdirs.sh @@ -75,7 +75,12 @@ test_expect_success 're-setup nested submodule' ' GIT_WORK_TREE=../../../nested git -C sub1/.git/modules/nested config \ core.worktree "../../../nested" && # make sure this re-setup is correct - git status --ignore-submodules=none + git status --ignore-submodules=none && + + # also make sure this old setup does not regress + git submodule update --init --recursive >out 2>err && + test_must_be_empty out && + test_must_be_empty err ' test_expect_success 'absorb the git dir in a nested submodule' ' -- 2.20.0.rc2.403.gdbc3b29805-goog ^ permalink raw reply related [flat|nested] 22+ messages in thread
* Re: [PATCH 1/4] submodule update: add regression test with old style setups 2018-12-07 23:54 ` [PATCH 1/4] submodule update: add regression test with old style setups Stefan Beller @ 2018-12-09 0:11 ` Junio C Hamano 0 siblings, 0 replies; 22+ messages in thread From: Junio C Hamano @ 2018-12-09 0:11 UTC (permalink / raw) To: Stefan Beller; +Cc: git Stefan Beller <sbeller@google.com> writes: > As f178c13fda (Revert "Merge branch 'sb/submodule-core-worktree'", > 2018-09-07) was produced shortly before a release, nobody asked for > a regression test to be included. Add a regression test that makes sure > that the invocation of `git submodule update` on old setups doesn't > produce errors as pointed out in f178c13fda. > > The place to add such a regression test may look odd in t7412, but > that is the best place as there we setup old style submodule setups > explicitly. Very good first step. Thanks. > > Signed-off-by: Stefan Beller <sbeller@google.com> > --- > t/t7412-submodule-absorbgitdirs.sh | 7 ++++++- > 1 file changed, 6 insertions(+), 1 deletion(-) > > diff --git a/t/t7412-submodule-absorbgitdirs.sh b/t/t7412-submodule-absorbgitdirs.sh > index ce74c12da2..1cfa150768 100755 > --- a/t/t7412-submodule-absorbgitdirs.sh > +++ b/t/t7412-submodule-absorbgitdirs.sh > @@ -75,7 +75,12 @@ test_expect_success 're-setup nested submodule' ' > GIT_WORK_TREE=../../../nested git -C sub1/.git/modules/nested config \ > core.worktree "../../../nested" && > # make sure this re-setup is correct > - git status --ignore-submodules=none > + git status --ignore-submodules=none && > + > + # also make sure this old setup does not regress > + git submodule update --init --recursive >out 2>err && > + test_must_be_empty out && > + test_must_be_empty err > ' > > test_expect_success 'absorb the git dir in a nested submodule' ' ^ permalink raw reply [flat|nested] 22+ messages in thread
* [PATCH 2/4] submodule: unset core.worktree if no working tree is present 2018-12-07 23:54 [PATCH 0/4] Stefan Beller 2018-12-07 23:54 ` [PATCH 1/4] submodule update: add regression test with old style setups Stefan Beller @ 2018-12-07 23:54 ` Stefan Beller 2018-12-08 6:44 ` Junio C Hamano 2018-12-07 23:54 ` [PATCH 3/4] submodule--helper: fix BUG message in ensure_core_worktree Stefan Beller ` (2 subsequent siblings) 4 siblings, 1 reply; 22+ messages in thread From: Stefan Beller @ 2018-12-07 23:54 UTC (permalink / raw) To: git; +Cc: Stefan Beller, Junio C Hamano This reintroduces 4fa4f90ccd (submodule: unset core.worktree if no working tree is present, 2018-06-12), which was reverted as part of f178c13fda (Revert "Merge branch 'sb/submodule-core-worktree'", 2018-09-07). 4fa4f90ccd was reverted as its followup commit was faulty, but without the accompanying change of the followup, we'd have an incomplete workflow of setting `core.worktree` again, when it is needed such as checking out a revision that contains a submodule. So re-introduce that commit as-is, focusing on fixing up the followup Signed-off-by: Stefan Beller <sbeller@google.com> Signed-off-by: Junio C Hamano <gitster@pobox.com> Signed-off-by: Stefan Beller <sbeller@google.com> --- submodule.c | 14 ++++++++++++++ submodule.h | 2 ++ t/lib-submodule-update.sh | 3 ++- 3 files changed, 18 insertions(+), 1 deletion(-) diff --git a/submodule.c b/submodule.c index 6415cc5580..d393e947e6 100644 --- a/submodule.c +++ b/submodule.c @@ -1561,6 +1561,18 @@ int bad_to_remove_submodule(const char *path, unsigned flags) return ret; } +void submodule_unset_core_worktree(const struct submodule *sub) +{ + char *config_path = xstrfmt("%s/modules/%s/config", + get_git_common_dir(), sub->name); + + if (git_config_set_in_file_gently(config_path, "core.worktree", NULL)) + warning(_("Could not unset core.worktree setting in submodule '%s'"), + sub->path); + + free(config_path); +} + static const char *get_super_prefix_or_empty(void) { const char *s = get_super_prefix(); @@ -1726,6 +1738,8 @@ int submodule_move_head(const char *path, if (is_empty_dir(path)) rmdir_or_warn(path); + + submodule_unset_core_worktree(sub); } } out: diff --git a/submodule.h b/submodule.h index a680214c01..9e18e9b807 100644 --- a/submodule.h +++ b/submodule.h @@ -131,6 +131,8 @@ int submodule_move_head(const char *path, const char *new_head, unsigned flags); +void submodule_unset_core_worktree(const struct submodule *sub); + /* * Prepare the "env_array" parameter of a "struct child_process" for executing * a submodule by clearing any repo-specific environment variables, but diff --git a/t/lib-submodule-update.sh b/t/lib-submodule-update.sh index 016391723c..51d4555549 100755 --- a/t/lib-submodule-update.sh +++ b/t/lib-submodule-update.sh @@ -709,7 +709,8 @@ test_submodule_recursing_with_args_common() { git branch -t remove_sub1 origin/remove_sub1 && $command remove_sub1 && test_superproject_content origin/remove_sub1 && - ! test -e sub1 + ! test -e sub1 && + test_must_fail git config -f .git/modules/sub1/config core.worktree ) ' # ... absorbing a .git directory along the way. -- 2.20.0.rc2.403.gdbc3b29805-goog ^ permalink raw reply related [flat|nested] 22+ messages in thread
* Re: [PATCH 2/4] submodule: unset core.worktree if no working tree is present 2018-12-07 23:54 ` [PATCH 2/4] submodule: unset core.worktree if no working tree is present Stefan Beller @ 2018-12-08 6:44 ` Junio C Hamano 0 siblings, 0 replies; 22+ messages in thread From: Junio C Hamano @ 2018-12-08 6:44 UTC (permalink / raw) To: Stefan Beller; +Cc: git Stefan Beller <sbeller@google.com> writes: > This reintroduces 4fa4f90ccd (submodule: unset core.worktree if no working > tree is present, 2018-06-12), which was reverted as part of f178c13fda > (Revert "Merge branch 'sb/submodule-core-worktree'", 2018-09-07). > > 4fa4f90ccd was reverted as its followup commit was faulty, but without > the accompanying change of the followup, we'd have an incomplete workflow > of setting `core.worktree` again, when it is needed such as checking out > a revision that contains a submodule. > > So re-introduce that commit as-is, focusing on fixing up the followup I was hoping to hear (given what 0/4 claimed) a clearer explanation of what this change wants to achieve, but that is lacking. No need to grumble about an earlier work was that turned out to be inappropriate for the codebase back then. Repeatedly saying "this is needed" without giving further explaining why it is so, or anything like that, would help readers. Just pretend that the ealier commits and their reversion never happened, and further pretend that we are doing the best thing that should happen to our codebase. How would we explain this change, what the problem it tries to solve and what the solution looks like in the larger picture? When removing a working tree of a submodule (e.g. we may be switching back to an earlier commit in the superproject that did not have the submodule in question yet), we failed to unset core.worktree of the submodule's repository. That caused this and that issues, exhibited by a few new tests this commit adds. Make sure that core.worktree gets unset so that a leftover setting won't cause these issues. or something like that? I am just guessing by looking at the old commit's text, as the above two paragraphs and one sentence does not say much. > diff --git a/submodule.c b/submodule.c > index 6415cc5580..d393e947e6 100644 > --- a/submodule.c > +++ b/submodule.c > @@ -1561,6 +1561,18 @@ int bad_to_remove_submodule(const char *path, unsigned flags) > return ret; > } > > +void submodule_unset_core_worktree(const struct submodule *sub) > +{ > + char *config_path = xstrfmt("%s/modules/%s/config", > + get_git_common_dir(), sub->name); > + > + if (git_config_set_in_file_gently(config_path, "core.worktree", NULL)) > + warning(_("Could not unset core.worktree setting in submodule '%s'"), > + sub->path); > + > + free(config_path); > +} > + > static const char *get_super_prefix_or_empty(void) > { > const char *s = get_super_prefix(); > @@ -1726,6 +1738,8 @@ int submodule_move_head(const char *path, > > if (is_empty_dir(path)) > rmdir_or_warn(path); > + > + submodule_unset_core_worktree(sub); > } > } > out: > diff --git a/submodule.h b/submodule.h > index a680214c01..9e18e9b807 100644 > --- a/submodule.h > +++ b/submodule.h > @@ -131,6 +131,8 @@ int submodule_move_head(const char *path, > const char *new_head, > unsigned flags); > > +void submodule_unset_core_worktree(const struct submodule *sub); > + > /* > * Prepare the "env_array" parameter of a "struct child_process" for executing > * a submodule by clearing any repo-specific environment variables, but > diff --git a/t/lib-submodule-update.sh b/t/lib-submodule-update.sh > index 016391723c..51d4555549 100755 > --- a/t/lib-submodule-update.sh > +++ b/t/lib-submodule-update.sh > @@ -709,7 +709,8 @@ test_submodule_recursing_with_args_common() { > git branch -t remove_sub1 origin/remove_sub1 && > $command remove_sub1 && > test_superproject_content origin/remove_sub1 && > - ! test -e sub1 > + ! test -e sub1 && > + test_must_fail git config -f .git/modules/sub1/config core.worktree > ) > ' > # ... absorbing a .git directory along the way. ^ permalink raw reply [flat|nested] 22+ messages in thread
* [PATCH 3/4] submodule--helper: fix BUG message in ensure_core_worktree 2018-12-07 23:54 [PATCH 0/4] Stefan Beller 2018-12-07 23:54 ` [PATCH 1/4] submodule update: add regression test with old style setups Stefan Beller 2018-12-07 23:54 ` [PATCH 2/4] submodule: unset core.worktree if no working tree is present Stefan Beller @ 2018-12-07 23:54 ` Stefan Beller 2018-12-08 6:55 ` Junio C Hamano 2018-12-07 23:54 ` [PATCH 4/4] submodule deinit: unset core.worktree Stefan Beller 2018-12-08 5:57 ` [PATCH 0/4] Junio C Hamano 4 siblings, 1 reply; 22+ messages in thread From: Stefan Beller @ 2018-12-07 23:54 UTC (permalink / raw) To: git; +Cc: Stefan Beller Shortly after f178c13fda (Revert "Merge branch 'sb/submodule-core-worktree'", 2018-09-07), we had another series that implemented partially the same, ensuring that core.worktree was set in a checked out submodule, namely 74d4731da1 (submodule--helper: replace connect-gitdir-workingtree by ensure-core-worktree, 2018-08-13) As the series 4d6d6ef1fc (Merge branch 'sb/submodule-update-in-c', 2018-09-17) has different goals than the reverted series 7e25437d35 (Merge branch 'sb/submodule-core-worktree', 2018-07-18), I'd wanted to replay the series on top of it to reach the goal of having `core.worktree` correctly set when the submodules worktree is present, and unset when the worktree is not present. The replay resulted in a strange merge conflict highlighting that the BUG message was not changed in 74d4731da1 (submodule--helper: replace connect-gitdir-workingtree by ensure-core-worktree, 2018-08-13). Fix the error message. Signed-off-by: Stefan Beller <sbeller@google.com> --- builtin/submodule--helper.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c index d38113a31a..31ac30cf2f 100644 --- a/builtin/submodule--helper.c +++ b/builtin/submodule--helper.c @@ -2045,7 +2045,7 @@ static int ensure_core_worktree(int argc, const char **argv, const char *prefix) struct repository subrepo; if (argc != 2) - BUG("submodule--helper connect-gitdir-workingtree <name> <path>"); + BUG("submodule--helper ensure-core-worktree <path>"); path = argv[1]; -- 2.20.0.rc2.403.gdbc3b29805-goog ^ permalink raw reply related [flat|nested] 22+ messages in thread
* Re: [PATCH 3/4] submodule--helper: fix BUG message in ensure_core_worktree 2018-12-07 23:54 ` [PATCH 3/4] submodule--helper: fix BUG message in ensure_core_worktree Stefan Beller @ 2018-12-08 6:55 ` Junio C Hamano 2018-12-12 22:46 ` Stefan Beller 0 siblings, 1 reply; 22+ messages in thread From: Junio C Hamano @ 2018-12-08 6:55 UTC (permalink / raw) To: Stefan Beller; +Cc: git Stefan Beller <sbeller@google.com> writes: > Shortly after f178c13fda (Revert "Merge branch > 'sb/submodule-core-worktree'", 2018-09-07), we had another series > that implemented partially the same, ensuring that core.worktree was > set in a checked out submodule, namely 74d4731da1 (submodule--helper: > replace connect-gitdir-workingtree by ensure-core-worktree, 2018-08-13) > > As the series 4d6d6ef1fc (Merge branch 'sb/submodule-update-in-c', > 2018-09-17) has different goals than the reverted series 7e25437d35 > (Merge branch 'sb/submodule-core-worktree', 2018-07-18), I'd wanted to > replay the series on top of it to reach the goal of having `core.worktree` > correctly set when the submodules worktree is present, and unset when the > worktree is not present. > > The replay resulted in a strange merge conflict highlighting that > the BUG message was not changed in 74d4731da1 (submodule--helper: > replace connect-gitdir-workingtree by ensure-core-worktree, 2018-08-13). > > Fix the error message. > > Signed-off-by: Stefan Beller <sbeller@google.com> > --- Unlike the step 2/4 I commented on, this does explain what this wants to do and why, at least when looked from sideways. Is the above saying the same as the following two-liner? An ealier mistake while rebasing to produce 74d4731da1 failed to update this BUG message. Fix this. > builtin/submodule--helper.c | 2 +- > 1 file changed, 1 insertion(+), 1 deletion(-) > > diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c > index d38113a31a..31ac30cf2f 100644 > --- a/builtin/submodule--helper.c > +++ b/builtin/submodule--helper.c > @@ -2045,7 +2045,7 @@ static int ensure_core_worktree(int argc, const char **argv, const char *prefix) > struct repository subrepo; > > if (argc != 2) > - BUG("submodule--helper connect-gitdir-workingtree <name> <path>"); > + BUG("submodule--helper ensure-core-worktree <path>"); > > path = argv[1]; ^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [PATCH 3/4] submodule--helper: fix BUG message in ensure_core_worktree 2018-12-08 6:55 ` Junio C Hamano @ 2018-12-12 22:46 ` Stefan Beller 2018-12-13 3:14 ` Junio C Hamano 0 siblings, 1 reply; 22+ messages in thread From: Stefan Beller @ 2018-12-12 22:46 UTC (permalink / raw) To: Junio C Hamano; +Cc: git > Unlike the step 2/4 I commented on, this does explain what this > wants to do and why, at least when looked from sideways. Is the > above saying the same as the following two-liner? > > An ealier mistake while rebasing to produce 74d4731da1 > failed to update this BUG message. Fix this. I am not sure if it was rebasing, which was executed mistakenly. So maybe just saying "74d4731da1 contains a faulty BUG message. Fix it." would do. The intent of the longer message was to shed light in how I found the BUG (ie. I did not see the BUG message, which would ask me to actually fix a bug, but found it via code inspection), which I thought was valuable information, too. ^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [PATCH 3/4] submodule--helper: fix BUG message in ensure_core_worktree 2018-12-12 22:46 ` Stefan Beller @ 2018-12-13 3:14 ` Junio C Hamano 0 siblings, 0 replies; 22+ messages in thread From: Junio C Hamano @ 2018-12-13 3:14 UTC (permalink / raw) To: Stefan Beller; +Cc: git Stefan Beller <sbeller@google.com> writes: >> Unlike the step 2/4 I commented on, this does explain what this >> wants to do and why, at least when looked from sideways. Is the >> above saying the same as the following two-liner? >> >> An ealier mistake while rebasing to produce 74d4731da1 >> failed to update this BUG message. Fix this. > > I am not sure if it was rebasing, which was executed mistakenly. > So maybe just saying "74d4731da1 contains a faulty BUG > message. Fix it." would do. > > The intent of the longer message was to shed light in how I found > the BUG (ie. I did not see the BUG message, which would ask me > to actually fix a bug, but found it via code inspection), which I > thought was valuable information, too. I guess that it could be stated in a way to make it valuable, but in the presented text, I somehow found it was making the more important part of the description (i.e. "this patch fixes a mistake made by 74d4731da1") buried and harder to grok. Thanks. ^ permalink raw reply [flat|nested] 22+ messages in thread
* [PATCH 4/4] submodule deinit: unset core.worktree 2018-12-07 23:54 [PATCH 0/4] Stefan Beller ` (2 preceding siblings ...) 2018-12-07 23:54 ` [PATCH 3/4] submodule--helper: fix BUG message in ensure_core_worktree Stefan Beller @ 2018-12-07 23:54 ` Stefan Beller 2018-12-08 7:03 ` Junio C Hamano 2018-12-08 5:57 ` [PATCH 0/4] Junio C Hamano 4 siblings, 1 reply; 22+ messages in thread From: Stefan Beller @ 2018-12-07 23:54 UTC (permalink / raw) To: git; +Cc: Stefan Beller This re-introduces 984cd77ddb (submodule deinit: unset core.worktree, 2018-06-18), which was reverted as part of f178c13fda (Revert "Merge branch 'sb/submodule-core-worktree'", 2018-09-07) The whole series was reverted as the offending commit e98317508c (submodule: ensure core.worktree is set after update, 2018-06-18) was relied on by other commits such as 984cd77ddb. Keep the offending commit reverted, but its functionality came back via 4d6d6ef1fc (Merge branch 'sb/submodule-update-in-c', 2018-09-17), such that we can reintroduce 984cd77ddb now. Signed-off-by: Stefan Beller <sbeller@google.com> --- builtin/submodule--helper.c | 2 ++ t/lib-submodule-update.sh | 2 +- t/t7400-submodule-basic.sh | 5 +++++ 3 files changed, 8 insertions(+), 1 deletion(-) diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c index 31ac30cf2f..672b74db89 100644 --- a/builtin/submodule--helper.c +++ b/builtin/submodule--helper.c @@ -1131,6 +1131,8 @@ static void deinit_submodule(const char *path, const char *prefix, if (!(flags & OPT_QUIET)) printf(format, displaypath); + submodule_unset_core_worktree(sub); + strbuf_release(&sb_rm); } diff --git a/t/lib-submodule-update.sh b/t/lib-submodule-update.sh index 51d4555549..5b56b23166 100755 --- a/t/lib-submodule-update.sh +++ b/t/lib-submodule-update.sh @@ -235,7 +235,7 @@ reset_work_tree_to_interested () { then mkdir -p submodule_update/.git/modules/sub1/modules && cp -r submodule_update_repo/.git/modules/sub1/modules/sub2 submodule_update/.git/modules/sub1/modules/sub2 - GIT_WORK_TREE=. git -C submodule_update/.git/modules/sub1/modules/sub2 config --unset core.worktree + # core.worktree is unset for sub2 as it is not checked out fi && # indicate we are interested in the submodule: git -C submodule_update config submodule.sub1.url "bogus" && diff --git a/t/t7400-submodule-basic.sh b/t/t7400-submodule-basic.sh index 76a7cb0af7..aba2d4d6ee 100755 --- a/t/t7400-submodule-basic.sh +++ b/t/t7400-submodule-basic.sh @@ -984,6 +984,11 @@ test_expect_success 'submodule deinit should remove the whole submodule section rmdir init ' +test_expect_success 'submodule deinit should unset core.worktree' ' + test_path_is_file .git/modules/example/config && + test_must_fail git config -f .git/modules/example/config core.worktree +' + test_expect_success 'submodule deinit from subdirectory' ' git submodule update --init && git config submodule.example.foo bar && -- 2.20.0.rc2.403.gdbc3b29805-goog ^ permalink raw reply related [flat|nested] 22+ messages in thread
* Re: [PATCH 4/4] submodule deinit: unset core.worktree 2018-12-07 23:54 ` [PATCH 4/4] submodule deinit: unset core.worktree Stefan Beller @ 2018-12-08 7:03 ` Junio C Hamano 0 siblings, 0 replies; 22+ messages in thread From: Junio C Hamano @ 2018-12-08 7:03 UTC (permalink / raw) To: Stefan Beller; +Cc: git Stefan Beller <sbeller@google.com> writes: > This re-introduces 984cd77ddb (submodule deinit: unset core.worktree, > 2018-06-18), which was reverted as part of f178c13fda (Revert "Merge > branch 'sb/submodule-core-worktree'", 2018-09-07) > > The whole series was reverted as the offending commit e98317508c > (submodule: ensure core.worktree is set after update, 2018-06-18) > was relied on by other commits such as 984cd77ddb. > > Keep the offending commit reverted, but its functionality came back via > 4d6d6ef1fc (Merge branch 'sb/submodule-update-in-c', 2018-09-17), such > that we can reintroduce 984cd77ddb now. None of the above three explains the most important thing directly, so readers fail to grasp what the main theme of the three-patch series is, without looking at the commits that were reverted already. Is the theme of the overall series to make sure core.worktree is set to point at the working tree when submodule's working tree is instantiated, and unset it when it is not? 2/4 was also explained (in the original) that it wants to unset and did so when "move_head" gets called. This one does the unset when a submodule is deinited. Are these the only two cases a submodule loses its working tree? If so, the log message for this step should declare victory by ending with something like ... as we covered the only other case in which a submodule loses its working tree in the earlier step (i.e. switching branches of top-level project to move to a commit that did not have the submodule), this makes the code always maintain core.worktree correctly unset when there is no working tree for a submodule. Thanks. I think I agree with what the series wants to do (if I read what it wants to do correctly, that is). > Signed-off-by: Stefan Beller <sbeller@google.com> > --- > builtin/submodule--helper.c | 2 ++ > t/lib-submodule-update.sh | 2 +- > t/t7400-submodule-basic.sh | 5 +++++ > 3 files changed, 8 insertions(+), 1 deletion(-) > > diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c > index 31ac30cf2f..672b74db89 100644 > --- a/builtin/submodule--helper.c > +++ b/builtin/submodule--helper.c > @@ -1131,6 +1131,8 @@ static void deinit_submodule(const char *path, const char *prefix, > if (!(flags & OPT_QUIET)) > printf(format, displaypath); > > + submodule_unset_core_worktree(sub); > + > strbuf_release(&sb_rm); > } > > diff --git a/t/lib-submodule-update.sh b/t/lib-submodule-update.sh > index 51d4555549..5b56b23166 100755 > --- a/t/lib-submodule-update.sh > +++ b/t/lib-submodule-update.sh > @@ -235,7 +235,7 @@ reset_work_tree_to_interested () { > then > mkdir -p submodule_update/.git/modules/sub1/modules && > cp -r submodule_update_repo/.git/modules/sub1/modules/sub2 submodule_update/.git/modules/sub1/modules/sub2 > - GIT_WORK_TREE=. git -C submodule_update/.git/modules/sub1/modules/sub2 config --unset core.worktree > + # core.worktree is unset for sub2 as it is not checked out > fi && > # indicate we are interested in the submodule: > git -C submodule_update config submodule.sub1.url "bogus" && > diff --git a/t/t7400-submodule-basic.sh b/t/t7400-submodule-basic.sh > index 76a7cb0af7..aba2d4d6ee 100755 > --- a/t/t7400-submodule-basic.sh > +++ b/t/t7400-submodule-basic.sh > @@ -984,6 +984,11 @@ test_expect_success 'submodule deinit should remove the whole submodule section > rmdir init > ' > > +test_expect_success 'submodule deinit should unset core.worktree' ' > + test_path_is_file .git/modules/example/config && > + test_must_fail git config -f .git/modules/example/config core.worktree > +' > + > test_expect_success 'submodule deinit from subdirectory' ' > git submodule update --init && > git config submodule.example.foo bar && ^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [PATCH 0/4] 2018-12-07 23:54 [PATCH 0/4] Stefan Beller ` (3 preceding siblings ...) 2018-12-07 23:54 ` [PATCH 4/4] submodule deinit: unset core.worktree Stefan Beller @ 2018-12-08 5:57 ` Junio C Hamano 2018-12-12 22:35 ` Stefan Beller 2018-12-14 23:59 ` [PATCH 0/4] submodules: unset core.worktree when no working tree present Stefan Beller 4 siblings, 2 replies; 22+ messages in thread From: Junio C Hamano @ 2018-12-08 5:57 UTC (permalink / raw) To: Stefan Beller; +Cc: git Stefan Beller <sbeller@google.com> writes: > A couple days before the 2.19 release we had a bug report about > broken submodules[1] and reverted[2] the commits leading up to them. > > The behavior of said bug fixed itself by taking a different approach[3], > specifically by a weaker enforcement of having `core.worktree` set in a > submodule [4]. > > The revert [2] was overly broad as we neared the release, such that we wanted > to rather keep the known buggy behavior of always having `core.worktree` set, > rather than figuring out how to fix the new bug of having 'git submodule update' > not working in old style repository setups. > > This series re-introduces those reverted patches, with no changes in code, > but with drastically changed commit messages, as those focus on why it is safe > to re-introduce them instead of explaining the desire for the change. The above was a bit too cryptic for me to grok, so let me try rephrasing to see if I got them all correctly. - three-patch series leading to 984cd77ddb were meant to fix some bug, but the series itself was buggy and caused problems; we got rid of them - the problem 984cd77ddb wanted to fix was fixed differently without reintroducing the problem three-patch series introduced. That fix is already with us since 4d6d6ef1fc. - now these three changes that were problematic in the past is resent without any update (other than that it has one preparatory patch to add tests). Is that what is going on? Obviously I am not getting "the other" benefit we wanted to gain out of these three patches (because the above description fails to explain what that is), other than to fix the issue that was fixed by 4d6d6ef1fc. Sorry for being puzzled... > [1] https://public-inbox.org/git/2659750.rG6xLiZASK@twilight > [2] f178c13fda (Revert "Merge branch 'sb/submodule-core-worktree'", 2018-09-07) > [3] 4d6d6ef1fc (Merge branch 'sb/submodule-update-in-c', 2018-09-17) > [4] 74d4731da1 (submodule--helper: replace connect-gitdir-workingtree by ensure-core-worktree, 2018-08-13) > > Stefan Beller (4): > submodule update: add regression test with old style setups > submodule: unset core.worktree if no working tree is present > submodule--helper: fix BUG message in ensure_core_worktree > submodule deinit: unset core.worktree > > builtin/submodule--helper.c | 4 +++- > submodule.c | 14 ++++++++++++++ > submodule.h | 2 ++ > t/lib-submodule-update.sh | 5 +++-- > t/t7400-submodule-basic.sh | 5 +++++ > t/t7412-submodule-absorbgitdirs.sh | 7 ++++++- > 6 files changed, 33 insertions(+), 4 deletions(-) ^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [PATCH 0/4] 2018-12-08 5:57 ` [PATCH 0/4] Junio C Hamano @ 2018-12-12 22:35 ` Stefan Beller 2018-12-13 3:15 ` Junio C Hamano 2018-12-14 23:59 ` [PATCH 0/4] submodules: unset core.worktree when no working tree present Stefan Beller 1 sibling, 1 reply; 22+ messages in thread From: Stefan Beller @ 2018-12-12 22:35 UTC (permalink / raw) To: Junio C Hamano; +Cc: git On Fri, Dec 7, 2018 at 9:57 PM Junio C Hamano <gitster@pobox.com> wrote: > > Stefan Beller <sbeller@google.com> writes: > > > A couple days before the 2.19 release we had a bug report about > > broken submodules[1] and reverted[2] the commits leading up to them. > > > > The behavior of said bug fixed itself by taking a different approach[3], > > specifically by a weaker enforcement of having `core.worktree` set in a > > submodule [4]. > > > > The revert [2] was overly broad as we neared the release, such that we wanted > > to rather keep the known buggy behavior of always having `core.worktree` set, > > rather than figuring out how to fix the new bug of having 'git submodule update' > > not working in old style repository setups. > > > > This series re-introduces those reverted patches, with no changes in code, > > but with drastically changed commit messages, as those focus on why it is safe > > to re-introduce them instead of explaining the desire for the change. > > The above was a bit too cryptic for me to grok, so let me try > rephrasing to see if I got them all correctly. > > - three-patch series leading to 984cd77ddb were meant to fix some > bug, but the series itself was buggy and caused problems; we got > rid of them yes. > - the problem 984cd77ddb wanted to fix was fixed differently e98317508c02* > without reintroducing the problem three-patch series introduced. > That fix is already with us since 4d6d6ef1fc. yes. > - now these three changes that were problematic in the past is > resent without any update (other than that it has one preparatory > patch to add tests). One of the three changes was problematic, (e98317508c02), the other two are good (in company of the third). But those two were not good on their own, which is why we reverted all three at once. Now that we have a different approach for the third, we could re-introduce the two. (4fa4f90ccd8, 984cd77ddbf0) We do that, but with precaution (an extra test); additional careful reading found a typo, hence we have "a third" patch, but that is totally different than what above was referred to "one of three". > Is that what is going on? Obviously I am not getting "the other" > benefit we wanted to gain out of these three patches (because the > above description fails to explain what that is), other than to fix > the issue that was fixed by 4d6d6ef1fc. The other benefit refers to 7e25437d35 (Merge branch 'sb/submodule-core-worktree', 2018-07-18) which was reverted as a whole. It's goal was to handle core.worktree appropriately. (Instead of having it there all the time, only have it when a working tree is present) > Sorry for being puzzled... This means I need to revamp the commit messages and cover letter altogether. Stefan ^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [PATCH 0/4] 2018-12-12 22:35 ` Stefan Beller @ 2018-12-13 3:15 ` Junio C Hamano 0 siblings, 0 replies; 22+ messages in thread From: Junio C Hamano @ 2018-12-13 3:15 UTC (permalink / raw) To: Stefan Beller; +Cc: git Stefan Beller <sbeller@google.com> writes: >> - now these three changes that were problematic in the past is >> resent without any update (other than that it has one preparatory >> patch to add tests). > > One of the three changes was problematic, (e98317508c02), > the other two are good (in company of the third). Ah, that is what I failed to read. > This means I need to revamp the commit messages and > cover letter altogether. I guess that would help future readers. Thanks. ^ permalink raw reply [flat|nested] 22+ messages in thread
* [PATCH 0/4] submodules: unset core.worktree when no working tree present 2018-12-08 5:57 ` [PATCH 0/4] Junio C Hamano 2018-12-12 22:35 ` Stefan Beller @ 2018-12-14 23:59 ` Stefan Beller 2018-12-14 23:59 ` [PATCH 1/4] submodule update: add regression test with old style setups Stefan Beller ` (3 more replies) 1 sibling, 4 replies; 22+ messages in thread From: Stefan Beller @ 2018-12-14 23:59 UTC (permalink / raw) To: gitster; +Cc: git, sbeller v2: I reworded the commit messages to explain the patches from the ground up instead of only linking to the old commits, that got reverted. > Just pretend that the ealier commits and their reversion never > happened, and further pretend that we are doing the best thing that > should happen to our codebase. I disagree with that first stance (I can freely admit those commits happened), but agree on the second point, so I explained why the code is the best for the code base now. So I kept those pointers in there, too, to make it easier for future code archeologists. v1: A couple days before the 2.19 release we had a bug report about broken submodules[1] and reverted[2] the commits leading up to them. The behavior of said bug fixed itself by taking a different approach[3], specifically by a weaker enforcement of having `core.worktree` set in a submodule [4]. The revert [2] was overly broad as we neared the release, such that we wanted to rather keep the known buggy behavior of always having `core.worktree` set, rather than figuring out how to fix the new bug of having 'git submodule update' not working in old style repository setups. This series re-introduces those reverted patches, with no changes in code, but with drastically changed commit messages, as those focus on why it is safe to re-introduce them instead of explaining the desire for the change. [1] https://public-inbox.org/git/2659750.rG6xLiZASK@twilight [2] f178c13fda (Revert "Merge branch 'sb/submodule-core-worktree'", 2018-09-07) [3] 4d6d6ef1fc (Merge branch 'sb/submodule-update-in-c', 2018-09-17) [4] 74d4731da1 (submodule--helper: replace connect-gitdir-workingtree by ensure-core-worktree, 2018-08-13) Stefan Beller (4): submodule update: add regression test with old style setups submodule: unset core.worktree if no working tree is present submodule--helper: fix BUG message in ensure_core_worktree submodule deinit: unset core.worktree builtin/submodule--helper.c | 4 +++- submodule.c | 14 ++++++++++++++ submodule.h | 2 ++ t/lib-submodule-update.sh | 5 +++-- t/t7400-submodule-basic.sh | 5 +++++ t/t7412-submodule-absorbgitdirs.sh | 7 ++++++- 6 files changed, 33 insertions(+), 4 deletions(-) -- 2.20.0.405.gbc1bbc6f85-goog ^ permalink raw reply [flat|nested] 22+ messages in thread
* [PATCH 1/4] submodule update: add regression test with old style setups 2018-12-14 23:59 ` [PATCH 0/4] submodules: unset core.worktree when no working tree present Stefan Beller @ 2018-12-14 23:59 ` Stefan Beller 2018-12-26 18:21 ` Junio C Hamano 2018-12-14 23:59 ` [PATCH 2/4] submodule: unset core.worktree if no working tree is present Stefan Beller ` (2 subsequent siblings) 3 siblings, 1 reply; 22+ messages in thread From: Stefan Beller @ 2018-12-14 23:59 UTC (permalink / raw) To: gitster; +Cc: git, sbeller As f178c13fda (Revert "Merge branch 'sb/submodule-core-worktree'", 2018-09-07) was produced shortly before a release, nobody asked for a regression test to be included. Add a regression test that makes sure that the invocation of `git submodule update` on old setups doesn't produce errors as pointed out in f178c13fda. The place to add such a regression test may look odd in t7412, but that is the best place as there we setup old style submodule setups explicitly. Signed-off-by: Stefan Beller <sbeller@google.com> --- t/t7412-submodule-absorbgitdirs.sh | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/t/t7412-submodule-absorbgitdirs.sh b/t/t7412-submodule-absorbgitdirs.sh index ce74c12da2..1cfa150768 100755 --- a/t/t7412-submodule-absorbgitdirs.sh +++ b/t/t7412-submodule-absorbgitdirs.sh @@ -75,7 +75,12 @@ test_expect_success 're-setup nested submodule' ' GIT_WORK_TREE=../../../nested git -C sub1/.git/modules/nested config \ core.worktree "../../../nested" && # make sure this re-setup is correct - git status --ignore-submodules=none + git status --ignore-submodules=none && + + # also make sure this old setup does not regress + git submodule update --init --recursive >out 2>err && + test_must_be_empty out && + test_must_be_empty err ' test_expect_success 'absorb the git dir in a nested submodule' ' -- 2.20.0.405.gbc1bbc6f85-goog ^ permalink raw reply related [flat|nested] 22+ messages in thread
* Re: [PATCH 1/4] submodule update: add regression test with old style setups 2018-12-14 23:59 ` [PATCH 1/4] submodule update: add regression test with old style setups Stefan Beller @ 2018-12-26 18:21 ` Junio C Hamano 0 siblings, 0 replies; 22+ messages in thread From: Junio C Hamano @ 2018-12-26 18:21 UTC (permalink / raw) To: Stefan Beller; +Cc: git Stefan Beller <sbeller@google.com> writes: > The place to add such a regression test may look odd in t7412, but > that is the best place as there we setup old style submodule setups > explicitly. Makes sense; thanks. > > Signed-off-by: Stefan Beller <sbeller@google.com> > --- > t/t7412-submodule-absorbgitdirs.sh | 7 ++++++- > 1 file changed, 6 insertions(+), 1 deletion(-) > > diff --git a/t/t7412-submodule-absorbgitdirs.sh b/t/t7412-submodule-absorbgitdirs.sh > index ce74c12da2..1cfa150768 100755 > --- a/t/t7412-submodule-absorbgitdirs.sh > +++ b/t/t7412-submodule-absorbgitdirs.sh > @@ -75,7 +75,12 @@ test_expect_success 're-setup nested submodule' ' > GIT_WORK_TREE=../../../nested git -C sub1/.git/modules/nested config \ > core.worktree "../../../nested" && > # make sure this re-setup is correct > - git status --ignore-submodules=none > + git status --ignore-submodules=none && > + > + # also make sure this old setup does not regress > + git submodule update --init --recursive >out 2>err && > + test_must_be_empty out && > + test_must_be_empty err > ' > > test_expect_success 'absorb the git dir in a nested submodule' ' ^ permalink raw reply [flat|nested] 22+ messages in thread
* [PATCH 2/4] submodule: unset core.worktree if no working tree is present 2018-12-14 23:59 ` [PATCH 0/4] submodules: unset core.worktree when no working tree present Stefan Beller 2018-12-14 23:59 ` [PATCH 1/4] submodule update: add regression test with old style setups Stefan Beller @ 2018-12-14 23:59 ` Stefan Beller 2018-12-26 18:27 ` Junio C Hamano 2018-12-14 23:59 ` [PATCH 3/4] submodule--helper: fix BUG message in ensure_core_worktree Stefan Beller 2018-12-14 23:59 ` [PATCH 4/4] submodule deinit: unset core.worktree Stefan Beller 3 siblings, 1 reply; 22+ messages in thread From: Stefan Beller @ 2018-12-14 23:59 UTC (permalink / raw) To: gitster; +Cc: git, sbeller When a submodules work tree is removed, we should unset its core.worktree setting as the worktree is no longer present. This is not just in line with the conceptual view of submodules, but it fixes an inconvenience for looking at submodules that are not checked out: git clone --recurse-submodules git://github.com/git/git && cd git && git checkout --recurse-submodules v2.13.0 git -C .git/modules/sha1collisiondetection log fatal: cannot chdir to '../../../sha1collisiondetection': \ No such file or directory With this patch applied, the final call to git log works instead of dying in its setup, as the checkout will unset the core.worktree setting such that following log will be run in a bare repository. This patch covers all commands that are in the unpack machinery, i.e. checkout, read-tree, reset. A follow up patch will address "git submodule deinit", which will also make use of the new function submodule_unset_core_worktree(), which is why we expose it in this patch. This patch was authored as 4fa4f90ccd (submodule: unset core.worktree if no working tree is present, 2018-06-12), which was reverted as part of f178c13fda (Revert "Merge branch 'sb/submodule-core-worktree'", 2018-09-07). The revert was needed as the nearby commit e98317508c (submodule: ensure core.worktree is set after update, 2018-06-18) is faulty and at the time of 7e25437d35 (Merge branch 'sb/submodule-core-worktree', 2018-07-18) we could not revert the faulty commit only, as they were depending on each other: If core.worktree is unset, we have to have ways to ensure that it is set again once the working tree reappears again. Now that 4d6d6ef1fc (Merge branch 'sb/submodule-update-in-c', 2018-09-17), specifically 74d4731da1 (submodule--helper: replace connect-gitdir-workingtree by ensure-core-worktree, 2018-08-13) is present, we already check and ensure core.worktree is set when populating a new work tree, such that we can re-introduce the commits that unset core.worktree when removing the worktree. Signed-off-by: Stefan Beller <sbeller@google.com> Signed-off-by: Junio C Hamano <gitster@pobox.com> Signed-off-by: Stefan Beller <sbeller@google.com> --- submodule.c | 14 ++++++++++++++ submodule.h | 2 ++ t/lib-submodule-update.sh | 3 ++- 3 files changed, 18 insertions(+), 1 deletion(-) diff --git a/submodule.c b/submodule.c index 6415cc5580..d393e947e6 100644 --- a/submodule.c +++ b/submodule.c @@ -1561,6 +1561,18 @@ int bad_to_remove_submodule(const char *path, unsigned flags) return ret; } +void submodule_unset_core_worktree(const struct submodule *sub) +{ + char *config_path = xstrfmt("%s/modules/%s/config", + get_git_common_dir(), sub->name); + + if (git_config_set_in_file_gently(config_path, "core.worktree", NULL)) + warning(_("Could not unset core.worktree setting in submodule '%s'"), + sub->path); + + free(config_path); +} + static const char *get_super_prefix_or_empty(void) { const char *s = get_super_prefix(); @@ -1726,6 +1738,8 @@ int submodule_move_head(const char *path, if (is_empty_dir(path)) rmdir_or_warn(path); + + submodule_unset_core_worktree(sub); } } out: diff --git a/submodule.h b/submodule.h index a680214c01..9e18e9b807 100644 --- a/submodule.h +++ b/submodule.h @@ -131,6 +131,8 @@ int submodule_move_head(const char *path, const char *new_head, unsigned flags); +void submodule_unset_core_worktree(const struct submodule *sub); + /* * Prepare the "env_array" parameter of a "struct child_process" for executing * a submodule by clearing any repo-specific environment variables, but diff --git a/t/lib-submodule-update.sh b/t/lib-submodule-update.sh index 016391723c..51d4555549 100755 --- a/t/lib-submodule-update.sh +++ b/t/lib-submodule-update.sh @@ -709,7 +709,8 @@ test_submodule_recursing_with_args_common() { git branch -t remove_sub1 origin/remove_sub1 && $command remove_sub1 && test_superproject_content origin/remove_sub1 && - ! test -e sub1 + ! test -e sub1 && + test_must_fail git config -f .git/modules/sub1/config core.worktree ) ' # ... absorbing a .git directory along the way. -- 2.20.0.405.gbc1bbc6f85-goog ^ permalink raw reply related [flat|nested] 22+ messages in thread
* Re: [PATCH 2/4] submodule: unset core.worktree if no working tree is present 2018-12-14 23:59 ` [PATCH 2/4] submodule: unset core.worktree if no working tree is present Stefan Beller @ 2018-12-26 18:27 ` Junio C Hamano 0 siblings, 0 replies; 22+ messages in thread From: Junio C Hamano @ 2018-12-26 18:27 UTC (permalink / raw) To: Stefan Beller; +Cc: git Stefan Beller <sbeller@google.com> writes: > 2018-09-07). The revert was needed as the nearby commit e98317508c > (submodule: ensure core.worktree is set after update, 2018-06-18) is > faulty and at the time of 7e25437d35 (Merge branch > 'sb/submodule-core-worktree', 2018-07-18) we could not revert the faulty > commit only, as they were depending on each other: If core.worktree is > unset, we have to have ways to ensure that it is set again once > the working tree reappears again. > > Now that 4d6d6ef1fc (Merge branch 'sb/submodule-update-in-c', 2018-09-17), > specifically 74d4731da1 (submodule--helper: replace > connect-gitdir-workingtree by ensure-core-worktree, 2018-08-13) is > present, we already check and ensure core.worktree is set when > populating a new work tree, such that we can re-introduce the commits > that unset core.worktree when removing the worktree. Cleanly explained. Will queue. Thanks. > Signed-off-by: Stefan Beller <sbeller@google.com> > Signed-off-by: Junio C Hamano <gitster@pobox.com> > Signed-off-by: Stefan Beller <sbeller@google.com> > --- > submodule.c | 14 ++++++++++++++ > submodule.h | 2 ++ > t/lib-submodule-update.sh | 3 ++- > 3 files changed, 18 insertions(+), 1 deletion(-) > > diff --git a/submodule.c b/submodule.c > index 6415cc5580..d393e947e6 100644 > --- a/submodule.c > +++ b/submodule.c > @@ -1561,6 +1561,18 @@ int bad_to_remove_submodule(const char *path, unsigned flags) > return ret; > } > > +void submodule_unset_core_worktree(const struct submodule *sub) > +{ > + char *config_path = xstrfmt("%s/modules/%s/config", > + get_git_common_dir(), sub->name); > + > + if (git_config_set_in_file_gently(config_path, "core.worktree", NULL)) > + warning(_("Could not unset core.worktree setting in submodule '%s'"), > + sub->path); > + > + free(config_path); > +} > + > static const char *get_super_prefix_or_empty(void) > { > const char *s = get_super_prefix(); > @@ -1726,6 +1738,8 @@ int submodule_move_head(const char *path, > > if (is_empty_dir(path)) > rmdir_or_warn(path); > + > + submodule_unset_core_worktree(sub); > } > } > out: > diff --git a/submodule.h b/submodule.h > index a680214c01..9e18e9b807 100644 > --- a/submodule.h > +++ b/submodule.h > @@ -131,6 +131,8 @@ int submodule_move_head(const char *path, > const char *new_head, > unsigned flags); > > +void submodule_unset_core_worktree(const struct submodule *sub); > + > /* > * Prepare the "env_array" parameter of a "struct child_process" for executing > * a submodule by clearing any repo-specific environment variables, but > diff --git a/t/lib-submodule-update.sh b/t/lib-submodule-update.sh > index 016391723c..51d4555549 100755 > --- a/t/lib-submodule-update.sh > +++ b/t/lib-submodule-update.sh > @@ -709,7 +709,8 @@ test_submodule_recursing_with_args_common() { > git branch -t remove_sub1 origin/remove_sub1 && > $command remove_sub1 && > test_superproject_content origin/remove_sub1 && > - ! test -e sub1 > + ! test -e sub1 && > + test_must_fail git config -f .git/modules/sub1/config core.worktree > ) > ' > # ... absorbing a .git directory along the way. ^ permalink raw reply [flat|nested] 22+ messages in thread
* [PATCH 3/4] submodule--helper: fix BUG message in ensure_core_worktree 2018-12-14 23:59 ` [PATCH 0/4] submodules: unset core.worktree when no working tree present Stefan Beller 2018-12-14 23:59 ` [PATCH 1/4] submodule update: add regression test with old style setups Stefan Beller 2018-12-14 23:59 ` [PATCH 2/4] submodule: unset core.worktree if no working tree is present Stefan Beller @ 2018-12-14 23:59 ` Stefan Beller 2018-12-14 23:59 ` [PATCH 4/4] submodule deinit: unset core.worktree Stefan Beller 3 siblings, 0 replies; 22+ messages in thread From: Stefan Beller @ 2018-12-14 23:59 UTC (permalink / raw) To: gitster; +Cc: git, sbeller 74d4731da1 (submodule--helper: replace connect-gitdir-workingtree by ensure-core-worktree, 2018-08-13) missed to update the BUG message. Fix it. Signed-off-by: Stefan Beller <sbeller@google.com> --- builtin/submodule--helper.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c index d38113a31a..31ac30cf2f 100644 --- a/builtin/submodule--helper.c +++ b/builtin/submodule--helper.c @@ -2045,7 +2045,7 @@ static int ensure_core_worktree(int argc, const char **argv, const char *prefix) struct repository subrepo; if (argc != 2) - BUG("submodule--helper connect-gitdir-workingtree <name> <path>"); + BUG("submodule--helper ensure-core-worktree <path>"); path = argv[1]; -- 2.20.0.405.gbc1bbc6f85-goog ^ permalink raw reply related [flat|nested] 22+ messages in thread
* [PATCH 4/4] submodule deinit: unset core.worktree 2018-12-14 23:59 ` [PATCH 0/4] submodules: unset core.worktree when no working tree present Stefan Beller ` (2 preceding siblings ...) 2018-12-14 23:59 ` [PATCH 3/4] submodule--helper: fix BUG message in ensure_core_worktree Stefan Beller @ 2018-12-14 23:59 ` Stefan Beller 3 siblings, 0 replies; 22+ messages in thread From: Stefan Beller @ 2018-12-14 23:59 UTC (permalink / raw) To: gitster; +Cc: git, sbeller When a submodule is deinit'd, the working tree is gone, so the setting of core.worktree is bogus. Unset it. As we covered the only other case in which a submodule loses its working tree in the earlier step (i.e. switching branches of top-level project to move to a commit that did not have the submodule), this makes the code always maintain core.worktree correctly unset when there is no working tree for a submodule. This re-introduces 984cd77ddb (submodule deinit: unset core.worktree, 2018-06-18), which was reverted as part of f178c13fda (Revert "Merge branch 'sb/submodule-core-worktree'", 2018-09-07) The whole series was reverted as the offending commit e98317508c (submodule: ensure core.worktree is set after update, 2018-06-18) was relied on by other commits such as 984cd77ddb. Keep the offending commit reverted, but its functionality came back via 4d6d6ef1fc (Merge branch 'sb/submodule-update-in-c', 2018-09-17), such that we can reintroduce 984cd77ddb now. Signed-off-by: Stefan Beller <sbeller@google.com> --- builtin/submodule--helper.c | 2 ++ t/lib-submodule-update.sh | 2 +- t/t7400-submodule-basic.sh | 5 +++++ 3 files changed, 8 insertions(+), 1 deletion(-) diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c index 31ac30cf2f..672b74db89 100644 --- a/builtin/submodule--helper.c +++ b/builtin/submodule--helper.c @@ -1131,6 +1131,8 @@ static void deinit_submodule(const char *path, const char *prefix, if (!(flags & OPT_QUIET)) printf(format, displaypath); + submodule_unset_core_worktree(sub); + strbuf_release(&sb_rm); } diff --git a/t/lib-submodule-update.sh b/t/lib-submodule-update.sh index 51d4555549..5b56b23166 100755 --- a/t/lib-submodule-update.sh +++ b/t/lib-submodule-update.sh @@ -235,7 +235,7 @@ reset_work_tree_to_interested () { then mkdir -p submodule_update/.git/modules/sub1/modules && cp -r submodule_update_repo/.git/modules/sub1/modules/sub2 submodule_update/.git/modules/sub1/modules/sub2 - GIT_WORK_TREE=. git -C submodule_update/.git/modules/sub1/modules/sub2 config --unset core.worktree + # core.worktree is unset for sub2 as it is not checked out fi && # indicate we are interested in the submodule: git -C submodule_update config submodule.sub1.url "bogus" && diff --git a/t/t7400-submodule-basic.sh b/t/t7400-submodule-basic.sh index 76a7cb0af7..aba2d4d6ee 100755 --- a/t/t7400-submodule-basic.sh +++ b/t/t7400-submodule-basic.sh @@ -984,6 +984,11 @@ test_expect_success 'submodule deinit should remove the whole submodule section rmdir init ' +test_expect_success 'submodule deinit should unset core.worktree' ' + test_path_is_file .git/modules/example/config && + test_must_fail git config -f .git/modules/example/config core.worktree +' + test_expect_success 'submodule deinit from subdirectory' ' git submodule update --init && git config submodule.example.foo bar && -- 2.20.0.405.gbc1bbc6f85-goog ^ permalink raw reply related [flat|nested] 22+ messages in thread
* Broken directory pathname pruning.. @ 2005-05-27 0:41 Linus Torvalds 2005-05-27 6:41 ` [PATCH] Diff updates, fixing pathspec and rename/copy interaction Junio C Hamano 0 siblings, 1 reply; 22+ messages in thread From: Linus Torvalds @ 2005-05-27 0:41 UTC (permalink / raw) To: Junio C Hamano, Git Mailing List The directory-based pathname pruning doesn't work any more. I used to just say git-whatchanged -v -p drivers/usb/ and I just noticed that it doesn't work any more. It _does_ work if I leave the final '/' off the thing. diff-tree itself does this right: that's shown by the fact that with the slash in place, we still do get the right _changelog_ that is restricted to drivers/usb changes, but the diffs themselves are missing. So it seems to be purely "diffcore_pathspec()" that is broken. Btw, I don't think we should call "diffcore_pathspec()" at all in diff-tree, because diff-tree already handles "interesting" paths correctly (and has to do so for performance reasons, since it's not acceptable to expand all the trees and diff them). So in the "git-whatchanged" case the fix is as simple as just removing those two lines, but the bug then continues to exist in the other *diff* programs.. Junio? Linus diff --git a/diff-tree.c b/diff-tree.c --- a/diff-tree.c +++ b/diff-tree.c @@ -268,8 +268,6 @@ static int call_diff_flush(void) diff_flush(DIFF_FORMAT_NO_OUTPUT, 0); return 0; } - if (nr_paths) - diffcore_pathspec(paths); if (header) { if (diff_output_format == DIFF_FORMAT_MACHINE) { const char *ep, *cp; ^ permalink raw reply [flat|nested] 22+ messages in thread
* [PATCH] Diff updates, fixing pathspec and rename/copy interaction. 2005-05-27 0:41 Broken directory pathname pruning Linus Torvalds @ 2005-05-27 6:41 ` Junio C Hamano 2005-05-27 15:56 ` Linus Torvalds 0 siblings, 1 reply; 22+ messages in thread From: Junio C Hamano @ 2005-05-27 6:41 UTC (permalink / raw) To: Linus Torvalds; +Cc: Git Mailing List During the mailing list discussion about diff-tree omitting to call diffcore-pathspec, I realized that the current rename/copy differentiator has a major flaw interacting with pathspec (or any other filepair filters, including pickaxe). The problem was that in order to tell if the rename-copy source still remains in the resulting tree (that is what determines if one of the rename-copy can become a rename or everybody needs to be a copy), diffcore-rename was sending a filepair that records unmodified source downstream, expecting that it reaches resolve_rename_copy() which happens as the final stage before actual output happens. Of course, pathspec and pickaxe can interfere and happily remove that entry, in which case what should be shown as a copy suddenly becomes a rename. The problem was fixed by changing the way diffcore-rename records whether the source file remains in the resulting tree. This patch also introduces an optimization for diff-tree -M and diff-tree -C to throw away implausible rename/copy source candidate by keeping the filesize information of already seen SHA1 object IDs in a cache. This cache is activated only when diff-tree is reading from --stdin (i.e. processing sequence of tree pairs) and when rename detection is used. Pickaxe acquired another option, --pickaxe-all, to diff-* three brothers. When a search string is touched, instead of showing only the changed file that touches that searched string, it shows the entire changeset. This is useful to see the change in context. Signed-off-by: Junio C Hamano <junkio@cox.net> --- diff-cache.c | 13 ++ diff-files.c | 11 +- diff-helper.c | 9 +- diff-tree.c | 16 ++- diff.c | 209 ++++++++++++++++++++++++++++++----------------- diff.h | 18 ++-- diffcore-pathspec.c | 5 - diffcore-pickaxe.c | 79 +++++++++++++---- diffcore-rename.c | 91 +++++++++----------- diffcore.h | 14 +-- git-external-diff-script | 2 t/t4007-rename-3.sh | 103 +++++++++++++++++++++++ 12 files changed, 392 insertions(+), 178 deletions(-) new file (100755): t/t4007-rename-3.sh diff --git a/diff-cache.c b/diff-cache.c --- a/diff-cache.c +++ b/diff-cache.c @@ -5,9 +5,10 @@ static int cached_only = 0; static int diff_output_format = DIFF_FORMAT_HUMAN; static int match_nonexisting = 0; static int detect_rename = 0; -static int reverse_diff = 0; +static int diff_setup_opt = 0; static int diff_score_opt = 0; static const char *pickaxe = NULL; +static int pickaxe_opts = 0; /* A file entry went away or appeared */ static void show_file(const char *prefix, struct cache_entry *ce, unsigned char *sha1, unsigned int mode) @@ -202,13 +203,17 @@ int main(int argc, const char **argv) continue; } if (!strcmp(arg, "-R")) { - reverse_diff = 1; + diff_setup_opt |= DIFF_SETUP_REVERSE; continue; } if (!strcmp(arg, "-S")) { pickaxe = arg + 2; continue; } + if (!strcmp(arg, "--pickaxe-all")) { + pickaxe_opts = DIFF_PICKAXE_ALL; + continue; + } if (!strcmp(arg, "-m")) { match_nonexisting = 1; continue; @@ -224,7 +229,7 @@ int main(int argc, const char **argv) usage(diff_cache_usage); /* The rest is for paths restriction. */ - diff_setup(reverse_diff); + diff_setup(diff_setup_opt); mark_merge_entries(); @@ -238,7 +243,7 @@ int main(int argc, const char **argv) if (detect_rename) diffcore_rename(detect_rename, diff_score_opt); if (pickaxe) - diffcore_pickaxe(pickaxe); + diffcore_pickaxe(pickaxe, pickaxe_opts); if (pathspec) diffcore_pathspec(pathspec); diff_flush(diff_output_format, 1); diff --git a/diff-files.c b/diff-files.c --- a/diff-files.c +++ b/diff-files.c @@ -11,9 +11,10 @@ static const char *diff_files_usage = static int diff_output_format = DIFF_FORMAT_HUMAN; static int detect_rename = 0; -static int reverse_diff = 0; +static int diff_setup_opt = 0; static int diff_score_opt = 0; static const char *pickaxe = NULL; +static int pickaxe_opts = 0; static int silent = 0; static void show_unmerge(const char *path) @@ -51,9 +52,11 @@ int main(int argc, const char **argv) else if (!strcmp(argv[1], "-z")) diff_output_format = DIFF_FORMAT_MACHINE; else if (!strcmp(argv[1], "-R")) - reverse_diff = 1; + diff_setup_opt |= DIFF_SETUP_REVERSE; else if (!strcmp(argv[1], "-S")) pickaxe = argv[1] + 2; + else if (!strcmp(argv[1], "--pickaxe-all")) + pickaxe_opts = DIFF_PICKAXE_ALL; else if (!strncmp(argv[1], "-M", 2)) { diff_score_opt = diff_scoreopt_parse(argv[1]); detect_rename = DIFF_DETECT_RENAME; @@ -75,7 +78,7 @@ int main(int argc, const char **argv) exit(1); } - diff_setup(reverse_diff); + diff_setup(diff_setup_opt); for (i = 0; i < entries; i++) { struct stat st; @@ -116,7 +119,7 @@ int main(int argc, const char **argv) if (detect_rename) diffcore_rename(detect_rename, diff_score_opt); if (pickaxe) - diffcore_pickaxe(pickaxe); + diffcore_pickaxe(pickaxe, pickaxe_opts); if (1 < argc) diffcore_pathspec(argv + 1); diff_flush(diff_output_format, 1); diff --git a/diff-helper.c b/diff-helper.c --- a/diff-helper.c +++ b/diff-helper.c @@ -4,9 +4,9 @@ #include "cache.h" #include "strbuf.h" #include "diff.h" -#include "diffcore.h" /* just for MAX_SCORE */ static const char *pickaxe = NULL; +static int pickaxe_opts = 0; static int line_termination = '\n'; static int inter_name_termination = '\t'; @@ -24,6 +24,8 @@ int main(int ac, const char **av) { else if (av[1][1] == 'S') { pickaxe = av[1] + 2; } + else if (!strcmp(av[1], "--pickaxe-all")) + pickaxe_opts = DIFF_PICKAXE_ALL; else usage(diff_helper_usage); ac--; av++; @@ -78,7 +80,6 @@ int main(int ac, const char **av) { if (status == 'R' || status == 'C') { two_paths = 1; sscanf(cp, "%d", &score); - score = score * MAX_SCORE / 100; if (line_termination) { cp = strchr(cp, inter_name_termination); @@ -129,14 +130,14 @@ int main(int ac, const char **av) { continue; } if (pickaxe) - diffcore_pickaxe(pickaxe); + diffcore_pickaxe(pickaxe, pickaxe_opts); if (1 < ac) diffcore_pathspec(av + 1); diff_flush(DIFF_FORMAT_PATCH, 0); printf("%s\n", sb.buf); } if (pickaxe) - diffcore_pickaxe(pickaxe); + diffcore_pickaxe(pickaxe, pickaxe_opts); if (1 < ac) diffcore_pathspec(av + 1); diff_flush(DIFF_FORMAT_PATCH, 0); diff --git a/diff-tree.c b/diff-tree.c --- a/diff-tree.c +++ b/diff-tree.c @@ -10,9 +10,10 @@ static int show_tree_entry_in_recursive static int read_stdin = 0; static int diff_output_format = DIFF_FORMAT_HUMAN; static int detect_rename = 0; -static int reverse_diff = 0; +static int diff_setup_opt = 0; static int diff_score_opt = 0; static const char *pickaxe = NULL; +static int pickaxe_opts = 0; static const char *header = NULL; static const char *header_prefix = ""; @@ -255,7 +256,7 @@ static int diff_tree_sha1(const unsigned static void call_diff_setup(void) { - diff_setup(reverse_diff); + diff_setup(diff_setup_opt); } static int call_diff_flush(void) @@ -263,7 +264,7 @@ static int call_diff_flush(void) if (detect_rename) diffcore_rename(detect_rename, diff_score_opt); if (pickaxe) - diffcore_pickaxe(pickaxe); + diffcore_pickaxe(pickaxe, pickaxe_opts); if (diff_queue_is_empty()) { diff_flush(DIFF_FORMAT_NO_OUTPUT, 0); return 0; @@ -504,7 +505,7 @@ int main(int argc, const char **argv) continue; } if (!strcmp(arg, "-R")) { - reverse_diff = 1; + diff_setup_opt |= DIFF_SETUP_REVERSE; continue; } if (!strcmp(arg, "-p")) { @@ -516,6 +517,10 @@ int main(int argc, const char **argv) pickaxe = arg + 2; continue; } + if (!strcmp(arg, "--pickaxe-all")) { + pickaxe_opts = DIFF_PICKAXE_ALL; + continue; + } if (!strncmp(arg, "-M", 2)) { detect_rename = DIFF_DETECT_RENAME; diff_score_opt = diff_scoreopt_parse(arg); @@ -580,6 +585,9 @@ int main(int argc, const char **argv) if (!read_stdin) return 0; + if (detect_rename) + diff_setup_opt |= (DIFF_SETUP_USE_SIZE_CACHE | + DIFF_SETUP_USE_CACHE); while (fgets(line, sizeof(line), stdin)) diff_tree_stdin(line); diff --git a/diff.c b/diff.c --- a/diff.c +++ b/diff.c @@ -12,6 +12,7 @@ static const char *diff_opts = "-pu"; static unsigned char null_sha1[20] = { 0, }; static int reverse_diff; +static int use_size_cache; static const char *external_diff(void) { @@ -141,7 +142,7 @@ static void builtin_diff(const char *nam printf("new mode %s\n", temp[1].mode); } if (xfrm_msg && xfrm_msg[0]) - fputs(xfrm_msg, stdout); + puts(xfrm_msg); if (strncmp(temp[0].mode, temp[1].mode, 3)) /* we do not run diff between different kind @@ -222,12 +223,60 @@ static int work_tree_matches(const char return 1; } +static struct sha1_size_cache { + unsigned char sha1[20]; + unsigned long size; +} **sha1_size_cache; +static int sha1_size_cache_nr, sha1_size_cache_alloc; + +static struct sha1_size_cache *locate_size_cache(unsigned char *sha1, + unsigned long size) +{ + int first, last; + struct sha1_size_cache *e; + + first = 0; + last = sha1_size_cache_nr; + while (last > first) { + int next = (last + first) >> 1; + e = sha1_size_cache[next]; + int cmp = memcmp(e->sha1, sha1, 20); + if (!cmp) + return e; + if (cmp < 0) { + last = next; + continue; + } + first = next+1; + } + /* not found */ + if (size == UINT_MAX) + return NULL; + /* insert to make it at "first" */ + if (sha1_size_cache_alloc <= sha1_size_cache_nr) { + sha1_size_cache_alloc = alloc_nr(sha1_size_cache_alloc); + sha1_size_cache = xrealloc(sha1_size_cache, + sha1_size_cache_alloc * + sizeof(*sha1_size_cache)); + } + sha1_size_cache_nr++; + if (first < sha1_size_cache_nr) + memmove(sha1_size_cache + first + 1, sha1_size_cache + first, + (sha1_size_cache_nr - first - 1) * + sizeof(*sha1_size_cache)); + e = xmalloc(sizeof(struct sha1_size_cache)); + sha1_size_cache[first] = e; + memcpy(e->sha1, sha1, 20); + e->size = size; + return e; +} + /* * While doing rename detection and pickaxe operation, we may need to * grab the data for the blob (or file) for our own in-core comparison. * diff_filespec has data and size fields for this purpose. */ -int diff_populate_filespec(struct diff_filespec *s) +int diff_populate_filespec(struct diff_filespec *s, int size_only) { int err = 0; if (!DIFF_FILE_VALID(s)) @@ -235,6 +284,9 @@ int diff_populate_filespec(struct diff_f if (S_ISDIR(s->mode)) return -1; + if (!use_size_cache) + size_only = 0; + if (s->data) return err; if (!s->sha1_valid || @@ -254,6 +306,8 @@ int diff_populate_filespec(struct diff_f s->size = st.st_size; if (!s->size) goto empty; + if (size_only) + return 0; if (S_ISLNK(st.st_mode)) { int ret; s->data = xmalloc(s->size); @@ -273,9 +327,21 @@ int diff_populate_filespec(struct diff_f close(fd); } else { + /* We cannot do size only for SHA1 blobs */ char type[20]; + struct sha1_size_cache *e; + + if (size_only) { + e = locate_size_cache(s->sha1, UINT_MAX); + if (e) { + s->size = e->size; + return 0; + } + } s->data = read_sha1_file(s->sha1, type, &s->size); s->should_free = 1; + if (s->data && size_only) + locate_size_cache(s->sha1, s->size); } return 0; } @@ -361,7 +427,7 @@ static void prepare_temp_file(const char return; } else { - if (diff_populate_filespec(one)) + if (diff_populate_filespec(one, 0)) die("cannot read data blob for %s", one->path); prep_temp_blob(temp, one->data, one->size, one->sha1, one->mode); @@ -492,9 +558,23 @@ static void run_diff(const char *name, run_external_diff(pgm, name, other, one, two, xfrm_msg); } -void diff_setup(int reverse_diff_) +void diff_setup(int flags) { - reverse_diff = reverse_diff_; + if (flags & DIFF_SETUP_REVERSE) + reverse_diff = 1; + if (flags & DIFF_SETUP_USE_CACHE) { + if (!active_cache) + /* read-cache does not die even when it fails + * so it is safe for us to do this here. Also + * it does not smudge active_cache or active_nr + * when it fails, so we do not have to worry about + * cleaning it up oufselves either. + */ + read_cache(); + } + if (flags & DIFF_SETUP_USE_SIZE_CACHE) + use_size_cache = 1; + } struct diff_queue_struct diff_queued_diff; @@ -517,10 +597,18 @@ struct diff_filepair *diff_queue(struct dp->one = one; dp->two = two; dp->score = 0; + dp->source_stays = 0; diff_q(queue, dp); return dp; } +void diff_free_filepair(struct diff_filepair *p) +{ + diff_free_filespec_data(p->one); + diff_free_filespec_data(p->two); + free(p); +} + static void diff_flush_raw(struct diff_filepair *p, int line_termination, int inter_name_termination) @@ -615,7 +703,7 @@ static void diff_flush_patch(struct diff sprintf(msg_, "similarity index %d%%\n" "copy from %s\n" - "copy to %s\n", + "copy to %s", (int)(0.5 + p->score * 100.0/MAX_SCORE), p->one->path, p->two->path); msg = msg_; @@ -624,7 +712,7 @@ static void diff_flush_patch(struct diff sprintf(msg_, "similarity index %d%%\n" "rename old %s\n" - "rename new %s\n", + "rename new %s", (int)(0.5 + p->score * 100.0/MAX_SCORE), p->one->path, p->two->path); msg = msg_; @@ -639,28 +727,6 @@ static void diff_flush_patch(struct diff run_diff(name, other, p->one, p->two, msg); } -int diff_needs_to_stay(struct diff_queue_struct *q, int i, - struct diff_filespec *it) -{ - /* If it will be used in later entry (either stay or used - * as the source of rename/copy), we need to copy, not rename. - */ - while (i < q->nr) { - struct diff_filepair *p = q->queue[i++]; - if (!DIFF_FILE_VALID(p->two)) - continue; /* removed is fine */ - if (strcmp(p->one->path, it->path)) - continue; /* not relevant */ - - /* p has its src set to *it and it is not a delete; - * it will be used for in-place change, rename/copy, - * or just stays there. We cannot rename it out. - */ - return 1; - } - return 0; -} - int diff_queue_is_empty(void) { struct diff_queue_struct *q = &diff_queued_diff; @@ -689,8 +755,8 @@ void diff_debug_filepair(const struct di { diff_debug_filespec(p->one, i, "one"); diff_debug_filespec(p->two, i, "two"); - fprintf(stderr, "score %d, status %c\n", - p->score, p->status ? : '?'); + fprintf(stderr, "score %d, status %c source_stays %d\n", + p->score, p->status ? : '?', p->source_stays); } void diff_debug_queue(const char *msg, struct diff_queue_struct *q) @@ -712,8 +778,6 @@ static void diff_resolve_rename_copy(voi struct diff_filepair *p, *pp; struct diff_queue_struct *q = &diff_queued_diff; - /* This should not depend on the ordering of things. */ - diff_debug_queue("resolve-rename-copy", q); for (i = 0; i < q->nr; i++) { @@ -721,23 +785,28 @@ static void diff_resolve_rename_copy(voi p->status = 0; /* undecided */ if (DIFF_PAIR_UNMERGED(p)) p->status = 'U'; - else if (!DIFF_FILE_VALID((p)->one)) + else if (!DIFF_FILE_VALID(p->one)) p->status = 'N'; - else if (!DIFF_FILE_VALID((p)->two)) { - /* Deletion record should be omitted if there - * are rename/copy entries using this one as - * the source. Then we can say one of them - * is a rename and the rest are copies. + else if (!DIFF_FILE_VALID(p->two)) { + /* Deleted entry may have been picked up by + * another rename-copy entry. So we scan the + * queue and if we find one that uses us as the + * source we do not say delete for this entry. */ - p->status = 'D'; for (j = 0; j < q->nr; j++) { pp = q->queue[j]; - if (!strcmp(pp->one->path, p->one->path) && - strcmp(pp->one->path, pp->two->path)) { + if (!strcmp(p->one->path, pp->one->path) && + pp->score) { + /* rename/copy are always valid + * so we do not say DIFF_FILE_VALID() + * on pp->one and pp->two. + */ p->status = 'X'; break; } } + if (!p->status) + p->status = 'D'; } else if (DIFF_PAIR_TYPE_CHANGED(p)) p->status = 'T'; @@ -746,33 +815,24 @@ static void diff_resolve_rename_copy(voi * whose both sides are valid and of the same type, i.e. * either in-place edit or rename/copy edit. */ - else if (strcmp(p->one->path, p->two->path)) { - /* See if there is somebody else anywhere that - * will keep the path (either modified or - * unmodified). If so, we have to be a copy, - * not a rename. In addition, if there is - * some other rename or copy that comes later - * than us that uses the same source, we - * have to be a copy, not a rename. + else if (p->score) { + if (p->source_stays) { + p->status = 'C'; + continue; + } + /* See if there is some other filepair that + * copies from the same source as us. If so + * we are a copy. Otherwise we are a rename. */ - for (j = 0; j < q->nr; j++) { + for (j = i + 1; j < q->nr; j++) { pp = q->queue[j]; if (strcmp(pp->one->path, p->one->path)) - continue; - if (!strcmp(pp->one->path, pp->two->path)) { - if (DIFF_FILE_VALID(pp->two)) { - /* non-delete */ - p->status = 'C'; - break; - } - continue; - } - /* pp is a rename/copy ... */ - if (i < j) { - /* ... and comes later than us */ - p->status = 'C'; - break; - } + continue; /* not us */ + if (!pp->score) + continue; /* not a rename/copy */ + /* pp is a rename/copy from the same source */ + p->status = 'C'; + break; } if (!p->status) p->status = 'R'; @@ -781,8 +841,11 @@ static void diff_resolve_rename_copy(voi p->one->mode != p->two->mode) p->status = 'M'; else - /* this is a "no-change" entry */ - p->status = 'X'; + /* this is a "no-change" entry. + * should not happen anymore. + * p->status = 'X'; + */ + die("internal error in diffcore: unmodified entry remains"); } diff_debug_queue("resolve-rename-copy done", q); } @@ -817,12 +880,8 @@ void diff_flush(int diff_output_style, i break; } } - for (i = 0; i < q->nr; i++) { - struct diff_filepair *p = q->queue[i]; - diff_free_filespec_data(p->one); - diff_free_filespec_data(p->two); - free(p); - } + for (i = 0; i < q->nr; i++) + diff_free_filepair(q->queue[i]); free(q->queue); q->queue = NULL; q->nr = q->alloc = 0; @@ -883,7 +942,7 @@ void diff_helper_input(unsigned old_mode if (new_mode) fill_filespec(two, new_sha1, new_mode); dp = diff_queue(&diff_queued_diff, one, two); - dp->score = score; + dp->score = score * MAX_SCORE / 100; dp->status = status; } diff --git a/diff.h b/diff.h --- a/diff.h +++ b/diff.h @@ -28,22 +28,28 @@ extern void diff_unmerge(const char *pat extern int diff_scoreopt_parse(const char *opt); -#define DIFF_FORMAT_HUMAN 0 -#define DIFF_FORMAT_MACHINE 1 -#define DIFF_FORMAT_PATCH 2 -#define DIFF_FORMAT_NO_OUTPUT 3 -extern void diff_setup(int reverse); +#define DIFF_SETUP_REVERSE 1 +#define DIFF_SETUP_USE_CACHE 2 +#define DIFF_SETUP_USE_SIZE_CACHE 4 +extern void diff_setup(int flags); #define DIFF_DETECT_RENAME 1 #define DIFF_DETECT_COPY 2 extern void diffcore_rename(int rename_copy, int minimum_score); -extern void diffcore_pickaxe(const char *needle); +#define DIFF_PICKAXE_ALL 1 +extern void diffcore_pickaxe(const char *needle, int opts); + extern void diffcore_pathspec(const char **pathspec); extern int diff_queue_is_empty(void); +#define DIFF_FORMAT_HUMAN 0 +#define DIFF_FORMAT_MACHINE 1 +#define DIFF_FORMAT_PATCH 2 +#define DIFF_FORMAT_NO_OUTPUT 3 + extern void diff_flush(int output_style, int resolve_rename_copy); #endif /* DIFF_H */ diff --git a/diffcore-pathspec.c b/diffcore-pathspec.c --- a/diffcore-pathspec.c +++ b/diffcore-pathspec.c @@ -55,11 +55,10 @@ void diffcore_pathspec(const char **path for (i = 0; i < q->nr; i++) { struct diff_filepair *p = q->queue[i]; - if (matches_pathspec(p->one->path, spec, speccnt) || - matches_pathspec(p->two->path, spec, speccnt)) + if (matches_pathspec(p->two->path, spec, speccnt)) diff_q(&outq, p); else - free(p); + diff_free_filepair(p); } free(q->queue); *q = outq; diff --git a/diffcore-pickaxe.c b/diffcore-pickaxe.c --- a/diffcore-pickaxe.c +++ b/diffcore-pickaxe.c @@ -11,7 +11,7 @@ static int contains(struct diff_filespec { unsigned long offset, sz; const char *data; - if (diff_populate_filespec(one)) + if (diff_populate_filespec(one, 0)) return 0; sz = one->size; data = one->data; @@ -21,36 +21,73 @@ static int contains(struct diff_filespec return 0; } -void diffcore_pickaxe(const char *needle) +void diffcore_pickaxe(const char *needle, int opts) { struct diff_queue_struct *q = &diff_queued_diff; unsigned long len = strlen(needle); - int i; + int i, has_changes; struct diff_queue_struct outq; outq.queue = NULL; outq.nr = outq.alloc = 0; - for (i = 0; i < q->nr; i++) { - struct diff_filepair *p = q->queue[i]; - int onum = outq.nr; - if (!DIFF_FILE_VALID(p->one)) { - if (!DIFF_FILE_VALID(p->two)) - continue; /* ignore nonsense */ - /* created */ - if (contains(p->two, needle, len)) - diff_q(&outq, p); + if (opts & DIFF_PICKAXE_ALL) { + /* Showing the whole changeset if needle exists */ + for (i = has_changes = 0; !has_changes && i < q->nr; i++) { + struct diff_filepair *p = q->queue[i]; + if (!DIFF_FILE_VALID(p->one)) { + if (!DIFF_FILE_VALID(p->two)) + continue; /* ignore unmerged */ + /* created */ + if (contains(p->two, needle, len)) + has_changes++; + } + else if (!DIFF_FILE_VALID(p->two)) { + if (contains(p->one, needle, len)) + has_changes++; + } + else if (!diff_unmodified_pair(p) && + contains(p->one, needle, len) != + contains(p->two, needle, len)) + has_changes++; } - else if (!DIFF_FILE_VALID(p->two)) { - if (contains(p->one, needle, len)) + if (has_changes) + return; /* not munge the queue */ + + /* otherwise we will clear the whole queue + * by copying the empty outq at the end of this + * function, but first clear the current entries + * in the queue. + */ + for (i = 0; i < q->nr; i++) + diff_free_filepair(q->queue[i]); + } + else + /* Showing only the filepairs that has the needle */ + for (i = 0; i < q->nr; i++) { + struct diff_filepair *p = q->queue[i]; + has_changes = 0; + if (!DIFF_FILE_VALID(p->one)) { + if (!DIFF_FILE_VALID(p->two)) + ; /* ignore unmerged */ + /* created */ + else if (contains(p->two, needle, len)) + has_changes = 1; + } + else if (!DIFF_FILE_VALID(p->two)) { + if (contains(p->one, needle, len)) + has_changes = 1; + } + else if (!diff_unmodified_pair(p) && + contains(p->one, needle, len) != + contains(p->two, needle, len)) + has_changes = 1; + + if (has_changes) diff_q(&outq, p); + else + diff_free_filepair(p); } - else if (!diff_unmodified_pair(p) && - contains(p->one, needle, len) != - contains(p->two, needle, len)) - diff_q(&outq, p); - if (onum == outq.nr) - free(p); - } + free(q->queue); *q = outq; return; diff --git a/diffcore-rename.c b/diffcore-rename.c --- a/diffcore-rename.c +++ b/diffcore-rename.c @@ -52,14 +52,15 @@ static struct diff_rename_dst *locate_re return &(rename_dst[first]); } +/* Table of rename/copy src files */ static struct diff_rename_src { struct diff_filespec *one; - unsigned src_used : 1; + unsigned src_stays : 1; } *rename_src; static int rename_src_nr, rename_src_alloc; -static struct diff_rename_src *locate_rename_src(struct diff_filespec *one, - int insert_ok) +static struct diff_rename_src *register_rename_src(struct diff_filespec *one, + int src_stays) { int first, last; @@ -77,9 +78,7 @@ static struct diff_rename_src *locate_re } first = next+1; } - /* not found */ - if (!insert_ok) - return NULL; + /* insert to make it at "first" */ if (rename_src_alloc <= rename_src_nr) { rename_src_alloc = alloc_nr(rename_src_alloc); @@ -91,7 +90,7 @@ static struct diff_rename_src *locate_re memmove(rename_src + first + 1, rename_src + first, (rename_src_nr - first - 1) * sizeof(*rename_src)); rename_src[first].one = one; - rename_src[first].src_used = 0; + rename_src[first].src_stays = src_stays; return &(rename_src[first]); } @@ -100,8 +99,11 @@ static int is_exact_match(struct diff_fi if (src->sha1_valid && dst->sha1_valid && !memcmp(src->sha1, dst->sha1, 20)) return 1; - if (diff_populate_filespec(src) || diff_populate_filespec(dst)) - /* this is an error but will be caught downstream */ + if (diff_populate_filespec(src, 1) || diff_populate_filespec(dst, 1)) + return 0; + if (src->size != dst->size) + return 0; + if (diff_populate_filespec(src, 0) || diff_populate_filespec(dst, 0)) return 0; if (src->size == dst->size && !memcmp(src->data, dst->data, src->size)) @@ -113,7 +115,6 @@ struct diff_score { int src; /* index in rename_src */ int dst; /* index in rename_dst */ int score; - int rank; }; static int estimate_similarity(struct diff_filespec *src, @@ -127,9 +128,11 @@ static int estimate_similarity(struct di * dst, and then some edit has been applied to dst. * * Compare them and return how similar they are, representing - * the score as an integer between 0 and 10000, except - * where they match exactly it is considered better than anything - * else. + * the score as an integer between 0 and MAX_SCORE. + * + * When there is an exact match, it is considered a better + * match than anything else; the destination does not even + * call into this function in that case. */ void *delta; unsigned long delta_size, base_size; @@ -149,6 +152,7 @@ static int estimate_similarity(struct di /* We would not consider edits that change the file size so * drastically. delta_size must be smaller than * (MAX_SCORE-minimum_score)/MAX_SCORE * min(src->size, dst->size). + * * Note that base_size == 0 case is handled here already * and the final score computation below would not have a * divide-by-zero issue. @@ -156,6 +160,9 @@ static int estimate_similarity(struct di if (base_size * (MAX_SCORE-minimum_score) < delta_size * MAX_SCORE) return 0; + if (diff_populate_filespec(src, 0) || diff_populate_filespec(dst, 0)) + return 0; /* error but caught downstream */ + delta = diff_delta(src->data, src->size, dst->data, dst->size, &delta_size); @@ -163,7 +170,7 @@ static int estimate_similarity(struct di /* A delta that has a lot of literal additions would have * big delta_size no matter what else it does. */ - if (minimum_score < MAX_SCORE * delta_size / base_size) + if (base_size * (MAX_SCORE-minimum_score) < delta_size * MAX_SCORE) return 0; /* Estimate the edit size by interpreting delta. */ @@ -200,15 +207,14 @@ static void record_rename_pair(struct di fill_filespec(two, dst->sha1, dst->mode); dp = diff_queue(renq, one, two); - dp->score = score; - - rename_src[src_index].src_used = 1; + dp->score = score ? : 1; /* make sure it is at least 1 */ + dp->source_stays = rename_src[src_index].src_stays; rename_dst[dst_index].pair = dp; } /* * We sort the rename similarity matrix with the score, in descending - * order (more similar first). + * order (the most similar first). */ static int score_compare(const void *a_, const void *b_) { @@ -223,7 +229,7 @@ int diff_scoreopt_parse(const char *opt) return -1; /* that is not a -M nor -C option */ diglen = strspn(opt+2, "0123456789"); if (diglen == 0 || strlen(opt+2) != diglen) - return 0; /* use default */ + return DEFAULT_MINIMUM_SCORE; /* use default */ sscanf(opt+2, "%d", &num); for (i = 0, scale = 1; i < diglen; i++) scale *= 10; @@ -255,9 +261,9 @@ void diffcore_rename(int detect_rename, else locate_rename_dst(p->two, 1); else if (!DIFF_FILE_VALID(p->two)) - locate_rename_src(p->one, 1); - else if (1 < detect_rename) /* find copy, too */ - locate_rename_src(p->one, 1); + register_rename_src(p->one, 0); + else if (detect_rename == DIFF_DETECT_COPY) + register_rename_src(p->one, 1); } if (rename_dst_nr == 0) goto cleanup; /* nothing to do */ @@ -308,7 +314,7 @@ void diffcore_rename(int detect_rename, if (dst->pair) continue; /* already done, either exact or fuzzy. */ if (mx[i].score < minimum_score) - break; /* there is not any more diffs applicable. */ + break; /* there is no more usable pair. */ record_rename_pair(&renq, mx[i].dst, mx[i].src, mx[i].score); } free(mx); @@ -317,28 +323,21 @@ void diffcore_rename(int detect_rename, flush_rest: /* At this point, we have found some renames and copies and they * are kept in renq. The original list is still in *q. - * - * Scan the original list and move them into the outq; we will sort - * outq and swap it into the queue supplied to pass that to - * downstream, so we assign the sort keys in this loop. - * - * See comments at the top of record_rename_pair for numbers used - * to assign rename_rank. */ outq.queue = NULL; outq.nr = outq.alloc = 0; for (i = 0; i < q->nr; i++) { struct diff_filepair *p = q->queue[i]; - struct diff_rename_src *src = locate_rename_src(p->one, 0); struct diff_rename_dst *dst = locate_rename_dst(p->two, 0); struct diff_filepair *pair_to_free = NULL; if (dst) { /* creation */ if (dst->pair) { - /* renq has rename/copy already to produce - * this file, so we do not emit the creation - * record in the output. + /* renq has rename/copy to produce + * this file already, so we do not + * emit the creation record in the + * output. */ diff_q(&outq, dst->pair); pair_to_free = p; @@ -350,25 +349,17 @@ void diffcore_rename(int detect_rename, diff_q(&outq, p); } else if (!diff_unmodified_pair(p)) - /* all the other cases need to be recorded as is */ + /* all the usual ones need to be kept */ diff_q(&outq, p); - else { - /* unmodified pair needs to be recorded only if - * it is used as the source of rename/copy - */ - if (src && src->src_used) - diff_q(&outq, p); - else - pair_to_free = p; - } - if (pair_to_free) { - diff_free_filespec_data(pair_to_free->one); - diff_free_filespec_data(pair_to_free->two); - free(pair_to_free); - } + else + /* no need to keep unmodified pairs */ + pair_to_free = p; + + if (pair_to_free) + diff_free_filepair(pair_to_free); } diff_debug_queue("done copying original", &outq); - + free(renq.queue); free(q->queue); *q = outq; diff --git a/diffcore.h b/diffcore.h --- a/diffcore.h +++ b/diffcore.h @@ -33,14 +33,17 @@ extern struct diff_filespec *alloc_files extern void fill_filespec(struct diff_filespec *, const unsigned char *, unsigned short); -extern int diff_populate_filespec(struct diff_filespec *); +extern int diff_populate_filespec(struct diff_filespec *, int); extern void diff_free_filespec_data(struct diff_filespec *); struct diff_filepair { struct diff_filespec *one; struct diff_filespec *two; - int score; /* only valid when one and two are different paths */ - int status; /* M C R N D U (see Documentation/diff-format.txt) */ + unsigned short int score; /* only valid when one and two are + * different paths + */ + char source_stays; /* all of R/C are copies */ + char status; /* M C R N D U (see Documentation/diff-format.txt) */ }; #define DIFF_PAIR_UNMERGED(p) \ (!DIFF_FILE_VALID((p)->one) && !DIFF_FILE_VALID((p)->two)) @@ -54,6 +57,8 @@ struct diff_filepair { (S_ISREG(mode) ? (S_IFREG | ce_permissions(mode)) : \ S_ISLNK(mode) ? S_IFLNK : S_IFDIR) +extern void diff_free_filepair(struct diff_filepair *); + extern int diff_unmodified_pair(struct diff_filepair *); struct diff_queue_struct { @@ -68,9 +73,6 @@ extern struct diff_filepair *diff_queue( struct diff_filespec *); extern void diff_q(struct diff_queue_struct *, struct diff_filepair *); -extern int diff_needs_to_stay(struct diff_queue_struct *, int, - struct diff_filespec *); - #define DIFF_DEBUG 0 #if DIFF_DEBUG void diff_debug_filespec(struct diff_filespec *, int, const char *); diff --git a/git-external-diff-script b/git-external-diff-script --- a/git-external-diff-script +++ b/git-external-diff-script @@ -59,7 +59,7 @@ then echo "new mode $mode2" if test "$xfrm_msg" != "" then - echo -n $xfrm_msg + echo "$xfrm_msg" fi fi diff ${GIT_DIFF_OPTS-'-pu'} -L "a/$name1" -L "b/$name2" "$tmp1" "$tmp2" diff --git a/t/t4007-rename-3.sh b/t/t4007-rename-3.sh new file mode 100755 --- /dev/null +++ b/t/t4007-rename-3.sh @@ -0,0 +1,103 @@ +#!/bin/sh +# +# Copyright (c) 2005 Junio C Hamano +# + +test_description='Rename interaction with pathspec. + +' +. ./test-lib.sh + +_x40='[0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f]' +_x40="$_x40$_x40$_x40$_x40$_x40$_x40$_x40$_x40" +sanitize_diff_raw='s/ \('"$_x40"'\) \1 \([CR]\)[0-9]* / \1 \1 \2# /' +compare_diff_raw () { + # When heuristics are improved, the score numbers would change. + # Ignore them while comparing. + # Also we do not check SHA1 hash generation in this test, which + # is a job for t0000-basic.sh + + sed -e "$sanitize_diff_raw" <"$1" >.tmp-1 + sed -e "$sanitize_diff_raw" <"$2" >.tmp-2 + diff -u .tmp-1 .tmp-2 && rm -f .tmp-1 .tmp-2 +} + +test_expect_success \ + 'prepare reference tree' \ + 'mkdir path0 path1 && + cp ../../COPYING path0/COPYING && + git-update-cache --add path0/COPYING && + tree=$(git-write-tree) && + echo $tree' + +test_expect_success \ + 'prepare work tree' \ + 'cp path0/COPYING path1/COPYING && + git-update-cache --add --remove path0/COPYING path1/COPYING' + +# In the tree, there is only path0/COPYING. In the cache, path0 and +# path1 both have COPYING and the latter is a copy of path0/COPYING. +# Comparing the full tree with cache should tell us so. + +git-diff-cache -C $tree >current + +cat >expected <<\EOF +:100644 100644 6ff87c4664981e4397625791c8ea3bbb5f2279a3 6ff87c4664981e4397625791c8ea3bbb5f2279a3 C100 path0/COPYING path1/COPYING +EOF + +test_expect_success \ + 'validate the result' \ + 'compare_diff_raw current expected' + +# In the tree, there is only path0/COPYING. In the cache, path0 and +# path1 both have COPYING and the latter is a copy of path0/COPYING. +# When we omit output from path0 it should still be able to tell us +# that path1/COPYING is result from a copy from path0/COPYING, not +# rename, which would imply path0/COPYING is now gone. + +git-diff-cache -C $tree path1 >current + +cat >expected <<\EOF +:100644 100644 6ff87c4664981e4397625791c8ea3bbb5f2279a3 6ff87c4664981e4397625791c8ea3bbb5f2279a3 C100 path0/COPYING path1/COPYING +EOF + +test_expect_success \ + 'validate the result' \ + 'compare_diff_raw current expected' + +test_expect_success \ + 'tweak work tree' \ + 'rm -f path0/COPYING && + git-update-cache --remove path0/COPYING' + +# In the tree, there is only path0/COPYING. In the cache, path0 does +# not have COPYING anymore and path1 has COPYING which is a copy of +# path0/COPYING. Showing the full tree with cache should tell us about +# the rename. + +git-diff-cache -C $tree >current + +cat >expected <<\EOF +:100644 100644 6ff87c4664981e4397625791c8ea3bbb5f2279a3 6ff87c4664981e4397625791c8ea3bbb5f2279a3 R100 path0/COPYING path1/COPYING +EOF + +test_expect_success \ + 'validate the result' \ + 'compare_diff_raw current expected' + +# In the tree, there is only path0/COPYING. In the cache, path0 does +# not have COPYING anymore and path1 has COPYING which is a copy of +# path0/COPYING. Even if we restrict the output to path1, it still +# should show us the rename. + +git-diff-cache -C $tree path1 >current + +cat >expected <<\EOF +:100644 100644 6ff87c4664981e4397625791c8ea3bbb5f2279a3 6ff87c4664981e4397625791c8ea3bbb5f2279a3 R100 path0/COPYING path1/COPYING +EOF + +test_expect_success \ + 'validate the result' \ + 'compare_diff_raw current expected' + +test_done \ No newline at end of file ------------------------------------------------ ^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [PATCH] Diff updates, fixing pathspec and rename/copy interaction. 2005-05-27 6:41 ` [PATCH] Diff updates, fixing pathspec and rename/copy interaction Junio C Hamano @ 2005-05-27 15:56 ` Linus Torvalds 2005-05-27 22:43 ` [PATCH 00/12] Diff updates Junio C Hamano 0 siblings, 1 reply; 22+ messages in thread From: Linus Torvalds @ 2005-05-27 15:56 UTC (permalink / raw) To: Junio C Hamano; +Cc: Git Mailing List On Thu, 26 May 2005, Junio C Hamano wrote: > > During the mailing list discussion about diff-tree omitting to > call diffcore-pathspec, I realized that the current rename/copy > differentiator has a major flaw interacting with pathspec (or > any other filepair filters, including pickaxe). > > The problem was that in order to tell if the rename-copy source > still remains in the resulting tree (that is what determines if > one of the rename-copy can become a rename or everybody needs to > be a copy), diffcore-rename was sending a filepair that records > unmodified source downstream, expecting that it reaches > resolve_rename_copy() which happens as the final stage before > actual output happens. Of course, pathspec and pickaxe can > interfere and happily remove that entry, in which case what > should be shown as a copy suddenly becomes a rename. Umm. I would much prefer a _much_ simpler fix at least for the pathname part, which is to just always require that pathspec handling is done _first_. Why? Because that's fundamentally how git-diff-tree has to work, and it's how my mental model has always been: the path limitations are a first-order filter, and if you give a directory, the end result should always look exactly as if that directory was a project of its own. In other words, if you limit yourself to a directory, and there was a rename that moved a file from outside that directory into it, then it is not a rename at all, it is a "create". The stuff outside the pathspec limit simply doesn't exist. This is fundamentally how git-diff-tree has to work for pathspec to make any sense at all, and it's also the only usage that makes any sense (ie when I say "git-whatchanged -p arch/i386 include/asm-i386", I expect that the patches that show up _only_ concern themselves with what happened in x86, and there's no cross-pollination with other stuff at all, even if rename detection is enabled). That in turn implies that the other pathspec users have to work the same way, for the thing to be consistent. Now, I don't know how you want pickaxe to work, and maybe you want that to run _after_ rename detection, I dunno. So I suspect you still want to do what this patch does, but I really don't want pathspec to be involved in this thing.. Linus ^ permalink raw reply [flat|nested] 22+ messages in thread
* [PATCH 00/12] Diff updates 2005-05-27 15:56 ` Linus Torvalds @ 2005-05-27 22:43 ` Junio C Hamano 2005-05-27 23:03 ` Junio C Hamano 0 siblings, 1 reply; 22+ messages in thread From: Junio C Hamano @ 2005-05-27 22:43 UTC (permalink / raw) To: Linus Torvalds; +Cc: Git Mailing List This series consists of the following 12 patches. Most of them are bugfixes and cleanups. The last one is somewhat iffy, although it does not break things, and lies somewhere between a request for inclusion and a request for comments. [PATCH 01/12] Fix math thinko in similarity estimator. [PATCH 02/12] Introduce diff_free_filepair() funcion. [PATCH 03/12] Make pathspec only care about the detination tree. [PATCH 04/12] Remove unused rank field from diff_core structure. [PATCH 05/12] Do not expose internal scaling to diff-helper. [PATCH 06/12] Remove final newline from the value of xfrm_msg variable. [PATCH 07/12] Clean up diff_setup() to make it more extensible. [PATCH 08/12] Remove a function not used anymore. [PATCH 09/12] Add --pickaxe-all to diff-* brothers. [PATCH 10/12] Fix the way diffcore-rename records unremoved source. [PATCH 11/12] Move pathspec to the beginning of the diffcore chain. [PATCH 12/12] Optimize diff-tree -[CM] --stdin ^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [PATCH 00/12] Diff updates 2005-05-27 22:43 ` [PATCH 00/12] Diff updates Junio C Hamano @ 2005-05-27 23:03 ` Junio C Hamano 2005-05-28 10:11 ` [PATCH] Do not show empty diff in diff-cache uncached Junio C Hamano 0 siblings, 1 reply; 22+ messages in thread From: Junio C Hamano @ 2005-05-27 23:03 UTC (permalink / raw) To: Linus Torvalds; +Cc: Git Mailing List I've said "I am done with diff" twice on this list already. Aside from unevitable bug reports ;-) I think this time I am done. At least the major ones I wanted to do. Except one thing. What do you think about the current behaviour of "diff-cache -p (uncached") in a work tree which was freshly checked-out, unmodified but you "touch"ed some files to make them stat-dirty? I think ancient diff-cache did not report those files, but with the new "diff --git" headers it will show the "diff --git" header mentioning those files followed by no content nor mode changes. Admittedly this matches the diff-raw output behaviour more closely, but I find it a bit distracting. Do you care about cleaning this up? ^ permalink raw reply [flat|nested] 22+ messages in thread
* [PATCH] Do not show empty diff in diff-cache uncached. 2005-05-27 23:03 ` Junio C Hamano @ 2005-05-28 10:11 ` Junio C Hamano 2005-05-29 18:53 ` Linus Torvalds 0 siblings, 1 reply; 22+ messages in thread From: Junio C Hamano @ 2005-05-28 10:11 UTC (permalink / raw) To: Linus Torvalds; +Cc: Git Mailing List Pre- "diff --git" built-in diff did not add any extended header on its own, so it did not show anything for unmodified but stat-dirty file from diff-cache command without --cached flag. Recent diff-cache produces "diff --git" header internally before calling the "diff" command, which results in an empty diff for such a file, cluttering the output. This patch fixes this. Signed-off-by: Junio C Hamano <junkio@cox.net> --- diff.c | 26 ++++++++++++++++++++++++++ diffcore-rename.c | 17 ----------------- diffcore.h | 2 ++ 3 files changed, 28 insertions(+), 17 deletions(-) diff --git a/diff.c b/diff.c --- a/diff.c +++ b/diff.c @@ -684,6 +684,23 @@ int diff_unmodified_pair(struct diff_fil return 0; } +int is_exact_match(struct diff_filespec *src, struct diff_filespec *dst) +{ + if (src->sha1_valid && dst->sha1_valid && + !memcmp(src->sha1, dst->sha1, 20)) + return 1; + if (diff_populate_filespec(src, 1) || diff_populate_filespec(dst, 1)) + return 0; + if (src->size != dst->size) + return 0; + if (diff_populate_filespec(src, 0) || diff_populate_filespec(dst, 0)) + return 0; + if (src->size == dst->size && + !memcmp(src->data, dst->data, src->size)) + return 1; + return 0; +} + static void diff_flush_patch(struct diff_filepair *p) { const char *name, *other; @@ -692,6 +709,15 @@ static void diff_flush_patch(struct diff if (diff_unmodified_pair(p)) return; + /* When diff-raw would have said "look at the filesystem", we + * need to see if the two are the same and if so not to emit + * anything at all. Avoid is_exact_match() comparison when it + * does not matter. + */ + if ((DIFF_FILE_VALID(p->two) && !p->two->sha1_valid) && + is_exact_match(p->one, p->two)) + return; + name = p->one->path; other = (strcmp(name, p->two->path) ? p->two->path : NULL); if ((DIFF_FILE_VALID(p->one) && S_ISDIR(p->one->mode)) || diff --git a/diffcore-rename.c b/diffcore-rename.c --- a/diffcore-rename.c +++ b/diffcore-rename.c @@ -94,23 +94,6 @@ static struct diff_rename_src *register_ return &(rename_src[first]); } -static int is_exact_match(struct diff_filespec *src, struct diff_filespec *dst) -{ - if (src->sha1_valid && dst->sha1_valid && - !memcmp(src->sha1, dst->sha1, 20)) - return 1; - if (diff_populate_filespec(src, 1) || diff_populate_filespec(dst, 1)) - return 0; - if (src->size != dst->size) - return 0; - if (diff_populate_filespec(src, 0) || diff_populate_filespec(dst, 0)) - return 0; - if (src->size == dst->size && - !memcmp(src->data, dst->data, src->size)) - return 1; - return 0; -} - struct diff_score { int src; /* index in rename_src */ int dst; /* index in rename_dst */ diff --git a/diffcore.h b/diffcore.h --- a/diffcore.h +++ b/diffcore.h @@ -29,6 +29,8 @@ struct diff_filespec { unsigned should_munmap : 1; /* data should be munmap()'ed */ }; +extern int is_exact_match(struct diff_filespec *, struct diff_filespec *); + extern struct diff_filespec *alloc_filespec(const char *); extern void fill_filespec(struct diff_filespec *, const unsigned char *, unsigned short); ------------------------------------------------ ^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [PATCH] Do not show empty diff in diff-cache uncached. 2005-05-28 10:11 ` [PATCH] Do not show empty diff in diff-cache uncached Junio C Hamano @ 2005-05-29 18:53 ` Linus Torvalds 2005-05-29 20:09 ` Junio C Hamano 0 siblings, 1 reply; 22+ messages in thread From: Linus Torvalds @ 2005-05-29 18:53 UTC (permalink / raw) To: Junio C Hamano; +Cc: Git Mailing List On Sat, 28 May 2005, Junio C Hamano wrote: > > Pre- "diff --git" built-in diff did not add any extended header > on its own, so it did not show anything for unmodified but > stat-dirty file from diff-cache command without --cached flag. > > Recent diff-cache produces "diff --git" header internally before > calling the "diff" command, which results in an empty diff for > such a file, cluttering the output. This patch fixes this. I'm not sure I like this. I actually _expect_ that "git-diff-files" will show files that don't match the index, even if they happen to have the exact content that the index points to. It's how I know whether the index is up-to-date or not. The exact same thing is trye of git-diff-cache. If something isn't up-to-date in the cache, you should show it, since certain operations depend on the cache being updated. Linus ^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [PATCH] Do not show empty diff in diff-cache uncached. 2005-05-29 18:53 ` Linus Torvalds @ 2005-05-29 20:09 ` Junio C Hamano 2005-05-29 21:52 ` Junio C Hamano 0 siblings, 1 reply; 22+ messages in thread From: Junio C Hamano @ 2005-05-29 20:09 UTC (permalink / raw) To: Linus Torvalds; +Cc: Git Mailing List >>>>> "LT" == Linus Torvalds <torvalds@osdl.org> writes: LT> I'm not sure I like this. LT> I actually _expect_ that "git-diff-files" will show files that don't match LT> the index, even if they happen to have the exact content that the index LT> points to. It's how I know whether the index is up-to-date or not. LT> The exact same thing is trye of git-diff-cache. If something isn't LT> up-to-date in the cache, you should show it, since certain operations LT> depend on the cache being updated. Let me make sure that we are on the same page. I am only talking about '-p' (diff-patch) case in this patch. The code should continue to show the 0{40} SHA1 on the right hand side in diff-raw output. Do you still want to see the header in that case to match the diff-raw exactly? ^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [PATCH] Do not show empty diff in diff-cache uncached. 2005-05-29 20:09 ` Junio C Hamano @ 2005-05-29 21:52 ` Junio C Hamano 2005-05-29 23:41 ` [PATCH 0/3] Leftover bits after 12-series Junio C Hamano 0 siblings, 1 reply; 22+ messages in thread From: Junio C Hamano @ 2005-05-29 21:52 UTC (permalink / raw) To: Linus Torvalds; +Cc: Git Mailing List >>>>> "JCH" == Junio C Hamano <junkio@cox.net> writes: JCH> Let me make sure that we are on the same page. Linus, now I've examined what are and what aren't merged in your tree, I think I know the answer to that question. The set you picked look sensible to me. I'm taking a look at the resulting tree to see if there are fixes and cleanups that I still think should be merged. I'll feed them afresh to you later, if there are any, after rebasing the patch to the tip of your tree. Please disregard the patches you have already discarded so far; this request-to-discard includes -O and -B enhancements. ^ permalink raw reply [flat|nested] 22+ messages in thread
* [PATCH 0/3] Leftover bits after 12-series 2005-05-29 21:52 ` Junio C Hamano @ 2005-05-29 23:41 ` Junio C Hamano 2005-05-30 6:58 ` [PATCH 0/4] Junio C Hamano 0 siblings, 1 reply; 22+ messages in thread From: Junio C Hamano @ 2005-05-29 23:41 UTC (permalink / raw) To: Linus Torvalds; +Cc: Git Mailing List >>>>> "JCH" == Junio C Hamano <junkio@cox.net> writes: JCH> I'm taking a look at the resulting tree to see if there are JCH> fixes and cleanups that I still think should be merged. I'll JCH> feed them afresh to you later, if there are any, after rebasing JCH> the patch to the tip of your tree. I'll be submitting a set of cleanup and bugfix patches. The first one is a real bugfix. The latter two are cleanups. [PATCH 1/3] diff-helper: Fix R/C score parsing under -z flag. [PATCH 2/3] diff: consolidate various calls into diffcore. [PATCH 3/3] diff: code clean-up. ^ permalink raw reply [flat|nested] 22+ messages in thread
* [PATCH 0/4] 2005-05-29 23:41 ` [PATCH 0/3] Leftover bits after 12-series Junio C Hamano @ 2005-05-30 6:58 ` Junio C Hamano 0 siblings, 0 replies; 22+ messages in thread From: Junio C Hamano @ 2005-05-30 6:58 UTC (permalink / raw) To: Linus Torvalds; +Cc: Git Mailing List Linus, as promised, I am sending a couple of further cleanup, and a pair of new diffcore routines. I am assuming that you would have applied the three clean-up patches I sent after you rejected some of my 12-piece set, before you use these four. They come on top of the previous three. Although I do not think they depend on the previous three, I am letting you know that that was how I tested these four: [PATCH 1/4] diff: further cleanup. [PATCH 2/4] diff: fix the culling of unneeded delete record. [PATCH 3/4] Add -B flag to diff-* brothers. [PATCH 4/4] Add -O<orderfile> option to diff-* brothers. The third one is the gem of this series. I think I covered the basics I can think of in the new test script, but there could still be cases that rename/copy detector does something interesting when broken pairs are involved. Please give it a good beating before you use it for anything important. This being diff routine, it obviously cannot corrupt your data, though. The fourth one was what both you and Petr expressed reluctance, although Thomas was supportive. I admit it is of "nice to have" category not "great we need to have it inside" category, but it is my favorite. Oh, before I forget, I was wondering if you want me to mark broken pair in any special way, just line I mark matched rename/copy pairs. Something along the lines of: diff --git a/foo b/foo dissimilarity index 100% deleted file mode 100644 --- a/foo +++ /dev/null @@ ... diff --git a/foo b/foo dissimilarity index 100% new file mode 100644 --- /dev/null +++ a/foo @@ ... ^ permalink raw reply [flat|nested] 22+ messages in thread
end of thread, other threads:[~2018-12-28 20:12 UTC | newest] Thread overview: 22+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2018-12-07 23:54 [PATCH 0/4] Stefan Beller 2018-12-07 23:54 ` [PATCH 1/4] submodule update: add regression test with old style setups Stefan Beller 2018-12-09 0:11 ` Junio C Hamano 2018-12-07 23:54 ` [PATCH 2/4] submodule: unset core.worktree if no working tree is present Stefan Beller 2018-12-08 6:44 ` Junio C Hamano 2018-12-07 23:54 ` [PATCH 3/4] submodule--helper: fix BUG message in ensure_core_worktree Stefan Beller 2018-12-08 6:55 ` Junio C Hamano 2018-12-12 22:46 ` Stefan Beller 2018-12-13 3:14 ` Junio C Hamano 2018-12-07 23:54 ` [PATCH 4/4] submodule deinit: unset core.worktree Stefan Beller 2018-12-08 7:03 ` Junio C Hamano 2018-12-08 5:57 ` [PATCH 0/4] Junio C Hamano 2018-12-12 22:35 ` Stefan Beller 2018-12-13 3:15 ` Junio C Hamano 2018-12-14 23:59 ` [PATCH 0/4] submodules: unset core.worktree when no working tree present Stefan Beller 2018-12-14 23:59 ` [PATCH 1/4] submodule update: add regression test with old style setups Stefan Beller 2018-12-26 18:21 ` Junio C Hamano 2018-12-14 23:59 ` [PATCH 2/4] submodule: unset core.worktree if no working tree is present Stefan Beller 2018-12-26 18:27 ` Junio C Hamano 2018-12-14 23:59 ` [PATCH 3/4] submodule--helper: fix BUG message in ensure_core_worktree Stefan Beller 2018-12-14 23:59 ` [PATCH 4/4] submodule deinit: unset core.worktree Stefan Beller -- strict thread matches above, loose matches on Subject: below -- 2005-05-27 0:41 Broken directory pathname pruning Linus Torvalds 2005-05-27 6:41 ` [PATCH] Diff updates, fixing pathspec and rename/copy interaction Junio C Hamano 2005-05-27 15:56 ` Linus Torvalds 2005-05-27 22:43 ` [PATCH 00/12] Diff updates Junio C Hamano 2005-05-27 23:03 ` Junio C Hamano 2005-05-28 10:11 ` [PATCH] Do not show empty diff in diff-cache uncached Junio C Hamano 2005-05-29 18:53 ` Linus Torvalds 2005-05-29 20:09 ` Junio C Hamano 2005-05-29 21:52 ` Junio C Hamano 2005-05-29 23:41 ` [PATCH 0/3] Leftover bits after 12-series Junio C Hamano 2005-05-30 6:58 ` [PATCH 0/4] Junio C Hamano
Code repositories for project(s) associated with this public inbox https://80x24.org/mirrors/git.git This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).