Repository: iterative/dvc

Issue:
experiments: repro --exp fails the first time after updating experiments workspace via pull
If new commits are made in the parent repro, and then an experiment based on the new parent HEAD is generated, `dvc repro --exp` fails, but will succeed the next time `repro` is run

```
example-get-started git:executor-tree  py:dvc ❯ dvc repro -e --params featurize.max_features=1500,featurize.ngrams=4                                     ⏎
ERROR: unexpected error - Cmd('git') failed due to: exit code(1)
  cmdline: git pull -v origin

Having any troubles? Hit us up at https://dvc.org/support, we are always happy to help!
example-get-started git:executor-tree  py:dvc ❯ dvc repro -e --params featurize.max_features=1500,featurize.ngrams=4                                     ⏎
...
Reproduced experiment 'ebbf40d'.
```


Discussion:

Resolving patch:
diff --git a/dvc/repo/experiments/__init__.py b/dvc/repo/experiments/__init__.py
--- a/dvc/repo/experiments/__init__.py
+++ b/dvc/repo/experiments/__init__.py
@@ -162,13 +162,25 @@ def _config_clone(self):
     def _scm_checkout(self, rev):
         self.scm.repo.git.reset(hard=True)
         if self.scm.repo.head.is_detached:
-            # switch back to default branch
-            self.scm.repo.heads[0].checkout()
+            self._checkout_default_branch()
         if not Git.is_sha(rev) or not self.scm.has_rev(rev):
             self.scm.pull()
         logger.debug("Checking out experiment commit '%s'", rev)
         self.scm.checkout(rev)
 
+    def _checkout_default_branch(self):
+        # switch to default branch
+        git_repo = self.scm.repo
+        origin_refs = git_repo.remotes["origin"].refs
+        ref = origin_refs["HEAD"].reference
+        branch_name = ref.name.split("/")[-1]
+        if branch_name in git_repo.heads:
+            branch = git_repo.heads[branch_name]
+        else:
+            branch = git_repo.create_head(branch_name, ref)
+            branch.set_tracking_branch(ref)
+        branch.checkout()
+
     def _stash_exp(self, *args, params: Optional[dict] = None, **kwargs):
         """Stash changes from the current (parent) workspace as an experiment.
 


Test patch:
diff --git a/tests/func/experiments/test_experiments.py b/tests/func/experiments/test_experiments.py
--- a/tests/func/experiments/test_experiments.py
+++ b/tests/func/experiments/test_experiments.py
@@ -22,3 +22,30 @@ def test_new_simple(tmp_dir, scm, dvc, mocker):
     assert (
         tmp_dir / ".dvc" / "experiments" / "metrics.yaml"
     ).read_text() == "foo: 2"
+
+
+def test_update_with_pull(tmp_dir, scm, dvc, mocker):
+    tmp_dir.gen("copy.py", COPY_SCRIPT)
+    tmp_dir.gen("params.yaml", "foo: 1")
+    stage = dvc.run(
+        cmd="python copy.py params.yaml metrics.yaml",
+        metrics_no_cache=["metrics.yaml"],
+        params=["foo"],
+        name="copy-file",
+    )
+    scm.add(["dvc.yaml", "dvc.lock", "copy.py", "params.yaml", "metrics.yaml"])
+    scm.commit("init")
+    expected_revs = [scm.get_rev()]
+
+    tmp_dir.gen("params.yaml", "foo: 2")
+    dvc.reproduce(stage.addressing, experiment=True)
+    scm.add(["dvc.yaml", "dvc.lock", "params.yaml", "metrics.yaml"])
+    scm.commit("promote experiment")
+    expected_revs.append(scm.get_rev())
+
+    tmp_dir.gen("params.yaml", "foo: 3")
+    dvc.reproduce(stage.addressing, experiment=True)
+
+    exp_scm = dvc.experiments.scm
+    for rev in expected_revs:
+        assert exp_scm.has_rev(rev)