fetch-and-push-remote: Extend sync parameters

* --source-fetch-all: Sync with `--current-branch` seems to be not
  always optimal when reusing one workspace for syncing different source
  trees. Allow fetching everything instead, it's expensive once but
  should speed up later sync jobs.
* --fetch-target-before-push: When pushing refs that are not known to
  the target Gerrit, but actually share significant history with other
  refs, then it fetching first speeds up the push a lot. On server side,
  pushing is much more expensive than fetching, and we don't want to
  block our shared Gerrits unnecessarily.

Change-Id: I9af3db2cd10a4dfd5027851d0346b02034b187b9
diff --git a/bin/fetch-and-push-remote b/bin/fetch-and-push-remote
index 9d3bbef..bcab729 100755
--- a/bin/fetch-and-push-remote
+++ b/bin/fetch-and-push-remote
@@ -40,6 +40,7 @@
 # Default values for internal parameters
 CREATE_PROJECTS=
 EXCLUDE_PROJECTS=
+FETCH_TARGET_BEFORE_PUSH=false
 INIT_AS_MIRROR=false
 MANIFEST=
 MANIFEST_BRANCH=
@@ -57,6 +58,7 @@
 REPO_SYNC_FORCE_SYNC=
 REPO_URL=
 SKIP_INIT=
+SOURCE_FETCH_ALL=false
 TARGET_BRANCH=
 
 _usage() {
@@ -181,6 +183,10 @@
 --force-sync                    : Pass "--force-sync" to repo sync, overwriting
                                   local git directories that need to point to a
                                   difference repo object directory.
+--source-fetch-all              : Fetch all branches from the source Gerrit. By
+                                  Default, --current-branch is set on repo sync.
+--fetch-target-before-push      : Fetch from the target Gerrit before push. Can
+                                  help speeding up pushing large projects.
 -j, --jobs                      : Number of jobs for repo sync and forall. Use
                                   this to speed up overall job execution. This
                                   can make logs unusable, so it's on 1 by
@@ -260,13 +266,17 @@
     if [ "${REPO_SYNC_FORCE_SYNC}" = true ]; then
         sync_params+=(--force-sync)
     fi
+    if [ "${SOURCE_FETCH_ALL}" = true ]; then
+        sync_params+=(--no-current-branch)
+    else
+        sync_params+=(--current-branch --no-tags)
+    fi
 
     log_bold "Repo init:"
     repo init "${init_params[@]}"
 
     log_bold "Repo sync:"
-    repo sync "${sync_params[@]}" --current-branch --detach --no-tags \
-        "${REPO_PROJECTS[@]}"
+    repo sync "${sync_params[@]}" --detach "${REPO_PROJECTS[@]}"
 }
 
 # Add target remote and create new remote projects if needed.
@@ -291,6 +301,10 @@
     fi
 
     repo_forall "add_git_remote; ${create_projects_cmd}"
+
+    if [ "${FETCH_TARGET_BEFORE_PUSH}" = true ]; then
+        repo_forall "git fetch \"${TARGET_GERRIT_NAME}\""
+    fi
 }
 
 
@@ -666,6 +680,14 @@
             REPO_SYNC_FORCE_SYNC=true
             shift 1
             ;;
+        --source-fetch-all)
+            SOURCE_FETCH_ALL=true
+            shift 1
+            ;;
+        --fetch-target-before-push)
+            FETCH_TARGET_BEFORE_PUSH=true
+            shift 1
+            ;;
         -j|--jobs)
             if [ $# -lt 2 ]; then
                 _usage >&2
@@ -695,7 +717,7 @@
 if [ ! -f "${repo_forall_functions}" ] ; then
     log_e "Unable to find repo-forall-functions.sh"
 fi
-repo_forall_args=(--abort-on-errors --verbose "${REPO_PROJECTS[@]}")
+repo_forall_args=(--abort-on-errors --verbose -p "${REPO_PROJECTS[@]}")
 if [ -n "${MANIFEST_GROUPS}" ]; then
     repo_forall_args+=("--groups=${MANIFEST_GROUPS}")
 fi