[PATCH] Add git-submodule command

Subsystems: documentation, kernel build + files below scripts/ (unless maintained elsewhere), the rest

DORMANTno replies

13 messages, 3 authors, 2016-06-15 · open the first message on its own page

[PATCH] Add git-submodule command

From: Lars Hjemli <hidden>
Date: 2016-06-15 22:43:12

This command can be used to initialize, update and inspect submodules. It
uses a .gitmodules file, readable by git-config, in the top level directory
of the 'superproject' to specify a mapping between submodule paths and
repository url. There is currently no way to override the mappings in the
.gitmodules file, except by manually creating the subproject repository.

Example .gitmodules layout:

[module "git"]
	url = git://git.kernel.org/pub/scm/git/git.git

Signed-off-by: Lars Hjemli <redacted>
---

On 5/24/07, Johannes Schindelin [off-list ref] wrote:
On Thu, 24 May 2007, Lars Hjemli wrote:
quoted
What I think would be nice is some porcelain support to manually init,
update and see the checked out version of selected subprojects, but as
standalone commands.
Yes, a la git-remote. I'd be much happier with that, too, especially since
I think that this can be a relatively small and easy-to-review script.
So, here it is. Please be kind :)

Btw: I've never managed to get asciidoc working on my machine, so the doc
isn't checked in any other format than plain text.


 Documentation/git-submodule.txt |   49 ++++++++++++
 Makefile                        |    2 +-
 git-submodule.sh                |  163 +++++++++++++++++++++++++++++++++++++++
 3 files changed, 213 insertions(+), 1 deletions(-)
 create mode 100644 Documentation/git-submodule.txt
 create mode 100755 git-submodule.sh
diff --git a/Documentation/git-submodule.txt b/Documentation/git-submodule.txt
new file mode 100644
index 0000000..6ec917c
--- /dev/null
+++ b/Documentation/git-submodule.txt
@@ -0,0 +1,49 @@
+git-submodule(1)
+================
+
+NAME
+----
+git-submodule - Initialize, update or inspect submodules
+
+
+SYNOPSIS
+--------
+'git-submodule' [--init | --update | --cached] [--quiet] <path>...
+
+DESCRIPTION
+-----------
+The command shows the status of each specified submodule path, or all
+submodules if none is specified. Each submodule sha1 is prefixed with '-'
+if the submodule is uninitialized and '+' if the checked out version of
+the submodule is different from the commit sha1 stored in the index.
+
+
+OPTIONS
+-------
+<path>::
+	Path to submodule
+
+-i, --init::
+	Initialize the specified submodules, i.e. clone the git repository
+	specified in .gitmodules and checkout the sha1 specified in the
+	index.
+
+-u, --update::
+	Update the specified submodules, i.e. checkout the sha1 specified
+	in the index
+
+--cached::
+	Display the sha1 stored in the index, not the currently checked
+	out revsion.
+
+-q, --quiet::
+	Be quiet
+
+
+Author
+------
+Written by Lars Hjemli <hjemli@gmail.com>
+
+GIT
+---
+Part of the gitlink:git[7] suite
diff --git a/Makefile b/Makefile
index 29243c6..5cf2169 100644
--- a/Makefile
+++ b/Makefile
@@ -209,7 +209,7 @@ SCRIPT_SH = \
 	git-applymbox.sh git-applypatch.sh git-am.sh \
 	git-merge.sh git-merge-stupid.sh git-merge-octopus.sh \
 	git-merge-resolve.sh git-merge-ours.sh \
-	git-lost-found.sh git-quiltimport.sh
+	git-lost-found.sh git-quiltimport.sh git-submodule.sh
 
 SCRIPT_PERL = \
 	git-add--interactive.perl \
