From 1cc2cfff91c61bb56236914da7be7b15584951df Mon Sep 17 00:00:00 2001 From: Avery Pennarun Date: Sat, 30 May 2009 03:18:27 -0400 Subject: [PATCH] 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. --- git-subtree.sh | 78 +++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 77 insertions(+), 1 deletion(-) diff --git a/git-subtree.sh b/git-subtree.sh index d82e03e6f..863e28bb7 100755 --- a/git-subtree.sh +++ b/git-subtree.sh @@ -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 } -- 2.30.2