diff options
author | David Turner <dturner@twosigma.com> | 2021-08-31 16:12:56 +0300 |
---|---|---|
committer | Junio C Hamano <gitster@pobox.com> | 2021-08-31 20:11:48 +0300 |
commit | f1c0368da4d64f394e4c099cb3c232671040d725 (patch) | |
tree | 405fc3b988ae1655abe9b97fb932a4e852f56920 /submodule.c | |
parent | 4577d26dc0aaae3bb35c8906db96ba043716f3f7 (diff) |
diff --submodule=diff: do not fail on ever-initialied deleted submodules
If you have ever initialized a submodule, open_submodule will open it.
If you then delete the submodule's worktree directory (but don't
remove it from .gitmodules), git diff --submodule=diff would error out
as it attempted to chdir into the now-deleted working tree directory.
This only matters if the submodules git dir is absorbed. If not, then
we no longer have anywhere to run the diff. But that case does not
trigger this error, because in that case, open_submodule fails, so we
don't resolve a left commit, so we exit early, which is the only thing
we could do.
If absorbed, then we can run the diff from the submodule's absorbed
git dir (.git/modules/sm2). In practice, that's a bit more
complicated, because `git diff` expects to be run from inside a
working directory, not a git dir. So it looks in the config for
core.worktree, and does chdir("../../../sm2"), which is the very dir
that we're trying to avoid visiting because it's been deleted. We
work around this by setting GIT_WORK_TREE (and GIT_DIR) to ".". It is
little weird to set GIT_WORK_TREE to something that is not a working
tree just to avoid an unnecessary chdir, but it works.
Signed-off-by: David Turner <dturner@twosigma.com
Signed-off-by: Junio C Hamano <gitster@pobox.com>
Diffstat (limited to 'submodule.c')
-rw-r--r-- | submodule.c | 10 |
1 files changed, 10 insertions, 0 deletions
diff --git a/submodule.c b/submodule.c index 0b1d9c1dde..8aeff95cfd 100644 --- a/submodule.c +++ b/submodule.c @@ -710,6 +710,16 @@ void show_submodule_inline_diff(struct diff_options *o, const char *path, strvec_push(&cp.args, oid_to_hex(new_oid)); prepare_submodule_repo_env(&cp.env_array); + + if (!is_directory(path)) { + /* fall back to absorbed git dir, if any */ + if (!sub) + goto done; + cp.dir = sub->gitdir; + strvec_push(&cp.env_array, GIT_DIR_ENVIRONMENT "=."); + strvec_push(&cp.env_array, GIT_WORK_TREE_ENVIRONMENT "=."); + } + if (start_command(&cp)) diff_emit_submodule_error(o, "(diff failed)\n"); |