Difference between revisions of "ParaView/Git/Maintain"

From KitwarePublic
< ParaView‎ | Git
Jump to: navigation, search
(Merging next topics into master)
(Gatekeeper Review Script)
 
(One intermediate revision by the same user not shown)
Line 29: Line 29:
  
 
==Gatekeeper Review Script==
 
==Gatekeeper Review Script==
<code lang="python">
 
  
</code>
+
Script used for weekly ParaView Gatekeeper Review.
 +
 
 +
<source lang="python">
 +
#!/usr/bin/env python
 +
import subprocess
 +
import sys
 +
import re
 +
 
 +
#------------------------------------------------------------------------------
 +
class UserCancelled(Exception):
 +
  def __str__(self):
 +
    return "Cancelled by user"
 +
 
 +
pv_only = re.compile("^\\s*([a-zA-Z0-9_-]+)\\s*\|?\\s*$");
 +
pv_and_vtk = re.compile("^\\s*([a-zA-Z0-9_-]+)\\s*|\\s*VTK\\s*$");
 +
 
 +
def execute(command, **kwargs):
 +
  no_echo = kwargs.get("no_echo")
 +
  if not no_echo:
 +
    print "> %s" % command
 +
  process = subprocess.Popen(command, shell=True,
 +
                            stdout=subprocess.PIPE,
 +
                            stderr=subprocess.STDOUT)
 +
  output,_ =  process.communicate()
 +
  if output and not no_echo:
 +
    print "  ------------------------------------------------------------------------------"
 +
    for part in output.splitlines():
 +
      print "  | %s" % part
 +
    print "  ------------------------------------------------------------------------------"
 +
  if process.returncode:
 +
    raise subprocess.CalledProcessError(command, process.returncode)
 +
  return output.strip()
 +
 
 +
def execute_vtk(command, **kwargs):
 +
  return execute("cd VTK && %s" % command, **kwargs)
 +
 
 +
def check(text):
 +
  if raw_input("\n> %s : (y/n) : " % text) != 'y':
 +
    raise UserCancelled()
 +
 
 +
#def merge_paraview_topic(name):
 +
#  execute("git log --oneline --decorate --graph origin/master..stage/%s" % name)
 +
#  check("Merge %s into ParaView?" % name)
 +
#  execute("ssh git@paraview.org stage ParaView merge -b master %s" % name)
 +
#
 +
#def merge_paraview_vtk_topic(name):
 +
#  execute("cd VTK && git log --oneline --decorate --graph pvvtk/pv-master..pvvtk/%s" % name)
 +
#  check("Merge %s into PVVTK?" % name)
 +
#  execute("ssh git@paraview.org stage PVVTK merge -b pv-master %s" % name)
 +
#  merge_paraview_topic(name)
 +
 
 +
def git_reachable(shaA, shaB):
 +
  "Returns true when shaB is reachable from shaA i.e. shaA is ancestor of shaB"
 +
  # based on logic from:
 +
  # http://stackoverflow.com/a/3006203
 +
  merge_base = execute("git merge-base %s %s" % (shaB, shaA), no_echo=True)
 +
  rev_parse = execute("git rev-parse --verify %s" % shaA, no_echo=True)
 +
  return merge_base == rev_parse
 +
 
 +
def git_vtk_reachable(shaA, shaB):
 +
  "Returns true when shaB is reachable from shaA i.e. shaA is ancestor of shaB"
 +
  # based on logic from:
 +
  # http://stackoverflow.com/a/3006203
 +
  merge_base = execute_vtk("git merge-base %s %s" % (shaB, shaA), no_echo=True)
 +
  rev_parse = execute_vtk("git rev-parse --verify %s" % shaA, no_echo=True)
 +
  return merge_base == rev_parse
 +
 
 +
