Doing push --force
is always kinda risky and here is an example of how it could produce some problems like loosing revisions remotely.
Suppose, there is some person Bob that has updated remote master
branch from B
to C
. And there is another person Mike that doesn't fetch this update yet and HEAD
of his master
is still B
. Then Mike
do push --force
and suddenly roll back remote master
to B
again:
mike@laptop $> git push --force origin
Counting objects: 19, done.
Delta compression using up to 8 threads.
Compressing objects: 100% (12/12), done.
Writing objects: 100% (12/12), 2.27 KiB, done.
Total 12 (delta 8), reused 0 (delta 0)
remote: => Syncing... [OK]
To [email protected]:path/to/project.git
C..B master -> master (forced update)
In other words, before Mike did that, remote master was like A---B---C
and he changed it to A---B
.
As you can see, C
revision here is remote only - it exists on git-server and on the Bob's laptop, because he pushed it to the remote master
. It means that there is no such local ref C
on the Mike's laptop.
Question 1: how can Mike set remote master
back to C
?
Mike has tried to solve that problem with push --force
again like the answer for similar question offers, but it doesn't work because there is no suck local ref:
mike@laptop $> git push --force origin C:master
error: src refspec C does not match any.
error: failed to push some refs to '[email protected]:path/to/project.git'
Question 2: how can Mike fetch C
revision from the git server? And if he can't do that - why git designed like that? Is it about safety in some rare cases? What problems it exactly prevents?
Usually fetch
retrieves branches and tags only, but C
doesn't belong to any branch (which means that there is no any remote branch that C
is parent commit or HEAD
of).
PS: let's assume that Mike has no ssh access to git server, it means that there is no way to call git from the server side.
PPS: Mike doesn't want Bob to know about that accident, so answer "Make Bob to push this commit again" is not what this question is about.
Luckily there is this thing called the reflog which helps to keep references to orphaned commits alive (for a time) so that they can be recovered if needed. To view the reflog, just type git reflog . git reflog tracks where your HEAD has been.
An orphan branch is a separate branch that starts with a different root commit. So the first commit in this branch will be the root of this branch without having any history. It can be accomplished by using the Git checkout command with the ––orphan option.
To fully delete a commit, you need to delete all references to it, and then force an aggressive garbage-collection. If you still have branches pointing to the commit, delete those first. After this, git show [commit-hash] will no longer show the commit, so you will know it is really deleted. Save this answer.
If you are using GitHub, you can follow the steps in this post to create a branch on commit C
after it has been orphaned.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With