Page MenuHomePhabricator

When landing a branch tracking upstream, try switching to local tracking branch of the same name
Closed, ResolvedPublic

Description

It's not uncommon for users to create local branches that directly track origin/master by making them using git branch -b newbranch origin/master. This is useful as it allows git pull --rebase to sync up with the remote, and is also what many pieces of basic git documentation suggest. When landing, however, this leaves them with a detached HEAD, as there's nothing left in the path to upstream.

But detached HEAD states are potentially confusing, and we can do better -- there may be other paths to upstream still in the repository. The simplest option, which is already implemented for branches which have no upstream set, is to try to swap to a local branch of the same name as the onto target, as long as it both exists and tracks the same upstream.

diff --git a/src/land/ArcanistGitLandEngine.php b/src/land/ArcanistGitLandEngine.php
index 95b33aa..7256b05 100644
--- a/src/land/ArcanistGitLandEngine.php
+++ b/src/land/ArcanistGitLandEngine.php
@@ -262,13 +262,26 @@ final class ArcanistGitLandEngine
         $path->removeUpstream($local_branch);
 
         if (!$path->getLength()) {
-          $this->writeInfo(
-            pht('UPDATE'),
-            pht(
-              'Local branch "%s" directly tracks remote, staying on '.
-              'detached HEAD.',
-              $local_branch));
-          return;
+          // The local branch tracked upstream directly; however, it
+          // may not be the only one to do so.  If there's a local
+          // branch of the same name that tracks the remote, try
+          // switching to that.
+          $local_branch = $this->getTargetOnto();
+          list($err) = $api->execManualLocal(
+            'rev-parse --verify %s',
+            $local_branch);
+          if (!$err) {
+            $path = $api->getPathToUpstream($local_branch);
+          }
+          if (!$path->isConnectedToRemote()) {
+            $this->writeInfo(
+              pht('UPDATE'),
+              pht(
+                'Local branch "%s" directly tracks remote, staying on '.
+                'detached HEAD.',
+                $local_branch));
+            return;
+          }
         }
 
         $local_branch = head($path->getLocalBranches());

(As a meta note, the contributing docs say to create a task, and not jump to making a diff -- hence this task. I can push a diff revision with that patch, if that's preferable)