def interactive_merge(topic, vtk_sha):
 +
  """Merge a ParaView topic interactively."""
 +
  print "--------------------------------------------------"
 +
  print "Topic:", topic
 +
  execute("git log --oneline --decorate --graph origin/master..stage/%s" % topic)
 +
  try:
 +
    if vtk_sha:
 +
      check("Merge '%s' into ParaView (+VTK)?" % topic)
 +
    else:
 +
      check("Merge '%s' into ParaView?" % topic)
 +
  except UserCancelled as e:
 +
    print " ", e, ", skipping..."
 +
    return False
 +
  if vtk_sha:
 +
    # this topic has a VTK change. Locate the VTK topic that brings in this
 +
    # change. Because people never name the two topic the same, we have to do
 +
    # some extra juggling here.
 +
 
 +
    # find all topics on pvvtk that this vtk_sha is available in.
 +
    vtk_topics = execute_vtk("git branch --contains=%s -r | grep pvvtk | sed -e 's|pvvtk/||' | sort" % vtk_sha, no_echo=True)
 +
    vtk_topics = vtk_topics.split()
 +
    if not "master" in vtk_topics:
 +
      raise RuntimeError, "VTK topic not merged into vtk-master. Cannot proceed with the merge."
 +
    vtk_topics.remove("master")
 +
    vtk_topics.remove("pv-next")
 +
    try:
 +
      vtk_topics.remove("pv-master")
 +
    except ValueError:
 +
      pass
 +
    try:
 +
      vtk_topics.remove("nightly-pv-next")
 +
    except ValueError:
 +
      pass
 +
 
 +
    if len(vtk_topics) > 1:
 +
      # ask the user which topic to merge.
 +
      print "  Possible VTK topics for SHA-1 ", vtk_sha
 +
      for index,vtk_topic in enumerate(vtk_topics):
 +
        print " ", index,":", vtk_topic
 +
      choice = int(raw_input("  Pick VTK Topic (0-%d): " % (len(vtk_topics)-1)))
 +
      if choice >= 0 and choice < len(vtk_topics):
 +
        # narrow down the available topics to the one chosen by the user.
 +
        vtk_topics = [vtk_topics[choice]]
 +
      else:
 +
        raise RuntimeError, "Invalid VTK topic chosen %d" % choice
 +
    elif len(vtk_topics) == 1:
 +
      try:
 +
        check(" - Merge vtk_topic '%s'" % vtk_topics[0])
 +
      except UserCancelled:
 +
        return False
 +
 
 +
    # at this point vtk_topics must have only 1 topic of interest.
 +
    if len(vtk_topics) != 1:
 +
      raise RuntimeError, "No VTK topic found/picked for ", vtk_sha
 +
    # warn the user if the vtk_topic has more commits than the one the ParaView topic refers to.
 +
    vtk_topic_head_sha = execute_vtk("git show --raw pvvtk/%s | head -n1 | sed -e 's|commit ||'" % vtk_topics[0], no_echo=True)
 +
    if vtk_topic_head_sha != vtk_sha:
 +
      print "WARNING: VTK topic '%s' has more commits than those refered by ParaView topic" % vtk_topics[0]
 +
      try:
 +
        check("Are you sure you want to merge it?")
 +
      except UserCancelled as e:
 +
        print " ", e, ", skipping..."
 +
        return False
 +
    execute("ssh git@paraview.org stage PVVTK merge -b pv-master %s" % vtk_topics[0])
 +
  execute("ssh git@paraview.org stage ParaView merge -b master %s" % topic)
 +
  print "Merge successful!!!"
 +
  return True
 +
 
 +
#------------------------------------------------------------------------------
 +
print """
 +
                      (                                           
 +
                      )\ )                                       
 +
                    (()/(    )  (      )  )  (    (  (  (   
 +
                      /(_))( /(  )(  ( /(  /((  )\  ))\  )\))( 
 +
                    (_))  )(_))(()\  )(_))(_))\((_) /((_)((_)()\ 
 +
                    | _ \((_)_  ((_)((_)_ _)((_)(_)(_))  _(()((_)
 +
                    |  _// _` || '_|/ _` |\ V / | |/ -_) \ V  V /
 +
                    |_|  \__,_||_|  \__,_| \_/  |_|\___|  \_/\_/  """
 +
print """
 +
  _____      _      _                              _____            _             
 +
  / ____|    | |    | |                            |  __ \          (_)             
 +
| |  __  __ _| |_ ___| | _____  ___ _ __  ___ _ __  | |__) |_____  ___  _____      __
 +
| | |_ |/ _` | __/ _ | |/ / _ \/ _ | '_ \ / _ | '__| |  _  // _ \ \ / | |/ _ \ \ /\ / /
 +
| |__| | (_| | ||  __|  |  __|  __| |_) |  __| |    | | \ |  __/\ V /| |  __/\ V  V /
 +
  \_____|\__,_|\__\___|_|\_\___|\___| .__/ \___|_|    |_|  \_\___| \_/ |_|\___| \_/\_/ 
 +
                                    | |                                               
 +
                                    |_|                                               
 +
"""
 +
 
 +