diff --git a/git-submodule.sh b/git-submodule.sh
new file mode 100755
index 0000000..c4a1cc3
--- /dev/null
+++ b/git-submodule.sh
@@ -0,0 +1,163 @@
+#!/bin/sh
+#
+# git-submodule.sh: init, update or list git submodules
+#
+# Copyright (c) 2007 Lars Hjemli
+
+USAGE='[-i | --init | -u | --update] [-q | --quiet] [--cached] <path>...'
+. git-sh-setup
+require_work_tree
+
+init=
+update=
+quiet=
+cached=
+
+#
+# print stuff on stdout unless -q was specified
+#
+say()
+{
+	if test -z "$quiet"
+	then
+		echo -e "$@"
+	fi
+}
+
+#
+# Find all (requested) submodules, run clone + checkout on missing paths
+#
+# $@ = requested paths (default to all)
+#
+modules_init()
+{
+	git ls-files --stage -- $@ | grep -e '^160000 ' |
+	while read mode sha1 stage path
+	do
+		test -d "$path/.git" && continue
+
+		if test -d "$path"
+		then
+			rmdir "$path" 2>/dev/null ||
+			die "Directory '$path' exist, but not as a submodule"
+		fi
+
+		test -e "$path" &&
+		die "A file already exist at path '$path'"
+
+		url=$(GIT_CONFIG=.gitmodules git-config module."$path".url)
+		test -z "$url" &&
+		die "No url found for submodule '$path' in .gitmodules"
+
+		git-clone "$url" "$path" ||
+		die "Clone of submodule '$path' failed"
+
+		$(cd "$path" && git-checkout -q "$sha1") ||
+		die "Checkout of submodule '$path' failed"
+
+		say "Submodule '$path' initialized"
+	done
+}
+
+#
+# Checkout correct revision of each initialized submodule
+#
+# $@ = requested paths (default to all)
+#
+modules_update()
+{
+	git ls-files --stage -- $@ | grep -e '^160000 ' |
+	while read mode sha1 stage path
+	do
+		if ! test -d "$path/.git"
+		then
+			say "Submodule '$path' not initialized"
+			continue;
+		fi
+		subsha1=$(cd "$path" && git-rev-parse --verify HEAD) ||
+		die "Unable to find current revision of submodule '$path'"
+
+		if test "$subsha1" != "$sha1"
+		then
+			$(cd "$path" && git-fetch && git-checkout -q "$sha1") ||
+			die "Unable to checkout revision $sha1 of submodule '$path'"
+
+			say "Submodule '$path' reset to revision $sha1"
+		fi
+	done
+}
+
+#
+# List all registered submodules, prefixed with:
+#  - submodule not initialized
+#  + different version checked out
+#
+# If --cached was specified the revision in the index will be printed
+# instead of the currently checked out revision.
+#
+# $@ = requested paths (default to all)
+#
+modules_list()
+{
+	git ls-files --stage -- $@ | grep -e '^160000 ' |
+	while read mode sha1 stage path
+	do
+		if ! test -d "$path/.git"
+		then
+			say "-$sha1 $path"
+			continue;
+		fi
+		revname=$(cd "$path" && git-describe $sha1)
+		if git diff-files --quiet -- "$path"
+		then
+			say " $sha1 $path\t($revname)"
+		else
+			if test -z "$cached"
+			then
+				sha1=$(cd "$path" && git-rev-parse --verify HEAD)
+				revname=$(cd "$path" && git-describe $sha1)
+			fi
+			say "+$sha1 $path\t($revname)"
+		fi
+	done
+}
+
+
+while case "$#" in 0) break ;; esac
+do
+	case "$1" in
+	-i|--init)
+		init=1
+		;;
+	-u|--update)
+		update=1
+		;;
+	-q|--quiet)
+		quiet=1
+		;;
+	--cached)
+		cached=1
+		;;
+	--)
+		break
+		;;
+	-*)
+		usage
+		;;
+	*)
+		break
+		;;
+	esac
+	shift
+done
+
+
+if test "$init" = "1"
+then
+	modules_init $@
+elif test "$update" = "1"
+then
+	modules_update $@
+else
+	modules_list $@
+fi
-- 
1.5.2.73.g18bece-dirty

Re: [PATCH] Add git-submodule command

From: Johannes Schindelin <hidden>
Date: 2016-06-15 22:43:12

Hi,

On Fri, 25 May 2007, Lars Hjemli wrote:
On 5/24/07, Johannes Schindelin [off-list ref] wrote:
quoted
On Thu, 24 May 2007, Lars Hjemli wrote:
quoted
What I think would be nice is some porcelain support to manually init,
update and see the checked out version of selected subprojects, but as
standalone commands.
Yes, a la git-remote. I'd be much happier with that, too, especially since
I think that this can be a relatively small and easy-to-review script.
So, here it is. Please be kind :)
Thank you very much! And it looks small enough that I will review it right 
away.
Btw: I've never managed to get asciidoc working on my machine, so the doc
isn't checked in any other format than plain text.
No problem, I will check that.

Ciao,
Dscho

Re: [PATCH] Add git-submodule command

From: Johannes Schindelin <hidden>
Date: 2016-06-15 22:43:12

Hi,

