I wrote the below script to push all the changes in the workspace, both in the submodules and the superproject. However, it sounds a little odd that, it is this complex to do what I want. Is there any better way, that I'm missing?
#!/bin/bash
if [ "$#" -ne 1 ]; then
echo "Illegal number of parameters"
exit
fi
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
cd "${SCRIPT_DIR}/../submodule1"
git status
git add -A
git commit -m "$1"
git push origin master
cd "${SCRIPT_DIR}/../submodule2"
git status
git add -A
git commit -m "$1"
git push origin master
cd "${SCRIPT_DIR}/../submodule3"
git status
git add -A
git commit -m "$1"
git push origin master
printf "\n\nUpdating Super Project\n\n"
cd ..
git status
git add -A
git commit -m "All Submodules Updated - $1"
git push origin master
If you already cloned the project and forgot --recurse-submodules , you can combine the git submodule init and git submodule update steps by running git submodule update --init . To also initialize, fetch and checkout any nested submodules, you can use the foolproof git submodule update --init --recursive .
Once you have set up the submodules you can update the repository with fetch/pull like you would normally do. To pull everything including the submodules, use the --recurse-submodules and the --remote parameter in the git pull command .
Pushing updates in the submodule. The submodule is just a separate repository. If you want to make changes to it, you should make the changes in its repository and push them like in a regular Git repository (just execute the git commands in the submodule's directory).
Submodules are very static and only track specific commits. Submodules do not track git refs or branches and are not automatically updated when the host repository is updated. When adding a submodule to a repository a new . gitmodules file will be created.
The git-powercommit script I wrote recently does push submodules recursively as a part of its workflow. Under the hood, there is a map-like iterator which uses git-status --porcelain=v2
to iterate over repository objects. Here is its definition:
mapchanges() {(
set -e -x
local filter="$1"
local commiter="$2"
git status --no-renames --porcelain=v2 | \
while read N XY sub mH mI mW hH hI path ; do
$filter $N $XY $sub $mH $mI $mW $hH $hI "$path"
done | \
sort -u --reverse | \
while read path; do
$commiter "$path"
done
)}
In order to iterate over submodules, you need to provide it with the filter and the action callback functions. In your case, the filter function could be:
filter_subm() {
# Inputs are according to `git status --porcelain=v2` spec. The function
# filters submodules which has changed commits.
local sub="$3"; shift 8; local path="$1"
case "$sub" in
SC??) echo "$path" ;;
*) ;;
esac
}
As for the action function, the origina script does commit the whole submodule, but in your case you could insert the push commands like the following
push_subm() {
local path="$1"
(cd -P "$path" && git push origin; )
}
Now, we bring everything together with the line like
mapchanges filter_subm push_subm
Please, consider reviewing the original script to find out the details on how to organize the recursion.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With