Skip to content

Instantly share code, notes, and snippets.

@felipec
Created May 30, 2012 16:54
Show Gist options
  • Save felipec/2837595 to your computer and use it in GitHub Desktop.
Save felipec/2837595 to your computer and use it in GitHub Desktop.
Code to find the first point a git branch started to diverge
#!/bin/bash
# actual code
find_merge ()
{
local selection extra
test "$2" && extra=" into $2"
git rev-list --min-parents=2 --grep="Merge branch '$1'$extra" --topo-order ${3:---all} | tail -1
}
branch_point ()
{
local first_merge second_merge merge
first_merge=$(find_merge $1 "" "$1 $2")
second_merge=$(find_merge $2 $1 $first_merge)
merge=${second_merge:-$first_merge}
# echo "merge: $merge" > /dev/stderr
if [ "$merge" ]; then
git merge-base $merge^1 $merge^2
else
git merge-base $1 $2
fi
}
# testing
do_repo ()
{
repo=$1
git init -q $1 && cd $1
}
do_commit ()
{
local branch base
if [ "$2" ]; then
test "$3" && base="refs/commits/$3" || base="$(git show-ref -s --heads $2)"
git checkout -q -B "$2" "${base:-HEAD}"
fi
branch=$(git symbolic-ref --short HEAD)
git commit --allow-empty -q -m "$1 - $branch"
git update-ref refs/commits/$1 HEAD
}
do_merge ()
{
local branch extra
test "$3" && git checkout -q $3
branch=$(git symbolic-ref --short HEAD)
test $branch != 'master' && extra=" into $branch"
git merge -q $2 -m "$1 - Merge branch '$2'$extra"
git update-ref refs/commits/$1 HEAD
}
show_repo ()
{
echo "== $repo =="
git log --oneline --decorate --graph --all --topo-order
}
do_test ()
{
c=$(branch_point $1 $2)
r=$(git name-rev --name-only --refs='refs/commits/*' $c)
s=${r#commits/}
echo "result: $s"
}
rm -rf test*
# X (master) (topic)
(
do_repo 'test1'
do_commit 'X'
git checkout -q -b topic master
show_repo
do_test 'topic' 'master'
)
# X (master)
# \
# A (topic)
(
do_repo 'test2'
do_commit 'X'
do_commit 'A' 'topic'
show_repo
do_test 'topic' 'master'
)
# X - B (master)
# \
# A (topic)
(
do_repo 'test3'
do_commit 'X'
do_commit 'A' 'topic'
do_commit 'B' 'master'
show_repo
do_test 'topic' 'master'
)
# X - B - C (master)
# \ /
# --- A (topic)
(
do_repo 'test4'
do_commit 'X'
do_commit 'A' 'topic'
do_commit 'B' 'master'
do_merge 'C' 'topic'
show_repo
do_test 'topic' 'master'
)
# X --- B (master)
# \ \
# A - C (topic)
(
do_repo 'test5'
do_commit 'X'
do_commit 'A' 'topic'
do_commit 'B' 'master'
do_merge 'C' 'master' 'topic'
show_repo
do_test 'topic' 'master'
)
# X - B - C - E (master)
# \ / /
# --- A - D (topic)
(
do_repo 'test6'
do_commit 'X'
do_commit 'A' 'topic'
do_commit 'B' 'master'
do_merge 'C' 'topic'
do_commit 'D' 'topic'
do_merge 'E' 'topic' 'master'
show_repo
do_test 'topic' 'master'
)
# X --- B - D - F (master)
# \ \ /
# A - C --- E (topic)
(
do_repo 'test7'
do_commit 'X'
do_commit 'A' 'topic'
do_commit 'B' 'master'
do_merge 'C' 'master' 'topic'
do_commit 'D' 'master'
do_commit 'E' 'topic'
do_merge 'F' 'topic' 'master'
show_repo
do_test 'topic' 'master'
)
# X - A ----- F (master)
# \ /
# B - C - E (topic)
# \ /
# D - + (test)
(
do_repo 'test8'
do_commit 'X'
do_commit 'A'
do_commit 'B' 'topic' 'X'
do_commit 'C'
do_commit 'D' 'test' 'B'
do_merge 'E' 'test' 'topic'
do_merge 'F' 'topic' 'master'
show_repo
do_test 'topic' 'master'
)
# X - A ----- F (master)
# \ /
# B - C - + (topic)
# \ \
# D - E (test)
(
do_repo 'test9'
do_commit 'X'
do_commit 'A'
do_commit 'B' 'topic' 'X'
do_commit 'C'
do_commit 'D' 'test' 'B'
do_merge 'E' 'topic' 'test'
do_merge 'F' 'topic' 'master'
show_repo
do_test 'topic' 'master'
)
# X - A ---- E - G (master)
# \ / /
# + - B - D / (fix)
# \ / /
# C - + - F (topic)
(
do_repo 'test10'
do_commit 'X'
do_commit 'A'
do_commit 'B' 'fix' 'X'
do_commit 'C' 'topic' 'X'
do_merge 'D' 'topic' 'fix'
do_merge 'E' 'fix' 'master'
do_commit 'F' 'topic'
do_merge 'G' 'topic' 'master'
show_repo
do_test 'topic' 'master'
)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment