summaryrefslogtreecommitdiff
path: root/contrib/subtree/git-subtree.sh
diff options
context:
space:
mode:
authorColin Stagner <ask+git@howdoi.land>2025-09-09 22:11:24 -0500
committerJunio C Hamano <gitster@pobox.com>2025-09-11 09:01:15 -0700
commit83f9dad7d6fb5988b68f80b25bd87c68693195dd (patch)
tree1a1293d75c7ae64f706dfb6c2eb4d1455fdea177 /contrib/subtree/git-subtree.sh
parent954d33a9757fcfab723a824116902f1eb16e05f7 (diff)
contrib/subtree: fix split with squashed subtrees
98ba49ccc2 (subtree: fix split processing with multiple subtrees present, 2023-12-01) increases the performance of git subtree split --prefix=subA by ignoring subtree merges which are outside of `subA/`. It also introduces a regression. Subtree merges that should be retained are incorrectly ignored if they: 1. are nested under `subA/`; and 2. are merged with `--squash`. For example, a subtree merged like: git subtree merge --squash --prefix=subA/subB "$rev" # ^^^^^^^^ ^^^^ is erroneously ignored during a split of `subA`. This causes missing tree files and different commit hashes starting in git v2.44.0-rc0. The method: should_ignore_subtree_split_commit REV should test only a single commit REV, but the combination of git log -1 --grep=... actually searches all *parent* commits until a `--grep` match is discovered. Rewrite this method to test only one REV at a time. Extract commit information with a single `git` call as opposed to three. The `test` conditions for rejecting a commit remain unchanged. Unit tests now cover nested subtrees. Signed-off-by: Colin Stagner <ask+git@howdoi.land> Acked-by: Phillip Wood <phillip.wood@dunelm.org.uk> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Diffstat (limited to 'contrib/subtree/git-subtree.sh')
-rwxr-xr-xcontrib/subtree/git-subtree.sh36
1 files changed, 28 insertions, 8 deletions
diff --git a/contrib/subtree/git-subtree.sh b/contrib/subtree/git-subtree.sh
index 3fddba797c..17106d1a72 100755
--- a/contrib/subtree/git-subtree.sh
+++ b/contrib/subtree/git-subtree.sh
@@ -785,20 +785,40 @@ ensure_valid_ref_format () {
die "fatal: '$1' does not look like a ref"
}
-# Usage: check if a commit from another subtree should be
+# Usage: should_ignore_subtree_split_commit REV
+#
+# Check if REV is a commit from another subtree and should be
# ignored from processing for splits
should_ignore_subtree_split_commit () {
assert test $# = 1
- local rev="$1"
- if test -n "$(git log -1 --grep="git-subtree-dir:" $rev)"
+
+ git show \
+ --no-patch \
+ --no-show-signature \
+ --format='%(trailers:key=git-subtree-dir,key=git-subtree-mainline)' \
+ "$1" |
+ (
+ have_mainline=
+ subtree_dir=
+
+ while read -r trailer val
+ do
+ case "$trailer" in
+ git-subtree-dir:)
+ subtree_dir="${val%/}" ;;
+ git-subtree-mainline:)
+ have_mainline=y ;;
+ esac
+ done
+
+ if test -n "${subtree_dir}" &&
+ test -z "${have_mainline}" &&
+ test "${subtree_dir}" != "$arg_prefix"
then
- if test -z "$(git log -1 --grep="git-subtree-mainline:" $rev)" &&
- test -z "$(git log -1 --grep="git-subtree-dir: $arg_prefix$" $rev)"
- then
- return 0
- fi
+ return 0
fi
return 1
+ )
}
# Usage: process_split_commit REV PARENTS