On Fri, 25 May 2007, Lars Hjemli wrote:
There is currently no way to override the mappings in the .gitmodules 
file, except by manually creating the subproject repository.
I think that is okay. We can add that easily at a later stage, and the 
script is much easier without that logic.
quoted hunk
diff --git a/Documentation/git-submodule.txt b/Documentation/git-submodule.txt
Looks good here, I checked with asciidoc.
quoted hunk
diff --git a/git-submodule.sh b/git-submodule.sh
new file mode 100755
index 0000000..c4a1cc3
--- /dev/null
+++ b/git-submodule.sh
@@ -0,0 +1,163 @@
+#!/bin/sh
+#
+# git-submodule.sh: init, update or list git submodules
+#
+# Copyright (c) 2007 Lars Hjemli
+
+USAGE='[-i | --init | -u | --update] [-q | --quiet] [--cached] <path>...'
+. git-sh-setup
+require_work_tree
+
+init=
+update=
+quiet=
+cached=
+
+#
+# print stuff on stdout unless -q was specified
+#
+say()
+{
+	if test -z "$quiet"
+	then
+		echo -e "$@"
+	fi
+}
+
+#
+# Find all (requested) submodules, run clone + checkout on missing paths
+#
+# $@ = requested paths (default to all)
+#
+modules_init()
+{
+	git ls-files --stage -- $@ | grep -e '^160000 ' |
Any reason you read in the stage? It does not seem that you use it.
+	while read mode sha1 stage path
+	do
+		test -d "$path/.git" && continue
+
+		if test -d "$path"
+		then
+			rmdir "$path" 2>/dev/null ||
+			die "Directory '$path' exist, but not as a submodule"
+		fi
+
+		test -e "$path" &&
+		die "A file already exist at path '$path'"
+
+		url=$(GIT_CONFIG=.gitmodules git-config module."$path".url)
I like that command ;-)
+		test -z "$url" &&
+		die "No url found for submodule '$path' in .gitmodules"
+
+		git-clone "$url" "$path" ||
+		die "Clone of submodule '$path' failed"
+
+		$(cd "$path" && git-checkout -q "$sha1") ||
+		die "Checkout of submodule '$path' failed"
+
+		say "Submodule '$path' initialized"
+	done
+}
+
+#
+# Checkout correct revision of each initialized submodule
+#
+# $@ = requested paths (default to all)
+#
+modules_update()
+{
+	git ls-files --stage -- $@ | grep -e '^160000 ' |
Same here.
+	while read mode sha1 stage path
+	do
+		if ! test -d "$path/.git"
+		then
+			say "Submodule '$path' not initialized"
+			continue;
+		fi
+		subsha1=$(cd "$path" && git-rev-parse --verify HEAD) ||
Maybe it would be a better idea to use "git --git-dir="$path" rev-parse 
..."? Just in case somebody calls this with GIT_DIR overridden...

Or, unset GIT_DIR explicitely.
+		die "Unable to find current revision of submodule '$path'"
+
+		if test "$subsha1" != "$sha1"
+		then
+			$(cd "$path" && git-fetch && git-checkout -q "$sha1") ||
This will make a detached HEAD, right? Do you want that? (I am not really 
interested in submodules myself, so I haven't thought about it, and I 
haven't followed that monster discussion.)
+			die "Unable to checkout revision $sha1 of submodule '$path'"
+
+			say "Submodule '$path' reset to revision $sha1"
I'd rather not say "reset", since this has a different meaning in Git, but 
rather "set to revision $sha1".
+		fi
+	done
+}
+
+#
+# List all registered submodules, prefixed with:
+#  - submodule not initialized
+#  + different version checked out
+#
+# If --cached was specified the revision in the index will be printed
+# instead of the currently checked out revision.
+#
+# $@ = requested paths (default to all)
+#
+modules_list()
+{
+	git ls-files --stage -- $@ | grep -e '^160000 ' |
+	while read mode sha1 stage path
+	do
+		if ! test -d "$path/.git"
+		then
+			say "-$sha1 $path"
+			continue;
+		fi
+		revname=$(cd "$path" && git-describe $sha1)
+		if git diff-files --quiet -- "$path"
+		then
+			say " $sha1 $path\t($revname)"
+		else
+			if test -z "$cached"
+			then
+				sha1=$(cd "$path" && git-rev-parse --verify HEAD)
+				revname=$(cd "$path" && git-describe $sha1)
+			fi
+			say "+$sha1 $path\t($revname)"
+		fi
+	done
+}
+
+
+while case "$#" in 0) break ;; esac
+do
+	case "$1" in
+	-i|--init)
+		init=1
+		;;
+	-u|--update)
+		update=1
+		;;
+	-q|--quiet)
+		quiet=1
+		;;
+	--cached)
+		cached=1
+		;;
+	--)
+		break
+		;;
+	-*)
+		usage
+		;;
+	*)
+		break
+		;;
+	esac
+	shift
+done
+
+
+if test "$init" = "1"
+then
+	modules_init $@
+elif test "$update" = "1"
+then
+	modules_update $@
+else
+	modules_list $@
+fi
I'll let Junio comment on that command line parsing...

All in all, I like it: it is short, to the point, and it should do the job 
(maybe with a few enhancements like "--update" without arguments means 
_all_ submodules).

Ciao,
Dscho

Re: [PATCH] Add git-submodule command

From: Lars Hjemli <hidden>
Date: 2016-06-15 22:43:12

On 5/25/07, Johannes Schindelin [off-list ref] wrote:
Hi,

