@@ -19,6 +19,7 @@ $(gettext "Options"):
1919 $( gettext " pacman log file," )
2020 $( gettext " default value taken from pacman configuration file," )
2121 $( gettext " or otherwise defaults to" ) "/var/log/pacman.log"
22+ --git $( gettext " uses git for choosing version, viable only for aur packages" )
2223 --maxdepth <$( gettext " integer" ) >
2324 $( gettext " maximum depth to search for cached packages, defaults to" ) 1
2425 --ala-url <url>
@@ -167,8 +168,10 @@ matches_name_version_filter() {
167168 return 0
168169 fi
169170
170- version_regex=" [^-]+-[0-9.]+"
171- pkg_version=$( sed -r " s/.*$name -($version_regex )-(any|$DOWNGRADE_ARCH )\\ .pkg\\ .tar\\ .(gz|xz|zst)/\1/g" <<< " $pkg" )
171+ # version: 2025.11.12.r15.g0eed3fe
172+ version_regex=" [a-zA-Z0-9.]+"
173+ hash_or_minor=" ([0-9]+|[a-z0-9]{6,})"
174+ pkg_version=$( sed -r " s/.*$name -($version_regex )(-$hash_or_minor )?-(any|$DOWNGRADE_ARCH )\\ .(git)?pkg\\ .tar\\ .(gz|xz|zst)/\1\2/g" <<< " $pkg" )
172175 cmp=$( vercmp " $pkg_version " " $search_version " )
173176
174177 case " $operator " in
@@ -196,6 +199,34 @@ matches_name_version_filter() {
196199 esac
197200}
198201
202+ search_git () {
203+ local name=$1 pairs path
204+
205+ # Delay this defaulting so #read_pacman_conf behavior is tested
206+ if (( ! ${# PACMAN_CACHE[@]} )) ; then
207+ mapfile -t PACMAN_CACHE < <( read_pacman_conf CacheDir)
208+ fi
209+
210+ for cache in " ${PACMAN_CACHE[@]} " ; do
211+ path=" $cache /$name " # directory name
212+ if ! [[ -d " $path /.git" ]]; then
213+ {
214+ gettext " \` $path \" not a git directory, skipping..."
215+ echo
216+ } >&2
217+ continue
218+ fi
219+
220+ # TODO: in future could be enhanced by counting every commit
221+ # that DOES NOT change version as minor like 0.0.1-2 instead of any
222+ # pair = abcd12 1.0
223+ pairs=$( git -C " $path " log -p --oneline --format=" GIT: %h" PKGBUILD | grep -e ' GIT:.*' -e ' +pkgver' | grep -Pzo ' GIT: .*\n\+pkgver=.*\n' | sed ' s/GIT: \|+pkgver=//' | tr -d ' \0' )
224+
225+ # shellcheck disable=SC2086
226+ echo " $path /$name " $pairs | awk ' {for(i=2;i<NF;i+=2) printf "%s-%s-%s-any.gitpkg.tar.gz\n", $1, $(i+1), $i}' | sort -V
227+ done
228+ }
229+
199230search_ala () {
200231 local name=$1 uriname pkgfile_re index
201232
@@ -217,7 +248,10 @@ search_ala() {
217248search_cache () {
218249 local name=$1 pkgfile_re index
219250
220- pkgfile_re=" $name -[^-]+-[0-9.]+-(any|$DOWNGRADE_ARCH )\\ .pkg\\ .tar\\ .(gz|xz|zst)"
251+ # version: 2025.11.12.r15.g0eed3fe
252+ version_regex=" [a-zA-Z0-9.]+"
253+ hash_or_minor=" ([0-9]+|[a-z0-9]{6,})"
254+ pkgfile_re=" $name -($version_regex )(-$hash_or_minor )?-(any|$DOWNGRADE_ARCH )\\ .pkg\\ .tar\\ .(gz|xz|zst)"
221255
222256 # Delay this defaulting so #read_pacman_conf behavior is tested
223257 if (( ! ${# PACMAN_CACHE[@]} )) ; then
@@ -258,7 +292,7 @@ output_package() {
258292 fi
259293
260294 # Remote or local file
261- if [[ $path =~ ^/ ]]; then
295+ if [[ $path =~ ^/ && ! ( $path = ~ gitpkg) ]]; then
262296 location=" $( dirname " $path " ) "
263297 timestamp=$( stat -c ' %y' " $path " | cut -d' ' -f1)
264298 else
@@ -293,7 +327,7 @@ extract_version_parts() {
293327 s|^.\{' ${# pkgname} ' \}-\?||;
294328
295329 # Strip package extension
296- s|\.pkg\(\.tar\)\?\(\.[a-z0-9A-Z]\+\)\?$||;
330+ s|\.\(git\)\? pkg\(\.tar\)\?\(\.[a-z0-9A-Z]\+\)\?$||;
297331
298332 # (epoch:)?version(-release)?(-arch)? -> epoch,version,release,arch
299333 s|\(\([^:]*\):\)\?\([^-]*\)\(-\([^-]*\)\)\?\(-\(.*\)\)\?|\2,\3,\5,\7|;
@@ -320,6 +354,11 @@ process_term() {
320354
321355 candidates=($( printf ' %s\n' " ${candidates[@]} " | sort_packages) )
322356
357+ # this is already sorted
358+ if (( DOWNGRADE_FROM_GIT)) ; then
359+ candidates=($( search_git " $name " | filter_packages " $name " " $operator " " $version " ) " ${candidates[@]} " )
360+ fi
361+
323362 if (( "${# candidates[@]} " == 0 )) ; then
324363 {
325364 gettext " No results found"
@@ -440,6 +479,9 @@ parse_options() {
440479 exit 1
441480 fi
442481 ;;
482+ --git)
483+ DOWNGRADE_FROM_GIT=1
484+ ;;
443485 --maxdepth)
444486 if [[ -n " $2 " ]]; then
445487 shift
@@ -523,6 +565,34 @@ parse_options() {
523565 fi
524566}
525567
568+ build_pkg () {
569+ local item=" $1 " path commit_hash build_failed versionreg hashreg gitpkgreg
570+ if [[ " $item " =~ .* gitpkg.tar.gz ]]; then
571+ # version: 2025.11.12.r15.g0eed3fe
572+ versionreg=" ([a-zA-Z0-9]+\.?)*"
573+ hashreg=' [a-z0-9]{6,}'
574+ # hash_or_minor="-([0-9]+|[a-z0-9]{6,})" # leaving this as a note, only hash should appear tho
575+ gitpkgreg=" (.*)-$versionreg -($hashreg )-(any|$DOWNGRADE_ARCH ).gitpkg.tar.gz"
576+ path=$( dirname " $item " )
577+ commit_hash=$( sed -r " s/$gitpkgreg /\3/" <<< " $item" )
578+
579+ pushd " $path " > /dev/null
580+ su -P " $( stat -c" %U" PKGBUILD) " -c " git checkout $commit_hash &>/dev/null && makepkg -fs | tee makepkg.log"
581+ build_failed=$?
582+ # NOTE: when force-canceling, users might need to manually do checkout master
583+ # otherwise they won't be able to update that pkg using yay or whatever I guess...
584+ su " $( stat -c" %U" PKGBUILD) " -c " git switch - &>/dev/null"
585+ if (( build_failed)) ; then
586+ exit 1
587+ fi
588+
589+ item=" $( find " $path " -maxdepth 1 -type f -name " $( sed -nr ' /.*Finished making: ([^ ]+) ([^ ]+) .*/{s//\1-\2/;p}' makepkg.log) *" -print -quit) "
590+ rm makepkg.log
591+ popd > /dev/null
592+ fi
593+ printf " %s\0" " $item " >> new_to_install.downgrade
594+ }
595+
526596cli () {
527597 local conf_args=()
528598
@@ -536,6 +606,14 @@ cli() {
536606
537607 # Proceed with rest of workflow
538608 main " ${terms[@]} "
609+ if (( DOWNGRADE_FROM_GIT)) ; then
610+ for item in " ${to_install[@]} " ; do
611+ build_pkg " $item "
612+ done
613+ mapfile -d ' ' to_install < new_to_install.downgrade
614+ rm new_to_install.downgrade
615+ fi
616+
539617 pacman -U " ${pacman_args[@]} " " ${to_install[@]} "
540618 prompt_to_ignore " ${to_ignore[@]} "
541619}
@@ -545,6 +623,7 @@ PACMAN="pacman"
545623PACMAN_CONF=" /etc/pacman.conf"
546624DOWNGRADE_ARCH=" $( pacman-conf Architecture | head -n 1) "
547625DOWNGRADE_ALA_URL=" https://archive.archlinux.org"
626+ DOWNGRADE_FROM_GIT=0
548627DOWNGRADE_FROM_ALA=1
549628DOWNGRADE_FROM_CACHE=1
550629DOWNGRADE_MAXDEPTH=1
0 commit comments