Merge branch 'jl/submodule-deinit'
There was no Porcelain way to say "I no longer am interested in this submodule", once you express your interest in a submodule with "submodule init". "submodule deinit" is the way to do so. * jl/submodule-deinit: submodule: add 'deinit' command
This commit is contained in:
commit
b03b41e24c
@ -149,6 +149,10 @@ files that aren't ignored are present in the submodules work tree.
|
||||
Ignored files are deemed expendable and won't stop a submodule's work
|
||||
tree from being removed.
|
||||
|
||||
If you only want to remove the local checkout of a submodule from your
|
||||
work tree without committing the removal,
|
||||
use linkgit:git-submodule[1] `deinit` instead.
|
||||
|
||||
EXAMPLES
|
||||
--------
|
||||
`git rm Documentation/\*.txt`::
|
||||
|
@ -13,6 +13,7 @@ SYNOPSIS
|
||||
[--reference <repository>] [--] <repository> [<path>]
|
||||
'git submodule' [--quiet] status [--cached] [--recursive] [--] [<path>...]
|
||||
'git submodule' [--quiet] init [--] [<path>...]
|
||||
'git submodule' [--quiet] deinit [-f|--force] [--] <path>...
|
||||
'git submodule' [--quiet] update [--init] [--remote] [-N|--no-fetch]
|
||||
[-f|--force] [--rebase] [--reference <repository>]
|
||||
[--merge] [--recursive] [--] [<path>...]
|
||||
@ -135,6 +136,19 @@ init::
|
||||
the explicit 'init' step if you do not intend to customize
|
||||
any submodule locations.
|
||||
|
||||
deinit::
|
||||
Unregister the given submodules, i.e. remove the whole
|
||||
`submodule.$name` section from .git/config together with their work
|
||||
tree. Further calls to `git submodule update`, `git submodule foreach`
|
||||
and `git submodule sync` will skip any unregistered submodules until
|
||||
they are initialized again, so use this command if you don't want to
|
||||
have a local checkout of the submodule in your work tree anymore. If
|
||||
you really want to remove a submodule from the repository and commit
|
||||
that use linkgit:git-rm[1] instead.
|
||||
+
|
||||
If `--force` is specified, the submodule's work tree will be removed even if
|
||||
it contains local modifications.
|
||||
|
||||
update::
|
||||
Update the registered submodules, i.e. clone missing submodules and
|
||||
checkout the commit specified in the index of the containing repository.
|
||||
@ -214,8 +228,10 @@ OPTIONS
|
||||
|
||||
-f::
|
||||
--force::
|
||||
This option is only valid for add and update commands.
|
||||
This option is only valid for add, deinit and update commands.
|
||||
When running add, allow adding an otherwise ignored submodule path.
|
||||
When running deinit the submodule work trees will be removed even if
|
||||
they contain local changes.
|
||||
When running update, throw away local changes in submodules when
|
||||
switching to a different commit; and always run a checkout operation
|
||||
in the submodule, even if the commit listed in the index of the
|
||||
|
@ -2419,7 +2419,7 @@ _git_submodule ()
|
||||
{
|
||||
__git_has_doubledash && return
|
||||
|
||||
local subcommands="add status init update summary foreach sync"
|
||||
local subcommands="add status init deinit update summary foreach sync"
|
||||
if [ -z "$(__git_find_on_cmdline "$subcommands")" ]; then
|
||||
case "$cur" in
|
||||
--*)
|
||||
|
@ -8,6 +8,7 @@ dashless=$(basename "$0" | sed -e 's/-/ /')
|
||||
USAGE="[--quiet] add [-b <branch>] [-f|--force] [--name <name>] [--reference <repository>] [--] <repository> [<path>]
|
||||
or: $dashless [--quiet] status [--cached] [--recursive] [--] [<path>...]
|
||||
or: $dashless [--quiet] init [--] [<path>...]
|
||||
or: $dashless [--quiet] deinit [-f|--force] [--] <path>...
|
||||
or: $dashless [--quiet] update [--init] [--remote] [-N|--no-fetch] [-f|--force] [--rebase] [--reference <repository>] [--merge] [--recursive] [--] [<path>...]
|
||||
or: $dashless [--quiet] summary [--cached|--files] [--summary-limit <n>] [commit] [--] [<path>...]
|
||||
or: $dashless [--quiet] foreach [--recursive] <command>
|
||||
@ -546,6 +547,80 @@ cmd_init()
|
||||
done
|
||||
}
|
||||
|
||||
#
|
||||
# Unregister submodules from .git/config and remove their work tree
|
||||
#
|
||||
# $@ = requested paths (use '.' to deinit all submodules)
|
||||
#
|
||||
cmd_deinit()
|
||||
{
|
||||
# parse $args after "submodule ... deinit".
|
||||
while test $# -ne 0
|
||||
do
|
||||
case "$1" in
|
||||
-f|--force)
|
||||
force=$1
|
||||
;;
|
||||
-q|--quiet)
|
||||
GIT_QUIET=1
|
||||
;;
|
||||
--)
|
||||
shift
|
||||
break
|
||||
;;
|
||||
-*)
|
||||
usage
|
||||
;;
|
||||
*)
|
||||
break
|
||||
;;
|
||||
esac
|
||||
shift
|
||||
done
|
||||
|
||||
if test $# = 0
|
||||
then
|
||||
die "$(eval_gettext "Use '.' if you really want to deinitialize all submodules")"
|
||||
fi
|
||||
|
||||
module_list "$@" |
|
||||
while read mode sha1 stage sm_path
|
||||
do
|
||||
die_if_unmatched "$mode"
|
||||
name=$(module_name "$sm_path") || exit
|
||||
|
||||
# Remove the submodule work tree (unless the user already did it)
|
||||
if test -d "$sm_path"
|
||||
then
|
||||
# Protect submodules containing a .git directory
|
||||
if test -d "$sm_path/.git"
|
||||
then
|
||||
echo >&2 "$(eval_gettext "Submodule work tree '\$sm_path' contains a .git directory")"
|
||||
die "$(eval_gettext "(use 'rm -rf' if you really want to remove it including all of its history)")"
|
||||
fi
|
||||
|
||||
if test -z "$force"
|
||||
then
|
||||
git rm -n "$sm_path" ||
|
||||
die "$(eval_gettext "Submodule work tree '\$sm_path' contains local modifications; use '-f' to discard them")"
|
||||
fi
|
||||
rm -rf "$sm_path" || say "$(eval_gettext "Could not remove submodule work tree '\$sm_path'")"
|
||||
fi
|
||||
|
||||
mkdir "$sm_path" || say "$(eval_gettext "Could not create empty submodule directory '\$sm_path'")"
|
||||
|
||||
# Remove the .git/config entries (unless the user already did it)
|
||||
if test -n "$(git config --get-regexp submodule."$name\.")"
|
||||
then
|
||||
# Remove the whole section so we have a clean state when
|
||||
# the user later decides to init this submodule again
|
||||
url=$(git config submodule."$name".url)
|
||||
git config --remove-section submodule."$name" 2>/dev/null &&
|
||||
say "$(eval_gettext "Submodule '\$name' (\$url) unregistered for path '\$sm_path'")"
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
#
|
||||
# Update each submodule path to correct revision, using clone and checkout as needed
|
||||
#
|
||||
@ -1162,7 +1237,7 @@ cmd_sync()
|
||||
while test $# != 0 && test -z "$command"
|
||||
do
|
||||
case "$1" in
|
||||
add | foreach | init | update | status | summary | sync)
|
||||
add | foreach | init | deinit | update | status | summary | sync)
|
||||
command=$1
|
||||
;;
|
||||
-q|--quiet)
|
||||
|
@ -757,4 +757,104 @@ test_expect_success 'submodule add with an existing name fails unless forced' '
|
||||
)
|
||||
'
|
||||
|
||||
test_expect_success 'set up a second submodule' '
|
||||
git submodule add ./init2 example2 &&
|
||||
git commit -m "submodule example2 added"
|
||||
'
|
||||
|
||||
test_expect_success 'submodule deinit should remove the whole submodule section from .git/config' '
|
||||
git config submodule.example.foo bar &&
|
||||
git config submodule.example2.frotz nitfol &&
|
||||
git submodule deinit init &&
|
||||
test -z "$(git config --get-regexp "submodule\.example\.")" &&
|
||||
test -n "$(git config --get-regexp "submodule\.example2\.")" &&
|
||||
test -f example2/.git &&
|
||||
rmdir init
|
||||
'
|
||||
|
||||
test_expect_success 'submodule deinit . deinits all initialized submodules' '
|
||||
git submodule update --init &&
|
||||
git config submodule.example.foo bar &&
|
||||
git config submodule.example2.frotz nitfol &&
|
||||
test_must_fail git submodule deinit &&
|
||||
git submodule deinit . &&
|
||||
test -z "$(git config --get-regexp "submodule\.example\.")" &&
|
||||
test -z "$(git config --get-regexp "submodule\.example2\.")" &&
|
||||
rmdir init example2
|
||||
'
|
||||
|
||||
test_expect_success 'submodule deinit deinits a submodule when its work tree is missing or empty' '
|
||||
git submodule update --init &&
|
||||
rm -rf init example2/* example2/.git &&
|
||||
git submodule deinit init example2 &&
|
||||
test -z "$(git config --get-regexp "submodule\.example\.")" &&
|
||||
test -z "$(git config --get-regexp "submodule\.example2\.")" &&
|
||||
rmdir init
|
||||
'
|
||||
|
||||
test_expect_success 'submodule deinit fails when the submodule contains modifications unless forced' '
|
||||
git submodule update --init &&
|
||||
echo X >>init/s &&
|
||||
test_must_fail git submodule deinit init &&
|
||||
test -n "$(git config --get-regexp "submodule\.example\.")" &&
|
||||
test -f example2/.git &&
|
||||
git submodule deinit -f init &&
|
||||
test -z "$(git config --get-regexp "submodule\.example\.")" &&
|
||||
rmdir init
|
||||
'
|
||||
|
||||
test_expect_success 'submodule deinit fails when the submodule contains untracked files unless forced' '
|
||||
git submodule update --init &&
|
||||
echo X >>init/untracked &&
|
||||
test_must_fail git submodule deinit init &&
|
||||
test -n "$(git config --get-regexp "submodule\.example\.")" &&
|
||||
test -f example2/.git &&
|
||||
git submodule deinit -f init &&
|
||||
test -z "$(git config --get-regexp "submodule\.example\.")" &&
|
||||
rmdir init
|
||||
'
|
||||
|
||||
test_expect_success 'submodule deinit fails when the submodule HEAD does not match unless forced' '
|
||||
git submodule update --init &&
|
||||
(
|
||||
cd init &&
|
||||
git checkout HEAD^
|
||||
) &&
|
||||
test_must_fail git submodule deinit init &&
|
||||
test -n "$(git config --get-regexp "submodule\.example\.")" &&
|
||||
test -f example2/.git &&
|
||||
git submodule deinit -f init &&
|
||||
test -z "$(git config --get-regexp "submodule\.example\.")" &&
|
||||
rmdir init
|
||||
'
|
||||
|
||||
test_expect_success 'submodule deinit is silent when used on an uninitialized submodule' '
|
||||
git submodule update --init &&
|
||||
git submodule deinit init >actual &&
|
||||
test_i18ngrep "Submodule .example. (.*) unregistered for path .init" actual &&
|
||||
git submodule deinit init >actual &&
|
||||
test_i18ngrep ! "Submodule .example. (.*) unregistered for path .init" actual &&
|
||||
git submodule deinit . >actual &&
|
||||
test_i18ngrep ! "Submodule .example. (.*) unregistered for path .init" actual &&
|
||||
test_i18ngrep "Submodule .example2. (.*) unregistered for path .example2" actual &&
|
||||
git submodule deinit . >actual &&
|
||||
test_i18ngrep ! "Submodule .example. (.*) unregistered for path .init" actual &&
|
||||
test_i18ngrep ! "Submodule .example2. (.*) unregistered for path .example2" actual &&
|
||||
rmdir init example2
|
||||
'
|
||||
|
||||
test_expect_success 'submodule deinit fails when submodule has a .git directory even when forced' '
|
||||
git submodule update --init &&
|
||||
(
|
||||
cd init &&
|
||||
rm .git &&
|
||||
cp -R ../.git/modules/example .git &&
|
||||
GIT_WORK_TREE=. git config --unset core.worktree
|
||||
) &&
|
||||
test_must_fail git submodule deinit init &&
|
||||
test_must_fail git submodule deinit -f init &&
|
||||
test -d init/.git &&
|
||||
test -n "$(git config --get-regexp "submodule\.example\.")"
|
||||
'
|
||||
|
||||
test_done
|
||||
|
Loading…
Reference in New Issue
Block a user