Re: [PATCH] Add git-submodule command

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

Re: [PATCH] Add git-submodule command

From: Junio C Hamano <hidden>
Date: 2016-06-15 22:43:12

"Lars Hjemli" [off-list ref] writes:
On 5/25/07, Junio C Hamano [off-list ref] wrote:
...
quoted
I really do not want that (mis)conception that .gitmodules
specify the default and .git/config the override.  I really
think we should use the .git/config as _the_ only authority to
get URL, but keyed with the three-level scheme, with URL in
.gitmodules used _solely_ as a hint when setting up the URL in
the .git/config file.

        cf. $gmane/47502, 47548, 47621
I've read these articles, but I think much of the concerns about
trusting the url supplied by upstream goes away when the submodule
clone/checkout isn't an integrated part of the superproject
clone/checkout. Besides, if you trust your upstream enough to clone
their repository (the superproject), why wouldn't you trust the data
(.gitmodules) in that very repository?
It's not about trusting.  You would need to support the mapping
for network connectivity reasons, and you would also need to
notice and reconfirm when the suggested URL in .gitmodules
changes (perhaps because the upstream relocated from sf.net to
repo.or.cz ;-), you would need something like what I described
in order to keep track of user preference for each submodule in
.git/config anyway.  If that "mapping" ends up to be ident
mapping for most people, that is fine.  At least by always doing
the three-level mapping we would not have any special case in
the code, and this is not the performance critical part of the
system.

