Make mark-merge-base cap the marked merge base at the real merge-base.

R=agable@chromium.org
BUG=

Review URL: https://codereview.chromium.org/212213004

git-svn-id: svn://svn.chromium.org/chrome/trunk/tools/depot_tools@259697 0039d316-1c4b-4281-b951-d872f2087c98
diff --git a/git_common.py b/git_common.py
index 80398ba..e164ba9 100644
--- a/git_common.py
+++ b/git_common.py
@@ -245,6 +245,15 @@
     yield line.split()[-1]
 
 
+def run_with_retcode(*cmd, **kwargs):
+  """Run a command but only return the status code."""
+  try:
+    run(*cmd, **kwargs)
+    return 0
+  except subprocess2.CalledProcessError as cpe:
+    return cpe.returncode
+
+
 def config(option, default=None):
   try:
     return run('config', '--get', option) or default
@@ -322,16 +331,24 @@
   If parent is supplied, it's used instead of calling upstream(branch).
   """
   base = branch_config(branch, 'base')
+  parent = parent or upstream(branch)
+  actual_merge_base = run('merge-base', parent, branch)
+
+  def is_ancestor(a, b):
+    return run_with_retcode('merge-base', '--is-ancestor', a, b) == 0
+
   if base:
-    try:
-      run('merge-base', '--is-ancestor', base, branch)
-      logging.debug('Found pre-set merge-base for %s: %s', branch, base)
-    except subprocess2.CalledProcessError:
+    if not is_ancestor(base, branch):
       logging.debug('Found WRONG pre-set merge-base for %s: %s', branch, base)
       base = None
+    elif is_ancestor(base, actual_merge_base):
+      logging.debug('Found OLD pre-set merge-base for %s: %s', branch, base)
+      base = None
+    else:
+      logging.debug('Found pre-set merge-base for %s: %s', branch, base)
 
   if not base:
-    base = run('merge-base', parent or upstream(branch), branch)
+    base = actual_merge_base
     manual_merge_base(branch, base)
 
   return base
diff --git a/tests/git_common_test.py b/tests/git_common_test.py
index 940b565..39d2ecb 100755
--- a/tests/git_common_test.py
+++ b/tests/git_common_test.py
@@ -436,6 +436,14 @@
 
     self.assertEqual({}, self.repo.run(self.gc.branch_config_map, 'base'))
 
+    # if it's too old, then it caps at merge-base
+    self.repo.run(self.gc.manual_merge_base, 'branch_K', self.repo['A'])
+
+    self.assertEqual(
+      self.repo['B'],
+      self.repo.run(self.gc.get_or_create_merge_base, 'branch_K', 'branch_G')
+    )
+
   def testGetBranchTree(self):
     skipped, tree = self.repo.run(self.gc.get_branch_tree)
     self.assertEqual(skipped, {'master', 'root_X'})