First, undo any single-branch-ness or shallowness unless the new clone would have been single-branch and/or shallow (in which case do any single-branch-ness or shallowness, but do the shallowing at the end of the process). Clean out any other nonstandard settings that accumulated in .git/config
, other than ones you would have set manually in your git clone
operation.
Then, if needed, rename one upstream / origin remote, removing all the others. Suppose, for instance, you had intended to use the default git clone
remote name of origin
, but the existing repository uses upstream1
for that and has a second remote upstream2
. Remove upstream2
(with git remote remove
) and rename upstream1
to origin
(with git remote rename
).
Then, run git fetch
on the remote name you are keeping, whatever that is, with the --prune
and --prune-tags
options. The default is origin
so if you're keeping the default you can just git fetch -p
as this will mean git fetch =p origin
. (I'm not 100% sure what happens to the upstream setting of the current branch, whatever it is, if it was some other remote, so you might want to just run git fetch -p origin
to be safe in all cases.)
This next step assumes non-single-branch-ness. I'm not sure what origin/HEAD
is when you use a single-branch clone of, say, branch X
while origin's HEAD
is set to master
. If you're not worried about single-branch-ness (or you never use origin/HEAD
) none of this really matters anyway, but I'm trying to be complete here.
Now run git remote set-head --auto
on the remaining remote, e.g., git remote --set-head origin --auto
. There's a slight race between the previous step and this one. If the upstream Git that you would have git clone
d is moving its HEAD around from branch to branch all the time, that's sort of inevitable: which HEAD
you got from them would depend on when you did your git clone
. However, this will expose the difference between running git clone
and running this sequence of commands. If the upstream Git isn't moving its HEAD around, there is no race here: their HEAD
is stable between the git fetch
and the git remote set-head
.
Now choose the one local branch name you wish to have. Typically, in a fresh git clone
with all the defaults, the one local branch you would have is the one they recommend with their HEAD
, which is now copied to your origin/HEAD
due to the git remote set-head
. So read that out (git branch -r origin
for instance, or git symbolic-ref refs/remotes/origin/HEAD
) to see which branch that is. (It's probably master
.) Check out that branch name—this should succeed even if your Git has to create it—and make sure its upstream is set to the appropriate remote-tracking name (e.g., origin/master
), changing it if necessary. Use git reset --hard @{upstream}
to:
- move it, if
git checkout
didn't create it;
- reset your index and work-tree
and then delete the others and use git clean -dfx
to remove all directories and files that would not have been extracted from the initial git checkout
that a git clone
would have run as its last step.
You're now done, unless you wanted a shallow clone, in which case you may now need to en-shallow-ize your current repository. You may optionally run git gc --prune=all
to clean up pack files.
Summary, minus all the fiddling with single-branch and shallow and such
If we can make a few reasonable assumptions the processes gets a lot simpler. The assumptions are:
- no single-branch-ness, no shallowness, and just one remote
origin
that's already set correctly;
- no local branches named
origin/*
to trip you up below;
- no other screwy local settings to clean up (e.g., you didn't
git config user.name
in this repository); and
- no desire to fuss with
git remote set-head
(you can do that any time though).
In this case, the process is this, which is pretty much cut-and-paste-able, just change master
to whatever branch you wanted to keep:
git fetch -p --prune-tags
git checkout master # or whatever branch you intended to keep
git branch --set-upstream-to=origin/master # use correct origin/ name here
git reset --hard origin/master # update work-tree
git clean -dfx # remove non-committed stuff from work-tree
git for-each-ref --format='%(refname:short)' refs/heads |
while read name; do
[ "$name" == "master" ] && continue # skip the one to keep
git branch -D "$name" # delete the others
done
(the above is untested, so be careful!). The --set-upstream-to
step is typically unnecessary (it will be a no-op), but I included it for completeness.
Please note that the git clean -dfx
step potentially removes a lot of potentially-useful files. You said you wanted the state you'd have if you ran git clone
, though, and none of those potentially-useful files would be copied by git clone
. Since you are probably doing this to avoid this particular git clean
type of effect, you probably want to omit, or at the least modify a lot, the git clean
step.