gclient: don't update cache if needed revision is already there.

Tested end-to-end, for example
  https://ci.chromium.org/swarming/task/3a0147207378b910
which contains:
  src/media/cdm/api (Elapsed: 0:00:01)
  ----------------------------------------
  [0:00:00] Started.
  _____ src\media\cdm\api at ea5df8e78fbd0a4c24cc3a1f3faefefcd1b45237
  [0:00:00] running "git cat-file -e ea5df8e78fbd0a4c24cc3a1f3faefefcd1b45237" in "e:\b\s\w\ir\cache\git\chromium.googlesource.com-chromium-cdm"
  skipping mirror update, it has rev=ea5df8e78fbd0a4c24cc3a1f3faefefcd1b45237 already

thereby saving on needless git fetch (~40s in glcient sync on win trybots),
and reducing the rate of .pack file accumulation inside cache directories.


Risks: silently broken recipes which run gclient sync (or worse, bot_update)
as a means of fetching latest commits in all repos of a solution. I think
the benefit of faster bot_update in chromium CQ is worth the potential risk.

PSA: https://groups.google.com/a/chromium.org/d/msg/infra-dev/UYLdBwAXm1Y/OV9QB6JnBQAJ

Bug: 749709
Change-Id: I7a9e8ab82a5e2b848e450f19a798ac18a0b5e201
Reviewed-on: https://chromium-review.googlesource.com/787331
Commit-Queue: Andrii Shyshkalov <tandrii@chromium.org>
Reviewed-by: Michael Achenbach <machenbach@chromium.org>
diff --git a/git_cache.py b/git_cache.py
index aedac25..01b6842 100755
--- a/git_cache.py
+++ b/git_cache.py
@@ -411,6 +411,24 @@
       return False
     return True
 
+  def contains_revision(self, revision):
+    if not self.exists():
+      return False
+
+    if sys.platform.startswith('win'):
+      # Windows .bat scripts use ^ as escape sequence, which means we have to
+      # escape it with itself for every .bat invocation.
+      needle = '%s^^^^{commit}' % revision
+    else:
+      needle = '%s^{commit}' % revision
+    try:
+      # cat-file exits with 0 on success, that is git object of given hash was
+      # found.
+      self.RunGit(['cat-file', '-e', needle])
+      return True
+    except subprocess.CalledProcessError:
+      return False
+
   def exists(self):
     return os.path.isfile(os.path.join(self.mirror_path, 'config'))