Falling foul of “- -force push” in git

Learning to use git in a team

If you are new to git and github it can be quite confusing how you are supposed to use it in a team. There are some tricky concepts like pull requests, local repos vs remote repos, squashing, merging, and rebasing.

When I started learning git I understood that I needed to create my own local “feature” branch off the main branch, and then use this feature branch to commit my changes. Once I was happy with my work I’d push my changes up to the remote copy of my feature branch.

On completing my task I would navigate to the github.com web GUI and create a pull request (PR) comparing main -> feature/jira-123-emm . After that PR was approved I’d press the magic “Squash + Merge” button that would merge my changes into the main branch.

It was all going well but what I kept finding is that the other team members who were more experienced and quicker than me would jump in with their own PRs; merging them into main faster than I could do my edits. At first the pace made it feel like the floor was moving under me and I couldn’t keep track of what was changing.

Rebase to the rescue?

This is when I discovered the wonders of git “rebase” which seemed like an elegant solution. Rebase grabs all the commits you’ve made since you branched from main, then moves them along as a bunch so that they branch off the latest commit to main instead. It is possible that one of the interim commits might have edited the same files that you’ve edited, so rebase walks sequentially through each interim commit and stops to prompt you to resolve a “conflict” in files if this has happened.

Why I initially liked rebase is because it made conceptual sense to me, and the prompts from the git bash sort of guided me through step by step. Each time I came across a conflict I would pause to resolve it and then do a git – -add ./path/to/file and move on.

Rebase

https://www.atlassian.com/git/tutorials/rewriting-history/git-rebase

As soon as I had completed a rebase, I would then push to my remote branch and make my pull request as a dutifully up-to-date branch holder.

The difficulties with rebase and the danger of force

There was just one issue. Sometimes I would get a message saying that the remote branch “rejected” my changes. After some googling I found that one solution was simply to do “git push – -force” and this would force the remote branch to take my rebased version of the code.

Here’s the thing I didn’t realise though, I assumed that “git push – -force” did a forced overwrite of my remote branch (which was unique to me and nobody else would be contributing to). But actually what it does is it pushes my entire local repo, and overwrites all branches with whatever state they are at in my local repo. This is quite a different thing.

So my workflow was:

git checkout main
git pull
git checkout feature/jira-123-emm
git rebase main
#follow the rebase workflow
git push --force

And this would overwrite all the remote branches with the state of my local repo.

Ninety percent of the time you would get away with this workflow because most people only really care about the state of remote main (as feature branches are worked on locally). But if someone completes a PR and merges it into main in between you doing your git pull and git push –force, then their changes to main are getting erased. And if they’ve deleted their feature branch (which is the usual workflow) then “oops” they’re feature is gone. So this is what happened to me, or rather what happened to my team mate because of me.

A better way to update your branch

A better workflow for using git in a team is to merge the origin branch into your own local feature branch, and resolve conflicts in your local repo before pushing. This is the workflow I now use:

On your own feature branch:

git fetch
git merge origin/main

Also this is why you shouldn’t listen to Star Wars, don’t use the –force.

A good resource on git force push: https://www.git-tower.com/learn/git/faq/git-force-push