I think the response to the case when upstream repository
relocates from the ".gitmodule for default, .git/config for
override" camp would be "you asked to override in .git/config,
so it is your job to notice the change in .gitmodules and adjust
your override URL".  That is a serious mistake in usability
point of view.  Repository relocation would (hopefully) seldom
happen, but when it does happen, things either would break
(which is easier to diagnose and manually fix up), or things
clone fine but we reach a wrong repository (which is harder to
notice, as "fetch" may succeed -- it just would not fetch the
right commit).  Being able to notice when upstream repository
relocates and to ask for confirmation when that happens would
eliminate a lot of confusion from that.
Another possibility is simply doing the submodule clone/checkout by
hand (i.e. do 'git clone preferred-url path', don't do 'git submodule
init path').
But that is what this patch is trying to help the users, isn't
it?  It reduces the attractiveness of this new tool greatly if
you give up there.
quoted
When the name of the commit object in the
superproject tree and/or index is 0{40}, it would be a good
extension to use "whatever commit that happens to be at the tip
of this branch" taken from the .gitmodules file.
I really can't imagine what kind of superproject would have such a
setup. Why would this be needed?
"We would work with any working version of Linux 2.6 kernel"
would be a sensible thing to say, I would think.

It's purely optional, and as you seem to agree always detaching
HEAD is easier to explain, you do not need "module.$path.branch"
at all.  I just mentioned 0{40} as a possible use case for that
configuration variable.

Re: [PATCH] Add git-submodule command

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

[This thread is starting to get long, sorry for even more noise about
the submodule stuff]

On 5/25/07, Junio C Hamano [off-list ref] wrote:
"Lars Hjemli" [off-list ref] writes:
quoted
On 5/25/07, Junio C Hamano [off-list ref] wrote:
...
quoted
I really do not want that (mis)conception that .gitmodules
specify the default and .git/config the override.  I really
think we should use the .git/config as _the_ only authority to
get URL, but keyed with the three-level scheme, with URL in
.gitmodules used _solely_ as a hint when setting up the URL in
the .git/config file.

        cf. $gmane/47502, 47548, 47621
I've read these articles, but I think much of the concerns about
trusting the url supplied by upstream goes away when the submodule
clone/checkout isn't an integrated part of the superproject
clone/checkout. Besides, if you trust your upstream enough to clone
their repository (the superproject), why wouldn't you trust the data
(.gitmodules) in that very repository?
It's not about trusting.  You would need to support the mapping
for network connectivity reasons, and you would also need to
notice and reconfirm when the suggested URL in .gitmodules
changes (perhaps because the upstream relocated from sf.net to
repo.or.cz ;-), you would need something like what I described
in order to keep track of user preference for each submodule in
.git/config anyway.  If that "mapping" ends up to be ident
mapping for most people, that is fine.  At least by always doing
the three-level mapping we would not have any special case in
the code, and this is not the performance critical part of the
system.

I think the response to the case when upstream repository
relocates from the ".gitmodule for default, .git/config for
override" camp would be "you asked to override in .git/config,
so it is your job to notice the change in .gitmodules and adjust
your override URL".  That is a serious mistake in usability
point of view.  Repository relocation would (hopefully) seldom
happen, but when it does happen, things either would break
(which is easier to diagnose and manually fix up), or things
clone fine but we reach a wrong repository (which is harder to
notice, as "fetch" may succeed -- it just would not fetch the
right commit).  Being able to notice when upstream repository
relocates and to ask for confirmation when that happens would
eliminate a lot of confusion from that.
Basically, I'd say that as long as the superproject names the sha1 of
the submodule commit, nothing else matters.

If you track a submodule, you would easily notice it if the submodule
has the 'wrong' commit checked out (git diff, git status, git
submodule status). And 'git submodule update' would synchronize the
submodules you have decided to track, or error out with a message like
"Unable to checkout '$sha1' in submodule '$path'".

This is when the ugly sides of submodules raises its head (the
'official' repo has moved, my local repo is out of date, whatever). I
just don't see the need for solving those problems now. The 'git
submodule' command would make the common cases easier. Hopefully(?)
that would encourage more people to test/use submodules, and the
problems that actually _needs_ solving will then show up in due time.
quoted
Another possibility is simply doing the submodule clone/checkout by
hand (i.e. do 'git clone preferred-url path', don't do 'git submodule
init path').
But that is what this patch is trying to help the users, isn't
it?  It reduces the attractiveness of this new tool greatly if
you give up there.
Well, I happen to think that the average user of submodules wouldn't
care the slightest bit where the submodule was cloned from, as long as
the sha1 matches. So no, the patch was more about the lack of
submodule porcelain and less about completeness.

quoted
quoted
When the name of the commit object in the
superproject tree and/or index is 0{40}, it would be a good
extension to use "whatever commit that happens to be at the tip
of this branch" taken from the .gitmodules file.
I really can't imagine what kind of superproject would have such a
setup. Why would this be needed?
"We would work with any working version of Linux 2.6 kernel"
would be a sensible thing to say, I would think.
Maybe. I wouldn't want to automatically track the tip of _any_ branch,
since I would have no way of knowing if what works today will also
work tomorrow (or even compile).
It's purely optional, and as you seem to agree always detaching
HEAD is easier to explain, you do not need "module.$path.branch"
at all.  I just mentioned 0{40} as a possible use case for that
configuration variable.
Ok.

I'll redo the patch, removing the branch-specific things, and try to shut up :)

-- 
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

With this entry in .gitmodules (and a commit reference in the index entry for
the path "git"), the command 'git submodule init' will clone the repository
at kernel.org into the directory "git".

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

On 5/26/07, Lars Hjemli [off-list ref] wrote:
I'll redo the patch, removing the branch-specific things, and try to
shut up :)
This is my final uttering ;-)


 .gitignore                      |    1 +
 Documentation/git-submodule.txt |   65 +++++++++++++++
 Makefile                        |    2 +-
 git-submodule.sh                |  172 +++++++++++++++++++++++++++++++++++++++
 4 files changed, 239 insertions(+), 1 deletions(-)
 create mode 100644 Documentation/git-submodule.txt
 create mode 100755 git-submodule.sh
diff --git a/.gitignore b/.gitignore
index 4dc0c39..8fc4923 100644
--- a/.gitignore
+++ b/.gitignore
@@ -126,6 +126,7 @@ git-ssh-push
 git-ssh-upload
 git-status
 git-stripspace
+git-submodule
 git-svn
 git-svnimport
 git-symbolic-ref
