Home > Software engineering >  How to update Remote/Origin on another computer after branch renaming
How to update Remote/Origin on another computer after branch renaming

Time:06-18

I found a way to update my computer and Remote/Origin branch to match when I rename a branch.

you can imagine renaming branch as:

git checkout oldBranchName

git branch -m renamedBranch

git push origin :oldBranchName renamedBranch // deletes old branch and push the renamed branch

My computer's local .git/refs/remotes/origin is updated and any use of CLI or GUI(for git like Sourcetree) looks correct on my computer.

I am trying to find an easy/least risky way of updating the reference on a coworker's computer.

Something like:

# !!! Fake git command, only for clarifying a point
git update --refs

OR

git pull/fetch --refs
  • Using --set-upstream to link branch "oldBranchName" to origin/renamedBranchName is confusing.
  • "git update-ref" seems dangerous and not really what I am looking for.

Note: I do understand that my coworker can delete the old branch and pull the new renamedBranch, however, this does not scale well to 10 coworkers.

CodePudding user response:

TL;DR

This is a bit long, so here's a TL;DR simple recipe for each of them:

  1. run git fetch --prune;

  2. if they have a branch named oldBranchName, run:

    git branch -m oldBranchName renamedBranch
    git branch --set-upstream-to=origin/renamedBranch renamedBranch
    

    (in that order). If they don't have that branch, these two commands will fail (harmlessly).

That's it: just the three commands (or one command if they have no oldBranchName). The longer version below explains what this is for and gives an alternative sequence in the rare case that they have a really ancient Git version that lacks a few of these options.

Long

They need to run git fetch to see the new branch name, which will show up in their clone as origin/renamedBranch. They can run this command at any time (unlike git pull, which can only be run at "safe" times). But there are two remaining issues:

  1. They will still have origin/oldBranchName, at least by default (see more below).
  2. If they have a branch named oldBranchName, they still have that branch, still named oldBranchName. There is nothing wrong with this as far as Git is concerned: a branch name in your clone need not match the branch name in some other clone, including the clone over at origin. But it's confusing to work with.

To fix item 1, they need to tell their own Git software to "prune" remote-tracking names (the various origin/* names) that no longer exist as branch names over on origin. The key to understanding this is:

  • Each repository has its own branch names. Your branch names are yours and their branch names are theirs. We (humans) like to use the same name to keep things simple, but that's not a Git requirement.

  • Whenever they run git fetch—and remember that git pull is a convenience command that runs two Git commands for you, with the first one being git fetch; it's the second command that makes git pull hard—their Git software calls up some other Git software over at origin. The Git software over at origin lists out all the branch names in the clone at origin. So their Git (their software, operating in/on their repository) sees origin's Git's branch names. Their Git takes each of these names and renames it by sticking origin/ in front of it.1 The result is a remote-tracking name (identified in part by the origin/ in front, and in part because if you ask for colorized branch-name-listings, Git normally prints the remote-tracking names in red and the [local2] branch names in green).

  • So, your Git's remote-tracking names—origin/main, origin/develop, and so on—are your Git's way of remembering some other Git's names. That's it!

The normal update process, though, goes like this:

  1. you run git fetch origin (or just git fetch, which does the same thing);
  2. your Git (your software in your repo) calls up their Git at origin;
  3. they list out their branch names;
  4. your Git changes their branch names into your remote-tracking names, using the same renaming system every time;
  5. for each name obtained this way, your Git creates or updates the remote-tracking name.

If a branch name gets deleted on the remote, there's no corresponding remote-tracking name in step 4, so there's no update in step 5. If origin had a branch xyzzy yesterday and you ran git fetch, your Git created origin/xyzzy in your Git yesterday. Today, they have no xyzzy, and your Git doesn't update your origin/xyzzy. It doesn't remove it either. You're left with a stale remote-tracking name.

To clear out all the stale names, you have two Git commands:

  • git remote prune origin, or
  • git fetch --prune origin.

These supposedly do exactly the same thing. There was a range of Git versions (whose numbers I forget, back in the 1.7 or 1.8 days) where the code was a little broken and one of the two commands worked better than the other, so if you have a really old Git and one of the two commands isn't working right, try the other one. But both are supposed to:

  1. call up the Git over at origin and have it list out its branch names;
  2. do the usual renaming to form remote-tracking names; and
  3. remove from your own repository any remote-tracking name for which there's no longer a branch name over on origin.

Step 3 here is the pruning part. Using git fetch --prune will also do the regular git fetch work, while git remote origin prune will only do the pruning work.

Having now gotten rid of origin/renamedBranch in your own local clone, you now have one remaining problem: your own branch named oldBranchName still exists, if it existed before, and it still records origin/oldBranchName as its upstream setting, if it did so before. So we must rename the branch. That's easy: git branch -m does the trick. With one name:

git branch -m foo

Git renames the current branch so that its name is now foo. That's not what we want, unless the current branch is oldBranchName, but:

git branch -m oldBranchName renamedBranch

will rename the branch named oldBranchName to renamedBranch even if oldBranchName is the current branch. So that handles the first part.

To fix the second part—that the branch we just renamed might still have origin/oldBranchName set as its upstream—we just need to use git branch --set-upstream-to.3 This takes, after the equals sign, the new upstream, and then an optional branch name like git branch -m. If you don't give the optional branch name, it updates the current branch—not what we want unless oldBranchName is the current branch—so again we provide the renamed branch name:

git branch --set-upstream-to=origin/renamedBranch renamedBranch

We've now:

  • updated our origin/* names, clearing out the dead junk, via git fetch --prune; and
  • renamed our local branch and fixed its upstream setting

and that is everything we need to do.


1Internally, Git does this with a crazy-complicated system, but that's the normal end result.

2The word local here is redundant: your branch names are yours. They're all local. Even your remote-tracking names are local, they're just made up from the remote's branch names. They're made up freshly on every git fetch!

3If you have a very old git branch command, it may not have --set-upstream-to. In this case it has --set-upstream, which takes its arguments in confusing order: git branch --set-upstream renamedBranch origin/renamedBranch.)

  • Related