On Fri, 25 May 2007, Lars Hjemli wrote:
quoted
There is currently no way to override the mappings in the .gitmodules
file, except by manually creating the subproject repository.
I think that is okay. We can add that easily at a later stage, and the
script is much easier without that logic.
Yes. And it is sort of a feature: if you've cloned the submodule using
a different (aka local) url, 'git submodule --init' will leave it
alone.
quoted
diff --git a/Documentation/git-submodule.txt b/Documentation/git-submodule.txt
Looks good here, I checked with asciidoc.
Thanks.
quoted
diff --git a/git-submodule.sh b/git-submodule.sh
new file mode 100755
index 0000000..c4a1cc3
--- /dev/null
+++ b/git-submodule.sh
@@ -0,0 +1,163 @@
+#!/bin/sh
+#
+# git-submodule.sh: init, update or list git submodules
+#
+# Copyright (c) 2007 Lars Hjemli
+
+USAGE='[-i | --init | -u | --update] [-q | --quiet] [--cached] <path>...'
+. git-sh-setup
+require_work_tree
+
+init=
+update=
+quiet=
+cached=
+
+#
+# print stuff on stdout unless -q was specified
+#
+say()
+{
+     if test -z "$quiet"
+     then
+             echo -e "$@"
+     fi
+}
+
+#
+# Find all (requested) submodules, run clone + checkout on missing paths
+#
+# $@ = requested paths (default to all)
+#
+modules_init()
+{
+     git ls-files --stage -- $@ | grep -e '^160000 ' |
Any reason you read in the stage? It does not seem that you use it.
Are there any other way to get the mode info?

quoted
+     while read mode sha1 stage path
+     do
+             test -d "$path/.git" && continue
+
+             if test -d "$path"
+             then
+                     rmdir "$path" 2>/dev/null ||
+                     die "Directory '$path' exist, but not as a submodule"
+             fi
+
+             test -e "$path" &&
+             die "A file already exist at path '$path'"
+
+             url=$(GIT_CONFIG=.gitmodules git-config module."$path".url)
I like that command ;-)
quoted
+             test -z "$url" &&
+             die "No url found for submodule '$path' in .gitmodules"
+
+             git-clone "$url" "$path" ||
+             die "Clone of submodule '$path' failed"
+
+             $(cd "$path" && git-checkout -q "$sha1") ||
+             die "Checkout of submodule '$path' failed"
+
+             say "Submodule '$path' initialized"
+     done
+}
+
+#
+# Checkout correct revision of each initialized submodule
+#
+# $@ = requested paths (default to all)
+#
+modules_update()
+{
+     git ls-files --stage -- $@ | grep -e '^160000 ' |
Same here.
quoted
+     while read mode sha1 stage path
+     do
+             if ! test -d "$path/.git"
+             then
+                     say "Submodule '$path' not initialized"
+                     continue;
+             fi
+             subsha1=$(cd "$path" && git-rev-parse --verify HEAD) ||
Maybe it would be a better idea to use "git --git-dir="$path" rev-parse
..."? Just in case somebody calls this with GIT_DIR overridden...

Or, unset GIT_DIR explicitely.
Hmm, that's annoying (overridden GIT_DIR). I guess 'git --git-dir
$path/.git' would be the easiest solution.

quoted
+             die "Unable to find current revision of submodule '$path'"
+
+             if test "$subsha1" != "$sha1"
+             then
+                     $(cd "$path" && git-fetch && git-checkout -q "$sha1") ||
This will make a detached HEAD, right? Do you want that? (I am not really
interested in submodules myself, so I haven't thought about it, and I
haven't followed that monster discussion.)
Well, we might want to be smarter about this, but on the other hand:
if the user cares, he can always do 'cd $path && git checkout
$branch', since 'git submodule -u' will skip submodules with the
correct commit checked out.
quoted
+                     die "Unable to checkout revision $sha1 of submodule '$path'"
+
+                     say "Submodule '$path' reset to revision $sha1"
I'd rather not say "reset", since this has a different meaning in Git, but
rather "set to revision $sha1".
Ok.
quoted
+             fi
+     done
+}
+
+#
+# List all registered submodules, prefixed with:
+#  - submodule not initialized
+#  + different version checked out
+#
+# If --cached was specified the revision in the index will be printed
+# instead of the currently checked out revision.
+#
+# $@ = requested paths (default to all)
+#
+modules_list()
+{
+     git ls-files --stage -- $@ | grep -e '^160000 ' |
+     while read mode sha1 stage path
+     do
+             if ! test -d "$path/.git"
+             then
+                     say "-$sha1 $path"
+                     continue;
+             fi
+             revname=$(cd "$path" && git-describe $sha1)
+             if git diff-files --quiet -- "$path"
+             then
+                     say " $sha1 $path\t($revname)"
+             else
+                     if test -z "$cached"
+                     then
+                             sha1=$(cd "$path" && git-rev-parse --verify HEAD)
+                             revname=$(cd "$path" && git-describe $sha1)
+                     fi
+                     say "+$sha1 $path\t($revname)"
+             fi
+     done
+}
+
+
+while case "$#" in 0) break ;; esac
+do
+     case "$1" in
+     -i|--init)
+             init=1
+             ;;
+     -u|--update)
+             update=1
+             ;;
+     -q|--quiet)
+             quiet=1
+             ;;
+     --cached)
+             cached=1
+             ;;
+     --)
+             break
+             ;;
+     -*)
+             usage
+             ;;
+     *)
+             break
+             ;;
+     esac
+     shift
+done
+
+
+if test "$init" = "1"
+then
+     modules_init $@
+elif test "$update" = "1"
+then
+     modules_update $@
+else
+     modules_list $@
+fi
I'll let Junio comment on that command line parsing...
Heh, I'm a shell illiterate...
All in all, I like it: it is short, to the point, and it should do the job
(maybe with a few enhancements like "--update" without arguments means
_all_ submodules).
Well, it does (or should) update all initialized submodules, but maybe
that's not what you meant?