print"""                  **** LOCAL CHANGES MAY BE OVERWRITTEN !!! **** """
 +
print"""                  **** LOCAL CHANGES MAY BE OVERWRITTEN !!! **** """
 +
print"""                  **** LOCAL CHANGES MAY BE OVERWRITTEN !!! **** """
 +
print"""                  **** LOCAL CHANGES MAY BE OVERWRITTEN !!! **** \n\n"""
 +
 
 +
#------------------------------------------------------------------------------
 +
print "Preparing repository for Gatekeeper Review..."
 +
# Ensure all "core" remotes are up-to-date.
 +
execute("git fetch origin -p")
 +
execute("git fetch stage -p")
 +
execute_vtk("git fetch origin -p")
 +
execute_vtk("git fetch pvvtk -p")
 +
 
 +
#------------------------------------------------------------------------------
 +
# Locate all topics merged into next that are currently on stage.
 +
topics = execute("git branch -r --merged origin/nightly-next | grep stage | sed -e 's|stage/||' | sort", no_echo=True)
 +
topics = topics.split()
 +
try:
 +
  topics.remove("master");topics.remove("next")
 +
except ValueError:
 +
  pass
 +
 
 +
#------------------------------------------------------------------------------
 +
# For each topic, determine if is changes VTK.
 +
# A topic changes VTK if the VTK SHA it refers to is not reachable form the
 +
# VTK SHA in master.
 +
master_vtk_ref = execute("git ls-tree origin/master VTK | awk '{print $3}'", no_echo=True)
 +
vtk_topics_map = {}
 +
for topic in topics:
 +
  topic_vtk_ref = execute("git ls-tree stage/%s VTK | awk '{print $3}'" % topic , no_echo=True)
 +
  already_in_master = git_vtk_reachable(topic_vtk_ref, master_vtk_ref)
 +
  if already_in_master:
 +
    vtk_topics_map[topic] = None
 +
  else:
 +
    vtk_topics_map[topic] = topic_vtk_ref
 +
 
 +
#------------------------------------------------------------------------------
 +
# Print some status messages for the human.
 +
print ""
 +
print "---------------------------------------------"
 +
print "Topics in next that can be merged: "
 +
for topic in topics:
 +
  if vtk_topics_map[topic]:
 +
    print "(VTK)  ", topic
 +
  else:
 +
    print "      ", topic
 +
print ""
 +
print ""
 +
 
 +
#------------------------------------------------------------------------------
 +
# Interactively merge the topics.
 +
topics_merged = []
 +
for topic in topics:
 +
  if interactive_merge(topic, vtk_topics_map[topic]):
 +
    topics_merged.append(topic)
 +
 
 +
#------------------------------------------------------------------------------
 +
check("Wrapup gatekeeper review?")
 +
execute("git fetch origin -p")
 +
execute("git fetch stage -p")
 +
execute_vtk("git fetch origin -p")
 +
execute_vtk("git fetch pvvtk -p")
 +
 
 +
# merge pvvtk/pv-master into origin/master
 +
execute_vtk("git checkout -f origin/master")
 +
execute_vtk("git merge --no-ff pvvtk/pv-master")
 +
execute_vtk("git push gerrit HEAD:master")
 +
 
 +
# reset pv-next.
 +
execute_vtk("git checkout -f pvvtk/pv-master")
 +
# dfff5bee7e6dd05e3b763dde829841766679056d is the pv-next deny commit.
 +
execute_vtk("git merge --no-ff dfff5bee7e6dd05e3b763dde829841766679056d -m 'Merge pv-master into pv-next'")
 +
execute_vtk("git push -f pvvtk HEAD:pv-next")
 +
 
 +
# reset next.
 +
# first get the list of topics merged in next that will get unmerged.
 +
dangling_topics = execute("git branch -r --merged stage/next | grep stage | sed -e 's|stage/||' | sort", no_echo=True)
 +
dangling_topics = dangling_topics.split()
 +
try:
 +
  dangling_topics.remove("master")
 +
except ValueError:
 +
  pass
 +
try:
 +
  dangling_topics.remove("next")
 +
