Home > Software engineering >  How to replace remote repository content with unrelated history?
How to replace remote repository content with unrelated history?

Time:04-08

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 no master in your replacement repository, you may want to have GitHub set the name main, not the name master. Then you may want to delete the old name master 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 to git 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.

  • Related