Thanks for the review!

--
larsh

Re: [PATCH] Add git-submodule command

From: Johannes Schindelin <hidden>
Date: 2016-06-15 22:43:12

Hi,

On Fri, 25 May 2007, Lars Hjemli wrote:
On 5/25/07, Johannes Schindelin [off-list ref] wrote:
quoted
On Fri, 25 May 2007, Lars Hjemli wrote:
quoted
+modules_init()
+{
+     git ls-files --stage -- $@ | grep -e '^160000 ' |
Any reason you read in the stage? It does not seem that you use it.
Are there any other way to get the mode info?
Ah, I missed that. Right.
quoted
quoted
+             subsha1=$(cd "$path" && git-rev-parse --verify HEAD) ||
Maybe it would be a better idea to use "git --git-dir="$path" 
rev-parse ..."? Just in case somebody calls this with GIT_DIR 
overridden...

Or, unset GIT_DIR explicitely.
Hmm, that's annoying (overridden GIT_DIR). I guess 'git --git-dir 
$path/.git' would be the easiest solution.
But you have to repeat it on every subsequent Git command. OTOH if you 
unset GIT_DIR, you can no longer be sure that you have the correct git dir 
for Git calls in the superproject...
quoted
quoted
+             die "Unable to find current revision of submodule '$path'"
+
+             if test "$subsha1" != "$sha1"
+             then
+                     $(cd "$path" && git-fetch && git-checkout -q
"$sha1") ||

This will make a detached HEAD, right? Do you want that? (I am not 
really interested in submodules myself, so I haven't thought about it, 
and I haven't followed that monster discussion.)
Well, we might want to be smarter about this, but on the other hand: if 
the user cares, he can always do 'cd $path && git checkout $branch', 
since 'git submodule -u' will skip submodules with the correct commit 
checked out.
Fair enough, I guess...
quoted
I'll let Junio comment on that command line parsing...
Heh, I'm a shell illiterate...
;-)

I guess Junio would like one of his famous

	case ,"$init","$update",[...] in
	*1*1) usage
	esac

to prevent running with two actions...
quoted
All in all, I like it: it is short, to the point, and it should do the 
job (maybe with a few enhancements like "--update" without arguments 
means _all_ submodules).
Well, it does (or should) update all initialized submodules, but maybe 
that's not what you meant?
Oops. I meant "init". I mean, most people who want to clone a superproject 
want the submodules being initialized without hassles, probably. But maybe 
that should be another option: "--clone-superproject" or something. Dunno. 
There's time for that after the initial git-submodule.

Ciao,
Dscho

Re: [PATCH] Add git-submodule command

From: Lars Hjemli <hidden>
Date: 2016-06-15 22:43:12

On 5/25/07, Johannes Schindelin [off-list ref] wrote:
On Fri, 25 May 2007, Lars Hjemli wrote:
quoted
On 5/25/07, Johannes Schindelin [off-list ref] wrote:
quoted
On Fri, 25 May 2007, Lars Hjemli wrote:
quoted
+             die "Unable to find current revision of submodule '$path'"
+
+             if test "$subsha1" != "$sha1"
+             then
+                     $(cd "$path" && git-fetch && git-checkout -q
"$sha1") ||

This will make a detached HEAD, right? Do you want that? (I am not
really interested in submodules myself, so I haven't thought about it,
and I haven't followed that monster discussion.)
Well, we might want to be smarter about this, but on the other hand: if
the user cares, he can always do 'cd $path && git checkout $branch',
since 'git submodule -u' will skip submodules with the correct commit
checked out.
Fair enough, I guess...
The only alternative I can think of is to check if module.$path.branch
is specified in .gitmodules: if it is, and it's pointing at the wanted
sha1, the right thing would be to checkout that branch. Any other sort
of dwim is bound to get it wrong.

quoted
quoted
I'll let Junio comment on that command line parsing...
Heh, I'm a shell illiterate...
;-)

I guess Junio would like one of his famous

        case ,"$init","$update",[...] in
        *1*1) usage
        esac

to prevent running with two actions...
Ahh, that's something I can handle

quoted
quoted
All in all, I like it: it is short, to the point, and it should do the
job (maybe with a few enhancements like "--update" without arguments
means _all_ submodules).
Well, it does (or should) update all initialized submodules, but maybe
that's not what you meant?
Oops. I meant "init".
Hmm, it does (or should) clone all submodules if you run 'git
submodule --init' (no paths specified). Did it fail for you?


-- 
larsh

Re: [PATCH] Add git-submodule command

From: Johannes Schindelin <hidden>
Date: 2016-06-15 22:43:12

Hi,

On Fri, 25 May 2007, Lars Hjemli wrote:
On 5/25/07, Johannes Schindelin [off-list ref] wrote:
quoted
On Fri, 25 May 2007, Lars Hjemli wrote:
quoted
On 5/25/07, Johannes Schindelin [off-list ref] wrote:
quoted
All in all, I like it: it is short, to the point, and it should do 
the job (maybe with a few enhancements like "--update" without 
arguments means _all_ submodules).
Well, it does (or should) update all initialized submodules, but 
maybe that's not what you meant?
Oops. I meant "init".
Hmm, it does (or should) clone all submodules if you run 'git submodule 
--init' (no paths specified). Did it fail for you?
I don't have any superproject to try with ;-)

