Our team at work is using git submodules to track re-usable code across projects, and it’s been pretty good so far, but we have hit minor snags along the way (such as the absence of a ‘git submodule rm’ command!). Another one is that using submodules adds a step to the sequence of things you have to do to publish changes: pushing submodule commits. It’s an easy thing to forget, but it’s a headache for anyone on the other end of a pull when git-checkout-index fails. This pre-commit hook script will cause the commit to fail if the commit contains new submodule moments and those moments are not present in the corresponding submodule origin.
#!/bin/sh function array_has { for item in $1 do if [ "$item" = "$2" ]; then return 1; fi done return 0; } diffs=`git diff --cached --name-only` IFS=`echo -en "\n\b"` for smstat in `git submodule 2>/dev/null` do if [[ "$smstat" =~ '^\+(.*)' ]]; then smstat=${BASH_REMATCH[1]} fi head=$(echo $smstat | awk '{print $1}') path=$(echo $smstat | awk '{print $2}') moment=$(git ls-files -s $path | awk '{print $2}') array_has $diffs $path if [ $? ]; then pushd >/dev/null $path for rhead in $(git ls-remote -h origin | awk '{print $1}') do if [ "$(git rev-list $moment ^$rhead)" != "" ] then unpub=1; fi done fi if [[ $unpub -gt 0 ]]; then echo -n "ERROR: you are trying to commit " echo -n "unpublished changes to the $path " echo "submodule." exit 1; fi done exit 0;
Tags: git
Seems that new features and concepts appear in Git at such a steady pace that it’s difficult for the jargon to keep up. I don’t follow the git mailing list as closely as I should: it’s too high-traffic and I already don’t have enough time to do the work I have on my plate.
Right now what’s getting tongue-tied is referring to the commit-id of a submodule stored in the HEAD of a containing repository. As far as I know, there’s not a good, succinct and unambiguous term for this commit-id.
I have decided to call it the ‘submodule moment‘, because moment captures the ideas nicely:
More importantly, though, this term disambiguates itself from the other verbal references to commit identifiers.
Tags: git
At work I’m involved in some projects that will very likely make heavy use of submodules. The reason is that submodules make it very convenient to make use of a set of “common” code without a ton of duplication. We’re currently breaking our “common” code into packages that can be included in a project independent of each other, and they will likely exist as submodules.
The challenge is that submodule support in Git isn’t quite as polished as you’d like it to be. What do you do if you have 20+ submodules, some of which may be on a branch and contain uncommitted changes that need to be dealt with? What if it’s been two weeks since you last looked at it?
One solution would be to write a git-all script like this (which is simpler than a real git-all would be, and may actually be incorrect):
#!/bin/sh # git-all for repo in $(find . -name '.git' -type d | xargs dirname); do pushd $repo >/dev/null git $* popd >/dev/null done
We used this approach, particularly before the advent of git-submodule, and some projects still use it. It’s not a bad approach, but it’s not really what you want.
Here’s another solution that’s a little more integrated into git itself:
#!/bin/sh # git-submodule-changes . git-sh-setup status=0 for sm in `git-submodule status | sed 's/^[[:space:]]*\(.*\)/\1/' | cut -d ' ' -f 2`; do pushd $sm >/dev/null substat=$(git-ls-files -d -m -o -s -u -t | cut -d ' ' -f 1 | sort | uniq) substat=$(echo $substat | tr -d '[[:space:]]') if [ "$substat" != "" ]; then status=1 fi printf "%7s %s\n" "$substat" $sm popd >/dev/null done exit $status
I think this works better. An added benefit is that you can do line-based scripting with tools like grep, sed, and awk (and tons of other unix utilities) with it, because all the info appears on one line:
{master}$ git submodule-changes
? sub0
sub1
This isn’t terribly illuminating, but the format is just “[HMRCK?] submodule-path” on each line. The optional codes are the single-character status codes from git-ls-files.
An even better solution would be to build this into git-submodule.sh, which I will look into as I get time.
Tags: git