Subject: Re: [PATCH 2/2] git-submodule: support 'rm' command.

From: Jens Lehmann <[email-masked]>
Date: Mon, 25 Jun 2012 18:58:36 +0200

Am 25.06.2012 12:57, schrieb Michał Górny:
> Add an 'rm' command to git-submodule which provides means to
> (semi-)easily remove git submodules.
> 
> Signed-off-by: Michał Górny <[email-masked]>
> ---
> Right now, it requires the submodule checkout to be removed manually
> first (so it does not remove unstaged commits), and just removes
> the index entry and module information from config.
> 
> I based it on 'cmd_add' code trying to preserve the original coding
> standards.

I really like the goal of this patch but would prefer that "git rm"
learns how to remove submodules instead of adding more code to the
git-submodule.sh script.

Also it shouldn't be necessary for the user to remove the directory
by hand before running "git rm". At least all files recorded in the
submodule can be removed (and if the submodule uses a gitfile that
can be removed too). Then all that is left are untracked files the
user has to decide what to do with (which might be removed too when
running "git rm --recurse-submodules=untracked").

>  Documentation/git-submodule.txt |   12 +++++++
>  git-submodule.sh                |   68 ++++++++++++++++++++++++++++++++++++++-
>  2 files changed, 79 insertions(+), 1 deletion(-)
> 
> diff --git a/Documentation/git-submodule.txt b/Documentation/git-submodule.txt
> index fbbbcb2..293c1bf 100644
> --- a/Documentation/git-submodule.txt
> +++ b/Documentation/git-submodule.txt
> @@ -11,6 +11,7 @@ SYNOPSIS
>  [verse]
>  'git submodule' [--quiet] add [-b branch] [-f|--force]
>  	      [--reference <repository>] [--] <repository> [<path>]
> +'git submodule' [--quiet] rm <path>...
>  'git submodule' [--quiet] status [--cached] [--recursive] [--] [<path>...]
>  'git submodule' [--quiet] init [--] [<path>...]
>  'git submodule' [--quiet] update [--init] [-N|--no-fetch] [--rebase]
> @@ -104,6 +105,17 @@ together in the same relative location, and only the
>  superproject's URL needs to be provided: git-submodule will correctly
>  locate the submodule using the relative URL in .gitmodules.
>  
> +rm::
> +	Remove and unregister the submodules at given paths.
> ++
> +This requires at least one <path> argument. The repository checkout
> +existing at that directory needs to be removed manually from
> +the filesystem prior to calling this command. Note that all local
> +changes will be lost.

Me thinks without -f a "git rm" should only then remove a submodule
if no local modifications exist and current HEAD is part of a remote
branch (so you can't loose unpushed commits by accident). If the
submodule uses a gitfile a local branch might be sufficient for that,
as the git directory lives on.

> ++
> +This command removes the submodule from the current git index,
> +the .gitmodules file and the local repository config.

It should not be removed from .git/config by default. The user may
have special settings there and the presence in .git/config shows
he cared about having the submodule checked out, which should not
be revoked by just removing the submodule from the work tree.
Unless he removes the config from there himself he should get back
a populated submodule when he checks out an earlier commit and says
"git submodule update".

>  status::
>  	Show the status of the submodules. This will print the SHA-1 of the
>  	currently checked out commit for each submodule, along with the
> diff --git a/git-submodule.sh b/git-submodule.sh
> index fbf2faf..88fd414 100755
> --- a/git-submodule.sh
> +++ b/git-submodule.sh
> @@ -6,6 +6,7 @@
>  
>  dashless=$(basename "$0" | sed -e 's/-/ /')
>  USAGE="[--quiet] add [-b branch] [-f|--force] [--reference <repository>] [--] <repository> [<path>]
> +   or: $dashless [--quiet] rm [--] <path>...
>     or: $dashless [--quiet] status [--cached] [--recursive] [--] [<path>...]
>     or: $dashless [--quiet] init [--] [<path>...]
>     or: $dashless [--quiet] update [--init] [-N|--no-fetch] [-f|--force] [--rebase] [--reference <repository>] [--merge] [--recursive] [--] [<path>...]
> @@ -308,6 +309,71 @@ Use -f if you really want to add it." >&2
>  }
>  
>  #
> +# Remove submodules from the working tree, .gitmodules and the index
> +#
> +# $@ = submodule paths
> +#
> +cmd_rm()
> +{
> +	# parse $args after "submodule ... rm".
> +	while test $# -ne 0
> +	do
> +		case "$1" in
> +		--)
> +			shift
> +			break
> +			;;
> +		-*)
> +			usage
> +			;;
> +		*)
> +			break
> +			;;
> +		esac
> +		shift
> +	done
> +
> +	if test -z "$1"; then
> +		usage
> +	fi
> +
> +	while test $# -ne 0
> +	do
> +		sm_path=$1
> +		shift
> +
> +		# normalize path:
> +		# multiple //; leading ./; /./; /../; trailing /
> +		sm_path=$(printf '%s/\n' "$sm_path" |
> +			sed -e '
> +				s|//*|/|g
> +				s|^\(\./\)*||
> +				s|/\./|/|g
> +				:start
> +				s|\([^/]*\)/\.\./||
> +				tstart
> +				s|/*$||
> +			')
> +		git ls-files --error-unmatch "$sm_path" > /dev/null 2>&1 ||
> +		die "$(eval_gettext "'\$sm_path' does not exist in the index")"
> +
> +		if test -e "$sm_path"
> +		then
> +			die "$(eval_gettext "'\$sm_path' needs to be removed manually first")"
> +		fi
> +
> +		git rm --cached "$sm_path" ||
> +		die "$(eval_gettext "Failed to remove submodule '\$sm_path'")"
> +
> +		git config -f .gitmodules --remove-section submodule."$sm_path" &&
> +		git add --force .gitmodules ||
> +		die "$(eval_gettext "Failed to unregister submodule '\$sm_path'")"
> +
> +		git config --remove-section submodule."$sm_path"
> +	done
> +}
> +
> +#
>  # Execute an arbitrary command sequence in each checked out
>  # submodule
>  #
> @@ -996,7 +1062,7 @@ cmd_sync()
>  while test $# != 0 && test -z "$command"
>  do
>  	case "$1" in
> -	add | foreach | init | update | status | summary | sync)
> +	add | rm | foreach | init | update | status | summary | sync)
>  		command=$1
>  		;;
>  	-q|--quiet)
>