except ValueError:
 +
  pass
 +
execute("git checkout -f origin/master")
 +
execute("git merge --no-ff aa525d5d662ea6c7036e47a07e4c8a146a773e5f -m 'Merge master into next'")
 +
execute("git push -f origin HEAD:next")
 +
 
 +
print ""
 +
print ""
 +
print "SUMMARY"
 +
 
 +
print "---------------------------------------------"
 +
print "Topics merged into master: "
 +
for topic in topics_merged:
 +
  if vtk_topics_map[topic]:
 +
    print "(VTK)  ", topic
 +
  else:
 +
    print "      ", topic
 +
print ""
 +
print ""
 +
print "---------------------------------------------"
 +
print "Topics reverted from next: "
 +
for topic in dangling_topics:
 +
  print " ", topic
 +
</source>
  
 
==Miscellaneous Commands==
 
==Miscellaneous Commands==

Latest revision as of 14:26, 28 September 2012


This page documents how to maintain ParaView branches through Git. See our table of contents for more information.

Merging next topics into master

Before you begin, perform initial setup:

1.

2.

$ git clone --recursive git://paraview.org/ParaView.git

3.

$ ./Utilities/SetupForDevelopment.sh

Gatekeeper Review Script

Script used for weekly ParaView Gatekeeper Review.

#!/usr/bin/env python
import subprocess
import sys
import re
 
#------------------------------------------------------------------------------
class UserCancelled(Exception):
  def __str__(self):
    return "Cancelled by user"
 
pv_only = re.compile("^\\s*([a-zA-Z0-9_-]+)\\s*\|?\\s*$");
pv_and_vtk = re.compile("^\\s*([a-zA-Z0-9_-]+)\\s*|\\s*VTK\\s*$");
 
def execute(command, **kwargs):
  no_echo = kwargs.get("no_echo")
  if not no_echo:
    print "> %s" % command
  process = subprocess.Popen(command, shell=True,
                             stdout=subprocess.PIPE,
                             stderr=subprocess.STDOUT)
  output,_ =  process.communicate()
  if output and not no_echo:
    print "  ------------------------------------------------------------------------------"
    for part in output.splitlines():
      print "  | %s" % part
    print "  ------------------------------------------------------------------------------"
  if process.returncode:
    raise subprocess.CalledProcessError(command, process.returncode)
  return output.strip()
 
def execute_vtk(command, **kwargs):
  return execute("cd VTK && %s" % command, **kwargs)
 
def check(text):
  if raw_input("\n> %s : (y/n) : " % text) != 'y':
    raise UserCancelled()
 
#def merge_paraview_topic(name):
#  execute("git log --oneline --decorate --graph origin/master..stage/%s" % name)
#  check("Merge %s into ParaView?" % name)
#  execute("ssh git@paraview.org stage ParaView merge -b master %s" % name)
#
#def merge_paraview_vtk_topic(name):
#  execute("cd VTK && git log --oneline --decorate --graph pvvtk/pv-master..pvvtk/%s" % name)
#  check("Merge %s into PVVTK?" % name)
#  execute("ssh git@paraview.org stage PVVTK merge -b pv-master %s" % name)
#  merge_paraview_topic(name)
 
def git_reachable(shaA, shaB):
  "Returns true when shaB is reachable from shaA i.e. shaA is ancestor of shaB"
  # based on logic from:
  # http://stackoverflow.com/a/3006203
  merge_base = execute("git merge-base %s %s" % (shaB, shaA), no_echo=True)
  rev_parse = execute("git rev-parse --verify %s" % shaA, no_echo=True)
  return merge_base == rev_parse
 
def git_vtk_reachable(shaA, shaB):
  "Returns true when shaB is reachable from shaA i.e. shaA is ancestor of shaB"
  # based on logic from:
  # http://stackoverflow.com/a/3006203
  merge_base = execute_vtk("git merge-base %s %s" % (shaB, shaA), no_echo=True)
  rev_parse = execute_vtk("git rev-parse --verify %s" % shaA, no_echo=True)
  return merge_base == rev_parse
 
