Open
Description
Plugin idea for supporting sparse checkout
Here are some Just targets to consider:
In just sync
if [ "$(git config submodule.external/data.update)" = "none" ]; then
echo 'Initializing data'
justify data init
fi
Init
Note: Docs say sparse-checkout init is deprecated, so probably should be matching that behavior instead.
data_init) # git sparse-checkout init for external/data
local git_version=${git_version-$(git_version)}
local sm_name=external/data
local sm_path="$(git config -f .gitmodules "submodule.${sm_name}.path")"
### 1. First clone --no-checkout ###
if version_lt "${git_version}" 1.8.4; then
# Port of git's submodule update's clone.
local git_dir="$("${GIT}" rev-parse --git-dir)/modules/${sm_path}"
"${GIT}" submodule init "${sm_path}"
mkdir -p "$(dirname "${git_dir}")"
"${GIT}" clone --no-checkout \
--separate-git-dir "${git_dir}" \
"$("${GIT}" config "submodule.${sm_name}.url")" \
"${sm_path}"
else
# A close equivalent of clone no checkout
"${GIT}" -c "submodule.${sm_name}.update="'!true' submodule update --init external/data
fi
### 2. git sparse-checkout init ###
pushd "${sm_path}" &> /dev/null
if version_lt "${git_version}" 2.25.0; then
"${GIT}" config core.sparseCheckout true
else # 2.25.0
"${GIT}" sparse-checkout init --cone
fi
justify data set prod .gitlab
popd &> /dev/null
### 3. Now, return normal control over to git submodule
"${GIT}" config "submodule.${sm_name}.update" checkout
"${GIT}" submodule update "${sm_path}"
pushd "${sm_path}" &> /dev/null
# I'm ok with always doing read-tree here, as I am init-ing and this
# directory should would have not existed before "data init" started
# This is needed for corner cases even in git 2.25 like when someone deinit's a sparse submodule
# which results in a no-checkout scenario where every file is stages as deleted, and we need to
# read-tree, and not prompt the user, so don't call "just data read-tree"
"${GIT}" read-tree -mu HEAD
popd &> /dev/null
;;
Add
data_add) # git sparse-checkout add for external/data
local git_version=${git_version-$(git_version)}
pushd "${DATA_DIR}" &> /dev/null
if version_lt "${git_version}" 2.26.0; then
echo "Approximation of 'git sparse-checkout add', update to git 2.26.0 or newer for more reliable results" >&2
local add_dir
local sparse_file="$("${GIT}" rev-parse --git-dir)/info/sparse-checkout"
for add_dir in ${@+"${@}"}; do
# The entry should look like /foo/bar/, starting and ending with a /
if [ "${add_dir:0:1}" != "/" ]; then
add_dir="/${add_dir}"
fi
if [ "${add_dir:${#add_dir}-1:1}" != "/" ]; then
add_dir="${add_dir}/"
fi
# Just blindly add it, no cone check. TODO: Cone?
echo "${add_dir}" >> "${sparse_file}"
done
justify data read-tree
else
"${GIT}" sparse-checkout add ${@+"${@}"}
fi
popd &> /dev/null
extra_args=${#}
;;
List
data_list) # git sparse-checkout list for external/data
local git_version=${git_version-$(git_version)}
pushd "${DATA_DIR}" &> /dev/null
if version_lt "${git_version}" 2.25.0; then
echo "Approximation of 'git sparse-checkout list', update to git 2.25.0 or newer for more reliable results" >&2
sed -En 's|^/(.*)/|\1|p' ../../.git/modules/external/data/info/sparse-checkout
else
"${GIT}" sparse-checkout list
fi
popd &> /dev/null
;;
Disable
data_disable) # git sparse-checkout disable for external/data
local git_version=${git_version-$(git_version)}
pushd "$DATA_DIR}" &> /dev/null
if version_lt "${git_version}" 2.25.0; then
echo "Approximation of 'git sparse-checkout disable', update to git 2.25.0 or newer for more reliable results" >&2
"${GIT}" config core.sparseCheckout false
"${GIT}" read-tree -mu HEAD
else
"${GIT}" sparse-checkout disable
fi
popd &> /dev/null
;;
Set
data_set) # git sparse-checkout set for external/data
local git_version=${git_version-$(git_version)}
pushd "${DATA_DIR}" &> /dev/null
if version_lt "${git_version}" 2.25.0; then
echo '/*
!/*/' > "$("${GIT}" rev-parse --git-dir)/info/sparse-checkout"
justify data add ${@+"${@}"}
else
"${GIT}" sparse-checkout set ${@+"${@}"}
fi
popd &> /dev/null
extra_args=${#}
;;
Other
data_read-tree) # git read-tree -mu HEAD for external/data
# Several references refer to read-tree being the way to update the workspace
# https://vmiklos.hu/blog/sparse-checkout-example-in-git-1-7
# https://web.archive.org/web/20130121010056/https://blog.quilitz.de/2010/03/checkout-sub-directories-in-git-sparse-checkouts/comment-page-1/
# https://stackoverflow.com/a/2340860/4166604
# https://stackoverflow.com/a/50818880/4166604
# This is more destructive of a command then I thought it was.
# This will remove any STAGED changes, which is not what I think is the point? I just
# wanted something like "git checkout" that will update the workspace after the sparse-checkout
# is updated. I originally thought this was less intrusive.
# This behavior is also what we want on initial clone. A clone --no-checkout looks like all files
# are staged as deleted. So reverting that is exactly what we need on data init
pushd "${DATA_DIR}" &> /dev/null
if [ -z "$(${GIT} status --untracked-files=no --porcelain 2>/dev/null)" ]; then
"${GIT}" read-tree -mu HEAD
else
echo "external/data is in a dirty state. This command will revert the ${RED}staged changes in external/data!${NC}."
git status --untracked-files=no
local ans
ask_question "Are you sure you want to execute 'git read-tree -mu HEAD' on external/data?" ans y
if [ "${ans}" = "1" ]; then
"${GIT}" read-tree -mu HEAD
else
echo "To complete sparse checkout, run: ${YELLOW}git read-tree -mu HEAD${NC}"
fi
fi
popd &> /dev/null
;;
data_ls-files) # git ls-files for external/data
pushd "${DATA_DIR}" &> /dev/null
"${GIT}" ls-files
popd &> /dev/null
;;
data_ls-dirs) # Print directory tree for external/data
pushd "${DATA_DIR}" &> /dev/null
"${GIT}" ls-files -z | xargs -0 dirname | sort -u
popd &> /dev/null
;;