Actually, I missed the "$@" in modules_init. You might want to change the 
documentation, though, since it suggests (at least to yours truly) that 
you _need_ to pass a path with "--init".

Even happier,
Dscho

Re: [PATCH] Add git-submodule command

From: Lars Hjemli <hidden>
Date: 2016-06-15 22:43:12

On 5/25/07, Johannes Schindelin [off-list ref] wrote:
Hi,

On Fri, 25 May 2007, Lars Hjemli wrote:
quoted
On 5/25/07, Johannes Schindelin [off-list ref] wrote:
quoted
On Fri, 25 May 2007, Lars Hjemli wrote:
quoted
On 5/25/07, Johannes Schindelin [off-list ref] wrote:
quoted
All in all, I like it: it is short, to the point, and it should do
the job (maybe with a few enhancements like "--update" without
arguments means _all_ submodules).
Well, it does (or should) update all initialized submodules, but
maybe that's not what you meant?
Oops. I meant "init".
Hmm, it does (or should) clone all submodules if you run 'git submodule
--init' (no paths specified). Did it fail for you?
I don't have any superproject to try with ;-)
You could always try cgit ;-)
Actually, I missed the "$@" in modules_init. You might want to change the
documentation, though, since it suggests (at least to yours truly) that
you _need_ to pass a path with "--init".
Ok, will do.

--
larsh

[PATCH] Add git-submodule command

From: Lars Hjemli <hidden>
Date: 2016-06-15 22:43:12

This command can be used to initialize, update and inspect submodules. It
uses a .gitmodules file, readable by git-config, in the top level directory
of the 'superproject' to specify a mapping between submodule paths and
repository url. There is currently no way to override the mappings in the
.gitmodules file, except by manually creating the subproject repository.

Example .gitmodules layout:

[module "git"]
	url = git://git.kernel.org/pub/scm/git/git.git
	branch = maint

The branch-key in .gitmodules is optional. When specified, 'git-submodule -u'
will checkout the named branch if its tip matches the commit-sha1 in the
superprojects index. Otherwise, 'git-submodule -u' will create a detached
HEAD in the submodule.

Signed-off-by: Lars Hjemli <redacted>
---

This is an updated patch that hopefully deals with all the previous issues.

I've also added support for specifying module.$path.branch in .gitmodules,
but not support for general url rewriting based on local config. If that
is a wanted feature, it should be trivial to add later on.

Btw: testing this quickly becomes tedious, so I'll try to make a proper
testscript later tonight.


 Documentation/git-submodule.txt |   63 ++++++++++++++
 Makefile                        |    2 +-
 git-submodule.sh                |  178 +++++++++++++++++++++++++++++++++++++++
 3 files changed, 242 insertions(+), 1 deletions(-)
 create mode 100644 Documentation/git-submodule.txt
 create mode 100755 git-submodule.sh
diff --git a/Documentation/git-submodule.txt b/Documentation/git-submodule.txt
new file mode 100644
index 0000000..81236aa
--- /dev/null
+++ b/Documentation/git-submodule.txt
@@ -0,0 +1,63 @@
+git-submodule(1)
+================
+
+NAME
+----
+git-submodule - Initialize, update or inspect submodules
+
+
+SYNOPSIS
+--------
+'git-submodule' [--init | --update | --cached] [--quiet] [--] [<path>...]
+
+
+DESCRIPTION
+-----------
+The command shows the status of each specified submodule path, or all
+submodules if none is specified. Each submodule sha1 is prefixed with '-'
+if the submodule is uninitialized and '+' if the checked out version of
+the submodule is different from the commit sha1 stored in the index.
+
+
+OPTIONS
+-------
+<path>::
+	Path to submodule(s)
+
+-i, --init::
+	Initialize the specified submodules, i.e. clone the git repository
+	specified in .gitmodules and checkout the sha1 specified in the
+	index.
+
+-u, --update::
+	Update the specified submodules, i.e. checkout the sha1 specified
+	in the index
+
+--cached::
+	Display the sha1 stored in the index, not the currently checked
+	out revsion.
+
+-q, --quiet::
+	Be quiet
+
+
+FILES
+-----
+When cloning submodules, a .gitmodules file in the top-level directory
+of the containing work-tree is examined for the url of each submodule.
+The url is the value of the key module.$path.url.
+
+When updating submodules, the same .gitmodules file is examined for a key
+named 'module.$path.branch'. If found, and if the named branch is currently
+at the same revision as the commit-id in the containing repositories index,
+the specified branch will be checked out in the submodule. If not found, or
+if the branch isn't currently positioned at the wanted revision, a checkout
+of the wanted sha1 will happen in the submodule, leaving its HEAD detached.
+
+Author
+------
+Written by Lars Hjemli <hjemli@gmail.com>
+
+GIT
+---
+Part of the gitlink:git[7] suite
diff --git a/Makefile b/Makefile
index 29243c6..5cf2169 100644
--- a/Makefile
+++ b/Makefile
@@ -209,7 +209,7 @@ SCRIPT_SH = \
 	git-applymbox.sh git-applypatch.sh git-am.sh \
 	git-merge.sh git-merge-stupid.sh git-merge-octopus.sh \
 	git-merge-resolve.sh git-merge-ours.sh \