def interactive_merge(topic, vtk_sha):
  """Merge a ParaView topic interactively."""
  print "--------------------------------------------------"
  print "Topic:", topic
  execute("git log --oneline --decorate --graph origin/master..stage/%s" % topic)
  try:
    if vtk_sha:
      check("Merge '%s' into ParaView (+VTK)?" % topic)
    else:
      check("Merge '%s' into ParaView?" % topic)
  except UserCancelled as e:
    print " ", e, ", skipping..."
    return False
  if vtk_sha:
    # this topic has a VTK change. Locate the VTK topic that brings in this
    # change. Because people never name the two topic the same, we have to do
    # some extra juggling here.
 
    # find all topics on pvvtk that this vtk_sha is available in.
    vtk_topics = execute_vtk("git branch --contains=%s -r | grep pvvtk | sed -e 's|pvvtk/||' | sort" % vtk_sha, no_echo=True)
    vtk_topics = vtk_topics.split()
    if not "master" in vtk_topics:
      raise RuntimeError, "VTK topic not merged into vtk-master. Cannot proceed with the merge."
    vtk_topics.remove("master")
    vtk_topics.remove("pv-next")
    try:
      vtk_topics.remove("pv-master")
    except ValueError:
      pass
    try:
      vtk_topics.remove("nightly-pv-next")
    except ValueError:
      pass
 
    if len(vtk_topics) > 1:
      # ask the user which topic to merge.
      print "  Possible VTK topics for SHA-1 ", vtk_sha
      for index,vtk_topic in enumerate(vtk_topics):
        print " ", index,":", vtk_topic
      choice = int(raw_input("  Pick VTK Topic (0-%d): " % (len(vtk_topics)-1)))
      if choice >= 0 and choice < len(vtk_topics):
        # narrow down the available topics to the one chosen by the user.
        vtk_topics = [vtk_topics[choice]]
      else:
        raise RuntimeError, "Invalid VTK topic chosen %d" % choice
    elif len(vtk_topics) == 1:
      try:
        check(" - Merge vtk_topic '%s'" % vtk_topics[0])
      except UserCancelled:
        return False
 
    # at this point vtk_topics must have only 1 topic of interest.
    if len(vtk_topics) != 1:
      raise RuntimeError, "No VTK topic found/picked for ", vtk_sha
    # warn the user if the vtk_topic has more commits than the one the ParaView topic refers to.
    vtk_topic_head_sha = execute_vtk("git show --raw pvvtk/%s | head -n1 | sed -e 's|commit ||'" % vtk_topics[0], no_echo=True)
    if vtk_topic_head_sha != vtk_sha:
      print "WARNING: VTK topic '%s' has more commits than those refered by ParaView topic" % vtk_topics[0]
      try:
        check("Are you sure you want to merge it?")
      except UserCancelled as e:
        print " ", e, ", skipping..."
        return False
    execute("ssh git@paraview.org stage PVVTK merge -b pv-master %s" % vtk_topics[0])
  execute("ssh git@paraview.org stage ParaView merge -b master %s" % topic)
  print "Merge successful!!!"
  return True
 
#------------------------------------------------------------------------------
print """
                      (                                            
                      )\ )                                         
                     (()/(    )  (       )   )   (     (   (  (    
                      /(_))( /(  )(   ( /(  /((  )\   ))\  )\))(   
                     (_))  )(_))(()\  )(_))(_))\((_) /((_)((_)()\  
                     | _ \((_)_  ((_)((_)_ _)((_)(_)(_))  _(()((_) 
                     |  _// _` || '_|/ _` |\ V / | |/ -_) \ V  V / 
                     |_|  \__,_||_|  \__,_| \_/  |_|\___|  \_/\_/  """
print """
   _____       _       _                               _____            _               
  / ____|     | |     | |                             |  __ \          (_)              
 | |  __  __ _| |_ ___| | _____  ___ _ __   ___ _ __  | |__) |_____   ___  _____      __
 | | |_ |/ _` | __/ _ | |/ / _ \/ _ | '_ \ / _ | '__| |  _  // _ \ \ / | |/ _ \ \ /\ / /
 | |__| | (_| | ||  __|   |  __|  __| |_) |  __| |    | | \ |  __/\ V /| |  __/\ V  V / 
  \_____|\__,_|\__\___|_|\_\___|\___| .__/ \___|_|    |_|  \_\___| \_/ |_|\___| \_/\_/  
                                    | |                                                 
                                    |_|                                                 
"""
 
