|
|
|
#!/bin/sh
|
|
|
|
|
|
|
|
clean= next=next
|
|
|
|
branch=`git symbolic-ref HEAD`
|
|
|
|
while case $# in 0) break ;; esac
|
|
|
|
do
|
|
|
|
case "$1" in
|
|
|
|
--clean)
|
|
|
|
test refs/heads/master = "$branch" || {
|
|
|
|
echo >&2 Not on master
|
|
|
|
exit 1
|
|
|
|
}
|
|
|
|
clean=t
|
|
|
|
;;
|
|
|
|
--next)
|
|
|
|
test 2 -le $# || {
|
|
|
|
echo >&2 "Need argument"
|
|
|
|
exit 1
|
|
|
|
}
|
|
|
|
next="$2"
|
|
|
|
git rev-parse --verify "$next" >/dev/null || exit
|
|
|
|
shift
|
|
|
|
;;
|
|
|
|
*)
|
|
|
|
echo >&2 "$0 [--clean | --next test-next ]"
|
|
|
|
exit 1
|
|
|
|
;;
|
|
|
|
esac
|
|
|
|
shift
|
|
|
|
done
|
|
|
|
|
|
|
|
master_sha1=`git rev-parse --verify refs/heads/master`
|
|
|
|
LF='
|
|
|
|
'
|
|
|
|
(cd .git/refs/heads && find -type f) |
|
|
|
|
sed -n \
|
|
|
|
-e 's/^\.\///' \
|
|
|
|
-e '/^[^\/][^\/]\//p' |
|
|
|
|
sort |
|
|
|
|
while read topic
|
|
|
|
do
|
|
|
|
rebase= done= not_done= trouble= date=
|
|
|
|
topic_sha1=`git rev-parse --verify "refs/heads/$topic"`
|
|
|
|
is_current=
|
|
|
|
if test "refs/heads/$topic" = "$branch"
|
|
|
|
then
|
|
|
|
is_current=" *"
|
|
|
|
fi
|
|
|
|
|
|
|
|
date=`
|
|
|
|
git-rev-list -1 --pretty "$topic" |
|
|
|
|
sed -ne 's/^Date: *\(.*\)/ (\1)/p'
|
|
|
|
`
|
|
|
|
# (1)
|
|
|
|
only_next_1=`git-rev-list ^master "^$topic" ${next} | sort`
|
|
|
|
only_next_2=`git-rev-list ^master ${next} | sort`
|
|
|
|
if test "$only_next_1" = "$only_next_2"
|
|
|
|
then
|
|
|
|
not_in_topic=`git-rev-list "^$topic" master`
|
|
|
|
if test -z "$not_in_topic"
|
|
|
|
then
|
|
|
|
rebase=" (vanilla)"
|
|
|
|
else
|
|
|
|
rebase=" (can be rebased)"
|
|
|
|
fi
|
|
|
|
fi
|
|
|
|
|
|
|
|
# (2)
|
|
|
|
not_in_master=`
|
|
|
|
git-rev-list ^master "$topic"
|
|
|
|
`
|
|
|
|
test -z "$not_in_master" &&
|
|
|
|
done="${LF}Fully merged -- delete."
|
|
|
|
|
|
|
|
# (3)
|
|
|
|
not_in_next=`
|
|
|
|
git-rev-list --pretty=oneline ^${next} "$topic" |
|
|
|
|
sed -e 's/^[0-9a-f]* / - /'
|
|
|
|
`
|
|
|
|
if test -n "$not_in_next"
|
|
|
|
then
|
|
|
|
if test -n "$done"
|
|
|
|
then
|
|
|
|
# If $topic and master are the same,
|
|
|
|
# it is fine.
|
|
|
|
test "$master_sha1" = "$topic_sha1" ||
|
|
|
|
trouble="${LF}### MODIFIED AFTER COOKED ###"
|
|
|
|
fi
|
|
|
|
not_done="${LF}Still not merged in ${next}$rebase.$LF$not_in_next"
|
|
|
|
elif test -n "$done"
|
|
|
|
then
|
|
|
|
not_done=
|
|
|
|
else
|
|
|
|
not_done="${LF}Up to date."
|
|
|
|
fi
|
|
|
|
|
|
|
|
echo "*** $topic ***$date$is_current$trouble$done$not_done"
|
|
|
|
|
|
|
|
if test -z "$trouble$not_done" &&
|
|
|
|
test -n "$done" &&
|
|
|
|
test t = "$clean"
|
|
|
|
then
|
|
|
|
git branch -d "$topic"
|
|
|
|
fi
|
|
|
|
done
|
|
|
|
|
|
|
|
exit
|
|
|
|
|
|
|
|
################################################################
|
|
|
|
Using Topic Branches
|
|
|
|
|
|
|
|
Some important disciplines first.
|
|
|
|
|
|
|
|
* Once a topic branch forks from "master", avoid merging "master"
|
|
|
|
updates into the topic branch unless necessary to resolve conflicts
|
|
|
|
early.
|
|
|
|
|
|
|
|
* Once a topic branch is fully cooked and merged into "master",
|
|
|
|
delete it. If you need to build on top of it to correct
|
|
|
|
earlier mistakes, create a new topic branch by forking at the
|
|
|
|
tip of the "master". This is not strictly necessary, but it
|
|
|
|
makes it easier to keep your history simple.
|
|
|
|
|
|
|
|
* Whenever you need to test or publish your changes to topic
|
|
|
|
branches, merge them into "next" branch.
|
|
|
|
|
|
|
|
So, you would want to know:
|
|
|
|
|
|
|
|
(1) ... if a topic branch has ever been merged to "next". Young
|
|
|
|
topic branches can have stupid mistakes you would rather
|
|
|
|
clean up, and things that have not been merged into other
|
|
|
|
branches can be easily rebased without affecting others.
|
|
|
|
|
|
|
|
(2) ... if a topic branch has been fully merged to "master".
|
|
|
|
Then you can delete it. More importantly, you can tell you
|
|
|
|
should not build on top of it.
|
|
|
|
|
|
|
|
(3) ... if a topic branch has commits unmerged to "next". You
|
|
|
|
need to merge them to test and/or publish.
|
|
|
|
|
|
|
|
Let's look at this example:
|
|
|
|
|
|
|
|
o---o---o---o---o---o---o---o---o---o "next"
|
|
|
|
/ / / /
|
|
|
|
/ a---a---b A / /
|
|
|
|
/ / / /
|
|
|
|
/ / c---c---c---c B /
|
|
|
|
/ / / \ /
|
|
|
|
/ / / b---b C \ /
|
|
|
|
/ / / / \ /
|
|
|
|
---o---o---o---o---o---o---o---o---o---o---o "master"
|
|
|
|
|
|
|
|
|
|
|
|
A, B and C are topic branches.
|
|
|
|
|
|
|
|
* A has one fix since it was merged up to "next".
|
|
|
|
|
|
|
|
* B has finished. It has been fully merged up to "master" and "next",
|
|
|
|
and is ready to be deleted.
|
|
|
|
|
|
|
|
* C has not merged to "next" at all.
|
|
|
|
|
|
|
|
To compute (1):
|
|
|
|
|
|
|
|
git-rev-list ^master ^topic next
|
|
|
|
git-rev-list ^master next
|
|
|
|
|
|
|
|
if these match, topic has not merged in next at all.
|
|
|
|
|
|
|
|
To compute (2):
|
|
|
|
|
|
|
|
git-rev-list master..topic
|
|
|
|
|
|
|
|
if this is empty, it is fully merged to "master".
|
|
|
|
|
|
|
|
To compute (3):
|
|
|
|
|
|
|
|
git-rev-list next..topic
|
|
|
|
|
|
|
|
if this is empty, there is nothing to merge to "next".
|
|
|
|
|