In arch linux - How to modify a PKGBUILD which uses git sources to pull only a shallow clone? - Unix & Linux Stack Exchange, the questioner asks how to make makepkg clone only the relevant commit needed to build the package, instead of the whole git history.
Starting from git 2.49.0, it is technically possible to git clone a single commit. However, there is an additional difficulty.
In summary, some package's PKGBUILD contains git describe command. For this to work, you need to fetch until the nearest tag.
Originally, /usr/share/makepkg/source/git.sh contains download_git and extract_git shell functions.
Details
#!/usr/bin/bash
#
# git.sh - function for handling the download and "extraction" of Git sources
#
# Copyright (c) 2015-2024 Pacman Development Team <pacman-dev@lists.archlinux.org>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
[[ -n "$LIBMAKEPKG_SOURCE_GIT_SH" ]] && return
LIBMAKEPKG_SOURCE_GIT_SH=1
MAKEPKG_LIBRARY=${MAKEPKG_LIBRARY:-'/usr/share/makepkg'}
source "$MAKEPKG_LIBRARY/util/error.sh"
source "$MAKEPKG_LIBRARY/util/message.sh"
source "$MAKEPKG_LIBRARY/util/pkgbuild.sh"
download_git() {
# abort early if parent says not to fetch
if declare -p get_vcs > /dev/null 2>&1; then
(( get_vcs )) || return
fi
local netfile=$1
local dir=$(get_filepath "$netfile")
[[ -z "$dir" ]] && dir="$SRCDEST/$(get_filename "$netfile")"
local repo=$(get_filename "$netfile")
local url=$(get_url "$netfile")
url=${url#git+}
url=${url%%#*}
url=${url%%\?*}
if [[ ! -d "$dir" ]] || dir_is_empty "$dir" ; then
msg2 "$(gettext "Cloning %s %s repo...")" "${repo}" "git"
if ! git clone --origin=origin --mirror "$url" "$dir"; then
error "$(gettext "Failure while downloading %s %s repo")" "${repo}" "git"
plainerr "$(gettext "Aborting...")"
exit 1
fi
elif (( ! HOLDVER )); then
cd_safe "$dir"
# When invoking git on a potentially bare repository, we should pass -c safe.bareRepository=all
# to avoid breaking when the option is globally set to explicit
# Make sure we are fetching the right repo
local remote_url="$(git -c safe.bareRepository=all config --get remote.origin.url)"
if [[ "${url%%.git}" != "${remote_url%%.git}" ]] ; then
error "$(gettext "%s is not a clone of %s")" "$dir" "$url"
plainerr "$(gettext "Aborting...")"
exit $E_NOT_A_CLONE_OF
fi
msg2 "$(gettext "Updating %s %s repo...")" "${repo}" "git"
if ! git -c safe.bareRepository=all fetch --all -p; then
# only warn on failure to allow offline builds
warning "$(gettext "Failure while updating %s %s repo")" "${repo}" "git"
fi
fi
# Sanitize the cloned repo
# $GIT_DIR/info/attributes overrides .gitattributes, and thus no files in the repository
# can be altered by git features like export-subst or export-ignore
local MAKEPKG_GIT_DIR="$(git -c safe.bareRepository=all -C "$dir" rev-parse --absolute-git-dir)"
mkdir -p "$MAKEPKG_GIT_DIR/info"
echo "* -export-subst -export-ignore" > "$MAKEPKG_GIT_DIR/info/attributes"
}
extract_git() {
local netfile=$1 tagname
local fragment=$(get_uri_fragment "$netfile")
local repo=$(get_filename "$netfile")
local dir=$(get_filepath "$netfile")
[[ -z "$dir" ]] && dir="$SRCDEST/$(get_filename "$netfile")"
msg2 "$(gettext "Creating working copy of %s %s repo...")" "${repo}" "git"
pushd "$srcdir" &>/dev/null
local updating=0
if [[ -d "${dir##*/}" ]]; then
updating=1
cd_safe "${dir##*/}"
if ! git fetch; then
error "$(gettext "Failure while updating working copy of %s %s repo")" "${repo}" "git"
plainerr "$(gettext "Aborting...")"
exit 1
fi
cd_safe "$srcdir"
elif ! git clone --origin=origin -s "$dir" "${dir##*/}"; then
error "$(gettext "Failure while creating working copy of %s %s repo")" "${repo}" "git"
plainerr "$(gettext "Aborting...")"
exit 1
fi
cd_safe "${dir##*/}"
local ref=origin/HEAD
if [[ -n $fragment ]]; then
case ${fragment%%=*} in
commit|tag)
ref=${fragment##*=}
;;
branch)
ref=origin/${fragment##*=}
;;
*)
error "$(gettext "Unrecognized reference: %s")" "${fragment}"
plainerr "$(gettext "Aborting...")"
exit 1
esac
fi
if [[ ${fragment%%=*} = tag ]]; then
tagname="$(git tag -l --format='%(tag)' "$ref")"
if [[ -n $tagname && $tagname != "$ref" ]]; then
error "$(gettext "Failure while checking out version %s, the git tag has been forged")" "$ref"
plainerr "$(gettext "Aborting...")"
exit 1
fi
fi
if [[ $ref != "origin/HEAD" ]] || (( updating )) ; then
if ! git checkout --force --no-track -B makepkg "$ref" --; then
error "$(gettext "Failure while creating working copy of %s %s repo")" "${repo}" "git"
plainerr "$(gettext "Aborting...")"
exit 1
fi
fi
popd &>/dev/null
}
calc_checksum_git() {
local netfile=$1 integ=$2 ret=0 shellopts dir url fragment sum
# this function requires pipefail - save current status to restore later
shellopts=$(shopt -p -o pipefail)
shopt -s -o pipefail
dir=$(get_filepath "$netfile")
url=$(get_url "$netfile")
fragment=$(get_uri_fragment "$url")
case ${fragment%%=*} in
tag|commit)
fragval=${fragment##*=}
sum=$(GIT_CONFIG_GLOBAL=/dev/null GIT_CONFIG_SYSTEM=/dev/null git -c core.abbrev=no -C "$dir" archive --format tar "$fragval" | "${integ}sum" 2>&1) || ret=1
sum="${sum%% *}"
;;
*)
sum="SKIP"
;;
esac
eval "$shellopts"
printf '%s' "$sum"
return $ret
}You can change it to
Details
#!/usr/bin/bash
#
# git.sh - function for handling the download and "extraction" of Git sources
#
# Copyright (c) 2015-2024 Pacman Development Team <pacman-dev@lists.archlinux.org>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
[[ -n "$LIBMAKEPKG_SOURCE_GIT_SH" ]] && return
LIBMAKEPKG_SOURCE_GIT_SH=1
MAKEPKG_LIBRARY=${MAKEPKG_LIBRARY:-'/usr/share/makepkg'}
source "$MAKEPKG_LIBRARY/util/error.sh"
source "$MAKEPKG_LIBRARY/util/message.sh"
source "$MAKEPKG_LIBRARY/util/pkgbuild.sh"
get_ref_from_fragment() {
local fragment=$1
local ref=origin/HEAD
if [[ -n $fragment ]]; then
case ${fragment%%=*} in
commit|tag)
ref=${fragment##*=}
;;
branch)
ref=origin/${fragment##*=}
;;
*)
error "$(gettext "Unrecognized reference: %s")" "${fragment}"
plainerr "$(gettext "Aborting...")"
exit 1
esac
fi
printf "%s\n" "$ref"
}
download_git() {
# abort early if parent says not to fetch
if declare -p get_vcs > /dev/null 2>&1; then
(( get_vcs )) || return
fi
local netfile=$1
local dir=$(get_filepath "$netfile")
[[ -z "$dir" ]] && dir="$SRCDEST/$(get_filename "$netfile")"
local repo=$(get_filename "$netfile")
local url=$(get_url "$netfile")
url=${url#git+}
url=${url%%#*}
url=${url%%\?*}
if [[ ! -d "$dir" ]] || dir_is_empty "$dir" ; then
msg2 "$(gettext "Cloning %s %s repo...")" "${repo}" "git"
local fragment=$(get_uri_fragment "$netfile")
local ref=$(get_ref_from_fragment "$fragment")
if ! git clone --origin=origin --bare --revision "${ref/origin\//}" --depth 1 "$url" "$dir"; then
error "$(gettext "Failure while downloading %s %s repo")" "${repo}" "git"
plainerr "$(gettext "Aborting...")"
exit 1
fi
elif (( ! HOLDVER )); then
cd_safe "$dir"
# When invoking git on a potentially bare repository, we should pass -c safe.bareRepository=all
# to avoid breaking when the option is globally set to explicit
# Make sure we are fetching the right repo
local remote_url="$(git -c safe.bareRepository=all config --get remote.origin.url)"
if [[ "${url%%.git}" != "${remote_url%%.git}" ]] ; then
error "$(gettext "%s is not a clone of %s")" "$dir" "$url"
plainerr "$(gettext "Aborting...")"
exit $E_NOT_A_CLONE_OF
fi
msg2 "$(gettext "Updating %s %s repo...")" "${repo}" "git"
if ! git -c safe.bareRepository=all fetch --all -p; then
# only warn on failure to allow offline builds
warning "$(gettext "Failure while updating %s %s repo")" "${repo}" "git"
fi
fi
# Sanitize the cloned repo
# $GIT_DIR/info/attributes overrides .gitattributes, and thus no files in the repository
# can be altered by git features like export-subst or export-ignore
local MAKEPKG_GIT_DIR="$(git -c safe.bareRepository=all -C "$dir" rev-parse --absolute-git-dir)"
mkdir -p "$MAKEPKG_GIT_DIR/info"
echo "* -export-subst -export-ignore" > "$MAKEPKG_GIT_DIR/info/attributes"
}
extract_git() {
local netfile=$1 tagname
local fragment=$(get_uri_fragment "$netfile")
local repo=$(get_filename "$netfile")
local dir=$(get_filepath "$netfile")
[[ -z "$dir" ]] && dir="$SRCDEST/$(get_filename "$netfile")"
msg2 "$(gettext "Creating working copy of %s %s repo...")" "${repo}" "git"
pushd "$srcdir" &>/dev/null
local updating=0
if [[ -d "${dir##*/}" ]]; then
updating=1
cd_safe "${dir##*/}"
if ! git fetch; then
error "$(gettext "Failure while updating working copy of %s %s repo")" "${repo}" "git"
plainerr "$(gettext "Aborting...")"
exit 1
fi
cd_safe "$srcdir"
elif ! git clone --origin=origin -s "$dir" "${dir##*/}"; then
error "$(gettext "Failure while creating working copy of %s %s repo")" "${repo}" "git"
plainerr "$(gettext "Aborting...")"
exit 1
fi
cd_safe "${dir##*/}"
local ref=$(get_ref_from_fragment "$fragment")
if [[ ${fragment%%=*} = tag ]]; then
tagname="$(git tag -l --format='%(tag)' "$ref")"
if [[ -n $tagname && $tagname != "$ref" ]]; then
error "$(gettext "Failure while checking out version %s, the git tag has been forged")" "$ref"
plainerr "$(gettext "Aborting...")"
exit 1
fi
fi
if [[ $ref != "origin/HEAD" ]] || (( updating )) ; then
if ! git checkout --force --no-track -B makepkg "$ref" --; then
error "$(gettext "Failure while creating working copy of %s %s repo")" "${repo}" "git"
plainerr "$(gettext "Aborting...")"
exit 1
fi
fi
popd &>/dev/null
}
calc_checksum_git() {
local netfile=$1 integ=$2 ret=0 shellopts dir url fragment sum
# this function requires pipefail - save current status to restore later
shellopts=$(shopt -p -o pipefail)
shopt -s -o pipefail
dir=$(get_filepath "$netfile")
url=$(get_url "$netfile")
fragment=$(get_uri_fragment "$url")
case ${fragment%%=*} in
tag|commit)
fragval=${fragment##*=}
sum=$(GIT_CONFIG_GLOBAL=/dev/null GIT_CONFIG_SYSTEM=/dev/null git -c core.abbrev=no -C "$dir" archive --format tar "$fragval" | "${integ}sum" 2>&1) || ret=1
sum="${sum%% *}"
;;
*)
sum="SKIP"
;;
esac
eval "$shellopts"
printf '%s' "$sum"
return $ret
}The diff:
Details
@@ -29,6 +29,25 @@
source "$MAKEPKG_LIBRARY/util/message.sh"
source "$MAKEPKG_LIBRARY/util/pkgbuild.sh"
+get_ref_from_fragment() {
+ local fragment=$1
+ local ref=origin/HEAD
+ if [[ -n $fragment ]]; then
+ case ${fragment%%=*} in
+ commit|tag)
+ ref=${fragment##*=}
+ ;;
+ branch)
+ ref=origin/${fragment##*=}
+ ;;
+ *)
+ error "$(gettext "Unrecognized reference: %s")" "${fragment}"
+ plainerr "$(gettext "Aborting...")"
+ exit 1
+ esac
+ fi
+ printf "%s\n" "$ref"
+}
download_git() {
# abort early if parent says not to fetch
@@ -50,7 +69,9 @@
if [[ ! -d "$dir" ]] || dir_is_empty "$dir" ; then
msg2 "$(gettext "Cloning %s %s repo...")" "${repo}" "git"
- if ! git clone --origin=origin --mirror "$url" "$dir"; then
+ local fragment=$(get_uri_fragment "$netfile")
+ local ref=$(get_ref_from_fragment "$fragment")
+ if ! git clone --origin=origin --bare --revision "${ref/origin\//}" --depth 1 "$url" "$dir"; then
error "$(gettext "Failure while downloading %s %s repo")" "${repo}" "git"
plainerr "$(gettext "Aborting...")"
exit 1
@@ -112,21 +133,7 @@
cd_safe "${dir##*/}"
- local ref=origin/HEAD
- if [[ -n $fragment ]]; then
- case ${fragment%%=*} in
- commit|tag)
- ref=${fragment##*=}
- ;;
- branch)
- ref=origin/${fragment##*=}
- ;;
- *)
- error "$(gettext "Unrecognized reference: %s")" "${fragment}"
- plainerr "$(gettext "Aborting...")"
- exit 1
- esac
- fi
+ local ref=$(get_ref_from_fragment "$fragment")
if [[ ${fragment%%=*} = tag ]]; then
tagname="$(git tag -l --format='%(tag)' "$ref")"Which will somewhat work, but some package's pkgver function has git describe command. Such as
pkgver() {
cd "$pkgname"
git describe --long | sed -E 's/creduce-([^-]*)-([^-]*)-g/\1-r\2-/; s/-/./g'
}
For this to work, you need to know the nearest tag.