print"""                   **** LOCAL CHANGES MAY BE OVERWRITTEN !!! **** """
print"""                   **** LOCAL CHANGES MAY BE OVERWRITTEN !!! **** """
print"""                   **** LOCAL CHANGES MAY BE OVERWRITTEN !!! **** """
print"""                   **** LOCAL CHANGES MAY BE OVERWRITTEN !!! **** \n\n"""
 
#------------------------------------------------------------------------------
print "Preparing repository for Gatekeeper Review..."
# Ensure all "core" remotes are up-to-date.
execute("git fetch origin -p")
execute("git fetch stage -p")
execute_vtk("git fetch origin -p")
execute_vtk("git fetch pvvtk -p")
 
#------------------------------------------------------------------------------
# Locate all topics merged into next that are currently on stage.
topics = execute("git branch -r --merged origin/nightly-next | grep stage | sed -e 's|stage/||' | sort", no_echo=True)
topics = topics.split()
try:
  topics.remove("master");topics.remove("next")
except ValueError:
  pass
 
#------------------------------------------------------------------------------
# For each topic, determine if is changes VTK.
# A topic changes VTK if the VTK SHA it refers to is not reachable form the
# VTK SHA in master.
master_vtk_ref = execute("git ls-tree origin/master VTK | awk '{print $3}'", no_echo=True)
vtk_topics_map = {}
for topic in topics:
  topic_vtk_ref = execute("git ls-tree stage/%s VTK | awk '{print $3}'" % topic , no_echo=True)
  already_in_master = git_vtk_reachable(topic_vtk_ref, master_vtk_ref)
  if already_in_master:
    vtk_topics_map[topic] = None
  else:
    vtk_topics_map[topic] = topic_vtk_ref
 
#------------------------------------------------------------------------------
# Print some status messages for the human.
print ""
print "---------------------------------------------"
print "Topics in next that can be merged: "
for topic in topics:
  if vtk_topics_map[topic]:
    print "(VTK)  ", topic
  else:
    print "       ", topic
print ""
print ""
 
#------------------------------------------------------------------------------
# Interactively merge the topics.
topics_merged = []
for topic in topics:
  if interactive_merge(topic, vtk_topics_map[topic]):
    topics_merged.append(topic)
 
#------------------------------------------------------------------------------
check("Wrapup gatekeeper review?")
execute("git fetch origin -p")
execute("git fetch stage -p")
execute_vtk("git fetch origin -p")
execute_vtk("git fetch pvvtk -p")
 
# merge pvvtk/pv-master into origin/master
execute_vtk("git checkout -f origin/master")
execute_vtk("git merge --no-ff pvvtk/pv-master")
execute_vtk("git push gerrit HEAD:master")
 
# reset pv-next.
execute_vtk("git checkout -f pvvtk/pv-master")
# dfff5bee7e6dd05e3b763dde829841766679056d is the pv-next deny commit.
execute_vtk("git merge --no-ff dfff5bee7e6dd05e3b763dde829841766679056d -m 'Merge pv-master into pv-next'")
execute_vtk("git push -f pvvtk HEAD:pv-next")
 
# reset next.
# first get the list of topics merged in next that will get unmerged.
dangling_topics = execute("git branch -r --merged stage/next | grep stage | sed -e 's|stage/||' | sort", no_echo=True)
dangling_topics = dangling_topics.split()
try:
  dangling_topics.remove("master") 
except ValueError:
  pass
try:
  dangling_topics.remove("next") 
except ValueError:
  pass
execute("git checkout -f origin/master")
execute("git merge --no-ff aa525d5d662ea6c7036e47a07e4c8a146a773e5f -m 'Merge master into next'")
execute("git push -f origin HEAD:next")
 
print ""
print ""
print "SUMMARY"
 
print "---------------------------------------------"
print "Topics merged into master: "
for topic in topics_merged:
  if vtk_topics_map[topic]:
    print "(VTK)  ", topic
  else:
    print "       ", topic
print ""
print ""
print "---------------------------------------------"
print "Topics reverted from next: "
for topic in dangling_topics:
  print " ", topic

Miscellaneous Commands

  • Show branches merged in next or master on stage
$ git fetch stage -p
$ git branch -r --merged stage/next | grep stage
$ git branch -r --merged stage/master | grep stage
  • Find the SHA1 for the VTK submodule that a branch is referring to.
$ git ls-tree <branchname> VTK | awk '{print $3}'