repo_roll: Use git_roll_util rolls

Use fuchsia/git_roll_util Roll objects instead of pigweed/roll_util Roll
objects.

Bug: b/359925419
Change-Id: I3f3b86c3917f426c495b3bf70def4028b9897f79
Reviewed-on: https://pigweed-review.googlesource.com/c/infra/recipes/+/235272
Commit-Queue: Rob Mohr <mohrr@google.com>
Reviewed-by: Ted Pudlik <tpudlik@google.com>
Presubmit-Verified: CQ Bot Account <pigweed-scoped@luci-project-accounts.iam.gserviceaccount.com>
Lint: Lint 🤖 <android-build-ayeaye@system.gserviceaccount.com>
diff --git a/recipe_modules/repo_roll/__init__.py b/recipe_modules/repo_roll/__init__.py
index 2493e40..dca2ad6 100644
--- a/recipe_modules/repo_roll/__init__.py
+++ b/recipe_modules/repo_roll/__init__.py
@@ -17,10 +17,7 @@
 DEPS = [
     'fuchsia/git_roll_util',
     'fuchsia/sso',
-    'pigweed/checkout',
-    'pigweed/roll_util',
     'recipe_engine/buildbucket',
     'recipe_engine/file',
-    'recipe_engine/path',
     'recipe_engine/step',
 ]
diff --git a/recipe_modules/repo_roll/api.py b/recipe_modules/repo_roll/api.py
index 4d1f452..3655f6e 100644
--- a/recipe_modules/repo_roll/api.py
+++ b/recipe_modules/repo_roll/api.py
@@ -30,8 +30,8 @@
 
 if TYPE_CHECKING:  # pragma: no cover
     from recipe_engine import config_types
+    from RECIPE_MODULES.fuchsia.git_roll_util import api as git_roll_util_api
     from RECIPE_MODULES.pigweed.checkout import api as checkout_api
-    from RECIPE_MODULES.pigweed.roll_util import api as roll_util_api
     from PB.recipe_modules.pigweed.repo_roll import Project
 
 
@@ -42,14 +42,6 @@
         self.end(xml.etree.ElementTree.Comment)
 
 
-@dataclasses.dataclass
-class RevisionChange:
-    dir: config_types.Path
-    old: str
-    new: str
-    direction: roll_util_api.Direction
-
-
 class RepoRollApi(recipe_api.RecipeApi):
     """Update an Android Repo Tool project."""
 
@@ -72,7 +64,7 @@
         self,
         checkout: checkout_api.CheckoutContext,
         project: Project,
-    ) -> list[roll_util_api.Roll]:
+    ) -> list[git_roll_util_api.Roll]:
         new_revision = None
 
         # Try to get new_revision from the trigger.
@@ -170,19 +162,6 @@
         else:
             proj_branch = 'main'
 
-        # If we still don't have a revision then it wasn't in the trigger.
-        # (Perhaps this was manually triggered.) In this case we need to
-        # determine the latest revision of this repository. The use_trigger flag
-        # should have no effect but using it to be explicit. Checking out even
-        # if not needed so commit messages can be collected later.
-        proj_dir = self.m.path.start_dir / 'project'
-        proj_checkout = self.m.checkout(
-            CheckoutOptions(
-                remote=manifest_remote, branch=proj_branch, use_trigger=False
-            ),
-            root=proj_dir,
-        )
-
         new_revision = self.m.git_roll_util.resolve_new_revision(
             manifest_remote,
             proj_branch,
@@ -208,16 +187,15 @@
         # confusion.
         proj_attrib['revision'] = proj.attrib['revision'] = new_revision
 
-        direction = self.m.roll_util.Direction.FORWARD
-        if not self.is_branch(old_revision):
-            direction = self.m.roll_util.get_roll_direction(
-                proj_dir, old_revision, new_revision
+        try:
+            roll = self.m.git_roll_util.get_roll(
+                repo_url=manifest_remote,
+                repo_short_name=project.path_to_update,
+                old_rev=old_revision,
+                new_rev=new_revision,
             )
 
-        if not self.m.roll_util.can_roll(direction):
-            self.m.roll_util.skip_roll_step(
-                manifest_remote, old_revision, new_revision
-            )
+        except self.m.git_roll_util.BackwardsRollError:
             return []
 
         self._order_attributes(root)
@@ -230,12 +208,4 @@
             ),
         )
 
-        return [
-            self.m.roll_util.create_roll(
-                project_name=project.path_to_update,
-                old_revision=old_revision,
-                new_revision=new_revision,
-                proj_dir=proj_dir,
-                direction=direction,
-            ),
-        ]
+        return [roll]
diff --git a/recipe_modules/repo_roll/tests/full.expected/backwards.json b/recipe_modules/repo_roll/tests/full.expected/backwards.json
index 91f0db6..a4566dd 100644
--- a/recipe_modules/repo_roll/tests/full.expected/backwards.json
+++ b/recipe_modules/repo_roll/tests/full.expected/backwards.json
@@ -44,529 +44,6 @@
     ]
   },
   {
-    "cmd": [],
-    "name": "checkout a"
-  },
-  {
-    "cmd": [],
-    "name": "checkout a.options",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@",
-      "@@@STEP_SUMMARY_TEXT@remote: \"https://foo.googlesource.com/a\"\nbranch: \"main\"\n@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "checkout a.options with defaults",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@",
-      "@@@STEP_SUMMARY_TEXT@remote: \"https://foo.googlesource.com/a\"\nbranch: \"main\"\nmanifest_file: \"default.xml\"\nrepo_init_timeout_sec: 20\nrepo_sync_timeout_sec: 120\nnumber_of_attempts: 3\nsubmodule_timeout_sec: 600\n@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "checkout a.not matching branch names",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "checkout a.cache",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@",
-      "@@@STEP_SUMMARY_TEXT@miss@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "vpython3",
-      "-u",
-      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
-      "--json-output",
-      "/path/to/tmp/json",
-      "ensure-directory",
-      "--mode",
-      "0o777",
-      "[CACHE]/git"
-    ],
-    "infra_step": true,
-    "name": "checkout a.cache.ensure git cache dir",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "vpython3",
-      "-u",
-      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
-      "--json-output",
-      "/path/to/tmp/json",
-      "copy",
-      "",
-      "[CACHE]/git/.GUARD_FILE"
-    ],
-    "infra_step": true,
-    "name": "checkout a.cache.write git cache guard file",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "vpython3",
-      "-u",
-      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
-      "--json-output",
-      "/path/to/tmp/json",
-      "ensure-directory",
-      "--mode",
-      "0o777",
-      "[CACHE]/git/foo.googlesource.com-a"
-    ],
-    "infra_step": true,
-    "name": "checkout a.cache.makedirs",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "init"
-    ],
-    "cwd": "[CACHE]/git/foo.googlesource.com-a",
-    "infra_step": true,
-    "name": "checkout a.cache.git init",
-    "timeout": 300.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "config",
-      "remote.origin.url",
-      "https://foo.googlesource.com/a"
-    ],
-    "cwd": "[CACHE]/git/foo.googlesource.com-a",
-    "infra_step": true,
-    "name": "checkout a.cache.remote set-url",
-    "timeout": 300.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "config",
-      "fetch.uriprotocols",
-      "https"
-    ],
-    "cwd": "[CACHE]/git/foo.googlesource.com-a",
-    "infra_step": true,
-    "name": "checkout a.cache.set fetch.uriprotocols",
-    "timeout": 300.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "checkout a.cache.timeout 10s",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "fetch",
-      "--prune",
-      "--tags",
-      "--jobs",
-      "4",
-      "origin",
-      "--no-recurse-submodules"
-    ],
-    "cwd": "[CACHE]/git/foo.googlesource.com-a",
-    "infra_step": true,
-    "name": "checkout a.cache.git fetch",
-    "timeout": 1200.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "merge",
-      "FETCH_HEAD"
-    ],
-    "cwd": "[CACHE]/git/foo.googlesource.com-a",
-    "infra_step": true,
-    "name": "checkout a.cache.git merge",
-    "timeout": 600.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "checkout a.cache.timeout 10s (2)",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "submodule",
-      "update",
-      "--recursive",
-      "--force",
-      "--jobs",
-      "4"
-    ],
-    "cwd": "[CACHE]/git/foo.googlesource.com-a",
-    "infra_step": true,
-    "name": "checkout a.cache.git submodule update",
-    "timeout": 600,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "vpython3",
-      "-u",
-      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
-      "--json-output",
-      "/path/to/tmp/json",
-      "remove",
-      "[CACHE]/git/.GUARD_FILE"
-    ],
-    "infra_step": true,
-    "name": "checkout a.cache.remove git cache guard file",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "vpython3",
-      "-u",
-      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
-      "--json-output",
-      "/path/to/tmp/json",
-      "copytree",
-      "--symlinks",
-      "[CACHE]/git/foo.googlesource.com-a",
-      "[START_DIR]/project"
-    ],
-    "infra_step": true,
-    "name": "checkout a.copy from cache",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "checkout a.git checkout",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "checkout a.git checkout.timeout 10s",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "vpython3",
-      "-u",
-      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
-      "--json-output",
-      "/path/to/tmp/json",
-      "ensure-directory",
-      "--mode",
-      "0o777",
-      "[START_DIR]/project"
-    ],
-    "infra_step": true,
-    "luci_context": {
-      "deadline": {
-        "grace_period": 30.0,
-        "soft_deadline": 1337000019.0
-      }
-    },
-    "name": "checkout a.git checkout.makedirs",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "init"
-    ],
-    "cwd": "[START_DIR]/project",
-    "infra_step": true,
-    "name": "checkout a.git checkout.git init",
-    "timeout": 300.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "remote",
-      "add",
-      "origin",
-      "https://foo.googlesource.com/a"
-    ],
-    "cwd": "[START_DIR]/project",
-    "infra_step": true,
-    "name": "checkout a.git checkout.git remote",
-    "timeout": 600.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "config",
-      "core.longpaths",
-      "true"
-    ],
-    "cwd": "[START_DIR]/project",
-    "infra_step": true,
-    "name": "checkout a.git checkout.set core.longpaths",
-    "timeout": 300.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "config",
-      "fetch.uriprotocols",
-      "https"
-    ],
-    "cwd": "[START_DIR]/project",
-    "infra_step": true,
-    "name": "checkout a.git checkout.set fetch.uriprotocols",
-    "timeout": 300.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "fetch",
-      "--tags",
-      "--jobs",
-      "4",
-      "origin",
-      "main"
-    ],
-    "cwd": "[START_DIR]/project",
-    "infra_step": true,
-    "name": "checkout a.git checkout.git fetch",
-    "timeout": 1200.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "checkout",
-      "-f",
-      "FETCH_HEAD"
-    ],
-    "cwd": "[START_DIR]/project",
-    "infra_step": true,
-    "name": "checkout a.git checkout.git checkout",
-    "timeout": 600.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "rev-parse",
-      "HEAD"
-    ],
-    "cwd": "[START_DIR]/project",
-    "infra_step": true,
-    "name": "checkout a.git checkout.git rev-parse",
-    "timeout": 300.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "clean",
-      "-f",
-      "-d",
-      "-x"
-    ],
-    "cwd": "[START_DIR]/project",
-    "infra_step": true,
-    "name": "checkout a.git checkout.git clean",
-    "timeout": 600.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "checkout a.git log",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "log",
-      "--oneline",
-      "-n",
-      "10"
-    ],
-    "cwd": "[START_DIR]/project",
-    "name": "checkout a.git log.[START_DIR]/project",
-    "timeout": 600.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "clean",
-      "-f",
-      "-f",
-      "-d"
-    ],
-    "cwd": "[START_DIR]/project",
-    "name": "checkout a.git clean",
-    "timeout": 600.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "status"
-    ],
-    "cwd": "[START_DIR]/project",
-    "name": "checkout a.git status",
-    "timeout": 600.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "vpython3",
-      "-u",
-      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
-      "--json-output",
-      "/path/to/tmp/json",
-      "ensure-directory",
-      "--mode",
-      "0o777",
-      "[START_DIR]/snapshot"
-    ],
-    "infra_step": true,
-    "name": "checkout a.mkdir",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "submodule",
-      "status",
-      "--recursive"
-    ],
-    "cwd": "[START_DIR]/project",
-    "name": "checkout a.submodule-status",
-    "timeout": 600.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "vpython3",
-      "-u",
-      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
-      "--json-output",
-      "/path/to/tmp/json",
-      "copy",
-      "submodule status filler text",
-      "[START_DIR]/snapshot/submodules.log"
-    ],
-    "infra_step": true,
-    "name": "checkout a.write submodule snapshot",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@",
-      "@@@STEP_LOG_LINE@submodules.log@submodule status filler text@@@",
-      "@@@STEP_LOG_END@submodules.log@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "log",
-      "--oneline",
-      "-n",
-      "10"
-    ],
-    "cwd": "[START_DIR]/project",
-    "name": "checkout a.log",
-    "timeout": 600.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "vpython3",
-      "-u",
-      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
-      "--json-output",
-      "/path/to/tmp/json",
-      "copy",
-      "",
-      "[START_DIR]/snapshot/git.log"
-    ],
-    "infra_step": true,
-    "name": "checkout a.write git log",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@",
-      "@@@STEP_LOG_END@git.log@@@"
-    ]
-  },
-  {
     "cmd": [
       "git",
       "ls-remote",
@@ -583,48 +60,111 @@
   },
   {
     "cmd": [],
-    "name": "get roll direction",
-    "~followup_annotations": [
-      "@@@STEP_SUMMARY_TEXT@backward@@@"
-    ]
+    "name": "ensure infra/tools/luci/gitiles/${platform}"
   },
   {
-    "cmd": [
-      "git",
-      "merge-base",
-      "--is-ancestor",
-      "1111111111111111111111111111111111111111",
-      "h3ll0"
-    ],
-    "cwd": "[START_DIR]/project",
-    "name": "get roll direction.is forward",
-    "timeout": 600.0,
+    "cmd": [],
+    "name": "ensure infra/tools/luci/gitiles/${platform}.get packages",
     "~followup_annotations": [
       "@@@STEP_NEST_LEVEL@1@@@"
     ]
   },
   {
     "cmd": [
-      "git",
-      "merge-base",
-      "--is-ancestor",
-      "h3ll0",
-      "1111111111111111111111111111111111111111"
+      "vpython3",
+      "-u",
+      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
+      "--json-output",
+      "/path/to/tmp/json",
+      "copy",
+      "RECIPE_MODULE[fuchsia::gitiles]/resources/cipd.ensure",
+      "/path/to/tmp/"
     ],
-    "cwd": "[START_DIR]/project",
-    "name": "get roll direction.is backward",
-    "timeout": 600.0,
+    "infra_step": true,
+    "name": "ensure infra/tools/luci/gitiles/${platform}.get packages.read ensure file",
     "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
+      "@@@STEP_NEST_LEVEL@2@@@",
+      "@@@STEP_LOG_LINE@cipd.ensure@infra/tools/luci/gitiles/${platform} version:pinned-version@@@",
+      "@@@STEP_LOG_END@cipd.ensure@@@"
     ]
   },
   {
     "cmd": [],
-    "name": "cancelling roll",
+    "name": "ensure infra/tools/luci/gitiles/${platform}.install infra/tools/luci/gitiles",
     "~followup_annotations": [
-      "@@@STEP_SUMMARY_TEXT@not updating from 1111111 to h3ll0 because 1111111 is newer than h3ll0@@@",
-      "@@@STEP_LINK@1111111111111111111111111111111111111111@https://foo.googlesource.com/a/+/1111111111111111111111111111111111111111@@@",
-      "@@@STEP_LINK@h3ll0@https://foo.googlesource.com/a/+/h3ll0@@@"
+      "@@@STEP_NEST_LEVEL@1@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "vpython3",
+      "-u",
+      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
+      "--json-output",
+      "/path/to/tmp/json",
+      "ensure-directory",
+      "--mode",
+      "0o777",
+      "[START_DIR]/cipd_tool/infra/tools/luci/gitiles/0e548aa33f8113a45a5b3b62201e114e98e63d00f97296912380138f44597b07"
+    ],
+    "infra_step": true,
+    "name": "ensure infra/tools/luci/gitiles/${platform}.install infra/tools/luci/gitiles.ensure package directory",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@2@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "cipd",
+      "ensure",
+      "-root",
+      "[START_DIR]/cipd_tool/infra/tools/luci/gitiles/0e548aa33f8113a45a5b3b62201e114e98e63d00f97296912380138f44597b07",
+      "-ensure-file",
+      "infra/tools/luci/gitiles/${platform} version:pinned-version",
+      "-max-threads",
+      "0",
+      "-json-output",
+      "/path/to/tmp/json"
+    ],
+    "infra_step": true,
+    "name": "ensure infra/tools/luci/gitiles/${platform}.install infra/tools/luci/gitiles.ensure_installed",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@2@@@",
+      "@@@STEP_LOG_LINE@json.output@{@@@",
+      "@@@STEP_LOG_LINE@json.output@  \"result\": {@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"\": [@@@",
+      "@@@STEP_LOG_LINE@json.output@      {@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"instance_id\": \"resolved-instance_id-of-version:pinned-v\",@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"package\": \"infra/tools/luci/gitiles/resolved-platform\"@@@",
+      "@@@STEP_LOG_LINE@json.output@      }@@@",
+      "@@@STEP_LOG_LINE@json.output@    ]@@@",
+      "@@@STEP_LOG_LINE@json.output@  }@@@",
+      "@@@STEP_LOG_LINE@json.output@}@@@",
+      "@@@STEP_LOG_END@json.output@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "[START_DIR]/cipd_tool/infra/tools/luci/gitiles/0e548aa33f8113a45a5b3b62201e114e98e63d00f97296912380138f44597b07/gitiles",
+      "log",
+      "-json-output",
+      "/path/to/tmp/json",
+      "https://foo.googlesource.com/a",
+      "1111111111111111111111111111111111111111..h3ll0"
+    ],
+    "infra_step": true,
+    "name": "log a1",
+    "timeout": 300.0,
+    "~followup_annotations": [
+      "@@@STEP_LOG_LINE@json.output@[]@@@",
+      "@@@STEP_LOG_END@json.output@@@"
+    ]
+  },
+  {
+    "cmd": [],
+    "name": "detected backwards roll",
+    "~followup_annotations": [
+      "@@@STEP_TEXT@Detected backwards roll: expected 1111111 to precede h3ll0 in git history@@@"
     ]
   },
   {
diff --git a/recipe_modules/repo_roll/tests/full.expected/dotdot-prefix.json b/recipe_modules/repo_roll/tests/full.expected/dotdot-prefix.json
index 0184e46..dcb086e 100644
--- a/recipe_modules/repo_roll/tests/full.expected/dotdot-prefix.json
+++ b/recipe_modules/repo_roll/tests/full.expected/dotdot-prefix.json
@@ -57,50 +57,25 @@
   },
   {
     "cmd": [],
-    "name": "checkout g"
+    "name": "ensure infra/tools/luci/gitiles/${platform}"
   },
   {
     "cmd": [],
-    "name": "checkout g.options",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@",
-      "@@@STEP_SUMMARY_TEXT@remote: \"https://host.googlesource.com/prefix/g\"\nbranch: \"main\"\n@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "checkout g.options with defaults",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@",
-      "@@@STEP_SUMMARY_TEXT@remote: \"https://host.googlesource.com/prefix/g\"\nbranch: \"main\"\nmanifest_file: \"default.xml\"\nrepo_init_timeout_sec: 20\nrepo_sync_timeout_sec: 120\nnumber_of_attempts: 3\nsubmodule_timeout_sec: 600\n@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "checkout g.not matching branch names",
+    "name": "ensure infra/tools/luci/gitiles/${platform}.get packages",
     "~followup_annotations": [
       "@@@STEP_NEST_LEVEL@1@@@"
     ]
   },
   {
-    "cmd": [],
-    "name": "checkout g.cache",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@",
-      "@@@STEP_SUMMARY_TEXT@miss@@@"
-    ]
-  },
-  {
     "cmd": [
       "vpython3",
       "-u",
       "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
       "--json-output",
       "/path/to/tmp/json",
-      "ensure-directory",
-      "--mode",
-      "0o777",
-      "[CACHE]/git"
+      "copy",
+      "RECIPE_MODULE[fuchsia::gitiles]/resources/cipd.ensure",
+      "/path/to/tmp/"
     ],
     "infra_step": true,
     "luci_context": {
@@ -115,7 +90,220 @@
         "hostname": "rdbhost"
       }
     },
-    "name": "checkout g.cache.ensure git cache dir",
+    "name": "ensure infra/tools/luci/gitiles/${platform}.get packages.read ensure file",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@2@@@",
+      "@@@STEP_LOG_LINE@cipd.ensure@infra/tools/luci/gitiles/${platform} version:pinned-version@@@",
+      "@@@STEP_LOG_END@cipd.ensure@@@"
+    ]
+  },
+  {
+    "cmd": [],
+    "name": "ensure infra/tools/luci/gitiles/${platform}.install infra/tools/luci/gitiles",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "vpython3",
+      "-u",
+      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
+      "--json-output",
+      "/path/to/tmp/json",
+      "ensure-directory",
+      "--mode",
+      "0o777",
+      "[START_DIR]/cipd_tool/infra/tools/luci/gitiles/0e548aa33f8113a45a5b3b62201e114e98e63d00f97296912380138f44597b07"
+    ],
+    "infra_step": true,
+    "luci_context": {
+      "realm": {
+        "name": "project:ci"
+      },
+      "resultdb": {
+        "current_invocation": {
+          "name": "invocations/build:8945511751514863184",
+          "update_token": "token"
+        },
+        "hostname": "rdbhost"
+      }
+    },
+    "name": "ensure infra/tools/luci/gitiles/${platform}.install infra/tools/luci/gitiles.ensure package directory",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@2@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "cipd",
+      "ensure",
+      "-root",
+      "[START_DIR]/cipd_tool/infra/tools/luci/gitiles/0e548aa33f8113a45a5b3b62201e114e98e63d00f97296912380138f44597b07",
+      "-ensure-file",
+      "infra/tools/luci/gitiles/${platform} version:pinned-version",
+      "-max-threads",
+      "0",
+      "-json-output",
+      "/path/to/tmp/json"
+    ],
+    "infra_step": true,
+    "luci_context": {
+      "realm": {
+        "name": "project:ci"
+      },
+      "resultdb": {
+        "current_invocation": {
+          "name": "invocations/build:8945511751514863184",
+          "update_token": "token"
+        },
+        "hostname": "rdbhost"
+      }
+    },
+    "name": "ensure infra/tools/luci/gitiles/${platform}.install infra/tools/luci/gitiles.ensure_installed",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@2@@@",
+      "@@@STEP_LOG_LINE@json.output@{@@@",
+      "@@@STEP_LOG_LINE@json.output@  \"result\": {@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"\": [@@@",
+      "@@@STEP_LOG_LINE@json.output@      {@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"instance_id\": \"resolved-instance_id-of-version:pinned-v\",@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"package\": \"infra/tools/luci/gitiles/resolved-platform\"@@@",
+      "@@@STEP_LOG_LINE@json.output@      }@@@",
+      "@@@STEP_LOG_LINE@json.output@    ]@@@",
+      "@@@STEP_LOG_LINE@json.output@  }@@@",
+      "@@@STEP_LOG_LINE@json.output@}@@@",
+      "@@@STEP_LOG_END@json.output@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "[START_DIR]/cipd_tool/infra/tools/luci/gitiles/0e548aa33f8113a45a5b3b62201e114e98e63d00f97296912380138f44597b07/gitiles",
+      "log",
+      "-json-output",
+      "/path/to/tmp/json",
+      "https://host.googlesource.com/prefix/g",
+      "main..2d72510e447ab60a9728aeea2362d8be2cbd7789"
+    ],
+    "infra_step": true,
+    "luci_context": {
+      "realm": {
+        "name": "project:ci"
+      },
+      "resultdb": {
+        "current_invocation": {
+          "name": "invocations/build:8945511751514863184",
+          "update_token": "token"
+        },
+        "hostname": "rdbhost"
+      }
+    },
+    "name": "log g7",
+    "timeout": 300.0,
+    "~followup_annotations": [
+      "@@@STEP_LOG_LINE@json.output@[@@@",
+      "@@@STEP_LOG_LINE@json.output@  {@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"author\": {@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"email\": \"fake_A@fake_0.email.com\",@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"name\": \"Fake A\",@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"time\": \"Mon Jan 01 00:00:00 2015\"@@@",
+      "@@@STEP_LOG_LINE@json.output@    },@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"committer\": {@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"email\": \"fake_A@fake_0.email.com\",@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"name\": \"Fake A\",@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"time\": \"Mon Jan 01 00:00:00 2015\"@@@",
+      "@@@STEP_LOG_LINE@json.output@    },@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"id\": \"3e30158f2a7caccb7a9f6632a60011e7a44e1e5c\",@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"message\": \"fake A msg 0\",@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"parents\": [@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"83a7614b3b60951511be50db1b9561daff4bb447\"@@@",
+      "@@@STEP_LOG_LINE@json.output@    ],@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"tree\": \"1b6412b24ec3add84836c8fdd1af5ac8e35b61d9\",@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"tree_diff\": [@@@",
+      "@@@STEP_LOG_LINE@json.output@      {@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"new_id\": \"8bea05ad53680fce6937543f0d98cd48e295b8ff\",@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"new_mode\": 33188,@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"new_path\": \"a.py\",@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"old_id\": \"0000000000000000000000000000000000000000\",@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"old_mode\": 0,@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"type\": \"add\"@@@",
+      "@@@STEP_LOG_LINE@json.output@      }@@@",
+      "@@@STEP_LOG_LINE@json.output@    ]@@@",
+      "@@@STEP_LOG_LINE@json.output@  },@@@",
+      "@@@STEP_LOG_LINE@json.output@  {@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"author\": {@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"email\": \"fake_A@fake_1.email.com\",@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"name\": \"Fake A\",@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"time\": \"Mon Jan 01 00:00:00 2015\"@@@",
+      "@@@STEP_LOG_LINE@json.output@    },@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"committer\": {@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"email\": \"fake_A@fake_1.email.com\",@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"name\": \"Fake A\",@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"time\": \"Mon Jan 01 00:00:00 2015\"@@@",
+      "@@@STEP_LOG_LINE@json.output@    },@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"id\": \"3380b83c11e029b7291c83c44e7b1ce09d465fd1\",@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"message\": \"fake A msg 1\",@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"parents\": [@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"8675a52c73c701cb0b2c48f5ed4a9058c624e6cd\"@@@",
+      "@@@STEP_LOG_LINE@json.output@    ],@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"tree\": \"a1b1e6aa501915989b45a95e1224ec2a88655eb3\",@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"tree_diff\": [@@@",
+      "@@@STEP_LOG_LINE@json.output@      {@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"new_id\": \"06bc4c79002f278528aaddae4e056a11f58c19ad\",@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"new_mode\": 33188,@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"new_path\": \"b.py\",@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"old_id\": \"0000000000000000000000000000000000000000\",@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"old_mode\": 0,@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"type\": \"add\"@@@",
+      "@@@STEP_LOG_LINE@json.output@      }@@@",
+      "@@@STEP_LOG_LINE@json.output@    ]@@@",
+      "@@@STEP_LOG_LINE@json.output@  },@@@",
+      "@@@STEP_LOG_LINE@json.output@  {@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"author\": {@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"email\": \"fake_A@fake_2.email.com\",@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"name\": \"Fake A\",@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"time\": \"Mon Jan 01 00:00:00 2015\"@@@",
+      "@@@STEP_LOG_LINE@json.output@    },@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"committer\": {@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"email\": \"fake_A@fake_2.email.com\",@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"name\": \"Fake A\",@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"time\": \"Mon Jan 01 00:00:00 2015\"@@@",
+      "@@@STEP_LOG_LINE@json.output@    },@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"id\": \"363caa907186de786cb5292cd1ab7245da954815\",@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"message\": \"fake A msg 2\",@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"parents\": [@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"255c6325c4c654e17e6b35142e3912c86f1718f2\"@@@",
+      "@@@STEP_LOG_LINE@json.output@    ],@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"tree\": \"e84d4ad259e69da73d2b842e2b9709f08e8b22bd\",@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"tree_diff\": [@@@",
+      "@@@STEP_LOG_LINE@json.output@      {@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"new_id\": \"d7f478bf423219f2f47c1a6ed344fc597a8bf18f\",@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"new_mode\": 33188,@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"new_path\": \"c.py\",@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"old_id\": \"0000000000000000000000000000000000000000\",@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"old_mode\": 0,@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"type\": \"add\"@@@",
+      "@@@STEP_LOG_LINE@json.output@      }@@@",
+      "@@@STEP_LOG_LINE@json.output@    ]@@@",
+      "@@@STEP_LOG_LINE@json.output@  }@@@",
+      "@@@STEP_LOG_LINE@json.output@]@@@",
+      "@@@STEP_LOG_END@json.output@@@"
+    ]
+  },
+  {
+    "cmd": [],
+    "name": "get gerrit change numbers"
+  },
+  {
+    "cmd": [],
+    "name": "get gerrit change numbers.ensure infra/tools/luci/gerrit/${platform}",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@"
+    ]
+  },
+  {
+    "cmd": [],
+    "name": "get gerrit change numbers.ensure infra/tools/luci/gerrit/${platform}.get packages",
     "~followup_annotations": [
       "@@@STEP_NEST_LEVEL@2@@@"
     ]
@@ -128,8 +316,8 @@
       "--json-output",
       "/path/to/tmp/json",
       "copy",
-      "",
-      "[CACHE]/git/.GUARD_FILE"
+      "RECIPE_MODULE[fuchsia::gerrit]/resources/cipd.ensure",
+      "/path/to/tmp/"
     ],
     "infra_step": true,
     "luci_context": {
@@ -144,7 +332,16 @@
         "hostname": "rdbhost"
       }
     },
-    "name": "checkout g.cache.write git cache guard file",
+    "name": "get gerrit change numbers.ensure infra/tools/luci/gerrit/${platform}.get packages.read ensure file",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@3@@@",
+      "@@@STEP_LOG_LINE@cipd.ensure@infra/tools/luci/gerrit/${platform} version:pinned-version@@@",
+      "@@@STEP_LOG_END@cipd.ensure@@@"
+    ]
+  },
+  {
+    "cmd": [],
+    "name": "get gerrit change numbers.ensure infra/tools/luci/gerrit/${platform}.install infra/tools/luci/gerrit",
     "~followup_annotations": [
       "@@@STEP_NEST_LEVEL@2@@@"
     ]
@@ -159,7 +356,7 @@
       "ensure-directory",
       "--mode",
       "0o777",
-      "[CACHE]/git/host.googlesource.com-prefix-g"
+      "[START_DIR]/cipd_tool/infra/tools/luci/gerrit/0e548aa33f8113a45a5b3b62201e114e98e63d00f97296912380138f44597b07"
     ],
     "infra_step": true,
     "luci_context": {
@@ -174,17 +371,24 @@
         "hostname": "rdbhost"
       }
     },
-    "name": "checkout g.cache.makedirs",
+    "name": "get gerrit change numbers.ensure infra/tools/luci/gerrit/${platform}.install infra/tools/luci/gerrit.ensure package directory",
     "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
+      "@@@STEP_NEST_LEVEL@3@@@"
     ]
   },
   {
     "cmd": [
-      "git",
-      "init"
+      "cipd",
+      "ensure",
+      "-root",
+      "[START_DIR]/cipd_tool/infra/tools/luci/gerrit/0e548aa33f8113a45a5b3b62201e114e98e63d00f97296912380138f44597b07",
+      "-ensure-file",
+      "infra/tools/luci/gerrit/${platform} version:pinned-version",
+      "-max-threads",
+      "0",
+      "-json-output",
+      "/path/to/tmp/json"
     ],
-    "cwd": "[CACHE]/git/host.googlesource.com-prefix-g",
     "infra_step": true,
     "luci_context": {
       "realm": {
@@ -198,20 +402,33 @@
         "hostname": "rdbhost"
       }
     },
-    "name": "checkout g.cache.git init",
-    "timeout": 300.0,
+    "name": "get gerrit change numbers.ensure infra/tools/luci/gerrit/${platform}.install infra/tools/luci/gerrit.ensure_installed",
     "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
+      "@@@STEP_NEST_LEVEL@3@@@",
+      "@@@STEP_LOG_LINE@json.output@{@@@",
+      "@@@STEP_LOG_LINE@json.output@  \"result\": {@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"\": [@@@",
+      "@@@STEP_LOG_LINE@json.output@      {@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"instance_id\": \"resolved-instance_id-of-version:pinned-v\",@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"package\": \"infra/tools/luci/gerrit/resolved-platform\"@@@",
+      "@@@STEP_LOG_LINE@json.output@      }@@@",
+      "@@@STEP_LOG_LINE@json.output@    ]@@@",
+      "@@@STEP_LOG_LINE@json.output@  }@@@",
+      "@@@STEP_LOG_LINE@json.output@}@@@",
+      "@@@STEP_LOG_END@json.output@@@"
     ]
   },
   {
     "cmd": [
-      "git",
-      "config",
-      "remote.origin.url",
-      "https://host.googlesource.com/prefix/g"
+      "[START_DIR]/cipd_tool/infra/tools/luci/gerrit/0e548aa33f8113a45a5b3b62201e114e98e63d00f97296912380138f44597b07/gerrit",
+      "change-detail",
+      "-host",
+      "https://host-review.googlesource.com",
+      "-input",
+      "{\"change_id\": \"3e30158f2a7caccb7a9f6632a60011e7a44e1e5c\"}",
+      "-output",
+      "/path/to/tmp/json"
     ],
-    "cwd": "[CACHE]/git/host.googlesource.com-prefix-g",
     "infra_step": true,
     "luci_context": {
       "realm": {
@@ -225,149 +442,31 @@
         "hostname": "rdbhost"
       }
     },
-    "name": "checkout g.cache.remote set-url",
-    "timeout": 300.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "config",
-      "fetch.uriprotocols",
-      "https"
-    ],
-    "cwd": "[CACHE]/git/host.googlesource.com-prefix-g",
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout g.cache.set fetch.uriprotocols",
-    "timeout": 300.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "checkout g.cache.timeout 10s",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "fetch",
-      "--prune",
-      "--tags",
-      "--jobs",
-      "4",
-      "origin",
-      "--no-recurse-submodules"
-    ],
-    "cwd": "[CACHE]/git/host.googlesource.com-prefix-g",
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout g.cache.git fetch",
-    "timeout": 1200.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "merge",
-      "FETCH_HEAD"
-    ],
-    "cwd": "[CACHE]/git/host.googlesource.com-prefix-g",
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout g.cache.git merge",
-    "timeout": 600.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "checkout g.cache.timeout 10s (2)",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "submodule",
-      "update",
-      "--recursive",
-      "--force",
-      "--jobs",
-      "4"
-    ],
-    "cwd": "[CACHE]/git/host.googlesource.com-prefix-g",
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout g.cache.git submodule update",
+    "name": "get gerrit change numbers.change details for 3e30158",
     "timeout": 600,
     "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
+      "@@@STEP_NEST_LEVEL@1@@@",
+      "@@@STEP_LOG_LINE@json.output@{@@@",
+      "@@@STEP_LOG_LINE@json.output@  \"_number\": 12345@@@",
+      "@@@STEP_LOG_LINE@json.output@}@@@",
+      "@@@STEP_LOG_END@json.output@@@",
+      "@@@STEP_LOG_LINE@json.input@{@@@",
+      "@@@STEP_LOG_LINE@json.input@  \"change_id\": \"3e30158f2a7caccb7a9f6632a60011e7a44e1e5c\"@@@",
+      "@@@STEP_LOG_LINE@json.input@}@@@",
+      "@@@STEP_LOG_END@json.input@@@",
+      "@@@STEP_LINK@gerrit link@https://host-review.googlesource.com/q/3e30158f2a7caccb7a9f6632a60011e7a44e1e5c@@@"
     ]
   },
   {
     "cmd": [
-      "vpython3",
-      "-u",
-      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
-      "--json-output",
-      "/path/to/tmp/json",
-      "remove",
-      "[CACHE]/git/.GUARD_FILE"
+      "[START_DIR]/cipd_tool/infra/tools/luci/gerrit/0e548aa33f8113a45a5b3b62201e114e98e63d00f97296912380138f44597b07/gerrit",
+      "change-detail",
+      "-host",
+      "https://host-review.googlesource.com",
+      "-input",
+      "{\"change_id\": \"3380b83c11e029b7291c83c44e7b1ce09d465fd1\"}",
+      "-output",
+      "/path/to/tmp/json"
     ],
     "infra_step": true,
     "luci_context": {
@@ -382,516 +481,31 @@
         "hostname": "rdbhost"
       }
     },
-    "name": "checkout g.cache.remove git cache guard file",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "vpython3",
-      "-u",
-      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
-      "--json-output",
-      "/path/to/tmp/json",
-      "copytree",
-      "--symlinks",
-      "[CACHE]/git/host.googlesource.com-prefix-g",
-      "[START_DIR]/project"
-    ],
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout g.copy from cache",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "checkout g.git checkout",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "checkout g.git checkout.timeout 10s",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "vpython3",
-      "-u",
-      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
-      "--json-output",
-      "/path/to/tmp/json",
-      "ensure-directory",
-      "--mode",
-      "0o777",
-      "[START_DIR]/project"
-    ],
-    "infra_step": true,
-    "luci_context": {
-      "deadline": {
-        "grace_period": 30.0,
-        "soft_deadline": 1337000019.0
-      },
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout g.git checkout.makedirs",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "init"
-    ],
-    "cwd": "[START_DIR]/project",
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout g.git checkout.git init",
-    "timeout": 300.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "remote",
-      "add",
-      "origin",
-      "https://host.googlesource.com/prefix/g"
-    ],
-    "cwd": "[START_DIR]/project",
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout g.git checkout.git remote",
-    "timeout": 600.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "config",
-      "core.longpaths",
-      "true"
-    ],
-    "cwd": "[START_DIR]/project",
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout g.git checkout.set core.longpaths",
-    "timeout": 300.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "config",
-      "fetch.uriprotocols",
-      "https"
-    ],
-    "cwd": "[START_DIR]/project",
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout g.git checkout.set fetch.uriprotocols",
-    "timeout": 300.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "fetch",
-      "--tags",
-      "--jobs",
-      "4",
-      "origin",
-      "main"
-    ],
-    "cwd": "[START_DIR]/project",
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout g.git checkout.git fetch",
-    "timeout": 1200.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "checkout",
-      "-f",
-      "FETCH_HEAD"
-    ],
-    "cwd": "[START_DIR]/project",
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout g.git checkout.git checkout",
-    "timeout": 600.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "rev-parse",
-      "HEAD"
-    ],
-    "cwd": "[START_DIR]/project",
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout g.git checkout.git rev-parse",
-    "timeout": 300.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "clean",
-      "-f",
-      "-d",
-      "-x"
-    ],
-    "cwd": "[START_DIR]/project",
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout g.git checkout.git clean",
-    "timeout": 600.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "checkout g.git log",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "log",
-      "--oneline",
-      "-n",
-      "10"
-    ],
-    "cwd": "[START_DIR]/project",
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout g.git log.[START_DIR]/project",
-    "timeout": 600.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "clean",
-      "-f",
-      "-f",
-      "-d"
-    ],
-    "cwd": "[START_DIR]/project",
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout g.git clean",
-    "timeout": 600.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "status"
-    ],
-    "cwd": "[START_DIR]/project",
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout g.git status",
-    "timeout": 600.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "vpython3",
-      "-u",
-      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
-      "--json-output",
-      "/path/to/tmp/json",
-      "ensure-directory",
-      "--mode",
-      "0o777",
-      "[START_DIR]/snapshot"
-    ],
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout g.mkdir",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "submodule",
-      "status",
-      "--recursive"
-    ],
-    "cwd": "[START_DIR]/project",
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout g.submodule-status",
-    "timeout": 600.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "vpython3",
-      "-u",
-      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
-      "--json-output",
-      "/path/to/tmp/json",
-      "copy",
-      "submodule status filler text",
-      "[START_DIR]/snapshot/submodules.log"
-    ],
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout g.write submodule snapshot",
+    "name": "get gerrit change numbers.change details for 3380b83",
+    "timeout": 600,
     "~followup_annotations": [
       "@@@STEP_NEST_LEVEL@1@@@",
-      "@@@STEP_LOG_LINE@submodules.log@submodule status filler text@@@",
-      "@@@STEP_LOG_END@submodules.log@@@"
+      "@@@STEP_LOG_LINE@json.output@{@@@",
+      "@@@STEP_LOG_LINE@json.output@  \"_number\": 12345@@@",
+      "@@@STEP_LOG_LINE@json.output@}@@@",
+      "@@@STEP_LOG_END@json.output@@@",
+      "@@@STEP_LOG_LINE@json.input@{@@@",
+      "@@@STEP_LOG_LINE@json.input@  \"change_id\": \"3380b83c11e029b7291c83c44e7b1ce09d465fd1\"@@@",
+      "@@@STEP_LOG_LINE@json.input@}@@@",
+      "@@@STEP_LOG_END@json.input@@@",
+      "@@@STEP_LINK@gerrit link@https://host-review.googlesource.com/q/3380b83c11e029b7291c83c44e7b1ce09d465fd1@@@"
     ]
   },
   {
     "cmd": [
-      "git",
-      "log",
-      "--oneline",
-      "-n",
-      "10"
-    ],
-    "cwd": "[START_DIR]/project",
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout g.log",
-    "timeout": 600.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "vpython3",
-      "-u",
-      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
-      "--json-output",
-      "/path/to/tmp/json",
-      "copy",
-      "",
-      "[START_DIR]/snapshot/git.log"
+      "[START_DIR]/cipd_tool/infra/tools/luci/gerrit/0e548aa33f8113a45a5b3b62201e114e98e63d00f97296912380138f44597b07/gerrit",
+      "change-detail",
+      "-host",
+      "https://host-review.googlesource.com",
+      "-input",
+      "{\"change_id\": \"363caa907186de786cb5292cd1ab7245da954815\"}",
+      "-output",
+      "/path/to/tmp/json"
     ],
     "infra_step": true,
     "luci_context": {
@@ -906,10 +520,19 @@
         "hostname": "rdbhost"
       }
     },
-    "name": "checkout g.write git log",
+    "name": "get gerrit change numbers.change details for 363caa9",
+    "timeout": 600,
     "~followup_annotations": [
       "@@@STEP_NEST_LEVEL@1@@@",
-      "@@@STEP_LOG_END@git.log@@@"
+      "@@@STEP_LOG_LINE@json.output@{@@@",
+      "@@@STEP_LOG_LINE@json.output@  \"_number\": 12345@@@",
+      "@@@STEP_LOG_LINE@json.output@}@@@",
+      "@@@STEP_LOG_END@json.output@@@",
+      "@@@STEP_LOG_LINE@json.input@{@@@",
+      "@@@STEP_LOG_LINE@json.input@  \"change_id\": \"363caa907186de786cb5292cd1ab7245da954815\"@@@",
+      "@@@STEP_LOG_LINE@json.input@}@@@",
+      "@@@STEP_LOG_END@json.input@@@",
+      "@@@STEP_LINK@gerrit link@https://host-review.googlesource.com/q/363caa907186de786cb5292cd1ab7245da954815@@@"
     ]
   },
   {
@@ -966,338 +589,22 @@
   },
   {
     "cmd": [],
-    "name": "remote"
-  },
-  {
-    "cmd": [
-      "git",
-      "remote"
-    ],
-    "cwd": "[START_DIR]/project",
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "remote.name",
-    "timeout": 600.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "remote",
-      "get-url",
-      "origin"
-    ],
-    "cwd": "[START_DIR]/project",
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "remote.url",
-    "timeout": 600.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "g7"
-  },
-  {
-    "cmd": [
-      "git",
-      "log",
-      "--pretty=format:%H\n%an\n%ae\n%B",
-      "-z",
-      "--max-count",
-      "5",
-      "2d72510e447ab60a9728aeea2362d8be2cbd7789"
-    ],
-    "cwd": "[START_DIR]/project",
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "g7.git log",
-    "timeout": 600.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "g7.ensure infra/tools/luci/gerrit/${platform}",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "g7.ensure infra/tools/luci/gerrit/${platform}.get packages",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "vpython3",
-      "-u",
-      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
-      "--json-output",
-      "/path/to/tmp/json",
-      "copy",
-      "RECIPE_MODULE[fuchsia::gerrit]/resources/cipd.ensure",
-      "/path/to/tmp/"
-    ],
-    "cwd": "[START_DIR]/project",
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "g7.ensure infra/tools/luci/gerrit/${platform}.get packages.read ensure file",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@3@@@",
-      "@@@STEP_LOG_LINE@cipd.ensure@infra/tools/luci/gerrit/${platform} version:pinned-version@@@",
-      "@@@STEP_LOG_END@cipd.ensure@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "g7.ensure infra/tools/luci/gerrit/${platform}.install infra/tools/luci/gerrit",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "vpython3",
-      "-u",
-      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
-      "--json-output",
-      "/path/to/tmp/json",
-      "ensure-directory",
-      "--mode",
-      "0o777",
-      "[START_DIR]/cipd_tool/infra/tools/luci/gerrit/0e548aa33f8113a45a5b3b62201e114e98e63d00f97296912380138f44597b07"
-    ],
-    "cwd": "[START_DIR]/project",
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "g7.ensure infra/tools/luci/gerrit/${platform}.install infra/tools/luci/gerrit.ensure package directory",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@3@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "cipd",
-      "ensure",
-      "-root",
-      "[START_DIR]/cipd_tool/infra/tools/luci/gerrit/0e548aa33f8113a45a5b3b62201e114e98e63d00f97296912380138f44597b07",
-      "-ensure-file",
-      "infra/tools/luci/gerrit/${platform} version:pinned-version",
-      "-max-threads",
-      "0",
-      "-json-output",
-      "/path/to/tmp/json"
-    ],
-    "cwd": "[START_DIR]/project",
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "g7.ensure infra/tools/luci/gerrit/${platform}.install infra/tools/luci/gerrit.ensure_installed",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@3@@@",
-      "@@@STEP_LOG_LINE@json.output@{@@@",
-      "@@@STEP_LOG_LINE@json.output@  \"result\": {@@@",
-      "@@@STEP_LOG_LINE@json.output@    \"\": [@@@",
-      "@@@STEP_LOG_LINE@json.output@      {@@@",
-      "@@@STEP_LOG_LINE@json.output@        \"instance_id\": \"resolved-instance_id-of-version:pinned-v\",@@@",
-      "@@@STEP_LOG_LINE@json.output@        \"package\": \"infra/tools/luci/gerrit/resolved-platform\"@@@",
-      "@@@STEP_LOG_LINE@json.output@      }@@@",
-      "@@@STEP_LOG_LINE@json.output@    ]@@@",
-      "@@@STEP_LOG_LINE@json.output@  }@@@",
-      "@@@STEP_LOG_LINE@json.output@}@@@",
-      "@@@STEP_LOG_END@json.output@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "[START_DIR]/cipd_tool/infra/tools/luci/gerrit/0e548aa33f8113a45a5b3b62201e114e98e63d00f97296912380138f44597b07/gerrit",
-      "change-query",
-      "-host",
-      "https://pigweed-review.googlesource.com",
-      "-input",
-      "{\"params\": {\"q\": \"commit:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\"}}",
-      "-output",
-      "/path/to/tmp/json"
-    ],
-    "cwd": "[START_DIR]/project",
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "g7.get change-id",
-    "timeout": 600,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@",
-      "@@@STEP_LOG_LINE@json.output@[@@@",
-      "@@@STEP_LOG_LINE@json.output@  {@@@",
-      "@@@STEP_LOG_LINE@json.output@    \"_number\": 12345@@@",
-      "@@@STEP_LOG_LINE@json.output@  }@@@",
-      "@@@STEP_LOG_LINE@json.output@]@@@",
-      "@@@STEP_LOG_END@json.output@@@",
-      "@@@STEP_LOG_LINE@json.input@{@@@",
-      "@@@STEP_LOG_LINE@json.input@  \"params\": {@@@",
-      "@@@STEP_LOG_LINE@json.input@    \"q\": \"commit:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\"@@@",
-      "@@@STEP_LOG_LINE@json.input@  }@@@",
-      "@@@STEP_LOG_LINE@json.input@}@@@",
-      "@@@STEP_LOG_END@json.input@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "[START_DIR]/cipd_tool/infra/tools/luci/gerrit/0e548aa33f8113a45a5b3b62201e114e98e63d00f97296912380138f44597b07/gerrit",
-      "change-detail",
-      "-host",
-      "https://pigweed-review.googlesource.com",
-      "-input",
-      "{\"change_id\": \"12345\"}",
-      "-output",
-      "/path/to/tmp/json"
-    ],
-    "cwd": "[START_DIR]/project",
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "g7.get 12345",
-    "timeout": 600,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@",
-      "@@@STEP_LOG_LINE@json.output@{@@@",
-      "@@@STEP_LOG_LINE@json.output@  \"owner\": {@@@",
-      "@@@STEP_LOG_LINE@json.output@    \"email\": \"author@example.com\",@@@",
-      "@@@STEP_LOG_LINE@json.output@    \"name\": \"author\"@@@",
-      "@@@STEP_LOG_LINE@json.output@  },@@@",
-      "@@@STEP_LOG_LINE@json.output@  \"reviewers\": {@@@",
-      "@@@STEP_LOG_LINE@json.output@    \"REVIEWER\": [@@@",
-      "@@@STEP_LOG_LINE@json.output@      {@@@",
-      "@@@STEP_LOG_LINE@json.output@        \"email\": \"reviewer@example.com\",@@@",
-      "@@@STEP_LOG_LINE@json.output@        \"name\": \"reviewer\"@@@",
-      "@@@STEP_LOG_LINE@json.output@      },@@@",
-      "@@@STEP_LOG_LINE@json.output@      {@@@",
-      "@@@STEP_LOG_LINE@json.output@        \"email\": \"nobody@google.com\",@@@",
-      "@@@STEP_LOG_LINE@json.output@        \"name\": \"nobody\"@@@",
-      "@@@STEP_LOG_LINE@json.output@      },@@@",
-      "@@@STEP_LOG_LINE@json.output@      {@@@",
-      "@@@STEP_LOG_LINE@json.output@        \"email\": \"robot@gserviceaccount.com\",@@@",
-      "@@@STEP_LOG_LINE@json.output@        \"name\": \"robot\"@@@",
-      "@@@STEP_LOG_LINE@json.output@      }@@@",
-      "@@@STEP_LOG_LINE@json.output@    ]@@@",
-      "@@@STEP_LOG_LINE@json.output@  }@@@",
-      "@@@STEP_LOG_LINE@json.output@}@@@",
-      "@@@STEP_LOG_END@json.output@@@",
-      "@@@STEP_LOG_LINE@json.input@{@@@",
-      "@@@STEP_LOG_LINE@json.input@  \"change_id\": \"12345\"@@@",
-      "@@@STEP_LOG_LINE@json.input@}@@@",
-      "@@@STEP_LOG_END@json.input@@@",
-      "@@@STEP_LINK@gerrit link@https://pigweed-review.googlesource.com/q/12345@@@"
-    ]
-  },
-  {
-    "cmd": [],
     "name": "roll"
   },
   {
     "cmd": [],
-    "name": "roll.project_name",
+    "name": "roll.repo_url",
     "~followup_annotations": [
       "@@@STEP_NEST_LEVEL@1@@@",
-      "@@@STEP_SUMMARY_TEXT@g7@@@"
+      "@@@STEP_SUMMARY_TEXT@https://host.googlesource.com/prefix/g@@@"
     ]
   },
   {
     "cmd": [],
-    "name": "roll.proj_dir",
+    "name": "roll.repo_short_name",
     "~followup_annotations": [
       "@@@STEP_NEST_LEVEL@1@@@",
-      "@@@STEP_SUMMARY_TEXT@[START_DIR]/project@@@"
+      "@@@STEP_SUMMARY_TEXT@g7@@@"
     ]
   },
   {
@@ -1318,10 +625,10 @@
   },
   {
     "cmd": [],
-    "name": "roll.direction",
+    "name": "roll.commit message",
     "~followup_annotations": [
       "@@@STEP_NEST_LEVEL@1@@@",
-      "@@@STEP_SUMMARY_TEXT@Direction.FORWARD@@@"
+      "@@@STEP_SUMMARY_TEXT@[roll] Roll g7 main..2d72510 (3 commits)\n\n3e30158:https://host-review.googlesource.com/c/prefix/g/+/12345 fake A msg 0\n3380b83:https://host-review.googlesource.com/c/prefix/g/+/12345 fake A msg 1\n363caa9:https://host-review.googlesource.com/c/prefix/g/+/12345 fake A msg 2\n\nRolled-Repo: https://host.googlesource.com/prefix/g\nRolled-Commits: main..2d72510e447ab6@@@"
     ]
   },
   {
diff --git a/recipe_modules/repo_roll/tests/full.expected/equivalent.json b/recipe_modules/repo_roll/tests/full.expected/equivalent.json
index c539079..cc5414e 100644
--- a/recipe_modules/repo_roll/tests/full.expected/equivalent.json
+++ b/recipe_modules/repo_roll/tests/full.expected/equivalent.json
@@ -44,529 +44,6 @@
     ]
   },
   {
-    "cmd": [],
-    "name": "checkout b"
-  },
-  {
-    "cmd": [],
-    "name": "checkout b.options",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@",
-      "@@@STEP_SUMMARY_TEXT@remote: \"https://bar.googlesource.com/b\"\nbranch: \"main\"\n@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "checkout b.options with defaults",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@",
-      "@@@STEP_SUMMARY_TEXT@remote: \"https://bar.googlesource.com/b\"\nbranch: \"main\"\nmanifest_file: \"default.xml\"\nrepo_init_timeout_sec: 20\nrepo_sync_timeout_sec: 120\nnumber_of_attempts: 3\nsubmodule_timeout_sec: 600\n@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "checkout b.not matching branch names",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "checkout b.cache",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@",
-      "@@@STEP_SUMMARY_TEXT@miss@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "vpython3",
-      "-u",
-      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
-      "--json-output",
-      "/path/to/tmp/json",
-      "ensure-directory",
-      "--mode",
-      "0o777",
-      "[CACHE]/git"
-    ],
-    "infra_step": true,
-    "name": "checkout b.cache.ensure git cache dir",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "vpython3",
-      "-u",
-      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
-      "--json-output",
-      "/path/to/tmp/json",
-      "copy",
-      "",
-      "[CACHE]/git/.GUARD_FILE"
-    ],
-    "infra_step": true,
-    "name": "checkout b.cache.write git cache guard file",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "vpython3",
-      "-u",
-      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
-      "--json-output",
-      "/path/to/tmp/json",
-      "ensure-directory",
-      "--mode",
-      "0o777",
-      "[CACHE]/git/bar.googlesource.com-b"
-    ],
-    "infra_step": true,
-    "name": "checkout b.cache.makedirs",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "init"
-    ],
-    "cwd": "[CACHE]/git/bar.googlesource.com-b",
-    "infra_step": true,
-    "name": "checkout b.cache.git init",
-    "timeout": 300.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "config",
-      "remote.origin.url",
-      "https://bar.googlesource.com/b"
-    ],
-    "cwd": "[CACHE]/git/bar.googlesource.com-b",
-    "infra_step": true,
-    "name": "checkout b.cache.remote set-url",
-    "timeout": 300.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "config",
-      "fetch.uriprotocols",
-      "https"
-    ],
-    "cwd": "[CACHE]/git/bar.googlesource.com-b",
-    "infra_step": true,
-    "name": "checkout b.cache.set fetch.uriprotocols",
-    "timeout": 300.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "checkout b.cache.timeout 10s",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "fetch",
-      "--prune",
-      "--tags",
-      "--jobs",
-      "4",
-      "origin",
-      "--no-recurse-submodules"
-    ],
-    "cwd": "[CACHE]/git/bar.googlesource.com-b",
-    "infra_step": true,
-    "name": "checkout b.cache.git fetch",
-    "timeout": 1200.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "merge",
-      "FETCH_HEAD"
-    ],
-    "cwd": "[CACHE]/git/bar.googlesource.com-b",
-    "infra_step": true,
-    "name": "checkout b.cache.git merge",
-    "timeout": 600.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "checkout b.cache.timeout 10s (2)",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "submodule",
-      "update",
-      "--recursive",
-      "--force",
-      "--jobs",
-      "4"
-    ],
-    "cwd": "[CACHE]/git/bar.googlesource.com-b",
-    "infra_step": true,
-    "name": "checkout b.cache.git submodule update",
-    "timeout": 600,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "vpython3",
-      "-u",
-      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
-      "--json-output",
-      "/path/to/tmp/json",
-      "remove",
-      "[CACHE]/git/.GUARD_FILE"
-    ],
-    "infra_step": true,
-    "name": "checkout b.cache.remove git cache guard file",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "vpython3",
-      "-u",
-      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
-      "--json-output",
-      "/path/to/tmp/json",
-      "copytree",
-      "--symlinks",
-      "[CACHE]/git/bar.googlesource.com-b",
-      "[START_DIR]/project"
-    ],
-    "infra_step": true,
-    "name": "checkout b.copy from cache",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "checkout b.git checkout",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "checkout b.git checkout.timeout 10s",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "vpython3",
-      "-u",
-      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
-      "--json-output",
-      "/path/to/tmp/json",
-      "ensure-directory",
-      "--mode",
-      "0o777",
-      "[START_DIR]/project"
-    ],
-    "infra_step": true,
-    "luci_context": {
-      "deadline": {
-        "grace_period": 30.0,
-        "soft_deadline": 1337000019.0
-      }
-    },
-    "name": "checkout b.git checkout.makedirs",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "init"
-    ],
-    "cwd": "[START_DIR]/project",
-    "infra_step": true,
-    "name": "checkout b.git checkout.git init",
-    "timeout": 300.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "remote",
-      "add",
-      "origin",
-      "https://bar.googlesource.com/b"
-    ],
-    "cwd": "[START_DIR]/project",
-    "infra_step": true,
-    "name": "checkout b.git checkout.git remote",
-    "timeout": 600.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "config",
-      "core.longpaths",
-      "true"
-    ],
-    "cwd": "[START_DIR]/project",
-    "infra_step": true,
-    "name": "checkout b.git checkout.set core.longpaths",
-    "timeout": 300.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "config",
-      "fetch.uriprotocols",
-      "https"
-    ],
-    "cwd": "[START_DIR]/project",
-    "infra_step": true,
-    "name": "checkout b.git checkout.set fetch.uriprotocols",
-    "timeout": 300.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "fetch",
-      "--tags",
-      "--jobs",
-      "4",
-      "origin",
-      "main"
-    ],
-    "cwd": "[START_DIR]/project",
-    "infra_step": true,
-    "name": "checkout b.git checkout.git fetch",
-    "timeout": 1200.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "checkout",
-      "-f",
-      "FETCH_HEAD"
-    ],
-    "cwd": "[START_DIR]/project",
-    "infra_step": true,
-    "name": "checkout b.git checkout.git checkout",
-    "timeout": 600.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "rev-parse",
-      "HEAD"
-    ],
-    "cwd": "[START_DIR]/project",
-    "infra_step": true,
-    "name": "checkout b.git checkout.git rev-parse",
-    "timeout": 300.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "clean",
-      "-f",
-      "-d",
-      "-x"
-    ],
-    "cwd": "[START_DIR]/project",
-    "infra_step": true,
-    "name": "checkout b.git checkout.git clean",
-    "timeout": 600.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "checkout b.git log",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "log",
-      "--oneline",
-      "-n",
-      "10"
-    ],
-    "cwd": "[START_DIR]/project",
-    "name": "checkout b.git log.[START_DIR]/project",
-    "timeout": 600.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "clean",
-      "-f",
-      "-f",
-      "-d"
-    ],
-    "cwd": "[START_DIR]/project",
-    "name": "checkout b.git clean",
-    "timeout": 600.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "status"
-    ],
-    "cwd": "[START_DIR]/project",
-    "name": "checkout b.git status",
-    "timeout": 600.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "vpython3",
-      "-u",
-      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
-      "--json-output",
-      "/path/to/tmp/json",
-      "ensure-directory",
-      "--mode",
-      "0o777",
-      "[START_DIR]/snapshot"
-    ],
-    "infra_step": true,
-    "name": "checkout b.mkdir",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "submodule",
-      "status",
-      "--recursive"
-    ],
-    "cwd": "[START_DIR]/project",
-    "name": "checkout b.submodule-status",
-    "timeout": 600.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "vpython3",
-      "-u",
-      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
-      "--json-output",
-      "/path/to/tmp/json",
-      "copy",
-      "submodule status filler text",
-      "[START_DIR]/snapshot/submodules.log"
-    ],
-    "infra_step": true,
-    "name": "checkout b.write submodule snapshot",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@",
-      "@@@STEP_LOG_LINE@submodules.log@submodule status filler text@@@",
-      "@@@STEP_LOG_END@submodules.log@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "log",
-      "--oneline",
-      "-n",
-      "10"
-    ],
-    "cwd": "[START_DIR]/project",
-    "name": "checkout b.log",
-    "timeout": 600.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "vpython3",
-      "-u",
-      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
-      "--json-output",
-      "/path/to/tmp/json",
-      "copy",
-      "",
-      "[START_DIR]/snapshot/git.log"
-    ],
-    "infra_step": true,
-    "name": "checkout b.write git log",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@",
-      "@@@STEP_LOG_END@git.log@@@"
-    ]
-  },
-  {
     "cmd": [
       "git",
       "ls-remote",
@@ -583,37 +60,37 @@
   },
   {
     "cmd": [],
-    "name": "get roll direction",
-    "~followup_annotations": [
-      "@@@STEP_SUMMARY_TEXT@forward@@@"
-    ]
+    "name": "ensure infra/tools/luci/gitiles/${platform}"
   },
   {
-    "cmd": [
-      "git",
-      "merge-base",
-      "--is-ancestor",
-      "2222222222222222222222222222222222222222",
-      "h3ll0"
-    ],
-    "cwd": "[START_DIR]/project",
-    "name": "get roll direction.is forward",
-    "timeout": 600.0,
+    "cmd": [],
+    "name": "ensure infra/tools/luci/gitiles/${platform}.get packages",
     "~followup_annotations": [
       "@@@STEP_NEST_LEVEL@1@@@"
     ]
   },
   {
     "cmd": [
-      "git",
-      "merge-base",
-      "--is-ancestor",
-      "h3ll0",
-      "2222222222222222222222222222222222222222"
+      "vpython3",
+      "-u",
+      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
+      "--json-output",
+      "/path/to/tmp/json",
+      "copy",
+      "RECIPE_MODULE[fuchsia::gitiles]/resources/cipd.ensure",
+      "/path/to/tmp/"
     ],
-    "cwd": "[START_DIR]/project",
-    "name": "get roll direction.is backward",
-    "timeout": 600.0,
+    "infra_step": true,
+    "name": "ensure infra/tools/luci/gitiles/${platform}.get packages.read ensure file",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@2@@@",
+      "@@@STEP_LOG_LINE@cipd.ensure@infra/tools/luci/gitiles/${platform} version:pinned-version@@@",
+      "@@@STEP_LOG_END@cipd.ensure@@@"
+    ]
+  },
+  {
+    "cmd": [],
+    "name": "ensure infra/tools/luci/gitiles/${platform}.install infra/tools/luci/gitiles",
     "~followup_annotations": [
       "@@@STEP_NEST_LEVEL@1@@@"
     ]
@@ -625,6 +102,329 @@
       "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
       "--json-output",
       "/path/to/tmp/json",
+      "ensure-directory",
+      "--mode",
+      "0o777",
+      "[START_DIR]/cipd_tool/infra/tools/luci/gitiles/0e548aa33f8113a45a5b3b62201e114e98e63d00f97296912380138f44597b07"
+    ],
+    "infra_step": true,
+    "name": "ensure infra/tools/luci/gitiles/${platform}.install infra/tools/luci/gitiles.ensure package directory",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@2@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "cipd",
+      "ensure",
+      "-root",
+      "[START_DIR]/cipd_tool/infra/tools/luci/gitiles/0e548aa33f8113a45a5b3b62201e114e98e63d00f97296912380138f44597b07",
+      "-ensure-file",
+      "infra/tools/luci/gitiles/${platform} version:pinned-version",
+      "-max-threads",
+      "0",
+      "-json-output",
+      "/path/to/tmp/json"
+    ],
+    "infra_step": true,
+    "name": "ensure infra/tools/luci/gitiles/${platform}.install infra/tools/luci/gitiles.ensure_installed",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@2@@@",
+      "@@@STEP_LOG_LINE@json.output@{@@@",
+      "@@@STEP_LOG_LINE@json.output@  \"result\": {@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"\": [@@@",
+      "@@@STEP_LOG_LINE@json.output@      {@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"instance_id\": \"resolved-instance_id-of-version:pinned-v\",@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"package\": \"infra/tools/luci/gitiles/resolved-platform\"@@@",
+      "@@@STEP_LOG_LINE@json.output@      }@@@",
+      "@@@STEP_LOG_LINE@json.output@    ]@@@",
+      "@@@STEP_LOG_LINE@json.output@  }@@@",
+      "@@@STEP_LOG_LINE@json.output@}@@@",
+      "@@@STEP_LOG_END@json.output@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "[START_DIR]/cipd_tool/infra/tools/luci/gitiles/0e548aa33f8113a45a5b3b62201e114e98e63d00f97296912380138f44597b07/gitiles",
+      "log",
+      "-json-output",
+      "/path/to/tmp/json",
+      "https://bar.googlesource.com/b",
+      "2222222222222222222222222222222222222222..h3ll0"
+    ],
+    "infra_step": true,
+    "name": "log b2",
+    "timeout": 300.0,
+    "~followup_annotations": [
+      "@@@STEP_LOG_LINE@json.output@[@@@",
+      "@@@STEP_LOG_LINE@json.output@  {@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"author\": {@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"email\": \"fake_A@fake_0.email.com\",@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"name\": \"Fake A\",@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"time\": \"Mon Jan 01 00:00:00 2015\"@@@",
+      "@@@STEP_LOG_LINE@json.output@    },@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"committer\": {@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"email\": \"fake_A@fake_0.email.com\",@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"name\": \"Fake A\",@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"time\": \"Mon Jan 01 00:00:00 2015\"@@@",
+      "@@@STEP_LOG_LINE@json.output@    },@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"id\": \"3e30158f2a7caccb7a9f6632a60011e7a44e1e5c\",@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"message\": \"fake A msg 0\",@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"parents\": [@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"83a7614b3b60951511be50db1b9561daff4bb447\"@@@",
+      "@@@STEP_LOG_LINE@json.output@    ],@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"tree\": \"1b6412b24ec3add84836c8fdd1af5ac8e35b61d9\",@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"tree_diff\": [@@@",
+      "@@@STEP_LOG_LINE@json.output@      {@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"new_id\": \"8bea05ad53680fce6937543f0d98cd48e295b8ff\",@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"new_mode\": 33188,@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"new_path\": \"a.py\",@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"old_id\": \"0000000000000000000000000000000000000000\",@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"old_mode\": 0,@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"type\": \"add\"@@@",
+      "@@@STEP_LOG_LINE@json.output@      }@@@",
+      "@@@STEP_LOG_LINE@json.output@    ]@@@",
+      "@@@STEP_LOG_LINE@json.output@  },@@@",
+      "@@@STEP_LOG_LINE@json.output@  {@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"author\": {@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"email\": \"fake_A@fake_1.email.com\",@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"name\": \"Fake A\",@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"time\": \"Mon Jan 01 00:00:00 2015\"@@@",
+      "@@@STEP_LOG_LINE@json.output@    },@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"committer\": {@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"email\": \"fake_A@fake_1.email.com\",@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"name\": \"Fake A\",@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"time\": \"Mon Jan 01 00:00:00 2015\"@@@",
+      "@@@STEP_LOG_LINE@json.output@    },@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"id\": \"3380b83c11e029b7291c83c44e7b1ce09d465fd1\",@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"message\": \"fake A msg 1\",@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"parents\": [@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"8675a52c73c701cb0b2c48f5ed4a9058c624e6cd\"@@@",
+      "@@@STEP_LOG_LINE@json.output@    ],@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"tree\": \"a1b1e6aa501915989b45a95e1224ec2a88655eb3\",@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"tree_diff\": [@@@",
+      "@@@STEP_LOG_LINE@json.output@      {@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"new_id\": \"06bc4c79002f278528aaddae4e056a11f58c19ad\",@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"new_mode\": 33188,@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"new_path\": \"b.py\",@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"old_id\": \"0000000000000000000000000000000000000000\",@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"old_mode\": 0,@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"type\": \"add\"@@@",
+      "@@@STEP_LOG_LINE@json.output@      }@@@",
+      "@@@STEP_LOG_LINE@json.output@    ]@@@",
+      "@@@STEP_LOG_LINE@json.output@  },@@@",
+      "@@@STEP_LOG_LINE@json.output@  {@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"author\": {@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"email\": \"fake_A@fake_2.email.com\",@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"name\": \"Fake A\",@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"time\": \"Mon Jan 01 00:00:00 2015\"@@@",
+      "@@@STEP_LOG_LINE@json.output@    },@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"committer\": {@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"email\": \"fake_A@fake_2.email.com\",@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"name\": \"Fake A\",@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"time\": \"Mon Jan 01 00:00:00 2015\"@@@",
+      "@@@STEP_LOG_LINE@json.output@    },@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"id\": \"363caa907186de786cb5292cd1ab7245da954815\",@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"message\": \"fake A msg 2\",@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"parents\": [@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"255c6325c4c654e17e6b35142e3912c86f1718f2\"@@@",
+      "@@@STEP_LOG_LINE@json.output@    ],@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"tree\": \"e84d4ad259e69da73d2b842e2b9709f08e8b22bd\",@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"tree_diff\": [@@@",
+      "@@@STEP_LOG_LINE@json.output@      {@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"new_id\": \"d7f478bf423219f2f47c1a6ed344fc597a8bf18f\",@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"new_mode\": 33188,@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"new_path\": \"c.py\",@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"old_id\": \"0000000000000000000000000000000000000000\",@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"old_mode\": 0,@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"type\": \"add\"@@@",
+      "@@@STEP_LOG_LINE@json.output@      }@@@",
+      "@@@STEP_LOG_LINE@json.output@    ]@@@",
+      "@@@STEP_LOG_LINE@json.output@  }@@@",
+      "@@@STEP_LOG_LINE@json.output@]@@@",
+      "@@@STEP_LOG_END@json.output@@@"
+    ]
+  },
+  {
+    "cmd": [],
+    "name": "get gerrit change numbers"
+  },
+  {
+    "cmd": [],
+    "name": "get gerrit change numbers.ensure infra/tools/luci/gerrit/${platform}",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@"
+    ]
+  },
+  {
+    "cmd": [],
+    "name": "get gerrit change numbers.ensure infra/tools/luci/gerrit/${platform}.get packages",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@2@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "vpython3",
+      "-u",
+      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
+      "--json-output",
+      "/path/to/tmp/json",
+      "copy",
+      "RECIPE_MODULE[fuchsia::gerrit]/resources/cipd.ensure",
+      "/path/to/tmp/"
+    ],
+    "infra_step": true,
+    "name": "get gerrit change numbers.ensure infra/tools/luci/gerrit/${platform}.get packages.read ensure file",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@3@@@",
+      "@@@STEP_LOG_LINE@cipd.ensure@infra/tools/luci/gerrit/${platform} version:pinned-version@@@",
+      "@@@STEP_LOG_END@cipd.ensure@@@"
+    ]
+  },
+  {
+    "cmd": [],
+    "name": "get gerrit change numbers.ensure infra/tools/luci/gerrit/${platform}.install infra/tools/luci/gerrit",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@2@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "vpython3",
+      "-u",
+      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
+      "--json-output",
+      "/path/to/tmp/json",
+      "ensure-directory",
+      "--mode",
+      "0o777",
+      "[START_DIR]/cipd_tool/infra/tools/luci/gerrit/0e548aa33f8113a45a5b3b62201e114e98e63d00f97296912380138f44597b07"
+    ],
+    "infra_step": true,
+    "name": "get gerrit change numbers.ensure infra/tools/luci/gerrit/${platform}.install infra/tools/luci/gerrit.ensure package directory",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@3@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "cipd",
+      "ensure",
+      "-root",
+      "[START_DIR]/cipd_tool/infra/tools/luci/gerrit/0e548aa33f8113a45a5b3b62201e114e98e63d00f97296912380138f44597b07",
+      "-ensure-file",
+      "infra/tools/luci/gerrit/${platform} version:pinned-version",
+      "-max-threads",
+      "0",
+      "-json-output",
+      "/path/to/tmp/json"
+    ],
+    "infra_step": true,
+    "name": "get gerrit change numbers.ensure infra/tools/luci/gerrit/${platform}.install infra/tools/luci/gerrit.ensure_installed",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@3@@@",
+      "@@@STEP_LOG_LINE@json.output@{@@@",
+      "@@@STEP_LOG_LINE@json.output@  \"result\": {@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"\": [@@@",
+      "@@@STEP_LOG_LINE@json.output@      {@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"instance_id\": \"resolved-instance_id-of-version:pinned-v\",@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"package\": \"infra/tools/luci/gerrit/resolved-platform\"@@@",
+      "@@@STEP_LOG_LINE@json.output@      }@@@",
+      "@@@STEP_LOG_LINE@json.output@    ]@@@",
+      "@@@STEP_LOG_LINE@json.output@  }@@@",
+      "@@@STEP_LOG_LINE@json.output@}@@@",
+      "@@@STEP_LOG_END@json.output@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "[START_DIR]/cipd_tool/infra/tools/luci/gerrit/0e548aa33f8113a45a5b3b62201e114e98e63d00f97296912380138f44597b07/gerrit",
+      "change-detail",
+      "-host",
+      "https://bar-review.googlesource.com",
+      "-input",
+      "{\"change_id\": \"3e30158f2a7caccb7a9f6632a60011e7a44e1e5c\"}",
+      "-output",
+      "/path/to/tmp/json"
+    ],
+    "infra_step": true,
+    "name": "get gerrit change numbers.change details for 3e30158",
+    "timeout": 600,
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@",
+      "@@@STEP_LOG_LINE@json.output@{@@@",
+      "@@@STEP_LOG_LINE@json.output@  \"_number\": 12345@@@",
+      "@@@STEP_LOG_LINE@json.output@}@@@",
+      "@@@STEP_LOG_END@json.output@@@",
+      "@@@STEP_LOG_LINE@json.input@{@@@",
+      "@@@STEP_LOG_LINE@json.input@  \"change_id\": \"3e30158f2a7caccb7a9f6632a60011e7a44e1e5c\"@@@",
+      "@@@STEP_LOG_LINE@json.input@}@@@",
+      "@@@STEP_LOG_END@json.input@@@",
+      "@@@STEP_LINK@gerrit link@https://bar-review.googlesource.com/q/3e30158f2a7caccb7a9f6632a60011e7a44e1e5c@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "[START_DIR]/cipd_tool/infra/tools/luci/gerrit/0e548aa33f8113a45a5b3b62201e114e98e63d00f97296912380138f44597b07/gerrit",
+      "change-detail",
+      "-host",
+      "https://bar-review.googlesource.com",
+      "-input",
+      "{\"change_id\": \"3380b83c11e029b7291c83c44e7b1ce09d465fd1\"}",
+      "-output",
+      "/path/to/tmp/json"
+    ],
+    "infra_step": true,
+    "name": "get gerrit change numbers.change details for 3380b83",
+    "timeout": 600,
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@",
+      "@@@STEP_LOG_LINE@json.output@{@@@",
+      "@@@STEP_LOG_LINE@json.output@  \"_number\": 12345@@@",
+      "@@@STEP_LOG_LINE@json.output@}@@@",
+      "@@@STEP_LOG_END@json.output@@@",
+      "@@@STEP_LOG_LINE@json.input@{@@@",
+      "@@@STEP_LOG_LINE@json.input@  \"change_id\": \"3380b83c11e029b7291c83c44e7b1ce09d465fd1\"@@@",
+      "@@@STEP_LOG_LINE@json.input@}@@@",
+      "@@@STEP_LOG_END@json.input@@@",
+      "@@@STEP_LINK@gerrit link@https://bar-review.googlesource.com/q/3380b83c11e029b7291c83c44e7b1ce09d465fd1@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "[START_DIR]/cipd_tool/infra/tools/luci/gerrit/0e548aa33f8113a45a5b3b62201e114e98e63d00f97296912380138f44597b07/gerrit",
+      "change-detail",
+      "-host",
+      "https://bar-review.googlesource.com",
+      "-input",
+      "{\"change_id\": \"363caa907186de786cb5292cd1ab7245da954815\"}",
+      "-output",
+      "/path/to/tmp/json"
+    ],
+    "infra_step": true,
+    "name": "get gerrit change numbers.change details for 363caa9",
+    "timeout": 600,
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@",
+      "@@@STEP_LOG_LINE@json.output@{@@@",
+      "@@@STEP_LOG_LINE@json.output@  \"_number\": 12345@@@",
+      "@@@STEP_LOG_LINE@json.output@}@@@",
+      "@@@STEP_LOG_END@json.output@@@",
+      "@@@STEP_LOG_LINE@json.input@{@@@",
+      "@@@STEP_LOG_LINE@json.input@  \"change_id\": \"363caa907186de786cb5292cd1ab7245da954815\"@@@",
+      "@@@STEP_LOG_LINE@json.input@}@@@",
+      "@@@STEP_LOG_END@json.input@@@",
+      "@@@STEP_LINK@gerrit link@https://bar-review.googlesource.com/q/363caa907186de786cb5292cd1ab7245da954815@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "vpython3",
+      "-u",
+      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
+      "--json-output",
+      "/path/to/tmp/json",
       "copy",
       "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<manifest>\n  <!-- single-line comment -->\n  <remote fetch=\"sso://foo\" name=\"foo\" review=\"sso://foo\" />\n  <remote fetch=\"sso://bar\" name=\"bar\" review=\"sso://bar\" />\n  <remote fetch=\"..\" name=\"host\" review=\"sso://host\" />\n  <remote fetch=\"../prefix\" name=\"dotdot-prefix\" review=\"sso://host/prefix\" />\n  <remote fetch=\"sso://host/prefix\" name=\"host-prefix\" review=\"sso://host/prefix\" />\n  <default remote=\"bar\" />\n  <project name=\"a\" path=\"a1\" remote=\"foo\" revision=\"1111111111111111111111111111111111111111\" upstream=\"main\" />\n  <project name=\"b\" path=\"b2\" revision=\"h3ll0\" upstream=\"main\" />\n  <!--\n  multi\n  line\n  comment\n  -->\n  <project name=\"c\" path=\"c3\" revision=\"main\" />\n  <project name=\"d\" path=\"d4\" revision=\"0000000000111111111122222222223333333333\" />\n  <project name=\"e5\" revision=\"refs/tags/e\" />\n  <project name=\"f\" path=\"f6\" remote=\"host\" revision=\"main\" />\n  <project name=\"g\" path=\"g7\" remote=\"dotdot-prefix\" revision=\"main\" />\n  <project name=\"h\" path=\"h8\" remote=\"host-prefix\" revision=\"main\" />\n</manifest>\n",
       "[START_DIR]/checkout/default.xml"
@@ -660,240 +460,22 @@
   },
   {
     "cmd": [],
-    "name": "remote"
-  },
-  {
-    "cmd": [
-      "git",
-      "remote"
-    ],
-    "cwd": "[START_DIR]/project",
-    "name": "remote.name",
-    "timeout": 600.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "remote",
-      "get-url",
-      "origin"
-    ],
-    "cwd": "[START_DIR]/project",
-    "name": "remote.url",
-    "timeout": 600.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "b2"
-  },
-  {
-    "cmd": [
-      "git",
-      "log",
-      "--pretty=format:%H\n%an\n%ae\n%B",
-      "-z",
-      "2222222222222222222222222222222222222222..h3ll0"
-    ],
-    "cwd": "[START_DIR]/project",
-    "name": "b2.git log",
-    "timeout": 600.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "b2.ensure infra/tools/luci/gerrit/${platform}",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "b2.ensure infra/tools/luci/gerrit/${platform}.get packages",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "vpython3",
-      "-u",
-      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
-      "--json-output",
-      "/path/to/tmp/json",
-      "copy",
-      "RECIPE_MODULE[fuchsia::gerrit]/resources/cipd.ensure",
-      "/path/to/tmp/"
-    ],
-    "cwd": "[START_DIR]/project",
-    "infra_step": true,
-    "name": "b2.ensure infra/tools/luci/gerrit/${platform}.get packages.read ensure file",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@3@@@",
-      "@@@STEP_LOG_LINE@cipd.ensure@infra/tools/luci/gerrit/${platform} version:pinned-version@@@",
-      "@@@STEP_LOG_END@cipd.ensure@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "b2.ensure infra/tools/luci/gerrit/${platform}.install infra/tools/luci/gerrit",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "vpython3",
-      "-u",
-      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
-      "--json-output",
-      "/path/to/tmp/json",
-      "ensure-directory",
-      "--mode",
-      "0o777",
-      "[START_DIR]/cipd_tool/infra/tools/luci/gerrit/0e548aa33f8113a45a5b3b62201e114e98e63d00f97296912380138f44597b07"
-    ],
-    "cwd": "[START_DIR]/project",
-    "infra_step": true,
-    "name": "b2.ensure infra/tools/luci/gerrit/${platform}.install infra/tools/luci/gerrit.ensure package directory",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@3@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "cipd",
-      "ensure",
-      "-root",
-      "[START_DIR]/cipd_tool/infra/tools/luci/gerrit/0e548aa33f8113a45a5b3b62201e114e98e63d00f97296912380138f44597b07",
-      "-ensure-file",
-      "infra/tools/luci/gerrit/${platform} version:pinned-version",
-      "-max-threads",
-      "0",
-      "-json-output",
-      "/path/to/tmp/json"
-    ],
-    "cwd": "[START_DIR]/project",
-    "infra_step": true,
-    "name": "b2.ensure infra/tools/luci/gerrit/${platform}.install infra/tools/luci/gerrit.ensure_installed",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@3@@@",
-      "@@@STEP_LOG_LINE@json.output@{@@@",
-      "@@@STEP_LOG_LINE@json.output@  \"result\": {@@@",
-      "@@@STEP_LOG_LINE@json.output@    \"\": [@@@",
-      "@@@STEP_LOG_LINE@json.output@      {@@@",
-      "@@@STEP_LOG_LINE@json.output@        \"instance_id\": \"resolved-instance_id-of-version:pinned-v\",@@@",
-      "@@@STEP_LOG_LINE@json.output@        \"package\": \"infra/tools/luci/gerrit/resolved-platform\"@@@",
-      "@@@STEP_LOG_LINE@json.output@      }@@@",
-      "@@@STEP_LOG_LINE@json.output@    ]@@@",
-      "@@@STEP_LOG_LINE@json.output@  }@@@",
-      "@@@STEP_LOG_LINE@json.output@}@@@",
-      "@@@STEP_LOG_END@json.output@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "[START_DIR]/cipd_tool/infra/tools/luci/gerrit/0e548aa33f8113a45a5b3b62201e114e98e63d00f97296912380138f44597b07/gerrit",
-      "change-query",
-      "-host",
-      "https://pigweed-review.googlesource.com",
-      "-input",
-      "{\"params\": {\"q\": \"commit:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\"}}",
-      "-output",
-      "/path/to/tmp/json"
-    ],
-    "cwd": "[START_DIR]/project",
-    "infra_step": true,
-    "name": "b2.get change-id",
-    "timeout": 600,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@",
-      "@@@STEP_LOG_LINE@json.output@[@@@",
-      "@@@STEP_LOG_LINE@json.output@  {@@@",
-      "@@@STEP_LOG_LINE@json.output@    \"_number\": 12345@@@",
-      "@@@STEP_LOG_LINE@json.output@  }@@@",
-      "@@@STEP_LOG_LINE@json.output@]@@@",
-      "@@@STEP_LOG_END@json.output@@@",
-      "@@@STEP_LOG_LINE@json.input@{@@@",
-      "@@@STEP_LOG_LINE@json.input@  \"params\": {@@@",
-      "@@@STEP_LOG_LINE@json.input@    \"q\": \"commit:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\"@@@",
-      "@@@STEP_LOG_LINE@json.input@  }@@@",
-      "@@@STEP_LOG_LINE@json.input@}@@@",
-      "@@@STEP_LOG_END@json.input@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "[START_DIR]/cipd_tool/infra/tools/luci/gerrit/0e548aa33f8113a45a5b3b62201e114e98e63d00f97296912380138f44597b07/gerrit",
-      "change-detail",
-      "-host",
-      "https://pigweed-review.googlesource.com",
-      "-input",
-      "{\"change_id\": \"12345\"}",
-      "-output",
-      "/path/to/tmp/json"
-    ],
-    "cwd": "[START_DIR]/project",
-    "infra_step": true,
-    "name": "b2.get 12345",
-    "timeout": 600,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@",
-      "@@@STEP_LOG_LINE@json.output@{@@@",
-      "@@@STEP_LOG_LINE@json.output@  \"owner\": {@@@",
-      "@@@STEP_LOG_LINE@json.output@    \"email\": \"author@example.com\",@@@",
-      "@@@STEP_LOG_LINE@json.output@    \"name\": \"author\"@@@",
-      "@@@STEP_LOG_LINE@json.output@  },@@@",
-      "@@@STEP_LOG_LINE@json.output@  \"reviewers\": {@@@",
-      "@@@STEP_LOG_LINE@json.output@    \"REVIEWER\": [@@@",
-      "@@@STEP_LOG_LINE@json.output@      {@@@",
-      "@@@STEP_LOG_LINE@json.output@        \"email\": \"reviewer@example.com\",@@@",
-      "@@@STEP_LOG_LINE@json.output@        \"name\": \"reviewer\"@@@",
-      "@@@STEP_LOG_LINE@json.output@      },@@@",
-      "@@@STEP_LOG_LINE@json.output@      {@@@",
-      "@@@STEP_LOG_LINE@json.output@        \"email\": \"nobody@google.com\",@@@",
-      "@@@STEP_LOG_LINE@json.output@        \"name\": \"nobody\"@@@",
-      "@@@STEP_LOG_LINE@json.output@      },@@@",
-      "@@@STEP_LOG_LINE@json.output@      {@@@",
-      "@@@STEP_LOG_LINE@json.output@        \"email\": \"robot@gserviceaccount.com\",@@@",
-      "@@@STEP_LOG_LINE@json.output@        \"name\": \"robot\"@@@",
-      "@@@STEP_LOG_LINE@json.output@      }@@@",
-      "@@@STEP_LOG_LINE@json.output@    ]@@@",
-      "@@@STEP_LOG_LINE@json.output@  }@@@",
-      "@@@STEP_LOG_LINE@json.output@}@@@",
-      "@@@STEP_LOG_END@json.output@@@",
-      "@@@STEP_LOG_LINE@json.input@{@@@",
-      "@@@STEP_LOG_LINE@json.input@  \"change_id\": \"12345\"@@@",
-      "@@@STEP_LOG_LINE@json.input@}@@@",
-      "@@@STEP_LOG_END@json.input@@@",
-      "@@@STEP_LINK@gerrit link@https://pigweed-review.googlesource.com/q/12345@@@"
-    ]
-  },
-  {
-    "cmd": [],
     "name": "roll"
   },
   {
     "cmd": [],
-    "name": "roll.project_name",
+    "name": "roll.repo_url",
     "~followup_annotations": [
       "@@@STEP_NEST_LEVEL@1@@@",
-      "@@@STEP_SUMMARY_TEXT@b2@@@"
+      "@@@STEP_SUMMARY_TEXT@https://bar.googlesource.com/b@@@"
     ]
   },
   {
     "cmd": [],
-    "name": "roll.proj_dir",
+    "name": "roll.repo_short_name",
     "~followup_annotations": [
       "@@@STEP_NEST_LEVEL@1@@@",
-      "@@@STEP_SUMMARY_TEXT@[START_DIR]/project@@@"
+      "@@@STEP_SUMMARY_TEXT@b2@@@"
     ]
   },
   {
@@ -914,10 +496,10 @@
   },
   {
     "cmd": [],
-    "name": "roll.direction",
+    "name": "roll.commit message",
     "~followup_annotations": [
       "@@@STEP_NEST_LEVEL@1@@@",
-      "@@@STEP_SUMMARY_TEXT@Direction.FORWARD@@@"
+      "@@@STEP_SUMMARY_TEXT@[roll] Roll b2 2222222..h3ll0 (3 commits)\n\n3e30158:https://bar-review.googlesource.com/c/b/+/12345 fake A msg 0\n3380b83:https://bar-review.googlesource.com/c/b/+/12345 fake A msg 1\n363caa9:https://bar-review.googlesource.com/c/b/+/12345 fake A msg 2\n\nRolled-Repo: https://bar.googlesource.com/b\nRolled-Commits: 22222222222222..h3ll0@@@"
     ]
   },
   {
diff --git a/recipe_modules/repo_roll/tests/full.expected/host-dot-dot.json b/recipe_modules/repo_roll/tests/full.expected/host-dot-dot.json
index 027f72b..ef40780 100644
--- a/recipe_modules/repo_roll/tests/full.expected/host-dot-dot.json
+++ b/recipe_modules/repo_roll/tests/full.expected/host-dot-dot.json
@@ -57,50 +57,25 @@
   },
   {
     "cmd": [],
-    "name": "checkout f"
+    "name": "ensure infra/tools/luci/gitiles/${platform}"
   },
   {
     "cmd": [],
-    "name": "checkout f.options",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@",
-      "@@@STEP_SUMMARY_TEXT@remote: \"https://host.googlesource.com/f\"\nbranch: \"main\"\n@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "checkout f.options with defaults",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@",
-      "@@@STEP_SUMMARY_TEXT@remote: \"https://host.googlesource.com/f\"\nbranch: \"main\"\nmanifest_file: \"default.xml\"\nrepo_init_timeout_sec: 20\nrepo_sync_timeout_sec: 120\nnumber_of_attempts: 3\nsubmodule_timeout_sec: 600\n@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "checkout f.not matching branch names",
+    "name": "ensure infra/tools/luci/gitiles/${platform}.get packages",
     "~followup_annotations": [
       "@@@STEP_NEST_LEVEL@1@@@"
     ]
   },
   {
-    "cmd": [],
-    "name": "checkout f.cache",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@",
-      "@@@STEP_SUMMARY_TEXT@miss@@@"
-    ]
-  },
-  {
     "cmd": [
       "vpython3",
       "-u",
       "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
       "--json-output",
       "/path/to/tmp/json",
-      "ensure-directory",
-      "--mode",
-      "0o777",
-      "[CACHE]/git"
+      "copy",
+      "RECIPE_MODULE[fuchsia::gitiles]/resources/cipd.ensure",
+      "/path/to/tmp/"
     ],
     "infra_step": true,
     "luci_context": {
@@ -115,7 +90,220 @@
         "hostname": "rdbhost"
       }
     },
-    "name": "checkout f.cache.ensure git cache dir",
+    "name": "ensure infra/tools/luci/gitiles/${platform}.get packages.read ensure file",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@2@@@",
+      "@@@STEP_LOG_LINE@cipd.ensure@infra/tools/luci/gitiles/${platform} version:pinned-version@@@",
+      "@@@STEP_LOG_END@cipd.ensure@@@"
+    ]
+  },
+  {
+    "cmd": [],
+    "name": "ensure infra/tools/luci/gitiles/${platform}.install infra/tools/luci/gitiles",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "vpython3",
+      "-u",
+      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
+      "--json-output",
+      "/path/to/tmp/json",
+      "ensure-directory",
+      "--mode",
+      "0o777",
+      "[START_DIR]/cipd_tool/infra/tools/luci/gitiles/0e548aa33f8113a45a5b3b62201e114e98e63d00f97296912380138f44597b07"
+    ],
+    "infra_step": true,
+    "luci_context": {
+      "realm": {
+        "name": "project:ci"
+      },
+      "resultdb": {
+        "current_invocation": {
+          "name": "invocations/build:8945511751514863184",
+          "update_token": "token"
+        },
+        "hostname": "rdbhost"
+      }
+    },
+    "name": "ensure infra/tools/luci/gitiles/${platform}.install infra/tools/luci/gitiles.ensure package directory",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@2@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "cipd",
+      "ensure",
+      "-root",
+      "[START_DIR]/cipd_tool/infra/tools/luci/gitiles/0e548aa33f8113a45a5b3b62201e114e98e63d00f97296912380138f44597b07",
+      "-ensure-file",
+      "infra/tools/luci/gitiles/${platform} version:pinned-version",
+      "-max-threads",
+      "0",
+      "-json-output",
+      "/path/to/tmp/json"
+    ],
+    "infra_step": true,
+    "luci_context": {
+      "realm": {
+        "name": "project:ci"
+      },
+      "resultdb": {
+        "current_invocation": {
+          "name": "invocations/build:8945511751514863184",
+          "update_token": "token"
+        },
+        "hostname": "rdbhost"
+      }
+    },
+    "name": "ensure infra/tools/luci/gitiles/${platform}.install infra/tools/luci/gitiles.ensure_installed",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@2@@@",
+      "@@@STEP_LOG_LINE@json.output@{@@@",
+      "@@@STEP_LOG_LINE@json.output@  \"result\": {@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"\": [@@@",
+      "@@@STEP_LOG_LINE@json.output@      {@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"instance_id\": \"resolved-instance_id-of-version:pinned-v\",@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"package\": \"infra/tools/luci/gitiles/resolved-platform\"@@@",
+      "@@@STEP_LOG_LINE@json.output@      }@@@",
+      "@@@STEP_LOG_LINE@json.output@    ]@@@",
+      "@@@STEP_LOG_LINE@json.output@  }@@@",
+      "@@@STEP_LOG_LINE@json.output@}@@@",
+      "@@@STEP_LOG_END@json.output@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "[START_DIR]/cipd_tool/infra/tools/luci/gitiles/0e548aa33f8113a45a5b3b62201e114e98e63d00f97296912380138f44597b07/gitiles",
+      "log",
+      "-json-output",
+      "/path/to/tmp/json",
+      "https://host.googlesource.com/f",
+      "main..2d72510e447ab60a9728aeea2362d8be2cbd7789"
+    ],
+    "infra_step": true,
+    "luci_context": {
+      "realm": {
+        "name": "project:ci"
+      },
+      "resultdb": {
+        "current_invocation": {
+          "name": "invocations/build:8945511751514863184",
+          "update_token": "token"
+        },
+        "hostname": "rdbhost"
+      }
+    },
+    "name": "log f6",
+    "timeout": 300.0,
+    "~followup_annotations": [
+      "@@@STEP_LOG_LINE@json.output@[@@@",
+      "@@@STEP_LOG_LINE@json.output@  {@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"author\": {@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"email\": \"fake_A@fake_0.email.com\",@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"name\": \"Fake A\",@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"time\": \"Mon Jan 01 00:00:00 2015\"@@@",
+      "@@@STEP_LOG_LINE@json.output@    },@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"committer\": {@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"email\": \"fake_A@fake_0.email.com\",@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"name\": \"Fake A\",@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"time\": \"Mon Jan 01 00:00:00 2015\"@@@",
+      "@@@STEP_LOG_LINE@json.output@    },@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"id\": \"3e30158f2a7caccb7a9f6632a60011e7a44e1e5c\",@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"message\": \"fake A msg 0\",@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"parents\": [@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"83a7614b3b60951511be50db1b9561daff4bb447\"@@@",
+      "@@@STEP_LOG_LINE@json.output@    ],@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"tree\": \"1b6412b24ec3add84836c8fdd1af5ac8e35b61d9\",@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"tree_diff\": [@@@",
+      "@@@STEP_LOG_LINE@json.output@      {@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"new_id\": \"8bea05ad53680fce6937543f0d98cd48e295b8ff\",@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"new_mode\": 33188,@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"new_path\": \"a.py\",@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"old_id\": \"0000000000000000000000000000000000000000\",@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"old_mode\": 0,@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"type\": \"add\"@@@",
+      "@@@STEP_LOG_LINE@json.output@      }@@@",
+      "@@@STEP_LOG_LINE@json.output@    ]@@@",
+      "@@@STEP_LOG_LINE@json.output@  },@@@",
+      "@@@STEP_LOG_LINE@json.output@  {@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"author\": {@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"email\": \"fake_A@fake_1.email.com\",@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"name\": \"Fake A\",@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"time\": \"Mon Jan 01 00:00:00 2015\"@@@",
+      "@@@STEP_LOG_LINE@json.output@    },@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"committer\": {@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"email\": \"fake_A@fake_1.email.com\",@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"name\": \"Fake A\",@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"time\": \"Mon Jan 01 00:00:00 2015\"@@@",
+      "@@@STEP_LOG_LINE@json.output@    },@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"id\": \"3380b83c11e029b7291c83c44e7b1ce09d465fd1\",@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"message\": \"fake A msg 1\",@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"parents\": [@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"8675a52c73c701cb0b2c48f5ed4a9058c624e6cd\"@@@",
+      "@@@STEP_LOG_LINE@json.output@    ],@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"tree\": \"a1b1e6aa501915989b45a95e1224ec2a88655eb3\",@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"tree_diff\": [@@@",
+      "@@@STEP_LOG_LINE@json.output@      {@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"new_id\": \"06bc4c79002f278528aaddae4e056a11f58c19ad\",@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"new_mode\": 33188,@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"new_path\": \"b.py\",@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"old_id\": \"0000000000000000000000000000000000000000\",@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"old_mode\": 0,@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"type\": \"add\"@@@",
+      "@@@STEP_LOG_LINE@json.output@      }@@@",
+      "@@@STEP_LOG_LINE@json.output@    ]@@@",
+      "@@@STEP_LOG_LINE@json.output@  },@@@",
+      "@@@STEP_LOG_LINE@json.output@  {@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"author\": {@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"email\": \"fake_A@fake_2.email.com\",@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"name\": \"Fake A\",@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"time\": \"Mon Jan 01 00:00:00 2015\"@@@",
+      "@@@STEP_LOG_LINE@json.output@    },@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"committer\": {@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"email\": \"fake_A@fake_2.email.com\",@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"name\": \"Fake A\",@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"time\": \"Mon Jan 01 00:00:00 2015\"@@@",
+      "@@@STEP_LOG_LINE@json.output@    },@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"id\": \"363caa907186de786cb5292cd1ab7245da954815\",@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"message\": \"fake A msg 2\",@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"parents\": [@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"255c6325c4c654e17e6b35142e3912c86f1718f2\"@@@",
+      "@@@STEP_LOG_LINE@json.output@    ],@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"tree\": \"e84d4ad259e69da73d2b842e2b9709f08e8b22bd\",@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"tree_diff\": [@@@",
+      "@@@STEP_LOG_LINE@json.output@      {@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"new_id\": \"d7f478bf423219f2f47c1a6ed344fc597a8bf18f\",@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"new_mode\": 33188,@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"new_path\": \"c.py\",@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"old_id\": \"0000000000000000000000000000000000000000\",@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"old_mode\": 0,@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"type\": \"add\"@@@",
+      "@@@STEP_LOG_LINE@json.output@      }@@@",
+      "@@@STEP_LOG_LINE@json.output@    ]@@@",
+      "@@@STEP_LOG_LINE@json.output@  }@@@",
+      "@@@STEP_LOG_LINE@json.output@]@@@",
+      "@@@STEP_LOG_END@json.output@@@"
+    ]
+  },
+  {
+    "cmd": [],
+    "name": "get gerrit change numbers"
+  },
+  {
+    "cmd": [],
+    "name": "get gerrit change numbers.ensure infra/tools/luci/gerrit/${platform}",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@"
+    ]
+  },
+  {
+    "cmd": [],
+    "name": "get gerrit change numbers.ensure infra/tools/luci/gerrit/${platform}.get packages",
     "~followup_annotations": [
       "@@@STEP_NEST_LEVEL@2@@@"
     ]
@@ -128,8 +316,8 @@
       "--json-output",
       "/path/to/tmp/json",
       "copy",
-      "",
-      "[CACHE]/git/.GUARD_FILE"
+      "RECIPE_MODULE[fuchsia::gerrit]/resources/cipd.ensure",
+      "/path/to/tmp/"
     ],
     "infra_step": true,
     "luci_context": {
@@ -144,7 +332,16 @@
         "hostname": "rdbhost"
       }
     },
-    "name": "checkout f.cache.write git cache guard file",
+    "name": "get gerrit change numbers.ensure infra/tools/luci/gerrit/${platform}.get packages.read ensure file",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@3@@@",
+      "@@@STEP_LOG_LINE@cipd.ensure@infra/tools/luci/gerrit/${platform} version:pinned-version@@@",
+      "@@@STEP_LOG_END@cipd.ensure@@@"
+    ]
+  },
+  {
+    "cmd": [],
+    "name": "get gerrit change numbers.ensure infra/tools/luci/gerrit/${platform}.install infra/tools/luci/gerrit",
     "~followup_annotations": [
       "@@@STEP_NEST_LEVEL@2@@@"
     ]
@@ -159,7 +356,7 @@
       "ensure-directory",
       "--mode",
       "0o777",
-      "[CACHE]/git/host.googlesource.com-f"
+      "[START_DIR]/cipd_tool/infra/tools/luci/gerrit/0e548aa33f8113a45a5b3b62201e114e98e63d00f97296912380138f44597b07"
     ],
     "infra_step": true,
     "luci_context": {
@@ -174,17 +371,24 @@
         "hostname": "rdbhost"
       }
     },
-    "name": "checkout f.cache.makedirs",
+    "name": "get gerrit change numbers.ensure infra/tools/luci/gerrit/${platform}.install infra/tools/luci/gerrit.ensure package directory",
     "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
+      "@@@STEP_NEST_LEVEL@3@@@"
     ]
   },
   {
     "cmd": [
-      "git",
-      "init"
+      "cipd",
+      "ensure",
+      "-root",
+      "[START_DIR]/cipd_tool/infra/tools/luci/gerrit/0e548aa33f8113a45a5b3b62201e114e98e63d00f97296912380138f44597b07",
+      "-ensure-file",
+      "infra/tools/luci/gerrit/${platform} version:pinned-version",
+      "-max-threads",
+      "0",
+      "-json-output",
+      "/path/to/tmp/json"
     ],
-    "cwd": "[CACHE]/git/host.googlesource.com-f",
     "infra_step": true,
     "luci_context": {
       "realm": {
@@ -198,20 +402,33 @@
         "hostname": "rdbhost"
       }
     },
-    "name": "checkout f.cache.git init",
-    "timeout": 300.0,
+    "name": "get gerrit change numbers.ensure infra/tools/luci/gerrit/${platform}.install infra/tools/luci/gerrit.ensure_installed",
     "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
+      "@@@STEP_NEST_LEVEL@3@@@",
+      "@@@STEP_LOG_LINE@json.output@{@@@",
+      "@@@STEP_LOG_LINE@json.output@  \"result\": {@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"\": [@@@",
+      "@@@STEP_LOG_LINE@json.output@      {@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"instance_id\": \"resolved-instance_id-of-version:pinned-v\",@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"package\": \"infra/tools/luci/gerrit/resolved-platform\"@@@",
+      "@@@STEP_LOG_LINE@json.output@      }@@@",
+      "@@@STEP_LOG_LINE@json.output@    ]@@@",
+      "@@@STEP_LOG_LINE@json.output@  }@@@",
+      "@@@STEP_LOG_LINE@json.output@}@@@",
+      "@@@STEP_LOG_END@json.output@@@"
     ]
   },
   {
     "cmd": [
-      "git",
-      "config",
-      "remote.origin.url",
-      "https://host.googlesource.com/f"
+      "[START_DIR]/cipd_tool/infra/tools/luci/gerrit/0e548aa33f8113a45a5b3b62201e114e98e63d00f97296912380138f44597b07/gerrit",
+      "change-detail",
+      "-host",
+      "https://host-review.googlesource.com",
+      "-input",
+      "{\"change_id\": \"3e30158f2a7caccb7a9f6632a60011e7a44e1e5c\"}",
+      "-output",
+      "/path/to/tmp/json"
     ],
-    "cwd": "[CACHE]/git/host.googlesource.com-f",
     "infra_step": true,
     "luci_context": {
       "realm": {
@@ -225,149 +442,31 @@
         "hostname": "rdbhost"
       }
     },
-    "name": "checkout f.cache.remote set-url",
-    "timeout": 300.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "config",
-      "fetch.uriprotocols",
-      "https"
-    ],
-    "cwd": "[CACHE]/git/host.googlesource.com-f",
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout f.cache.set fetch.uriprotocols",
-    "timeout": 300.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "checkout f.cache.timeout 10s",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "fetch",
-      "--prune",
-      "--tags",
-      "--jobs",
-      "4",
-      "origin",
-      "--no-recurse-submodules"
-    ],
-    "cwd": "[CACHE]/git/host.googlesource.com-f",
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout f.cache.git fetch",
-    "timeout": 1200.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "merge",
-      "FETCH_HEAD"
-    ],
-    "cwd": "[CACHE]/git/host.googlesource.com-f",
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout f.cache.git merge",
-    "timeout": 600.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "checkout f.cache.timeout 10s (2)",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "submodule",
-      "update",
-      "--recursive",
-      "--force",
-      "--jobs",
-      "4"
-    ],
-    "cwd": "[CACHE]/git/host.googlesource.com-f",
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout f.cache.git submodule update",
+    "name": "get gerrit change numbers.change details for 3e30158",
     "timeout": 600,
     "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
+      "@@@STEP_NEST_LEVEL@1@@@",
+      "@@@STEP_LOG_LINE@json.output@{@@@",
+      "@@@STEP_LOG_LINE@json.output@  \"_number\": 12345@@@",
+      "@@@STEP_LOG_LINE@json.output@}@@@",
+      "@@@STEP_LOG_END@json.output@@@",
+      "@@@STEP_LOG_LINE@json.input@{@@@",
+      "@@@STEP_LOG_LINE@json.input@  \"change_id\": \"3e30158f2a7caccb7a9f6632a60011e7a44e1e5c\"@@@",
+      "@@@STEP_LOG_LINE@json.input@}@@@",
+      "@@@STEP_LOG_END@json.input@@@",
+      "@@@STEP_LINK@gerrit link@https://host-review.googlesource.com/q/3e30158f2a7caccb7a9f6632a60011e7a44e1e5c@@@"
     ]
   },
   {
     "cmd": [
-      "vpython3",
-      "-u",
-      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
-      "--json-output",
-      "/path/to/tmp/json",
-      "remove",
-      "[CACHE]/git/.GUARD_FILE"
+      "[START_DIR]/cipd_tool/infra/tools/luci/gerrit/0e548aa33f8113a45a5b3b62201e114e98e63d00f97296912380138f44597b07/gerrit",
+      "change-detail",
+      "-host",
+      "https://host-review.googlesource.com",
+      "-input",
+      "{\"change_id\": \"3380b83c11e029b7291c83c44e7b1ce09d465fd1\"}",
+      "-output",
+      "/path/to/tmp/json"
     ],
     "infra_step": true,
     "luci_context": {
@@ -382,516 +481,31 @@
         "hostname": "rdbhost"
       }
     },
-    "name": "checkout f.cache.remove git cache guard file",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "vpython3",
-      "-u",
-      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
-      "--json-output",
-      "/path/to/tmp/json",
-      "copytree",
-      "--symlinks",
-      "[CACHE]/git/host.googlesource.com-f",
-      "[START_DIR]/project"
-    ],
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout f.copy from cache",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "checkout f.git checkout",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "checkout f.git checkout.timeout 10s",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "vpython3",
-      "-u",
-      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
-      "--json-output",
-      "/path/to/tmp/json",
-      "ensure-directory",
-      "--mode",
-      "0o777",
-      "[START_DIR]/project"
-    ],
-    "infra_step": true,
-    "luci_context": {
-      "deadline": {
-        "grace_period": 30.0,
-        "soft_deadline": 1337000019.0
-      },
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout f.git checkout.makedirs",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "init"
-    ],
-    "cwd": "[START_DIR]/project",
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout f.git checkout.git init",
-    "timeout": 300.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "remote",
-      "add",
-      "origin",
-      "https://host.googlesource.com/f"
-    ],
-    "cwd": "[START_DIR]/project",
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout f.git checkout.git remote",
-    "timeout": 600.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "config",
-      "core.longpaths",
-      "true"
-    ],
-    "cwd": "[START_DIR]/project",
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout f.git checkout.set core.longpaths",
-    "timeout": 300.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "config",
-      "fetch.uriprotocols",
-      "https"
-    ],
-    "cwd": "[START_DIR]/project",
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout f.git checkout.set fetch.uriprotocols",
-    "timeout": 300.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "fetch",
-      "--tags",
-      "--jobs",
-      "4",
-      "origin",
-      "main"
-    ],
-    "cwd": "[START_DIR]/project",
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout f.git checkout.git fetch",
-    "timeout": 1200.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "checkout",
-      "-f",
-      "FETCH_HEAD"
-    ],
-    "cwd": "[START_DIR]/project",
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout f.git checkout.git checkout",
-    "timeout": 600.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "rev-parse",
-      "HEAD"
-    ],
-    "cwd": "[START_DIR]/project",
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout f.git checkout.git rev-parse",
-    "timeout": 300.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "clean",
-      "-f",
-      "-d",
-      "-x"
-    ],
-    "cwd": "[START_DIR]/project",
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout f.git checkout.git clean",
-    "timeout": 600.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "checkout f.git log",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "log",
-      "--oneline",
-      "-n",
-      "10"
-    ],
-    "cwd": "[START_DIR]/project",
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout f.git log.[START_DIR]/project",
-    "timeout": 600.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "clean",
-      "-f",
-      "-f",
-      "-d"
-    ],
-    "cwd": "[START_DIR]/project",
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout f.git clean",
-    "timeout": 600.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "status"
-    ],
-    "cwd": "[START_DIR]/project",
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout f.git status",
-    "timeout": 600.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "vpython3",
-      "-u",
-      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
-      "--json-output",
-      "/path/to/tmp/json",
-      "ensure-directory",
-      "--mode",
-      "0o777",
-      "[START_DIR]/snapshot"
-    ],
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout f.mkdir",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "submodule",
-      "status",
-      "--recursive"
-    ],
-    "cwd": "[START_DIR]/project",
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout f.submodule-status",
-    "timeout": 600.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "vpython3",
-      "-u",
-      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
-      "--json-output",
-      "/path/to/tmp/json",
-      "copy",
-      "submodule status filler text",
-      "[START_DIR]/snapshot/submodules.log"
-    ],
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout f.write submodule snapshot",
+    "name": "get gerrit change numbers.change details for 3380b83",
+    "timeout": 600,
     "~followup_annotations": [
       "@@@STEP_NEST_LEVEL@1@@@",
-      "@@@STEP_LOG_LINE@submodules.log@submodule status filler text@@@",
-      "@@@STEP_LOG_END@submodules.log@@@"
+      "@@@STEP_LOG_LINE@json.output@{@@@",
+      "@@@STEP_LOG_LINE@json.output@  \"_number\": 12345@@@",
+      "@@@STEP_LOG_LINE@json.output@}@@@",
+      "@@@STEP_LOG_END@json.output@@@",
+      "@@@STEP_LOG_LINE@json.input@{@@@",
+      "@@@STEP_LOG_LINE@json.input@  \"change_id\": \"3380b83c11e029b7291c83c44e7b1ce09d465fd1\"@@@",
+      "@@@STEP_LOG_LINE@json.input@}@@@",
+      "@@@STEP_LOG_END@json.input@@@",
+      "@@@STEP_LINK@gerrit link@https://host-review.googlesource.com/q/3380b83c11e029b7291c83c44e7b1ce09d465fd1@@@"
     ]
   },
   {
     "cmd": [
-      "git",
-      "log",
-      "--oneline",
-      "-n",
-      "10"
-    ],
-    "cwd": "[START_DIR]/project",
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout f.log",
-    "timeout": 600.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "vpython3",
-      "-u",
-      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
-      "--json-output",
-      "/path/to/tmp/json",
-      "copy",
-      "",
-      "[START_DIR]/snapshot/git.log"
+      "[START_DIR]/cipd_tool/infra/tools/luci/gerrit/0e548aa33f8113a45a5b3b62201e114e98e63d00f97296912380138f44597b07/gerrit",
+      "change-detail",
+      "-host",
+      "https://host-review.googlesource.com",
+      "-input",
+      "{\"change_id\": \"363caa907186de786cb5292cd1ab7245da954815\"}",
+      "-output",
+      "/path/to/tmp/json"
     ],
     "infra_step": true,
     "luci_context": {
@@ -906,10 +520,19 @@
         "hostname": "rdbhost"
       }
     },
-    "name": "checkout f.write git log",
+    "name": "get gerrit change numbers.change details for 363caa9",
+    "timeout": 600,
     "~followup_annotations": [
       "@@@STEP_NEST_LEVEL@1@@@",
-      "@@@STEP_LOG_END@git.log@@@"
+      "@@@STEP_LOG_LINE@json.output@{@@@",
+      "@@@STEP_LOG_LINE@json.output@  \"_number\": 12345@@@",
+      "@@@STEP_LOG_LINE@json.output@}@@@",
+      "@@@STEP_LOG_END@json.output@@@",
+      "@@@STEP_LOG_LINE@json.input@{@@@",
+      "@@@STEP_LOG_LINE@json.input@  \"change_id\": \"363caa907186de786cb5292cd1ab7245da954815\"@@@",
+      "@@@STEP_LOG_LINE@json.input@}@@@",
+      "@@@STEP_LOG_END@json.input@@@",
+      "@@@STEP_LINK@gerrit link@https://host-review.googlesource.com/q/363caa907186de786cb5292cd1ab7245da954815@@@"
     ]
   },
   {
@@ -966,338 +589,22 @@
   },
   {
     "cmd": [],
-    "name": "remote"
-  },
-  {
-    "cmd": [
-      "git",
-      "remote"
-    ],
-    "cwd": "[START_DIR]/project",
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "remote.name",
-    "timeout": 600.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "remote",
-      "get-url",
-      "origin"
-    ],
-    "cwd": "[START_DIR]/project",
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "remote.url",
-    "timeout": 600.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "f6"
-  },
-  {
-    "cmd": [
-      "git",
-      "log",
-      "--pretty=format:%H\n%an\n%ae\n%B",
-      "-z",
-      "--max-count",
-      "5",
-      "2d72510e447ab60a9728aeea2362d8be2cbd7789"
-    ],
-    "cwd": "[START_DIR]/project",
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "f6.git log",
-    "timeout": 600.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "f6.ensure infra/tools/luci/gerrit/${platform}",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "f6.ensure infra/tools/luci/gerrit/${platform}.get packages",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "vpython3",
-      "-u",
-      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
-      "--json-output",
-      "/path/to/tmp/json",
-      "copy",
-      "RECIPE_MODULE[fuchsia::gerrit]/resources/cipd.ensure",
-      "/path/to/tmp/"
-    ],
-    "cwd": "[START_DIR]/project",
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "f6.ensure infra/tools/luci/gerrit/${platform}.get packages.read ensure file",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@3@@@",
-      "@@@STEP_LOG_LINE@cipd.ensure@infra/tools/luci/gerrit/${platform} version:pinned-version@@@",
-      "@@@STEP_LOG_END@cipd.ensure@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "f6.ensure infra/tools/luci/gerrit/${platform}.install infra/tools/luci/gerrit",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "vpython3",
-      "-u",
-      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
-      "--json-output",
-      "/path/to/tmp/json",
-      "ensure-directory",
-      "--mode",
-      "0o777",
-      "[START_DIR]/cipd_tool/infra/tools/luci/gerrit/0e548aa33f8113a45a5b3b62201e114e98e63d00f97296912380138f44597b07"
-    ],
-    "cwd": "[START_DIR]/project",
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "f6.ensure infra/tools/luci/gerrit/${platform}.install infra/tools/luci/gerrit.ensure package directory",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@3@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "cipd",
-      "ensure",
-      "-root",
-      "[START_DIR]/cipd_tool/infra/tools/luci/gerrit/0e548aa33f8113a45a5b3b62201e114e98e63d00f97296912380138f44597b07",
-      "-ensure-file",
-      "infra/tools/luci/gerrit/${platform} version:pinned-version",
-      "-max-threads",
-      "0",
-      "-json-output",
-      "/path/to/tmp/json"
-    ],
-    "cwd": "[START_DIR]/project",
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "f6.ensure infra/tools/luci/gerrit/${platform}.install infra/tools/luci/gerrit.ensure_installed",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@3@@@",
-      "@@@STEP_LOG_LINE@json.output@{@@@",
-      "@@@STEP_LOG_LINE@json.output@  \"result\": {@@@",
-      "@@@STEP_LOG_LINE@json.output@    \"\": [@@@",
-      "@@@STEP_LOG_LINE@json.output@      {@@@",
-      "@@@STEP_LOG_LINE@json.output@        \"instance_id\": \"resolved-instance_id-of-version:pinned-v\",@@@",
-      "@@@STEP_LOG_LINE@json.output@        \"package\": \"infra/tools/luci/gerrit/resolved-platform\"@@@",
-      "@@@STEP_LOG_LINE@json.output@      }@@@",
-      "@@@STEP_LOG_LINE@json.output@    ]@@@",
-      "@@@STEP_LOG_LINE@json.output@  }@@@",
-      "@@@STEP_LOG_LINE@json.output@}@@@",
-      "@@@STEP_LOG_END@json.output@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "[START_DIR]/cipd_tool/infra/tools/luci/gerrit/0e548aa33f8113a45a5b3b62201e114e98e63d00f97296912380138f44597b07/gerrit",
-      "change-query",
-      "-host",
-      "https://pigweed-review.googlesource.com",
-      "-input",
-      "{\"params\": {\"q\": \"commit:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\"}}",
-      "-output",
-      "/path/to/tmp/json"
-    ],
-    "cwd": "[START_DIR]/project",
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "f6.get change-id",
-    "timeout": 600,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@",
-      "@@@STEP_LOG_LINE@json.output@[@@@",
-      "@@@STEP_LOG_LINE@json.output@  {@@@",
-      "@@@STEP_LOG_LINE@json.output@    \"_number\": 12345@@@",
-      "@@@STEP_LOG_LINE@json.output@  }@@@",
-      "@@@STEP_LOG_LINE@json.output@]@@@",
-      "@@@STEP_LOG_END@json.output@@@",
-      "@@@STEP_LOG_LINE@json.input@{@@@",
-      "@@@STEP_LOG_LINE@json.input@  \"params\": {@@@",
-      "@@@STEP_LOG_LINE@json.input@    \"q\": \"commit:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\"@@@",
-      "@@@STEP_LOG_LINE@json.input@  }@@@",
-      "@@@STEP_LOG_LINE@json.input@}@@@",
-      "@@@STEP_LOG_END@json.input@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "[START_DIR]/cipd_tool/infra/tools/luci/gerrit/0e548aa33f8113a45a5b3b62201e114e98e63d00f97296912380138f44597b07/gerrit",
-      "change-detail",
-      "-host",
-      "https://pigweed-review.googlesource.com",
-      "-input",
-      "{\"change_id\": \"12345\"}",
-      "-output",
-      "/path/to/tmp/json"
-    ],
-    "cwd": "[START_DIR]/project",
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "f6.get 12345",
-    "timeout": 600,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@",
-      "@@@STEP_LOG_LINE@json.output@{@@@",
-      "@@@STEP_LOG_LINE@json.output@  \"owner\": {@@@",
-      "@@@STEP_LOG_LINE@json.output@    \"email\": \"author@example.com\",@@@",
-      "@@@STEP_LOG_LINE@json.output@    \"name\": \"author\"@@@",
-      "@@@STEP_LOG_LINE@json.output@  },@@@",
-      "@@@STEP_LOG_LINE@json.output@  \"reviewers\": {@@@",
-      "@@@STEP_LOG_LINE@json.output@    \"REVIEWER\": [@@@",
-      "@@@STEP_LOG_LINE@json.output@      {@@@",
-      "@@@STEP_LOG_LINE@json.output@        \"email\": \"reviewer@example.com\",@@@",
-      "@@@STEP_LOG_LINE@json.output@        \"name\": \"reviewer\"@@@",
-      "@@@STEP_LOG_LINE@json.output@      },@@@",
-      "@@@STEP_LOG_LINE@json.output@      {@@@",
-      "@@@STEP_LOG_LINE@json.output@        \"email\": \"nobody@google.com\",@@@",
-      "@@@STEP_LOG_LINE@json.output@        \"name\": \"nobody\"@@@",
-      "@@@STEP_LOG_LINE@json.output@      },@@@",
-      "@@@STEP_LOG_LINE@json.output@      {@@@",
-      "@@@STEP_LOG_LINE@json.output@        \"email\": \"robot@gserviceaccount.com\",@@@",
-      "@@@STEP_LOG_LINE@json.output@        \"name\": \"robot\"@@@",
-      "@@@STEP_LOG_LINE@json.output@      }@@@",
-      "@@@STEP_LOG_LINE@json.output@    ]@@@",
-      "@@@STEP_LOG_LINE@json.output@  }@@@",
-      "@@@STEP_LOG_LINE@json.output@}@@@",
-      "@@@STEP_LOG_END@json.output@@@",
-      "@@@STEP_LOG_LINE@json.input@{@@@",
-      "@@@STEP_LOG_LINE@json.input@  \"change_id\": \"12345\"@@@",
-      "@@@STEP_LOG_LINE@json.input@}@@@",
-      "@@@STEP_LOG_END@json.input@@@",
-      "@@@STEP_LINK@gerrit link@https://pigweed-review.googlesource.com/q/12345@@@"
-    ]
-  },
-  {
-    "cmd": [],
     "name": "roll"
   },
   {
     "cmd": [],
-    "name": "roll.project_name",
+    "name": "roll.repo_url",
     "~followup_annotations": [
       "@@@STEP_NEST_LEVEL@1@@@",
-      "@@@STEP_SUMMARY_TEXT@f6@@@"
+      "@@@STEP_SUMMARY_TEXT@https://host.googlesource.com/f@@@"
     ]
   },
   {
     "cmd": [],
-    "name": "roll.proj_dir",
+    "name": "roll.repo_short_name",
     "~followup_annotations": [
       "@@@STEP_NEST_LEVEL@1@@@",
-      "@@@STEP_SUMMARY_TEXT@[START_DIR]/project@@@"
+      "@@@STEP_SUMMARY_TEXT@f6@@@"
     ]
   },
   {
@@ -1318,10 +625,10 @@
   },
   {
     "cmd": [],
-    "name": "roll.direction",
+    "name": "roll.commit message",
     "~followup_annotations": [
       "@@@STEP_NEST_LEVEL@1@@@",
-      "@@@STEP_SUMMARY_TEXT@Direction.FORWARD@@@"
+      "@@@STEP_SUMMARY_TEXT@[roll] Roll f6 main..2d72510 (3 commits)\n\n3e30158:https://host-review.googlesource.com/c/f/+/12345 fake A msg 0\n3380b83:https://host-review.googlesource.com/c/f/+/12345 fake A msg 1\n363caa9:https://host-review.googlesource.com/c/f/+/12345 fake A msg 2\n\nRolled-Repo: https://host.googlesource.com/f\nRolled-Commits: main..2d72510e447ab6@@@"
     ]
   },
   {
diff --git a/recipe_modules/repo_roll/tests/full.expected/host-prefix.json b/recipe_modules/repo_roll/tests/full.expected/host-prefix.json
index 4c962ef..b109063 100644
--- a/recipe_modules/repo_roll/tests/full.expected/host-prefix.json
+++ b/recipe_modules/repo_roll/tests/full.expected/host-prefix.json
@@ -57,50 +57,25 @@
   },
   {
     "cmd": [],
-    "name": "checkout h"
+    "name": "ensure infra/tools/luci/gitiles/${platform}"
   },
   {
     "cmd": [],
-    "name": "checkout h.options",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@",
-      "@@@STEP_SUMMARY_TEXT@remote: \"https://host.googlesource.com/prefix/h\"\nbranch: \"main\"\n@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "checkout h.options with defaults",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@",
-      "@@@STEP_SUMMARY_TEXT@remote: \"https://host.googlesource.com/prefix/h\"\nbranch: \"main\"\nmanifest_file: \"default.xml\"\nrepo_init_timeout_sec: 20\nrepo_sync_timeout_sec: 120\nnumber_of_attempts: 3\nsubmodule_timeout_sec: 600\n@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "checkout h.not matching branch names",
+    "name": "ensure infra/tools/luci/gitiles/${platform}.get packages",
     "~followup_annotations": [
       "@@@STEP_NEST_LEVEL@1@@@"
     ]
   },
   {
-    "cmd": [],
-    "name": "checkout h.cache",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@",
-      "@@@STEP_SUMMARY_TEXT@miss@@@"
-    ]
-  },
-  {
     "cmd": [
       "vpython3",
       "-u",
       "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
       "--json-output",
       "/path/to/tmp/json",
-      "ensure-directory",
-      "--mode",
-      "0o777",
-      "[CACHE]/git"
+      "copy",
+      "RECIPE_MODULE[fuchsia::gitiles]/resources/cipd.ensure",
+      "/path/to/tmp/"
     ],
     "infra_step": true,
     "luci_context": {
@@ -115,7 +90,220 @@
         "hostname": "rdbhost"
       }
     },
-    "name": "checkout h.cache.ensure git cache dir",
+    "name": "ensure infra/tools/luci/gitiles/${platform}.get packages.read ensure file",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@2@@@",
+      "@@@STEP_LOG_LINE@cipd.ensure@infra/tools/luci/gitiles/${platform} version:pinned-version@@@",
+      "@@@STEP_LOG_END@cipd.ensure@@@"
+    ]
+  },
+  {
+    "cmd": [],
+    "name": "ensure infra/tools/luci/gitiles/${platform}.install infra/tools/luci/gitiles",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "vpython3",
+      "-u",
+      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
+      "--json-output",
+      "/path/to/tmp/json",
+      "ensure-directory",
+      "--mode",
+      "0o777",
+      "[START_DIR]/cipd_tool/infra/tools/luci/gitiles/0e548aa33f8113a45a5b3b62201e114e98e63d00f97296912380138f44597b07"
+    ],
+    "infra_step": true,
+    "luci_context": {
+      "realm": {
+        "name": "project:ci"
+      },
+      "resultdb": {
+        "current_invocation": {
+          "name": "invocations/build:8945511751514863184",
+          "update_token": "token"
+        },
+        "hostname": "rdbhost"
+      }
+    },
+    "name": "ensure infra/tools/luci/gitiles/${platform}.install infra/tools/luci/gitiles.ensure package directory",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@2@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "cipd",
+      "ensure",
+      "-root",
+      "[START_DIR]/cipd_tool/infra/tools/luci/gitiles/0e548aa33f8113a45a5b3b62201e114e98e63d00f97296912380138f44597b07",
+      "-ensure-file",
+      "infra/tools/luci/gitiles/${platform} version:pinned-version",
+      "-max-threads",
+      "0",
+      "-json-output",
+      "/path/to/tmp/json"
+    ],
+    "infra_step": true,
+    "luci_context": {
+      "realm": {
+        "name": "project:ci"
+      },
+      "resultdb": {
+        "current_invocation": {
+          "name": "invocations/build:8945511751514863184",
+          "update_token": "token"
+        },
+        "hostname": "rdbhost"
+      }
+    },
+    "name": "ensure infra/tools/luci/gitiles/${platform}.install infra/tools/luci/gitiles.ensure_installed",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@2@@@",
+      "@@@STEP_LOG_LINE@json.output@{@@@",
+      "@@@STEP_LOG_LINE@json.output@  \"result\": {@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"\": [@@@",
+      "@@@STEP_LOG_LINE@json.output@      {@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"instance_id\": \"resolved-instance_id-of-version:pinned-v\",@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"package\": \"infra/tools/luci/gitiles/resolved-platform\"@@@",
+      "@@@STEP_LOG_LINE@json.output@      }@@@",
+      "@@@STEP_LOG_LINE@json.output@    ]@@@",
+      "@@@STEP_LOG_LINE@json.output@  }@@@",
+      "@@@STEP_LOG_LINE@json.output@}@@@",
+      "@@@STEP_LOG_END@json.output@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "[START_DIR]/cipd_tool/infra/tools/luci/gitiles/0e548aa33f8113a45a5b3b62201e114e98e63d00f97296912380138f44597b07/gitiles",
+      "log",
+      "-json-output",
+      "/path/to/tmp/json",
+      "https://host.googlesource.com/prefix/h",
+      "main..2d72510e447ab60a9728aeea2362d8be2cbd7789"
+    ],
+    "infra_step": true,
+    "luci_context": {
+      "realm": {
+        "name": "project:ci"
+      },
+      "resultdb": {
+        "current_invocation": {
+          "name": "invocations/build:8945511751514863184",
+          "update_token": "token"
+        },
+        "hostname": "rdbhost"
+      }
+    },
+    "name": "log h8",
+    "timeout": 300.0,
+    "~followup_annotations": [
+      "@@@STEP_LOG_LINE@json.output@[@@@",
+      "@@@STEP_LOG_LINE@json.output@  {@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"author\": {@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"email\": \"fake_A@fake_0.email.com\",@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"name\": \"Fake A\",@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"time\": \"Mon Jan 01 00:00:00 2015\"@@@",
+      "@@@STEP_LOG_LINE@json.output@    },@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"committer\": {@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"email\": \"fake_A@fake_0.email.com\",@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"name\": \"Fake A\",@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"time\": \"Mon Jan 01 00:00:00 2015\"@@@",
+      "@@@STEP_LOG_LINE@json.output@    },@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"id\": \"3e30158f2a7caccb7a9f6632a60011e7a44e1e5c\",@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"message\": \"fake A msg 0\",@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"parents\": [@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"83a7614b3b60951511be50db1b9561daff4bb447\"@@@",
+      "@@@STEP_LOG_LINE@json.output@    ],@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"tree\": \"1b6412b24ec3add84836c8fdd1af5ac8e35b61d9\",@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"tree_diff\": [@@@",
+      "@@@STEP_LOG_LINE@json.output@      {@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"new_id\": \"8bea05ad53680fce6937543f0d98cd48e295b8ff\",@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"new_mode\": 33188,@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"new_path\": \"a.py\",@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"old_id\": \"0000000000000000000000000000000000000000\",@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"old_mode\": 0,@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"type\": \"add\"@@@",
+      "@@@STEP_LOG_LINE@json.output@      }@@@",
+      "@@@STEP_LOG_LINE@json.output@    ]@@@",
+      "@@@STEP_LOG_LINE@json.output@  },@@@",
+      "@@@STEP_LOG_LINE@json.output@  {@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"author\": {@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"email\": \"fake_A@fake_1.email.com\",@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"name\": \"Fake A\",@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"time\": \"Mon Jan 01 00:00:00 2015\"@@@",
+      "@@@STEP_LOG_LINE@json.output@    },@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"committer\": {@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"email\": \"fake_A@fake_1.email.com\",@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"name\": \"Fake A\",@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"time\": \"Mon Jan 01 00:00:00 2015\"@@@",
+      "@@@STEP_LOG_LINE@json.output@    },@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"id\": \"3380b83c11e029b7291c83c44e7b1ce09d465fd1\",@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"message\": \"fake A msg 1\",@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"parents\": [@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"8675a52c73c701cb0b2c48f5ed4a9058c624e6cd\"@@@",
+      "@@@STEP_LOG_LINE@json.output@    ],@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"tree\": \"a1b1e6aa501915989b45a95e1224ec2a88655eb3\",@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"tree_diff\": [@@@",
+      "@@@STEP_LOG_LINE@json.output@      {@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"new_id\": \"06bc4c79002f278528aaddae4e056a11f58c19ad\",@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"new_mode\": 33188,@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"new_path\": \"b.py\",@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"old_id\": \"0000000000000000000000000000000000000000\",@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"old_mode\": 0,@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"type\": \"add\"@@@",
+      "@@@STEP_LOG_LINE@json.output@      }@@@",
+      "@@@STEP_LOG_LINE@json.output@    ]@@@",
+      "@@@STEP_LOG_LINE@json.output@  },@@@",
+      "@@@STEP_LOG_LINE@json.output@  {@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"author\": {@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"email\": \"fake_A@fake_2.email.com\",@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"name\": \"Fake A\",@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"time\": \"Mon Jan 01 00:00:00 2015\"@@@",
+      "@@@STEP_LOG_LINE@json.output@    },@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"committer\": {@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"email\": \"fake_A@fake_2.email.com\",@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"name\": \"Fake A\",@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"time\": \"Mon Jan 01 00:00:00 2015\"@@@",
+      "@@@STEP_LOG_LINE@json.output@    },@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"id\": \"363caa907186de786cb5292cd1ab7245da954815\",@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"message\": \"fake A msg 2\",@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"parents\": [@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"255c6325c4c654e17e6b35142e3912c86f1718f2\"@@@",
+      "@@@STEP_LOG_LINE@json.output@    ],@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"tree\": \"e84d4ad259e69da73d2b842e2b9709f08e8b22bd\",@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"tree_diff\": [@@@",
+      "@@@STEP_LOG_LINE@json.output@      {@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"new_id\": \"d7f478bf423219f2f47c1a6ed344fc597a8bf18f\",@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"new_mode\": 33188,@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"new_path\": \"c.py\",@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"old_id\": \"0000000000000000000000000000000000000000\",@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"old_mode\": 0,@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"type\": \"add\"@@@",
+      "@@@STEP_LOG_LINE@json.output@      }@@@",
+      "@@@STEP_LOG_LINE@json.output@    ]@@@",
+      "@@@STEP_LOG_LINE@json.output@  }@@@",
+      "@@@STEP_LOG_LINE@json.output@]@@@",
+      "@@@STEP_LOG_END@json.output@@@"
+    ]
+  },
+  {
+    "cmd": [],
+    "name": "get gerrit change numbers"
+  },
+  {
+    "cmd": [],
+    "name": "get gerrit change numbers.ensure infra/tools/luci/gerrit/${platform}",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@"
+    ]
+  },
+  {
+    "cmd": [],
+    "name": "get gerrit change numbers.ensure infra/tools/luci/gerrit/${platform}.get packages",
     "~followup_annotations": [
       "@@@STEP_NEST_LEVEL@2@@@"
     ]
@@ -128,8 +316,8 @@
       "--json-output",
       "/path/to/tmp/json",
       "copy",
-      "",
-      "[CACHE]/git/.GUARD_FILE"
+      "RECIPE_MODULE[fuchsia::gerrit]/resources/cipd.ensure",
+      "/path/to/tmp/"
     ],
     "infra_step": true,
     "luci_context": {
@@ -144,7 +332,16 @@
         "hostname": "rdbhost"
       }
     },
-    "name": "checkout h.cache.write git cache guard file",
+    "name": "get gerrit change numbers.ensure infra/tools/luci/gerrit/${platform}.get packages.read ensure file",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@3@@@",
+      "@@@STEP_LOG_LINE@cipd.ensure@infra/tools/luci/gerrit/${platform} version:pinned-version@@@",
+      "@@@STEP_LOG_END@cipd.ensure@@@"
+    ]
+  },
+  {
+    "cmd": [],
+    "name": "get gerrit change numbers.ensure infra/tools/luci/gerrit/${platform}.install infra/tools/luci/gerrit",
     "~followup_annotations": [
       "@@@STEP_NEST_LEVEL@2@@@"
     ]
@@ -159,7 +356,7 @@
       "ensure-directory",
       "--mode",
       "0o777",
-      "[CACHE]/git/host.googlesource.com-prefix-h"
+      "[START_DIR]/cipd_tool/infra/tools/luci/gerrit/0e548aa33f8113a45a5b3b62201e114e98e63d00f97296912380138f44597b07"
     ],
     "infra_step": true,
     "luci_context": {
@@ -174,17 +371,24 @@
         "hostname": "rdbhost"
       }
     },
-    "name": "checkout h.cache.makedirs",
+    "name": "get gerrit change numbers.ensure infra/tools/luci/gerrit/${platform}.install infra/tools/luci/gerrit.ensure package directory",
     "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
+      "@@@STEP_NEST_LEVEL@3@@@"
     ]
   },
   {
     "cmd": [
-      "git",
-      "init"
+      "cipd",
+      "ensure",
+      "-root",
+      "[START_DIR]/cipd_tool/infra/tools/luci/gerrit/0e548aa33f8113a45a5b3b62201e114e98e63d00f97296912380138f44597b07",
+      "-ensure-file",
+      "infra/tools/luci/gerrit/${platform} version:pinned-version",
+      "-max-threads",
+      "0",
+      "-json-output",
+      "/path/to/tmp/json"
     ],
-    "cwd": "[CACHE]/git/host.googlesource.com-prefix-h",
     "infra_step": true,
     "luci_context": {
       "realm": {
@@ -198,20 +402,33 @@
         "hostname": "rdbhost"
       }
     },
-    "name": "checkout h.cache.git init",
-    "timeout": 300.0,
+    "name": "get gerrit change numbers.ensure infra/tools/luci/gerrit/${platform}.install infra/tools/luci/gerrit.ensure_installed",
     "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
+      "@@@STEP_NEST_LEVEL@3@@@",
+      "@@@STEP_LOG_LINE@json.output@{@@@",
+      "@@@STEP_LOG_LINE@json.output@  \"result\": {@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"\": [@@@",
+      "@@@STEP_LOG_LINE@json.output@      {@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"instance_id\": \"resolved-instance_id-of-version:pinned-v\",@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"package\": \"infra/tools/luci/gerrit/resolved-platform\"@@@",
+      "@@@STEP_LOG_LINE@json.output@      }@@@",
+      "@@@STEP_LOG_LINE@json.output@    ]@@@",
+      "@@@STEP_LOG_LINE@json.output@  }@@@",
+      "@@@STEP_LOG_LINE@json.output@}@@@",
+      "@@@STEP_LOG_END@json.output@@@"
     ]
   },
   {
     "cmd": [
-      "git",
-      "config",
-      "remote.origin.url",
-      "https://host.googlesource.com/prefix/h"
+      "[START_DIR]/cipd_tool/infra/tools/luci/gerrit/0e548aa33f8113a45a5b3b62201e114e98e63d00f97296912380138f44597b07/gerrit",
+      "change-detail",
+      "-host",
+      "https://host-review.googlesource.com",
+      "-input",
+      "{\"change_id\": \"3e30158f2a7caccb7a9f6632a60011e7a44e1e5c\"}",
+      "-output",
+      "/path/to/tmp/json"
     ],
-    "cwd": "[CACHE]/git/host.googlesource.com-prefix-h",
     "infra_step": true,
     "luci_context": {
       "realm": {
@@ -225,149 +442,31 @@
         "hostname": "rdbhost"
       }
     },
-    "name": "checkout h.cache.remote set-url",
-    "timeout": 300.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "config",
-      "fetch.uriprotocols",
-      "https"
-    ],
-    "cwd": "[CACHE]/git/host.googlesource.com-prefix-h",
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout h.cache.set fetch.uriprotocols",
-    "timeout": 300.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "checkout h.cache.timeout 10s",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "fetch",
-      "--prune",
-      "--tags",
-      "--jobs",
-      "4",
-      "origin",
-      "--no-recurse-submodules"
-    ],
-    "cwd": "[CACHE]/git/host.googlesource.com-prefix-h",
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout h.cache.git fetch",
-    "timeout": 1200.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "merge",
-      "FETCH_HEAD"
-    ],
-    "cwd": "[CACHE]/git/host.googlesource.com-prefix-h",
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout h.cache.git merge",
-    "timeout": 600.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "checkout h.cache.timeout 10s (2)",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "submodule",
-      "update",
-      "--recursive",
-      "--force",
-      "--jobs",
-      "4"
-    ],
-    "cwd": "[CACHE]/git/host.googlesource.com-prefix-h",
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout h.cache.git submodule update",
+    "name": "get gerrit change numbers.change details for 3e30158",
     "timeout": 600,
     "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
+      "@@@STEP_NEST_LEVEL@1@@@",
+      "@@@STEP_LOG_LINE@json.output@{@@@",
+      "@@@STEP_LOG_LINE@json.output@  \"_number\": 12345@@@",
+      "@@@STEP_LOG_LINE@json.output@}@@@",
+      "@@@STEP_LOG_END@json.output@@@",
+      "@@@STEP_LOG_LINE@json.input@{@@@",
+      "@@@STEP_LOG_LINE@json.input@  \"change_id\": \"3e30158f2a7caccb7a9f6632a60011e7a44e1e5c\"@@@",
+      "@@@STEP_LOG_LINE@json.input@}@@@",
+      "@@@STEP_LOG_END@json.input@@@",
+      "@@@STEP_LINK@gerrit link@https://host-review.googlesource.com/q/3e30158f2a7caccb7a9f6632a60011e7a44e1e5c@@@"
     ]
   },
   {
     "cmd": [
-      "vpython3",
-      "-u",
-      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
-      "--json-output",
-      "/path/to/tmp/json",
-      "remove",
-      "[CACHE]/git/.GUARD_FILE"
+      "[START_DIR]/cipd_tool/infra/tools/luci/gerrit/0e548aa33f8113a45a5b3b62201e114e98e63d00f97296912380138f44597b07/gerrit",
+      "change-detail",
+      "-host",
+      "https://host-review.googlesource.com",
+      "-input",
+      "{\"change_id\": \"3380b83c11e029b7291c83c44e7b1ce09d465fd1\"}",
+      "-output",
+      "/path/to/tmp/json"
     ],
     "infra_step": true,
     "luci_context": {
@@ -382,516 +481,31 @@
         "hostname": "rdbhost"
       }
     },
-    "name": "checkout h.cache.remove git cache guard file",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "vpython3",
-      "-u",
-      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
-      "--json-output",
-      "/path/to/tmp/json",
-      "copytree",
-      "--symlinks",
-      "[CACHE]/git/host.googlesource.com-prefix-h",
-      "[START_DIR]/project"
-    ],
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout h.copy from cache",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "checkout h.git checkout",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "checkout h.git checkout.timeout 10s",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "vpython3",
-      "-u",
-      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
-      "--json-output",
-      "/path/to/tmp/json",
-      "ensure-directory",
-      "--mode",
-      "0o777",
-      "[START_DIR]/project"
-    ],
-    "infra_step": true,
-    "luci_context": {
-      "deadline": {
-        "grace_period": 30.0,
-        "soft_deadline": 1337000019.0
-      },
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout h.git checkout.makedirs",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "init"
-    ],
-    "cwd": "[START_DIR]/project",
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout h.git checkout.git init",
-    "timeout": 300.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "remote",
-      "add",
-      "origin",
-      "https://host.googlesource.com/prefix/h"
-    ],
-    "cwd": "[START_DIR]/project",
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout h.git checkout.git remote",
-    "timeout": 600.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "config",
-      "core.longpaths",
-      "true"
-    ],
-    "cwd": "[START_DIR]/project",
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout h.git checkout.set core.longpaths",
-    "timeout": 300.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "config",
-      "fetch.uriprotocols",
-      "https"
-    ],
-    "cwd": "[START_DIR]/project",
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout h.git checkout.set fetch.uriprotocols",
-    "timeout": 300.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "fetch",
-      "--tags",
-      "--jobs",
-      "4",
-      "origin",
-      "main"
-    ],
-    "cwd": "[START_DIR]/project",
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout h.git checkout.git fetch",
-    "timeout": 1200.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "checkout",
-      "-f",
-      "FETCH_HEAD"
-    ],
-    "cwd": "[START_DIR]/project",
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout h.git checkout.git checkout",
-    "timeout": 600.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "rev-parse",
-      "HEAD"
-    ],
-    "cwd": "[START_DIR]/project",
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout h.git checkout.git rev-parse",
-    "timeout": 300.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "clean",
-      "-f",
-      "-d",
-      "-x"
-    ],
-    "cwd": "[START_DIR]/project",
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout h.git checkout.git clean",
-    "timeout": 600.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "checkout h.git log",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "log",
-      "--oneline",
-      "-n",
-      "10"
-    ],
-    "cwd": "[START_DIR]/project",
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout h.git log.[START_DIR]/project",
-    "timeout": 600.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "clean",
-      "-f",
-      "-f",
-      "-d"
-    ],
-    "cwd": "[START_DIR]/project",
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout h.git clean",
-    "timeout": 600.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "status"
-    ],
-    "cwd": "[START_DIR]/project",
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout h.git status",
-    "timeout": 600.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "vpython3",
-      "-u",
-      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
-      "--json-output",
-      "/path/to/tmp/json",
-      "ensure-directory",
-      "--mode",
-      "0o777",
-      "[START_DIR]/snapshot"
-    ],
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout h.mkdir",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "submodule",
-      "status",
-      "--recursive"
-    ],
-    "cwd": "[START_DIR]/project",
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout h.submodule-status",
-    "timeout": 600.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "vpython3",
-      "-u",
-      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
-      "--json-output",
-      "/path/to/tmp/json",
-      "copy",
-      "submodule status filler text",
-      "[START_DIR]/snapshot/submodules.log"
-    ],
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout h.write submodule snapshot",
+    "name": "get gerrit change numbers.change details for 3380b83",
+    "timeout": 600,
     "~followup_annotations": [
       "@@@STEP_NEST_LEVEL@1@@@",
-      "@@@STEP_LOG_LINE@submodules.log@submodule status filler text@@@",
-      "@@@STEP_LOG_END@submodules.log@@@"
+      "@@@STEP_LOG_LINE@json.output@{@@@",
+      "@@@STEP_LOG_LINE@json.output@  \"_number\": 12345@@@",
+      "@@@STEP_LOG_LINE@json.output@}@@@",
+      "@@@STEP_LOG_END@json.output@@@",
+      "@@@STEP_LOG_LINE@json.input@{@@@",
+      "@@@STEP_LOG_LINE@json.input@  \"change_id\": \"3380b83c11e029b7291c83c44e7b1ce09d465fd1\"@@@",
+      "@@@STEP_LOG_LINE@json.input@}@@@",
+      "@@@STEP_LOG_END@json.input@@@",
+      "@@@STEP_LINK@gerrit link@https://host-review.googlesource.com/q/3380b83c11e029b7291c83c44e7b1ce09d465fd1@@@"
     ]
   },
   {
     "cmd": [
-      "git",
-      "log",
-      "--oneline",
-      "-n",
-      "10"
-    ],
-    "cwd": "[START_DIR]/project",
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout h.log",
-    "timeout": 600.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "vpython3",
-      "-u",
-      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
-      "--json-output",
-      "/path/to/tmp/json",
-      "copy",
-      "",
-      "[START_DIR]/snapshot/git.log"
+      "[START_DIR]/cipd_tool/infra/tools/luci/gerrit/0e548aa33f8113a45a5b3b62201e114e98e63d00f97296912380138f44597b07/gerrit",
+      "change-detail",
+      "-host",
+      "https://host-review.googlesource.com",
+      "-input",
+      "{\"change_id\": \"363caa907186de786cb5292cd1ab7245da954815\"}",
+      "-output",
+      "/path/to/tmp/json"
     ],
     "infra_step": true,
     "luci_context": {
@@ -906,10 +520,19 @@
         "hostname": "rdbhost"
       }
     },
-    "name": "checkout h.write git log",
+    "name": "get gerrit change numbers.change details for 363caa9",
+    "timeout": 600,
     "~followup_annotations": [
       "@@@STEP_NEST_LEVEL@1@@@",
-      "@@@STEP_LOG_END@git.log@@@"
+      "@@@STEP_LOG_LINE@json.output@{@@@",
+      "@@@STEP_LOG_LINE@json.output@  \"_number\": 12345@@@",
+      "@@@STEP_LOG_LINE@json.output@}@@@",
+      "@@@STEP_LOG_END@json.output@@@",
+      "@@@STEP_LOG_LINE@json.input@{@@@",
+      "@@@STEP_LOG_LINE@json.input@  \"change_id\": \"363caa907186de786cb5292cd1ab7245da954815\"@@@",
+      "@@@STEP_LOG_LINE@json.input@}@@@",
+      "@@@STEP_LOG_END@json.input@@@",
+      "@@@STEP_LINK@gerrit link@https://host-review.googlesource.com/q/363caa907186de786cb5292cd1ab7245da954815@@@"
     ]
   },
   {
@@ -966,338 +589,22 @@
   },
   {
     "cmd": [],
-    "name": "remote"
-  },
-  {
-    "cmd": [
-      "git",
-      "remote"
-    ],
-    "cwd": "[START_DIR]/project",
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "remote.name",
-    "timeout": 600.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "remote",
-      "get-url",
-      "origin"
-    ],
-    "cwd": "[START_DIR]/project",
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "remote.url",
-    "timeout": 600.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "h8"
-  },
-  {
-    "cmd": [
-      "git",
-      "log",
-      "--pretty=format:%H\n%an\n%ae\n%B",
-      "-z",
-      "--max-count",
-      "5",
-      "2d72510e447ab60a9728aeea2362d8be2cbd7789"
-    ],
-    "cwd": "[START_DIR]/project",
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "h8.git log",
-    "timeout": 600.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "h8.ensure infra/tools/luci/gerrit/${platform}",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "h8.ensure infra/tools/luci/gerrit/${platform}.get packages",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "vpython3",
-      "-u",
-      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
-      "--json-output",
-      "/path/to/tmp/json",
-      "copy",
-      "RECIPE_MODULE[fuchsia::gerrit]/resources/cipd.ensure",
-      "/path/to/tmp/"
-    ],
-    "cwd": "[START_DIR]/project",
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "h8.ensure infra/tools/luci/gerrit/${platform}.get packages.read ensure file",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@3@@@",
-      "@@@STEP_LOG_LINE@cipd.ensure@infra/tools/luci/gerrit/${platform} version:pinned-version@@@",
-      "@@@STEP_LOG_END@cipd.ensure@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "h8.ensure infra/tools/luci/gerrit/${platform}.install infra/tools/luci/gerrit",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "vpython3",
-      "-u",
-      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
-      "--json-output",
-      "/path/to/tmp/json",
-      "ensure-directory",
-      "--mode",
-      "0o777",
-      "[START_DIR]/cipd_tool/infra/tools/luci/gerrit/0e548aa33f8113a45a5b3b62201e114e98e63d00f97296912380138f44597b07"
-    ],
-    "cwd": "[START_DIR]/project",
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "h8.ensure infra/tools/luci/gerrit/${platform}.install infra/tools/luci/gerrit.ensure package directory",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@3@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "cipd",
-      "ensure",
-      "-root",
-      "[START_DIR]/cipd_tool/infra/tools/luci/gerrit/0e548aa33f8113a45a5b3b62201e114e98e63d00f97296912380138f44597b07",
-      "-ensure-file",
-      "infra/tools/luci/gerrit/${platform} version:pinned-version",
-      "-max-threads",
-      "0",
-      "-json-output",
-      "/path/to/tmp/json"
-    ],
-    "cwd": "[START_DIR]/project",
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "h8.ensure infra/tools/luci/gerrit/${platform}.install infra/tools/luci/gerrit.ensure_installed",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@3@@@",
-      "@@@STEP_LOG_LINE@json.output@{@@@",
-      "@@@STEP_LOG_LINE@json.output@  \"result\": {@@@",
-      "@@@STEP_LOG_LINE@json.output@    \"\": [@@@",
-      "@@@STEP_LOG_LINE@json.output@      {@@@",
-      "@@@STEP_LOG_LINE@json.output@        \"instance_id\": \"resolved-instance_id-of-version:pinned-v\",@@@",
-      "@@@STEP_LOG_LINE@json.output@        \"package\": \"infra/tools/luci/gerrit/resolved-platform\"@@@",
-      "@@@STEP_LOG_LINE@json.output@      }@@@",
-      "@@@STEP_LOG_LINE@json.output@    ]@@@",
-      "@@@STEP_LOG_LINE@json.output@  }@@@",
-      "@@@STEP_LOG_LINE@json.output@}@@@",
-      "@@@STEP_LOG_END@json.output@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "[START_DIR]/cipd_tool/infra/tools/luci/gerrit/0e548aa33f8113a45a5b3b62201e114e98e63d00f97296912380138f44597b07/gerrit",
-      "change-query",
-      "-host",
-      "https://pigweed-review.googlesource.com",
-      "-input",
-      "{\"params\": {\"q\": \"commit:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\"}}",
-      "-output",
-      "/path/to/tmp/json"
-    ],
-    "cwd": "[START_DIR]/project",
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "h8.get change-id",
-    "timeout": 600,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@",
-      "@@@STEP_LOG_LINE@json.output@[@@@",
-      "@@@STEP_LOG_LINE@json.output@  {@@@",
-      "@@@STEP_LOG_LINE@json.output@    \"_number\": 12345@@@",
-      "@@@STEP_LOG_LINE@json.output@  }@@@",
-      "@@@STEP_LOG_LINE@json.output@]@@@",
-      "@@@STEP_LOG_END@json.output@@@",
-      "@@@STEP_LOG_LINE@json.input@{@@@",
-      "@@@STEP_LOG_LINE@json.input@  \"params\": {@@@",
-      "@@@STEP_LOG_LINE@json.input@    \"q\": \"commit:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\"@@@",
-      "@@@STEP_LOG_LINE@json.input@  }@@@",
-      "@@@STEP_LOG_LINE@json.input@}@@@",
-      "@@@STEP_LOG_END@json.input@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "[START_DIR]/cipd_tool/infra/tools/luci/gerrit/0e548aa33f8113a45a5b3b62201e114e98e63d00f97296912380138f44597b07/gerrit",
-      "change-detail",
-      "-host",
-      "https://pigweed-review.googlesource.com",
-      "-input",
-      "{\"change_id\": \"12345\"}",
-      "-output",
-      "/path/to/tmp/json"
-    ],
-    "cwd": "[START_DIR]/project",
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "h8.get 12345",
-    "timeout": 600,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@",
-      "@@@STEP_LOG_LINE@json.output@{@@@",
-      "@@@STEP_LOG_LINE@json.output@  \"owner\": {@@@",
-      "@@@STEP_LOG_LINE@json.output@    \"email\": \"author@example.com\",@@@",
-      "@@@STEP_LOG_LINE@json.output@    \"name\": \"author\"@@@",
-      "@@@STEP_LOG_LINE@json.output@  },@@@",
-      "@@@STEP_LOG_LINE@json.output@  \"reviewers\": {@@@",
-      "@@@STEP_LOG_LINE@json.output@    \"REVIEWER\": [@@@",
-      "@@@STEP_LOG_LINE@json.output@      {@@@",
-      "@@@STEP_LOG_LINE@json.output@        \"email\": \"reviewer@example.com\",@@@",
-      "@@@STEP_LOG_LINE@json.output@        \"name\": \"reviewer\"@@@",
-      "@@@STEP_LOG_LINE@json.output@      },@@@",
-      "@@@STEP_LOG_LINE@json.output@      {@@@",
-      "@@@STEP_LOG_LINE@json.output@        \"email\": \"nobody@google.com\",@@@",
-      "@@@STEP_LOG_LINE@json.output@        \"name\": \"nobody\"@@@",
-      "@@@STEP_LOG_LINE@json.output@      },@@@",
-      "@@@STEP_LOG_LINE@json.output@      {@@@",
-      "@@@STEP_LOG_LINE@json.output@        \"email\": \"robot@gserviceaccount.com\",@@@",
-      "@@@STEP_LOG_LINE@json.output@        \"name\": \"robot\"@@@",
-      "@@@STEP_LOG_LINE@json.output@      }@@@",
-      "@@@STEP_LOG_LINE@json.output@    ]@@@",
-      "@@@STEP_LOG_LINE@json.output@  }@@@",
-      "@@@STEP_LOG_LINE@json.output@}@@@",
-      "@@@STEP_LOG_END@json.output@@@",
-      "@@@STEP_LOG_LINE@json.input@{@@@",
-      "@@@STEP_LOG_LINE@json.input@  \"change_id\": \"12345\"@@@",
-      "@@@STEP_LOG_LINE@json.input@}@@@",
-      "@@@STEP_LOG_END@json.input@@@",
-      "@@@STEP_LINK@gerrit link@https://pigweed-review.googlesource.com/q/12345@@@"
-    ]
-  },
-  {
-    "cmd": [],
     "name": "roll"
   },
   {
     "cmd": [],
-    "name": "roll.project_name",
+    "name": "roll.repo_url",
     "~followup_annotations": [
       "@@@STEP_NEST_LEVEL@1@@@",
-      "@@@STEP_SUMMARY_TEXT@h8@@@"
+      "@@@STEP_SUMMARY_TEXT@https://host.googlesource.com/prefix/h@@@"
     ]
   },
   {
     "cmd": [],
-    "name": "roll.proj_dir",
+    "name": "roll.repo_short_name",
     "~followup_annotations": [
       "@@@STEP_NEST_LEVEL@1@@@",
-      "@@@STEP_SUMMARY_TEXT@[START_DIR]/project@@@"
+      "@@@STEP_SUMMARY_TEXT@h8@@@"
     ]
   },
   {
@@ -1318,10 +625,10 @@
   },
   {
     "cmd": [],
-    "name": "roll.direction",
+    "name": "roll.commit message",
     "~followup_annotations": [
       "@@@STEP_NEST_LEVEL@1@@@",
-      "@@@STEP_SUMMARY_TEXT@Direction.FORWARD@@@"
+      "@@@STEP_SUMMARY_TEXT@[roll] Roll h8 main..2d72510 (3 commits)\n\n3e30158:https://host-review.googlesource.com/c/prefix/h/+/12345 fake A msg 0\n3380b83:https://host-review.googlesource.com/c/prefix/h/+/12345 fake A msg 1\n363caa9:https://host-review.googlesource.com/c/prefix/h/+/12345 fake A msg 2\n\nRolled-Repo: https://host.googlesource.com/prefix/h\nRolled-Commits: main..2d72510e447ab6@@@"
     ]
   },
   {
diff --git a/recipe_modules/repo_roll/tests/full.expected/no-trigger-with-revision-branch.json b/recipe_modules/repo_roll/tests/full.expected/no-trigger-with-revision-branch.json
index bf24a06..e37f471 100644
--- a/recipe_modules/repo_roll/tests/full.expected/no-trigger-with-revision-branch.json
+++ b/recipe_modules/repo_roll/tests/full.expected/no-trigger-with-revision-branch.json
@@ -44,529 +44,6 @@
     ]
   },
   {
-    "cmd": [],
-    "name": "checkout c"
-  },
-  {
-    "cmd": [],
-    "name": "checkout c.options",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@",
-      "@@@STEP_SUMMARY_TEXT@remote: \"https://bar.googlesource.com/c\"\nbranch: \"main\"\n@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "checkout c.options with defaults",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@",
-      "@@@STEP_SUMMARY_TEXT@remote: \"https://bar.googlesource.com/c\"\nbranch: \"main\"\nmanifest_file: \"default.xml\"\nrepo_init_timeout_sec: 20\nrepo_sync_timeout_sec: 120\nnumber_of_attempts: 3\nsubmodule_timeout_sec: 600\n@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "checkout c.not matching branch names",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "checkout c.cache",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@",
-      "@@@STEP_SUMMARY_TEXT@miss@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "vpython3",
-      "-u",
-      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
-      "--json-output",
-      "/path/to/tmp/json",
-      "ensure-directory",
-      "--mode",
-      "0o777",
-      "[CACHE]/git"
-    ],
-    "infra_step": true,
-    "name": "checkout c.cache.ensure git cache dir",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "vpython3",
-      "-u",
-      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
-      "--json-output",
-      "/path/to/tmp/json",
-      "copy",
-      "",
-      "[CACHE]/git/.GUARD_FILE"
-    ],
-    "infra_step": true,
-    "name": "checkout c.cache.write git cache guard file",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "vpython3",
-      "-u",
-      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
-      "--json-output",
-      "/path/to/tmp/json",
-      "ensure-directory",
-      "--mode",
-      "0o777",
-      "[CACHE]/git/bar.googlesource.com-c"
-    ],
-    "infra_step": true,
-    "name": "checkout c.cache.makedirs",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "init"
-    ],
-    "cwd": "[CACHE]/git/bar.googlesource.com-c",
-    "infra_step": true,
-    "name": "checkout c.cache.git init",
-    "timeout": 300.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "config",
-      "remote.origin.url",
-      "https://bar.googlesource.com/c"
-    ],
-    "cwd": "[CACHE]/git/bar.googlesource.com-c",
-    "infra_step": true,
-    "name": "checkout c.cache.remote set-url",
-    "timeout": 300.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "config",
-      "fetch.uriprotocols",
-      "https"
-    ],
-    "cwd": "[CACHE]/git/bar.googlesource.com-c",
-    "infra_step": true,
-    "name": "checkout c.cache.set fetch.uriprotocols",
-    "timeout": 300.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "checkout c.cache.timeout 10s",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "fetch",
-      "--prune",
-      "--tags",
-      "--jobs",
-      "4",
-      "origin",
-      "--no-recurse-submodules"
-    ],
-    "cwd": "[CACHE]/git/bar.googlesource.com-c",
-    "infra_step": true,
-    "name": "checkout c.cache.git fetch",
-    "timeout": 1200.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "merge",
-      "FETCH_HEAD"
-    ],
-    "cwd": "[CACHE]/git/bar.googlesource.com-c",
-    "infra_step": true,
-    "name": "checkout c.cache.git merge",
-    "timeout": 600.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "checkout c.cache.timeout 10s (2)",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "submodule",
-      "update",
-      "--recursive",
-      "--force",
-      "--jobs",
-      "4"
-    ],
-    "cwd": "[CACHE]/git/bar.googlesource.com-c",
-    "infra_step": true,
-    "name": "checkout c.cache.git submodule update",
-    "timeout": 600,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "vpython3",
-      "-u",
-      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
-      "--json-output",
-      "/path/to/tmp/json",
-      "remove",
-      "[CACHE]/git/.GUARD_FILE"
-    ],
-    "infra_step": true,
-    "name": "checkout c.cache.remove git cache guard file",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "vpython3",
-      "-u",
-      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
-      "--json-output",
-      "/path/to/tmp/json",
-      "copytree",
-      "--symlinks",
-      "[CACHE]/git/bar.googlesource.com-c",
-      "[START_DIR]/project"
-    ],
-    "infra_step": true,
-    "name": "checkout c.copy from cache",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "checkout c.git checkout",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "checkout c.git checkout.timeout 10s",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "vpython3",
-      "-u",
-      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
-      "--json-output",
-      "/path/to/tmp/json",
-      "ensure-directory",
-      "--mode",
-      "0o777",
-      "[START_DIR]/project"
-    ],
-    "infra_step": true,
-    "luci_context": {
-      "deadline": {
-        "grace_period": 30.0,
-        "soft_deadline": 1337000019.0
-      }
-    },
-    "name": "checkout c.git checkout.makedirs",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "init"
-    ],
-    "cwd": "[START_DIR]/project",
-    "infra_step": true,
-    "name": "checkout c.git checkout.git init",
-    "timeout": 300.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "remote",
-      "add",
-      "origin",
-      "https://bar.googlesource.com/c"
-    ],
-    "cwd": "[START_DIR]/project",
-    "infra_step": true,
-    "name": "checkout c.git checkout.git remote",
-    "timeout": 600.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "config",
-      "core.longpaths",
-      "true"
-    ],
-    "cwd": "[START_DIR]/project",
-    "infra_step": true,
-    "name": "checkout c.git checkout.set core.longpaths",
-    "timeout": 300.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "config",
-      "fetch.uriprotocols",
-      "https"
-    ],
-    "cwd": "[START_DIR]/project",
-    "infra_step": true,
-    "name": "checkout c.git checkout.set fetch.uriprotocols",
-    "timeout": 300.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "fetch",
-      "--tags",
-      "--jobs",
-      "4",
-      "origin",
-      "main"
-    ],
-    "cwd": "[START_DIR]/project",
-    "infra_step": true,
-    "name": "checkout c.git checkout.git fetch",
-    "timeout": 1200.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "checkout",
-      "-f",
-      "FETCH_HEAD"
-    ],
-    "cwd": "[START_DIR]/project",
-    "infra_step": true,
-    "name": "checkout c.git checkout.git checkout",
-    "timeout": 600.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "rev-parse",
-      "HEAD"
-    ],
-    "cwd": "[START_DIR]/project",
-    "infra_step": true,
-    "name": "checkout c.git checkout.git rev-parse",
-    "timeout": 300.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "clean",
-      "-f",
-      "-d",
-      "-x"
-    ],
-    "cwd": "[START_DIR]/project",
-    "infra_step": true,
-    "name": "checkout c.git checkout.git clean",
-    "timeout": 600.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "checkout c.git log",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "log",
-      "--oneline",
-      "-n",
-      "10"
-    ],
-    "cwd": "[START_DIR]/project",
-    "name": "checkout c.git log.[START_DIR]/project",
-    "timeout": 600.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "clean",
-      "-f",
-      "-f",
-      "-d"
-    ],
-    "cwd": "[START_DIR]/project",
-    "name": "checkout c.git clean",
-    "timeout": 600.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "status"
-    ],
-    "cwd": "[START_DIR]/project",
-    "name": "checkout c.git status",
-    "timeout": 600.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "vpython3",
-      "-u",
-      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
-      "--json-output",
-      "/path/to/tmp/json",
-      "ensure-directory",
-      "--mode",
-      "0o777",
-      "[START_DIR]/snapshot"
-    ],
-    "infra_step": true,
-    "name": "checkout c.mkdir",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "submodule",
-      "status",
-      "--recursive"
-    ],
-    "cwd": "[START_DIR]/project",
-    "name": "checkout c.submodule-status",
-    "timeout": 600.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "vpython3",
-      "-u",
-      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
-      "--json-output",
-      "/path/to/tmp/json",
-      "copy",
-      "submodule status filler text",
-      "[START_DIR]/snapshot/submodules.log"
-    ],
-    "infra_step": true,
-    "name": "checkout c.write submodule snapshot",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@",
-      "@@@STEP_LOG_LINE@submodules.log@submodule status filler text@@@",
-      "@@@STEP_LOG_END@submodules.log@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "log",
-      "--oneline",
-      "-n",
-      "10"
-    ],
-    "cwd": "[START_DIR]/project",
-    "name": "checkout c.log",
-    "timeout": 600.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "vpython3",
-      "-u",
-      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
-      "--json-output",
-      "/path/to/tmp/json",
-      "copy",
-      "",
-      "[START_DIR]/snapshot/git.log"
-    ],
-    "infra_step": true,
-    "name": "checkout c.write git log",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@",
-      "@@@STEP_LOG_END@git.log@@@"
-    ]
-  },
-  {
     "cmd": [
       "git",
       "ls-remote",
@@ -582,6 +59,366 @@
     ]
   },
   {
+    "cmd": [],
+    "name": "ensure infra/tools/luci/gitiles/${platform}"
+  },
+  {
+    "cmd": [],
+    "name": "ensure infra/tools/luci/gitiles/${platform}.get packages",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "vpython3",
+      "-u",
+      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
+      "--json-output",
+      "/path/to/tmp/json",
+      "copy",
+      "RECIPE_MODULE[fuchsia::gitiles]/resources/cipd.ensure",
+      "/path/to/tmp/"
+    ],
+    "infra_step": true,
+    "name": "ensure infra/tools/luci/gitiles/${platform}.get packages.read ensure file",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@2@@@",
+      "@@@STEP_LOG_LINE@cipd.ensure@infra/tools/luci/gitiles/${platform} version:pinned-version@@@",
+      "@@@STEP_LOG_END@cipd.ensure@@@"
+    ]
+  },
+  {
+    "cmd": [],
+    "name": "ensure infra/tools/luci/gitiles/${platform}.install infra/tools/luci/gitiles",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "vpython3",
+      "-u",
+      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
+      "--json-output",
+      "/path/to/tmp/json",
+      "ensure-directory",
+      "--mode",
+      "0o777",
+      "[START_DIR]/cipd_tool/infra/tools/luci/gitiles/0e548aa33f8113a45a5b3b62201e114e98e63d00f97296912380138f44597b07"
+    ],
+    "infra_step": true,
+    "name": "ensure infra/tools/luci/gitiles/${platform}.install infra/tools/luci/gitiles.ensure package directory",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@2@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "cipd",
+      "ensure",
+      "-root",
+      "[START_DIR]/cipd_tool/infra/tools/luci/gitiles/0e548aa33f8113a45a5b3b62201e114e98e63d00f97296912380138f44597b07",
+      "-ensure-file",
+      "infra/tools/luci/gitiles/${platform} version:pinned-version",
+      "-max-threads",
+      "0",
+      "-json-output",
+      "/path/to/tmp/json"
+    ],
+    "infra_step": true,
+    "name": "ensure infra/tools/luci/gitiles/${platform}.install infra/tools/luci/gitiles.ensure_installed",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@2@@@",
+      "@@@STEP_LOG_LINE@json.output@{@@@",
+      "@@@STEP_LOG_LINE@json.output@  \"result\": {@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"\": [@@@",
+      "@@@STEP_LOG_LINE@json.output@      {@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"instance_id\": \"resolved-instance_id-of-version:pinned-v\",@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"package\": \"infra/tools/luci/gitiles/resolved-platform\"@@@",
+      "@@@STEP_LOG_LINE@json.output@      }@@@",
+      "@@@STEP_LOG_LINE@json.output@    ]@@@",
+      "@@@STEP_LOG_LINE@json.output@  }@@@",
+      "@@@STEP_LOG_LINE@json.output@}@@@",
+      "@@@STEP_LOG_END@json.output@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "[START_DIR]/cipd_tool/infra/tools/luci/gitiles/0e548aa33f8113a45a5b3b62201e114e98e63d00f97296912380138f44597b07/gitiles",
+      "log",
+      "-json-output",
+      "/path/to/tmp/json",
+      "https://bar.googlesource.com/c",
+      "main..h3ll0"
+    ],
+    "infra_step": true,
+    "name": "log c3",
+    "timeout": 300.0,
+    "~followup_annotations": [
+      "@@@STEP_LOG_LINE@json.output@[@@@",
+      "@@@STEP_LOG_LINE@json.output@  {@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"author\": {@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"email\": \"fake_A@fake_0.email.com\",@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"name\": \"Fake A\",@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"time\": \"Mon Jan 01 00:00:00 2015\"@@@",
+      "@@@STEP_LOG_LINE@json.output@    },@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"committer\": {@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"email\": \"fake_A@fake_0.email.com\",@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"name\": \"Fake A\",@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"time\": \"Mon Jan 01 00:00:00 2015\"@@@",
+      "@@@STEP_LOG_LINE@json.output@    },@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"id\": \"3e30158f2a7caccb7a9f6632a60011e7a44e1e5c\",@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"message\": \"fake A msg 0\",@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"parents\": [@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"83a7614b3b60951511be50db1b9561daff4bb447\"@@@",
+      "@@@STEP_LOG_LINE@json.output@    ],@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"tree\": \"1b6412b24ec3add84836c8fdd1af5ac8e35b61d9\",@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"tree_diff\": [@@@",
+      "@@@STEP_LOG_LINE@json.output@      {@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"new_id\": \"8bea05ad53680fce6937543f0d98cd48e295b8ff\",@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"new_mode\": 33188,@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"new_path\": \"a.py\",@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"old_id\": \"0000000000000000000000000000000000000000\",@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"old_mode\": 0,@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"type\": \"add\"@@@",
+      "@@@STEP_LOG_LINE@json.output@      }@@@",
+      "@@@STEP_LOG_LINE@json.output@    ]@@@",
+      "@@@STEP_LOG_LINE@json.output@  },@@@",
+      "@@@STEP_LOG_LINE@json.output@  {@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"author\": {@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"email\": \"fake_A@fake_1.email.com\",@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"name\": \"Fake A\",@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"time\": \"Mon Jan 01 00:00:00 2015\"@@@",
+      "@@@STEP_LOG_LINE@json.output@    },@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"committer\": {@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"email\": \"fake_A@fake_1.email.com\",@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"name\": \"Fake A\",@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"time\": \"Mon Jan 01 00:00:00 2015\"@@@",
+      "@@@STEP_LOG_LINE@json.output@    },@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"id\": \"3380b83c11e029b7291c83c44e7b1ce09d465fd1\",@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"message\": \"fake A msg 1\",@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"parents\": [@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"8675a52c73c701cb0b2c48f5ed4a9058c624e6cd\"@@@",
+      "@@@STEP_LOG_LINE@json.output@    ],@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"tree\": \"a1b1e6aa501915989b45a95e1224ec2a88655eb3\",@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"tree_diff\": [@@@",
+      "@@@STEP_LOG_LINE@json.output@      {@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"new_id\": \"06bc4c79002f278528aaddae4e056a11f58c19ad\",@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"new_mode\": 33188,@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"new_path\": \"b.py\",@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"old_id\": \"0000000000000000000000000000000000000000\",@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"old_mode\": 0,@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"type\": \"add\"@@@",
+      "@@@STEP_LOG_LINE@json.output@      }@@@",
+      "@@@STEP_LOG_LINE@json.output@    ]@@@",
+      "@@@STEP_LOG_LINE@json.output@  },@@@",
+      "@@@STEP_LOG_LINE@json.output@  {@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"author\": {@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"email\": \"fake_A@fake_2.email.com\",@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"name\": \"Fake A\",@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"time\": \"Mon Jan 01 00:00:00 2015\"@@@",
+      "@@@STEP_LOG_LINE@json.output@    },@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"committer\": {@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"email\": \"fake_A@fake_2.email.com\",@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"name\": \"Fake A\",@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"time\": \"Mon Jan 01 00:00:00 2015\"@@@",
+      "@@@STEP_LOG_LINE@json.output@    },@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"id\": \"363caa907186de786cb5292cd1ab7245da954815\",@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"message\": \"fake A msg 2\",@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"parents\": [@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"255c6325c4c654e17e6b35142e3912c86f1718f2\"@@@",
+      "@@@STEP_LOG_LINE@json.output@    ],@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"tree\": \"e84d4ad259e69da73d2b842e2b9709f08e8b22bd\",@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"tree_diff\": [@@@",
+      "@@@STEP_LOG_LINE@json.output@      {@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"new_id\": \"d7f478bf423219f2f47c1a6ed344fc597a8bf18f\",@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"new_mode\": 33188,@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"new_path\": \"c.py\",@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"old_id\": \"0000000000000000000000000000000000000000\",@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"old_mode\": 0,@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"type\": \"add\"@@@",
+      "@@@STEP_LOG_LINE@json.output@      }@@@",
+      "@@@STEP_LOG_LINE@json.output@    ]@@@",
+      "@@@STEP_LOG_LINE@json.output@  }@@@",
+      "@@@STEP_LOG_LINE@json.output@]@@@",
+      "@@@STEP_LOG_END@json.output@@@"
+    ]
+  },
+  {
+    "cmd": [],
+    "name": "get gerrit change numbers"
+  },
+  {
+    "cmd": [],
+    "name": "get gerrit change numbers.ensure infra/tools/luci/gerrit/${platform}",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@"
+    ]
+  },
+  {
+    "cmd": [],
+    "name": "get gerrit change numbers.ensure infra/tools/luci/gerrit/${platform}.get packages",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@2@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "vpython3",
+      "-u",
+      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
+      "--json-output",
+      "/path/to/tmp/json",
+      "copy",
+      "RECIPE_MODULE[fuchsia::gerrit]/resources/cipd.ensure",
+      "/path/to/tmp/"
+    ],
+    "infra_step": true,
+    "name": "get gerrit change numbers.ensure infra/tools/luci/gerrit/${platform}.get packages.read ensure file",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@3@@@",
+      "@@@STEP_LOG_LINE@cipd.ensure@infra/tools/luci/gerrit/${platform} version:pinned-version@@@",
+      "@@@STEP_LOG_END@cipd.ensure@@@"
+    ]
+  },
+  {
+    "cmd": [],
+    "name": "get gerrit change numbers.ensure infra/tools/luci/gerrit/${platform}.install infra/tools/luci/gerrit",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@2@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "vpython3",
+      "-u",
+      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
+      "--json-output",
+      "/path/to/tmp/json",
+      "ensure-directory",
+      "--mode",
+      "0o777",
+      "[START_DIR]/cipd_tool/infra/tools/luci/gerrit/0e548aa33f8113a45a5b3b62201e114e98e63d00f97296912380138f44597b07"
+    ],
+    "infra_step": true,
+    "name": "get gerrit change numbers.ensure infra/tools/luci/gerrit/${platform}.install infra/tools/luci/gerrit.ensure package directory",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@3@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "cipd",
+      "ensure",
+      "-root",
+      "[START_DIR]/cipd_tool/infra/tools/luci/gerrit/0e548aa33f8113a45a5b3b62201e114e98e63d00f97296912380138f44597b07",
+      "-ensure-file",
+      "infra/tools/luci/gerrit/${platform} version:pinned-version",
+      "-max-threads",
+      "0",
+      "-json-output",
+      "/path/to/tmp/json"
+    ],
+    "infra_step": true,
+    "name": "get gerrit change numbers.ensure infra/tools/luci/gerrit/${platform}.install infra/tools/luci/gerrit.ensure_installed",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@3@@@",
+      "@@@STEP_LOG_LINE@json.output@{@@@",
+      "@@@STEP_LOG_LINE@json.output@  \"result\": {@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"\": [@@@",
+      "@@@STEP_LOG_LINE@json.output@      {@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"instance_id\": \"resolved-instance_id-of-version:pinned-v\",@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"package\": \"infra/tools/luci/gerrit/resolved-platform\"@@@",
+      "@@@STEP_LOG_LINE@json.output@      }@@@",
+      "@@@STEP_LOG_LINE@json.output@    ]@@@",
+      "@@@STEP_LOG_LINE@json.output@  }@@@",
+      "@@@STEP_LOG_LINE@json.output@}@@@",
+      "@@@STEP_LOG_END@json.output@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "[START_DIR]/cipd_tool/infra/tools/luci/gerrit/0e548aa33f8113a45a5b3b62201e114e98e63d00f97296912380138f44597b07/gerrit",
+      "change-detail",
+      "-host",
+      "https://bar-review.googlesource.com",
+      "-input",
+      "{\"change_id\": \"3e30158f2a7caccb7a9f6632a60011e7a44e1e5c\"}",
+      "-output",
+      "/path/to/tmp/json"
+    ],
+    "infra_step": true,
+    "name": "get gerrit change numbers.change details for 3e30158",
+    "timeout": 600,
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@",
+      "@@@STEP_LOG_LINE@json.output@{@@@",
+      "@@@STEP_LOG_LINE@json.output@  \"_number\": 12345@@@",
+      "@@@STEP_LOG_LINE@json.output@}@@@",
+      "@@@STEP_LOG_END@json.output@@@",
+      "@@@STEP_LOG_LINE@json.input@{@@@",
+      "@@@STEP_LOG_LINE@json.input@  \"change_id\": \"3e30158f2a7caccb7a9f6632a60011e7a44e1e5c\"@@@",
+      "@@@STEP_LOG_LINE@json.input@}@@@",
+      "@@@STEP_LOG_END@json.input@@@",
+      "@@@STEP_LINK@gerrit link@https://bar-review.googlesource.com/q/3e30158f2a7caccb7a9f6632a60011e7a44e1e5c@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "[START_DIR]/cipd_tool/infra/tools/luci/gerrit/0e548aa33f8113a45a5b3b62201e114e98e63d00f97296912380138f44597b07/gerrit",
+      "change-detail",
+      "-host",
+      "https://bar-review.googlesource.com",
+      "-input",
+      "{\"change_id\": \"3380b83c11e029b7291c83c44e7b1ce09d465fd1\"}",
+      "-output",
+      "/path/to/tmp/json"
+    ],
+    "infra_step": true,
+    "name": "get gerrit change numbers.change details for 3380b83",
+    "timeout": 600,
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@",
+      "@@@STEP_LOG_LINE@json.output@{@@@",
+      "@@@STEP_LOG_LINE@json.output@  \"_number\": 12345@@@",
+      "@@@STEP_LOG_LINE@json.output@}@@@",
+      "@@@STEP_LOG_END@json.output@@@",
+      "@@@STEP_LOG_LINE@json.input@{@@@",
+      "@@@STEP_LOG_LINE@json.input@  \"change_id\": \"3380b83c11e029b7291c83c44e7b1ce09d465fd1\"@@@",
+      "@@@STEP_LOG_LINE@json.input@}@@@",
+      "@@@STEP_LOG_END@json.input@@@",
+      "@@@STEP_LINK@gerrit link@https://bar-review.googlesource.com/q/3380b83c11e029b7291c83c44e7b1ce09d465fd1@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "[START_DIR]/cipd_tool/infra/tools/luci/gerrit/0e548aa33f8113a45a5b3b62201e114e98e63d00f97296912380138f44597b07/gerrit",
+      "change-detail",
+      "-host",
+      "https://bar-review.googlesource.com",
+      "-input",
+      "{\"change_id\": \"363caa907186de786cb5292cd1ab7245da954815\"}",
+      "-output",
+      "/path/to/tmp/json"
+    ],
+    "infra_step": true,
+    "name": "get gerrit change numbers.change details for 363caa9",
+    "timeout": 600,
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@",
+      "@@@STEP_LOG_LINE@json.output@{@@@",
+      "@@@STEP_LOG_LINE@json.output@  \"_number\": 12345@@@",
+      "@@@STEP_LOG_LINE@json.output@}@@@",
+      "@@@STEP_LOG_END@json.output@@@",
+      "@@@STEP_LOG_LINE@json.input@{@@@",
+      "@@@STEP_LOG_LINE@json.input@  \"change_id\": \"363caa907186de786cb5292cd1ab7245da954815\"@@@",
+      "@@@STEP_LOG_LINE@json.input@}@@@",
+      "@@@STEP_LOG_END@json.input@@@",
+      "@@@STEP_LINK@gerrit link@https://bar-review.googlesource.com/q/363caa907186de786cb5292cd1ab7245da954815@@@"
+    ]
+  },
+  {
     "cmd": [
       "vpython3",
       "-u",
@@ -623,242 +460,22 @@
   },
   {
     "cmd": [],
-    "name": "remote"
-  },
-  {
-    "cmd": [
-      "git",
-      "remote"
-    ],
-    "cwd": "[START_DIR]/project",
-    "name": "remote.name",
-    "timeout": 600.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "remote",
-      "get-url",
-      "origin"
-    ],
-    "cwd": "[START_DIR]/project",
-    "name": "remote.url",
-    "timeout": 600.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "c3"
-  },
-  {
-    "cmd": [
-      "git",
-      "log",
-      "--pretty=format:%H\n%an\n%ae\n%B",
-      "-z",
-      "--max-count",
-      "5",
-      "h3ll0"
-    ],
-    "cwd": "[START_DIR]/project",
-    "name": "c3.git log",
-    "timeout": 600.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "c3.ensure infra/tools/luci/gerrit/${platform}",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "c3.ensure infra/tools/luci/gerrit/${platform}.get packages",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "vpython3",
-      "-u",
-      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
-      "--json-output",
-      "/path/to/tmp/json",
-      "copy",
-      "RECIPE_MODULE[fuchsia::gerrit]/resources/cipd.ensure",
-      "/path/to/tmp/"
-    ],
-    "cwd": "[START_DIR]/project",
-    "infra_step": true,
-    "name": "c3.ensure infra/tools/luci/gerrit/${platform}.get packages.read ensure file",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@3@@@",
-      "@@@STEP_LOG_LINE@cipd.ensure@infra/tools/luci/gerrit/${platform} version:pinned-version@@@",
-      "@@@STEP_LOG_END@cipd.ensure@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "c3.ensure infra/tools/luci/gerrit/${platform}.install infra/tools/luci/gerrit",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "vpython3",
-      "-u",
-      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
-      "--json-output",
-      "/path/to/tmp/json",
-      "ensure-directory",
-      "--mode",
-      "0o777",
-      "[START_DIR]/cipd_tool/infra/tools/luci/gerrit/0e548aa33f8113a45a5b3b62201e114e98e63d00f97296912380138f44597b07"
-    ],
-    "cwd": "[START_DIR]/project",
-    "infra_step": true,
-    "name": "c3.ensure infra/tools/luci/gerrit/${platform}.install infra/tools/luci/gerrit.ensure package directory",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@3@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "cipd",
-      "ensure",
-      "-root",
-      "[START_DIR]/cipd_tool/infra/tools/luci/gerrit/0e548aa33f8113a45a5b3b62201e114e98e63d00f97296912380138f44597b07",
-      "-ensure-file",
-      "infra/tools/luci/gerrit/${platform} version:pinned-version",
-      "-max-threads",
-      "0",
-      "-json-output",
-      "/path/to/tmp/json"
-    ],
-    "cwd": "[START_DIR]/project",
-    "infra_step": true,
-    "name": "c3.ensure infra/tools/luci/gerrit/${platform}.install infra/tools/luci/gerrit.ensure_installed",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@3@@@",
-      "@@@STEP_LOG_LINE@json.output@{@@@",
-      "@@@STEP_LOG_LINE@json.output@  \"result\": {@@@",
-      "@@@STEP_LOG_LINE@json.output@    \"\": [@@@",
-      "@@@STEP_LOG_LINE@json.output@      {@@@",
-      "@@@STEP_LOG_LINE@json.output@        \"instance_id\": \"resolved-instance_id-of-version:pinned-v\",@@@",
-      "@@@STEP_LOG_LINE@json.output@        \"package\": \"infra/tools/luci/gerrit/resolved-platform\"@@@",
-      "@@@STEP_LOG_LINE@json.output@      }@@@",
-      "@@@STEP_LOG_LINE@json.output@    ]@@@",
-      "@@@STEP_LOG_LINE@json.output@  }@@@",
-      "@@@STEP_LOG_LINE@json.output@}@@@",
-      "@@@STEP_LOG_END@json.output@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "[START_DIR]/cipd_tool/infra/tools/luci/gerrit/0e548aa33f8113a45a5b3b62201e114e98e63d00f97296912380138f44597b07/gerrit",
-      "change-query",
-      "-host",
-      "https://pigweed-review.googlesource.com",
-      "-input",
-      "{\"params\": {\"q\": \"commit:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\"}}",
-      "-output",
-      "/path/to/tmp/json"
-    ],
-    "cwd": "[START_DIR]/project",
-    "infra_step": true,
-    "name": "c3.get change-id",
-    "timeout": 600,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@",
-      "@@@STEP_LOG_LINE@json.output@[@@@",
-      "@@@STEP_LOG_LINE@json.output@  {@@@",
-      "@@@STEP_LOG_LINE@json.output@    \"_number\": 12345@@@",
-      "@@@STEP_LOG_LINE@json.output@  }@@@",
-      "@@@STEP_LOG_LINE@json.output@]@@@",
-      "@@@STEP_LOG_END@json.output@@@",
-      "@@@STEP_LOG_LINE@json.input@{@@@",
-      "@@@STEP_LOG_LINE@json.input@  \"params\": {@@@",
-      "@@@STEP_LOG_LINE@json.input@    \"q\": \"commit:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\"@@@",
-      "@@@STEP_LOG_LINE@json.input@  }@@@",
-      "@@@STEP_LOG_LINE@json.input@}@@@",
-      "@@@STEP_LOG_END@json.input@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "[START_DIR]/cipd_tool/infra/tools/luci/gerrit/0e548aa33f8113a45a5b3b62201e114e98e63d00f97296912380138f44597b07/gerrit",
-      "change-detail",
-      "-host",
-      "https://pigweed-review.googlesource.com",
-      "-input",
-      "{\"change_id\": \"12345\"}",
-      "-output",
-      "/path/to/tmp/json"
-    ],
-    "cwd": "[START_DIR]/project",
-    "infra_step": true,
-    "name": "c3.get 12345",
-    "timeout": 600,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@",
-      "@@@STEP_LOG_LINE@json.output@{@@@",
-      "@@@STEP_LOG_LINE@json.output@  \"owner\": {@@@",
-      "@@@STEP_LOG_LINE@json.output@    \"email\": \"author@example.com\",@@@",
-      "@@@STEP_LOG_LINE@json.output@    \"name\": \"author\"@@@",
-      "@@@STEP_LOG_LINE@json.output@  },@@@",
-      "@@@STEP_LOG_LINE@json.output@  \"reviewers\": {@@@",
-      "@@@STEP_LOG_LINE@json.output@    \"REVIEWER\": [@@@",
-      "@@@STEP_LOG_LINE@json.output@      {@@@",
-      "@@@STEP_LOG_LINE@json.output@        \"email\": \"reviewer@example.com\",@@@",
-      "@@@STEP_LOG_LINE@json.output@        \"name\": \"reviewer\"@@@",
-      "@@@STEP_LOG_LINE@json.output@      },@@@",
-      "@@@STEP_LOG_LINE@json.output@      {@@@",
-      "@@@STEP_LOG_LINE@json.output@        \"email\": \"nobody@google.com\",@@@",
-      "@@@STEP_LOG_LINE@json.output@        \"name\": \"nobody\"@@@",
-      "@@@STEP_LOG_LINE@json.output@      },@@@",
-      "@@@STEP_LOG_LINE@json.output@      {@@@",
-      "@@@STEP_LOG_LINE@json.output@        \"email\": \"robot@gserviceaccount.com\",@@@",
-      "@@@STEP_LOG_LINE@json.output@        \"name\": \"robot\"@@@",
-      "@@@STEP_LOG_LINE@json.output@      }@@@",
-      "@@@STEP_LOG_LINE@json.output@    ]@@@",
-      "@@@STEP_LOG_LINE@json.output@  }@@@",
-      "@@@STEP_LOG_LINE@json.output@}@@@",
-      "@@@STEP_LOG_END@json.output@@@",
-      "@@@STEP_LOG_LINE@json.input@{@@@",
-      "@@@STEP_LOG_LINE@json.input@  \"change_id\": \"12345\"@@@",
-      "@@@STEP_LOG_LINE@json.input@}@@@",
-      "@@@STEP_LOG_END@json.input@@@",
-      "@@@STEP_LINK@gerrit link@https://pigweed-review.googlesource.com/q/12345@@@"
-    ]
-  },
-  {
-    "cmd": [],
     "name": "roll"
   },
   {
     "cmd": [],
-    "name": "roll.project_name",
+    "name": "roll.repo_url",
     "~followup_annotations": [
       "@@@STEP_NEST_LEVEL@1@@@",
-      "@@@STEP_SUMMARY_TEXT@c3@@@"
+      "@@@STEP_SUMMARY_TEXT@https://bar.googlesource.com/c@@@"
     ]
   },
   {
     "cmd": [],
-    "name": "roll.proj_dir",
+    "name": "roll.repo_short_name",
     "~followup_annotations": [
       "@@@STEP_NEST_LEVEL@1@@@",
-      "@@@STEP_SUMMARY_TEXT@[START_DIR]/project@@@"
+      "@@@STEP_SUMMARY_TEXT@c3@@@"
     ]
   },
   {
@@ -879,10 +496,10 @@
   },
   {
     "cmd": [],
-    "name": "roll.direction",
+    "name": "roll.commit message",
     "~followup_annotations": [
       "@@@STEP_NEST_LEVEL@1@@@",
-      "@@@STEP_SUMMARY_TEXT@Direction.FORWARD@@@"
+      "@@@STEP_SUMMARY_TEXT@[roll] Roll c3 main..h3ll0 (3 commits)\n\n3e30158:https://bar-review.googlesource.com/c/c/+/12345 fake A msg 0\n3380b83:https://bar-review.googlesource.com/c/c/+/12345 fake A msg 1\n363caa9:https://bar-review.googlesource.com/c/c/+/12345 fake A msg 2\n\nRolled-Repo: https://bar.googlesource.com/c\nRolled-Commits: main..h3ll0@@@"
     ]
   },
   {
diff --git a/recipe_modules/repo_roll/tests/full.expected/no-trigger-with-revision-hash.json b/recipe_modules/repo_roll/tests/full.expected/no-trigger-with-revision-hash.json
index cf957bf..4b62343 100644
--- a/recipe_modules/repo_roll/tests/full.expected/no-trigger-with-revision-hash.json
+++ b/recipe_modules/repo_roll/tests/full.expected/no-trigger-with-revision-hash.json
@@ -44,529 +44,6 @@
     ]
   },
   {
-    "cmd": [],
-    "name": "checkout d"
-  },
-  {
-    "cmd": [],
-    "name": "checkout d.options",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@",
-      "@@@STEP_SUMMARY_TEXT@remote: \"https://bar.googlesource.com/d\"\nbranch: \"main\"\n@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "checkout d.options with defaults",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@",
-      "@@@STEP_SUMMARY_TEXT@remote: \"https://bar.googlesource.com/d\"\nbranch: \"main\"\nmanifest_file: \"default.xml\"\nrepo_init_timeout_sec: 20\nrepo_sync_timeout_sec: 120\nnumber_of_attempts: 3\nsubmodule_timeout_sec: 600\n@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "checkout d.not matching branch names",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "checkout d.cache",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@",
-      "@@@STEP_SUMMARY_TEXT@miss@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "vpython3",
-      "-u",
-      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
-      "--json-output",
-      "/path/to/tmp/json",
-      "ensure-directory",
-      "--mode",
-      "0o777",
-      "[CACHE]/git"
-    ],
-    "infra_step": true,
-    "name": "checkout d.cache.ensure git cache dir",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "vpython3",
-      "-u",
-      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
-      "--json-output",
-      "/path/to/tmp/json",
-      "copy",
-      "",
-      "[CACHE]/git/.GUARD_FILE"
-    ],
-    "infra_step": true,
-    "name": "checkout d.cache.write git cache guard file",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "vpython3",
-      "-u",
-      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
-      "--json-output",
-      "/path/to/tmp/json",
-      "ensure-directory",
-      "--mode",
-      "0o777",
-      "[CACHE]/git/bar.googlesource.com-d"
-    ],
-    "infra_step": true,
-    "name": "checkout d.cache.makedirs",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "init"
-    ],
-    "cwd": "[CACHE]/git/bar.googlesource.com-d",
-    "infra_step": true,
-    "name": "checkout d.cache.git init",
-    "timeout": 300.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "config",
-      "remote.origin.url",
-      "https://bar.googlesource.com/d"
-    ],
-    "cwd": "[CACHE]/git/bar.googlesource.com-d",
-    "infra_step": true,
-    "name": "checkout d.cache.remote set-url",
-    "timeout": 300.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "config",
-      "fetch.uriprotocols",
-      "https"
-    ],
-    "cwd": "[CACHE]/git/bar.googlesource.com-d",
-    "infra_step": true,
-    "name": "checkout d.cache.set fetch.uriprotocols",
-    "timeout": 300.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "checkout d.cache.timeout 10s",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "fetch",
-      "--prune",
-      "--tags",
-      "--jobs",
-      "4",
-      "origin",
-      "--no-recurse-submodules"
-    ],
-    "cwd": "[CACHE]/git/bar.googlesource.com-d",
-    "infra_step": true,
-    "name": "checkout d.cache.git fetch",
-    "timeout": 1200.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "merge",
-      "FETCH_HEAD"
-    ],
-    "cwd": "[CACHE]/git/bar.googlesource.com-d",
-    "infra_step": true,
-    "name": "checkout d.cache.git merge",
-    "timeout": 600.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "checkout d.cache.timeout 10s (2)",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "submodule",
-      "update",
-      "--recursive",
-      "--force",
-      "--jobs",
-      "4"
-    ],
-    "cwd": "[CACHE]/git/bar.googlesource.com-d",
-    "infra_step": true,
-    "name": "checkout d.cache.git submodule update",
-    "timeout": 600,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "vpython3",
-      "-u",
-      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
-      "--json-output",
-      "/path/to/tmp/json",
-      "remove",
-      "[CACHE]/git/.GUARD_FILE"
-    ],
-    "infra_step": true,
-    "name": "checkout d.cache.remove git cache guard file",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "vpython3",
-      "-u",
-      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
-      "--json-output",
-      "/path/to/tmp/json",
-      "copytree",
-      "--symlinks",
-      "[CACHE]/git/bar.googlesource.com-d",
-      "[START_DIR]/project"
-    ],
-    "infra_step": true,
-    "name": "checkout d.copy from cache",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "checkout d.git checkout",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "checkout d.git checkout.timeout 10s",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "vpython3",
-      "-u",
-      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
-      "--json-output",
-      "/path/to/tmp/json",
-      "ensure-directory",
-      "--mode",
-      "0o777",
-      "[START_DIR]/project"
-    ],
-    "infra_step": true,
-    "luci_context": {
-      "deadline": {
-        "grace_period": 30.0,
-        "soft_deadline": 1337000019.0
-      }
-    },
-    "name": "checkout d.git checkout.makedirs",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "init"
-    ],
-    "cwd": "[START_DIR]/project",
-    "infra_step": true,
-    "name": "checkout d.git checkout.git init",
-    "timeout": 300.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "remote",
-      "add",
-      "origin",
-      "https://bar.googlesource.com/d"
-    ],
-    "cwd": "[START_DIR]/project",
-    "infra_step": true,
-    "name": "checkout d.git checkout.git remote",
-    "timeout": 600.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "config",
-      "core.longpaths",
-      "true"
-    ],
-    "cwd": "[START_DIR]/project",
-    "infra_step": true,
-    "name": "checkout d.git checkout.set core.longpaths",
-    "timeout": 300.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "config",
-      "fetch.uriprotocols",
-      "https"
-    ],
-    "cwd": "[START_DIR]/project",
-    "infra_step": true,
-    "name": "checkout d.git checkout.set fetch.uriprotocols",
-    "timeout": 300.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "fetch",
-      "--tags",
-      "--jobs",
-      "4",
-      "origin",
-      "main"
-    ],
-    "cwd": "[START_DIR]/project",
-    "infra_step": true,
-    "name": "checkout d.git checkout.git fetch",
-    "timeout": 1200.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "checkout",
-      "-f",
-      "FETCH_HEAD"
-    ],
-    "cwd": "[START_DIR]/project",
-    "infra_step": true,
-    "name": "checkout d.git checkout.git checkout",
-    "timeout": 600.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "rev-parse",
-      "HEAD"
-    ],
-    "cwd": "[START_DIR]/project",
-    "infra_step": true,
-    "name": "checkout d.git checkout.git rev-parse",
-    "timeout": 300.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "clean",
-      "-f",
-      "-d",
-      "-x"
-    ],
-    "cwd": "[START_DIR]/project",
-    "infra_step": true,
-    "name": "checkout d.git checkout.git clean",
-    "timeout": 600.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "checkout d.git log",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "log",
-      "--oneline",
-      "-n",
-      "10"
-    ],
-    "cwd": "[START_DIR]/project",
-    "name": "checkout d.git log.[START_DIR]/project",
-    "timeout": 600.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "clean",
-      "-f",
-      "-f",
-      "-d"
-    ],
-    "cwd": "[START_DIR]/project",
-    "name": "checkout d.git clean",
-    "timeout": 600.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "status"
-    ],
-    "cwd": "[START_DIR]/project",
-    "name": "checkout d.git status",
-    "timeout": 600.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "vpython3",
-      "-u",
-      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
-      "--json-output",
-      "/path/to/tmp/json",
-      "ensure-directory",
-      "--mode",
-      "0o777",
-      "[START_DIR]/snapshot"
-    ],
-    "infra_step": true,
-    "name": "checkout d.mkdir",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "submodule",
-      "status",
-      "--recursive"
-    ],
-    "cwd": "[START_DIR]/project",
-    "name": "checkout d.submodule-status",
-    "timeout": 600.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "vpython3",
-      "-u",
-      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
-      "--json-output",
-      "/path/to/tmp/json",
-      "copy",
-      "submodule status filler text",
-      "[START_DIR]/snapshot/submodules.log"
-    ],
-    "infra_step": true,
-    "name": "checkout d.write submodule snapshot",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@",
-      "@@@STEP_LOG_LINE@submodules.log@submodule status filler text@@@",
-      "@@@STEP_LOG_END@submodules.log@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "log",
-      "--oneline",
-      "-n",
-      "10"
-    ],
-    "cwd": "[START_DIR]/project",
-    "name": "checkout d.log",
-    "timeout": 600.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "vpython3",
-      "-u",
-      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
-      "--json-output",
-      "/path/to/tmp/json",
-      "copy",
-      "",
-      "[START_DIR]/snapshot/git.log"
-    ],
-    "infra_step": true,
-    "name": "checkout d.write git log",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@",
-      "@@@STEP_LOG_END@git.log@@@"
-    ]
-  },
-  {
     "cmd": [
       "git",
       "ls-remote",
diff --git a/recipe_modules/repo_roll/tests/full.expected/no-trigger-with-revision-tag.json b/recipe_modules/repo_roll/tests/full.expected/no-trigger-with-revision-tag.json
index 15518e5..54653e7 100644
--- a/recipe_modules/repo_roll/tests/full.expected/no-trigger-with-revision-tag.json
+++ b/recipe_modules/repo_roll/tests/full.expected/no-trigger-with-revision-tag.json
@@ -44,529 +44,6 @@
     ]
   },
   {
-    "cmd": [],
-    "name": "checkout e5"
-  },
-  {
-    "cmd": [],
-    "name": "checkout e5.options",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@",
-      "@@@STEP_SUMMARY_TEXT@remote: \"https://bar.googlesource.com/e5\"\nbranch: \"main\"\n@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "checkout e5.options with defaults",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@",
-      "@@@STEP_SUMMARY_TEXT@remote: \"https://bar.googlesource.com/e5\"\nbranch: \"main\"\nmanifest_file: \"default.xml\"\nrepo_init_timeout_sec: 20\nrepo_sync_timeout_sec: 120\nnumber_of_attempts: 3\nsubmodule_timeout_sec: 600\n@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "checkout e5.not matching branch names",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "checkout e5.cache",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@",
-      "@@@STEP_SUMMARY_TEXT@miss@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "vpython3",
-      "-u",
-      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
-      "--json-output",
-      "/path/to/tmp/json",
-      "ensure-directory",
-      "--mode",
-      "0o777",
-      "[CACHE]/git"
-    ],
-    "infra_step": true,
-    "name": "checkout e5.cache.ensure git cache dir",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "vpython3",
-      "-u",
-      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
-      "--json-output",
-      "/path/to/tmp/json",
-      "copy",
-      "",
-      "[CACHE]/git/.GUARD_FILE"
-    ],
-    "infra_step": true,
-    "name": "checkout e5.cache.write git cache guard file",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "vpython3",
-      "-u",
-      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
-      "--json-output",
-      "/path/to/tmp/json",
-      "ensure-directory",
-      "--mode",
-      "0o777",
-      "[CACHE]/git/bar.googlesource.com-e5"
-    ],
-    "infra_step": true,
-    "name": "checkout e5.cache.makedirs",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "init"
-    ],
-    "cwd": "[CACHE]/git/bar.googlesource.com-e5",
-    "infra_step": true,
-    "name": "checkout e5.cache.git init",
-    "timeout": 300.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "config",
-      "remote.origin.url",
-      "https://bar.googlesource.com/e5"
-    ],
-    "cwd": "[CACHE]/git/bar.googlesource.com-e5",
-    "infra_step": true,
-    "name": "checkout e5.cache.remote set-url",
-    "timeout": 300.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "config",
-      "fetch.uriprotocols",
-      "https"
-    ],
-    "cwd": "[CACHE]/git/bar.googlesource.com-e5",
-    "infra_step": true,
-    "name": "checkout e5.cache.set fetch.uriprotocols",
-    "timeout": 300.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "checkout e5.cache.timeout 10s",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "fetch",
-      "--prune",
-      "--tags",
-      "--jobs",
-      "4",
-      "origin",
-      "--no-recurse-submodules"
-    ],
-    "cwd": "[CACHE]/git/bar.googlesource.com-e5",
-    "infra_step": true,
-    "name": "checkout e5.cache.git fetch",
-    "timeout": 1200.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "merge",
-      "FETCH_HEAD"
-    ],
-    "cwd": "[CACHE]/git/bar.googlesource.com-e5",
-    "infra_step": true,
-    "name": "checkout e5.cache.git merge",
-    "timeout": 600.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "checkout e5.cache.timeout 10s (2)",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "submodule",
-      "update",
-      "--recursive",
-      "--force",
-      "--jobs",
-      "4"
-    ],
-    "cwd": "[CACHE]/git/bar.googlesource.com-e5",
-    "infra_step": true,
-    "name": "checkout e5.cache.git submodule update",
-    "timeout": 600,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "vpython3",
-      "-u",
-      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
-      "--json-output",
-      "/path/to/tmp/json",
-      "remove",
-      "[CACHE]/git/.GUARD_FILE"
-    ],
-    "infra_step": true,
-    "name": "checkout e5.cache.remove git cache guard file",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "vpython3",
-      "-u",
-      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
-      "--json-output",
-      "/path/to/tmp/json",
-      "copytree",
-      "--symlinks",
-      "[CACHE]/git/bar.googlesource.com-e5",
-      "[START_DIR]/project"
-    ],
-    "infra_step": true,
-    "name": "checkout e5.copy from cache",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "checkout e5.git checkout",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "checkout e5.git checkout.timeout 10s",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "vpython3",
-      "-u",
-      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
-      "--json-output",
-      "/path/to/tmp/json",
-      "ensure-directory",
-      "--mode",
-      "0o777",
-      "[START_DIR]/project"
-    ],
-    "infra_step": true,
-    "luci_context": {
-      "deadline": {
-        "grace_period": 30.0,
-        "soft_deadline": 1337000019.0
-      }
-    },
-    "name": "checkout e5.git checkout.makedirs",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "init"
-    ],
-    "cwd": "[START_DIR]/project",
-    "infra_step": true,
-    "name": "checkout e5.git checkout.git init",
-    "timeout": 300.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "remote",
-      "add",
-      "origin",
-      "https://bar.googlesource.com/e5"
-    ],
-    "cwd": "[START_DIR]/project",
-    "infra_step": true,
-    "name": "checkout e5.git checkout.git remote",
-    "timeout": 600.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "config",
-      "core.longpaths",
-      "true"
-    ],
-    "cwd": "[START_DIR]/project",
-    "infra_step": true,
-    "name": "checkout e5.git checkout.set core.longpaths",
-    "timeout": 300.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "config",
-      "fetch.uriprotocols",
-      "https"
-    ],
-    "cwd": "[START_DIR]/project",
-    "infra_step": true,
-    "name": "checkout e5.git checkout.set fetch.uriprotocols",
-    "timeout": 300.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "fetch",
-      "--tags",
-      "--jobs",
-      "4",
-      "origin",
-      "main"
-    ],
-    "cwd": "[START_DIR]/project",
-    "infra_step": true,
-    "name": "checkout e5.git checkout.git fetch",
-    "timeout": 1200.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "checkout",
-      "-f",
-      "FETCH_HEAD"
-    ],
-    "cwd": "[START_DIR]/project",
-    "infra_step": true,
-    "name": "checkout e5.git checkout.git checkout",
-    "timeout": 600.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "rev-parse",
-      "HEAD"
-    ],
-    "cwd": "[START_DIR]/project",
-    "infra_step": true,
-    "name": "checkout e5.git checkout.git rev-parse",
-    "timeout": 300.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "clean",
-      "-f",
-      "-d",
-      "-x"
-    ],
-    "cwd": "[START_DIR]/project",
-    "infra_step": true,
-    "name": "checkout e5.git checkout.git clean",
-    "timeout": 600.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "checkout e5.git log",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "log",
-      "--oneline",
-      "-n",
-      "10"
-    ],
-    "cwd": "[START_DIR]/project",
-    "name": "checkout e5.git log.[START_DIR]/project",
-    "timeout": 600.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "clean",
-      "-f",
-      "-f",
-      "-d"
-    ],
-    "cwd": "[START_DIR]/project",
-    "name": "checkout e5.git clean",
-    "timeout": 600.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "status"
-    ],
-    "cwd": "[START_DIR]/project",
-    "name": "checkout e5.git status",
-    "timeout": 600.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "vpython3",
-      "-u",
-      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
-      "--json-output",
-      "/path/to/tmp/json",
-      "ensure-directory",
-      "--mode",
-      "0o777",
-      "[START_DIR]/snapshot"
-    ],
-    "infra_step": true,
-    "name": "checkout e5.mkdir",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "submodule",
-      "status",
-      "--recursive"
-    ],
-    "cwd": "[START_DIR]/project",
-    "name": "checkout e5.submodule-status",
-    "timeout": 600.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "vpython3",
-      "-u",
-      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
-      "--json-output",
-      "/path/to/tmp/json",
-      "copy",
-      "submodule status filler text",
-      "[START_DIR]/snapshot/submodules.log"
-    ],
-    "infra_step": true,
-    "name": "checkout e5.write submodule snapshot",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@",
-      "@@@STEP_LOG_LINE@submodules.log@submodule status filler text@@@",
-      "@@@STEP_LOG_END@submodules.log@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "log",
-      "--oneline",
-      "-n",
-      "10"
-    ],
-    "cwd": "[START_DIR]/project",
-    "name": "checkout e5.log",
-    "timeout": 600.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "vpython3",
-      "-u",
-      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
-      "--json-output",
-      "/path/to/tmp/json",
-      "copy",
-      "",
-      "[START_DIR]/snapshot/git.log"
-    ],
-    "infra_step": true,
-    "name": "checkout e5.write git log",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@",
-      "@@@STEP_LOG_END@git.log@@@"
-    ]
-  },
-  {
     "cmd": [
       "git",
       "ls-remote",
diff --git a/recipe_modules/repo_roll/tests/full.expected/no-trigger-with-upstream.json b/recipe_modules/repo_roll/tests/full.expected/no-trigger-with-upstream.json
index c15bcd1..c1c37a3 100644
--- a/recipe_modules/repo_roll/tests/full.expected/no-trigger-with-upstream.json
+++ b/recipe_modules/repo_roll/tests/full.expected/no-trigger-with-upstream.json
@@ -44,529 +44,6 @@
     ]
   },
   {
-    "cmd": [],
-    "name": "checkout a"
-  },
-  {
-    "cmd": [],
-    "name": "checkout a.options",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@",
-      "@@@STEP_SUMMARY_TEXT@remote: \"https://foo.googlesource.com/a\"\nbranch: \"main\"\n@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "checkout a.options with defaults",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@",
-      "@@@STEP_SUMMARY_TEXT@remote: \"https://foo.googlesource.com/a\"\nbranch: \"main\"\nmanifest_file: \"default.xml\"\nrepo_init_timeout_sec: 20\nrepo_sync_timeout_sec: 120\nnumber_of_attempts: 3\nsubmodule_timeout_sec: 600\n@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "checkout a.not matching branch names",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "checkout a.cache",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@",
-      "@@@STEP_SUMMARY_TEXT@miss@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "vpython3",
-      "-u",
-      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
-      "--json-output",
-      "/path/to/tmp/json",
-      "ensure-directory",
-      "--mode",
-      "0o777",
-      "[CACHE]/git"
-    ],
-    "infra_step": true,
-    "name": "checkout a.cache.ensure git cache dir",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "vpython3",
-      "-u",
-      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
-      "--json-output",
-      "/path/to/tmp/json",
-      "copy",
-      "",
-      "[CACHE]/git/.GUARD_FILE"
-    ],
-    "infra_step": true,
-    "name": "checkout a.cache.write git cache guard file",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "vpython3",
-      "-u",
-      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
-      "--json-output",
-      "/path/to/tmp/json",
-      "ensure-directory",
-      "--mode",
-      "0o777",
-      "[CACHE]/git/foo.googlesource.com-a"
-    ],
-    "infra_step": true,
-    "name": "checkout a.cache.makedirs",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "init"
-    ],
-    "cwd": "[CACHE]/git/foo.googlesource.com-a",
-    "infra_step": true,
-    "name": "checkout a.cache.git init",
-    "timeout": 300.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "config",
-      "remote.origin.url",
-      "https://foo.googlesource.com/a"
-    ],
-    "cwd": "[CACHE]/git/foo.googlesource.com-a",
-    "infra_step": true,
-    "name": "checkout a.cache.remote set-url",
-    "timeout": 300.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "config",
-      "fetch.uriprotocols",
-      "https"
-    ],
-    "cwd": "[CACHE]/git/foo.googlesource.com-a",
-    "infra_step": true,
-    "name": "checkout a.cache.set fetch.uriprotocols",
-    "timeout": 300.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "checkout a.cache.timeout 10s",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "fetch",
-      "--prune",
-      "--tags",
-      "--jobs",
-      "4",
-      "origin",
-      "--no-recurse-submodules"
-    ],
-    "cwd": "[CACHE]/git/foo.googlesource.com-a",
-    "infra_step": true,
-    "name": "checkout a.cache.git fetch",
-    "timeout": 1200.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "merge",
-      "FETCH_HEAD"
-    ],
-    "cwd": "[CACHE]/git/foo.googlesource.com-a",
-    "infra_step": true,
-    "name": "checkout a.cache.git merge",
-    "timeout": 600.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "checkout a.cache.timeout 10s (2)",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "submodule",
-      "update",
-      "--recursive",
-      "--force",
-      "--jobs",
-      "4"
-    ],
-    "cwd": "[CACHE]/git/foo.googlesource.com-a",
-    "infra_step": true,
-    "name": "checkout a.cache.git submodule update",
-    "timeout": 600,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "vpython3",
-      "-u",
-      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
-      "--json-output",
-      "/path/to/tmp/json",
-      "remove",
-      "[CACHE]/git/.GUARD_FILE"
-    ],
-    "infra_step": true,
-    "name": "checkout a.cache.remove git cache guard file",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "vpython3",
-      "-u",
-      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
-      "--json-output",
-      "/path/to/tmp/json",
-      "copytree",
-      "--symlinks",
-      "[CACHE]/git/foo.googlesource.com-a",
-      "[START_DIR]/project"
-    ],
-    "infra_step": true,
-    "name": "checkout a.copy from cache",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "checkout a.git checkout",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "checkout a.git checkout.timeout 10s",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "vpython3",
-      "-u",
-      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
-      "--json-output",
-      "/path/to/tmp/json",
-      "ensure-directory",
-      "--mode",
-      "0o777",
-      "[START_DIR]/project"
-    ],
-    "infra_step": true,
-    "luci_context": {
-      "deadline": {
-        "grace_period": 30.0,
-        "soft_deadline": 1337000019.0
-      }
-    },
-    "name": "checkout a.git checkout.makedirs",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "init"
-    ],
-    "cwd": "[START_DIR]/project",
-    "infra_step": true,
-    "name": "checkout a.git checkout.git init",
-    "timeout": 300.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "remote",
-      "add",
-      "origin",
-      "https://foo.googlesource.com/a"
-    ],
-    "cwd": "[START_DIR]/project",
-    "infra_step": true,
-    "name": "checkout a.git checkout.git remote",
-    "timeout": 600.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "config",
-      "core.longpaths",
-      "true"
-    ],
-    "cwd": "[START_DIR]/project",
-    "infra_step": true,
-    "name": "checkout a.git checkout.set core.longpaths",
-    "timeout": 300.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "config",
-      "fetch.uriprotocols",
-      "https"
-    ],
-    "cwd": "[START_DIR]/project",
-    "infra_step": true,
-    "name": "checkout a.git checkout.set fetch.uriprotocols",
-    "timeout": 300.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "fetch",
-      "--tags",
-      "--jobs",
-      "4",
-      "origin",
-      "main"
-    ],
-    "cwd": "[START_DIR]/project",
-    "infra_step": true,
-    "name": "checkout a.git checkout.git fetch",
-    "timeout": 1200.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "checkout",
-      "-f",
-      "FETCH_HEAD"
-    ],
-    "cwd": "[START_DIR]/project",
-    "infra_step": true,
-    "name": "checkout a.git checkout.git checkout",
-    "timeout": 600.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "rev-parse",
-      "HEAD"
-    ],
-    "cwd": "[START_DIR]/project",
-    "infra_step": true,
-    "name": "checkout a.git checkout.git rev-parse",
-    "timeout": 300.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "clean",
-      "-f",
-      "-d",
-      "-x"
-    ],
-    "cwd": "[START_DIR]/project",
-    "infra_step": true,
-    "name": "checkout a.git checkout.git clean",
-    "timeout": 600.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "checkout a.git log",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "log",
-      "--oneline",
-      "-n",
-      "10"
-    ],
-    "cwd": "[START_DIR]/project",
-    "name": "checkout a.git log.[START_DIR]/project",
-    "timeout": 600.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "clean",
-      "-f",
-      "-f",
-      "-d"
-    ],
-    "cwd": "[START_DIR]/project",
-    "name": "checkout a.git clean",
-    "timeout": 600.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "status"
-    ],
-    "cwd": "[START_DIR]/project",
-    "name": "checkout a.git status",
-    "timeout": 600.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "vpython3",
-      "-u",
-      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
-      "--json-output",
-      "/path/to/tmp/json",
-      "ensure-directory",
-      "--mode",
-      "0o777",
-      "[START_DIR]/snapshot"
-    ],
-    "infra_step": true,
-    "name": "checkout a.mkdir",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "submodule",
-      "status",
-      "--recursive"
-    ],
-    "cwd": "[START_DIR]/project",
-    "name": "checkout a.submodule-status",
-    "timeout": 600.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "vpython3",
-      "-u",
-      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
-      "--json-output",
-      "/path/to/tmp/json",
-      "copy",
-      "submodule status filler text",
-      "[START_DIR]/snapshot/submodules.log"
-    ],
-    "infra_step": true,
-    "name": "checkout a.write submodule snapshot",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@",
-      "@@@STEP_LOG_LINE@submodules.log@submodule status filler text@@@",
-      "@@@STEP_LOG_END@submodules.log@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "log",
-      "--oneline",
-      "-n",
-      "10"
-    ],
-    "cwd": "[START_DIR]/project",
-    "name": "checkout a.log",
-    "timeout": 600.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "vpython3",
-      "-u",
-      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
-      "--json-output",
-      "/path/to/tmp/json",
-      "copy",
-      "",
-      "[START_DIR]/snapshot/git.log"
-    ],
-    "infra_step": true,
-    "name": "checkout a.write git log",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@",
-      "@@@STEP_LOG_END@git.log@@@"
-    ]
-  },
-  {
     "cmd": [
       "git",
       "ls-remote",
@@ -583,37 +60,37 @@
   },
   {
     "cmd": [],
-    "name": "get roll direction",
-    "~followup_annotations": [
-      "@@@STEP_SUMMARY_TEXT@forward@@@"
-    ]
+    "name": "ensure infra/tools/luci/gitiles/${platform}"
   },
   {
-    "cmd": [
-      "git",
-      "merge-base",
-      "--is-ancestor",
-      "1111111111111111111111111111111111111111",
-      "h3ll0"
-    ],
-    "cwd": "[START_DIR]/project",
-    "name": "get roll direction.is forward",
-    "timeout": 600.0,
+    "cmd": [],
+    "name": "ensure infra/tools/luci/gitiles/${platform}.get packages",
     "~followup_annotations": [
       "@@@STEP_NEST_LEVEL@1@@@"
     ]
   },
   {
     "cmd": [
-      "git",
-      "merge-base",
-      "--is-ancestor",
-      "h3ll0",
-      "1111111111111111111111111111111111111111"
+      "vpython3",
+      "-u",
+      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
+      "--json-output",
+      "/path/to/tmp/json",
+      "copy",
+      "RECIPE_MODULE[fuchsia::gitiles]/resources/cipd.ensure",
+      "/path/to/tmp/"
     ],
-    "cwd": "[START_DIR]/project",
-    "name": "get roll direction.is backward",
-    "timeout": 600.0,
+    "infra_step": true,
+    "name": "ensure infra/tools/luci/gitiles/${platform}.get packages.read ensure file",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@2@@@",
+      "@@@STEP_LOG_LINE@cipd.ensure@infra/tools/luci/gitiles/${platform} version:pinned-version@@@",
+      "@@@STEP_LOG_END@cipd.ensure@@@"
+    ]
+  },
+  {
+    "cmd": [],
+    "name": "ensure infra/tools/luci/gitiles/${platform}.install infra/tools/luci/gitiles",
     "~followup_annotations": [
       "@@@STEP_NEST_LEVEL@1@@@"
     ]
@@ -625,6 +102,329 @@
       "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
       "--json-output",
       "/path/to/tmp/json",
+      "ensure-directory",
+      "--mode",
+      "0o777",
+      "[START_DIR]/cipd_tool/infra/tools/luci/gitiles/0e548aa33f8113a45a5b3b62201e114e98e63d00f97296912380138f44597b07"
+    ],
+    "infra_step": true,
+    "name": "ensure infra/tools/luci/gitiles/${platform}.install infra/tools/luci/gitiles.ensure package directory",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@2@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "cipd",
+      "ensure",
+      "-root",
+      "[START_DIR]/cipd_tool/infra/tools/luci/gitiles/0e548aa33f8113a45a5b3b62201e114e98e63d00f97296912380138f44597b07",
+      "-ensure-file",
+      "infra/tools/luci/gitiles/${platform} version:pinned-version",
+      "-max-threads",
+      "0",
+      "-json-output",
+      "/path/to/tmp/json"
+    ],
+    "infra_step": true,
+    "name": "ensure infra/tools/luci/gitiles/${platform}.install infra/tools/luci/gitiles.ensure_installed",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@2@@@",
+      "@@@STEP_LOG_LINE@json.output@{@@@",
+      "@@@STEP_LOG_LINE@json.output@  \"result\": {@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"\": [@@@",
+      "@@@STEP_LOG_LINE@json.output@      {@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"instance_id\": \"resolved-instance_id-of-version:pinned-v\",@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"package\": \"infra/tools/luci/gitiles/resolved-platform\"@@@",
+      "@@@STEP_LOG_LINE@json.output@      }@@@",
+      "@@@STEP_LOG_LINE@json.output@    ]@@@",
+      "@@@STEP_LOG_LINE@json.output@  }@@@",
+      "@@@STEP_LOG_LINE@json.output@}@@@",
+      "@@@STEP_LOG_END@json.output@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "[START_DIR]/cipd_tool/infra/tools/luci/gitiles/0e548aa33f8113a45a5b3b62201e114e98e63d00f97296912380138f44597b07/gitiles",
+      "log",
+      "-json-output",
+      "/path/to/tmp/json",
+      "https://foo.googlesource.com/a",
+      "1111111111111111111111111111111111111111..h3ll0"
+    ],
+    "infra_step": true,
+    "name": "log a1",
+    "timeout": 300.0,
+    "~followup_annotations": [
+      "@@@STEP_LOG_LINE@json.output@[@@@",
+      "@@@STEP_LOG_LINE@json.output@  {@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"author\": {@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"email\": \"fake_A@fake_0.email.com\",@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"name\": \"Fake A\",@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"time\": \"Mon Jan 01 00:00:00 2015\"@@@",
+      "@@@STEP_LOG_LINE@json.output@    },@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"committer\": {@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"email\": \"fake_A@fake_0.email.com\",@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"name\": \"Fake A\",@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"time\": \"Mon Jan 01 00:00:00 2015\"@@@",
+      "@@@STEP_LOG_LINE@json.output@    },@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"id\": \"3e30158f2a7caccb7a9f6632a60011e7a44e1e5c\",@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"message\": \"fake A msg 0\",@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"parents\": [@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"83a7614b3b60951511be50db1b9561daff4bb447\"@@@",
+      "@@@STEP_LOG_LINE@json.output@    ],@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"tree\": \"1b6412b24ec3add84836c8fdd1af5ac8e35b61d9\",@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"tree_diff\": [@@@",
+      "@@@STEP_LOG_LINE@json.output@      {@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"new_id\": \"8bea05ad53680fce6937543f0d98cd48e295b8ff\",@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"new_mode\": 33188,@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"new_path\": \"a.py\",@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"old_id\": \"0000000000000000000000000000000000000000\",@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"old_mode\": 0,@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"type\": \"add\"@@@",
+      "@@@STEP_LOG_LINE@json.output@      }@@@",
+      "@@@STEP_LOG_LINE@json.output@    ]@@@",
+      "@@@STEP_LOG_LINE@json.output@  },@@@",
+      "@@@STEP_LOG_LINE@json.output@  {@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"author\": {@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"email\": \"fake_A@fake_1.email.com\",@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"name\": \"Fake A\",@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"time\": \"Mon Jan 01 00:00:00 2015\"@@@",
+      "@@@STEP_LOG_LINE@json.output@    },@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"committer\": {@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"email\": \"fake_A@fake_1.email.com\",@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"name\": \"Fake A\",@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"time\": \"Mon Jan 01 00:00:00 2015\"@@@",
+      "@@@STEP_LOG_LINE@json.output@    },@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"id\": \"3380b83c11e029b7291c83c44e7b1ce09d465fd1\",@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"message\": \"fake A msg 1\",@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"parents\": [@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"8675a52c73c701cb0b2c48f5ed4a9058c624e6cd\"@@@",
+      "@@@STEP_LOG_LINE@json.output@    ],@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"tree\": \"a1b1e6aa501915989b45a95e1224ec2a88655eb3\",@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"tree_diff\": [@@@",
+      "@@@STEP_LOG_LINE@json.output@      {@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"new_id\": \"06bc4c79002f278528aaddae4e056a11f58c19ad\",@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"new_mode\": 33188,@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"new_path\": \"b.py\",@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"old_id\": \"0000000000000000000000000000000000000000\",@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"old_mode\": 0,@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"type\": \"add\"@@@",
+      "@@@STEP_LOG_LINE@json.output@      }@@@",
+      "@@@STEP_LOG_LINE@json.output@    ]@@@",
+      "@@@STEP_LOG_LINE@json.output@  },@@@",
+      "@@@STEP_LOG_LINE@json.output@  {@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"author\": {@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"email\": \"fake_A@fake_2.email.com\",@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"name\": \"Fake A\",@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"time\": \"Mon Jan 01 00:00:00 2015\"@@@",
+      "@@@STEP_LOG_LINE@json.output@    },@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"committer\": {@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"email\": \"fake_A@fake_2.email.com\",@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"name\": \"Fake A\",@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"time\": \"Mon Jan 01 00:00:00 2015\"@@@",
+      "@@@STEP_LOG_LINE@json.output@    },@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"id\": \"363caa907186de786cb5292cd1ab7245da954815\",@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"message\": \"fake A msg 2\",@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"parents\": [@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"255c6325c4c654e17e6b35142e3912c86f1718f2\"@@@",
+      "@@@STEP_LOG_LINE@json.output@    ],@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"tree\": \"e84d4ad259e69da73d2b842e2b9709f08e8b22bd\",@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"tree_diff\": [@@@",
+      "@@@STEP_LOG_LINE@json.output@      {@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"new_id\": \"d7f478bf423219f2f47c1a6ed344fc597a8bf18f\",@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"new_mode\": 33188,@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"new_path\": \"c.py\",@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"old_id\": \"0000000000000000000000000000000000000000\",@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"old_mode\": 0,@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"type\": \"add\"@@@",
+      "@@@STEP_LOG_LINE@json.output@      }@@@",
+      "@@@STEP_LOG_LINE@json.output@    ]@@@",
+      "@@@STEP_LOG_LINE@json.output@  }@@@",
+      "@@@STEP_LOG_LINE@json.output@]@@@",
+      "@@@STEP_LOG_END@json.output@@@"
+    ]
+  },
+  {
+    "cmd": [],
+    "name": "get gerrit change numbers"
+  },
+  {
+    "cmd": [],
+    "name": "get gerrit change numbers.ensure infra/tools/luci/gerrit/${platform}",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@"
+    ]
+  },
+  {
+    "cmd": [],
+    "name": "get gerrit change numbers.ensure infra/tools/luci/gerrit/${platform}.get packages",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@2@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "vpython3",
+      "-u",
+      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
+      "--json-output",
+      "/path/to/tmp/json",
+      "copy",
+      "RECIPE_MODULE[fuchsia::gerrit]/resources/cipd.ensure",
+      "/path/to/tmp/"
+    ],
+    "infra_step": true,
+    "name": "get gerrit change numbers.ensure infra/tools/luci/gerrit/${platform}.get packages.read ensure file",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@3@@@",
+      "@@@STEP_LOG_LINE@cipd.ensure@infra/tools/luci/gerrit/${platform} version:pinned-version@@@",
+      "@@@STEP_LOG_END@cipd.ensure@@@"
+    ]
+  },
+  {
+    "cmd": [],
+    "name": "get gerrit change numbers.ensure infra/tools/luci/gerrit/${platform}.install infra/tools/luci/gerrit",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@2@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "vpython3",
+      "-u",
+      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
+      "--json-output",
+      "/path/to/tmp/json",
+      "ensure-directory",
+      "--mode",
+      "0o777",
+      "[START_DIR]/cipd_tool/infra/tools/luci/gerrit/0e548aa33f8113a45a5b3b62201e114e98e63d00f97296912380138f44597b07"
+    ],
+    "infra_step": true,
+    "name": "get gerrit change numbers.ensure infra/tools/luci/gerrit/${platform}.install infra/tools/luci/gerrit.ensure package directory",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@3@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "cipd",
+      "ensure",
+      "-root",
+      "[START_DIR]/cipd_tool/infra/tools/luci/gerrit/0e548aa33f8113a45a5b3b62201e114e98e63d00f97296912380138f44597b07",
+      "-ensure-file",
+      "infra/tools/luci/gerrit/${platform} version:pinned-version",
+      "-max-threads",
+      "0",
+      "-json-output",
+      "/path/to/tmp/json"
+    ],
+    "infra_step": true,
+    "name": "get gerrit change numbers.ensure infra/tools/luci/gerrit/${platform}.install infra/tools/luci/gerrit.ensure_installed",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@3@@@",
+      "@@@STEP_LOG_LINE@json.output@{@@@",
+      "@@@STEP_LOG_LINE@json.output@  \"result\": {@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"\": [@@@",
+      "@@@STEP_LOG_LINE@json.output@      {@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"instance_id\": \"resolved-instance_id-of-version:pinned-v\",@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"package\": \"infra/tools/luci/gerrit/resolved-platform\"@@@",
+      "@@@STEP_LOG_LINE@json.output@      }@@@",
+      "@@@STEP_LOG_LINE@json.output@    ]@@@",
+      "@@@STEP_LOG_LINE@json.output@  }@@@",
+      "@@@STEP_LOG_LINE@json.output@}@@@",
+      "@@@STEP_LOG_END@json.output@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "[START_DIR]/cipd_tool/infra/tools/luci/gerrit/0e548aa33f8113a45a5b3b62201e114e98e63d00f97296912380138f44597b07/gerrit",
+      "change-detail",
+      "-host",
+      "https://foo-review.googlesource.com",
+      "-input",
+      "{\"change_id\": \"3e30158f2a7caccb7a9f6632a60011e7a44e1e5c\"}",
+      "-output",
+      "/path/to/tmp/json"
+    ],
+    "infra_step": true,
+    "name": "get gerrit change numbers.change details for 3e30158",
+    "timeout": 600,
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@",
+      "@@@STEP_LOG_LINE@json.output@{@@@",
+      "@@@STEP_LOG_LINE@json.output@  \"_number\": 12345@@@",
+      "@@@STEP_LOG_LINE@json.output@}@@@",
+      "@@@STEP_LOG_END@json.output@@@",
+      "@@@STEP_LOG_LINE@json.input@{@@@",
+      "@@@STEP_LOG_LINE@json.input@  \"change_id\": \"3e30158f2a7caccb7a9f6632a60011e7a44e1e5c\"@@@",
+      "@@@STEP_LOG_LINE@json.input@}@@@",
+      "@@@STEP_LOG_END@json.input@@@",
+      "@@@STEP_LINK@gerrit link@https://foo-review.googlesource.com/q/3e30158f2a7caccb7a9f6632a60011e7a44e1e5c@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "[START_DIR]/cipd_tool/infra/tools/luci/gerrit/0e548aa33f8113a45a5b3b62201e114e98e63d00f97296912380138f44597b07/gerrit",
+      "change-detail",
+      "-host",
+      "https://foo-review.googlesource.com",
+      "-input",
+      "{\"change_id\": \"3380b83c11e029b7291c83c44e7b1ce09d465fd1\"}",
+      "-output",
+      "/path/to/tmp/json"
+    ],
+    "infra_step": true,
+    "name": "get gerrit change numbers.change details for 3380b83",
+    "timeout": 600,
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@",
+      "@@@STEP_LOG_LINE@json.output@{@@@",
+      "@@@STEP_LOG_LINE@json.output@  \"_number\": 12345@@@",
+      "@@@STEP_LOG_LINE@json.output@}@@@",
+      "@@@STEP_LOG_END@json.output@@@",
+      "@@@STEP_LOG_LINE@json.input@{@@@",
+      "@@@STEP_LOG_LINE@json.input@  \"change_id\": \"3380b83c11e029b7291c83c44e7b1ce09d465fd1\"@@@",
+      "@@@STEP_LOG_LINE@json.input@}@@@",
+      "@@@STEP_LOG_END@json.input@@@",
+      "@@@STEP_LINK@gerrit link@https://foo-review.googlesource.com/q/3380b83c11e029b7291c83c44e7b1ce09d465fd1@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "[START_DIR]/cipd_tool/infra/tools/luci/gerrit/0e548aa33f8113a45a5b3b62201e114e98e63d00f97296912380138f44597b07/gerrit",
+      "change-detail",
+      "-host",
+      "https://foo-review.googlesource.com",
+      "-input",
+      "{\"change_id\": \"363caa907186de786cb5292cd1ab7245da954815\"}",
+      "-output",
+      "/path/to/tmp/json"
+    ],
+    "infra_step": true,
+    "name": "get gerrit change numbers.change details for 363caa9",
+    "timeout": 600,
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@",
+      "@@@STEP_LOG_LINE@json.output@{@@@",
+      "@@@STEP_LOG_LINE@json.output@  \"_number\": 12345@@@",
+      "@@@STEP_LOG_LINE@json.output@}@@@",
+      "@@@STEP_LOG_END@json.output@@@",
+      "@@@STEP_LOG_LINE@json.input@{@@@",
+      "@@@STEP_LOG_LINE@json.input@  \"change_id\": \"363caa907186de786cb5292cd1ab7245da954815\"@@@",
+      "@@@STEP_LOG_LINE@json.input@}@@@",
+      "@@@STEP_LOG_END@json.input@@@",
+      "@@@STEP_LINK@gerrit link@https://foo-review.googlesource.com/q/363caa907186de786cb5292cd1ab7245da954815@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "vpython3",
+      "-u",
+      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
+      "--json-output",
+      "/path/to/tmp/json",
       "copy",
       "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<manifest>\n  <!-- single-line comment -->\n  <remote fetch=\"sso://foo\" name=\"foo\" review=\"sso://foo\" />\n  <remote fetch=\"sso://bar\" name=\"bar\" review=\"sso://bar\" />\n  <remote fetch=\"..\" name=\"host\" review=\"sso://host\" />\n  <remote fetch=\"../prefix\" name=\"dotdot-prefix\" review=\"sso://host/prefix\" />\n  <remote fetch=\"sso://host/prefix\" name=\"host-prefix\" review=\"sso://host/prefix\" />\n  <default remote=\"bar\" />\n  <project name=\"a\" path=\"a1\" remote=\"foo\" revision=\"h3ll0\" upstream=\"main\" />\n  <project name=\"b\" path=\"b2\" revision=\"2222222222222222222222222222222222222222\" upstream=\"main\" />\n  <!--\n  multi\n  line\n  comment\n  -->\n  <project name=\"c\" path=\"c3\" revision=\"main\" />\n  <project name=\"d\" path=\"d4\" revision=\"0000000000111111111122222222223333333333\" />\n  <project name=\"e5\" revision=\"refs/tags/e\" />\n  <project name=\"f\" path=\"f6\" remote=\"host\" revision=\"main\" />\n  <project name=\"g\" path=\"g7\" remote=\"dotdot-prefix\" revision=\"main\" />\n  <project name=\"h\" path=\"h8\" remote=\"host-prefix\" revision=\"main\" />\n</manifest>\n",
       "[START_DIR]/checkout/default.xml"
@@ -660,240 +460,22 @@
   },
   {
     "cmd": [],
-    "name": "remote"
-  },
-  {
-    "cmd": [
-      "git",
-      "remote"
-    ],
-    "cwd": "[START_DIR]/project",
-    "name": "remote.name",
-    "timeout": 600.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "remote",
-      "get-url",
-      "origin"
-    ],
-    "cwd": "[START_DIR]/project",
-    "name": "remote.url",
-    "timeout": 600.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "a1"
-  },
-  {
-    "cmd": [
-      "git",
-      "log",
-      "--pretty=format:%H\n%an\n%ae\n%B",
-      "-z",
-      "1111111111111111111111111111111111111111..h3ll0"
-    ],
-    "cwd": "[START_DIR]/project",
-    "name": "a1.git log",
-    "timeout": 600.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "a1.ensure infra/tools/luci/gerrit/${platform}",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "a1.ensure infra/tools/luci/gerrit/${platform}.get packages",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "vpython3",
-      "-u",
-      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
-      "--json-output",
-      "/path/to/tmp/json",
-      "copy",
-      "RECIPE_MODULE[fuchsia::gerrit]/resources/cipd.ensure",
-      "/path/to/tmp/"
-    ],
-    "cwd": "[START_DIR]/project",
-    "infra_step": true,
-    "name": "a1.ensure infra/tools/luci/gerrit/${platform}.get packages.read ensure file",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@3@@@",
-      "@@@STEP_LOG_LINE@cipd.ensure@infra/tools/luci/gerrit/${platform} version:pinned-version@@@",
-      "@@@STEP_LOG_END@cipd.ensure@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "a1.ensure infra/tools/luci/gerrit/${platform}.install infra/tools/luci/gerrit",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "vpython3",
-      "-u",
-      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
-      "--json-output",
-      "/path/to/tmp/json",
-      "ensure-directory",
-      "--mode",
-      "0o777",
-      "[START_DIR]/cipd_tool/infra/tools/luci/gerrit/0e548aa33f8113a45a5b3b62201e114e98e63d00f97296912380138f44597b07"
-    ],
-    "cwd": "[START_DIR]/project",
-    "infra_step": true,
-    "name": "a1.ensure infra/tools/luci/gerrit/${platform}.install infra/tools/luci/gerrit.ensure package directory",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@3@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "cipd",
-      "ensure",
-      "-root",
-      "[START_DIR]/cipd_tool/infra/tools/luci/gerrit/0e548aa33f8113a45a5b3b62201e114e98e63d00f97296912380138f44597b07",
-      "-ensure-file",
-      "infra/tools/luci/gerrit/${platform} version:pinned-version",
-      "-max-threads",
-      "0",
-      "-json-output",
-      "/path/to/tmp/json"
-    ],
-    "cwd": "[START_DIR]/project",
-    "infra_step": true,
-    "name": "a1.ensure infra/tools/luci/gerrit/${platform}.install infra/tools/luci/gerrit.ensure_installed",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@3@@@",
-      "@@@STEP_LOG_LINE@json.output@{@@@",
-      "@@@STEP_LOG_LINE@json.output@  \"result\": {@@@",
-      "@@@STEP_LOG_LINE@json.output@    \"\": [@@@",
-      "@@@STEP_LOG_LINE@json.output@      {@@@",
-      "@@@STEP_LOG_LINE@json.output@        \"instance_id\": \"resolved-instance_id-of-version:pinned-v\",@@@",
-      "@@@STEP_LOG_LINE@json.output@        \"package\": \"infra/tools/luci/gerrit/resolved-platform\"@@@",
-      "@@@STEP_LOG_LINE@json.output@      }@@@",
-      "@@@STEP_LOG_LINE@json.output@    ]@@@",
-      "@@@STEP_LOG_LINE@json.output@  }@@@",
-      "@@@STEP_LOG_LINE@json.output@}@@@",
-      "@@@STEP_LOG_END@json.output@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "[START_DIR]/cipd_tool/infra/tools/luci/gerrit/0e548aa33f8113a45a5b3b62201e114e98e63d00f97296912380138f44597b07/gerrit",
-      "change-query",
-      "-host",
-      "https://pigweed-review.googlesource.com",
-      "-input",
-      "{\"params\": {\"q\": \"commit:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\"}}",
-      "-output",
-      "/path/to/tmp/json"
-    ],
-    "cwd": "[START_DIR]/project",
-    "infra_step": true,
-    "name": "a1.get change-id",
-    "timeout": 600,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@",
-      "@@@STEP_LOG_LINE@json.output@[@@@",
-      "@@@STEP_LOG_LINE@json.output@  {@@@",
-      "@@@STEP_LOG_LINE@json.output@    \"_number\": 12345@@@",
-      "@@@STEP_LOG_LINE@json.output@  }@@@",
-      "@@@STEP_LOG_LINE@json.output@]@@@",
-      "@@@STEP_LOG_END@json.output@@@",
-      "@@@STEP_LOG_LINE@json.input@{@@@",
-      "@@@STEP_LOG_LINE@json.input@  \"params\": {@@@",
-      "@@@STEP_LOG_LINE@json.input@    \"q\": \"commit:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\"@@@",
-      "@@@STEP_LOG_LINE@json.input@  }@@@",
-      "@@@STEP_LOG_LINE@json.input@}@@@",
-      "@@@STEP_LOG_END@json.input@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "[START_DIR]/cipd_tool/infra/tools/luci/gerrit/0e548aa33f8113a45a5b3b62201e114e98e63d00f97296912380138f44597b07/gerrit",
-      "change-detail",
-      "-host",
-      "https://pigweed-review.googlesource.com",
-      "-input",
-      "{\"change_id\": \"12345\"}",
-      "-output",
-      "/path/to/tmp/json"
-    ],
-    "cwd": "[START_DIR]/project",
-    "infra_step": true,
-    "name": "a1.get 12345",
-    "timeout": 600,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@",
-      "@@@STEP_LOG_LINE@json.output@{@@@",
-      "@@@STEP_LOG_LINE@json.output@  \"owner\": {@@@",
-      "@@@STEP_LOG_LINE@json.output@    \"email\": \"author@example.com\",@@@",
-      "@@@STEP_LOG_LINE@json.output@    \"name\": \"author\"@@@",
-      "@@@STEP_LOG_LINE@json.output@  },@@@",
-      "@@@STEP_LOG_LINE@json.output@  \"reviewers\": {@@@",
-      "@@@STEP_LOG_LINE@json.output@    \"REVIEWER\": [@@@",
-      "@@@STEP_LOG_LINE@json.output@      {@@@",
-      "@@@STEP_LOG_LINE@json.output@        \"email\": \"reviewer@example.com\",@@@",
-      "@@@STEP_LOG_LINE@json.output@        \"name\": \"reviewer\"@@@",
-      "@@@STEP_LOG_LINE@json.output@      },@@@",
-      "@@@STEP_LOG_LINE@json.output@      {@@@",
-      "@@@STEP_LOG_LINE@json.output@        \"email\": \"nobody@google.com\",@@@",
-      "@@@STEP_LOG_LINE@json.output@        \"name\": \"nobody\"@@@",
-      "@@@STEP_LOG_LINE@json.output@      },@@@",
-      "@@@STEP_LOG_LINE@json.output@      {@@@",
-      "@@@STEP_LOG_LINE@json.output@        \"email\": \"robot@gserviceaccount.com\",@@@",
-      "@@@STEP_LOG_LINE@json.output@        \"name\": \"robot\"@@@",
-      "@@@STEP_LOG_LINE@json.output@      }@@@",
-      "@@@STEP_LOG_LINE@json.output@    ]@@@",
-      "@@@STEP_LOG_LINE@json.output@  }@@@",
-      "@@@STEP_LOG_LINE@json.output@}@@@",
-      "@@@STEP_LOG_END@json.output@@@",
-      "@@@STEP_LOG_LINE@json.input@{@@@",
-      "@@@STEP_LOG_LINE@json.input@  \"change_id\": \"12345\"@@@",
-      "@@@STEP_LOG_LINE@json.input@}@@@",
-      "@@@STEP_LOG_END@json.input@@@",
-      "@@@STEP_LINK@gerrit link@https://pigweed-review.googlesource.com/q/12345@@@"
-    ]
-  },
-  {
-    "cmd": [],
     "name": "roll"
   },
   {
     "cmd": [],
-    "name": "roll.project_name",
+    "name": "roll.repo_url",
     "~followup_annotations": [
       "@@@STEP_NEST_LEVEL@1@@@",
-      "@@@STEP_SUMMARY_TEXT@a1@@@"
+      "@@@STEP_SUMMARY_TEXT@https://foo.googlesource.com/a@@@"
     ]
   },
   {
     "cmd": [],
-    "name": "roll.proj_dir",
+    "name": "roll.repo_short_name",
     "~followup_annotations": [
       "@@@STEP_NEST_LEVEL@1@@@",
-      "@@@STEP_SUMMARY_TEXT@[START_DIR]/project@@@"
+      "@@@STEP_SUMMARY_TEXT@a1@@@"
     ]
   },
   {
@@ -914,10 +496,10 @@
   },
   {
     "cmd": [],
-    "name": "roll.direction",
+    "name": "roll.commit message",
     "~followup_annotations": [
       "@@@STEP_NEST_LEVEL@1@@@",
-      "@@@STEP_SUMMARY_TEXT@Direction.FORWARD@@@"
+      "@@@STEP_SUMMARY_TEXT@[roll] Roll a1 1111111..h3ll0 (3 commits)\n\n3e30158:https://foo-review.googlesource.com/c/a/+/12345 fake A msg 0\n3380b83:https://foo-review.googlesource.com/c/a/+/12345 fake A msg 1\n363caa9:https://foo-review.googlesource.com/c/a/+/12345 fake A msg 2\n\nRolled-Repo: https://foo.googlesource.com/a\nRolled-Commits: 11111111111111..h3ll0@@@"
     ]
   },
   {
diff --git a/recipe_modules/repo_roll/tests/full.expected/success.json b/recipe_modules/repo_roll/tests/full.expected/success.json
index 335e82f..54e1656 100644
--- a/recipe_modules/repo_roll/tests/full.expected/success.json
+++ b/recipe_modules/repo_roll/tests/full.expected/success.json
@@ -57,50 +57,25 @@
   },
   {
     "cmd": [],
-    "name": "checkout a"
+    "name": "ensure infra/tools/luci/gitiles/${platform}"
   },
   {
     "cmd": [],
-    "name": "checkout a.options",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@",
-      "@@@STEP_SUMMARY_TEXT@remote: \"https://foo.googlesource.com/a\"\nbranch: \"main\"\n@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "checkout a.options with defaults",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@",
-      "@@@STEP_SUMMARY_TEXT@remote: \"https://foo.googlesource.com/a\"\nbranch: \"main\"\nmanifest_file: \"default.xml\"\nrepo_init_timeout_sec: 20\nrepo_sync_timeout_sec: 120\nnumber_of_attempts: 3\nsubmodule_timeout_sec: 600\n@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "checkout a.not matching branch names",
+    "name": "ensure infra/tools/luci/gitiles/${platform}.get packages",
     "~followup_annotations": [
       "@@@STEP_NEST_LEVEL@1@@@"
     ]
   },
   {
-    "cmd": [],
-    "name": "checkout a.cache",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@",
-      "@@@STEP_SUMMARY_TEXT@miss@@@"
-    ]
-  },
-  {
     "cmd": [
       "vpython3",
       "-u",
       "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
       "--json-output",
       "/path/to/tmp/json",
-      "ensure-directory",
-      "--mode",
-      "0o777",
-      "[CACHE]/git"
+      "copy",
+      "RECIPE_MODULE[fuchsia::gitiles]/resources/cipd.ensure",
+      "/path/to/tmp/"
     ],
     "infra_step": true,
     "luci_context": {
@@ -115,7 +90,220 @@
         "hostname": "rdbhost"
       }
     },
-    "name": "checkout a.cache.ensure git cache dir",
+    "name": "ensure infra/tools/luci/gitiles/${platform}.get packages.read ensure file",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@2@@@",
+      "@@@STEP_LOG_LINE@cipd.ensure@infra/tools/luci/gitiles/${platform} version:pinned-version@@@",
+      "@@@STEP_LOG_END@cipd.ensure@@@"
+    ]
+  },
+  {
+    "cmd": [],
+    "name": "ensure infra/tools/luci/gitiles/${platform}.install infra/tools/luci/gitiles",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "vpython3",
+      "-u",
+      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
+      "--json-output",
+      "/path/to/tmp/json",
+      "ensure-directory",
+      "--mode",
+      "0o777",
+      "[START_DIR]/cipd_tool/infra/tools/luci/gitiles/0e548aa33f8113a45a5b3b62201e114e98e63d00f97296912380138f44597b07"
+    ],
+    "infra_step": true,
+    "luci_context": {
+      "realm": {
+        "name": "project:ci"
+      },
+      "resultdb": {
+        "current_invocation": {
+          "name": "invocations/build:8945511751514863184",
+          "update_token": "token"
+        },
+        "hostname": "rdbhost"
+      }
+    },
+    "name": "ensure infra/tools/luci/gitiles/${platform}.install infra/tools/luci/gitiles.ensure package directory",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@2@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "cipd",
+      "ensure",
+      "-root",
+      "[START_DIR]/cipd_tool/infra/tools/luci/gitiles/0e548aa33f8113a45a5b3b62201e114e98e63d00f97296912380138f44597b07",
+      "-ensure-file",
+      "infra/tools/luci/gitiles/${platform} version:pinned-version",
+      "-max-threads",
+      "0",
+      "-json-output",
+      "/path/to/tmp/json"
+    ],
+    "infra_step": true,
+    "luci_context": {
+      "realm": {
+        "name": "project:ci"
+      },
+      "resultdb": {
+        "current_invocation": {
+          "name": "invocations/build:8945511751514863184",
+          "update_token": "token"
+        },
+        "hostname": "rdbhost"
+      }
+    },
+    "name": "ensure infra/tools/luci/gitiles/${platform}.install infra/tools/luci/gitiles.ensure_installed",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@2@@@",
+      "@@@STEP_LOG_LINE@json.output@{@@@",
+      "@@@STEP_LOG_LINE@json.output@  \"result\": {@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"\": [@@@",
+      "@@@STEP_LOG_LINE@json.output@      {@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"instance_id\": \"resolved-instance_id-of-version:pinned-v\",@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"package\": \"infra/tools/luci/gitiles/resolved-platform\"@@@",
+      "@@@STEP_LOG_LINE@json.output@      }@@@",
+      "@@@STEP_LOG_LINE@json.output@    ]@@@",
+      "@@@STEP_LOG_LINE@json.output@  }@@@",
+      "@@@STEP_LOG_LINE@json.output@}@@@",
+      "@@@STEP_LOG_END@json.output@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "[START_DIR]/cipd_tool/infra/tools/luci/gitiles/0e548aa33f8113a45a5b3b62201e114e98e63d00f97296912380138f44597b07/gitiles",
+      "log",
+      "-json-output",
+      "/path/to/tmp/json",
+      "https://foo.googlesource.com/a",
+      "1111111111111111111111111111111111111111..2d72510e447ab60a9728aeea2362d8be2cbd7789"
+    ],
+    "infra_step": true,
+    "luci_context": {
+      "realm": {
+        "name": "project:ci"
+      },
+      "resultdb": {
+        "current_invocation": {
+          "name": "invocations/build:8945511751514863184",
+          "update_token": "token"
+        },
+        "hostname": "rdbhost"
+      }
+    },
+    "name": "log a1",
+    "timeout": 300.0,
+    "~followup_annotations": [
+      "@@@STEP_LOG_LINE@json.output@[@@@",
+      "@@@STEP_LOG_LINE@json.output@  {@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"author\": {@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"email\": \"fake_A@fake_0.email.com\",@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"name\": \"Fake A\",@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"time\": \"Mon Jan 01 00:00:00 2015\"@@@",
+      "@@@STEP_LOG_LINE@json.output@    },@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"committer\": {@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"email\": \"fake_A@fake_0.email.com\",@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"name\": \"Fake A\",@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"time\": \"Mon Jan 01 00:00:00 2015\"@@@",
+      "@@@STEP_LOG_LINE@json.output@    },@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"id\": \"3e30158f2a7caccb7a9f6632a60011e7a44e1e5c\",@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"message\": \"fake A msg 0\",@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"parents\": [@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"83a7614b3b60951511be50db1b9561daff4bb447\"@@@",
+      "@@@STEP_LOG_LINE@json.output@    ],@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"tree\": \"1b6412b24ec3add84836c8fdd1af5ac8e35b61d9\",@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"tree_diff\": [@@@",
+      "@@@STEP_LOG_LINE@json.output@      {@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"new_id\": \"8bea05ad53680fce6937543f0d98cd48e295b8ff\",@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"new_mode\": 33188,@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"new_path\": \"a.py\",@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"old_id\": \"0000000000000000000000000000000000000000\",@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"old_mode\": 0,@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"type\": \"add\"@@@",
+      "@@@STEP_LOG_LINE@json.output@      }@@@",
+      "@@@STEP_LOG_LINE@json.output@    ]@@@",
+      "@@@STEP_LOG_LINE@json.output@  },@@@",
+      "@@@STEP_LOG_LINE@json.output@  {@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"author\": {@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"email\": \"fake_A@fake_1.email.com\",@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"name\": \"Fake A\",@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"time\": \"Mon Jan 01 00:00:00 2015\"@@@",
+      "@@@STEP_LOG_LINE@json.output@    },@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"committer\": {@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"email\": \"fake_A@fake_1.email.com\",@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"name\": \"Fake A\",@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"time\": \"Mon Jan 01 00:00:00 2015\"@@@",
+      "@@@STEP_LOG_LINE@json.output@    },@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"id\": \"3380b83c11e029b7291c83c44e7b1ce09d465fd1\",@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"message\": \"fake A msg 1\",@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"parents\": [@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"8675a52c73c701cb0b2c48f5ed4a9058c624e6cd\"@@@",
+      "@@@STEP_LOG_LINE@json.output@    ],@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"tree\": \"a1b1e6aa501915989b45a95e1224ec2a88655eb3\",@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"tree_diff\": [@@@",
+      "@@@STEP_LOG_LINE@json.output@      {@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"new_id\": \"06bc4c79002f278528aaddae4e056a11f58c19ad\",@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"new_mode\": 33188,@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"new_path\": \"b.py\",@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"old_id\": \"0000000000000000000000000000000000000000\",@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"old_mode\": 0,@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"type\": \"add\"@@@",
+      "@@@STEP_LOG_LINE@json.output@      }@@@",
+      "@@@STEP_LOG_LINE@json.output@    ]@@@",
+      "@@@STEP_LOG_LINE@json.output@  },@@@",
+      "@@@STEP_LOG_LINE@json.output@  {@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"author\": {@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"email\": \"fake_A@fake_2.email.com\",@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"name\": \"Fake A\",@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"time\": \"Mon Jan 01 00:00:00 2015\"@@@",
+      "@@@STEP_LOG_LINE@json.output@    },@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"committer\": {@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"email\": \"fake_A@fake_2.email.com\",@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"name\": \"Fake A\",@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"time\": \"Mon Jan 01 00:00:00 2015\"@@@",
+      "@@@STEP_LOG_LINE@json.output@    },@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"id\": \"363caa907186de786cb5292cd1ab7245da954815\",@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"message\": \"fake A msg 2\",@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"parents\": [@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"255c6325c4c654e17e6b35142e3912c86f1718f2\"@@@",
+      "@@@STEP_LOG_LINE@json.output@    ],@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"tree\": \"e84d4ad259e69da73d2b842e2b9709f08e8b22bd\",@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"tree_diff\": [@@@",
+      "@@@STEP_LOG_LINE@json.output@      {@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"new_id\": \"d7f478bf423219f2f47c1a6ed344fc597a8bf18f\",@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"new_mode\": 33188,@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"new_path\": \"c.py\",@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"old_id\": \"0000000000000000000000000000000000000000\",@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"old_mode\": 0,@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"type\": \"add\"@@@",
+      "@@@STEP_LOG_LINE@json.output@      }@@@",
+      "@@@STEP_LOG_LINE@json.output@    ]@@@",
+      "@@@STEP_LOG_LINE@json.output@  }@@@",
+      "@@@STEP_LOG_LINE@json.output@]@@@",
+      "@@@STEP_LOG_END@json.output@@@"
+    ]
+  },
+  {
+    "cmd": [],
+    "name": "get gerrit change numbers"
+  },
+  {
+    "cmd": [],
+    "name": "get gerrit change numbers.ensure infra/tools/luci/gerrit/${platform}",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@"
+    ]
+  },
+  {
+    "cmd": [],
+    "name": "get gerrit change numbers.ensure infra/tools/luci/gerrit/${platform}.get packages",
     "~followup_annotations": [
       "@@@STEP_NEST_LEVEL@2@@@"
     ]
@@ -128,8 +316,8 @@
       "--json-output",
       "/path/to/tmp/json",
       "copy",
-      "",
-      "[CACHE]/git/.GUARD_FILE"
+      "RECIPE_MODULE[fuchsia::gerrit]/resources/cipd.ensure",
+      "/path/to/tmp/"
     ],
     "infra_step": true,
     "luci_context": {
@@ -144,7 +332,16 @@
         "hostname": "rdbhost"
       }
     },
-    "name": "checkout a.cache.write git cache guard file",
+    "name": "get gerrit change numbers.ensure infra/tools/luci/gerrit/${platform}.get packages.read ensure file",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@3@@@",
+      "@@@STEP_LOG_LINE@cipd.ensure@infra/tools/luci/gerrit/${platform} version:pinned-version@@@",
+      "@@@STEP_LOG_END@cipd.ensure@@@"
+    ]
+  },
+  {
+    "cmd": [],
+    "name": "get gerrit change numbers.ensure infra/tools/luci/gerrit/${platform}.install infra/tools/luci/gerrit",
     "~followup_annotations": [
       "@@@STEP_NEST_LEVEL@2@@@"
     ]
@@ -159,7 +356,7 @@
       "ensure-directory",
       "--mode",
       "0o777",
-      "[CACHE]/git/foo.googlesource.com-a"
+      "[START_DIR]/cipd_tool/infra/tools/luci/gerrit/0e548aa33f8113a45a5b3b62201e114e98e63d00f97296912380138f44597b07"
     ],
     "infra_step": true,
     "luci_context": {
@@ -174,17 +371,24 @@
         "hostname": "rdbhost"
       }
     },
-    "name": "checkout a.cache.makedirs",
+    "name": "get gerrit change numbers.ensure infra/tools/luci/gerrit/${platform}.install infra/tools/luci/gerrit.ensure package directory",
     "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
+      "@@@STEP_NEST_LEVEL@3@@@"
     ]
   },
   {
     "cmd": [
-      "git",
-      "init"
+      "cipd",
+      "ensure",
+      "-root",
+      "[START_DIR]/cipd_tool/infra/tools/luci/gerrit/0e548aa33f8113a45a5b3b62201e114e98e63d00f97296912380138f44597b07",
+      "-ensure-file",
+      "infra/tools/luci/gerrit/${platform} version:pinned-version",
+      "-max-threads",
+      "0",
+      "-json-output",
+      "/path/to/tmp/json"
     ],
-    "cwd": "[CACHE]/git/foo.googlesource.com-a",
     "infra_step": true,
     "luci_context": {
       "realm": {
@@ -198,20 +402,33 @@
         "hostname": "rdbhost"
       }
     },
-    "name": "checkout a.cache.git init",
-    "timeout": 300.0,
+    "name": "get gerrit change numbers.ensure infra/tools/luci/gerrit/${platform}.install infra/tools/luci/gerrit.ensure_installed",
     "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
+      "@@@STEP_NEST_LEVEL@3@@@",
+      "@@@STEP_LOG_LINE@json.output@{@@@",
+      "@@@STEP_LOG_LINE@json.output@  \"result\": {@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"\": [@@@",
+      "@@@STEP_LOG_LINE@json.output@      {@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"instance_id\": \"resolved-instance_id-of-version:pinned-v\",@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"package\": \"infra/tools/luci/gerrit/resolved-platform\"@@@",
+      "@@@STEP_LOG_LINE@json.output@      }@@@",
+      "@@@STEP_LOG_LINE@json.output@    ]@@@",
+      "@@@STEP_LOG_LINE@json.output@  }@@@",
+      "@@@STEP_LOG_LINE@json.output@}@@@",
+      "@@@STEP_LOG_END@json.output@@@"
     ]
   },
   {
     "cmd": [
-      "git",
-      "config",
-      "remote.origin.url",
-      "https://foo.googlesource.com/a"
+      "[START_DIR]/cipd_tool/infra/tools/luci/gerrit/0e548aa33f8113a45a5b3b62201e114e98e63d00f97296912380138f44597b07/gerrit",
+      "change-detail",
+      "-host",
+      "https://foo-review.googlesource.com",
+      "-input",
+      "{\"change_id\": \"3e30158f2a7caccb7a9f6632a60011e7a44e1e5c\"}",
+      "-output",
+      "/path/to/tmp/json"
     ],
-    "cwd": "[CACHE]/git/foo.googlesource.com-a",
     "infra_step": true,
     "luci_context": {
       "realm": {
@@ -225,149 +442,31 @@
         "hostname": "rdbhost"
       }
     },
-    "name": "checkout a.cache.remote set-url",
-    "timeout": 300.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "config",
-      "fetch.uriprotocols",
-      "https"
-    ],
-    "cwd": "[CACHE]/git/foo.googlesource.com-a",
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout a.cache.set fetch.uriprotocols",
-    "timeout": 300.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "checkout a.cache.timeout 10s",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "fetch",
-      "--prune",
-      "--tags",
-      "--jobs",
-      "4",
-      "origin",
-      "--no-recurse-submodules"
-    ],
-    "cwd": "[CACHE]/git/foo.googlesource.com-a",
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout a.cache.git fetch",
-    "timeout": 1200.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "merge",
-      "FETCH_HEAD"
-    ],
-    "cwd": "[CACHE]/git/foo.googlesource.com-a",
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout a.cache.git merge",
-    "timeout": 600.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "checkout a.cache.timeout 10s (2)",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "submodule",
-      "update",
-      "--recursive",
-      "--force",
-      "--jobs",
-      "4"
-    ],
-    "cwd": "[CACHE]/git/foo.googlesource.com-a",
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout a.cache.git submodule update",
+    "name": "get gerrit change numbers.change details for 3e30158",
     "timeout": 600,
     "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
+      "@@@STEP_NEST_LEVEL@1@@@",
+      "@@@STEP_LOG_LINE@json.output@{@@@",
+      "@@@STEP_LOG_LINE@json.output@  \"_number\": 12345@@@",
+      "@@@STEP_LOG_LINE@json.output@}@@@",
+      "@@@STEP_LOG_END@json.output@@@",
+      "@@@STEP_LOG_LINE@json.input@{@@@",
+      "@@@STEP_LOG_LINE@json.input@  \"change_id\": \"3e30158f2a7caccb7a9f6632a60011e7a44e1e5c\"@@@",
+      "@@@STEP_LOG_LINE@json.input@}@@@",
+      "@@@STEP_LOG_END@json.input@@@",
+      "@@@STEP_LINK@gerrit link@https://foo-review.googlesource.com/q/3e30158f2a7caccb7a9f6632a60011e7a44e1e5c@@@"
     ]
   },
   {
     "cmd": [
-      "vpython3",
-      "-u",
-      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
-      "--json-output",
-      "/path/to/tmp/json",
-      "remove",
-      "[CACHE]/git/.GUARD_FILE"
+      "[START_DIR]/cipd_tool/infra/tools/luci/gerrit/0e548aa33f8113a45a5b3b62201e114e98e63d00f97296912380138f44597b07/gerrit",
+      "change-detail",
+      "-host",
+      "https://foo-review.googlesource.com",
+      "-input",
+      "{\"change_id\": \"3380b83c11e029b7291c83c44e7b1ce09d465fd1\"}",
+      "-output",
+      "/path/to/tmp/json"
     ],
     "infra_step": true,
     "luci_context": {
@@ -382,516 +481,31 @@
         "hostname": "rdbhost"
       }
     },
-    "name": "checkout a.cache.remove git cache guard file",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "vpython3",
-      "-u",
-      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
-      "--json-output",
-      "/path/to/tmp/json",
-      "copytree",
-      "--symlinks",
-      "[CACHE]/git/foo.googlesource.com-a",
-      "[START_DIR]/project"
-    ],
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout a.copy from cache",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "checkout a.git checkout",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "checkout a.git checkout.timeout 10s",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "vpython3",
-      "-u",
-      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
-      "--json-output",
-      "/path/to/tmp/json",
-      "ensure-directory",
-      "--mode",
-      "0o777",
-      "[START_DIR]/project"
-    ],
-    "infra_step": true,
-    "luci_context": {
-      "deadline": {
-        "grace_period": 30.0,
-        "soft_deadline": 1337000019.0
-      },
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout a.git checkout.makedirs",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "init"
-    ],
-    "cwd": "[START_DIR]/project",
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout a.git checkout.git init",
-    "timeout": 300.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "remote",
-      "add",
-      "origin",
-      "https://foo.googlesource.com/a"
-    ],
-    "cwd": "[START_DIR]/project",
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout a.git checkout.git remote",
-    "timeout": 600.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "config",
-      "core.longpaths",
-      "true"
-    ],
-    "cwd": "[START_DIR]/project",
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout a.git checkout.set core.longpaths",
-    "timeout": 300.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "config",
-      "fetch.uriprotocols",
-      "https"
-    ],
-    "cwd": "[START_DIR]/project",
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout a.git checkout.set fetch.uriprotocols",
-    "timeout": 300.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "fetch",
-      "--tags",
-      "--jobs",
-      "4",
-      "origin",
-      "main"
-    ],
-    "cwd": "[START_DIR]/project",
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout a.git checkout.git fetch",
-    "timeout": 1200.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "checkout",
-      "-f",
-      "FETCH_HEAD"
-    ],
-    "cwd": "[START_DIR]/project",
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout a.git checkout.git checkout",
-    "timeout": 600.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "rev-parse",
-      "HEAD"
-    ],
-    "cwd": "[START_DIR]/project",
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout a.git checkout.git rev-parse",
-    "timeout": 300.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "clean",
-      "-f",
-      "-d",
-      "-x"
-    ],
-    "cwd": "[START_DIR]/project",
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout a.git checkout.git clean",
-    "timeout": 600.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "checkout a.git log",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "log",
-      "--oneline",
-      "-n",
-      "10"
-    ],
-    "cwd": "[START_DIR]/project",
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout a.git log.[START_DIR]/project",
-    "timeout": 600.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "clean",
-      "-f",
-      "-f",
-      "-d"
-    ],
-    "cwd": "[START_DIR]/project",
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout a.git clean",
-    "timeout": 600.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "status"
-    ],
-    "cwd": "[START_DIR]/project",
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout a.git status",
-    "timeout": 600.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "vpython3",
-      "-u",
-      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
-      "--json-output",
-      "/path/to/tmp/json",
-      "ensure-directory",
-      "--mode",
-      "0o777",
-      "[START_DIR]/snapshot"
-    ],
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout a.mkdir",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "submodule",
-      "status",
-      "--recursive"
-    ],
-    "cwd": "[START_DIR]/project",
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout a.submodule-status",
-    "timeout": 600.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "vpython3",
-      "-u",
-      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
-      "--json-output",
-      "/path/to/tmp/json",
-      "copy",
-      "submodule status filler text",
-      "[START_DIR]/snapshot/submodules.log"
-    ],
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout a.write submodule snapshot",
+    "name": "get gerrit change numbers.change details for 3380b83",
+    "timeout": 600,
     "~followup_annotations": [
       "@@@STEP_NEST_LEVEL@1@@@",
-      "@@@STEP_LOG_LINE@submodules.log@submodule status filler text@@@",
-      "@@@STEP_LOG_END@submodules.log@@@"
+      "@@@STEP_LOG_LINE@json.output@{@@@",
+      "@@@STEP_LOG_LINE@json.output@  \"_number\": 12345@@@",
+      "@@@STEP_LOG_LINE@json.output@}@@@",
+      "@@@STEP_LOG_END@json.output@@@",
+      "@@@STEP_LOG_LINE@json.input@{@@@",
+      "@@@STEP_LOG_LINE@json.input@  \"change_id\": \"3380b83c11e029b7291c83c44e7b1ce09d465fd1\"@@@",
+      "@@@STEP_LOG_LINE@json.input@}@@@",
+      "@@@STEP_LOG_END@json.input@@@",
+      "@@@STEP_LINK@gerrit link@https://foo-review.googlesource.com/q/3380b83c11e029b7291c83c44e7b1ce09d465fd1@@@"
     ]
   },
   {
     "cmd": [
-      "git",
-      "log",
-      "--oneline",
-      "-n",
-      "10"
-    ],
-    "cwd": "[START_DIR]/project",
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout a.log",
-    "timeout": 600.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "vpython3",
-      "-u",
-      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
-      "--json-output",
-      "/path/to/tmp/json",
-      "copy",
-      "",
-      "[START_DIR]/snapshot/git.log"
+      "[START_DIR]/cipd_tool/infra/tools/luci/gerrit/0e548aa33f8113a45a5b3b62201e114e98e63d00f97296912380138f44597b07/gerrit",
+      "change-detail",
+      "-host",
+      "https://foo-review.googlesource.com",
+      "-input",
+      "{\"change_id\": \"363caa907186de786cb5292cd1ab7245da954815\"}",
+      "-output",
+      "/path/to/tmp/json"
     ],
     "infra_step": true,
     "luci_context": {
@@ -906,71 +520,19 @@
         "hostname": "rdbhost"
       }
     },
-    "name": "checkout a.write git log",
+    "name": "get gerrit change numbers.change details for 363caa9",
+    "timeout": 600,
     "~followup_annotations": [
       "@@@STEP_NEST_LEVEL@1@@@",
-      "@@@STEP_LOG_END@git.log@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "get roll direction",
-    "~followup_annotations": [
-      "@@@STEP_SUMMARY_TEXT@forward@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "merge-base",
-      "--is-ancestor",
-      "1111111111111111111111111111111111111111",
-      "2d72510e447ab60a9728aeea2362d8be2cbd7789"
-    ],
-    "cwd": "[START_DIR]/project",
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "get roll direction.is forward",
-    "timeout": 600.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "merge-base",
-      "--is-ancestor",
-      "2d72510e447ab60a9728aeea2362d8be2cbd7789",
-      "1111111111111111111111111111111111111111"
-    ],
-    "cwd": "[START_DIR]/project",
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "get roll direction.is backward",
-    "timeout": 600.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
+      "@@@STEP_LOG_LINE@json.output@{@@@",
+      "@@@STEP_LOG_LINE@json.output@  \"_number\": 12345@@@",
+      "@@@STEP_LOG_LINE@json.output@}@@@",
+      "@@@STEP_LOG_END@json.output@@@",
+      "@@@STEP_LOG_LINE@json.input@{@@@",
+      "@@@STEP_LOG_LINE@json.input@  \"change_id\": \"363caa907186de786cb5292cd1ab7245da954815\"@@@",
+      "@@@STEP_LOG_LINE@json.input@}@@@",
+      "@@@STEP_LOG_END@json.input@@@",
+      "@@@STEP_LINK@gerrit link@https://foo-review.googlesource.com/q/363caa907186de786cb5292cd1ab7245da954815@@@"
     ]
   },
   {
@@ -1027,336 +589,22 @@
   },
   {
     "cmd": [],
-    "name": "remote"
-  },
-  {
-    "cmd": [
-      "git",
-      "remote"
-    ],
-    "cwd": "[START_DIR]/project",
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "remote.name",
-    "timeout": 600.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "remote",
-      "get-url",
-      "origin"
-    ],
-    "cwd": "[START_DIR]/project",
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "remote.url",
-    "timeout": 600.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "a1"
-  },
-  {
-    "cmd": [
-      "git",
-      "log",
-      "--pretty=format:%H\n%an\n%ae\n%B",
-      "-z",
-      "1111111111111111111111111111111111111111..2d72510e447ab60a9728aeea2362d8be2cbd7789"
-    ],
-    "cwd": "[START_DIR]/project",
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "a1.git log",
-    "timeout": 600.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "a1.ensure infra/tools/luci/gerrit/${platform}",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "a1.ensure infra/tools/luci/gerrit/${platform}.get packages",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "vpython3",
-      "-u",
-      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
-      "--json-output",
-      "/path/to/tmp/json",
-      "copy",
-      "RECIPE_MODULE[fuchsia::gerrit]/resources/cipd.ensure",
-      "/path/to/tmp/"
-    ],
-    "cwd": "[START_DIR]/project",
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "a1.ensure infra/tools/luci/gerrit/${platform}.get packages.read ensure file",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@3@@@",
-      "@@@STEP_LOG_LINE@cipd.ensure@infra/tools/luci/gerrit/${platform} version:pinned-version@@@",
-      "@@@STEP_LOG_END@cipd.ensure@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "a1.ensure infra/tools/luci/gerrit/${platform}.install infra/tools/luci/gerrit",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "vpython3",
-      "-u",
-      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
-      "--json-output",
-      "/path/to/tmp/json",
-      "ensure-directory",
-      "--mode",
-      "0o777",
-      "[START_DIR]/cipd_tool/infra/tools/luci/gerrit/0e548aa33f8113a45a5b3b62201e114e98e63d00f97296912380138f44597b07"
-    ],
-    "cwd": "[START_DIR]/project",
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "a1.ensure infra/tools/luci/gerrit/${platform}.install infra/tools/luci/gerrit.ensure package directory",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@3@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "cipd",
-      "ensure",
-      "-root",
-      "[START_DIR]/cipd_tool/infra/tools/luci/gerrit/0e548aa33f8113a45a5b3b62201e114e98e63d00f97296912380138f44597b07",
-      "-ensure-file",
-      "infra/tools/luci/gerrit/${platform} version:pinned-version",
-      "-max-threads",
-      "0",
-      "-json-output",
-      "/path/to/tmp/json"
-    ],
-    "cwd": "[START_DIR]/project",
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "a1.ensure infra/tools/luci/gerrit/${platform}.install infra/tools/luci/gerrit.ensure_installed",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@3@@@",
-      "@@@STEP_LOG_LINE@json.output@{@@@",
-      "@@@STEP_LOG_LINE@json.output@  \"result\": {@@@",
-      "@@@STEP_LOG_LINE@json.output@    \"\": [@@@",
-      "@@@STEP_LOG_LINE@json.output@      {@@@",
-      "@@@STEP_LOG_LINE@json.output@        \"instance_id\": \"resolved-instance_id-of-version:pinned-v\",@@@",
-      "@@@STEP_LOG_LINE@json.output@        \"package\": \"infra/tools/luci/gerrit/resolved-platform\"@@@",
-      "@@@STEP_LOG_LINE@json.output@      }@@@",
-      "@@@STEP_LOG_LINE@json.output@    ]@@@",
-      "@@@STEP_LOG_LINE@json.output@  }@@@",
-      "@@@STEP_LOG_LINE@json.output@}@@@",
-      "@@@STEP_LOG_END@json.output@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "[START_DIR]/cipd_tool/infra/tools/luci/gerrit/0e548aa33f8113a45a5b3b62201e114e98e63d00f97296912380138f44597b07/gerrit",
-      "change-query",
-      "-host",
-      "https://pigweed-review.googlesource.com",
-      "-input",
-      "{\"params\": {\"q\": \"commit:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\"}}",
-      "-output",
-      "/path/to/tmp/json"
-    ],
-    "cwd": "[START_DIR]/project",
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "a1.get change-id",
-    "timeout": 600,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@",
-      "@@@STEP_LOG_LINE@json.output@[@@@",
-      "@@@STEP_LOG_LINE@json.output@  {@@@",
-      "@@@STEP_LOG_LINE@json.output@    \"_number\": 12345@@@",
-      "@@@STEP_LOG_LINE@json.output@  }@@@",
-      "@@@STEP_LOG_LINE@json.output@]@@@",
-      "@@@STEP_LOG_END@json.output@@@",
-      "@@@STEP_LOG_LINE@json.input@{@@@",
-      "@@@STEP_LOG_LINE@json.input@  \"params\": {@@@",
-      "@@@STEP_LOG_LINE@json.input@    \"q\": \"commit:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\"@@@",
-      "@@@STEP_LOG_LINE@json.input@  }@@@",
-      "@@@STEP_LOG_LINE@json.input@}@@@",
-      "@@@STEP_LOG_END@json.input@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "[START_DIR]/cipd_tool/infra/tools/luci/gerrit/0e548aa33f8113a45a5b3b62201e114e98e63d00f97296912380138f44597b07/gerrit",
-      "change-detail",
-      "-host",
-      "https://pigweed-review.googlesource.com",
-      "-input",
-      "{\"change_id\": \"12345\"}",
-      "-output",
-      "/path/to/tmp/json"
-    ],
-    "cwd": "[START_DIR]/project",
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "a1.get 12345",
-    "timeout": 600,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@",
-      "@@@STEP_LOG_LINE@json.output@{@@@",
-      "@@@STEP_LOG_LINE@json.output@  \"owner\": {@@@",
-      "@@@STEP_LOG_LINE@json.output@    \"email\": \"author@example.com\",@@@",
-      "@@@STEP_LOG_LINE@json.output@    \"name\": \"author\"@@@",
-      "@@@STEP_LOG_LINE@json.output@  },@@@",
-      "@@@STEP_LOG_LINE@json.output@  \"reviewers\": {@@@",
-      "@@@STEP_LOG_LINE@json.output@    \"REVIEWER\": [@@@",
-      "@@@STEP_LOG_LINE@json.output@      {@@@",
-      "@@@STEP_LOG_LINE@json.output@        \"email\": \"reviewer@example.com\",@@@",
-      "@@@STEP_LOG_LINE@json.output@        \"name\": \"reviewer\"@@@",
-      "@@@STEP_LOG_LINE@json.output@      },@@@",
-      "@@@STEP_LOG_LINE@json.output@      {@@@",
-      "@@@STEP_LOG_LINE@json.output@        \"email\": \"nobody@google.com\",@@@",
-      "@@@STEP_LOG_LINE@json.output@        \"name\": \"nobody\"@@@",
-      "@@@STEP_LOG_LINE@json.output@      },@@@",
-      "@@@STEP_LOG_LINE@json.output@      {@@@",
-      "@@@STEP_LOG_LINE@json.output@        \"email\": \"robot@gserviceaccount.com\",@@@",
-      "@@@STEP_LOG_LINE@json.output@        \"name\": \"robot\"@@@",
-      "@@@STEP_LOG_LINE@json.output@      }@@@",
-      "@@@STEP_LOG_LINE@json.output@    ]@@@",
-      "@@@STEP_LOG_LINE@json.output@  }@@@",
-      "@@@STEP_LOG_LINE@json.output@}@@@",
-      "@@@STEP_LOG_END@json.output@@@",
-      "@@@STEP_LOG_LINE@json.input@{@@@",
-      "@@@STEP_LOG_LINE@json.input@  \"change_id\": \"12345\"@@@",
-      "@@@STEP_LOG_LINE@json.input@}@@@",
-      "@@@STEP_LOG_END@json.input@@@",
-      "@@@STEP_LINK@gerrit link@https://pigweed-review.googlesource.com/q/12345@@@"
-    ]
-  },
-  {
-    "cmd": [],
     "name": "roll"
   },
   {
     "cmd": [],
-    "name": "roll.project_name",
+    "name": "roll.repo_url",
     "~followup_annotations": [
       "@@@STEP_NEST_LEVEL@1@@@",
-      "@@@STEP_SUMMARY_TEXT@a1@@@"
+      "@@@STEP_SUMMARY_TEXT@https://foo.googlesource.com/a@@@"
     ]
   },
   {
     "cmd": [],
-    "name": "roll.proj_dir",
+    "name": "roll.repo_short_name",
     "~followup_annotations": [
       "@@@STEP_NEST_LEVEL@1@@@",
-      "@@@STEP_SUMMARY_TEXT@[START_DIR]/project@@@"
+      "@@@STEP_SUMMARY_TEXT@a1@@@"
     ]
   },
   {
@@ -1377,10 +625,10 @@
   },
   {
     "cmd": [],
-    "name": "roll.direction",
+    "name": "roll.commit message",
     "~followup_annotations": [
       "@@@STEP_NEST_LEVEL@1@@@",
-      "@@@STEP_SUMMARY_TEXT@Direction.FORWARD@@@"
+      "@@@STEP_SUMMARY_TEXT@[roll] Roll a1 1111111..2d72510 (3 commits)\n\n3e30158:https://foo-review.googlesource.com/c/a/+/12345 fake A msg 0\n3380b83:https://foo-review.googlesource.com/c/a/+/12345 fake A msg 1\n363caa9:https://foo-review.googlesource.com/c/a/+/12345 fake A msg 2\n\nRolled-Repo: https://foo.googlesource.com/a\nRolled-Commits: 11111111111111..2d72510e447ab6@@@"
     ]
   },
   {
diff --git a/recipe_modules/repo_roll/tests/full.expected/upstream-not-set.json b/recipe_modules/repo_roll/tests/full.expected/upstream-not-set.json
index 5709946..2fec22c 100644
--- a/recipe_modules/repo_roll/tests/full.expected/upstream-not-set.json
+++ b/recipe_modules/repo_roll/tests/full.expected/upstream-not-set.json
@@ -57,50 +57,25 @@
   },
   {
     "cmd": [],
-    "name": "checkout c"
+    "name": "ensure infra/tools/luci/gitiles/${platform}"
   },
   {
     "cmd": [],
-    "name": "checkout c.options",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@",
-      "@@@STEP_SUMMARY_TEXT@remote: \"https://bar.googlesource.com/c\"\nbranch: \"main\"\n@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "checkout c.options with defaults",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@",
-      "@@@STEP_SUMMARY_TEXT@remote: \"https://bar.googlesource.com/c\"\nbranch: \"main\"\nmanifest_file: \"default.xml\"\nrepo_init_timeout_sec: 20\nrepo_sync_timeout_sec: 120\nnumber_of_attempts: 3\nsubmodule_timeout_sec: 600\n@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "checkout c.not matching branch names",
+    "name": "ensure infra/tools/luci/gitiles/${platform}.get packages",
     "~followup_annotations": [
       "@@@STEP_NEST_LEVEL@1@@@"
     ]
   },
   {
-    "cmd": [],
-    "name": "checkout c.cache",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@",
-      "@@@STEP_SUMMARY_TEXT@miss@@@"
-    ]
-  },
-  {
     "cmd": [
       "vpython3",
       "-u",
       "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
       "--json-output",
       "/path/to/tmp/json",
-      "ensure-directory",
-      "--mode",
-      "0o777",
-      "[CACHE]/git"
+      "copy",
+      "RECIPE_MODULE[fuchsia::gitiles]/resources/cipd.ensure",
+      "/path/to/tmp/"
     ],
     "infra_step": true,
     "luci_context": {
@@ -115,7 +90,220 @@
         "hostname": "rdbhost"
       }
     },
-    "name": "checkout c.cache.ensure git cache dir",
+    "name": "ensure infra/tools/luci/gitiles/${platform}.get packages.read ensure file",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@2@@@",
+      "@@@STEP_LOG_LINE@cipd.ensure@infra/tools/luci/gitiles/${platform} version:pinned-version@@@",
+      "@@@STEP_LOG_END@cipd.ensure@@@"
+    ]
+  },
+  {
+    "cmd": [],
+    "name": "ensure infra/tools/luci/gitiles/${platform}.install infra/tools/luci/gitiles",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "vpython3",
+      "-u",
+      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
+      "--json-output",
+      "/path/to/tmp/json",
+      "ensure-directory",
+      "--mode",
+      "0o777",
+      "[START_DIR]/cipd_tool/infra/tools/luci/gitiles/0e548aa33f8113a45a5b3b62201e114e98e63d00f97296912380138f44597b07"
+    ],
+    "infra_step": true,
+    "luci_context": {
+      "realm": {
+        "name": "project:ci"
+      },
+      "resultdb": {
+        "current_invocation": {
+          "name": "invocations/build:8945511751514863184",
+          "update_token": "token"
+        },
+        "hostname": "rdbhost"
+      }
+    },
+    "name": "ensure infra/tools/luci/gitiles/${platform}.install infra/tools/luci/gitiles.ensure package directory",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@2@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "cipd",
+      "ensure",
+      "-root",
+      "[START_DIR]/cipd_tool/infra/tools/luci/gitiles/0e548aa33f8113a45a5b3b62201e114e98e63d00f97296912380138f44597b07",
+      "-ensure-file",
+      "infra/tools/luci/gitiles/${platform} version:pinned-version",
+      "-max-threads",
+      "0",
+      "-json-output",
+      "/path/to/tmp/json"
+    ],
+    "infra_step": true,
+    "luci_context": {
+      "realm": {
+        "name": "project:ci"
+      },
+      "resultdb": {
+        "current_invocation": {
+          "name": "invocations/build:8945511751514863184",
+          "update_token": "token"
+        },
+        "hostname": "rdbhost"
+      }
+    },
+    "name": "ensure infra/tools/luci/gitiles/${platform}.install infra/tools/luci/gitiles.ensure_installed",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@2@@@",
+      "@@@STEP_LOG_LINE@json.output@{@@@",
+      "@@@STEP_LOG_LINE@json.output@  \"result\": {@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"\": [@@@",
+      "@@@STEP_LOG_LINE@json.output@      {@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"instance_id\": \"resolved-instance_id-of-version:pinned-v\",@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"package\": \"infra/tools/luci/gitiles/resolved-platform\"@@@",
+      "@@@STEP_LOG_LINE@json.output@      }@@@",
+      "@@@STEP_LOG_LINE@json.output@    ]@@@",
+      "@@@STEP_LOG_LINE@json.output@  }@@@",
+      "@@@STEP_LOG_LINE@json.output@}@@@",
+      "@@@STEP_LOG_END@json.output@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "[START_DIR]/cipd_tool/infra/tools/luci/gitiles/0e548aa33f8113a45a5b3b62201e114e98e63d00f97296912380138f44597b07/gitiles",
+      "log",
+      "-json-output",
+      "/path/to/tmp/json",
+      "https://bar.googlesource.com/c",
+      "main..2d72510e447ab60a9728aeea2362d8be2cbd7789"
+    ],
+    "infra_step": true,
+    "luci_context": {
+      "realm": {
+        "name": "project:ci"
+      },
+      "resultdb": {
+        "current_invocation": {
+          "name": "invocations/build:8945511751514863184",
+          "update_token": "token"
+        },
+        "hostname": "rdbhost"
+      }
+    },
+    "name": "log c3",
+    "timeout": 300.0,
+    "~followup_annotations": [
+      "@@@STEP_LOG_LINE@json.output@[@@@",
+      "@@@STEP_LOG_LINE@json.output@  {@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"author\": {@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"email\": \"fake_A@fake_0.email.com\",@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"name\": \"Fake A\",@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"time\": \"Mon Jan 01 00:00:00 2015\"@@@",
+      "@@@STEP_LOG_LINE@json.output@    },@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"committer\": {@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"email\": \"fake_A@fake_0.email.com\",@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"name\": \"Fake A\",@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"time\": \"Mon Jan 01 00:00:00 2015\"@@@",
+      "@@@STEP_LOG_LINE@json.output@    },@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"id\": \"3e30158f2a7caccb7a9f6632a60011e7a44e1e5c\",@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"message\": \"fake A msg 0\",@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"parents\": [@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"83a7614b3b60951511be50db1b9561daff4bb447\"@@@",
+      "@@@STEP_LOG_LINE@json.output@    ],@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"tree\": \"1b6412b24ec3add84836c8fdd1af5ac8e35b61d9\",@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"tree_diff\": [@@@",
+      "@@@STEP_LOG_LINE@json.output@      {@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"new_id\": \"8bea05ad53680fce6937543f0d98cd48e295b8ff\",@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"new_mode\": 33188,@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"new_path\": \"a.py\",@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"old_id\": \"0000000000000000000000000000000000000000\",@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"old_mode\": 0,@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"type\": \"add\"@@@",
+      "@@@STEP_LOG_LINE@json.output@      }@@@",
+      "@@@STEP_LOG_LINE@json.output@    ]@@@",
+      "@@@STEP_LOG_LINE@json.output@  },@@@",
+      "@@@STEP_LOG_LINE@json.output@  {@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"author\": {@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"email\": \"fake_A@fake_1.email.com\",@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"name\": \"Fake A\",@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"time\": \"Mon Jan 01 00:00:00 2015\"@@@",
+      "@@@STEP_LOG_LINE@json.output@    },@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"committer\": {@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"email\": \"fake_A@fake_1.email.com\",@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"name\": \"Fake A\",@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"time\": \"Mon Jan 01 00:00:00 2015\"@@@",
+      "@@@STEP_LOG_LINE@json.output@    },@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"id\": \"3380b83c11e029b7291c83c44e7b1ce09d465fd1\",@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"message\": \"fake A msg 1\",@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"parents\": [@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"8675a52c73c701cb0b2c48f5ed4a9058c624e6cd\"@@@",
+      "@@@STEP_LOG_LINE@json.output@    ],@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"tree\": \"a1b1e6aa501915989b45a95e1224ec2a88655eb3\",@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"tree_diff\": [@@@",
+      "@@@STEP_LOG_LINE@json.output@      {@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"new_id\": \"06bc4c79002f278528aaddae4e056a11f58c19ad\",@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"new_mode\": 33188,@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"new_path\": \"b.py\",@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"old_id\": \"0000000000000000000000000000000000000000\",@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"old_mode\": 0,@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"type\": \"add\"@@@",
+      "@@@STEP_LOG_LINE@json.output@      }@@@",
+      "@@@STEP_LOG_LINE@json.output@    ]@@@",
+      "@@@STEP_LOG_LINE@json.output@  },@@@",
+      "@@@STEP_LOG_LINE@json.output@  {@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"author\": {@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"email\": \"fake_A@fake_2.email.com\",@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"name\": \"Fake A\",@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"time\": \"Mon Jan 01 00:00:00 2015\"@@@",
+      "@@@STEP_LOG_LINE@json.output@    },@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"committer\": {@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"email\": \"fake_A@fake_2.email.com\",@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"name\": \"Fake A\",@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"time\": \"Mon Jan 01 00:00:00 2015\"@@@",
+      "@@@STEP_LOG_LINE@json.output@    },@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"id\": \"363caa907186de786cb5292cd1ab7245da954815\",@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"message\": \"fake A msg 2\",@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"parents\": [@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"255c6325c4c654e17e6b35142e3912c86f1718f2\"@@@",
+      "@@@STEP_LOG_LINE@json.output@    ],@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"tree\": \"e84d4ad259e69da73d2b842e2b9709f08e8b22bd\",@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"tree_diff\": [@@@",
+      "@@@STEP_LOG_LINE@json.output@      {@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"new_id\": \"d7f478bf423219f2f47c1a6ed344fc597a8bf18f\",@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"new_mode\": 33188,@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"new_path\": \"c.py\",@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"old_id\": \"0000000000000000000000000000000000000000\",@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"old_mode\": 0,@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"type\": \"add\"@@@",
+      "@@@STEP_LOG_LINE@json.output@      }@@@",
+      "@@@STEP_LOG_LINE@json.output@    ]@@@",
+      "@@@STEP_LOG_LINE@json.output@  }@@@",
+      "@@@STEP_LOG_LINE@json.output@]@@@",
+      "@@@STEP_LOG_END@json.output@@@"
+    ]
+  },
+  {
+    "cmd": [],
+    "name": "get gerrit change numbers"
+  },
+  {
+    "cmd": [],
+    "name": "get gerrit change numbers.ensure infra/tools/luci/gerrit/${platform}",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@"
+    ]
+  },
+  {
+    "cmd": [],
+    "name": "get gerrit change numbers.ensure infra/tools/luci/gerrit/${platform}.get packages",
     "~followup_annotations": [
       "@@@STEP_NEST_LEVEL@2@@@"
     ]
@@ -128,8 +316,8 @@
       "--json-output",
       "/path/to/tmp/json",
       "copy",
-      "",
-      "[CACHE]/git/.GUARD_FILE"
+      "RECIPE_MODULE[fuchsia::gerrit]/resources/cipd.ensure",
+      "/path/to/tmp/"
     ],
     "infra_step": true,
     "luci_context": {
@@ -144,7 +332,16 @@
         "hostname": "rdbhost"
       }
     },
-    "name": "checkout c.cache.write git cache guard file",
+    "name": "get gerrit change numbers.ensure infra/tools/luci/gerrit/${platform}.get packages.read ensure file",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@3@@@",
+      "@@@STEP_LOG_LINE@cipd.ensure@infra/tools/luci/gerrit/${platform} version:pinned-version@@@",
+      "@@@STEP_LOG_END@cipd.ensure@@@"
+    ]
+  },
+  {
+    "cmd": [],
+    "name": "get gerrit change numbers.ensure infra/tools/luci/gerrit/${platform}.install infra/tools/luci/gerrit",
     "~followup_annotations": [
       "@@@STEP_NEST_LEVEL@2@@@"
     ]
@@ -159,7 +356,7 @@
       "ensure-directory",
       "--mode",
       "0o777",
-      "[CACHE]/git/bar.googlesource.com-c"
+      "[START_DIR]/cipd_tool/infra/tools/luci/gerrit/0e548aa33f8113a45a5b3b62201e114e98e63d00f97296912380138f44597b07"
     ],
     "infra_step": true,
     "luci_context": {
@@ -174,17 +371,24 @@
         "hostname": "rdbhost"
       }
     },
-    "name": "checkout c.cache.makedirs",
+    "name": "get gerrit change numbers.ensure infra/tools/luci/gerrit/${platform}.install infra/tools/luci/gerrit.ensure package directory",
     "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
+      "@@@STEP_NEST_LEVEL@3@@@"
     ]
   },
   {
     "cmd": [
-      "git",
-      "init"
+      "cipd",
+      "ensure",
+      "-root",
+      "[START_DIR]/cipd_tool/infra/tools/luci/gerrit/0e548aa33f8113a45a5b3b62201e114e98e63d00f97296912380138f44597b07",
+      "-ensure-file",
+      "infra/tools/luci/gerrit/${platform} version:pinned-version",
+      "-max-threads",
+      "0",
+      "-json-output",
+      "/path/to/tmp/json"
     ],
-    "cwd": "[CACHE]/git/bar.googlesource.com-c",
     "infra_step": true,
     "luci_context": {
       "realm": {
@@ -198,20 +402,33 @@
         "hostname": "rdbhost"
       }
     },
-    "name": "checkout c.cache.git init",
-    "timeout": 300.0,
+    "name": "get gerrit change numbers.ensure infra/tools/luci/gerrit/${platform}.install infra/tools/luci/gerrit.ensure_installed",
     "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
+      "@@@STEP_NEST_LEVEL@3@@@",
+      "@@@STEP_LOG_LINE@json.output@{@@@",
+      "@@@STEP_LOG_LINE@json.output@  \"result\": {@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"\": [@@@",
+      "@@@STEP_LOG_LINE@json.output@      {@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"instance_id\": \"resolved-instance_id-of-version:pinned-v\",@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"package\": \"infra/tools/luci/gerrit/resolved-platform\"@@@",
+      "@@@STEP_LOG_LINE@json.output@      }@@@",
+      "@@@STEP_LOG_LINE@json.output@    ]@@@",
+      "@@@STEP_LOG_LINE@json.output@  }@@@",
+      "@@@STEP_LOG_LINE@json.output@}@@@",
+      "@@@STEP_LOG_END@json.output@@@"
     ]
   },
   {
     "cmd": [
-      "git",
-      "config",
-      "remote.origin.url",
-      "https://bar.googlesource.com/c"
+      "[START_DIR]/cipd_tool/infra/tools/luci/gerrit/0e548aa33f8113a45a5b3b62201e114e98e63d00f97296912380138f44597b07/gerrit",
+      "change-detail",
+      "-host",
+      "https://bar-review.googlesource.com",
+      "-input",
+      "{\"change_id\": \"3e30158f2a7caccb7a9f6632a60011e7a44e1e5c\"}",
+      "-output",
+      "/path/to/tmp/json"
     ],
-    "cwd": "[CACHE]/git/bar.googlesource.com-c",
     "infra_step": true,
     "luci_context": {
       "realm": {
@@ -225,149 +442,31 @@
         "hostname": "rdbhost"
       }
     },
-    "name": "checkout c.cache.remote set-url",
-    "timeout": 300.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "config",
-      "fetch.uriprotocols",
-      "https"
-    ],
-    "cwd": "[CACHE]/git/bar.googlesource.com-c",
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout c.cache.set fetch.uriprotocols",
-    "timeout": 300.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "checkout c.cache.timeout 10s",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "fetch",
-      "--prune",
-      "--tags",
-      "--jobs",
-      "4",
-      "origin",
-      "--no-recurse-submodules"
-    ],
-    "cwd": "[CACHE]/git/bar.googlesource.com-c",
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout c.cache.git fetch",
-    "timeout": 1200.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "merge",
-      "FETCH_HEAD"
-    ],
-    "cwd": "[CACHE]/git/bar.googlesource.com-c",
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout c.cache.git merge",
-    "timeout": 600.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "checkout c.cache.timeout 10s (2)",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "submodule",
-      "update",
-      "--recursive",
-      "--force",
-      "--jobs",
-      "4"
-    ],
-    "cwd": "[CACHE]/git/bar.googlesource.com-c",
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout c.cache.git submodule update",
+    "name": "get gerrit change numbers.change details for 3e30158",
     "timeout": 600,
     "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
+      "@@@STEP_NEST_LEVEL@1@@@",
+      "@@@STEP_LOG_LINE@json.output@{@@@",
+      "@@@STEP_LOG_LINE@json.output@  \"_number\": 12345@@@",
+      "@@@STEP_LOG_LINE@json.output@}@@@",
+      "@@@STEP_LOG_END@json.output@@@",
+      "@@@STEP_LOG_LINE@json.input@{@@@",
+      "@@@STEP_LOG_LINE@json.input@  \"change_id\": \"3e30158f2a7caccb7a9f6632a60011e7a44e1e5c\"@@@",
+      "@@@STEP_LOG_LINE@json.input@}@@@",
+      "@@@STEP_LOG_END@json.input@@@",
+      "@@@STEP_LINK@gerrit link@https://bar-review.googlesource.com/q/3e30158f2a7caccb7a9f6632a60011e7a44e1e5c@@@"
     ]
   },
   {
     "cmd": [
-      "vpython3",
-      "-u",
-      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
-      "--json-output",
-      "/path/to/tmp/json",
-      "remove",
-      "[CACHE]/git/.GUARD_FILE"
+      "[START_DIR]/cipd_tool/infra/tools/luci/gerrit/0e548aa33f8113a45a5b3b62201e114e98e63d00f97296912380138f44597b07/gerrit",
+      "change-detail",
+      "-host",
+      "https://bar-review.googlesource.com",
+      "-input",
+      "{\"change_id\": \"3380b83c11e029b7291c83c44e7b1ce09d465fd1\"}",
+      "-output",
+      "/path/to/tmp/json"
     ],
     "infra_step": true,
     "luci_context": {
@@ -382,516 +481,31 @@
         "hostname": "rdbhost"
       }
     },
-    "name": "checkout c.cache.remove git cache guard file",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "vpython3",
-      "-u",
-      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
-      "--json-output",
-      "/path/to/tmp/json",
-      "copytree",
-      "--symlinks",
-      "[CACHE]/git/bar.googlesource.com-c",
-      "[START_DIR]/project"
-    ],
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout c.copy from cache",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "checkout c.git checkout",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "checkout c.git checkout.timeout 10s",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "vpython3",
-      "-u",
-      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
-      "--json-output",
-      "/path/to/tmp/json",
-      "ensure-directory",
-      "--mode",
-      "0o777",
-      "[START_DIR]/project"
-    ],
-    "infra_step": true,
-    "luci_context": {
-      "deadline": {
-        "grace_period": 30.0,
-        "soft_deadline": 1337000019.0
-      },
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout c.git checkout.makedirs",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "init"
-    ],
-    "cwd": "[START_DIR]/project",
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout c.git checkout.git init",
-    "timeout": 300.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "remote",
-      "add",
-      "origin",
-      "https://bar.googlesource.com/c"
-    ],
-    "cwd": "[START_DIR]/project",
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout c.git checkout.git remote",
-    "timeout": 600.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "config",
-      "core.longpaths",
-      "true"
-    ],
-    "cwd": "[START_DIR]/project",
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout c.git checkout.set core.longpaths",
-    "timeout": 300.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "config",
-      "fetch.uriprotocols",
-      "https"
-    ],
-    "cwd": "[START_DIR]/project",
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout c.git checkout.set fetch.uriprotocols",
-    "timeout": 300.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "fetch",
-      "--tags",
-      "--jobs",
-      "4",
-      "origin",
-      "main"
-    ],
-    "cwd": "[START_DIR]/project",
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout c.git checkout.git fetch",
-    "timeout": 1200.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "checkout",
-      "-f",
-      "FETCH_HEAD"
-    ],
-    "cwd": "[START_DIR]/project",
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout c.git checkout.git checkout",
-    "timeout": 600.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "rev-parse",
-      "HEAD"
-    ],
-    "cwd": "[START_DIR]/project",
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout c.git checkout.git rev-parse",
-    "timeout": 300.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "clean",
-      "-f",
-      "-d",
-      "-x"
-    ],
-    "cwd": "[START_DIR]/project",
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout c.git checkout.git clean",
-    "timeout": 600.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "checkout c.git log",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "log",
-      "--oneline",
-      "-n",
-      "10"
-    ],
-    "cwd": "[START_DIR]/project",
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout c.git log.[START_DIR]/project",
-    "timeout": 600.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "clean",
-      "-f",
-      "-f",
-      "-d"
-    ],
-    "cwd": "[START_DIR]/project",
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout c.git clean",
-    "timeout": 600.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "status"
-    ],
-    "cwd": "[START_DIR]/project",
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout c.git status",
-    "timeout": 600.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "vpython3",
-      "-u",
-      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
-      "--json-output",
-      "/path/to/tmp/json",
-      "ensure-directory",
-      "--mode",
-      "0o777",
-      "[START_DIR]/snapshot"
-    ],
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout c.mkdir",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "submodule",
-      "status",
-      "--recursive"
-    ],
-    "cwd": "[START_DIR]/project",
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout c.submodule-status",
-    "timeout": 600.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "vpython3",
-      "-u",
-      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
-      "--json-output",
-      "/path/to/tmp/json",
-      "copy",
-      "submodule status filler text",
-      "[START_DIR]/snapshot/submodules.log"
-    ],
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout c.write submodule snapshot",
+    "name": "get gerrit change numbers.change details for 3380b83",
+    "timeout": 600,
     "~followup_annotations": [
       "@@@STEP_NEST_LEVEL@1@@@",
-      "@@@STEP_LOG_LINE@submodules.log@submodule status filler text@@@",
-      "@@@STEP_LOG_END@submodules.log@@@"
+      "@@@STEP_LOG_LINE@json.output@{@@@",
+      "@@@STEP_LOG_LINE@json.output@  \"_number\": 12345@@@",
+      "@@@STEP_LOG_LINE@json.output@}@@@",
+      "@@@STEP_LOG_END@json.output@@@",
+      "@@@STEP_LOG_LINE@json.input@{@@@",
+      "@@@STEP_LOG_LINE@json.input@  \"change_id\": \"3380b83c11e029b7291c83c44e7b1ce09d465fd1\"@@@",
+      "@@@STEP_LOG_LINE@json.input@}@@@",
+      "@@@STEP_LOG_END@json.input@@@",
+      "@@@STEP_LINK@gerrit link@https://bar-review.googlesource.com/q/3380b83c11e029b7291c83c44e7b1ce09d465fd1@@@"
     ]
   },
   {
     "cmd": [
-      "git",
-      "log",
-      "--oneline",
-      "-n",
-      "10"
-    ],
-    "cwd": "[START_DIR]/project",
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout c.log",
-    "timeout": 600.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "vpython3",
-      "-u",
-      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
-      "--json-output",
-      "/path/to/tmp/json",
-      "copy",
-      "",
-      "[START_DIR]/snapshot/git.log"
+      "[START_DIR]/cipd_tool/infra/tools/luci/gerrit/0e548aa33f8113a45a5b3b62201e114e98e63d00f97296912380138f44597b07/gerrit",
+      "change-detail",
+      "-host",
+      "https://bar-review.googlesource.com",
+      "-input",
+      "{\"change_id\": \"363caa907186de786cb5292cd1ab7245da954815\"}",
+      "-output",
+      "/path/to/tmp/json"
     ],
     "infra_step": true,
     "luci_context": {
@@ -906,10 +520,19 @@
         "hostname": "rdbhost"
       }
     },
-    "name": "checkout c.write git log",
+    "name": "get gerrit change numbers.change details for 363caa9",
+    "timeout": 600,
     "~followup_annotations": [
       "@@@STEP_NEST_LEVEL@1@@@",
-      "@@@STEP_LOG_END@git.log@@@"
+      "@@@STEP_LOG_LINE@json.output@{@@@",
+      "@@@STEP_LOG_LINE@json.output@  \"_number\": 12345@@@",
+      "@@@STEP_LOG_LINE@json.output@}@@@",
+      "@@@STEP_LOG_END@json.output@@@",
+      "@@@STEP_LOG_LINE@json.input@{@@@",
+      "@@@STEP_LOG_LINE@json.input@  \"change_id\": \"363caa907186de786cb5292cd1ab7245da954815\"@@@",
+      "@@@STEP_LOG_LINE@json.input@}@@@",
+      "@@@STEP_LOG_END@json.input@@@",
+      "@@@STEP_LINK@gerrit link@https://bar-review.googlesource.com/q/363caa907186de786cb5292cd1ab7245da954815@@@"
     ]
   },
   {
@@ -966,338 +589,22 @@
   },
   {
     "cmd": [],
-    "name": "remote"
-  },
-  {
-    "cmd": [
-      "git",
-      "remote"
-    ],
-    "cwd": "[START_DIR]/project",
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "remote.name",
-    "timeout": 600.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "remote",
-      "get-url",
-      "origin"
-    ],
-    "cwd": "[START_DIR]/project",
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "remote.url",
-    "timeout": 600.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "c3"
-  },
-  {
-    "cmd": [
-      "git",
-      "log",
-      "--pretty=format:%H\n%an\n%ae\n%B",
-      "-z",
-      "--max-count",
-      "5",
-      "2d72510e447ab60a9728aeea2362d8be2cbd7789"
-    ],
-    "cwd": "[START_DIR]/project",
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "c3.git log",
-    "timeout": 600.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "c3.ensure infra/tools/luci/gerrit/${platform}",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "c3.ensure infra/tools/luci/gerrit/${platform}.get packages",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "vpython3",
-      "-u",
-      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
-      "--json-output",
-      "/path/to/tmp/json",
-      "copy",
-      "RECIPE_MODULE[fuchsia::gerrit]/resources/cipd.ensure",
-      "/path/to/tmp/"
-    ],
-    "cwd": "[START_DIR]/project",
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "c3.ensure infra/tools/luci/gerrit/${platform}.get packages.read ensure file",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@3@@@",
-      "@@@STEP_LOG_LINE@cipd.ensure@infra/tools/luci/gerrit/${platform} version:pinned-version@@@",
-      "@@@STEP_LOG_END@cipd.ensure@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "c3.ensure infra/tools/luci/gerrit/${platform}.install infra/tools/luci/gerrit",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "vpython3",
-      "-u",
-      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
-      "--json-output",
-      "/path/to/tmp/json",
-      "ensure-directory",
-      "--mode",
-      "0o777",
-      "[START_DIR]/cipd_tool/infra/tools/luci/gerrit/0e548aa33f8113a45a5b3b62201e114e98e63d00f97296912380138f44597b07"
-    ],
-    "cwd": "[START_DIR]/project",
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "c3.ensure infra/tools/luci/gerrit/${platform}.install infra/tools/luci/gerrit.ensure package directory",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@3@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "cipd",
-      "ensure",
-      "-root",
-      "[START_DIR]/cipd_tool/infra/tools/luci/gerrit/0e548aa33f8113a45a5b3b62201e114e98e63d00f97296912380138f44597b07",
-      "-ensure-file",
-      "infra/tools/luci/gerrit/${platform} version:pinned-version",
-      "-max-threads",
-      "0",
-      "-json-output",
-      "/path/to/tmp/json"
-    ],
-    "cwd": "[START_DIR]/project",
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "c3.ensure infra/tools/luci/gerrit/${platform}.install infra/tools/luci/gerrit.ensure_installed",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@3@@@",
-      "@@@STEP_LOG_LINE@json.output@{@@@",
-      "@@@STEP_LOG_LINE@json.output@  \"result\": {@@@",
-      "@@@STEP_LOG_LINE@json.output@    \"\": [@@@",
-      "@@@STEP_LOG_LINE@json.output@      {@@@",
-      "@@@STEP_LOG_LINE@json.output@        \"instance_id\": \"resolved-instance_id-of-version:pinned-v\",@@@",
-      "@@@STEP_LOG_LINE@json.output@        \"package\": \"infra/tools/luci/gerrit/resolved-platform\"@@@",
-      "@@@STEP_LOG_LINE@json.output@      }@@@",
-      "@@@STEP_LOG_LINE@json.output@    ]@@@",
-      "@@@STEP_LOG_LINE@json.output@  }@@@",
-      "@@@STEP_LOG_LINE@json.output@}@@@",
-      "@@@STEP_LOG_END@json.output@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "[START_DIR]/cipd_tool/infra/tools/luci/gerrit/0e548aa33f8113a45a5b3b62201e114e98e63d00f97296912380138f44597b07/gerrit",
-      "change-query",
-      "-host",
-      "https://pigweed-review.googlesource.com",
-      "-input",
-      "{\"params\": {\"q\": \"commit:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\"}}",
-      "-output",
-      "/path/to/tmp/json"
-    ],
-    "cwd": "[START_DIR]/project",
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "c3.get change-id",
-    "timeout": 600,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@",
-      "@@@STEP_LOG_LINE@json.output@[@@@",
-      "@@@STEP_LOG_LINE@json.output@  {@@@",
-      "@@@STEP_LOG_LINE@json.output@    \"_number\": 12345@@@",
-      "@@@STEP_LOG_LINE@json.output@  }@@@",
-      "@@@STEP_LOG_LINE@json.output@]@@@",
-      "@@@STEP_LOG_END@json.output@@@",
-      "@@@STEP_LOG_LINE@json.input@{@@@",
-      "@@@STEP_LOG_LINE@json.input@  \"params\": {@@@",
-      "@@@STEP_LOG_LINE@json.input@    \"q\": \"commit:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\"@@@",
-      "@@@STEP_LOG_LINE@json.input@  }@@@",
-      "@@@STEP_LOG_LINE@json.input@}@@@",
-      "@@@STEP_LOG_END@json.input@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "[START_DIR]/cipd_tool/infra/tools/luci/gerrit/0e548aa33f8113a45a5b3b62201e114e98e63d00f97296912380138f44597b07/gerrit",
-      "change-detail",
-      "-host",
-      "https://pigweed-review.googlesource.com",
-      "-input",
-      "{\"change_id\": \"12345\"}",
-      "-output",
-      "/path/to/tmp/json"
-    ],
-    "cwd": "[START_DIR]/project",
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "c3.get 12345",
-    "timeout": 600,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@",
-      "@@@STEP_LOG_LINE@json.output@{@@@",
-      "@@@STEP_LOG_LINE@json.output@  \"owner\": {@@@",
-      "@@@STEP_LOG_LINE@json.output@    \"email\": \"author@example.com\",@@@",
-      "@@@STEP_LOG_LINE@json.output@    \"name\": \"author\"@@@",
-      "@@@STEP_LOG_LINE@json.output@  },@@@",
-      "@@@STEP_LOG_LINE@json.output@  \"reviewers\": {@@@",
-      "@@@STEP_LOG_LINE@json.output@    \"REVIEWER\": [@@@",
-      "@@@STEP_LOG_LINE@json.output@      {@@@",
-      "@@@STEP_LOG_LINE@json.output@        \"email\": \"reviewer@example.com\",@@@",
-      "@@@STEP_LOG_LINE@json.output@        \"name\": \"reviewer\"@@@",
-      "@@@STEP_LOG_LINE@json.output@      },@@@",
-      "@@@STEP_LOG_LINE@json.output@      {@@@",
-      "@@@STEP_LOG_LINE@json.output@        \"email\": \"nobody@google.com\",@@@",
-      "@@@STEP_LOG_LINE@json.output@        \"name\": \"nobody\"@@@",
-      "@@@STEP_LOG_LINE@json.output@      },@@@",
-      "@@@STEP_LOG_LINE@json.output@      {@@@",
-      "@@@STEP_LOG_LINE@json.output@        \"email\": \"robot@gserviceaccount.com\",@@@",
-      "@@@STEP_LOG_LINE@json.output@        \"name\": \"robot\"@@@",
-      "@@@STEP_LOG_LINE@json.output@      }@@@",
-      "@@@STEP_LOG_LINE@json.output@    ]@@@",
-      "@@@STEP_LOG_LINE@json.output@  }@@@",
-      "@@@STEP_LOG_LINE@json.output@}@@@",
-      "@@@STEP_LOG_END@json.output@@@",
-      "@@@STEP_LOG_LINE@json.input@{@@@",
-      "@@@STEP_LOG_LINE@json.input@  \"change_id\": \"12345\"@@@",
-      "@@@STEP_LOG_LINE@json.input@}@@@",
-      "@@@STEP_LOG_END@json.input@@@",
-      "@@@STEP_LINK@gerrit link@https://pigweed-review.googlesource.com/q/12345@@@"
-    ]
-  },
-  {
-    "cmd": [],
     "name": "roll"
   },
   {
     "cmd": [],
-    "name": "roll.project_name",
+    "name": "roll.repo_url",
     "~followup_annotations": [
       "@@@STEP_NEST_LEVEL@1@@@",
-      "@@@STEP_SUMMARY_TEXT@c3@@@"
+      "@@@STEP_SUMMARY_TEXT@https://bar.googlesource.com/c@@@"
     ]
   },
   {
     "cmd": [],
-    "name": "roll.proj_dir",
+    "name": "roll.repo_short_name",
     "~followup_annotations": [
       "@@@STEP_NEST_LEVEL@1@@@",
-      "@@@STEP_SUMMARY_TEXT@[START_DIR]/project@@@"
+      "@@@STEP_SUMMARY_TEXT@c3@@@"
     ]
   },
   {
@@ -1318,10 +625,10 @@
   },
   {
     "cmd": [],
-    "name": "roll.direction",
+    "name": "roll.commit message",
     "~followup_annotations": [
       "@@@STEP_NEST_LEVEL@1@@@",
-      "@@@STEP_SUMMARY_TEXT@Direction.FORWARD@@@"
+      "@@@STEP_SUMMARY_TEXT@[roll] Roll c3 main..2d72510 (3 commits)\n\n3e30158:https://bar-review.googlesource.com/c/c/+/12345 fake A msg 0\n3380b83:https://bar-review.googlesource.com/c/c/+/12345 fake A msg 1\n363caa9:https://bar-review.googlesource.com/c/c/+/12345 fake A msg 2\n\nRolled-Repo: https://bar.googlesource.com/c\nRolled-Commits: main..2d72510e447ab6@@@"
     ]
   },
   {
diff --git a/recipe_modules/repo_roll/tests/full.py b/recipe_modules/repo_roll/tests/full.py
index ecb24bc..2b59f79 100644
--- a/recipe_modules/repo_roll/tests/full.py
+++ b/recipe_modules/repo_roll/tests/full.py
@@ -26,9 +26,10 @@
 from recipe_engine import post_process, recipe_test_api
 
 DEPS = [
+    'fuchsia/gitiles',
+    'fuchsia/roll_commit_message',
     'pigweed/checkout',
     'pigweed/repo_roll',
-    'pigweed/roll_util',
     'recipe_engine/buildbucket',
     'recipe_engine/properties',
     'recipe_engine/step',
@@ -52,11 +53,11 @@
             if rolls:
                 roll = rolls[0]
                 with api.step.nest('roll'):
-                    dir = api.step.empty('project_name').presentation
-                    dir.step_summary_text = roll.project_name
+                    dir = api.step.empty('repo_url').presentation
+                    dir.step_summary_text = roll.repo_url
 
-                    dir = api.step.empty('proj_dir').presentation
-                    dir.step_summary_text = roll.proj_dir
+                    dir = api.step.empty('repo_short_name').presentation
+                    dir.step_summary_text = roll.repo_short_name
 
                     old = api.step.empty('old_revision').presentation
                     old.step_summary_text = roll.old_revision
@@ -64,8 +65,11 @@
                     new = api.step.empty('new_revision').presentation
                     new.step_summary_text = roll.new_revision
 
-                    direction = api.step.empty('direction').presentation
-                    direction.step_summary_text = str(roll.direction)
+                    message = api.step.empty('commit message').presentation
+                    message.step_summary_text = api.roll_commit_message.format(
+                        *rolls,
+                        send_comment=True,
+                    )
 
 
 def GenTests(api) -> Generator[recipe_test_api.TestData, None, None]:
@@ -76,18 +80,12 @@
         props.projects.append(Project(path_to_update=path))
         return api.properties(props)
 
-    def commit_data(name=None):
-        return api.roll_util.commit_data(
-            name, api.roll_util.commit('a' * 40, 'foo\nbar')
-        )
-
     yield api.test(
         'success',
         properties(path='a1'),
         api.buildbucket.ci_build(git_repo='https://foo.googlesource.com/a'),
         api.repo_roll.read_step_data(),
-        api.roll_util.forward_roll(),
-        commit_data('a1'),
+        api.gitiles.log('log a1', 'A'),
     )
 
     yield api.test(
@@ -102,8 +100,7 @@
         'equivalent',
         properties(path='b2'),
         api.repo_roll.read_step_data(),
-        api.roll_util.forward_roll(),
-        commit_data('b2'),
+        api.gitiles.log('log b2', 'A'),
     )
 
     yield api.test(
@@ -111,7 +108,7 @@
         properties(path='c3'),
         api.buildbucket.ci_build(git_repo='https://bar.googlesource.com/c'),
         api.repo_roll.read_step_data(),
-        commit_data('c3'),
+        api.gitiles.log('log c3', 'A'),
     )
 
     yield api.test(
@@ -126,15 +123,14 @@
         'no-trigger-with-upstream',
         properties(path='a1'),
         api.repo_roll.read_step_data(),
-        api.roll_util.forward_roll(),
-        commit_data('a1'),
+        api.gitiles.log('log a1', 'A'),
     )
 
     yield api.test(
         'no-trigger-with-revision-branch',
         properties(path='c3'),
         api.repo_roll.read_step_data(),
-        commit_data('c3'),
+        api.gitiles.log('log c3', 'A'),
     )
 
     yield api.test(
@@ -155,7 +151,7 @@
         'backwards',
         properties(path='a1'),
         api.repo_roll.read_step_data(),
-        api.roll_util.backward_roll(),
+        api.gitiles.log('log a1', 'A', n=0),
     )
 
     yield api.test(
@@ -163,7 +159,7 @@
         properties(path='f6'),
         api.buildbucket.ci_build(git_repo='https://host.googlesource.com/f'),
         api.repo_roll.read_step_data(),
-        commit_data('f6'),
+        api.gitiles.log('log f6', 'A'),
     )
 
     yield api.test(
@@ -173,7 +169,7 @@
             git_repo='https://host.googlesource.com/prefix/g'
         ),
         api.repo_roll.read_step_data(),
-        commit_data('g7'),
+        api.gitiles.log('log g7', 'A'),
     )
 
     yield api.test(
@@ -183,5 +179,5 @@
             git_repo='https://host.googlesource.com/prefix/h'
         ),
         api.repo_roll.read_step_data(),
-        commit_data('h8'),
+        api.gitiles.log('log h8', 'A'),
     )
diff --git a/recipes/repo_roller.expected/backwards.json b/recipes/repo_roller.expected/backwards.json
index 2531390..73d5819 100644
--- a/recipes/repo_roller.expected/backwards.json
+++ b/recipes/repo_roller.expected/backwards.json
@@ -1007,40 +1007,16 @@
   },
   {
     "cmd": [],
-    "name": "checkout a"
+    "name": "ensure infra/tools/luci/gitiles/${platform}"
   },
   {
     "cmd": [],
-    "name": "checkout a.options",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@",
-      "@@@STEP_SUMMARY_TEXT@remote: \"https://foo.googlesource.com/a\"\nbranch: \"main\"\n@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "checkout a.options with defaults",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@",
-      "@@@STEP_SUMMARY_TEXT@remote: \"https://foo.googlesource.com/a\"\nbranch: \"main\"\nmanifest_file: \"default.xml\"\nrepo_init_timeout_sec: 20\nrepo_sync_timeout_sec: 120\nnumber_of_attempts: 3\nsubmodule_timeout_sec: 600\n@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "checkout a.not matching branch names",
+    "name": "ensure infra/tools/luci/gitiles/${platform}.get packages",
     "~followup_annotations": [
       "@@@STEP_NEST_LEVEL@1@@@"
     ]
   },
   {
-    "cmd": [],
-    "name": "checkout a.cache",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@",
-      "@@@STEP_SUMMARY_TEXT@miss@@@"
-    ]
-  },
-  {
     "cmd": [
       "vpython3",
       "-u",
@@ -1048,8 +1024,8 @@
       "--json-output",
       "/path/to/tmp/json",
       "copy",
-      "",
-      "[CACHE]/git/.GUARD_FILE"
+      "RECIPE_MODULE[fuchsia::gitiles]/resources/cipd.ensure",
+      "/path/to/tmp/"
     ],
     "infra_step": true,
     "luci_context": {
@@ -1064,9 +1040,18 @@
         "hostname": "rdbhost"
       }
     },
-    "name": "checkout a.cache.write git cache guard file",
+    "name": "ensure infra/tools/luci/gitiles/${platform}.get packages.read ensure file",
     "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
+      "@@@STEP_NEST_LEVEL@2@@@",
+      "@@@STEP_LOG_LINE@cipd.ensure@infra/tools/luci/gitiles/${platform} version:pinned-version@@@",
+      "@@@STEP_LOG_END@cipd.ensure@@@"
+    ]
+  },
+  {
+    "cmd": [],
+    "name": "ensure infra/tools/luci/gitiles/${platform}.install infra/tools/luci/gitiles",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@"
     ]
   },
   {
@@ -1079,7 +1064,7 @@
       "ensure-directory",
       "--mode",
       "0o777",
-      "[CACHE]/git/foo.googlesource.com-a"
+      "[START_DIR]/cipd_tool/infra/tools/luci/gitiles/0e548aa33f8113a45a5b3b62201e114e98e63d00f97296912380138f44597b07"
     ],
     "infra_step": true,
     "luci_context": {
@@ -1094,200 +1079,23 @@
         "hostname": "rdbhost"
       }
     },
-    "name": "checkout a.cache.makedirs",
+    "name": "ensure infra/tools/luci/gitiles/${platform}.install infra/tools/luci/gitiles.ensure package directory",
     "~followup_annotations": [
       "@@@STEP_NEST_LEVEL@2@@@"
     ]
   },
   {
     "cmd": [
-      "git",
-      "init"
-    ],
-    "cwd": "[CACHE]/git/foo.googlesource.com-a",
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout a.cache.git init",
-    "timeout": 300.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "config",
-      "remote.origin.url",
-      "https://foo.googlesource.com/a"
-    ],
-    "cwd": "[CACHE]/git/foo.googlesource.com-a",
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout a.cache.remote set-url",
-    "timeout": 300.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "config",
-      "fetch.uriprotocols",
-      "https"
-    ],
-    "cwd": "[CACHE]/git/foo.googlesource.com-a",
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout a.cache.set fetch.uriprotocols",
-    "timeout": 300.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "checkout a.cache.timeout 10s",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "fetch",
-      "--prune",
-      "--tags",
-      "--jobs",
-      "4",
-      "origin",
-      "--no-recurse-submodules"
-    ],
-    "cwd": "[CACHE]/git/foo.googlesource.com-a",
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout a.cache.git fetch",
-    "timeout": 1200.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "merge",
-      "FETCH_HEAD"
-    ],
-    "cwd": "[CACHE]/git/foo.googlesource.com-a",
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout a.cache.git merge",
-    "timeout": 600.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "checkout a.cache.timeout 10s (2)",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "submodule",
-      "update",
-      "--recursive",
-      "--force",
-      "--jobs",
-      "4"
-    ],
-    "cwd": "[CACHE]/git/foo.googlesource.com-a",
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout a.cache.git submodule update",
-    "timeout": 600,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "vpython3",
-      "-u",
-      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
-      "--json-output",
-      "/path/to/tmp/json",
-      "remove",
-      "[CACHE]/git/.GUARD_FILE"
+      "cipd",
+      "ensure",
+      "-root",
+      "[START_DIR]/cipd_tool/infra/tools/luci/gitiles/0e548aa33f8113a45a5b3b62201e114e98e63d00f97296912380138f44597b07",
+      "-ensure-file",
+      "infra/tools/luci/gitiles/${platform} version:pinned-version",
+      "-max-threads",
+      "0",
+      "-json-output",
+      "/path/to/tmp/json"
     ],
     "infra_step": true,
     "luci_context": {
@@ -1302,403 +1110,30 @@
         "hostname": "rdbhost"
       }
     },
-    "name": "checkout a.cache.remove git cache guard file",
+    "name": "ensure infra/tools/luci/gitiles/${platform}.install infra/tools/luci/gitiles.ensure_installed",
     "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
+      "@@@STEP_NEST_LEVEL@2@@@",
+      "@@@STEP_LOG_LINE@json.output@{@@@",
+      "@@@STEP_LOG_LINE@json.output@  \"result\": {@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"\": [@@@",
+      "@@@STEP_LOG_LINE@json.output@      {@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"instance_id\": \"resolved-instance_id-of-version:pinned-v\",@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"package\": \"infra/tools/luci/gitiles/resolved-platform\"@@@",
+      "@@@STEP_LOG_LINE@json.output@      }@@@",
+      "@@@STEP_LOG_LINE@json.output@    ]@@@",
+      "@@@STEP_LOG_LINE@json.output@  }@@@",
+      "@@@STEP_LOG_LINE@json.output@}@@@",
+      "@@@STEP_LOG_END@json.output@@@"
     ]
   },
   {
     "cmd": [
-      "vpython3",
-      "-u",
-      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
-      "--json-output",
-      "/path/to/tmp/json",
-      "copytree",
-      "--symlinks",
-      "[CACHE]/git/foo.googlesource.com-a",
-      "[START_DIR]/project"
-    ],
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout a.copy from cache",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "checkout a.git checkout",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "checkout a.git checkout.timeout 10s",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "vpython3",
-      "-u",
-      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
-      "--json-output",
-      "/path/to/tmp/json",
-      "ensure-directory",
-      "--mode",
-      "0o777",
-      "[START_DIR]/project"
-    ],
-    "infra_step": true,
-    "luci_context": {
-      "deadline": {
-        "grace_period": 30.0,
-        "soft_deadline": 1337000028.0
-      },
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout a.git checkout.makedirs",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "init"
-    ],
-    "cwd": "[START_DIR]/project",
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout a.git checkout.git init",
-    "timeout": 300.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "remote",
-      "add",
-      "origin",
-      "https://foo.googlesource.com/a"
-    ],
-    "cwd": "[START_DIR]/project",
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout a.git checkout.git remote",
-    "timeout": 600.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "config",
-      "core.longpaths",
-      "true"
-    ],
-    "cwd": "[START_DIR]/project",
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout a.git checkout.set core.longpaths",
-    "timeout": 300.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "config",
-      "fetch.uriprotocols",
-      "https"
-    ],
-    "cwd": "[START_DIR]/project",
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout a.git checkout.set fetch.uriprotocols",
-    "timeout": 300.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "fetch",
-      "--tags",
-      "--jobs",
-      "4",
-      "origin",
-      "main"
-    ],
-    "cwd": "[START_DIR]/project",
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout a.git checkout.git fetch",
-    "timeout": 1200.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "checkout",
-      "-f",
-      "FETCH_HEAD"
-    ],
-    "cwd": "[START_DIR]/project",
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout a.git checkout.git checkout",
-    "timeout": 600.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "rev-parse",
-      "HEAD"
-    ],
-    "cwd": "[START_DIR]/project",
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout a.git checkout.git rev-parse",
-    "timeout": 300.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "clean",
-      "-f",
-      "-d",
-      "-x"
-    ],
-    "cwd": "[START_DIR]/project",
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout a.git checkout.git clean",
-    "timeout": 600.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "checkout a.git log",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
+      "[START_DIR]/cipd_tool/infra/tools/luci/gitiles/0e548aa33f8113a45a5b3b62201e114e98e63d00f97296912380138f44597b07/gitiles",
       "log",
-      "--oneline",
-      "-n",
-      "10"
-    ],
-    "cwd": "[START_DIR]/project",
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout a.git log.[START_DIR]/project",
-    "timeout": 600.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "clean",
-      "-f",
-      "-f",
-      "-d"
-    ],
-    "cwd": "[START_DIR]/project",
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout a.git clean",
-    "timeout": 600.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "status"
-    ],
-    "cwd": "[START_DIR]/project",
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout a.git status",
-    "timeout": 600.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "vpython3",
-      "-u",
-      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
-      "--json-output",
+      "-json-output",
       "/path/to/tmp/json",
-      "ensure-directory",
-      "--mode",
-      "0o777",
-      "[START_DIR]/snapshot"
+      "https://foo.googlesource.com/a",
+      "1111111111111111111111111111111111111111..2d72510e447ab60a9728aeea2362d8be2cbd7789"
     ],
     "infra_step": true,
     "luci_context": {
@@ -1713,193 +1148,18 @@
         "hostname": "rdbhost"
       }
     },
-    "name": "checkout a.mkdir",
+    "name": "log a1",
+    "timeout": 300.0,
     "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "submodule",
-      "status",
-      "--recursive"
-    ],
-    "cwd": "[START_DIR]/project",
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout a.submodule-status",
-    "timeout": 600.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "vpython3",
-      "-u",
-      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
-      "--json-output",
-      "/path/to/tmp/json",
-      "copy",
-      "submodule status filler text",
-      "[START_DIR]/snapshot/submodules.log"
-    ],
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout a.write submodule snapshot",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@",
-      "@@@STEP_LOG_LINE@submodules.log@submodule status filler text@@@",
-      "@@@STEP_LOG_END@submodules.log@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "log",
-      "--oneline",
-      "-n",
-      "10"
-    ],
-    "cwd": "[START_DIR]/project",
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout a.log",
-    "timeout": 600.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "vpython3",
-      "-u",
-      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
-      "--json-output",
-      "/path/to/tmp/json",
-      "copy",
-      "",
-      "[START_DIR]/snapshot/git.log"
-    ],
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout a.write git log",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@",
-      "@@@STEP_LOG_END@git.log@@@"
+      "@@@STEP_LOG_LINE@json.output@[]@@@",
+      "@@@STEP_LOG_END@json.output@@@"
     ]
   },
   {
     "cmd": [],
-    "name": "get roll direction",
+    "name": "detected backwards roll",
     "~followup_annotations": [
-      "@@@STEP_SUMMARY_TEXT@backward@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "merge-base",
-      "--is-ancestor",
-      "1111111111111111111111111111111111111111",
-      "2d72510e447ab60a9728aeea2362d8be2cbd7789"
-    ],
-    "cwd": "[START_DIR]/project",
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "get roll direction.is forward",
-    "timeout": 600.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "merge-base",
-      "--is-ancestor",
-      "2d72510e447ab60a9728aeea2362d8be2cbd7789",
-      "1111111111111111111111111111111111111111"
-    ],
-    "cwd": "[START_DIR]/project",
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "get roll direction.is backward",
-    "timeout": 600.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "cancelling roll",
-    "~followup_annotations": [
-      "@@@STEP_SUMMARY_TEXT@not updating from 1111111 to 2d72510 because 1111111 is newer than 2d72510@@@",
-      "@@@STEP_LINK@1111111111111111111111111111111111111111@https://foo.googlesource.com/a/+/1111111111111111111111111111111111111111@@@",
-      "@@@STEP_LINK@2d72510e447ab60a9728aeea2362d8be2cbd7789@https://foo.googlesource.com/a/+/2d72510e447ab60a9728aeea2362d8be2cbd7789@@@"
+      "@@@STEP_TEXT@Detected backwards roll: expected 1111111 to precede 2d72510 in git history@@@"
     ]
   },
   {
diff --git a/recipes/repo_roller.expected/equivalent.json b/recipes/repo_roller.expected/equivalent.json
index 4de18f2..9463fb5 100644
--- a/recipes/repo_roller.expected/equivalent.json
+++ b/recipes/repo_roller.expected/equivalent.json
@@ -1007,40 +1007,16 @@
   },
   {
     "cmd": [],
-    "name": "checkout b"
+    "name": "ensure infra/tools/luci/gitiles/${platform}"
   },
   {
     "cmd": [],
-    "name": "checkout b.options",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@",
-      "@@@STEP_SUMMARY_TEXT@remote: \"https://bar.googlesource.com/b\"\nbranch: \"main\"\n@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "checkout b.options with defaults",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@",
-      "@@@STEP_SUMMARY_TEXT@remote: \"https://bar.googlesource.com/b\"\nbranch: \"main\"\nmanifest_file: \"default.xml\"\nrepo_init_timeout_sec: 20\nrepo_sync_timeout_sec: 120\nnumber_of_attempts: 3\nsubmodule_timeout_sec: 600\n@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "checkout b.not matching branch names",
+    "name": "ensure infra/tools/luci/gitiles/${platform}.get packages",
     "~followup_annotations": [
       "@@@STEP_NEST_LEVEL@1@@@"
     ]
   },
   {
-    "cmd": [],
-    "name": "checkout b.cache",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@",
-      "@@@STEP_SUMMARY_TEXT@miss@@@"
-    ]
-  },
-  {
     "cmd": [
       "vpython3",
       "-u",
@@ -1048,8 +1024,8 @@
       "--json-output",
       "/path/to/tmp/json",
       "copy",
-      "",
-      "[CACHE]/git/.GUARD_FILE"
+      "RECIPE_MODULE[fuchsia::gitiles]/resources/cipd.ensure",
+      "/path/to/tmp/"
     ],
     "infra_step": true,
     "luci_context": {
@@ -1064,7 +1040,258 @@
         "hostname": "rdbhost"
       }
     },
-    "name": "checkout b.cache.write git cache guard file",
+    "name": "ensure infra/tools/luci/gitiles/${platform}.get packages.read ensure file",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@2@@@",
+      "@@@STEP_LOG_LINE@cipd.ensure@infra/tools/luci/gitiles/${platform} version:pinned-version@@@",
+      "@@@STEP_LOG_END@cipd.ensure@@@"
+    ]
+  },
+  {
+    "cmd": [],
+    "name": "ensure infra/tools/luci/gitiles/${platform}.install infra/tools/luci/gitiles",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "vpython3",
+      "-u",
+      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
+      "--json-output",
+      "/path/to/tmp/json",
+      "ensure-directory",
+      "--mode",
+      "0o777",
+      "[START_DIR]/cipd_tool/infra/tools/luci/gitiles/0e548aa33f8113a45a5b3b62201e114e98e63d00f97296912380138f44597b07"
+    ],
+    "infra_step": true,
+    "luci_context": {
+      "realm": {
+        "name": "project:ci"
+      },
+      "resultdb": {
+        "current_invocation": {
+          "name": "invocations/build:8945511751514863184",
+          "update_token": "token"
+        },
+        "hostname": "rdbhost"
+      }
+    },
+    "name": "ensure infra/tools/luci/gitiles/${platform}.install infra/tools/luci/gitiles.ensure package directory",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@2@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "cipd",
+      "ensure",
+      "-root",
+      "[START_DIR]/cipd_tool/infra/tools/luci/gitiles/0e548aa33f8113a45a5b3b62201e114e98e63d00f97296912380138f44597b07",
+      "-ensure-file",
+      "infra/tools/luci/gitiles/${platform} version:pinned-version",
+      "-max-threads",
+      "0",
+      "-json-output",
+      "/path/to/tmp/json"
+    ],
+    "infra_step": true,
+    "luci_context": {
+      "realm": {
+        "name": "project:ci"
+      },
+      "resultdb": {
+        "current_invocation": {
+          "name": "invocations/build:8945511751514863184",
+          "update_token": "token"
+        },
+        "hostname": "rdbhost"
+      }
+    },
+    "name": "ensure infra/tools/luci/gitiles/${platform}.install infra/tools/luci/gitiles.ensure_installed",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@2@@@",
+      "@@@STEP_LOG_LINE@json.output@{@@@",
+      "@@@STEP_LOG_LINE@json.output@  \"result\": {@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"\": [@@@",
+      "@@@STEP_LOG_LINE@json.output@      {@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"instance_id\": \"resolved-instance_id-of-version:pinned-v\",@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"package\": \"infra/tools/luci/gitiles/resolved-platform\"@@@",
+      "@@@STEP_LOG_LINE@json.output@      }@@@",
+      "@@@STEP_LOG_LINE@json.output@    ]@@@",
+      "@@@STEP_LOG_LINE@json.output@  }@@@",
+      "@@@STEP_LOG_LINE@json.output@}@@@",
+      "@@@STEP_LOG_END@json.output@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "[START_DIR]/cipd_tool/infra/tools/luci/gitiles/0e548aa33f8113a45a5b3b62201e114e98e63d00f97296912380138f44597b07/gitiles",
+      "log",
+      "-json-output",
+      "/path/to/tmp/json",
+      "https://bar.googlesource.com/b",
+      "2222222222222222222222222222222222222222..2d72510e447ab60a9728aeea2362d8be2cbd7789"
+    ],
+    "infra_step": true,
+    "luci_context": {
+      "realm": {
+        "name": "project:ci"
+      },
+      "resultdb": {
+        "current_invocation": {
+          "name": "invocations/build:8945511751514863184",
+          "update_token": "token"
+        },
+        "hostname": "rdbhost"
+      }
+    },
+    "name": "log b2",
+    "timeout": 300.0,
+    "~followup_annotations": [
+      "@@@STEP_LOG_LINE@json.output@[@@@",
+      "@@@STEP_LOG_LINE@json.output@  {@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"author\": {@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"email\": \"fake_A@fake_0.email.com\",@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"name\": \"Fake A\",@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"time\": \"Mon Jan 01 00:00:00 2015\"@@@",
+      "@@@STEP_LOG_LINE@json.output@    },@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"committer\": {@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"email\": \"fake_A@fake_0.email.com\",@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"name\": \"Fake A\",@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"time\": \"Mon Jan 01 00:00:00 2015\"@@@",
+      "@@@STEP_LOG_LINE@json.output@    },@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"id\": \"3e30158f2a7caccb7a9f6632a60011e7a44e1e5c\",@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"message\": \"fake A msg 0\",@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"parents\": [@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"83a7614b3b60951511be50db1b9561daff4bb447\"@@@",
+      "@@@STEP_LOG_LINE@json.output@    ],@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"tree\": \"1b6412b24ec3add84836c8fdd1af5ac8e35b61d9\",@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"tree_diff\": [@@@",
+      "@@@STEP_LOG_LINE@json.output@      {@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"new_id\": \"8bea05ad53680fce6937543f0d98cd48e295b8ff\",@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"new_mode\": 33188,@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"new_path\": \"a.py\",@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"old_id\": \"0000000000000000000000000000000000000000\",@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"old_mode\": 0,@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"type\": \"add\"@@@",
+      "@@@STEP_LOG_LINE@json.output@      }@@@",
+      "@@@STEP_LOG_LINE@json.output@    ]@@@",
+      "@@@STEP_LOG_LINE@json.output@  },@@@",
+      "@@@STEP_LOG_LINE@json.output@  {@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"author\": {@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"email\": \"fake_A@fake_1.email.com\",@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"name\": \"Fake A\",@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"time\": \"Mon Jan 01 00:00:00 2015\"@@@",
+      "@@@STEP_LOG_LINE@json.output@    },@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"committer\": {@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"email\": \"fake_A@fake_1.email.com\",@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"name\": \"Fake A\",@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"time\": \"Mon Jan 01 00:00:00 2015\"@@@",
+      "@@@STEP_LOG_LINE@json.output@    },@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"id\": \"3380b83c11e029b7291c83c44e7b1ce09d465fd1\",@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"message\": \"fake A msg 1\",@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"parents\": [@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"8675a52c73c701cb0b2c48f5ed4a9058c624e6cd\"@@@",
+      "@@@STEP_LOG_LINE@json.output@    ],@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"tree\": \"a1b1e6aa501915989b45a95e1224ec2a88655eb3\",@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"tree_diff\": [@@@",
+      "@@@STEP_LOG_LINE@json.output@      {@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"new_id\": \"06bc4c79002f278528aaddae4e056a11f58c19ad\",@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"new_mode\": 33188,@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"new_path\": \"b.py\",@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"old_id\": \"0000000000000000000000000000000000000000\",@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"old_mode\": 0,@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"type\": \"add\"@@@",
+      "@@@STEP_LOG_LINE@json.output@      }@@@",
+      "@@@STEP_LOG_LINE@json.output@    ]@@@",
+      "@@@STEP_LOG_LINE@json.output@  },@@@",
+      "@@@STEP_LOG_LINE@json.output@  {@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"author\": {@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"email\": \"fake_A@fake_2.email.com\",@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"name\": \"Fake A\",@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"time\": \"Mon Jan 01 00:00:00 2015\"@@@",
+      "@@@STEP_LOG_LINE@json.output@    },@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"committer\": {@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"email\": \"fake_A@fake_2.email.com\",@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"name\": \"Fake A\",@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"time\": \"Mon Jan 01 00:00:00 2015\"@@@",
+      "@@@STEP_LOG_LINE@json.output@    },@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"id\": \"363caa907186de786cb5292cd1ab7245da954815\",@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"message\": \"fake A msg 2\",@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"parents\": [@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"255c6325c4c654e17e6b35142e3912c86f1718f2\"@@@",
+      "@@@STEP_LOG_LINE@json.output@    ],@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"tree\": \"e84d4ad259e69da73d2b842e2b9709f08e8b22bd\",@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"tree_diff\": [@@@",
+      "@@@STEP_LOG_LINE@json.output@      {@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"new_id\": \"d7f478bf423219f2f47c1a6ed344fc597a8bf18f\",@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"new_mode\": 33188,@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"new_path\": \"c.py\",@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"old_id\": \"0000000000000000000000000000000000000000\",@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"old_mode\": 0,@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"type\": \"add\"@@@",
+      "@@@STEP_LOG_LINE@json.output@      }@@@",
+      "@@@STEP_LOG_LINE@json.output@    ]@@@",
+      "@@@STEP_LOG_LINE@json.output@  }@@@",
+      "@@@STEP_LOG_LINE@json.output@]@@@",
+      "@@@STEP_LOG_END@json.output@@@"
+    ]
+  },
+  {
+    "cmd": [],
+    "name": "get gerrit change numbers"
+  },
+  {
+    "cmd": [],
+    "name": "get gerrit change numbers.ensure infra/tools/luci/gerrit/${platform}",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@"
+    ]
+  },
+  {
+    "cmd": [],
+    "name": "get gerrit change numbers.ensure infra/tools/luci/gerrit/${platform}.get packages",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@2@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "vpython3",
+      "-u",
+      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
+      "--json-output",
+      "/path/to/tmp/json",
+      "copy",
+      "RECIPE_MODULE[fuchsia::gerrit]/resources/cipd.ensure",
+      "/path/to/tmp/"
+    ],
+    "infra_step": true,
+    "luci_context": {
+      "realm": {
+        "name": "project:ci"
+      },
+      "resultdb": {
+        "current_invocation": {
+          "name": "invocations/build:8945511751514863184",
+          "update_token": "token"
+        },
+        "hostname": "rdbhost"
+      }
+    },
+    "name": "get gerrit change numbers.ensure infra/tools/luci/gerrit/${platform}.get packages.read ensure file",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@3@@@",
+      "@@@STEP_LOG_LINE@cipd.ensure@infra/tools/luci/gerrit/${platform} version:pinned-version@@@",
+      "@@@STEP_LOG_END@cipd.ensure@@@"
+    ]
+  },
+  {
+    "cmd": [],
+    "name": "get gerrit change numbers.ensure infra/tools/luci/gerrit/${platform}.install infra/tools/luci/gerrit",
     "~followup_annotations": [
       "@@@STEP_NEST_LEVEL@2@@@"
     ]
@@ -1079,7 +1306,7 @@
       "ensure-directory",
       "--mode",
       "0o777",
-      "[CACHE]/git/bar.googlesource.com-b"
+      "[START_DIR]/cipd_tool/infra/tools/luci/gerrit/0e548aa33f8113a45a5b3b62201e114e98e63d00f97296912380138f44597b07"
     ],
     "infra_step": true,
     "luci_context": {
@@ -1094,17 +1321,24 @@
         "hostname": "rdbhost"
       }
     },
-    "name": "checkout b.cache.makedirs",
+    "name": "get gerrit change numbers.ensure infra/tools/luci/gerrit/${platform}.install infra/tools/luci/gerrit.ensure package directory",
     "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
+      "@@@STEP_NEST_LEVEL@3@@@"
     ]
   },
   {
     "cmd": [
-      "git",
-      "init"
+      "cipd",
+      "ensure",
+      "-root",
+      "[START_DIR]/cipd_tool/infra/tools/luci/gerrit/0e548aa33f8113a45a5b3b62201e114e98e63d00f97296912380138f44597b07",
+      "-ensure-file",
+      "infra/tools/luci/gerrit/${platform} version:pinned-version",
+      "-max-threads",
+      "0",
+      "-json-output",
+      "/path/to/tmp/json"
     ],
-    "cwd": "[CACHE]/git/bar.googlesource.com-b",
     "infra_step": true,
     "luci_context": {
       "realm": {
@@ -1118,20 +1352,33 @@
         "hostname": "rdbhost"
       }
     },
-    "name": "checkout b.cache.git init",
-    "timeout": 300.0,
+    "name": "get gerrit change numbers.ensure infra/tools/luci/gerrit/${platform}.install infra/tools/luci/gerrit.ensure_installed",
     "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
+      "@@@STEP_NEST_LEVEL@3@@@",
+      "@@@STEP_LOG_LINE@json.output@{@@@",
+      "@@@STEP_LOG_LINE@json.output@  \"result\": {@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"\": [@@@",
+      "@@@STEP_LOG_LINE@json.output@      {@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"instance_id\": \"resolved-instance_id-of-version:pinned-v\",@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"package\": \"infra/tools/luci/gerrit/resolved-platform\"@@@",
+      "@@@STEP_LOG_LINE@json.output@      }@@@",
+      "@@@STEP_LOG_LINE@json.output@    ]@@@",
+      "@@@STEP_LOG_LINE@json.output@  }@@@",
+      "@@@STEP_LOG_LINE@json.output@}@@@",
+      "@@@STEP_LOG_END@json.output@@@"
     ]
   },
   {
     "cmd": [
-      "git",
-      "config",
-      "remote.origin.url",
-      "https://bar.googlesource.com/b"
+      "[START_DIR]/cipd_tool/infra/tools/luci/gerrit/0e548aa33f8113a45a5b3b62201e114e98e63d00f97296912380138f44597b07/gerrit",
+      "change-detail",
+      "-host",
+      "https://bar-review.googlesource.com",
+      "-input",
+      "{\"change_id\": \"3e30158f2a7caccb7a9f6632a60011e7a44e1e5c\"}",
+      "-output",
+      "/path/to/tmp/json"
     ],
-    "cwd": "[CACHE]/git/bar.googlesource.com-b",
     "infra_step": true,
     "luci_context": {
       "realm": {
@@ -1145,149 +1392,31 @@
         "hostname": "rdbhost"
       }
     },
-    "name": "checkout b.cache.remote set-url",
-    "timeout": 300.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "config",
-      "fetch.uriprotocols",
-      "https"
-    ],
-    "cwd": "[CACHE]/git/bar.googlesource.com-b",
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout b.cache.set fetch.uriprotocols",
-    "timeout": 300.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "checkout b.cache.timeout 10s",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "fetch",
-      "--prune",
-      "--tags",
-      "--jobs",
-      "4",
-      "origin",
-      "--no-recurse-submodules"
-    ],
-    "cwd": "[CACHE]/git/bar.googlesource.com-b",
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout b.cache.git fetch",
-    "timeout": 1200.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "merge",
-      "FETCH_HEAD"
-    ],
-    "cwd": "[CACHE]/git/bar.googlesource.com-b",
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout b.cache.git merge",
-    "timeout": 600.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "checkout b.cache.timeout 10s (2)",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "submodule",
-      "update",
-      "--recursive",
-      "--force",
-      "--jobs",
-      "4"
-    ],
-    "cwd": "[CACHE]/git/bar.googlesource.com-b",
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout b.cache.git submodule update",
+    "name": "get gerrit change numbers.change details for 3e30158",
     "timeout": 600,
     "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
+      "@@@STEP_NEST_LEVEL@1@@@",
+      "@@@STEP_LOG_LINE@json.output@{@@@",
+      "@@@STEP_LOG_LINE@json.output@  \"_number\": 12345@@@",
+      "@@@STEP_LOG_LINE@json.output@}@@@",
+      "@@@STEP_LOG_END@json.output@@@",
+      "@@@STEP_LOG_LINE@json.input@{@@@",
+      "@@@STEP_LOG_LINE@json.input@  \"change_id\": \"3e30158f2a7caccb7a9f6632a60011e7a44e1e5c\"@@@",
+      "@@@STEP_LOG_LINE@json.input@}@@@",
+      "@@@STEP_LOG_END@json.input@@@",
+      "@@@STEP_LINK@gerrit link@https://bar-review.googlesource.com/q/3e30158f2a7caccb7a9f6632a60011e7a44e1e5c@@@"
     ]
   },
   {
     "cmd": [
-      "vpython3",
-      "-u",
-      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
-      "--json-output",
-      "/path/to/tmp/json",
-      "remove",
-      "[CACHE]/git/.GUARD_FILE"
+      "[START_DIR]/cipd_tool/infra/tools/luci/gerrit/0e548aa33f8113a45a5b3b62201e114e98e63d00f97296912380138f44597b07/gerrit",
+      "change-detail",
+      "-host",
+      "https://bar-review.googlesource.com",
+      "-input",
+      "{\"change_id\": \"3380b83c11e029b7291c83c44e7b1ce09d465fd1\"}",
+      "-output",
+      "/path/to/tmp/json"
     ],
     "infra_step": true,
     "luci_context": {
@@ -1302,516 +1431,31 @@
         "hostname": "rdbhost"
       }
     },
-    "name": "checkout b.cache.remove git cache guard file",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "vpython3",
-      "-u",
-      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
-      "--json-output",
-      "/path/to/tmp/json",
-      "copytree",
-      "--symlinks",
-      "[CACHE]/git/bar.googlesource.com-b",
-      "[START_DIR]/project"
-    ],
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout b.copy from cache",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "checkout b.git checkout",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "checkout b.git checkout.timeout 10s",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "vpython3",
-      "-u",
-      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
-      "--json-output",
-      "/path/to/tmp/json",
-      "ensure-directory",
-      "--mode",
-      "0o777",
-      "[START_DIR]/project"
-    ],
-    "infra_step": true,
-    "luci_context": {
-      "deadline": {
-        "grace_period": 30.0,
-        "soft_deadline": 1337000028.0
-      },
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout b.git checkout.makedirs",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "init"
-    ],
-    "cwd": "[START_DIR]/project",
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout b.git checkout.git init",
-    "timeout": 300.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "remote",
-      "add",
-      "origin",
-      "https://bar.googlesource.com/b"
-    ],
-    "cwd": "[START_DIR]/project",
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout b.git checkout.git remote",
-    "timeout": 600.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "config",
-      "core.longpaths",
-      "true"
-    ],
-    "cwd": "[START_DIR]/project",
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout b.git checkout.set core.longpaths",
-    "timeout": 300.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "config",
-      "fetch.uriprotocols",
-      "https"
-    ],
-    "cwd": "[START_DIR]/project",
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout b.git checkout.set fetch.uriprotocols",
-    "timeout": 300.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "fetch",
-      "--tags",
-      "--jobs",
-      "4",
-      "origin",
-      "main"
-    ],
-    "cwd": "[START_DIR]/project",
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout b.git checkout.git fetch",
-    "timeout": 1200.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "checkout",
-      "-f",
-      "FETCH_HEAD"
-    ],
-    "cwd": "[START_DIR]/project",
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout b.git checkout.git checkout",
-    "timeout": 600.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "rev-parse",
-      "HEAD"
-    ],
-    "cwd": "[START_DIR]/project",
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout b.git checkout.git rev-parse",
-    "timeout": 300.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "clean",
-      "-f",
-      "-d",
-      "-x"
-    ],
-    "cwd": "[START_DIR]/project",
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout b.git checkout.git clean",
-    "timeout": 600.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "checkout b.git log",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "log",
-      "--oneline",
-      "-n",
-      "10"
-    ],
-    "cwd": "[START_DIR]/project",
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout b.git log.[START_DIR]/project",
-    "timeout": 600.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "clean",
-      "-f",
-      "-f",
-      "-d"
-    ],
-    "cwd": "[START_DIR]/project",
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout b.git clean",
-    "timeout": 600.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "status"
-    ],
-    "cwd": "[START_DIR]/project",
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout b.git status",
-    "timeout": 600.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "vpython3",
-      "-u",
-      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
-      "--json-output",
-      "/path/to/tmp/json",
-      "ensure-directory",
-      "--mode",
-      "0o777",
-      "[START_DIR]/snapshot"
-    ],
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout b.mkdir",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "submodule",
-      "status",
-      "--recursive"
-    ],
-    "cwd": "[START_DIR]/project",
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout b.submodule-status",
-    "timeout": 600.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "vpython3",
-      "-u",
-      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
-      "--json-output",
-      "/path/to/tmp/json",
-      "copy",
-      "submodule status filler text",
-      "[START_DIR]/snapshot/submodules.log"
-    ],
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout b.write submodule snapshot",
+    "name": "get gerrit change numbers.change details for 3380b83",
+    "timeout": 600,
     "~followup_annotations": [
       "@@@STEP_NEST_LEVEL@1@@@",
-      "@@@STEP_LOG_LINE@submodules.log@submodule status filler text@@@",
-      "@@@STEP_LOG_END@submodules.log@@@"
+      "@@@STEP_LOG_LINE@json.output@{@@@",
+      "@@@STEP_LOG_LINE@json.output@  \"_number\": 12345@@@",
+      "@@@STEP_LOG_LINE@json.output@}@@@",
+      "@@@STEP_LOG_END@json.output@@@",
+      "@@@STEP_LOG_LINE@json.input@{@@@",
+      "@@@STEP_LOG_LINE@json.input@  \"change_id\": \"3380b83c11e029b7291c83c44e7b1ce09d465fd1\"@@@",
+      "@@@STEP_LOG_LINE@json.input@}@@@",
+      "@@@STEP_LOG_END@json.input@@@",
+      "@@@STEP_LINK@gerrit link@https://bar-review.googlesource.com/q/3380b83c11e029b7291c83c44e7b1ce09d465fd1@@@"
     ]
   },
   {
     "cmd": [
-      "git",
-      "log",
-      "--oneline",
-      "-n",
-      "10"
-    ],
-    "cwd": "[START_DIR]/project",
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout b.log",
-    "timeout": 600.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "vpython3",
-      "-u",
-      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
-      "--json-output",
-      "/path/to/tmp/json",
-      "copy",
-      "",
-      "[START_DIR]/snapshot/git.log"
+      "[START_DIR]/cipd_tool/infra/tools/luci/gerrit/0e548aa33f8113a45a5b3b62201e114e98e63d00f97296912380138f44597b07/gerrit",
+      "change-detail",
+      "-host",
+      "https://bar-review.googlesource.com",
+      "-input",
+      "{\"change_id\": \"363caa907186de786cb5292cd1ab7245da954815\"}",
+      "-output",
+      "/path/to/tmp/json"
     ],
     "infra_step": true,
     "luci_context": {
@@ -1826,71 +1470,19 @@
         "hostname": "rdbhost"
       }
     },
-    "name": "checkout b.write git log",
+    "name": "get gerrit change numbers.change details for 363caa9",
+    "timeout": 600,
     "~followup_annotations": [
       "@@@STEP_NEST_LEVEL@1@@@",
-      "@@@STEP_LOG_END@git.log@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "get roll direction",
-    "~followup_annotations": [
-      "@@@STEP_SUMMARY_TEXT@forward@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "merge-base",
-      "--is-ancestor",
-      "2222222222222222222222222222222222222222",
-      "2d72510e447ab60a9728aeea2362d8be2cbd7789"
-    ],
-    "cwd": "[START_DIR]/project",
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "get roll direction.is forward",
-    "timeout": 600.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "merge-base",
-      "--is-ancestor",
-      "2d72510e447ab60a9728aeea2362d8be2cbd7789",
-      "2222222222222222222222222222222222222222"
-    ],
-    "cwd": "[START_DIR]/project",
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "get roll direction.is backward",
-    "timeout": 600.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
+      "@@@STEP_LOG_LINE@json.output@{@@@",
+      "@@@STEP_LOG_LINE@json.output@  \"_number\": 12345@@@",
+      "@@@STEP_LOG_LINE@json.output@}@@@",
+      "@@@STEP_LOG_END@json.output@@@",
+      "@@@STEP_LOG_LINE@json.input@{@@@",
+      "@@@STEP_LOG_LINE@json.input@  \"change_id\": \"363caa907186de786cb5292cd1ab7245da954815\"@@@",
+      "@@@STEP_LOG_LINE@json.input@}@@@",
+      "@@@STEP_LOG_END@json.input@@@",
+      "@@@STEP_LINK@gerrit link@https://bar-review.googlesource.com/q/363caa907186de786cb5292cd1ab7245da954815@@@"
     ]
   },
   {
@@ -1946,457 +1538,6 @@
     ]
   },
   {
-    "cmd": [],
-    "name": "remote"
-  },
-  {
-    "cmd": [
-      "git",
-      "remote"
-    ],
-    "cwd": "[START_DIR]/project",
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "remote.name",
-    "timeout": 600.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "remote",
-      "get-url",
-      "origin"
-    ],
-    "cwd": "[START_DIR]/project",
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "remote.url",
-    "timeout": 600.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "b2"
-  },
-  {
-    "cmd": [
-      "git",
-      "log",
-      "--pretty=format:%H\n%an\n%ae\n%B",
-      "-z",
-      "2222222222222222222222222222222222222222..2d72510e447ab60a9728aeea2362d8be2cbd7789"
-    ],
-    "cwd": "[START_DIR]/project",
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "b2.git log",
-    "timeout": 600.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "b2.ensure infra/tools/luci/gerrit/${platform}",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "b2.ensure infra/tools/luci/gerrit/${platform}.get packages",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "vpython3",
-      "-u",
-      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
-      "--json-output",
-      "/path/to/tmp/json",
-      "copy",
-      "RECIPE_MODULE[fuchsia::gerrit]/resources/cipd.ensure",
-      "/path/to/tmp/"
-    ],
-    "cwd": "[START_DIR]/project",
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "b2.ensure infra/tools/luci/gerrit/${platform}.get packages.read ensure file",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@3@@@",
-      "@@@STEP_LOG_LINE@cipd.ensure@infra/tools/luci/gerrit/${platform} version:pinned-version@@@",
-      "@@@STEP_LOG_END@cipd.ensure@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "b2.ensure infra/tools/luci/gerrit/${platform}.install infra/tools/luci/gerrit",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "vpython3",
-      "-u",
-      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
-      "--json-output",
-      "/path/to/tmp/json",
-      "ensure-directory",
-      "--mode",
-      "0o777",
-      "[START_DIR]/cipd_tool/infra/tools/luci/gerrit/0e548aa33f8113a45a5b3b62201e114e98e63d00f97296912380138f44597b07"
-    ],
-    "cwd": "[START_DIR]/project",
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "b2.ensure infra/tools/luci/gerrit/${platform}.install infra/tools/luci/gerrit.ensure package directory",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@3@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "cipd",
-      "ensure",
-      "-root",
-      "[START_DIR]/cipd_tool/infra/tools/luci/gerrit/0e548aa33f8113a45a5b3b62201e114e98e63d00f97296912380138f44597b07",
-      "-ensure-file",
-      "infra/tools/luci/gerrit/${platform} version:pinned-version",
-      "-max-threads",
-      "0",
-      "-json-output",
-      "/path/to/tmp/json"
-    ],
-    "cwd": "[START_DIR]/project",
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "b2.ensure infra/tools/luci/gerrit/${platform}.install infra/tools/luci/gerrit.ensure_installed",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@3@@@",
-      "@@@STEP_LOG_LINE@json.output@{@@@",
-      "@@@STEP_LOG_LINE@json.output@  \"result\": {@@@",
-      "@@@STEP_LOG_LINE@json.output@    \"\": [@@@",
-      "@@@STEP_LOG_LINE@json.output@      {@@@",
-      "@@@STEP_LOG_LINE@json.output@        \"instance_id\": \"resolved-instance_id-of-version:pinned-v\",@@@",
-      "@@@STEP_LOG_LINE@json.output@        \"package\": \"infra/tools/luci/gerrit/resolved-platform\"@@@",
-      "@@@STEP_LOG_LINE@json.output@      }@@@",
-      "@@@STEP_LOG_LINE@json.output@    ]@@@",
-      "@@@STEP_LOG_LINE@json.output@  }@@@",
-      "@@@STEP_LOG_LINE@json.output@}@@@",
-      "@@@STEP_LOG_END@json.output@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "[START_DIR]/cipd_tool/infra/tools/luci/gerrit/0e548aa33f8113a45a5b3b62201e114e98e63d00f97296912380138f44597b07/gerrit",
-      "change-query",
-      "-host",
-      "https://pigweed-review.googlesource.com",
-      "-input",
-      "{\"params\": {\"q\": \"commit:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\"}}",
-      "-output",
-      "/path/to/tmp/json"
-    ],
-    "cwd": "[START_DIR]/project",
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "b2.get change-id",
-    "timeout": 600,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@",
-      "@@@STEP_LOG_LINE@json.output@[@@@",
-      "@@@STEP_LOG_LINE@json.output@  {@@@",
-      "@@@STEP_LOG_LINE@json.output@    \"_number\": 12345@@@",
-      "@@@STEP_LOG_LINE@json.output@  }@@@",
-      "@@@STEP_LOG_LINE@json.output@]@@@",
-      "@@@STEP_LOG_END@json.output@@@",
-      "@@@STEP_LOG_LINE@json.input@{@@@",
-      "@@@STEP_LOG_LINE@json.input@  \"params\": {@@@",
-      "@@@STEP_LOG_LINE@json.input@    \"q\": \"commit:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\"@@@",
-      "@@@STEP_LOG_LINE@json.input@  }@@@",
-      "@@@STEP_LOG_LINE@json.input@}@@@",
-      "@@@STEP_LOG_END@json.input@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "[START_DIR]/cipd_tool/infra/tools/luci/gerrit/0e548aa33f8113a45a5b3b62201e114e98e63d00f97296912380138f44597b07/gerrit",
-      "change-detail",
-      "-host",
-      "https://pigweed-review.googlesource.com",
-      "-input",
-      "{\"change_id\": \"12345\"}",
-      "-output",
-      "/path/to/tmp/json"
-    ],
-    "cwd": "[START_DIR]/project",
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "b2.get 12345",
-    "timeout": 600,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@",
-      "@@@STEP_LOG_LINE@json.output@{@@@",
-      "@@@STEP_LOG_LINE@json.output@  \"owner\": {@@@",
-      "@@@STEP_LOG_LINE@json.output@    \"email\": \"author@example.com\",@@@",
-      "@@@STEP_LOG_LINE@json.output@    \"name\": \"author\"@@@",
-      "@@@STEP_LOG_LINE@json.output@  },@@@",
-      "@@@STEP_LOG_LINE@json.output@  \"reviewers\": {@@@",
-      "@@@STEP_LOG_LINE@json.output@    \"REVIEWER\": [@@@",
-      "@@@STEP_LOG_LINE@json.output@      {@@@",
-      "@@@STEP_LOG_LINE@json.output@        \"email\": \"reviewer@example.com\",@@@",
-      "@@@STEP_LOG_LINE@json.output@        \"name\": \"reviewer\"@@@",
-      "@@@STEP_LOG_LINE@json.output@      },@@@",
-      "@@@STEP_LOG_LINE@json.output@      {@@@",
-      "@@@STEP_LOG_LINE@json.output@        \"email\": \"nobody@google.com\",@@@",
-      "@@@STEP_LOG_LINE@json.output@        \"name\": \"nobody\"@@@",
-      "@@@STEP_LOG_LINE@json.output@      },@@@",
-      "@@@STEP_LOG_LINE@json.output@      {@@@",
-      "@@@STEP_LOG_LINE@json.output@        \"email\": \"robot@gserviceaccount.com\",@@@",
-      "@@@STEP_LOG_LINE@json.output@        \"name\": \"robot\"@@@",
-      "@@@STEP_LOG_LINE@json.output@      }@@@",
-      "@@@STEP_LOG_LINE@json.output@    ]@@@",
-      "@@@STEP_LOG_LINE@json.output@  }@@@",
-      "@@@STEP_LOG_LINE@json.output@}@@@",
-      "@@@STEP_LOG_END@json.output@@@",
-      "@@@STEP_LOG_LINE@json.input@{@@@",
-      "@@@STEP_LOG_LINE@json.input@  \"change_id\": \"12345\"@@@",
-      "@@@STEP_LOG_LINE@json.input@}@@@",
-      "@@@STEP_LOG_END@json.input@@@",
-      "@@@STEP_LINK@gerrit link@https://pigweed-review.googlesource.com/q/12345@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "cc nobody@google.com",
-    "~followup_annotations": [
-      "@@@STEP_SUMMARY_TEXT@not CCing, no account in Gerrit@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "[START_DIR]/cipd_tool/infra/tools/luci/gerrit/0e548aa33f8113a45a5b3b62201e114e98e63d00f97296912380138f44597b07/gerrit",
-      "account-query",
-      "-host",
-      "https://host-review.googlesource.com",
-      "-input",
-      "{\"params\": {\"q\": \"email:nobody@google.com\"}}",
-      "-output",
-      "/path/to/tmp/json"
-    ],
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "cc nobody@google.com.nobody@google.com",
-    "timeout": 600,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@",
-      "@@@STEP_LOG_LINE@json.output@[]@@@",
-      "@@@STEP_LOG_END@json.output@@@",
-      "@@@STEP_LOG_LINE@json.input@{@@@",
-      "@@@STEP_LOG_LINE@json.input@  \"params\": {@@@",
-      "@@@STEP_LOG_LINE@json.input@    \"q\": \"email:nobody@google.com\"@@@",
-      "@@@STEP_LOG_LINE@json.input@  }@@@",
-      "@@@STEP_LOG_LINE@json.input@}@@@",
-      "@@@STEP_LOG_END@json.input@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "cc reviewer@example.com",
-    "~followup_annotations": [
-      "@@@STEP_SUMMARY_TEXT@CCing@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "[START_DIR]/cipd_tool/infra/tools/luci/gerrit/0e548aa33f8113a45a5b3b62201e114e98e63d00f97296912380138f44597b07/gerrit",
-      "account-query",
-      "-host",
-      "https://host-review.googlesource.com",
-      "-input",
-      "{\"params\": {\"q\": \"email:reviewer@example.com\"}}",
-      "-output",
-      "/path/to/tmp/json"
-    ],
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "cc reviewer@example.com.reviewer@example.com",
-    "timeout": 600,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@",
-      "@@@STEP_LOG_LINE@json.output@[@@@",
-      "@@@STEP_LOG_LINE@json.output@  {@@@",
-      "@@@STEP_LOG_LINE@json.output@    \"_account_id\": 123@@@",
-      "@@@STEP_LOG_LINE@json.output@  }@@@",
-      "@@@STEP_LOG_LINE@json.output@]@@@",
-      "@@@STEP_LOG_END@json.output@@@",
-      "@@@STEP_LOG_LINE@json.input@{@@@",
-      "@@@STEP_LOG_LINE@json.input@  \"params\": {@@@",
-      "@@@STEP_LOG_LINE@json.input@    \"q\": \"email:reviewer@example.com\"@@@",
-      "@@@STEP_LOG_LINE@json.input@  }@@@",
-      "@@@STEP_LOG_LINE@json.input@}@@@",
-      "@@@STEP_LOG_END@json.input@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "cc robot@gserviceaccount.com",
-    "~followup_annotations": [
-      "@@@STEP_SUMMARY_TEXT@not CCing, robot account@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "authors",
-    "~followup_annotations": [
-      "@@@STEP_SUMMARY_TEXT@{Account(name='author', email='author@example.com')}@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "roll message"
-  },
-  {
-    "cmd": [],
-    "name": "roll message.message for b2",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@",
-      "@@@STEP_LOG_LINE@template@roll: {project_name}: {sanitized_message}@@@",
-      "@@@STEP_LOG_LINE@template@@@@",
-      "@@@STEP_LOG_LINE@template@{remote}@@@",
-      "@@@STEP_LOG_LINE@template@{project_name} Rolled-Commits: {old_revision:.15}..{new_revision:.15}@@@",
-      "@@@STEP_LOG_END@template@@@",
-      "@@@STEP_LOG_LINE@kwargs@'new_revision': '2d72510e447ab60a9728aeea2362d8be2cbd7789'@@@",
-      "@@@STEP_LOG_LINE@kwargs@'old_revision': '2222222222222222222222222222222222222222'@@@",
-      "@@@STEP_LOG_LINE@kwargs@'original_message': 'foo\\nbar'@@@",
-      "@@@STEP_LOG_LINE@kwargs@'project_name': 'b2'@@@",
-      "@@@STEP_LOG_LINE@kwargs@'remote': 'https://pigweed.googlesource.com/pigweed/pigweed'@@@",
-      "@@@STEP_LOG_LINE@kwargs@'sanitized_message': 'foo\\nbar'@@@",
-      "@@@STEP_LOG_END@kwargs@@@",
-      "@@@STEP_LOG_LINE@message@roll: b2: foo@@@",
-      "@@@STEP_LOG_LINE@message@bar@@@",
-      "@@@STEP_LOG_LINE@message@@@@",
-      "@@@STEP_LOG_LINE@message@https://pigweed.googlesource.com/pigweed/pigweed@@@",
-      "@@@STEP_LOG_LINE@message@b2 Rolled-Commits: 222222222222222..2d72510e447ab60@@@",
-      "@@@STEP_LOG_END@message@@@"
-    ]
-  },
-  {
     "cmd": [
       "git",
       "ls-files",
@@ -2593,11 +1734,9 @@
       "git",
       "commit",
       "-m",
-      "roll: b2: foo\nbar\n\nhttps://pigweed.googlesource.com/pigweed/pigweed\nb2 Rolled-Commits: 222222222222222..2d72510e447ab60\nRoller-URL: https://ci.chromium.org/b/8945511751514863184\nCQ-Do-Not-Cancel-Tryjobs: true\nChange-Id: I29f17ffd56e9f40bfb35bf83965b9a4effec4d69",
+      "roll: b2 2222222..2d72510 (3 commits)\n\n3e30158:https://bar-review.googlesource.com/c/b/+/12345 fake A msg 0\n3380b83:https://bar-review.googlesource.com/c/b/+/12345 fake A msg 1\n363caa9:https://bar-review.googlesource.com/c/b/+/12345 fake A msg 2\n\nRolled-Repo: https://bar.googlesource.com/b\nRolled-Commits: 22222222222222..2d72510e447ab6\nRoller-URL: https://ci.chromium.org/b/8945511751514863184\nCQ-Do-Not-Cancel-Tryjobs: true\nChange-Id: I29f17ffd56e9f40bfb35bf83965b9a4effec4d69",
       "-a",
-      "--no-verify",
-      "--author",
-      "author <author@pigweed.infra.roller.example.com>"
+      "--no-verify"
     ],
     "cwd": "[START_DIR]/co",
     "infra_step": true,
diff --git a/recipes/repo_roller.expected/success.json b/recipes/repo_roller.expected/success.json
index ae0b754..912c86f 100644
--- a/recipes/repo_roller.expected/success.json
+++ b/recipes/repo_roller.expected/success.json
@@ -1007,40 +1007,16 @@
   },
   {
     "cmd": [],
-    "name": "checkout a"
+    "name": "ensure infra/tools/luci/gitiles/${platform}"
   },
   {
     "cmd": [],
-    "name": "checkout a.options",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@",
-      "@@@STEP_SUMMARY_TEXT@remote: \"https://foo.googlesource.com/a\"\nbranch: \"main\"\n@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "checkout a.options with defaults",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@",
-      "@@@STEP_SUMMARY_TEXT@remote: \"https://foo.googlesource.com/a\"\nbranch: \"main\"\nmanifest_file: \"default.xml\"\nrepo_init_timeout_sec: 20\nrepo_sync_timeout_sec: 120\nnumber_of_attempts: 3\nsubmodule_timeout_sec: 600\n@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "checkout a.not matching branch names",
+    "name": "ensure infra/tools/luci/gitiles/${platform}.get packages",
     "~followup_annotations": [
       "@@@STEP_NEST_LEVEL@1@@@"
     ]
   },
   {
-    "cmd": [],
-    "name": "checkout a.cache",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@",
-      "@@@STEP_SUMMARY_TEXT@miss@@@"
-    ]
-  },
-  {
     "cmd": [
       "vpython3",
       "-u",
@@ -1048,8 +1024,8 @@
       "--json-output",
       "/path/to/tmp/json",
       "copy",
-      "",
-      "[CACHE]/git/.GUARD_FILE"
+      "RECIPE_MODULE[fuchsia::gitiles]/resources/cipd.ensure",
+      "/path/to/tmp/"
     ],
     "infra_step": true,
     "luci_context": {
@@ -1064,7 +1040,258 @@
         "hostname": "rdbhost"
       }
     },
-    "name": "checkout a.cache.write git cache guard file",
+    "name": "ensure infra/tools/luci/gitiles/${platform}.get packages.read ensure file",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@2@@@",
+      "@@@STEP_LOG_LINE@cipd.ensure@infra/tools/luci/gitiles/${platform} version:pinned-version@@@",
+      "@@@STEP_LOG_END@cipd.ensure@@@"
+    ]
+  },
+  {
+    "cmd": [],
+    "name": "ensure infra/tools/luci/gitiles/${platform}.install infra/tools/luci/gitiles",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "vpython3",
+      "-u",
+      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
+      "--json-output",
+      "/path/to/tmp/json",
+      "ensure-directory",
+      "--mode",
+      "0o777",
+      "[START_DIR]/cipd_tool/infra/tools/luci/gitiles/0e548aa33f8113a45a5b3b62201e114e98e63d00f97296912380138f44597b07"
+    ],
+    "infra_step": true,
+    "luci_context": {
+      "realm": {
+        "name": "project:ci"
+      },
+      "resultdb": {
+        "current_invocation": {
+          "name": "invocations/build:8945511751514863184",
+          "update_token": "token"
+        },
+        "hostname": "rdbhost"
+      }
+    },
+    "name": "ensure infra/tools/luci/gitiles/${platform}.install infra/tools/luci/gitiles.ensure package directory",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@2@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "cipd",
+      "ensure",
+      "-root",
+      "[START_DIR]/cipd_tool/infra/tools/luci/gitiles/0e548aa33f8113a45a5b3b62201e114e98e63d00f97296912380138f44597b07",
+      "-ensure-file",
+      "infra/tools/luci/gitiles/${platform} version:pinned-version",
+      "-max-threads",
+      "0",
+      "-json-output",
+      "/path/to/tmp/json"
+    ],
+    "infra_step": true,
+    "luci_context": {
+      "realm": {
+        "name": "project:ci"
+      },
+      "resultdb": {
+        "current_invocation": {
+          "name": "invocations/build:8945511751514863184",
+          "update_token": "token"
+        },
+        "hostname": "rdbhost"
+      }
+    },
+    "name": "ensure infra/tools/luci/gitiles/${platform}.install infra/tools/luci/gitiles.ensure_installed",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@2@@@",
+      "@@@STEP_LOG_LINE@json.output@{@@@",
+      "@@@STEP_LOG_LINE@json.output@  \"result\": {@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"\": [@@@",
+      "@@@STEP_LOG_LINE@json.output@      {@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"instance_id\": \"resolved-instance_id-of-version:pinned-v\",@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"package\": \"infra/tools/luci/gitiles/resolved-platform\"@@@",
+      "@@@STEP_LOG_LINE@json.output@      }@@@",
+      "@@@STEP_LOG_LINE@json.output@    ]@@@",
+      "@@@STEP_LOG_LINE@json.output@  }@@@",
+      "@@@STEP_LOG_LINE@json.output@}@@@",
+      "@@@STEP_LOG_END@json.output@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "[START_DIR]/cipd_tool/infra/tools/luci/gitiles/0e548aa33f8113a45a5b3b62201e114e98e63d00f97296912380138f44597b07/gitiles",
+      "log",
+      "-json-output",
+      "/path/to/tmp/json",
+      "https://foo.googlesource.com/a",
+      "1111111111111111111111111111111111111111..2d72510e447ab60a9728aeea2362d8be2cbd7789"
+    ],
+    "infra_step": true,
+    "luci_context": {
+      "realm": {
+        "name": "project:ci"
+      },
+      "resultdb": {
+        "current_invocation": {
+          "name": "invocations/build:8945511751514863184",
+          "update_token": "token"
+        },
+        "hostname": "rdbhost"
+      }
+    },
+    "name": "log a1",
+    "timeout": 300.0,
+    "~followup_annotations": [
+      "@@@STEP_LOG_LINE@json.output@[@@@",
+      "@@@STEP_LOG_LINE@json.output@  {@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"author\": {@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"email\": \"fake_A@fake_0.email.com\",@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"name\": \"Fake A\",@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"time\": \"Mon Jan 01 00:00:00 2015\"@@@",
+      "@@@STEP_LOG_LINE@json.output@    },@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"committer\": {@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"email\": \"fake_A@fake_0.email.com\",@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"name\": \"Fake A\",@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"time\": \"Mon Jan 01 00:00:00 2015\"@@@",
+      "@@@STEP_LOG_LINE@json.output@    },@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"id\": \"3e30158f2a7caccb7a9f6632a60011e7a44e1e5c\",@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"message\": \"fake A msg 0\",@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"parents\": [@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"83a7614b3b60951511be50db1b9561daff4bb447\"@@@",
+      "@@@STEP_LOG_LINE@json.output@    ],@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"tree\": \"1b6412b24ec3add84836c8fdd1af5ac8e35b61d9\",@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"tree_diff\": [@@@",
+      "@@@STEP_LOG_LINE@json.output@      {@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"new_id\": \"8bea05ad53680fce6937543f0d98cd48e295b8ff\",@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"new_mode\": 33188,@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"new_path\": \"a.py\",@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"old_id\": \"0000000000000000000000000000000000000000\",@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"old_mode\": 0,@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"type\": \"add\"@@@",
+      "@@@STEP_LOG_LINE@json.output@      }@@@",
+      "@@@STEP_LOG_LINE@json.output@    ]@@@",
+      "@@@STEP_LOG_LINE@json.output@  },@@@",
+      "@@@STEP_LOG_LINE@json.output@  {@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"author\": {@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"email\": \"fake_A@fake_1.email.com\",@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"name\": \"Fake A\",@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"time\": \"Mon Jan 01 00:00:00 2015\"@@@",
+      "@@@STEP_LOG_LINE@json.output@    },@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"committer\": {@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"email\": \"fake_A@fake_1.email.com\",@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"name\": \"Fake A\",@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"time\": \"Mon Jan 01 00:00:00 2015\"@@@",
+      "@@@STEP_LOG_LINE@json.output@    },@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"id\": \"3380b83c11e029b7291c83c44e7b1ce09d465fd1\",@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"message\": \"fake A msg 1\",@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"parents\": [@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"8675a52c73c701cb0b2c48f5ed4a9058c624e6cd\"@@@",
+      "@@@STEP_LOG_LINE@json.output@    ],@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"tree\": \"a1b1e6aa501915989b45a95e1224ec2a88655eb3\",@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"tree_diff\": [@@@",
+      "@@@STEP_LOG_LINE@json.output@      {@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"new_id\": \"06bc4c79002f278528aaddae4e056a11f58c19ad\",@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"new_mode\": 33188,@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"new_path\": \"b.py\",@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"old_id\": \"0000000000000000000000000000000000000000\",@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"old_mode\": 0,@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"type\": \"add\"@@@",
+      "@@@STEP_LOG_LINE@json.output@      }@@@",
+      "@@@STEP_LOG_LINE@json.output@    ]@@@",
+      "@@@STEP_LOG_LINE@json.output@  },@@@",
+      "@@@STEP_LOG_LINE@json.output@  {@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"author\": {@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"email\": \"fake_A@fake_2.email.com\",@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"name\": \"Fake A\",@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"time\": \"Mon Jan 01 00:00:00 2015\"@@@",
+      "@@@STEP_LOG_LINE@json.output@    },@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"committer\": {@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"email\": \"fake_A@fake_2.email.com\",@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"name\": \"Fake A\",@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"time\": \"Mon Jan 01 00:00:00 2015\"@@@",
+      "@@@STEP_LOG_LINE@json.output@    },@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"id\": \"363caa907186de786cb5292cd1ab7245da954815\",@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"message\": \"fake A msg 2\",@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"parents\": [@@@",
+      "@@@STEP_LOG_LINE@json.output@      \"255c6325c4c654e17e6b35142e3912c86f1718f2\"@@@",
+      "@@@STEP_LOG_LINE@json.output@    ],@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"tree\": \"e84d4ad259e69da73d2b842e2b9709f08e8b22bd\",@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"tree_diff\": [@@@",
+      "@@@STEP_LOG_LINE@json.output@      {@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"new_id\": \"d7f478bf423219f2f47c1a6ed344fc597a8bf18f\",@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"new_mode\": 33188,@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"new_path\": \"c.py\",@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"old_id\": \"0000000000000000000000000000000000000000\",@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"old_mode\": 0,@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"type\": \"add\"@@@",
+      "@@@STEP_LOG_LINE@json.output@      }@@@",
+      "@@@STEP_LOG_LINE@json.output@    ]@@@",
+      "@@@STEP_LOG_LINE@json.output@  }@@@",
+      "@@@STEP_LOG_LINE@json.output@]@@@",
+      "@@@STEP_LOG_END@json.output@@@"
+    ]
+  },
+  {
+    "cmd": [],
+    "name": "get gerrit change numbers"
+  },
+  {
+    "cmd": [],
+    "name": "get gerrit change numbers.ensure infra/tools/luci/gerrit/${platform}",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@"
+    ]
+  },
+  {
+    "cmd": [],
+    "name": "get gerrit change numbers.ensure infra/tools/luci/gerrit/${platform}.get packages",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@2@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "vpython3",
+      "-u",
+      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
+      "--json-output",
+      "/path/to/tmp/json",
+      "copy",
+      "RECIPE_MODULE[fuchsia::gerrit]/resources/cipd.ensure",
+      "/path/to/tmp/"
+    ],
+    "infra_step": true,
+    "luci_context": {
+      "realm": {
+        "name": "project:ci"
+      },
+      "resultdb": {
+        "current_invocation": {
+          "name": "invocations/build:8945511751514863184",
+          "update_token": "token"
+        },
+        "hostname": "rdbhost"
+      }
+    },
+    "name": "get gerrit change numbers.ensure infra/tools/luci/gerrit/${platform}.get packages.read ensure file",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@3@@@",
+      "@@@STEP_LOG_LINE@cipd.ensure@infra/tools/luci/gerrit/${platform} version:pinned-version@@@",
+      "@@@STEP_LOG_END@cipd.ensure@@@"
+    ]
+  },
+  {
+    "cmd": [],
+    "name": "get gerrit change numbers.ensure infra/tools/luci/gerrit/${platform}.install infra/tools/luci/gerrit",
     "~followup_annotations": [
       "@@@STEP_NEST_LEVEL@2@@@"
     ]
@@ -1079,7 +1306,7 @@
       "ensure-directory",
       "--mode",
       "0o777",
-      "[CACHE]/git/foo.googlesource.com-a"
+      "[START_DIR]/cipd_tool/infra/tools/luci/gerrit/0e548aa33f8113a45a5b3b62201e114e98e63d00f97296912380138f44597b07"
     ],
     "infra_step": true,
     "luci_context": {
@@ -1094,17 +1321,24 @@
         "hostname": "rdbhost"
       }
     },
-    "name": "checkout a.cache.makedirs",
+    "name": "get gerrit change numbers.ensure infra/tools/luci/gerrit/${platform}.install infra/tools/luci/gerrit.ensure package directory",
     "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
+      "@@@STEP_NEST_LEVEL@3@@@"
     ]
   },
   {
     "cmd": [
-      "git",
-      "init"
+      "cipd",
+      "ensure",
+      "-root",
+      "[START_DIR]/cipd_tool/infra/tools/luci/gerrit/0e548aa33f8113a45a5b3b62201e114e98e63d00f97296912380138f44597b07",
+      "-ensure-file",
+      "infra/tools/luci/gerrit/${platform} version:pinned-version",
+      "-max-threads",
+      "0",
+      "-json-output",
+      "/path/to/tmp/json"
     ],
-    "cwd": "[CACHE]/git/foo.googlesource.com-a",
     "infra_step": true,
     "luci_context": {
       "realm": {
@@ -1118,20 +1352,33 @@
         "hostname": "rdbhost"
       }
     },
-    "name": "checkout a.cache.git init",
-    "timeout": 300.0,
+    "name": "get gerrit change numbers.ensure infra/tools/luci/gerrit/${platform}.install infra/tools/luci/gerrit.ensure_installed",
     "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
+      "@@@STEP_NEST_LEVEL@3@@@",
+      "@@@STEP_LOG_LINE@json.output@{@@@",
+      "@@@STEP_LOG_LINE@json.output@  \"result\": {@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"\": [@@@",
+      "@@@STEP_LOG_LINE@json.output@      {@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"instance_id\": \"resolved-instance_id-of-version:pinned-v\",@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"package\": \"infra/tools/luci/gerrit/resolved-platform\"@@@",
+      "@@@STEP_LOG_LINE@json.output@      }@@@",
+      "@@@STEP_LOG_LINE@json.output@    ]@@@",
+      "@@@STEP_LOG_LINE@json.output@  }@@@",
+      "@@@STEP_LOG_LINE@json.output@}@@@",
+      "@@@STEP_LOG_END@json.output@@@"
     ]
   },
   {
     "cmd": [
-      "git",
-      "config",
-      "remote.origin.url",
-      "https://foo.googlesource.com/a"
+      "[START_DIR]/cipd_tool/infra/tools/luci/gerrit/0e548aa33f8113a45a5b3b62201e114e98e63d00f97296912380138f44597b07/gerrit",
+      "change-detail",
+      "-host",
+      "https://foo-review.googlesource.com",
+      "-input",
+      "{\"change_id\": \"3e30158f2a7caccb7a9f6632a60011e7a44e1e5c\"}",
+      "-output",
+      "/path/to/tmp/json"
     ],
-    "cwd": "[CACHE]/git/foo.googlesource.com-a",
     "infra_step": true,
     "luci_context": {
       "realm": {
@@ -1145,149 +1392,31 @@
         "hostname": "rdbhost"
       }
     },
-    "name": "checkout a.cache.remote set-url",
-    "timeout": 300.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "config",
-      "fetch.uriprotocols",
-      "https"
-    ],
-    "cwd": "[CACHE]/git/foo.googlesource.com-a",
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout a.cache.set fetch.uriprotocols",
-    "timeout": 300.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "checkout a.cache.timeout 10s",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "fetch",
-      "--prune",
-      "--tags",
-      "--jobs",
-      "4",
-      "origin",
-      "--no-recurse-submodules"
-    ],
-    "cwd": "[CACHE]/git/foo.googlesource.com-a",
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout a.cache.git fetch",
-    "timeout": 1200.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "merge",
-      "FETCH_HEAD"
-    ],
-    "cwd": "[CACHE]/git/foo.googlesource.com-a",
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout a.cache.git merge",
-    "timeout": 600.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "checkout a.cache.timeout 10s (2)",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "submodule",
-      "update",
-      "--recursive",
-      "--force",
-      "--jobs",
-      "4"
-    ],
-    "cwd": "[CACHE]/git/foo.googlesource.com-a",
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout a.cache.git submodule update",
+    "name": "get gerrit change numbers.change details for 3e30158",
     "timeout": 600,
     "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
+      "@@@STEP_NEST_LEVEL@1@@@",
+      "@@@STEP_LOG_LINE@json.output@{@@@",
+      "@@@STEP_LOG_LINE@json.output@  \"_number\": 12345@@@",
+      "@@@STEP_LOG_LINE@json.output@}@@@",
+      "@@@STEP_LOG_END@json.output@@@",
+      "@@@STEP_LOG_LINE@json.input@{@@@",
+      "@@@STEP_LOG_LINE@json.input@  \"change_id\": \"3e30158f2a7caccb7a9f6632a60011e7a44e1e5c\"@@@",
+      "@@@STEP_LOG_LINE@json.input@}@@@",
+      "@@@STEP_LOG_END@json.input@@@",
+      "@@@STEP_LINK@gerrit link@https://foo-review.googlesource.com/q/3e30158f2a7caccb7a9f6632a60011e7a44e1e5c@@@"
     ]
   },
   {
     "cmd": [
-      "vpython3",
-      "-u",
-      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
-      "--json-output",
-      "/path/to/tmp/json",
-      "remove",
-      "[CACHE]/git/.GUARD_FILE"
+      "[START_DIR]/cipd_tool/infra/tools/luci/gerrit/0e548aa33f8113a45a5b3b62201e114e98e63d00f97296912380138f44597b07/gerrit",
+      "change-detail",
+      "-host",
+      "https://foo-review.googlesource.com",
+      "-input",
+      "{\"change_id\": \"3380b83c11e029b7291c83c44e7b1ce09d465fd1\"}",
+      "-output",
+      "/path/to/tmp/json"
     ],
     "infra_step": true,
     "luci_context": {
@@ -1302,516 +1431,31 @@
         "hostname": "rdbhost"
       }
     },
-    "name": "checkout a.cache.remove git cache guard file",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "vpython3",
-      "-u",
-      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
-      "--json-output",
-      "/path/to/tmp/json",
-      "copytree",
-      "--symlinks",
-      "[CACHE]/git/foo.googlesource.com-a",
-      "[START_DIR]/project"
-    ],
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout a.copy from cache",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "checkout a.git checkout",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "checkout a.git checkout.timeout 10s",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "vpython3",
-      "-u",
-      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
-      "--json-output",
-      "/path/to/tmp/json",
-      "ensure-directory",
-      "--mode",
-      "0o777",
-      "[START_DIR]/project"
-    ],
-    "infra_step": true,
-    "luci_context": {
-      "deadline": {
-        "grace_period": 30.0,
-        "soft_deadline": 1337000028.0
-      },
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout a.git checkout.makedirs",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "init"
-    ],
-    "cwd": "[START_DIR]/project",
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout a.git checkout.git init",
-    "timeout": 300.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "remote",
-      "add",
-      "origin",
-      "https://foo.googlesource.com/a"
-    ],
-    "cwd": "[START_DIR]/project",
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout a.git checkout.git remote",
-    "timeout": 600.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "config",
-      "core.longpaths",
-      "true"
-    ],
-    "cwd": "[START_DIR]/project",
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout a.git checkout.set core.longpaths",
-    "timeout": 300.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "config",
-      "fetch.uriprotocols",
-      "https"
-    ],
-    "cwd": "[START_DIR]/project",
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout a.git checkout.set fetch.uriprotocols",
-    "timeout": 300.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "fetch",
-      "--tags",
-      "--jobs",
-      "4",
-      "origin",
-      "main"
-    ],
-    "cwd": "[START_DIR]/project",
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout a.git checkout.git fetch",
-    "timeout": 1200.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "checkout",
-      "-f",
-      "FETCH_HEAD"
-    ],
-    "cwd": "[START_DIR]/project",
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout a.git checkout.git checkout",
-    "timeout": 600.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "rev-parse",
-      "HEAD"
-    ],
-    "cwd": "[START_DIR]/project",
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout a.git checkout.git rev-parse",
-    "timeout": 300.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "clean",
-      "-f",
-      "-d",
-      "-x"
-    ],
-    "cwd": "[START_DIR]/project",
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout a.git checkout.git clean",
-    "timeout": 600.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "checkout a.git log",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "log",
-      "--oneline",
-      "-n",
-      "10"
-    ],
-    "cwd": "[START_DIR]/project",
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout a.git log.[START_DIR]/project",
-    "timeout": 600.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "clean",
-      "-f",
-      "-f",
-      "-d"
-    ],
-    "cwd": "[START_DIR]/project",
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout a.git clean",
-    "timeout": 600.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "status"
-    ],
-    "cwd": "[START_DIR]/project",
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout a.git status",
-    "timeout": 600.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "vpython3",
-      "-u",
-      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
-      "--json-output",
-      "/path/to/tmp/json",
-      "ensure-directory",
-      "--mode",
-      "0o777",
-      "[START_DIR]/snapshot"
-    ],
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout a.mkdir",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "submodule",
-      "status",
-      "--recursive"
-    ],
-    "cwd": "[START_DIR]/project",
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout a.submodule-status",
-    "timeout": 600.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "vpython3",
-      "-u",
-      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
-      "--json-output",
-      "/path/to/tmp/json",
-      "copy",
-      "submodule status filler text",
-      "[START_DIR]/snapshot/submodules.log"
-    ],
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout a.write submodule snapshot",
+    "name": "get gerrit change numbers.change details for 3380b83",
+    "timeout": 600,
     "~followup_annotations": [
       "@@@STEP_NEST_LEVEL@1@@@",
-      "@@@STEP_LOG_LINE@submodules.log@submodule status filler text@@@",
-      "@@@STEP_LOG_END@submodules.log@@@"
+      "@@@STEP_LOG_LINE@json.output@{@@@",
+      "@@@STEP_LOG_LINE@json.output@  \"_number\": 12345@@@",
+      "@@@STEP_LOG_LINE@json.output@}@@@",
+      "@@@STEP_LOG_END@json.output@@@",
+      "@@@STEP_LOG_LINE@json.input@{@@@",
+      "@@@STEP_LOG_LINE@json.input@  \"change_id\": \"3380b83c11e029b7291c83c44e7b1ce09d465fd1\"@@@",
+      "@@@STEP_LOG_LINE@json.input@}@@@",
+      "@@@STEP_LOG_END@json.input@@@",
+      "@@@STEP_LINK@gerrit link@https://foo-review.googlesource.com/q/3380b83c11e029b7291c83c44e7b1ce09d465fd1@@@"
     ]
   },
   {
     "cmd": [
-      "git",
-      "log",
-      "--oneline",
-      "-n",
-      "10"
-    ],
-    "cwd": "[START_DIR]/project",
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "checkout a.log",
-    "timeout": 600.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "vpython3",
-      "-u",
-      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
-      "--json-output",
-      "/path/to/tmp/json",
-      "copy",
-      "",
-      "[START_DIR]/snapshot/git.log"
+      "[START_DIR]/cipd_tool/infra/tools/luci/gerrit/0e548aa33f8113a45a5b3b62201e114e98e63d00f97296912380138f44597b07/gerrit",
+      "change-detail",
+      "-host",
+      "https://foo-review.googlesource.com",
+      "-input",
+      "{\"change_id\": \"363caa907186de786cb5292cd1ab7245da954815\"}",
+      "-output",
+      "/path/to/tmp/json"
     ],
     "infra_step": true,
     "luci_context": {
@@ -1826,71 +1470,19 @@
         "hostname": "rdbhost"
       }
     },
-    "name": "checkout a.write git log",
+    "name": "get gerrit change numbers.change details for 363caa9",
+    "timeout": 600,
     "~followup_annotations": [
       "@@@STEP_NEST_LEVEL@1@@@",
-      "@@@STEP_LOG_END@git.log@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "get roll direction",
-    "~followup_annotations": [
-      "@@@STEP_SUMMARY_TEXT@forward@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "merge-base",
-      "--is-ancestor",
-      "1111111111111111111111111111111111111111",
-      "2d72510e447ab60a9728aeea2362d8be2cbd7789"
-    ],
-    "cwd": "[START_DIR]/project",
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "get roll direction.is forward",
-    "timeout": 600.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "merge-base",
-      "--is-ancestor",
-      "2d72510e447ab60a9728aeea2362d8be2cbd7789",
-      "1111111111111111111111111111111111111111"
-    ],
-    "cwd": "[START_DIR]/project",
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "get roll direction.is backward",
-    "timeout": 600.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
+      "@@@STEP_LOG_LINE@json.output@{@@@",
+      "@@@STEP_LOG_LINE@json.output@  \"_number\": 12345@@@",
+      "@@@STEP_LOG_LINE@json.output@}@@@",
+      "@@@STEP_LOG_END@json.output@@@",
+      "@@@STEP_LOG_LINE@json.input@{@@@",
+      "@@@STEP_LOG_LINE@json.input@  \"change_id\": \"363caa907186de786cb5292cd1ab7245da954815\"@@@",
+      "@@@STEP_LOG_LINE@json.input@}@@@",
+      "@@@STEP_LOG_END@json.input@@@",
+      "@@@STEP_LINK@gerrit link@https://foo-review.googlesource.com/q/363caa907186de786cb5292cd1ab7245da954815@@@"
     ]
   },
   {
@@ -1946,405 +1538,6 @@
     ]
   },
   {
-    "cmd": [],
-    "name": "remote"
-  },
-  {
-    "cmd": [
-      "git",
-      "remote"
-    ],
-    "cwd": "[START_DIR]/project",
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "remote.name",
-    "timeout": 600.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "git",
-      "remote",
-      "get-url",
-      "origin"
-    ],
-    "cwd": "[START_DIR]/project",
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "remote.url",
-    "timeout": 600.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "a1"
-  },
-  {
-    "cmd": [
-      "git",
-      "log",
-      "--pretty=format:%H\n%an\n%ae\n%B",
-      "-z",
-      "1111111111111111111111111111111111111111..2d72510e447ab60a9728aeea2362d8be2cbd7789"
-    ],
-    "cwd": "[START_DIR]/project",
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "a1.git log",
-    "timeout": 600.0,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "a1.ensure infra/tools/luci/gerrit/${platform}",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "a1.ensure infra/tools/luci/gerrit/${platform}.get packages",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "vpython3",
-      "-u",
-      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
-      "--json-output",
-      "/path/to/tmp/json",
-      "copy",
-      "RECIPE_MODULE[fuchsia::gerrit]/resources/cipd.ensure",
-      "/path/to/tmp/"
-    ],
-    "cwd": "[START_DIR]/project",
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "a1.ensure infra/tools/luci/gerrit/${platform}.get packages.read ensure file",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@3@@@",
-      "@@@STEP_LOG_LINE@cipd.ensure@infra/tools/luci/gerrit/${platform} version:pinned-version@@@",
-      "@@@STEP_LOG_END@cipd.ensure@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "a1.ensure infra/tools/luci/gerrit/${platform}.install infra/tools/luci/gerrit",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@2@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "vpython3",
-      "-u",
-      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
-      "--json-output",
-      "/path/to/tmp/json",
-      "ensure-directory",
-      "--mode",
-      "0o777",
-      "[START_DIR]/cipd_tool/infra/tools/luci/gerrit/0e548aa33f8113a45a5b3b62201e114e98e63d00f97296912380138f44597b07"
-    ],
-    "cwd": "[START_DIR]/project",
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "a1.ensure infra/tools/luci/gerrit/${platform}.install infra/tools/luci/gerrit.ensure package directory",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@3@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "cipd",
-      "ensure",
-      "-root",
-      "[START_DIR]/cipd_tool/infra/tools/luci/gerrit/0e548aa33f8113a45a5b3b62201e114e98e63d00f97296912380138f44597b07",
-      "-ensure-file",
-      "infra/tools/luci/gerrit/${platform} version:pinned-version",
-      "-max-threads",
-      "0",
-      "-json-output",
-      "/path/to/tmp/json"
-    ],
-    "cwd": "[START_DIR]/project",
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "a1.ensure infra/tools/luci/gerrit/${platform}.install infra/tools/luci/gerrit.ensure_installed",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@3@@@",
-      "@@@STEP_LOG_LINE@json.output@{@@@",
-      "@@@STEP_LOG_LINE@json.output@  \"result\": {@@@",
-      "@@@STEP_LOG_LINE@json.output@    \"\": [@@@",
-      "@@@STEP_LOG_LINE@json.output@      {@@@",
-      "@@@STEP_LOG_LINE@json.output@        \"instance_id\": \"resolved-instance_id-of-version:pinned-v\",@@@",
-      "@@@STEP_LOG_LINE@json.output@        \"package\": \"infra/tools/luci/gerrit/resolved-platform\"@@@",
-      "@@@STEP_LOG_LINE@json.output@      }@@@",
-      "@@@STEP_LOG_LINE@json.output@    ]@@@",
-      "@@@STEP_LOG_LINE@json.output@  }@@@",
-      "@@@STEP_LOG_LINE@json.output@}@@@",
-      "@@@STEP_LOG_END@json.output@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "[START_DIR]/cipd_tool/infra/tools/luci/gerrit/0e548aa33f8113a45a5b3b62201e114e98e63d00f97296912380138f44597b07/gerrit",
-      "change-query",
-      "-host",
-      "https://pigweed-review.googlesource.com",
-      "-input",
-      "{\"params\": {\"q\": \"commit:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\"}}",
-      "-output",
-      "/path/to/tmp/json"
-    ],
-    "cwd": "[START_DIR]/project",
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "a1.get change-id",
-    "timeout": 600,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@",
-      "@@@STEP_LOG_LINE@json.output@[@@@",
-      "@@@STEP_LOG_LINE@json.output@  {@@@",
-      "@@@STEP_LOG_LINE@json.output@    \"_number\": 12345@@@",
-      "@@@STEP_LOG_LINE@json.output@  }@@@",
-      "@@@STEP_LOG_LINE@json.output@]@@@",
-      "@@@STEP_LOG_END@json.output@@@",
-      "@@@STEP_LOG_LINE@json.input@{@@@",
-      "@@@STEP_LOG_LINE@json.input@  \"params\": {@@@",
-      "@@@STEP_LOG_LINE@json.input@    \"q\": \"commit:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\"@@@",
-      "@@@STEP_LOG_LINE@json.input@  }@@@",
-      "@@@STEP_LOG_LINE@json.input@}@@@",
-      "@@@STEP_LOG_END@json.input@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "[START_DIR]/cipd_tool/infra/tools/luci/gerrit/0e548aa33f8113a45a5b3b62201e114e98e63d00f97296912380138f44597b07/gerrit",
-      "change-detail",
-      "-host",
-      "https://pigweed-review.googlesource.com",
-      "-input",
-      "{\"change_id\": \"12345\"}",
-      "-output",
-      "/path/to/tmp/json"
-    ],
-    "cwd": "[START_DIR]/project",
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "a1.get 12345",
-    "timeout": 600,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@",
-      "@@@STEP_LOG_LINE@json.output@{@@@",
-      "@@@STEP_LOG_LINE@json.output@  \"owner\": {@@@",
-      "@@@STEP_LOG_LINE@json.output@    \"email\": \"author@example.com\",@@@",
-      "@@@STEP_LOG_LINE@json.output@    \"name\": \"author\"@@@",
-      "@@@STEP_LOG_LINE@json.output@  },@@@",
-      "@@@STEP_LOG_LINE@json.output@  \"reviewers\": {@@@",
-      "@@@STEP_LOG_LINE@json.output@    \"REVIEWER\": [@@@",
-      "@@@STEP_LOG_LINE@json.output@      {@@@",
-      "@@@STEP_LOG_LINE@json.output@        \"email\": \"reviewer@example.com\",@@@",
-      "@@@STEP_LOG_LINE@json.output@        \"name\": \"reviewer\"@@@",
-      "@@@STEP_LOG_LINE@json.output@      },@@@",
-      "@@@STEP_LOG_LINE@json.output@      {@@@",
-      "@@@STEP_LOG_LINE@json.output@        \"email\": \"nobody@google.com\",@@@",
-      "@@@STEP_LOG_LINE@json.output@        \"name\": \"nobody\"@@@",
-      "@@@STEP_LOG_LINE@json.output@      },@@@",
-      "@@@STEP_LOG_LINE@json.output@      {@@@",
-      "@@@STEP_LOG_LINE@json.output@        \"email\": \"robot@gserviceaccount.com\",@@@",
-      "@@@STEP_LOG_LINE@json.output@        \"name\": \"robot\"@@@",
-      "@@@STEP_LOG_LINE@json.output@      }@@@",
-      "@@@STEP_LOG_LINE@json.output@    ]@@@",
-      "@@@STEP_LOG_LINE@json.output@  }@@@",
-      "@@@STEP_LOG_LINE@json.output@}@@@",
-      "@@@STEP_LOG_END@json.output@@@",
-      "@@@STEP_LOG_LINE@json.input@{@@@",
-      "@@@STEP_LOG_LINE@json.input@  \"change_id\": \"12345\"@@@",
-      "@@@STEP_LOG_LINE@json.input@}@@@",
-      "@@@STEP_LOG_END@json.input@@@",
-      "@@@STEP_LINK@gerrit link@https://pigweed-review.googlesource.com/q/12345@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "cc author@example.com",
-    "~followup_annotations": [
-      "@@@STEP_SUMMARY_TEXT@CCing@@@"
-    ]
-  },
-  {
-    "cmd": [
-      "[START_DIR]/cipd_tool/infra/tools/luci/gerrit/0e548aa33f8113a45a5b3b62201e114e98e63d00f97296912380138f44597b07/gerrit",
-      "account-query",
-      "-host",
-      "https://host-review.googlesource.com",
-      "-input",
-      "{\"params\": {\"q\": \"email:author@example.com\"}}",
-      "-output",
-      "/path/to/tmp/json"
-    ],
-    "infra_step": true,
-    "luci_context": {
-      "realm": {
-        "name": "project:ci"
-      },
-      "resultdb": {
-        "current_invocation": {
-          "name": "invocations/build:8945511751514863184",
-          "update_token": "token"
-        },
-        "hostname": "rdbhost"
-      }
-    },
-    "name": "cc author@example.com.author@example.com",
-    "timeout": 600,
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@",
-      "@@@STEP_LOG_LINE@json.output@[@@@",
-      "@@@STEP_LOG_LINE@json.output@  {@@@",
-      "@@@STEP_LOG_LINE@json.output@    \"_account_id\": 123@@@",
-      "@@@STEP_LOG_LINE@json.output@  }@@@",
-      "@@@STEP_LOG_LINE@json.output@]@@@",
-      "@@@STEP_LOG_END@json.output@@@",
-      "@@@STEP_LOG_LINE@json.input@{@@@",
-      "@@@STEP_LOG_LINE@json.input@  \"params\": {@@@",
-      "@@@STEP_LOG_LINE@json.input@    \"q\": \"email:author@example.com\"@@@",
-      "@@@STEP_LOG_LINE@json.input@  }@@@",
-      "@@@STEP_LOG_LINE@json.input@}@@@",
-      "@@@STEP_LOG_END@json.input@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "authors",
-    "~followup_annotations": [
-      "@@@STEP_SUMMARY_TEXT@{Account(name='author', email='author@example.com')}@@@"
-    ]
-  },
-  {
-    "cmd": [],
-    "name": "roll message"
-  },
-  {
-    "cmd": [],
-    "name": "roll message.message for a1",
-    "~followup_annotations": [
-      "@@@STEP_NEST_LEVEL@1@@@",
-      "@@@STEP_LOG_LINE@template@roll: {project_name}: {sanitized_message}@@@",
-      "@@@STEP_LOG_LINE@template@@@@",
-      "@@@STEP_LOG_LINE@template@{remote}@@@",
-      "@@@STEP_LOG_LINE@template@{project_name} Rolled-Commits: {old_revision:.15}..{new_revision:.15}@@@",
-      "@@@STEP_LOG_END@template@@@",
-      "@@@STEP_LOG_LINE@kwargs@'new_revision': '2d72510e447ab60a9728aeea2362d8be2cbd7789'@@@",
-      "@@@STEP_LOG_LINE@kwargs@'old_revision': '1111111111111111111111111111111111111111'@@@",
-      "@@@STEP_LOG_LINE@kwargs@'original_message': 'foo\\nbar'@@@",
-      "@@@STEP_LOG_LINE@kwargs@'project_name': 'a1'@@@",
-      "@@@STEP_LOG_LINE@kwargs@'remote': 'https://pigweed.googlesource.com/pigweed/pigweed'@@@",
-      "@@@STEP_LOG_LINE@kwargs@'sanitized_message': 'foo\\nbar'@@@",
-      "@@@STEP_LOG_END@kwargs@@@",
-      "@@@STEP_LOG_LINE@message@roll: a1: foo@@@",
-      "@@@STEP_LOG_LINE@message@bar@@@",
-      "@@@STEP_LOG_LINE@message@@@@",
-      "@@@STEP_LOG_LINE@message@https://pigweed.googlesource.com/pigweed/pigweed@@@",
-      "@@@STEP_LOG_LINE@message@a1 Rolled-Commits: 111111111111111..2d72510e447ab60@@@",
-      "@@@STEP_LOG_END@message@@@"
-    ]
-  },
-  {
     "cmd": [
       "git",
       "ls-files",
@@ -2541,11 +1734,9 @@
       "git",
       "commit",
       "-m",
-      "roll: a1: foo\nbar\n\nhttps://pigweed.googlesource.com/pigweed/pigweed\na1 Rolled-Commits: 111111111111111..2d72510e447ab60\nRoller-URL: https://ci.chromium.org/b/8945511751514863184\nCQ-Do-Not-Cancel-Tryjobs: true\nChange-Id: I29f17ffd56e9f40bfb35bf83965b9a4effec4d69",
+      "roll: a1 1111111..2d72510 (3 commits)\n\n3e30158:https://foo-review.googlesource.com/c/a/+/12345 fake A msg 0\n3380b83:https://foo-review.googlesource.com/c/a/+/12345 fake A msg 1\n363caa9:https://foo-review.googlesource.com/c/a/+/12345 fake A msg 2\n\nRolled-Repo: https://foo.googlesource.com/a\nRolled-Commits: 11111111111111..2d72510e447ab6\nRoller-URL: https://ci.chromium.org/b/8945511751514863184\nCQ-Do-Not-Cancel-Tryjobs: true\nChange-Id: I29f17ffd56e9f40bfb35bf83965b9a4effec4d69",
       "-a",
-      "--no-verify",
-      "--author",
-      "author <author@pigweed.infra.roller.example.com>"
+      "--no-verify"
     ],
     "cwd": "[START_DIR]/co",
     "infra_step": true,
@@ -2571,7 +1762,7 @@
       "--push-option",
       "nokeycheck",
       "origin",
-      "HEAD:refs/for/main%l=Commit-Queue+1,cc=author@example.com"
+      "HEAD:refs/for/main%l=Commit-Queue+1"
     ],
     "cwd": "[START_DIR]/co",
     "infra_step": true,
diff --git a/recipes/repo_roller.proto b/recipes/repo_roller.proto
index c8d0a56..9b1f194 100644
--- a/recipes/repo_roller.proto
+++ b/recipes/repo_roller.proto
@@ -59,4 +59,7 @@
   // Default is 10. To disable CCing, don't set the "cc_*_on_rolls" values
   // above, or set this to a negative value.
   int32 max_commits_for_ccing = 10;
+
+  // Line of text to divide the commit header and body from the footers.
+  string commit_divider = 11;
 }
diff --git a/recipes/repo_roller.py b/recipes/repo_roller.py
index f26f903..51d8778 100644
--- a/recipes/repo_roller.py
+++ b/recipes/repo_roller.py
@@ -32,15 +32,17 @@
 if TYPE_CHECKING:  # pragma: no cover
     from typing import Generator
     from recipe_engine import config_types, recipe_test_api
-    from RECIPE_MODULES.pigweed.roll_util import api as roll_util_api
+    from RECIPE_MODULES.fuchsia.roll_util import api as git_roll_util_api
 
 DEPS = [
     'fuchsia/auto_roller',
+    'fuchsia/git_roll_util',
+    'fuchsia/gitiles',
+    'fuchsia/roll_commit_message',
     'pigweed/checkout',
     'pigweed/repo_roll',
     'pigweed/roll_util',
     'recipe_engine/properties',
-    'recipe_engine/step',
 ]
 
 PROPERTIES = InputProperties
@@ -68,37 +70,9 @@
     assert len(rolls) == 1
     roll = rolls[0]
 
-    authors = api.roll_util.authors(roll)
-
-    max_commits_for_ccing = props.max_commits_for_ccing or 10
-    if len(roll.commits) <= max_commits_for_ccing:
-        cc = set()
-        if cc_authors_on_rolls:
-            cc.update(authors)
-        if cc_reviewers_on_rolls:
-            cc.update(api.roll_util.reviewers(roll))
-
-        def include_cc(email):
-            return api.roll_util.include_cc(
-                email, cc_domains, checkout.gerrit_host()
-            )
-
-        # include_cc() writes steps, so we want things sorted before calling it.
-        cc = sorted(set(cc))
-        cc_emails = [x.email for x in cc if include_cc(x)]
-
-        if always_cc:
-            props.auto_roller_options.cc_emails.extend(cc_emails)
-        else:
-            props.auto_roller_options.cc_on_failure_emails.extend(cc_emails)
-
-    author_override = None
-    with api.step.nest('authors') as pres:
-        pres.step_summary_text = repr(authors)
-    if len(authors) == 1 and props.forge_author:
-        author_override = attrs.asdict(
-            api.roll_util.fake_author(next(iter(authors)))
-        )
+    author_override: api.git_roll_util.Author | None = None
+    if props.forge_author:
+        author_override = api.git_roll_util.get_author_override(*rolls)
 
     # merge auto_roller_options and override_auto_roller_options.
     complete_auto_roller_options = api.roll_util.merge_auto_roller_overrides(
@@ -108,7 +82,12 @@
     change = api.auto_roller.attempt_roll(
         complete_auto_roller_options,
         repo_dir=checkout.root,
-        commit_message=api.roll_util.message(roll),
+        commit_message=api.roll_commit_message.format(
+            *rolls,
+            roll_prefix='roll:',
+            send_comment=True,
+            commit_divider=props.commit_divider,
+        ),
         author_override=author_override,
     )
 
@@ -143,11 +122,6 @@
 
         return api.properties(props)
 
-    def commit_data(name=None):
-        return api.roll_util.commit_data(
-            name, api.roll_util.commit('a' * 40, 'foo\nbar')
-        )
-
     yield api.test(
         'success',
         properties(
@@ -157,9 +131,8 @@
             always_cc=True,
         ),
         api.checkout.ci_test_data(git_repo='https://foo.googlesource.com/a'),
-        commit_data('a1'),
+        api.gitiles.log('log a1', 'A'),
         api.repo_roll.read_step_data(),
-        api.roll_util.forward_roll(),
         api.auto_roller.dry_run_success(),
     )
 
@@ -177,9 +150,8 @@
             cc_reviewers_on_rolls=True,
         ),
         api.checkout.ci_test_data(git_repo='https://equiv.googlesource.com/b'),
-        commit_data('b2'),
+        api.gitiles.log('log b2', 'A'),
         api.repo_roll.read_step_data(),
-        api.roll_util.forward_roll(),
         api.auto_roller.dry_run_success(),
     )
 
@@ -188,5 +160,5 @@
         properties(api, Project(path_to_update='a1')),
         api.checkout.ci_test_data(git_repo='https://foo.googlesource.com/a'),
         api.repo_roll.read_step_data(),
-        api.roll_util.backward_roll(),
+        api.gitiles.log('log a1', 'A', n=0),
     )