Originally published in adityasridhar.com
I am not able to commit to the remote repository, let me do a force push.
Let me Run Rebase on the remote repository, to make the commit history neater.
Let me amend my previous commit which is in the remote repository.
The points mentioned above are some of the things to avoid doing in Git.
In my previous posts I had covered about git basics and git amend and rebase. Click on the links to know more about them.
Git has amazing features and is very helpful for developers. But mistakes still happen while using git. Here I will be mentioning some of the things to avoid while using git and also explain why you should avoid them.
Force Push to Remote Repository
- Let's say 2 developers are working on a single branch.
- Developer 1 has finished the changes and pushed the code to the remote repository.
- Now Developer 2 has finished the changes, but is unable to push the code to the remote repository. Also Developer 2 is a beginner to Git.
- Developer 2 does a quick google search and finds out about force push command and uses it. The command is
git push -f
- Developer 1 checks the remote repository only to find out the code written by Developer 1 has completely disappeared.
This is because force push overrides the code in the remote repository and hence the existing code in remote repository gets lost.
The ideal way of handling the above scenario is Developer 2 needs to pull the latest code changes from the remote repository and rebase the code changes into the local repository. Once the rebase is done successfully, Developer 2 can push the code into Remote repository. Here we are talking about rebase from remote to local repo in the same branch.
Avoid force push unless absolutely necessary. Use it only as a last resort if there is no other way to handle a situation. But remember that force push will override the code in the remote repository.
In fact if you are using a User Interface like source tree, by default force push is disabled. You will have to manually enable it to use it.
Also if the right git workflows are used, each developer would be having their own feature branches, and such a scenario would not even occur.
Trying to Rebase the Remote repository
- Let's say 2 developers are working on a feature branch.
- Developer 1 has done a bunch of commits and pushed it to remote feature branch.
- Developer 2 takes the latest changes from the remote feature branch into the local feature branch.
- Developer 2 adds a bunch of commits to the local feature branch.
- But Developer 2 also wants to ensure that the latest changes from the release branch is rebased into the feature repository. So Developer 2 rebases the release branch onto the local feature branch. This is the rebase done from remote to local repo of different branches.
- Now Developer 2 tries to push the code to the remote feature branch. Git won't allow you since the commit history has changed. So Developer 2 would do a force push.
- Now when Developer 1 wants to pull the latest code from remote feature branch, it is a tough job since the commit history has changed. So Developer 1 will need to take care of a lot of code conflicts ( Even a few redundant code conflicts which were already taken care by developer 2)
Rebasing the remote repository will alter the commit history and will create issues when other developers try to pull the latest code from the remote repository.
The ideal way of handling this situation is to always rebase only the local repository. None of the commits in the local repo should have already been pushed to the remote repo.
If any of the commits have already been pushed to the remote feature branch, then its better to do a merge with the release branch rather than a rebase since merge would not alter the commit history.
Also if right git workflows are used, only one person would work on one feature branch and this issue would not even occur.
If only one person works on the feature branch and a rebase is done on the remote feature branch then there is no issue, since no other developers are pulling code from the same remote feature branch. But it is best to avoid rebasing a remote repository.
Rebase is a very powerful feature, but use it carefully.
Amending commits in the remote repository
- Let's say 2 developers are working on a feature branch.
- Developer 1 has done a commit and pushed it to remote feature branch. Let's call this as "commit old".
- Developer 2 pulls the latest code from the remote feature branch into the local feature branch
- Developer 2 is working on the code in the local repository and has not pushed any code to the remote repository yet.
- Developer 1 realises there was a mistake in the commit, and amends the commit in the local repo. Let's call this as "commit new".
- Developer 1 tries to push the amended commit to the remote feature branch. But git would not allow this since there is a change in commit history. So Developer 1 does a force push
- Now when Developer 2 wants to pull the latest code from the remote feature branch, git will notice the difference in commit histories and create a merge commit. Now when Developer 2 goes over the commit history in the local repo, Developer 2 will notice both "commit old" and "commit new". This destroys the whole point of amending a commit.
- Even if Developer 2 does a rebase from remote branch to the local branch, "old commit" will still be present in Developer 2's local. So it will still be a part of the commit history.
Amending a commit changes the commit history. So amending a commit in the remote repository will create confusion when other developers try to pull the latest code from the remote repository.
Best practise is to amend commits only in the local repository. Once the commit is there in the remote repository, it is better not to do any amends.
Also if right git workflows are used, only one person would work on one feature branch and this issue would not even occur. In this case amending a remote repository would not create any issues since no other developers are pulling code from the same remote feature branch.
Hard reset
- Hard reset is done by using
git reset --hard
- There are other types of reset as well like
--soft
and--mixed
which are not as dangerous as hard reset - Let's say developer 1 is working on a feature branch and has done 5 commits in the local repo.
- Also developer 1 is currently working on 2 files which are not yet commited.
- If developer 1 runs
git reset --hard <commit4hash>
the following things will happen. - The latest commit in feature branch will now be commit4 and commit5 is lost.
- The 2 uncommited files which developer 1 was working on is also lost
Commit 5 is still there internally in git but the reference to it is lost. We can get the commit5 back using git reflog
. But that being said it is still very risky to use hard reset.
Be very careful when you are using reset commands in git. You may have to use reset in some scenarios but evaluate the situation completely before going ahead with hard reset
How to know what are the bad practises while using git?
The list I have mentioned above does not cover everything. It just lists out some of the things that can go wrong while using git.
So how do you know in general what to be careful with while using git?
- One common thing you would have observed in the above list is that, issues occur when multiple people work on the same branch. So using the right git workflows would ensure only one person works on one feature branch at at time. The release branch would be handled by the tech lead or a senior developer. This workflow can prevent some major issues from happening.
- One other common thing you would observe is the use of force push everywhere. Git by default ensures that you cannot do any destructive change in the remote repository. But force push overrides the default behaviour of git.
- So whenever you are in a position where you have to use force push, use it only as a last resort. Also evaluate if there is any other way of achieving what you want without using force push.
- Any operation which alters the commit history in the remote repository can be dangerous. Alter the commit history only in your local repository. But even in the local repository be careful while using hard reset.
- Using git workflows maybe an overkill in very tiny projects. So in these projects multiple developers will work on the same branch. But before doing any major change in the remote repository, it is better to evaluate once if this will impact the other developers.
The points mentioned above are mainly for projects with multiple developers. If you are using git as a backup for your hobby project then there should be no issues.
Things like force push and hard reset are features of git. They are very useful in some scenarios. But it is better to evaluate before using them
Top comments (9)
Thanks for the great article. I'm still learning all this so why rebase and not simply pull in this case?
Good question. You can pull as well. But when you run git pull, it automatically does a merge. And whenever git merge happens, a merge commit is created. A merge commit is not a bad thing, but too many merge commits can make your local commit history look confusing. So that's why rebase is preferred for local repository, since rebase does not create an extra merge commit.
You can checkout my article on rebase to understand this further :)
adityasridhar.com/posts/how-to-bec...
Thanks. So if I understood correctly you advise to rebase from release->feature branch but not the other way around? Makes sense!
Yes. The basic ground rule is, if your branch has any commit which is there in the remote repository, it is better to avoid rebase since rebase alters commit history. It's fine if one developer is working. But if multiple developers are working then it becomes an issue
Nice article!
Another wrong way with Git is changing time on your development environment, trying to simulate with another project and forgot to return it. So, the commit was made 2 weeks ahead...on master. That was a bad day.
Remember kids, check your server time before to make a commit and push if you're playing with it.
Thanks. Yes, changing the time in your dev environment can create issues :D.
I use hard reset as my last resort.
I have mixed feelings about distinguishing by remote or local. As you point out each time the actual issue is shared vs unshared. I can see how this gives a good goto principle for Git beginners, but you learn through mistakes.
Also, if you do get into a rebase for a shared branch, you can reach for cherry-pick or rebase interactive to take just the needed changes.