Subject: [Q] Determing if a commit is reachable from the HEAD ?

From: Brian Foster <[email-masked]>
Date: Fri, 20 Jan 2012 14:33:29 +0100

Hello,

 Whilst I have found answers to my question on the Web,
 only one seems to do exactly what I want ....

                         x---Y---y---y---y  HEAD
                        /
  ...--o---o---C---o---S
                        \
                         n---n---N---*---*  other

 In a script, how can I determine commit Y is reachable
 from the current HEAD ?   And, much more importantly
 for my purposes, that commit N is _not_-reachable from
 the current HEAD ?  "A is reachable from B" meaning B
 is an ancestor of A (B could possibly part of a merge
 (not shown in the above diagram)):

  ✓ Commits o(all), C, S, x, y(all), and Y: YES  (reachable).
  ✗ Commits n(all), N, and *(all): NO  (not-reachable).

 The only readily script-able answer I've found is to use
 `git branch --contains=Y' and check to see if the current
 branch (conveniently marked `*') is/isn't included in the
 output.  That is probably Ok, but I'm wondering if there
 is some "better" method (with the IMPORTANT caveat it must
 work with GIT 1.5.x or later  ;-\ ).

 git-rev-list(1) may be a answer (see script below), but ....
 `git rev-list ^Y HEAD' lists all the y commits, which is Ok
 (correct for my purposes).  However, `git rev-list ^N HEAD'
 lists commits x, Y, and y(all) on branch "other", which is
 not-Ok:  As per above, the answer I want is "NO".

 Apologies if I've overlooked something totally obvious !

cheers,
	-blf-

=====(cut here and below)=====reach02.sh=====
#!/bin/bash
#
#                         x---Y---y---y---y  HEAD
#                        /
#  ...--o---o---C---o---S
#                        \
#                         n---n---N---*---*  other
#

: ${GIT:=git}	# Allow use of different installed GIT versions.

update_file() {
	date +"%c: $*" >>file
	$GIT add file  &&  $GIT commit -m "$*" file
}

set -e		# Terminate if problem creating diagrammed situation.

rm -rf -- reachable
mkdir  -- reachable
cd reachable

$GIT version
$GIT init

update_file     o1
update_file     o2
update_file "C (o3)";	$GIT tag C
update_file     o4
update_file "S (o5)";	$GIT tag S

$GIT checkout -b other
update_file     n1
update_file     n2
update_file "N (n3)";	$GIT tag N
update_file    "*1"
update_file    "*2"

$GIT checkout master
update_file     x
update_file "Y (y1)";	$GIT tag Y
update_file     y2
update_file     y3
update_file     y4

declare -i wrong=0

echo "Is Y reachable from HEAD?  Wanted answer: Yes."
$GIT log --oneline ^Y HEAD
if $GIT rev-list --quiet ^Y HEAD; then
	echo "rev-list: YES (wanted answer)!"
else
	echo "rev-list: No! *** not-wanted, oops... ***"
	wrong=$(( wrong + 1 ))
fi
if $GIT branch --contains=Y | grep -q -e '^\*'; then
	echo "contains: YES (wanted answer)!"
else
	echo "contains: No! *** not-wanted, oops... ***"
	wrong=$(( wrong + 1 ))
fi

echo "Is N reachable from HEAD?  Wanted answer: No."
$GIT log --oneline ^N HEAD
if $GIT rev-list --quiet ^N HEAD; then
	echo "rev-list: YES? *** not-wanted, oops... ***"
	wrong=$(( wrong + 1 ))
else
	echo "rev-list: No (wanted answer)!"
fi
if $GIT branch --contains=N | grep -q -e '^\*'; then
	echo "contains: YES? *** not-wanted, oops... ***"
	wrong=$(( wrong + 1 ))
else
	echo "contains: No (wanted answer)!"
fi

exit $wrong
=====(cut here and above)=====reach02.sh=====

-- 
Brian Foster
Principal MTS, Software        |  La Ciotat, France
Maxim Integrated Products      |  Web:  http://www.maxim-ic.com/