Git - Pull, Merge and Rebase

Git Pull

git pull is an alias for git fetch && git merge

What if you want to use rebase instead of merge with git pull? git pull --rebase

How to pull the latest changes into your branch without creating an extra merge commit? Run this command multiple times a day when working to avoid merge conficts. If there is a merge conflict when you run this, drop the --ff-only flag to deal with the conflict asap. This avoids merge conflicts later.

To pull from main

git pull origin main --ff-only

To pull from develop

git pull origin develop --ff-only

You can also configure git to only allow fast forwards on pulls without having to set it everytime:

git config --global pull.rebase true

https://spin.atomicobject.com/2020/05/05/git-configurations-default/

Unrelated histories

The refusing to merge unrelated histories error happens when you attempt to merge branches or repositories that Git perceives as having no common commit history.

To resolve the refusing to merge unrelated histories error, you need to instruct Git to allow merging of unrelated histories. This can be done using the --allow-unrelated-histories flag.

git pull origin main --allow-unrelated-histories

git merge origin/main --allow-unrelated-histories

Merging

Merge from a remote branch into a current branch

Checkout a different branch and Merge from another remote branch into that branch

Allows developers to merge Git branches while the logs of commits on branches remain intact.

Rebasing

Move work from the feature branch onto the main branch

It will result in this:

Lets users integrate changes from one branch to another. Once the action is complete, the logs are modified. Git rebase was developed to overcome merging’s shortcomings, specifically regarding logs.

Git merge, on the other hand, only changes the target branch and creates a commit, preserving the history of the source branch.

When pulling changes, should I merge or should I rebase?

TLDR: You don’t need to preserve a linear commit history. That is not necessary. Other developers on the team will be pissed if their changes or the commit history about their changes is messed with. What is the point of maintaining a linear commit history? To me, that seems totally un-necessary. Just use merge while pulling changes down until a more customized approach is necessary - especially when you have changes in local branch. If the local branch is clean, then there is no difference between merge and rebase when pulling changes down.

In most situations, you should rebase instead of merging down if you want a clean, linear commit history, especially when working on a feature branch that is not shared with other developers; however, if you need to preserve the exact chronological order of commits or are collaborating with others on a branch, then merging is the better choice as it avoids rewriting history.

Merge is best used when the target branch is supposed to be shared. Rebase is best used when the target branch is private. Merge preserves history. Rebase rewrites history.

Git rebase compresses all the changes into a single patch and integrates this new patch onto the target branch. Then, it moves the completed work from one branch to another, typically the master branch. In the process, rebase flattens the history, removing unwanted entries.

Resolving merge conflicts after a Git rebase

When you perform a git rebase operation, you’re typically moving commits around. Because of this, you might get into a situation where a merge conflict is introduced. That means that two of your commits modified the same line in the same file, and Git doesn’t know which change to apply.

After you reorder and manipulate commits using git rebase, should a merge conflict occur, Git will tell you so with the following message printed to the terminal:

error: could not apply fa39187... something to add to patch A

When you have resolved this problem, run git rebase --continue If you prefer to skip this patch, run git rebase --skip instead. To check out the original branch and stop rebasing, run git rebase --abort

Could not apply fa39187f3c3dfd2ab5faa38ac01cf3de7ce2e841... Change fake file

Here, Git is telling you which commit is causing the conflict (fa39187). You’re given three choices:

  1. You can run git rebase --abort to completely undo the rebase. Git will return you to your branch’s state as it was before git rebase was called.
  2. You can run git rebase --skip to completely skip the commit. That means that none of the changes introduced by the problematic commit will be included. It is very rare that you would choose this option.
  3. You can fix the conflict.

To fix the conflict, you can follow the standard procedures for resolving merge conflicts from the command line. When you’re finished, you’ll need to call git rebase --continue in order for Git to continue processing the rest of the rebase.

https://docs.github.com/en/github/getting-started-with-github/resolving-merge-conflicts-after-a-git-rebase

Git Interactive Rebase

Git cherry-pick is great when you know which commits you want (and you know their corresponding hashes) – it’s hard to beat the simplicity that cherry-pick provides.

But what about the situation where you don’t know what commits you want to pick? Thankfully, Git has you covered there as well! We can use interactive rebasing for this – it’s the best way to review a series of commits you’re about to rebase.

All interactive rebase means Git is using the rebase command with the -i option.

If you include this option, git will open up a UI to show you which commits are about to be copied below the target of the rebase. It also shows their commit hashes and messages, which is great for getting a bearing on what’s what.

When the interactive rebase dialog opens, you have the ability to do many things:

  1. You can reorder commits simply by changing their order
  2. You can choose to keep all commits or drop specific ones.
  3. squashing (combining) commits
  4. amending commit messages
  5. editing the commits themselves

Here’s a development situation that often happens: I’m trying to track down a bug but it is quite elusive. In order to aid in my detective work, I put in a few debug commands and a few print statements.

All of these debugging / print statements are in their own commits. Finally I track down the bug, fix it, and rejoice!

Only problem is that I now need to get my bugFix back into the main branch. If I simply fast-forwarded main, then main would get all my debug statements which is undesirable. There has to be another way…

We need to tell git to copy only one of the commits over. We can use the same commands:

  1. git rebase -i
  2. git cherry-pick

Reading material

https://www.atlassian.com/git/tutorials/merging-vs-rebasing


Links to this note