Add additional check for PS parents

When updating with external changes, depot_tools applies diff between
patchsets. It's not sufficient to just check local `base` commit with
the latest remote since both could be updated (e.g. via rebase-update
and Gerrit rebase).

R=gavinmak@google.com, jojwang@google.com

Bug: 1448243
Change-Id: Ib92d2f3958de15090a261c810ad19bdf085219a0
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/tools/depot_tools/+/4559308
Reviewed-by: Joanna Wang <jojwang@chromium.org>
Reviewed-by: Gavin Mak <gavinmak@google.com>
Commit-Queue: Josip Sokcevic <sokcevic@chromium.org>
diff --git a/git_cl.py b/git_cl.py
index ab6ad73..1afa709 100755
--- a/git_cl.py
+++ b/git_cl.py
@@ -2991,18 +2991,45 @@
         return
       print('No upstream branch set. Continuing upload with Gerrit merge base.')
 
+    external_parent_last_uploaded = self._GetChangeCommit(
+        revision=local_ps)['parents'][0]
+    external_base_last_uploaded = external_parent_last_uploaded['commit']
+
+    if external_base != external_base_last_uploaded:
+      print('\nPatch set merge bases are different (%s, %s).\n' %
+            (external_base_last_uploaded, external_base))
+      confirm_or_exit('Can\'t apply the latest changes from Gerrit.\n'
+                      'Continue with upload and override the latest changes?')
+      return
+
     # Fetch Gerrit's CL base if it doesn't exist locally.
     remote, _ = self.GetRemoteBranch()
     if not scm.GIT.IsValidRevision(settings.GetRoot(), external_base):
       RunGitSilent(['fetch', remote, external_base])
 
     # Get the diff between local_ps and external_ps.
+    print('Fetching changes...')
     issue = self.GetIssue()
     changes_ref = 'refs/changes/%02d/%d/' % (issue % 100, issue)
     RunGitSilent(['fetch', remote, changes_ref + str(local_ps)])
     last_uploaded = RunGitSilent(['rev-parse', 'FETCH_HEAD']).strip()
     RunGitSilent(['fetch', remote, changes_ref + str(external_ps)])
     latest_external = RunGitSilent(['rev-parse', 'FETCH_HEAD']).strip()
+
+    # If the commit parents are different, don't apply the diff as it very
+    # likely contains many more changes not relevant to this CL.
+    parents = RunGitSilent(
+        ['rev-parse',
+         '%s~1' % (last_uploaded),
+         '%s~1' % (latest_external)]).strip().split()
+    assert len(parents) == 2, 'Expected two parents.'
+    if parents[0] != parents[1]:
+      confirm_or_exit(
+          'Can\'t apply the latest changes from Gerrit (parent mismatch '
+          'between PS).\n'
+          'Continue with upload and override the latest changes?')
+      return
+
     diff = RunGitSilent(['diff', '%s..%s' % (last_uploaded, latest_external)])
 
     # Diff can be empty in the case of trivial rebases.