Answer a question

I need to "re-push" all branches (not just local branches) from my local clone to my origin (github server).

git push --all origin only pushes the branches that I had previously checked out. I want to push all of them, including the ones that I did not check out.

Why do I need to do this? Because someone did a git push -f --mirror and that removed almost all branches from the server (kept only the person's local branches).

Things that I have tried. Disclaimer: On all commands that I would be pushing something to the server I am using --dry-run because I want to see the result first.

  • git push --all origin. Only pushes branches that I had previously checked out.
  • Trying with a bare repository:
    • git clone --bare /path/to/loca/repo /some/path/BareRepo Create a local bare repository from the local repo.
    • git remote add origin2 https://github.com/xxx/Repo.git Adding a new remote on the BareRepo to github.
    • git push --all origin2 Pushing. Again only pushed branches that I had checked out on the original repository.
  • If I checkout a branch that I had never checked out and then run the push --all origin I see this branch on the output (--dry-run). So this is the fallback... checkout hundreds of branches. But I am looking for a better approach.

Any suggestions?

EDIT 1: Just to clarify. I still have my local clone without the removal of branches. This is what I am trying to use to restore the branches.

Answers

If you still have origin/* remote-tracking names in your local repository, you can do this. Warning: it's a bit clumsy. It's probably better to just grab the list of names into a file and edit it, rather than using the grep -v HEAD trick.

git for-each-ref --format='%(refname):refs/heads/%(refname:lstrip=3)' refs/remotes/origin | 
    grep -v HEAD |
    xargs git push origin

(this is really all one line, broken up for posting purpses, though as three lines in sh/bash it should still work too).

The general idea here is to use each of your remote-tracking refs/remotes/origin/* references to obtain a hash ID to send to the Git at origin, asking it to create or update its correspondingly-named branch.

Some very old versions of Git won't have the fancy %(refname:lstrip=3) handling, so it's a good idea to run just the:

git for-each-ref --format='%(refname):refs/heads/%(refname:lstrip=3)' refs/remotes/origin

part by itself first and verify that it produces the output one would expect, e.g.:

refs/remotes/origin/HEAD:refs/heads/HEAD
refs/remotes/origin/maint:refs/heads/maint
refs/remotes/origin/master:refs/heads/master
refs/remotes/origin/next:refs/heads/next
refs/remotes/origin/pu:refs/heads/pu
refs/remotes/origin/todo:refs/heads/todo

for my Git clone of the Git repository for Git. Note the extra HEAD line, which is why we use grep -v HEAD, which is clumsy as it will toss a branch name such as SHEADWICK, should you have such a name.

Logo

ModelScope旨在打造下一代开源的模型即服务共享平台,为泛AI开发者提供灵活、易用、低成本的一站式模型服务产品,让模型应用更简单!

更多推荐