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 (:roll_eyes:) 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:

  1. Undo the last commit
  2. Use stash option to save my changes
  3. Update the branch with my colleagues changes by using rebase
  4. Use stash pop to apply my changes on the top of the updated branch
  5. Resolve conflicts
  6. Commit the final changes after resolving conflicts
  7. 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 :smiley:

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 :smiley: