Basic "subtree merge --squash" support.

Instead of merging in the history of the entire subproject, just squash it
all into one commit, but try to at least track which commits we used so that
we can do future merges correctly.

Bonus feature: we can actually switch branches of the subproject this way,
just by "squash merging" back and forth from one tag to another.
This commit is contained in:
Avery Pennarun 2009-05-30 03:18:27 -04:00
parent 7ee9eef340
commit 1cc2cfff91

View File

@ -167,15 +167,46 @@ try_remove_previous()
fi
}
find_latest_squash()
{
debug "Looking for latest squash..."
dir="$1"
git log --grep="^git-subtree-dir: $dir\$" \
--pretty=format:'START %H%n%s%n%n%b%nEND%n' HEAD |
while read a b junk; do
case "$a" in
START) sq="$b" ;;
git-subtree-mainline:) main="$b" ;;
git-subtree-split:) sub="$b" ;;
END)
if [ -n "$sub" ]; then
if [ -n "$main" ]; then
# a rejoin commit?
# Pretend its sub was a squash.
sq="$sub"
fi
debug "Squash found: $sq $sub"
echo "$sq" "$sub"
break
fi
sq=
main=
sub=
;;
esac
done
}
find_existing_splits()
{
debug "Looking for prior splits..."
dir="$1"
revs="$2"
git log --grep="^git-subtree-dir: $dir\$" \
--pretty=format:'%s%n%n%b%nEND' $revs |
--pretty=format:'%s%n%n%b%nEND%n' $revs |
while read a b junk; do
case "$a" in
START) main="$b" ;;
git-subtree-mainline:) main="$b" ;;
git-subtree-split:) sub="$b" ;;
END)
@ -244,6 +275,28 @@ rejoin_msg()
EOF
}
squash_msg()
{
dir="$1"
oldsub="$2"
newsub="$3"
oldsub_short=$(git rev-parse --short "$oldsub")
newsub_short=$(git rev-parse --short "$newsub")
cat <<-EOF
Squashed '$dir/' changes from $oldsub_short..$newsub_short
EOF
git log --pretty=tformat:'%h %s' "$oldsub..$newsub"
git log --pretty=tformat:'REVERT: %h %s' "$newsub..$oldsub"
cat <<-EOF
git-subtree-dir: $dir
git-subtree-split: $newsub
EOF
}
toptree_for_commit()
{
commit="$1"
@ -278,6 +331,16 @@ tree_changed()
fi
}
new_squash_commit()
{
old="$1"
oldsub="$2"
newsub="$3"
tree=$(toptree_for_commit $newsub) || exit $?
squash_msg "$dir" "$oldsub" "$newsub" |
git commit-tree "$tree" -p "$old" || exit $?
}
copy_or_skip()
{
rev="$1"
@ -452,6 +515,19 @@ cmd_merge()
fi
rev="$1"
if [ -n "$squash" ]; then
first_split="$(find_latest_squash "$dir")"
if [ -z "$first_split" ]; then
die "Can't squash-merge: '$dir' was never added."
fi
set $first_split
old=$1
sub=$2
new=$(new_squash_commit "$old" "$sub" "$rev") || exit $?
debug "New squash commit: $new"
rev="$new"
fi
git merge -s subtree $rev
}