Git's magic to resolve common issues with active repositories
A common problem that I run into when working on active repositories.
Whenever I start developing a new feature, I do a git fetch
and git rebase origin/main
to make my local main
upto date with the remote main
. Then I create a new branch using git checkout -b <NEW_BRANCH_NAME>
But when working on repositories with active development where multiple people simultaneously merge their changes to the main branch, it gets a bit messy as the main
in the remote gets ahead of the local main
and thus the current local branch I work on gets out of sync.
To demonstrate the issue better, let us pick an example repository. I have created a new repo in my GitHub upgraded-octo-waffle
I cloned the repository into my local machine using
$ git clone git@github.com:KrishnaRekapalli/upgraded-octo-waffle.git
If the repository is cloned into the local machine sometime ago and if the local main and the remote main branches are out of sync, we can use the following set of commands to check if the local branch needs to be updated and take necessary action i.e. rebase
$ git fetch # fetches the latest changes
$ git status # shows how far behind is the local branch from the remote
$ git rebase origin/main #updates the local branch with all the new changes
Once I have all the latest changes incorporated to my local main
branch, I set out to work on my new feature by creating a new branch.
$ git checkout -b KR-my-new-feature
Before changes:
New changes:
Now I commit my new changes to the local branch.
$ git add waffle.py
$ git commit -m "added new method"
Here comes the twist in the story. Now I just realise that a colleague has just merged her changes to the remote/main
and they also edited the same file waffle.py
. Now waffle.py
looks like:
Now I want to incorporate the new changes to my branch. What can I do?
I first try:
$ git fetch
$ git rebase origin/main
The response is:
The rebase operation fails () because there are changes to the same file and same locations and Git is not able to figure out a clean way to update waffle.py
with my colleague’s changes on my feature branch.
Then I abort the rebase operation by doing
$ git rebase --abort
One solution to this problem is:
- Undo the last commit
- Use
stash
option to save my changes - Update the branch with my colleagues changes by using
rebase
- Use
stash pop
to apply my changes on the top of the updated branch - Resolve conflicts
- Commit the final changes after resolving conflicts
- Push my changes to the remote and merge
We will go over this process step-by-step now
1. Undo last commit
To undo the last commit to my branch, I do
$ git reset --soft HEAD~1
The number 1
indicates that we want to go back one commit and by using the flag, soft
we are asking Git to not discard the changes we made.
2. Stash my changes
Now I stash my changes by doing
$ git stash
This step keeps my changes safe and now I can use rebase to update my branch.
3. Update the branch with latest changes
For this I do
$ git rebase origin/main
Rebase now works without any complaints
4. Apply my changes again using Stash pop
Now it is time to apply my changes to the feature branch I am working on using stash pop
.
$ git stash pop
Now waffle.py
will look like:
So Git is expecting us to resolve the conflicts manually as the changes happened at the same place. Although these are different methods, Git is not so smart to figure that out. So it is our job to resolve the conflicts i.e. keep the changes we want and discard the changes we don’t.
5. Resolve conflicts
As I want to keep both the methods, I just remove the <<<<<<
and =======
and >>>>>>>
symbols and commit all the changes to the current branch
6. Commit the overall changes
As all the issues are resolved I simply add
and commit
my changes.
$ git add waffle.py
$ git commit -m "That was close! All good now :sweat_smile:"
7. Push changes to remote and merge my changes
Now we need to push the local branch to remote so that it can be merged with the main
branch.
$ git push -u origin KR-my-new-feature
What this does is creates a new remote branch with the same name as the local one and pushes all the changes there.
The response of the command:
Now I can happily create a PR and merge my new feature with the main branch.
I can’t resist but end this post with one of xkcd comics on Git. This captures my emotions about git for most part. While it is a game changing tool that spearheaded collaborative development, it can take a bit of time to get a hang of the capabilities and for most part, one may end up using only 10-15% of the core features of Git and there is a lot I don’t understand and keep learning as I run into problems