[git-rebase-update] Disallow `git gc` during git-rebase-update.

In theory this should prevent `git rebase-update` from invoking
potentially expensive `git gc` operations after every `git rebase`
(ideally once per branch, but sometimes as many as three per branch (!)).

This has outsized effects as the size of the repo or number of branches
increases, and additionally has penalties on Windows due to git's
POSIXey assumptions around how disk I/O works.

After doing all rebase stuff, we run `git gc --auto` from rebase-update
once (assuming we were successful; if the command failed then we don't
run gc at all).

R=apolito@google.com

Bug: 617218
Change-Id: I37a8f7953779f15b320e4ed7bb85119cb4bb665a
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/tools/depot_tools/+/2868766
Auto-Submit: Robbie Iannucci <iannucci@chromium.org>
Reviewed-by: Anthony Polito <apolito@google.com>
Commit-Queue: Robbie Iannucci <iannucci@chromium.org>
diff --git a/git_common.py b/git_common.py
index 523f628..d70bdfb 100644
--- a/git_common.py
+++ b/git_common.py
@@ -641,15 +641,22 @@
 RebaseRet = collections.namedtuple('RebaseRet', 'success stdout stderr')
 
 
-def rebase(parent, start, branch, abort=False):
+def rebase(parent, start, branch, abort=False, allow_gc=False):
   """Rebases |start|..|branch| onto the branch |parent|.
 
+  Sets 'gc.auto=0' for the duration of this call to prevent the rebase from
+  running a potentially slow garbage collection cycle.
+
   Args:
     parent - The new parent ref for the rebased commits.
     start  - The commit to start from
     branch - The branch to rebase
     abort  - If True, will call git-rebase --abort in the event that the rebase
              doesn't complete successfully.
+    allow_gc - If True, sets "-c gc.auto=1" on the rebase call, rather than
+               "-c gc.auto=0". Usually if you're doing a series of rebases,
+               you'll only want to run a single gc pass at the end of all the
+               rebase activity.
 
   Returns a namedtuple with fields:
     success - a boolean indicating that the rebase command completed
@@ -658,10 +665,16 @@
               rebase.
   """
   try:
-    args = ['--onto', parent, start, branch]
+    args = [
+      '-c', 'gc.auto={}'.format('1' if allow_gc else '0'),
+      'rebase',
+    ]
     if TEST_MODE:
-      args.insert(0, '--committer-date-is-author-date')
-    run('rebase', *args)
+      args.append('--committer-date-is-author-date')
+    args += [
+      '--onto', parent, start, branch,
+    ]
+    run(*args)
     return RebaseRet(True, '', '')
   except subprocess2.CalledProcessError as cpe:
     if abort:
@@ -1064,7 +1077,7 @@
     behind = int(behind_match.group(1)) if behind_match else None
 
     info_map[branch] = BranchesInfo(
-        hash=branch_hash, upstream=upstream_branch, commits=commits, 
+        hash=branch_hash, upstream=upstream_branch, commits=commits,
         behind=behind)
 
   # Set None for upstreams which are not branches (e.g empty upstream, remotes