I have a repository hosted on github that I used to develop some code, let's call it https://github.com/foo/bar.git.
In another, completely separate local repository I developed some other code. Now I want to push the content of this local repository to https://github.com/foo/bar.git, completely replacing the old content (branches, tags, etc.). How do I achieve this?
I know I could simply delete the repo on github and create a new one, but I would like to avoid this.
I set the remote URL in the local repo. I also did git push
, but this resulted in the new content coexisting with the original one (e.g. due to main
vs. master
branch mismatch). Is there a way to fix it?
CodePudding user response:
Xiidref's comment-answer is largely correct, but misses several notes:
Since you have a
main
now and nomaster
in your replacement repository, you may want to have GitHub set the namemain
, not the namemaster
. Then you may want to delete the old namemaster
entirely, but before you can do that, you likely need to tell GitHub to change their notion of the default branch for your GitHub-side repository, since you cannot delete the branch name that is the recommended default for clones.Alternatively, perhaps you'd like to continue using the name
master
on the remote. If so, you will need to decide whether to rename the branch in your own local repository. The easy thing is togit branch -m main master
and then force-push as needed.
To do the former (switch the GitHub branch name to main
), you can start with:
git remote add origin https://github.com/foo/bar.git
git push -u origin main
This sends (most if not all of) your new commits, with their lack of relation to the existing commits, to GitHub, then asks the GitHub-side software to create a new branch name main
there. On success, it sets the upstream of your local main
to your newly created origin/main
.
Now that main
exists over there, you can use the GitHub web pages or the gh
cli command to set the default branch name over there to main
:
gh repo edit --default-branch main
(or use a browser and the usual clicky button stuff).
More
You probably also want to delete all existing tag and other branch names on the GitHub side, then create new ones for any new branch and tag names.
You can—but do not have to; see below—use git push --delete
to delete all the branch and tag names that GitHub have, except for the new main
you just created, or the master
you just updated. To get a list of such names, consider using:
git ls-remote origin
which will spill them all out (you probably want to redirect this to a file you can edit). Be sure to filter out the names HEAD
and main
. You can supply the remaining names to a single git push origin --delete
with or without the refs/heads/
and refs/tags/
prefixes, e.g.:
git push origin --delete br1 br2 master tag1 tag2 tag3
Now, if you have more branch and/or tag names to set, you can do them all at once with one more git push
, e.g.:
git push -u origin newbr1 newbr2 newtag1 newtag2
(note: I'm not actually sure whether -u
works correctly when pushing tags; if it causes problems, consider splitting this into two separate git push
commands, one for branch names with -u
and one for tag names without -u
).
As a short-cut, consider:
git push --mirror origin
The --mirror
option will delete names not pushed, and will attempt to push (with --force
) all branch and tag names. So this should cover both the "delete old names" and "update new ones". I don't think this can be combined with -u
, though. You can instead run git fetch
afterward, to create the origin/*
names if / as needed, and then do a series of git branch --set-upstream-to
commands (which is easily scripted).
If you have any protected branch names, you may need to un-protect them before doing all this.
Caveat
Deleting the branch names from your GitHub-side repository makes the old commits that are there un-find-able. It does not, however, actually delete those commits. GitHub have an internal retention policy (for internal reasons having to do with GitHub forks) of keeping such commits forever, rather than Git's typical local 30 or 90 day expiration period. (You can ask the support folks to purge the dead commits, as you might do with commits that contain sensitive data. I'm not sure what the policies are on that for this kind of case, though.)
All of this means that it's (a) a lot easier to just delete your GitHub-side repository entirely; (b) doing so may save GitHub themselves some disk space, especially if there are no forks of your private repository. So I wouldn't bother doing this the more complicated, repository-retaining way. Of course, deleting and re-creating the repository also destroys the GitHub-only database of issues, PRs, and so on, which may be a consideration.