changeset 13617:189bdb3d9698

1960 developer tools should support git Reviewed by: Joshua M. Clulow <josh@sysmgr.org> Reviewed by: John Sonnenschein <johns@joyent.com> Approved by: Garrett D'Amore <garrett@damore.org>
author Richard Lowe <richlowe@richlowe.net>
date Wed, 15 Sep 2010 22:49:45 -0400
parents 5d28731f11c2
children c6ae14a341e8
files usr/src/pkg/manifests/developer-build-onbld.mf usr/src/tools/scripts/Makefile usr/src/tools/scripts/flg.flp.sh usr/src/tools/scripts/git-pbchk.1 usr/src/tools/scripts/git-pbchk.py usr/src/tools/scripts/nightly.sh usr/src/tools/scripts/webrev.1 usr/src/tools/scripts/webrev.sh usr/src/tools/scripts/which_scm.1 usr/src/tools/scripts/which_scm.sh usr/src/tools/scripts/ws.sh
diffstat 11 files changed, 827 insertions(+), 84 deletions(-) [+]
line wrap: on
line diff
--- a/usr/src/pkg/manifests/developer-build-onbld.mf	Wed Feb 22 14:00:06 2012 -0500
+++ b/usr/src/pkg/manifests/developer-build-onbld.mf	Wed Sep 15 22:49:45 2010 -0400
@@ -21,10 +21,9 @@
 
 #
 # Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+# Copyright 2010, Richard Lowe
 #
 
-# Copyright 2010, Richard Lowe
-
 set name=pkg.fmri value=pkg:/developer/build/onbld@$(PKGVERS)
 set name=pkg.description value="tools used to build the OS-Net consolidation"
 set name=pkg.summary value="OS-Net Build Tools"
@@ -106,6 +105,7 @@
 file path=opt/onbld/bin/flg.flp mode=0555
 file path=opt/onbld/bin/genoffsets mode=0555
 file path=opt/onbld/bin/get_depend_info mode=0555
+file path=opt/onbld/bin/git-pbchk mode=0555
 file path=opt/onbld/bin/hdrchk mode=0555
 file path=opt/onbld/bin/hg-active mode=0555
 file path=opt/onbld/bin/hgsetup mode=0555
@@ -235,6 +235,7 @@
 file path=opt/onbld/man/man1/find_elf.1
 file path=opt/onbld/man/man1/findunref.1
 file path=opt/onbld/man/man1/flg.flp.1
+file path=opt/onbld/man/man1/git-pbchk.1
 file path=opt/onbld/man/man1/hdrchk.1
 file path=opt/onbld/man/man1/hgsetup.1
 file path=opt/onbld/man/man1/interface_check.1
@@ -264,7 +265,9 @@
     license=usr/src/tools/ctf/dwarf/THIRDPARTYLICENSE
 license usr/src/tools/onbld/THIRDPARTYLICENSE \
     license=usr/src/tools/onbld/THIRDPARTYLICENSE
+link path=opt/onbld/bin/git-nits target=git-pbchk
 link path=opt/onbld/lib/python target=python2.4
+link path=opt/onbld/man/man1/git-nits.1 target=git-pbchk.1
 # DbLookups.py requires elementtree
 depend fmri=library/python-2/python-extra-24 type=require
 # webrev(1) requires ps2pdf
--- a/usr/src/tools/scripts/Makefile	Wed Feb 22 14:00:06 2012 -0500
+++ b/usr/src/tools/scripts/Makefile	Wed Sep 15 22:49:45 2010 -0400
@@ -68,12 +68,16 @@
 PYFILES= \
 	cddlchk \
 	copyrightchk \
+	git-pbchk \
 	hdrchk \
 	hg-active \
 	mapfilechk \
 	validate_pkg \
 	wsdiff
 
+SCRIPTLINKS= \
+	git-nits
+
 MAN1FILES= \
 	Install.1 \
 	bldenv.1 \
@@ -84,6 +88,7 @@
 	cstyle.1 \
 	find_elf.1 \
 	flg.flp.1 \
+	git-pbchk.1 \
 	hdrchk.1 \
 	interface_check.1 \
 	interface_cmp.1 \
@@ -99,6 +104,9 @@
 	wsdiff.1 \
 	xref.1
 
+MAN1LINKS= \
+	git-nits.1
+
 MAKEFILES= \
 	xref.mk
 
@@ -116,6 +124,8 @@
 
 include ../Makefile.tools
 
+ROOTONBLDSCRIPTLINKS = $(SCRIPTLINKS:%=$(ROOTONBLDBIN)/%)
+ROOTONBLDMAN1LINKS = $(MAN1LINKS:%=$(ROOTONBLDMAN1)/%)
 
 $(ROOTONBLDETCFILES)	:= FILEMODE=	644
 $(ROOTONBLDEXCEPTFILES)	:= FILEMODE=	644
@@ -128,10 +138,19 @@
 all:	$(SHFILES) $(PERLFILES) $(PERLMODULES) $(PYFILES) \
 	$(MAN1FILES) $(MAKEFILES)
 
+$(ROOTONBLDBIN)/git-nits:
+	$(RM) $(ROOTONBLDBIN)/git-nits
+	$(SYMLINK) git-pbchk $(ROOTONBLDBIN)/git-nits
+
+$(ROOTONBLDMAN1)/git-nits.1:
+	$(RM) $(ROOTONBLDMAN1)/git-nits.1
+	$(SYMLINK) git-pbchk.1 $(ROOTONBLDMAN1)/git-nits.1
+
 install: all .WAIT $(ROOTONBLDSHFILES) $(ROOTONBLDPERLFILES)	\
 		$(ROOTONBLDPERLMODULES) $(ROOTONBLDPYFILES)	\
-		$(ROOTONBLDMAN1FILES) $(ROOTONBLDMAKEFILES)	\
-		$(ROOTONBLDETCFILES) $(ROOTONBLDEXCEPTFILES)
+		$(ROOTONBLDSCRIPTLINKS) $(ROOTONBLDMAN1FILES)	\
+		$(ROOTONBLDMAKEFILES) $(ROOTONBLDETCFILES)	\
+		$(ROOTONBLDEXCEPTFILES) $(ROOTONBLDMAN1LINKS)
 
 clean:
 	$(RM) $(CLEANFILES)
--- a/usr/src/tools/scripts/flg.flp.sh	Wed Feb 22 14:00:06 2012 -0500
+++ b/usr/src/tools/scripts/flg.flp.sh	Wed Sep 15 22:49:45 2010 -0400
@@ -72,19 +72,19 @@
    	pat=$1
    	shift
 
-	if [ "$SCM_MODE" = "teamware" ] ; then
+	if [[ "$SCM_MODE" = "teamware" ]]; then
 		for dir; do
-			if [ -d $CODEMGR_WS/$dir ]; then
+			if [[ -d $CODEMGR_WS/$dir ]]; then
 				cd $CODEMGR_WS
 				find $dir -name "$pat" | \
 					sed -n s:/SCCS/s.:/:p | prpath
 				cd - > /dev/null
 			fi
 		done