diff --git a/Documentation/git-submodule.txt b/Documentation/git-submodule.txt
new file mode 100644
index 0000000..2135331
--- /dev/null
+++ b/Documentation/git-submodule.txt
@@ -0,0 +1,65 @@
+git-submodule(1)
+================
+
+NAME
+----
+git-submodule - Initialize, update or inspect submodules
+
+
+SYNOPSIS
+--------
+'git-submodule' [--quiet] [--cached] [status|init|update] [--] [<path>...]
+
+
+COMMANDS
+--------
+status::
+	Show the status of the submodules. This will print the sha1 of the
+	currently checked out commit for each submodule, along with the
+	submodule path and the output of gitlink:git-describe[1] for the
+	sha1. Each sha1 will be prefixed with '-' if the submodule is not
+	initialized and '+' if the currently checked out submodule commit
+	does not match the sha1 found in the index of the containing
+	repository. This command is the default command for git-submodule.
+
+init::
+	Initialize the submodules, i.e. clone the git repositories specified
+	in the .gitmodules file and checkout the submodule commits specified
+	in the index of the containing repository. This will make the
+	submodules HEAD be detached.
+
+update::
+	Update the initialized submodules, i.e. checkout the submodule commits
+	specified in the index of the containing repository. This will make
+	the submodules HEAD be detached.
+
+
+OPTIONS
+-------
+-q, --quiet::
+	Only print error messages.
+
+--cached::
+	Display the sha1 stored in the index, not the sha1 of the currently
+	checked out submodule commit. This option is only valid for the
+	status command.
+
+<path>::
+	Path to submodule(s). When specified this will restrict the command
+	to only operate on the submodules found at the specified paths.
+
+FILES
+-----
+When cloning submodules, a .gitmodules file in the top-level directory
+of the containing repository is used to find the url of each submodule.
+This file should be formatted in the same way as $GIR_DIR/config. The key
+to each submodule url is "module.$path.url".
+
+
+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..247b1ee
--- /dev/null
+++ b/git-submodule.sh
@@ -0,0 +1,172 @@
+#!/bin/sh
+#
+# git-submodules.sh: init, update or list git submodules
+#
+# Copyright (c) 2007 Lars Hjemli
+
+USAGE='[--quiet] [--cached] [status|init|update] [--] [<path>...]'
+. git-sh-setup
+require_work_tree
+
+init=
+update=
+status=
+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 sha1 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" != "$sha1"
+		then
+			$(unset GIT_DIR && cd "$path" && git-fetch &&
+				git-checkout -q "$sha1") ||
+			die "Unable to checkout '$sha1' in submodule '$path'"
+
+			say "Submodule '$path': checked out '$sha1'"
+		fi
+	done
+}
+
+#
+# List all registered submodules, prefixed with:
+#  - submodule not initialized
+#  + different revision 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
+	init)
+		init=1
+		;;
+	update)
+		update=1
+		;;
+	status)
+		status=1
+		;;
+	-q|--quiet)
+		quiet=1
+		;;
+	--cached)
+		cached=1
+		;;
+	--)
+		break
+		;;
+	-*)
+		usage
+		;;
+	*)
+		break
+		;;
+	esac
+	shift
+done
+
+case "$init,$update,$status,$cached" in
+1,,,)
+	modules_init $@
+	;;
+,1,,)
+	modules_update $@
+	;;
+,,*,*)
+	modules_list $@
+	;;
+*)
+	usage
+	;;
+esac
-- 
1.5.2.74.ga303

Re: [PATCH] Add git-submodule command

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

Hi,

On Sat, 26 May 2007, Lars Hjemli wrote:
On 5/26/07, Lars Hjemli [off-list ref] wrote:
quoted
I'll redo the patch, removing the branch-specific things, and try to
shut up :)
This is my final uttering ;-)
Don't be so shy. We're really making progress here, methinks.

Your version looks good to me.

Ciao,
Dscho "awaiting with impatience the test cases"
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help