-	git-lost-found.sh git-quiltimport.sh
+	git-lost-found.sh git-quiltimport.sh git-submodule.sh
 
 SCRIPT_PERL = \
 	git-add--interactive.perl \
diff --git a/git-submodule.sh b/git-submodule.sh
new file mode 100755
index 0000000..51a0f47
--- /dev/null
+++ b/git-submodule.sh
@@ -0,0 +1,178 @@
+#!/bin/sh
+#
+# git-submodules.sh: init, update or list git submodules
+#
+# Copyright (c) 2007 Lars Hjemli
+
+USAGE='[--init | --update | --cached] [--quiet] [--] [<path>...]'
+. git-sh-setup
+require_work_tree
+
+init=
+update=
+quiet=
+cached=
+
+#
+# print stuff on stdout unless -q was specified
+#
+say()
+{
+	if test -z "$quiet"
+	then
+		echo -e "$@"
+	fi
+}
+
+#
+# Run clone + checkout on missing submodules
+#
+# $@ = requested paths (default to all)
+#
+modules_init()
+{
+	git ls-files --stage -- $@ | grep -e '^160000 ' |
+	while read mode sha1 stage path
+	do
+		test -d "$path/.git" && continue
+
+		if test -d "$path"
+		then
+			rmdir "$path" 2>/dev/null ||
+			die "Directory '$path' exist, but not as a submodule"
+		fi
+
+		test -e "$path" &&
+		die "A file already exist at path '$path'"
+
+		url=$(GIT_CONFIG=.gitmodules git-config module."$path".url)
+		test -z "$url" &&
+		die "No url found for submodule '$path' in .gitmodules"
+
+		git-clone "$url" "$path" ||
+		die "Clone of submodule '$path' failed"
+
+		$(unset GIT_DIR && cd "$path" && git-checkout -q "$sha1") ||
+		die "Checkout of submodule '$path' failed"
+
+		say "Submodule '$path' initialized"
+	done
+}
+
+#
+# Checkout correct revision of each initialized submodule
+#
+# $@ = requested paths (default to all)
+#
+modules_update()
+{
+	git ls-files --stage -- $@ | grep -e '^160000 ' |
+	while read mode rev stage path
+	do
+		if ! test -d "$path/.git"
+		then
+			say "Submodule '$path' not initialized"
+			continue;
+		fi
+		subsha1=$(unset GIT_DIR && cd "$path" && git-rev-parse --verify HEAD) ||
+		die "Unable to find current revision of submodule '$path'"
+
+		if test "$subsha1" != "$rev"
+		then
+			$(unset GIT_DIR && cd "$path" && git-fetch)
+			branch=$(GIT_CONFIG=.gitmodules git-config module."$path".branch)
+			if test "$branch" != ""
+			then
+				branch_sha1=$(unset GIT_DIR && cd "$path" &&
+					git-rev-parse --verify "$branch")
+				if test "$branch_sha1" = "$rev"
+				then
+					rev="$branch"
+				fi
+			fi
+			$(unset GIT_DIR && cd "$path" && git-checkout -q "$rev") ||
+			die "Unable to checkout '$rev' in submodule '$path'"
+
+			say "Submodule '$path': checked out '$rev'"
+		fi
+	done
+}
+
+#
+# List all registered submodules, prefixed with:
+#  - submodule not initialized
+#  + different version checked out
+#
+# If --cached was specified the revision in the index will be printed
+# instead of the currently checked out revision.
+#
+# $@ = requested paths (default to all)
+#
+modules_list()
+{
+	git ls-files --stage -- $@ | grep -e '^160000 ' |
+	while read mode sha1 stage path
+	do
+		if ! test -d "$path/.git"
+		then
+			say "-$sha1 $path"
+			continue;
+		fi
+		revname=$(unset GIT_DIR && cd "$path" && git-describe $sha1)
+		if git diff-files --quiet -- "$path"
+		then
+			say " $sha1 $path\t($revname)"
+		else
+			if test -z "$cached"
+			then
+				sha1=$(unset GIT_DIR && cd "$path" && git-rev-parse --verify HEAD)
+				revname=$(unset GIT_DIR && cd "$path" && git-describe $sha1)
+			fi
+			say "+$sha1 $path\t($revname)"
+		fi
+	done
+}
+
+
+while case "$#" in 0) break ;; esac
+do
+	case "$1" in
+	-i|--init)
+		init=1
+		;;
+	-u|--update)
+		update=1
+		;;
+	-q|--quiet)
+		quiet=1
+		;;
+	--cached)
+		cached=1
+		;;
+	--)
+		break
+		;;
+	-*)
+		usage
+		;;
+	*)
+		break
+		;;
+	esac
+	shift
+done
+
+case "$init,$update,$cached" in
+1,,)
+	modules_init $@
+	;;
+,1,)
+	modules_update $@
+	;;
+,,*)
+	modules_list $@
+	;;
+*)
+	usage
+	;;
+esac
-- 
1.5.2.74.gea9f

