git push --force and how to deal with it — Martian Chronicles, Evil Martians’ te...
source link: https://evilmartians.com/chronicles/git-push---force-and-how-to-deal-with-it
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
git push --force and how to deal with it — Martian Chronicles, Evil Martians’ team blog
Have you ever found yourself in a situation where a wrong git command wreaked havoc on your project’s repo? People make mistakes, and sometimes those mistakes can cost hours of your team’s time. In this tutorial, we will show you how to recover from an unfortunate git push --force
quickly.
Let’s not get overly confident. Sooner or later, this is going to happen. While working with several remotes in the same git repository, you will eventually git push --force
into master
(or another important branch that should never be messed with).
That may happen, for instance, when deploying with Deis or Heroku that use separate git remotes to build and deploy an application. After a long day of work, it is incredibly easy to execute git push --force
instead of usual git push --force deis master
.
Oops! In the blink of an eye, your teammates have lost all their latest work. Time to face their rage.
However, as one excellent guide tells us, DON’T PANIC! The good thing is, you use git, and that means everything can be fixed.
Best case scenario: someone else who is working on the same code pulled a recent version of the
master
just before you broke it. Then all you have to do is to go into your team’s chat and ask that person to force push their recent changes.
If you are lucky, their local repository will have the full history of commits, your mistake will be overwritten with fresh code, and nothing will be lost. But what if you are not that lucky? Then, read on!
Case 1: You were the last person to push to master
before the mistake
Good news! You have everything you need to undo your mistake before your very eyes. Just do not close or clear your terminal. First, go into your team’s chat and confess your sins. Ask people not to mess with the repo for the next minute or so while you are fixing things.
In the output of git push --force
command in your shell look for a line that resembles this one:
+ deadbeef...f00f00ba master -> master (forced update)
The first group of symbols (which looks like a commit’s SHA prefix) is the key to the rescue. deadbeef
is your last good commit to the master
just before you inflicted damage.
So all you need is to… force push (fighting fire with fire!) this commit back to the master
branch, on top a bad one.
$ git push --force origin deadbeef:master
Congratulations! You have saved the day. Now it’s time to learn from your mistakes.
Case 2: master
was changed by someone else before you messed up
So, just before you did git push --force
someone had closed a bunch of pull requests, and the master
now looks nothing like your local copy. You can no longer do git push --force sha1:master
as you do not have recent commits locally (and you can’t get them with git fetch
because they do not belong to any branch anymore). Still, keep calm and ask your teammates to stay off the remote for a while.
We will benefit from the fact that GitHub does not remove unreachable commits immediately. Of course, you can not fetch them either, but there is a workaround.
Note that it will only work if you are “watching” the repository, so that everything happening in it appears in a feed displayed on your GitHub’s front page. Open that feed and look for something like this:
an hour ago
Username pushed to master at org/repo
- deadbeef Implement foo
- deadf00d Fix bar
Now you can:
- Compose a URL
https://github.com/org/repo/tree/deadbeef
, wheredeadbeef
is a hash of the last good commit to the damaged branch; - Open the branches/tags switcher in the GitHub’s web UI;
GitHub branch/tag switcher
- Create a name for a new temporary branch (e.g.,
master-before-force-push
); - Click “Create branch”.
Now you can fetch all missing commits:
$ git fetch
From github.com:org/repo
* [new branch] master-before-force-push -> origin/master-before-force-push
Your problem is now reduced to the one described in a previous example:
$ git push --force origin origin/master-before-force-push:master
If you still need your work to be in the master
, just rebase on top of it:
$ git rebase origin/master
How to avoid such disaster in the future
-
GitHub and GitLab have a feature called “protected branches.” Mark
master
,develop
,stable
, or any other crucial branches as protected and no one will be allowed to force push into them. It is always possible to temporarily “unprotect” a branch if you really need to overwrite history.Read the GitHub docs for details.
-
Instead of
--force
option, use--force-with-lease
. It will halt the push operation if someone has pushed to the same branch while you were working on it (and haven’t pulled any changes).See this article from Atlassian.
-
Create aliases for commands that use
git push --force
to prevent destructive actions by accident:# ~/.gitconfig [alias] deploy = "!git push --force deis \"$(git rev-parse --abbrev-ref HEAD):master\""
Read the ProGit chapter about aliases.
-
Never do your experiments in the main branch of a repository!
git checkout -b experiments
is your best friend.
Pro Tip: git push
has many options. --force
and --all
work together especially well. You can use this combo when returning to the project after several months of inactivity. Give it a try if you’re feeling extra adventurous!
Recommend
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK