submodule prototype
RFC 1/1 submodule prototype
hoi :)
so, now my little submodule prototype did it's first pull correctly so I think I should share some ideas here.
http://git.admingilde.org/tali/git.git/module
A submodule here is implemented as a more-or-less normal GIT repository. The object directory is shared with the parent and all refs are visible in both the parent and all submodules (via refs/parent and refs/module) so that fsck works.
On top of that is some special handling for commit and pull:
When commiting in the parent project then all submodule refs are stored in the tree, too.
Fetching from a remote parent copies all submodule references into the current repository, too.
After a successful merge the submodules are updated to reflect the new state.
The code below is obviously not finished and very fragile, it has only been tested with the litte test script so far, but I think it's a nice basis for discussion.
What do you think?
Some specific questions:
User interface: like show here only one more command to set up submodules and then using standard commands for parent and submodule or does it make more sense to add special commands for updating submodules (and not recursing into them by default)?
Does it really make sense to have one shared object directory? This allows to fetch the whole project in one go, but it might be more robust to set up individual object databases.
.gitignore +1 -0
@@ -47,6 +47,7 @@ git-http-push git-imap-send git-index-pack git-init-db +git-init-module git-instaweb git-local-fetch git-log
Makefile +1 -1
@@ -154,7 +154,7 @@ ### --- END CONFIGURATION SECTION --- SCRIPT_SH = \ git-bisect.sh git-branch.sh git-checkout.sh \ git-cherry.sh git-clean.sh git-clone.sh git-commit.sh \ - git-fetch.sh \ + git-fetch.sh git-init-module.sh \ git-ls-remote.sh \ git-merge-one-file.sh git-parse-remote.sh \ git-pull.sh git-rebase.sh \
git-checkout.sh +17 -0
@@ -211,3 +211,20 @@ if [ "$?" -eq 0 ]; then else exit 1 fi + +# +# Now checkout all the submodules recursively +# FIXME: handle branch updates +# +unset GIT_DIR +parent_dir=`pwd` +if test -r .gitmodules; then + while read module; do + cd "$parent_dir" + HEAD=$(git-symbolic-ref "../.gitmodule/$module/HEAD") + mkdir -p "$module" + cd "$module" + git-init-module >/dev/null + git-checkout $HEAD + done < .gitmodules +fi
git-clone.sh +1 -1
@@ -410,7 +410,7 @@ Pull: refs/heads/$head_points_at:$origin case "$no_checkout" in '') - git-read-tree -m -u -v HEAD HEAD + git-checkout esac fi rm -f "$GIT_DIR/CLONE_HEAD" "$GIT_DIR/REMOTE_HEAD"
git-commit.sh +12 -0
@@ -342,6 +342,18 @@ then TOP=./ fi +# update the .gitmodule/ contents +# FIXME: don't overwrite, test if submodule is ancestor of current value +if test -r .gitmodules; then + while read module; do + rm -rf ".gitmodule/$module" + mkdir -p ".gitmodule/$module/refs" + cp -a "$module/.git/refs/heads" ".gitmodule/$module/refs/" + cp -a "$module/.git/refs/tags" ".gitmodule/$module/refs/" + cp -a "$module/.git/HEAD" ".gitmodule/$module/" + done < .gitmodules +fi + case "$all,$also" in t,) save_index &&
git-init-module.sh new file +65 -0
65 lines not on this page · raw message
git-merge.sh +25 -0
@@ -97,8 +97,33 @@ finish () { esac ;; esac + + # now take a look at changes in submodules + if test -e .gitmodules; then + while read module; do + merge_module "$module" + done < .gitmodules + fi } +merge_module () { + module="$1" + HEAD=$(git-symbolic-ref "../.gitmodule/$module/HEAD") + new_head=$(cat ".gitmodule/$module/$HEAD") + # FIXME: first step: merge HEAD only + (set -e + cd "$module" + unset GIT_DIR + # FIXME: sure there is a nicer way to do this... + echo "Updateing $module" + git-branch "refs/update/$HEAD" "$new_head" + git-merge "updated by parent" "$HEAD" "refs/update/$HEAD" + git-branch -d "refs/update/$HEAD" + git-checkout "$HEAD" + ) +} + + rloga= while case "$#" in 0) break ;; esac do
git-parse-remote.sh +11 -0
@@ -149,6 +149,17 @@ get_remote_default_refs_for_fetch () { *) die "internal error: get-remote-default-ref-for-push $1" ;; esac + # also fetch all submodule data + if test -e .gitmodules; then + while read module; do + (cd .gitmodule/$module/refs && find * ! -type d) | + while read ref; do + # only fetch the ref, don't store it + # as it gets stored in the repository directly + echo ".refs/module/$module/$ref:" + done + done < .gitmodules + fi } get_remote_refs_for_push () {
t/t7500-submodule.sh new file +76 -0
76 lines not on this page · raw message
Signature · 1 line
Martin Waitz