Re: [PATCH] Add git-submodule command

From: Johannes Schindelin <hidden>
Date: 2016-06-15 22:43:12

Hi,

On Fri, 25 May 2007, Lars Hjemli wrote:
Btw: testing this quickly becomes tedious, so I'll try to make a proper 
testscript later tonight.
Very good.
+'git-submodule' [--init | --update | --cached] [--quiet] [--] [<path>...]
I did not realize this earlier, but we seem to have more and more programs 
where actions are specified without "--", i.e. "git-svn fetch", or 
"git-bundle create".

I actually like that, to separate actions from options. Hmm?
+-i, --init::
+	Initialize the specified submodules, i.e. clone the git repository
+	specified in .gitmodules and checkout the sha1 specified in the
+	index.
How about "Initialize the submodules...", and then another sentence "If 
you do not want to initialize all submodules, you can specify the subset 
to initialize"?
+-u, --update::
+	Update the specified submodules, i.e. checkout the sha1 specified
+	in the index
The full stop is missing here. And again, I would add another sentence 
"Submodules which have not been initialized are not touched by this 
operation."
+FILES
+-----
+When cloning submodules, a .gitmodules file in the top-level directory
+of the containing work-tree is examined for the url of each submodule.
+The url is the value of the key module.$path.url.
IIRC Junio talked about a name for overriding. But I think it would be 
even better to to override by mapping the URLs from .gitmodules to the 
locally-wanted URLs.

Junio?
+When updating submodules, the same .gitmodules file is examined for a key
+named 'module.$path.branch'. If found, and if the named branch is currently 
+at the same revision as the commit-id in the containing repositories index, 
+the specified branch will be checked out in the submodule. If not found, or 
+if the branch isn't currently positioned at the wanted revision, a checkout
+of the wanted sha1 will happen in the submodule, leaving its HEAD detached.
A very good description, and I think this is the only method to checkout 
the submodule which makes sense. (Just maybe default the value of 
module.<path>.branch to "master"?)
quoted hunk
+++ b/git-submodule.sh
@@ -0,0 +1,178 @@
+#!/bin/sh
+#
+# git-submodules.sh: init, update or list git submodules
+#
+# Copyright (c) 2007 Lars Hjemli
+
+USAGE='[--init | --update | --cached] [--quiet] [--] [<path>...]'
+. git-sh-setup
+require_work_tree
Maybe

	test -f "$GIT_DIR"/.gitmodules || die "Not a superproject"

Hmm?
+			rmdir "$path" 2>/dev/null ||
Just out of curiousity: is rmdir portable? I always used "rm -r"...
+case "$init,$update,$cached" in
+1,,)
+	modules_init $@
+	;;
:-)

Now I run out of comments...

Ciao,
Dscho

Re: [PATCH] Add git-submodule command

From: Linus Torvalds <torvalds@linux-foundation.org>
Date: 2016-06-15 22:43:12


On Fri, 25 May 2007, Johannes Schindelin wrote:
I did not realize this earlier, but we seem to have more and more programs 
where actions are specified without "--", i.e. "git-svn fetch", or 
"git-bundle create".
Hey, don't forget "git bisect", the granddaddy of them all.
I actually like that, to separate actions from options. Hmm?
I agree. If something effectively always takes a separate command, it's 
not an option, it's a subcommand.

		Linus

Re: [PATCH] Add git-submodule command

From: Johannes Schindelin <hidden>
Date: 2016-06-15 22:43:12

Hi,

On Fri, 25 May 2007, Linus Torvalds wrote:
On Fri, 25 May 2007, Johannes Schindelin wrote:
quoted
I did not realize this earlier, but we seem to have more and more programs 
where actions are specified without "--", i.e. "git-svn fetch", or 
"git-bundle create".
Hey, don't forget "git bisect", the granddaddy of them all.
Oh, sorry! How could I? Respect the elders. ;-)

Ciao,
Dscho

Re: [PATCH] Add git-submodule command

From: Lars Hjemli <hidden>
Date: 2016-06-15 22:43:12

On 5/25/07, Johannes Schindelin [off-list ref] wrote:
[* many usefull comments about the docs *]
Thanks, will fix
quoted
+USAGE='[--init | --update | --cached] [--quiet] [--] [<path>...]'
+. git-sh-setup
+require_work_tree
Maybe

        test -f "$GIT_DIR"/.gitmodules || die "Not a superproject"

Hmm?
Yeah, maybe. But the command will only touch entries with mode 160000
anyway, so it might not be a big deal.
quoted
+                     rmdir "$path" 2>/dev/null ||
Just out of curiousity: is rmdir portable? I always used "rm -r"...
I have no idea, really. But the reason for using rmdir was this
section of the man page:

NAME
       rmdir - remove empty directories

I do not want to delete an unempty directory. But there is probably
some better way to do this?

--
larsh
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help