-	elif [ "$SCM_MODE" = "mercurial" ]; then
+	elif [[ "$SCM_MODE" = "mercurial" || "$SCM_MODE" == "git" ]]; then
 		dirs=""
 		for dir; do
-			if [ -d $CODEMGR_WS/$dir ]; then
+			if [[ -d $CODEMGR_WS/$dir ]]; then
 				dirs="$dirs|${dir%/}"
 			fi
 		done
@@ -111,7 +111,7 @@
 #
 exec_file()
 {
-	if [ "${1##/}" = "$1" ]; then
+	if [[ "${1##/}" = "$1" ]]; then
 		. $CODEMGR_WS/$1
 	else
 		. $1
@@ -133,7 +133,7 @@
 			exec_file $1/$i
 			;;
 		*)
-			if [ -d $i -a ! -h $i ]; then
+			if [[ -d $i && ! -h $i ]]; then
 				incflg $1/$i
 				cd $1
 			fi
@@ -158,14 +158,14 @@
 	reltree=${CURTREE##$CODEMGR_WS?(/)}
 
 	while read srcfile; do
-		if [ "$RELPATHS" != y ]; then
+		if [[ "$RELPATHS" != y ]]; then
 			echo $srcfile
 			continue
 		fi
 
 		dots=
 		tree=$reltree
-		while [ "${srcfile##$tree}" = "$srcfile" ]; do
+		while [[ "${srcfile##$tree}" = "$srcfile" ]]; do
 			dots=../$dots
 			tree=`dirname $tree`
 			[ "$tree" = "." ] && break
@@ -179,7 +179,9 @@
 if [[ $SCM_MODE == "unknown" ]]; then
 	fail "Unable to determine SCM type currently in use."
 elif [[ $SCM_MODE == "mercurial" ]]; then
-	FILELIST=`hg manifest`
+	FILELIST=$(hg manifest)
+elif [[ $SCM_MODE == "git" ]]; then
+	FILELIST=$(cd $(dirname $(git rev-parse --git-dir)) && git ls-files)
 elif [[ $SCM_MODE != "teamware" ]]; then
 	fail "Unsupported SCM in use: $SCM_MODE"
 fi
@@ -204,11 +206,11 @@
 #
 # Determine the subtree being examined.
 #
-if [ $# -eq 0 ]; then
+if [[ $# -eq 0 ]]; then
 	SUBTREE=$CURTREE
-elif [ -d $1 ]; then
+elif [[ -d $1 ]]; then
 	SUBTREE=$1
-elif [ -d $CODEMGR_WS/$1 ]; then
+elif [[ -d $CODEMGR_WS/$1 ]]; then
 	SUBTREE=$CODEMGR_WS/$1
 else
 	fail "neither \$CODEMGR_WS/$1 nor $1 exists as a directory"
@@ -232,11 +234,11 @@
 cd $CODEMGR_WS
 CODEMGR_WS=`/bin/pwd`
 
-if [ "${SUBTREE##$CODEMGR_WS}" = "$SUBTREE" ]; then
+if [[ "${SUBTREE##$CODEMGR_WS}" = "$SUBTREE" ]]; then
 	fail "$SUBTREE is not a subtree of \$CODEMGR_WS"
 fi
 
-if [ "${CURTREE##$CODEMGR_WS}" = "$CURTREE" ]; then
+if [[ "${CURTREE##$CODEMGR_WS}" = "$CURTREE" ]]; then
 	fail "$CURTREE is not a subtree of \$CODEMGR_WS"
 fi
 
@@ -249,8 +251,8 @@
 # Find and execute all req.flg's at or above our subtree.
 #
 TREE=$SUBTREE
-while [ $TREE != $CODEMGR_WS ]; do
-	[ -f $TREE/req.flg ] && exec_file $TREE/req.flg
+while [[ $TREE != $CODEMGR_WS ]]; do
+	[[ -f $TREE/req.flg ]] && exec_file $TREE/req.flg
 	TREE=`dirname $TREE`
 done
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/scripts/git-pbchk.1	Wed Sep 15 22:49:45 2010 -0400
@@ -0,0 +1,95 @@
+'\" t
+.\"
+.\" This file and its contents are supplied under the terms of the
+.\" Common Development and Distribution License ("CDDL"), version 1.0.
+.\" You may only use this file in accordance with the terms of version
+.\" 1.0 of the CDDL.
+.\"
+.\" A full copy of the text of the CDDL should have accompanied this
+.\" source.  A copy of the CDDL is also available via the Internet at
+.\" http://www.illumos.org/license/CDDL.
+.\"
+.\"
+.\" Copyright 2011 Richard Lowe.
+.\"
+
+.TH "GIT\-PBCHK" "1" "December 2011" "" ""
+
+.SH "NAME"
+\fBgit\-pbchk\fR \- nits and pre\-putback checks for git
+
+.SH "SYNOPSIS"
+git\-pbchk [\-b \fIbranch\fR]
+
+.P
+git\-nits [\-b \fIbranch\fR]
+
+.SH "DESCRIPTION"
+Check your workspace for common nits and putback\-ending mistakes, a simple set of checks are run over various parts of your workspace and errors encountered are reported, afll of which should, generally, be fixed\.
+
+.TP
+Comment format
+Check that putback comments follow the prescribed format (only run for pbchk)
+
+.TP
+Copyrights
+Check that each source file contains a copyright notice for the current
+year\. You don't need to fix this if you, the potential new copyright holder, chooses not to
+
+.TP
+C style
+Check that C source files conform to the Illumos C style rules
+
+.TP
+Header check
+Check that C header files conform to the Illumos header style rules (in addition to the general C rules)
+
+.TP
+Java style
+Check that Java source files conform to the Illumos Java style rules (which differ from the traditionally recommended Java style)
+
+.TP
+SCCS Keywords
+Check that no source files contain unexpanded SCCS keywords\. It is possible that this check may false positive on certain inputs\. It is generally obvious when this is the case\.
+
+.IP
+This check does not check for expanded SCCS keywords, though the common \'ident\'\-style lines should be removed regardless of whether they are expanded\.
+
+.TP
+Mapfile check
+Check that linker mapfiles contain a comment directing anyone editing to read the directions in \fBusr/lib/README\.mapfiles\fR\.
+
+.SH "OPTIONS"
+
+.TP
+\fB\-b branch\fR:
+
+.IP
+Compare the current workspace to /branch/ for the purposes of generating file and comment lists\.
+
+.IP
+If this option is not specified an attempt is made to determine this automatically, if the git branch configuration contains this information\.
+
+.IP
+If no branch is specified and none can be determined automatically \fBorigin/master\fR is used\.
+
+.SH "FILES"
+\fBgit nits\fR and \fBgit pbchk\fR support NOT files of the form used by Cadmium with Mercurial\. These are looked for in \fB$CODEMGR_WS/\.git/\fR and in \fB$CODEMGR_WS/exception_lists/\fR as normal\. The files are named after the check from which they exclude files\.
+
+.IP "\(bu" 4
+\fBcopyright\.NOT\fR: exclude files listed from copyright checking
+
+.IP "\(bu" 4
+\fBcstyle\.NOT\fR: exclude files from the C style check
+
+.IP "\(bu" 4
+\fBhdrchk\.NOT\fR: exclude files from the C header style check
+
+.IP "\(bu" 4
+\fBkeywords\.NOT\fR: exclude files from the SCCS keywords check
+
+.IP "\(bu" 4
+\fBmapfilechk\.NOT\fR: exclude files from the linker mapfile check
+
+.IP "" 0
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/scripts/git-pbchk.py	Wed Sep 15 22:49:45 2010 -0400
@@ -0,0 +1,362 @@
+#!/usr/bin/python2.4
+#
+#  This program is free software; you can redistribute it and/or modify
+#  it under the terms of the GNU General Public License version 2
+#  as published by the Free Software Foundation.
+#
+#  This program is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#  GNU General Public License for more details.
+#
+#  You should have received a copy of the GNU General Public License
+#  along with this program; if not, write to the Free Software
+#  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+
+#
+# Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
+# Copyright 2008, 2012 Richard Lowe
+#
+
+import getopt
+import os
+import re
+import subprocess
+import sys
+
+from cStringIO import StringIO
+
+# This is necessary because, in a fit of pique, we used hg-format ignore lists
+# for NOT files.
+from mercurial import ignore
+
+#
+# Adjust the load path based on our location and the version of python into
+# which it is being loaded.  This assumes the normal onbld directory
+# structure, where we are in bin/ and the modules are in
+# lib/python(version)?/onbld/Scm/.  If that changes so too must this.
+#
+sys.path.insert(1, os.path.join(os.path.dirname(__file__), "..", "lib",
+                                "python%d.%d" % sys.version_info[:2]))
+
+#
+# Add the relative path to usr/src/tools to the load path, such that when run
+# from the source tree we use the modules also within the source tree.
+#
+sys.path.insert(2, os.path.join(os.path.dirname(__file__), ".."))
+
+from onbld.Checks import Comments, Copyright, CStyle, HdrChk
+from onbld.Checks import JStyle, Keywords, Mapfile
+
+
+class GitError(Exception):
+    pass
+
+def git(command):
+    """Run a command and return a stream containing its stdout (and write its
+    stderr to its stdout)"""
+
+    if type(command) != list:
+        command = command.split()
+
+    command = ["git"] + command
+
+    p = subprocess.Popen(command,
+                         stdout=subprocess.PIPE,
+                         stderr=subprocess.STDOUT)
+
+    err = p.wait()
+    if err != 0:
+        raise GitError(p.stdout.read())
+
+    return p.stdout
+
+
+def git_root():
+    """Return the root of the current git workspace"""
+
+    p = git('rev-parse --git-dir')
+
+    if not p:
+        sys.stderr.write("Failed finding git workspace\n")
+        sys.exit(err)
+
+    return os.path.abspath(os.path.join(p.readlines()[0],
+                                        os.path.pardir))
+
+
+def git_branch():
+    """Return the current git branch"""
+
+    p = git('branch')
+
+    if not p:
+        sys.stderr.write("Failed finding git branch\n")
+        sys.exit(err)
+
+    for elt in p:
+        if elt[0] == '*':
+            if elt.endswith('(no branch)'):
+                return None
+            return elt.split()[1]
+
+
+def git_parent_branch(branch):
+    """Return the parent of the current git branch.
+
+    If this branch tracks a remote branch, return the remote branch which is
+    tracked.  If not, default to origin/master."""
+
+    if not branch:
+        return None
+
+    p = git("for-each-ref --format=%(refname:short) %(upstream:short) " +
+            "refs/heads/")
+
+    if not p:
+        sys.stderr.write("Failed finding git parent branch\n")
+        sys.exit(err)
+
+    for line in p:
+        # Git 1.7 will leave a ' ' trailing any non-tracking branch
+        if ' ' in line and not line.endswith(' \n'):
+            local, remote = line.split()
+            if local == branch:
+                return remote
+    return 'origin/master'
+
+
+def git_comments(parent):
+    """Return a list of any checkin comments on this git branch"""
+
+    p = git('log --pretty=format:%%B %s..' % parent)
+
+    if not p:
+        sys.stderr.write("Failed getting git comments\n")
+        sys.exit(err)
+
+    return map(lambda x: x.strip(), p.readlines())
+
+
+def git_file_list(parent, paths=None):
+    """Return the set of files which have ever changed on this branch.
+
+    NB: This includes files which no longer exist, or no longer actually
+    differ."""
+
+    p = git("log --name-only --pretty=format: %s.. %s" %
+             (parent, ' '.join(paths)))
+
+    if not p:
+        sys.stderr.write("Failed building file-list from git\n")
+        sys.exit(err)
+
+    ret = set()
+    for fname in p:
+        if fname and not fname.isspace() and fname not in ret:
+            ret.add(fname.strip())
+
+    return ret
+
+
+def not_check(root, cmd):
+    """Return a function which returns True if a file given as an argument
+    should be excluded from the check named by 'cmd'"""
+
+    ignorefiles = filter(os.path.exists,
+                         [os.path.join(root, ".git", "%s.NOT" % cmd),
+                          os.path.join(root, "exception_lists", cmd)])
+    if len(ignorefiles) > 0:
+        return ignore.ignore(root, ignorefiles, sys.stderr.write)
+    else:
+        return lambda x: False
+
+
+def gen_files(root, parent, paths, exclude):
+    """Return a function producing file names, relative to the current
+    directory, of any file changed on this branch (limited to 'paths' if
+    requested), and excluding files for which exclude returns a true value """
+
+    # Taken entirely from Python 2.6's os.path.relpath which we would use if we
+    # could.
+    def relpath(path, here):
+        c = os.path.abspath(os.path.join(root, path)).split(os.path.sep)
+        s = os.path.abspath(here).split(os.path.sep)
+        l = len(os.path.commonprefix((s, c)))
+        return os.path.join(*[os.path.pardir] * (len(s)-l) + c[l:])
+
+    def ret(select=None):
+        if not select:
+            select = lambda x: True
+
+        for f in git_file_list(parent, paths):
+            f = relpath(f, '.')
+            if (os.path.exists(f) and select(f) and not exclude(f)):
+                yield f
+    return ret
+
+
+def comchk(root, parent, flist, output):
+    output.write("Comments:\n")
+
+    return Comments.comchk(git_comments(parent), check_db=True,
+                           output=output)
+
+
+def mapfilechk(root, parent, flist, output):
+    ret = 0
+
+    # We are interested in examining any file that has the following
+    # in its final path segment:
+    #    - Contains the word 'mapfile'
+    #    - Begins with 'map.'
+    #    - Ends with '.map'
+    # We don't want to match unless these things occur in final path segment
+    # because directory names with these strings don't indicate a mapfile.
+    # We also ignore files with suffixes that tell us that the files
+    # are not mapfiles.
+    MapfileRE = re.compile(r'.*((mapfile[^/]*)|(/map\.+[^/]*)|(\.map))$',
+        re.IGNORECASE)
+    NotMapSuffixRE = re.compile(r'.*\.[ch]$', re.IGNORECASE)
+
+    output.write("Mapfile comments:\n")
+
+    for f in flist(lambda x: MapfileRE.match(x) and not
+                   NotMapSuffixRE.match(x)):
+        fh = open(f, 'r')
+        ret |= Mapfile.mapfilechk(fh, output=output)
+        fh.close()
+    return ret
+
+
+def copyright(root, parent, flist, output):
+    ret = 0
+    output.write("Copyrights:\n")
+    for f in flist():
+        fh = open(f, 'r')
+        ret |= Copyright.copyright(fh, output=output)
+        fh.close()
+    return ret
+
+
+def hdrchk(root, parent, flist, output):
+    ret = 0
+    output.write("Header format:\n")
+    for f in flist(lambda x: x.endswith('.h')):
+        fh = open(f, 'r')
+        ret |= HdrChk.hdrchk(fh, lenient=True, output=output)
+        fh.close()
+    return ret
+
+
+def cstyle(root, parent, flist, output):
+    ret = 0
+    output.write("C style:\n")
+    for f in flist(lambda x: x.endswith('.c') or x.endswith('.h')):
+        fh = open(f, 'r')
+        ret |= CStyle.cstyle(fh, output=output, picky=True,
+                             check_posix_types=True,
+                             check_continuation=True)
+        fh.close()
+    return ret
+
+
+def jstyle(root, parent, flist, output):
+    ret = 0
+    output.write("Java style:\n")
+    for f in flist(lambda x: x.endswith('.java')):
+        fh = open(f, 'r')
+        ret |= JStyle.jstyle(fh, output=output, picky=True)
+        fh.close()
+    return ret
+
+
+def keywords(root, parent, flist, output):
+    ret = 0
+    output.write("SCCS Keywords:\n")
+    for f in flist():
+        fh = open(f, 'r')
+        ret |= Keywords.keywords(fh, output=output)
+        fh.close()
+    return ret
+
+
+def run_checks(root, parent, cmds, paths='', opts={}):
+    """Run the checks given in 'cmds', expected to have well-known signatures,
+    and report results for any which fail.
+
+    Return failure if any of them did.
+
+    NB: the function name of the commands passed in is used to name the NOT
+    file which excepts files from them."""
+
+    ret = 0
+
+    for cmd in cmds:
+        s = StringIO()
+
+        exclude = not_check(root, cmd.func_name)
+        result = cmd(root, parent, gen_files(root, parent, paths, exclude),
+                     output=s)
+        ret |= result
+
+        if result != 0:
+            print s.getvalue()
+
+    return ret
+
+
+def nits(root, parent, paths):
+    cmds = [copyright,
+            cstyle,
+            hdrchk,
+            jstyle,
+            keywords,
+            mapfilechk]
+    run_checks(root, parent, cmds, paths)
+
+
+def pbchk(root, parent, paths):
+    cmds = [comchk,
+            copyright,
+            cstyle,
+            hdrchk,
+            jstyle,
+            keywords,
+            mapfilechk]
+    run_checks(root, parent, cmds)
+
+
+def main(cmd, args):
+    parent_branch = None
+
+    try:
+        opts, args = getopt.getopt(args, 'b:')
+    except getopt.GetoptError, e:
+        sys.stderr.write(str(e) + '\n')
+        sys.stderr.write("Usage: %s [-b branch] [path...]\n" % cmd)
+        sys.exit(1)
+
+    for opt, arg in opts:
+        if opt == '-b':
+            parent_branch = arg
+
+    if not parent_branch:
+        parent_branch = git_parent_branch(git_branch())
+
+    func = nits
+    if cmd == 'git-pbchk':
+        func = pbchk
+        if args:
+            sys.stderr.write("only complete workspaces may be pbchk'd\n");
+            sys.exit(1)
+
+    func(git_root(), parent_branch, args)
+
+if __name__ == '__main__':
+    try:
+        main(os.path.basename(sys.argv[0]), sys.argv[1:])
+    except GitError, e:
+        sys.stderr.write("failed to run git:\n %s\n" % str(e))
+        sys.exit(1)
--- a/usr/src/tools/scripts/nightly.sh	Wed Feb 22 14:00:06 2012 -0500
+++ b/usr/src/tools/scripts/nightly.sh	Wed Sep 15 22:49:45 2010 -0400
@@ -733,7 +733,7 @@
 	# Remove all .ln files to ensure a full reference file
 	#
 	rm -f Nothing_to_remove \
-	    `find . \( -name SCCS -o -name .hg -o -name .svn \) \
+	    `find . \( -name SCCS -o -name .hg -o -name .svn -o -name .git \) \
 	    	-prune -o -type f -name '*.ln' -print `
 
 	/bin/time $MAKE -ek lint 2>&1 | \
@@ -2148,7 +2148,7 @@
 
 	# Remove all .make.state* files, just in case we are restarting
 	# the build after having interrupted a previous 'make clobber'.
-	find . \( -name SCCS -o -name .hg -o -name .svn \
+	find . \( -name SCCS -o -name .hg -o -name .svn -o -name .git \
 		-o -name 'interfaces.*' \) -prune \
 		-o -name '.make.*' -print | xargs rm -f
 
@@ -2184,7 +2184,7 @@
 	# We should probably blow away temporary directories too.
 	cd $SRC
 	find $relsrcdirs \( -name SCCS -o -name .hg -o -name .svn \
-	    -o -name 'interfaces.*' \) -prune -o \
+	    -o -name .git -o -name 'interfaces.*' \) -prune -o \
 	    \( -name '.make.*' -o -name 'lib*.a' -o -name 'lib*.so*' -o \
 	       -name '*.o' \) -print | \
 	    grep -v 'tools/ctf/dwarf/.*/libdwarf' | xargs rm -f
--- a/usr/src/tools/scripts/webrev.1	Wed Feb 22 14:00:06 2012 -0500
+++ b/usr/src/tools/scripts/webrev.1	Wed Sep 15 22:49:45 2010 -0400
@@ -22,7 +22,7 @@
 .\" Use is subject to license terms.
 .\"
 .\"
-.TH webrev 1 "22 Feb 2010"
+.TH webrev 1 "6 Dec 2010"
 .SH NAME
 webrev \- Generate HTML codereview materials
 .SH SYNOPSIS
@@ -60,7 +60,7 @@
 .B webrev
 builds a set of HTML files suitable for performing code review of
 source changes in a web browser.
-It supports Mercurial, Subversion and Teamware repositories.
+It supports Mercurial, Git, Subversion and Teamware repositories.
 At its most basic, usage is:
 .nf
         $ webrev
@@ -174,9 +174,22 @@
 In the case of Mercurial \fBwebrev\fR will attempt to use the output
 from the
 .BR hg (1)
-"hg root" to identify the workspace root, and the
+"hg root" command to identify the workspace root, and the
 "hg path default" command to identify the parent workspace.
 
+.SS Git
+In the case of Git \fBwebrev\fR will attempt to use the output from the
+.BR git (1)
+"git rev-parse --git-dir" command to identify the workspace root, and will
+attempt to use the remote branch which the current branch is tracking as the
+parent, if none is specified 'origin/master' will be used.
+
+The parent specified when using git is, in all cases, a git 'tree-ish' and
+never an actual git repository, remote or otherwise.  Anything specifiable to
+git as a tree-ish should, similarly, be specifiable as a parent for webrev.
+This includes branches, explicit revisions, reflog entries, etc. See
+.BR git-rev-parse (1)
+
 .SS Subversion
 In the case of Subversion \fBwebrev\fR will attempt to use the output
 from the
@@ -458,6 +471,7 @@
 .BR putback "(1),"
 .BR workspace "(1),"
 .BR hg "(1),"
+.BR git "(1),"
 .BR ssh_config "(4),"
 .BR svn "(1),"
 .BR which_scm "(1)"
--- a/usr/src/tools/scripts/webrev.sh	Wed Feb 22 14:00:06 2012 -0500
+++ b/usr/src/tools/scripts/webrev.sh	Wed Sep 15 22:49:45 2010 -0400
@@ -516,6 +516,16 @@
 	$SED -e "s/&/\&amp;/g" -e "s/</\&lt;/g" -e "s/>/\&gt;/g" "$@" | expand
 }
 
+# 
+# Trim a digest-style revision to a conventionally readable yet useful length
+#
+trim_digest()
+{
+	typeset digest=$1
+
+	echo $digest | $SED -e 's/\([0-9a-f]\{12\}\).*/\1/'
+}
+
 #
 # input_cmd | its2url | output_cmd
 #
@@ -1780,6 +1790,81 @@
 }
 
 #
+# Transform a specified 'git log' output format into a wx-like active list.
+#
+function git_wxfile
+{
+	typeset child="$1"
+	typeset parent="$2"
+
+	TMPFLIST=/tmp/$$.active
+	$PERL -e 'my (%files, %realfiles, $msg);
+	my $branch = $ARGV[0];
+	 
+	open(F, "git diff -M --name-status $branch |");
+	while (<F>) {
+	    chomp;
+	    if (/^R(\d+)\s+([^ ]+)\s+([^ ]+)/) { # rename
+		if ($1 >= 75) {			 # Probably worth treating as a rename
+		    $realfiles{$3} = $2
+		} else {
+		    $realfiles{$3} = $3;
+		    $realfiles{$2} = $2;
+		}
+	    } else {
+		my $f = (split /\s+/, $_)[1];
+		$realfiles{$f} = $f;
+	    }
+	}
+	close(F);
+	 
+	my $state = 1;		    # 0|comments, 1|files
+	open(F, "git whatchanged --pretty=format:%B $branch.. |");
+	while (<F>) {
+	    chomp;
+	    if (/^:[0-9]{6}/) {
+		my $fname = (split /\t/, $_)[1];
+		next if !defined($realfiles{$fname}); # No real change
+		$state = 1;
+		$files{$fname} = $msg;
+	    } else {
+		if ($state == 1) {
+		    $state = 0;
+		    $msg = /^\n/ ? "" : "\n";
+		}
+		$msg .= "$_\n" if ($_);
+	    }
+	}
+	close(F);
+	 
+	for (sort keys %files) {
+	    if ($realfiles{$_} ne $_) {
+		print "$_ $realfiles{$_}\n$files{$_}\n";
+	    } else {
+		print "$_\n$files{$_}\n"
+	    }
+	}' ${parent} > $TMPFLIST
+
+	wxfile=$TMPFLIST
+}
+
+#
+# flist_from_git
+# Build a wx-style active list, and hand it off to flist_from_wx
+#
+function flist_from_git
+{
+	typeset child=$1
+	typeset parent=$2
+
+	print " File list from: git ...\c"
+	git_wxfile "$child" "$parent";
+
+	# flist_from_wx prints the Done, so we don't have to.
+	flist_from_wx $TMPFLIST
+}
+
+#
 # flist_from_subversion
 #
 # Generate the file list by extracting file names from svn status.
@@ -1999,6 +2084,64 @@
 	fi
 }
 
+function build_old_new_git
+{
+	typeset olddir="$1"
+	typeset newdir="$2"
+	typeset o_mode=
+	typeset n_mode=
+	typeset o_object=
+	typeset n_object=
+	typeset OWD=$PWD
+	typeset file
+	typeset type
+
+	cd $CWS
+
+	#
+	# Get old file and its mode from the git object tree
+	#
+	if [[ "$PDIR" == "." ]]; then
+		file="$PF"
+	else
+	       file="$PDIR/$PF"
+	fi
+
+	if [[ -n $parent_webrev && -e $PWS/$PDIR/$PF ]]; then
+		cp $PWS/$PDIR/$PF $olddir/$PDIR/$PF
+	else
+                $GIT ls-tree $GIT_PARENT $file | read o_mode type o_object junk
+                $GIT cat-file $type $o_object > $olddir/$file 2>/dev/null
+                 
+                if (( $? != 0 )); then
+                        rm -f $olddir/$file
+                elif [[ -n $o_mode ]]; then
+                        # Strip the first 3 digits, to get a regular octal mode
+                        o_mode=${o_mode/???/}
+                        chmod $o_mode $olddir/$file
+                else
+                        # should never happen
+                        print -u2 "ERROR: set mode of $olddir/$file"
+                fi
+	fi
+
+	#
+	# new version of the file.
+	#
+	if [[ "$DIR" == "." ]]; then
+		file="$F"
+	else
+		file="$DIR/$F"
+	fi
+	rm -rf $newdir/$file
+
+        if [[ -e $CWS/$DIR/$F ]]; then
+            cp $CWS/$DIR/$F $newdir/$DIR/$F
+            chmod $(get_file_mode $CWS/$DIR/$F) $newdir/$DIR/$F
+        fi
+	cd $OWD
+}
+
 function build_old_new_subversion
 {
 	typeset olddir="$1"
@@ -2059,6 +2202,8 @@
 		build_old_new_teamware "$olddir" "$newdir"
 	elif [[ $SCM_MODE == "mercurial" ]]; then
 		build_old_new_mercurial "$olddir" "$newdir"
+	elif [[ $SCM_MODE == "git" ]]; then
+		build_old_new_git "$olddir" "$newdir"
 	elif [[ $SCM_MODE == "subversion" ]]; then
 		build_old_new_subversion "$olddir" "$newdir"
 	elif [[ $SCM_MODE == "unknown" ]]; then
@@ -2120,11 +2265,12 @@
 
 set +o noclobber
 
-PATH=$(dirname $(whence $0)):$PATH
+PATH=$(/bin/dirname "$(whence $0)"):$PATH
 
 [[ -z $WDIFF ]] && WDIFF=`look_for_prog wdiff`
 [[ -z $WX ]] && WX=`look_for_prog wx`
 [[ -z $HG_ACTIVE ]] && HG_ACTIVE=`look_for_prog hg-active`
+[[ -z $GIT ]] && GIT=`look_for_prog git`
 [[ -z $WHICH_SCM ]] && WHICH_SCM=`look_for_prog which_scm`
 [[ -z $CODEREVIEW ]] && CODEREVIEW=`look_for_prog codereview`
 [[ -z $PS2PDF ]] && PS2PDF=`look_for_prog ps2pdf`
@@ -2307,6 +2453,24 @@
 	    codemgr_ws=$(hg root -R $testparent 2>/dev/null)
 	[[ -z $codemgr_ws ]] && codemgr_ws=$(hg root 2>/dev/null)
 	CWS=$codemgr_ws
+elif [[ $SCM_MODE == "git" ]]; then
+	#
+	# Git priorities:
+	# 1. git rev-parse --git-dir from CODEMGR_WS environment variable
+	# 2. git rev-parse --git-dir from directory of invocation
+	#
+	[[ -z $codemgr_ws && -n $CODEMGR_WS ]] && \
+	    codemgr_ws=$($GIT --git-dir=$CODEMGR_WS/.git rev-parse --git-dir \
+                2>/dev/null)
+	[[ -z $codemgr_ws ]] && \
+	    codemgr_ws=$($GIT rev-parse --git-dir 2>/dev/null)
+
+	if [[ "$codemgr_ws" == ".git" ]]; then
+		codemgr_ws="${PWD}/${codemgr_ws}"
+	fi
+
+	codemgr_ws=$(dirname $codemgr_ws) # Lose the '/.git'
+	CWS="$codemgr_ws"
 elif [[ $SCM_MODE == "subversion" ]]; then
 	#
 	# Subversion priorities:
@@ -2358,8 +2522,8 @@
 # then note that fact and set the parent to the raw_files/new subdirectory.
 #
 if [[ -n $pflag && -d $codemgr_parent/raw_files/new ]]; then
-	parent_webrev="$codemgr_parent"
-	codemgr_parent="$codemgr_parent/raw_files/new"
+	parent_webrev=$(readlink -f "$codemgr_parent")
+	codemgr_parent=$(readlink -f "$codemgr_parent/raw_files/new")
 fi
 
 if [[ -z $wflag && -z $lflag ]]; then
@@ -2390,7 +2554,7 @@
 # is in use.
 #
 case "$SCM_MODE" in
-teamware|mercurial|subversion)
+teamware|mercurial|git|subversion)
 	;;
 unknown)
 	if [[ $flist_mode == "auto" ]]; then
@@ -2552,7 +2716,6 @@
 		codemgr_parent=`hg path -R $codemgr_ws default 2>/dev/null`
 	fi
 
-	CWS_REV=`hg parent -R $codemgr_ws --template '{node|short}' 2>/dev/null`
 	PWS=$codemgr_parent
 
 	#
@@ -2616,6 +2779,96 @@
 		print -u2 "Error: Cannot discover parent revision"
 		exit 1
 	fi
+
+	pnode=$(trim_digest $HG_PARENT)
+	PRETTY_PWS="${PWS} (at ${pnode})"
+	cnode=$(hg parent -R $codemgr_ws --template '{node|short}' \
+	    2>/dev/null)
+	PRETTY_CWS="${CWS} (at ${cnode})"}
+elif [[ $SCM_MODE == "git" ]]; then
+	#
+	# Parent can either be specified with -p, or specified with
+	# CODEMGR_PARENT in the environment.
+	#
+
+	if [[ -z $codemgr_parent && -n $CODEMGR_PARENT ]]; then
+		codemgr_parent=$CODEMGR_PARENT
+	fi
+
+	# Try to figure out the parent based on the branch the current
+	# branch is tracking, if we fail, use origin/master
+	this_branch=$($GIT branch | nawk '$1 == "*" { print $2 }')
+	par_branch="origin/master"
+
+        # If we're not on a branch there's nothing we can do
+        if [[ $this_branch != "(no branch)" ]]; then
+                $GIT for-each-ref                                                 \
+                    --format='%(refname:short) %(upstream:short)' refs/heads/ |   \
+                    while read local remote; do                                   \
+                	[[ "$local" == "$this_branch" ]] && par_branch="$remote"; \
+                    done
+	fi
+
+	if [[ -z $codemgr_parent ]]; then
+		codemgr_parent=$par_branch
+	fi
+	PWS=$codemgr_parent
+
+	#
+	# If the parent is a webrev, we want to do some things against
+	# the natural workspace parent (file list, comments, etc)
+	#
+	if [[ -n $parent_webrev ]]; then
+		real_parent=$par_branch
+	else
+		real_parent=$PWS
+	fi
+
+	if [[ -z $flist_done ]]; then
+		flist_from_git "$CWS" "$real_parent"
+		flist_done=1
+	fi
+
+	#
+	# If we have a file list now, pull out any variables set
+	# therein.
+	#
+	if [[ -n $flist_done ]]; then
+		env_from_flist
+	fi
+
+	#
+	# If we don't have a wx-format file list, build one we can pull change
+	# comments from.
+	#
+	if [[ -z $wxfile ]]; then
+		print "  Comments from: git...\c"
+		git_wxfile "$CWS" "$real_parent"
+		print " Done."
+	fi
+
+	if [[ -z $GIT_PARENT ]]; then
+		GIT_PARENT=$($GIT merge-base "$real_parent" HEAD)
+	fi
+	if [[ -z $GIT_PARENT ]]; then
+		print -u2 "Error: Cannot discover parent revision"
+		exit 1
+	fi
+
+	pnode=$(trim_digest $GIT_PARENT)
+
+	if [[ $real_parent == */* ]]; then
+		origin=$(echo $real_parent | cut -d/ -f1)
+		origin=$($GIT remote -v | \
+		    $AWK '$1 == "'$origin'" { print $2; exit }')
+		PRETTY_PWS="${PWS} (${origin} at ${pnode})"
+	else
+		PRETTY_PWS="${PWS} (at ${pnode})"
+	fi
+
+	cnode=$($GIT --git-dir=${codemgr_ws}/.git rev-parse --short=12 HEAD \
+	    2>/dev/null)
+	PRETTY_CWS="${CWS} (at ${cnode})"
 elif [[ $SCM_MODE == "subversion" ]]; then
 
 	#
@@ -2682,7 +2935,7 @@
 typeset -r its_sed_script=/tmp/$$.its_sed
 valid_prefixes=
 if [[ -z $nflag ]]; then
-	DEFREGFILE="$(dirname $(whence $0))/../etc/its.reg"
+	DEFREGFILE="$(/bin/dirname "$(whence $0)")/../etc/its.reg"
 	if [[ -n $Iflag ]]; then
 		REGFILE=$ITSREG
 	elif [[ -r $HOME/.its.reg ]]; then
@@ -2711,7 +2964,7 @@
 	done
 
 
-	DEFCONFFILE="$(dirname $(whence $0))/../etc/its.conf"
+	DEFCONFFILE="$(/bin/dirname "$(whence $0)")/../etc/its.conf"
 	CONFFILES=$DEFCONFFILE
 	if [[ -r $HOME/.its.conf ]]; then
 		CONFFILES="${CONFFILES} $HOME/.its.conf"
@@ -2895,21 +3148,11 @@
 #
 # Summarize what we're going to do.
 #
-if [[ -n $CWS_REV ]]; then
-	print "      Workspace: $CWS (at $CWS_REV)"
-else
-	print "      Workspace: $CWS"
-fi
+print "      Workspace: ${PRETTY_CWS:-$CWS}"
 if [[ -n $parent_webrev ]]; then
 	print "Compare against: webrev at $parent_webrev"
 else
-	if [[ -n $HG_PARENT ]]; then
-		hg_parent_short=`echo $HG_PARENT \
-			| $SED -e 's/\([0-9a-f]\{12\}\).*/\1/'`
-		print "Compare against: $PWS (at $hg_parent_short)"
-	else
-		print "Compare against: $PWS"
-	fi
+	print "Compare against: ${PRETTY_PWS:-$PWS}"
 fi
 
 [[ -n $INCLUDE_FILE ]] && print "      Including: $INCLUDE_FILE"
@@ -3260,19 +3503,13 @@
 
 PREPDATE=$(LC_ALL=C /usr/bin/date +%Y-%b-%d\ %R\ %z\ %Z)
 print "<tr><th>Prepared by:</th><td>$preparer on $PREPDATE</td></tr>"
-print "<tr><th>Workspace:</th><td>$CWS"
-if [[ -n $CWS_REV ]]; then
-	print "(at $CWS_REV)"
-fi
+print "<tr><th>Workspace:</th><td>${PRETTY_CWS:-$CWS}"
 print "</td></tr>"
 print "<tr><th>Compare against:</th><td>"
 if [[ -n $parent_webrev ]]; then
 	print "webrev at $parent_webrev"
 else
-	print "$PWS"
-	if [[ -n $hg_parent_short ]]; then
-		print "(at $hg_parent_short)"
-	fi
+	print "${PRETTY_PWS:-$PWS}"
 fi
 print "</td></tr>"
 print "<tr><th>Summary of changes:</th><td>"
--- a/usr/src/tools/scripts/which_scm.1	Wed Feb 22 14:00:06 2012 -0500
+++ b/usr/src/tools/scripts/which_scm.1	Wed Sep 15 22:49:45 2010 -0400
@@ -21,9 +21,7 @@
 .\" Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
 .\" Use is subject to license terms.
 .\"
-.\" ident	"%Z%%M%	%I%	%E% SMI"
-.\"
-.TH which_scm 1 "11 April 2008"
+.TH which_scm 1 "18 September 2009"
 .SH NAME
 which_scm \- Report Source Code Management system
 .SH SYNOPSIS
@@ -51,6 +49,7 @@
 used in the output format):
 .nf
 	cvs
+	git
 	mercurial
 	rcs
 	sccs
@@ -71,6 +70,7 @@
 
 .SH SEE ALSO
 .IR cvs(1) ,
+.IR git(1) ,
 .IR hg(1) ,
 .IR sccs(1)
 .IR svn(1) ,
--- a/usr/src/tools/scripts/which_scm.sh	Wed Feb 22 14:00:06 2012 -0500
+++ b/usr/src/tools/scripts/which_scm.sh	Wed Sep 15 22:49:45 2010 -0400
@@ -24,8 +24,6 @@
 # Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
-# ident	"%Z%%M%	%I%	%E% SMI"
-#
 
 # which_scm outputs two strings: one identifying the SCM in use, and
 # the second giving the root directory for the SCM, if known, or just
@@ -59,6 +57,7 @@
 	[ -d "$1/.hg" ] && scmid="$scmid mercurial"
 	[ -d "$1/CVS" ] && scmid="$scmid cvs"
 	[ -d "$1/.svn" ] && scmid="$scmid subversion"
+	[ -d "$1/.git" ] && scmid="$scmid git"
 	echo $scmid
 }
 
@@ -99,8 +98,8 @@
 	SCM_TYPE="$1"
 	# We're done searching if we hit either a change in type or the top
 	# of a "third type" control system.
-	if [[ "$SCM_TYPE" != "$CWD_TYPE" || "$SCM_TYPE" == mercurial || \
-	    "$SCM_TYPE" == teamware ]]; then
+	if [[ "$SCM_TYPE" != "$CWD_TYPE" || "$SCM_TYPE" == git || \
+	    "$SCM_TYPE" == mercurial || "$SCM_TYPE" == teamware ]]; then
 		break
 	fi
 	PREVDIR="$DIR"
--- a/usr/src/tools/scripts/ws.sh	Wed Feb 22 14:00:06 2012 -0500
+++ b/usr/src/tools/scripts/ws.sh	Wed Sep 15 22:49:45 2010 -0400
@@ -70,11 +70,11 @@
 		return
 	fi
 
-	if [ "$SCM_MODE" = "teamware" ]; then
+	if [[ "$SCM_MODE" = "teamware" ]]; then
 		# Check for problematic parent specification and adjust
 		proto=`echo $1|fmtwsname`
 		echo "${proto}/root_${MACH}"
-	elif [ "$SCM_MODE" = "mercurial" ]; then
+	elif [[ "$SCM_MODE" = "mercurial" ]]; then
 		proto=$1
 		#
 		# If the proto is a local repository then we can use it
@@ -82,11 +82,19 @@
 		# check if it exists or not, we never did for Teamware,
 		# since it might appear later anyway.
 		#
-		if [ "${proto##ssh://}" == "$proto" -a \
+		if [[ "${proto##ssh://}" == "$proto" -a \
 		     "${proto##http://}" == "$proto" -a \
-		     "${proto##https://}" == "$proto" ]; then
+		     "${proto##https://}" == "$proto" ]]; then
 			echo "${proto}/root_${MACH}"
 		fi
+	elif [[ "$SCM_MODE" = "git" ]]; then
+		#
+                # For git, we make no attempt to deal with the possibility of
+                # remote parent workspaces because, in the protodefs file, we
+                # don't actually acknowledge the concept of a parent workspace
+                # at all, in keeping with the rest of our git support.
+                #
+		echo "${1}/root_${MACH}"
 	fi
 }
 
@@ -98,14 +106,14 @@
 	return 0
 }
 
-if [ "$1" = "-e" ]; then
+if [[ "$1" = "-e" ]]; then
 	setenv=true
 	shift
 else
 	setenv=false
 fi
 
-WHICH_SCM=$(dirname $(whence $0))/which_scm
+WHICH_SCM=$(/bin/dirname $(whence $0))/which_scm
 if [[ ! -x $WHICH_SCM ]]; then
 	WHICH_SCM=which_scm
 fi
@@ -114,7 +122,7 @@
 # No workspace/repository path was given, so try and detect one from our
 # current directory we're in
 #
-if [ $# -lt 1 ]; then
+if [[ $# -lt 1 ]]; then
 	if env CODEMGR_WS="" $WHICH_SCM | read SCM_MODE tmpwsname && \
 	    [[ $SCM_MODE != unknown ]]; then
 		echo "Defaulting to $SCM_MODE repository $tmpwsname"
@@ -151,14 +159,14 @@
 #
 # Checking for CODEMGR_WSPATH
 #
-if [ "(" "${CODEMGR_WSPATH}x" != "x" ")" -a "(" ! -d $wsname ")" -a \
-     "(" `expr "$wsname" : "\/"` = "0" ")" ] 
+if [[ "(" "${CODEMGR_WSPATH}x" != "x" ")" -a "(" ! -d $wsname ")" -a \
+     "(" `expr "$wsname" : "\/"` = "0" ")" ]] 
 then
 	ofs=$IFS
 	IFS=": 	"
 	for i in $CODEMGR_WSPATH 
 	do
-		if [ -d ${i}/${wsname} ]; then
+		if [[ -d ${i}/${wsname} ]]; then
 			wsname=${i}/${wsname}
 			break
 		fi
@@ -170,7 +178,7 @@
 # to translate it to an absolute pathname.  We need an
 # absolute pathname in order to set CODEMGR_WS.
 #
-if [ `expr "$wsname" : "\/"` = "0" ] 
+if [[ `expr "$wsname" : "\/"` = "0" ]] 
 then
 	pwd=`pwd`
 	wsname="$pwd/$wsname"
@@ -179,7 +187,7 @@
 #
 #	Check to see if this is a valid workspace
 #
-if [ ! -d $wsname ]; then
+if [[ ! -d $wsname ]]; then
 	echo "$wsname . . . no such directory" >&2
 	if $setenv; then
 		cleanup_env
@@ -209,14 +217,18 @@
 SRC=$wsname/usr/src; export SRC
 TSRC=$wsname/usr/ontest; export TSRC
 
-if [ "$SCM_MODE" = "teamware" -a -d ${wsname}/Codemgr_wsdata ]; then
+if [[ "$SCM_MODE" = "teamware" -a -d ${wsname}/Codemgr_wsdata ]]; then
 	CM_DATA="Codemgr_wsdata"
 	wsosdir=$CODEMGR_WS/$CM_DATA/sunos
 	protofile=$wsosdir/protodefs
-elif [ "$SCM_MODE" = "mercurial" -a -d ${wsname}/.hg ]; then
+elif [[ "$SCM_MODE" = "mercurial" -a -d ${wsname}/.hg ]]; then
 	CM_DATA=".hg"
 	wsosdir=$CODEMGR_WS/$CM_DATA
 	protofile=$wsosdir/org.opensolaris.protodefs
+elif [[ "$SCM_MODE" = "git" -a -d ${wsname}/.git ]]; then
+	CM_DATA=".git"
+	wsosdir=$CODEMGR_WS/$CM_DATA
+	protofile=$wsosdir/org.opensolaris.protodefs
 else
 	echo "$wsname is not a supported workspace; type is $SCM_MODE" >&2
 	if $setenv; then
@@ -229,8 +241,8 @@
 
 MACH=`uname -p`
 
-if [ ! -f $protofile ]; then
-	if [ ! -w $CODEMGR_WS/$CM_DATA ]; then
+if [[ ! -f $protofile ]]; then
+	if [[ ! -w $CODEMGR_WS/$CM_DATA ]]; then
 		#
 		# The workspace doesn't have a protodefs file and I am
 		# unable to create one.  Tell user and use /tmp instead.
@@ -242,7 +254,7 @@
 		protofile=$wsosdir/protodefs
 	fi
 
-	if [ ! -d $wsosdir ]; then
+	if [[ ! -d $wsosdir ]]; then
 		mkdir $wsosdir
 	fi
 
@@ -274,9 +286,9 @@
 PROTO1=\$CODEMGR_WS/proto
 PROTOFILE_EoF
 	
-	if [ "$SCM_MODE" = "teamware" ]; then
+	if [[ "$SCM_MODE" = "teamware" ]]; then
 		cat << PROTOFILE_EoF >> $protofile
-if [ -f "\$CODEMGR_WS/Codemgr_wsdata/parent" ]; then
+if [[ -f "\$CODEMGR_WS/Codemgr_wsdata/parent" ]]; then
    #
    # If this workspace has an codemgr parent then set PROTO2 to
    # point to the parents proto space.
@@ -287,7 +299,7 @@
    fi
 fi
 PROTOFILE_EoF
-	elif [ "$SCM_MODE" = "mercurial" ]; then
+	elif [[ "$SCM_MODE" = "mercurial" ]]; then
 		cat << PROTOFILE_EoF >> $protofile
 parent=\`(cd \$CODEMGR_WS && hg path default 2>/dev/null)\`
 if [[ \$? -eq 0 && -n \$parent ]]; then
@@ -362,7 +374,7 @@
 fi
 
 if [[ -z "$ONBLD_DIR" ]]; then
-	ONBLD_DIR=$(dirname $(whence $0))
+	ONBLD_DIR=$(/bin/dirname $(whence $0))
 fi
 
 if ! echo ":$PATH:" | grep ":${ONBLD_DIR}:" > /dev/null; then
@@ -396,16 +408,16 @@
 
 echo ""
 echo "Workspace                    : $wsname"
-if [ -n "$parent" ]; then
+if [[ -n "$parent" ]]; then
    echo "Workspace Parent             : $parent"
 fi
 echo "Proto area (\$ROOT)           : $ROOT"
-if [ -n "$PARENT_ROOT" ]; then
+if [[ -n "$PARENT_ROOT" ]]; then
    echo "Parent proto area (\$PARENT_ROOT) : $PARENT_ROOT"
 fi
 echo "Root of source (\$SRC)        : $SRC"
 echo "Root of test source (\$TSRC)  : $TSRC"
-if [ $osbld_flag = "1" ]; then
+if [[ $osbld_flag = "1" ]]; then
    echo "Prepended to PATH            : $ONBLD_DIR"
 fi
 echo "Current directory (\$PWD)     : $wsname"