Skip to content

Git Rebasing

Git rebasing is one of the many workflows within Git. One of the behaviors of rebasing is to put your commits on top (meaning, as the most recent changes). Let's understand the most common use cases for Git Rebasing.

Use Cases

  • Updating Your Feature Branch: If the main branch has been updated since you created your feature branch rebasing puts your commits top of the main branch, to keep it up-to-date.
  • Resolving Merge Conflicts: When you encounter merge conflicts during a rebase, you can resolve them on a per-commit basis, ensuring that each commit is conflict-free.
  • Merging Long-Running Feature Branches: If a feature branch has been in development for a while and has accumulated many commits, rebasing it on the main branch can create a cleaner merge.
  • Cleaning Up Commit History: If your branch has many small, intermediate commits that are not relevant to the main branch's history, you can use rebase to squash or combine them into fewer meaningful commits.

Info

$githandle-feature-branch should be your github handle such as itdepends-feature-branch.

Rebase Without Conflicts

Step 1. Setup the environment

git checkout develop
git pull origin develop
git checkout -b $githandle-feature-branch
git reset HEAD~5 --hard
git push origin $githandle-feature-branch

What this does is ensure that develop is up to date, create a branch from that point, reset the branch back 5 commits so there is a divergence in it, and push that up to origin

Step 2. Make updates to the branch and push

touch README.md
echo "add to file" >> README.md
git add README.md
git commit -m 'update readme'
git push origin $githandle-feature-branch

Step 3. Rebase the Feature Branch

git rebase develop

If there are no conflicts, you'll see a message that the rebase is complete. If there are conflicts, Git will pause the rebase and let you know which files have conflicts. For now, we will presume there is no issue.

Step 4. Push the Updated Feature Branch:

git push origin $githandle-feature-branch

Note: By re-writing your git history, this is a deviation from the remote version history, and will require a "force push", see the next step for details.

Step 5. Handle Push Rejections:

If your pushed branch was rejected because it's now different from the remote, you'll need to force-push your changes.

git push --force origin $githandle-feature-branch

Use extreme caution when force pushing, in general you should

  • Push to your fork
  • Use on feature branches.
  • Never force push to develop or main
  • Have branch protection on your remote Git Service
  • Always communicate before if you must break any of these guidelines

Rebase Without Conflicts

We can pick up from the above steps, and create a merge conflict. The below steps will create an issue between the README.md updated in previous steps and now.

git checkout develop
touch README.md
echo "add to file on develop" >> README.md
git add README.md
git commit -m 'update readme'

Now we can rebase.

git checkout $githandle-feature-branch
git rebase develop

Resolve Conflicts:

Git will pause the rebase and indicate the files with conflicts. Open each conflicted file, resolve the conflicts, and save the changes.

Understanding Git Conflict Syntax

When Git cannot automatically merge changes from different branches, which typically occurs when changes have been made to the same lines of code in both branches. Git marks these conflicts in your code with special syntax, allowing you to manually resolve the differences.

A typical Git conflict looks like this:

Copy code
<<<<<<< HEAD
// Your changes from the current branch
=======
// Changes from the incoming branch
>>>>>>> incoming-branch
Here's how to read this syntax:

<<<<<<< HEAD: This marks the beginning of your changes, as they exist in your current branch (the one you're currently on).

=======: This line separates your changes from the changes in the incoming branch.

>>>>>>> incoming-branch: This marks the end of your changes and the beginning of the changes from the incoming branch (the one you're merging or pulling from).

To resolve the conflict, you need to decide which changes to keep and how to combine them. You can edit the conflicting lines directly in your code. After resolving the conflict, you remove the conflict markers and retain only the desired changes.

Here's an example of a resolved conflict:

// Your changes from the current branch
// Additional changes from the incoming branch

After resolving conflicts, make sure to stage and commit your changes to finalize the merge.

Tips for Resolving Conflicts:

  • Read Carefully: Understand the context of the conflicting changes before making decisions.
  • Use Visual Tools: Some IDEs (such as VS Code) and text editors offer visual tools to resolve conflicts, making the process easier.
  • Review: Once conflicts are resolved, review in editor or a Git Tool, such as GitHub enterprise.

Remember, conflict resolution is a critical part of collaborating with others using Git. Clear communication and collaboration among team members are key to successfully resolving conflicts and maintaining a clean and functional codebase.

Stage and Continue the Rebase

After resolving conflicts, stage the changes using git add for each resolved file. Then, continue the rebase:

git rebase --continue
Push the Updated Feature Branch:
git push origin $githandle-feature-branch

Challenge lab

  • No Conflict Rebase
    • Pull from develop
    • Reset the branch 5 commits
    • Create a new branch from there
    • Add a commit
    • Perform Rebase
    • Force Push
  • Merge Conflict Rebase
    • Pull from develop
    • Reset the branch 5 commits
    • Create a new branch from there
    • Adjust the same line that was adjusted in those 5 commits
    • Add a commit
    • Perform Rebase
    • Work through merge conflict
    • Force Push