Git Advanced - Rebase, Cherry-pick, Conflict Resolution

GOUROB DASGOUROB DAS
16 min read

Table of contents

Learning points:

  1. Git Rebase โ€“ Deep Dive

  2. Git Cherry-pick โ€“ Applying specific commits from one branch to another.

  3. Resolving Merge Conflicts โ€“ Identifying and resolving conflicts efficiently.

  4. Rewriting History โ€“ advanced use cases

  5. Amending Commits โ€“ How to modify the last commit without changing history and real-life use cases.

  6. Git Hooks โ€“ Automating tasks with pre-commit and post-commit hooks.

๐Ÿ“‹ Initial Tasks:

โœ… Task 1: Set up a Git repository or use an existing one for practicing advanced Git commands.

We will use your existing 60DaysDevOps-Challenges repository and create a subfolder git-advanced-practice.

Step 1.1: Navigate to the Repo

cd 60DaysDevOps-Challenges

Step 1.2: Create the Subfolder

mkdir git-advanced-practice
cd git-advanced-practice

โœ… Note: This is just a normal folder, NOT a submodule or symlink, so it will be visible on GitHub.

โœ… Task 2: Create a new branch (git checkout -b advanced-git-practice) and make multiple commits.

Step 2.1: Create the Branch

git checkout -b advanced-git-practice

Step 2.2: Add Some Files & Make Commits

echo "Git Rebase Notes" > rebase.txt
echo "Git Cherry-pick Notes" > cherry-pick.txt
git add .
git commit -m "Add rebase and cherry-pick notes"

echo "Git Hooks Notes" > hooks.txt
git add .
git commit -m "Add git hooks notes"

โœ… Task 3: Push your branch to a remote repository (git push origin advanced-git-practice).

Step 3.1: Set Up GitHub Authentication

Since you want to use your GitHub Token, configure it securely:

git remote set-url origin https://<your-username>:use your github accesstoken/<your-username>/60DaysDevOps-Challenges.git

Step 3.2: Push the Branch

git push origin advanced-git-practice

โœ… Task 4: Simulate a collaborative workflow: Create a second branch (feature-x), make commits, and merge it into the main branch.

Step 4.1: Create a New Branch for Feature-X

git checkout -b feature-x

Step 4.2: Make Some Changes and Commit

echo "Feature X development" > feature-x.txt
git add feature-x.txt
git commit -m "Add feature-x implementation"

Step 4.3: Switch to Main and Merge Feature-X

git checkout main
git merge feature-x

Step 4.4: Push the Changes

git push origin main

โœ… Task 5: Create an intentional merge conflict between two branches and attempt to resolve it.

Step 5.1: Create a Conflict

  1. Edit rebase.txt in advanced-git-practice branch:
echo "Git Rebase Explained - Version A" > rebase.txt
git add .
git commit -m "Modify rebase.txt in advanced-git-practice"
  1. Switch to feature-x and modify the same file:
git checkout feature-x
echo "Git Rebase Explained - Version B" > rebase.txt
git add .
git commit -m "Modify rebase.txt in feature-x"
  1. Merge the branch and trigger a conflict:
git checkout advanced-git-practice
git merge feature-x

Step 5.2: Resolve the Conflict

  • Open rebase.txt and manually resolve the conflict

  • Stage and commit:

git add rebase.txt
git commit -m "Resolve merge conflict in rebase.txt"

โœ… Task 6: Use git log --oneline --graph --all to visualize the commit history and branch structure.

git log --oneline --graph --all

โœ… This will show a graphical representation of your commits and branches.

โœ… OutPut


๐Ÿ”ฅ Challenges

๐Ÿ”นChallenge 1: Perform an interactive rebase to modify commit history (rename, squash, reorder commits).
๐Ÿ”น Challenge 2: Use git cherry-pick to apply a specific commit from another branch to your current branch.
๐Ÿ”น Challenge 3: Create a merge conflict scenario and manually resolve it using git merge and git rebase.
๐Ÿ”น Challenge 4: Undo a commit using git reset (soft, mixed, and hard) and git revert โ€“ understand the differences.
๐Ÿ”น Challenge 5: Amend the last commit message and add a forgotten file to the last commit using git commit --amend.
๐Ÿ”น Challenge 6: Set up Git hooks (pre-commit or post-commit) to automate a simple check before committing changes.
๐Ÿ”น Challenge 7: Rebase a feature branch on top of the main branch without creating unnecessary merge commits.
๐Ÿ”น Challenge 8: Create a branch, make multiple commits, then squash them into a single commit using git rebase -i.


โœ… Solutions

โœ… Challenge 1: Perform an interactive rebase to modify commit history (rename, squash, reorder commits).

Step 1: View Commit History

Before rebasing, check your recent commits:

git log --oneline --graph --all

You'll see something like:

abc1234 (HEAD -> advanced-git-practice) Add git hooks notes
def5678 Add rebase and cherry-pick notes
ghi9012 Initial commit in git-advanced-practice

โœ… OutPut

Step 2: Start an Interactive Rebase

To modify the last 3 commits, run:

git rebase -i HEAD~3

This opens an editor with commit history:

pick a1b2c3d Added new feature
pick e4f5g6h Fixed API issue 
pick i7j8k9l Updated documentation

Step 3: Modify Commits

1๏ธโƒฃ Rename a Commit Message

  • Change pick to reword for the commit you want to rename

reword a1b2c3d Added new feature

pick e4f5g6h Fixed API issue

pick i7j8k9l Updated documentation

  • Save and close the editor.

  • Git will prompt you to edit the commit message.

2๏ธโƒฃ Squash Commits (Combine Multiple Commits)

If you want to merge multiple commits into one, change:

pick a1b2c3d Added new feature
pick e4f5g6h Fixed API issue
squash i7j8k9l Updated documentation
  • Save and close the editor.

  • Git will show a new editor where you can combine commit messages.

3๏ธโƒฃ Reorder Commits

To reorder commits, simply change their order:

pick e4f5g6h Fixed API issue
pick i7j8k9l Updated documentation
pick a1b2c3d Added new feature
  • Save and close the editor.

  • Git will replay commits in the new order.

Step 4: Continue and Push Changes

After making changes:

git rebase --continue

If you've already pushed the commits, force push is required:

git push origin feature-branch --force

๐Ÿšจ Use caution when force-pushing, especially in shared branches.

โœ… OutPut

๐Ÿ›  Explanation of the Commands

CommandPurpose
git log --oneline --graph --allShows commit history in a compact format
git rebase -i HEAD~NStarts an interactive rebase for the last N commits
rewordEdits a commit message
squash (or s)Merges a commit into the previous one
git push --forceUpdates remote history after rewriting commits

โœ… You have successfully modified commit history! ๐Ÿš€


โœ… Challenge 2: Use git cherry-pick to apply a specific commit from another branch to your current branch.

Step 1: List Commits from Another Branch

Switch to the branch where you want to pick a commit from (e.g., feature-x)

git checkout feature-x

List commits in short format:

git log --oneline

Example output:

f1e2d3c Added new feature for user authentication
a4b5c6d Fixed bug in login form
d7e8f9a Updated README with API details

Choose the commit you want to cherry-pick (e.g., a4b5c6d).

โœ… OutPut

Step 2: Switch Back to the Target Branch

Switch to the branch where you want to apply the commit (e.g., advanced-git-practice):

git checkout advanced-git-practice

Step 3: Cherry-Pick the Commit

Apply the commit from feature-x:

git cherry-pick a6dc3dd

โœ… Expected Output

Step 4: Handle Cherry-Pick Conflicts (If Needed)

If there's a conflict:

  1. Resolve the conflict manually in the affected files.

  2. Mark the conflict as resolved:
    git add <resolved-file>

  3. Continue cherry-picking:
    git cherry-pick --continue

To abort the cherry-pick and restore the previous state

git cherry-pick --abort

Step 5: Push the Changes

git push origin main

โœ… Expected Output

๐Ÿ›  Explanation of the Commands

CommandPurpose
git log --onelineLists commit history in a compact format
git checkout <branch>Switches to the specified branch
git cherry-pick <commit-hash>Applies a specific commit to the current branch
git push origin <branch>Pushes the changes to the remote repository

โœ… Challenge 3: Create a merge conflict scenario and manually resolve it using git merge and git rebase.

Step 1: Create a New Branch and Make Changes

Switch to your working branch (advanced-git-practice)

git checkout advanced-git-practice

Create a new branch (conflict-branch):

git checkout -b conflict-branch

Modify a file (e.g., example.txt):

echo "This line is from conflict-branch" > example.txt

Commit the changes:

git add example.txt
git commit -m "Update example.txt from conflict-branch"

Push the branch to GitHub:

git push origin conflict-branch

โœ… OutPut

Step 2: Modify the Same File in Another Branch

Switch back to advanced-git-practice:

git checkout advanced-git-practice

Modify the same file (example.txt), but with a different change:

echo "This line is from advanced-git-practice" > example.txt

Push the changes:

git push origin advanced-git-practice

โœ… OutPut

Step 3: Merge conflict-branch into advanced-git-practice

Now, try to merge conflict-branch into advanced-git-practice:

git merge conflict-branch

Since both branches modified example.txt differently, Git will detect a conflict.

โœ… You will see output like this:

Step 4: Resolve the Conflict Manually

Open example.txt in a text editor:

nano example.txt

โœ…You will see something like this:

Edit the file to keep the correct version (or merge both lines):

This line is from both branches - merging conflict manually

โœ…You will see something like this:

Save the file and mark it as resolved:

git add example.txt
git commit -m "Resolved merge conflict in example.txt"

Push the resolved changes:

git push origin advanced-git-practice

โœ… OutPut

Step 5: Recreate the Conflict Using Rebase

Now, let's try resolving the same conflict using git rebase.

  1. First, reset advanced-git-practice to before the merge:
git reset --hard HEAD~1
  1. Rebase conflict-branch on top of advanced-git-practice:
git rebase conflict-branch

Git will stop and show a conflict message.

  1. Open example.txt, manually resolve the conflict as before, and save the file.

  2. Continue the rebase process:

git add example.txt
git rebase --continue
  1. Push the rebased changes:
git push origin advanced-git-practice --force

โœ… OutPut

๐Ÿ›  Explanation of the Commands

CommandPurpose
git checkout -b <branch>Creates and switches to a new branch
echo "text" > file.txtModifies the file
git merge <branch>Merges changes from another branch
git rebase <branch>Applies commits from another branch on top of the current branch
git add <file>Marks a file as resolved
git commit -m "message"Saves the changes
git rebase --continueContinues rebase after resolving conflicts
git push origin <branch> --forceForces push after rebase

โœ… Merge conflict created and resolved using both merge and rebase! ๐Ÿš€


โœ… Challenge 4: Undo a commit using git reset (soft, mixed, and hard) and git revert โ€“ understand the differences.

Step 1: Create Sample Commits

If you donโ€™t have recent commits to test, create some:

echo "First commit" > file1.txt
git add file1.txt
git commit -m "First commit"

echo "Second commit" > file2.txt
git add file2.txt
git commit -m "Second commit"

echo "Third commit" > file3.txt
git add file3.txt
git commit -m "Third commit"

Now, you have 3 commits in your history.

โœ… OutPut

Step 2: View Commit History

Check your last few commits:

git log --oneline --graph --all

โœ… OutPut

Step 3: Undo a Commit Using git reset

  1. Soft Reset (Keeps changes in Staging Area)
git reset --soft HEAD~1

โœ… Effect:

  • Last commit is removed from history.

  • Changes remain staged, so you can re-commit if needed.

Check status:

git status
  1. Mixed Reset (Keeps changes in Working Directory, but Unstaged)
git reset --mixed HEAD~1

โœ… Effect:

  • Last commit is removed from history.

  • Changes move to working directory (unstaged).

Check status:

git status
  1. Hard Reset (Deletes Commit & Changes)
git reset --hard HEAD~1

โœ… Effect:

  • Last commit is deleted completely.

  • Changes are lost forever (Use this carefully!).

Check history again:

git log --oneline

โœ… OutPut

Step 4: Undo a Commit Using git revert

Unlike git reset, git revert creates a new commit that undoes the previous commit (useful in shared repositories).

Undo the Last Commit Using Revert

git revert HEAD

โœ… Effect:

  • Creates a new commit that cancels the last commit.

  • Safe for shared repositories (no history rewriting).

If you want to revert a specific commit (e.g., 4bb83le):

git revert 4bb83le

This will create a new commit that undoes the changes from 4bb83le.

โœ… OutPut

๐Ÿ›  Explanation of the Commands

CommandEffect
git reset --soft HEAD~1Removes commit but keeps changes staged
git reset --mixed HEAD~1Removes commit but keeps changes unstaged
git reset --hard HEAD~1Completely removes commit and changes
git revert HEADCreates a new commit that undoes the last commit
git revert <commit>Creates a new commit that undoes a specific commit

โœ… Challenge 5: Amend the last commit message and add a forgotten file to the last commit using git commit --amend.

/Sep 1: Check the Last Commit Message

Step 1: Check the Last Commit Message

git log --oneline -1

This will display something like:

772ad36 Revert "Update example.txt from advanced-git-practice"

Step 2: Modify the Last Commit Message

If you only want to change the commit message, run:

git commit --amend -m "Updated commit message"

Step 3: Add a Forgotten File to the Last Commit

  1. Create or modify the file:
echo "New content" > forgotten.txt

Stage the new file:

git add forgotten.txt

Amend the last commit to include this file:

git commit --amend --no-edit
  • --no-edit keeps the same commit message.

  • The commit is now updated to include forgotten.txt.

โœ… OutPut

Step 4: Push the Amended Commit

If you have already pushed the commit to GitHub, you need to force push:

git push origin main --force

โœ… OutPut


โœ… Challenge 6: Set up Git hooks (pre-commit or post-commit) to automate a simple check before committing changes.

We can set up Git hooks to automate checks before committing changes. Below is a step-by-step guide to creating a pre-commit hook that checks for trailing whitespace before allowing a commit.

Step 1: Navigate to the Hooks Directory

Each Git repository has a .git/hooks/ directory containing sample hooks. Move into your repository:

cd /path/to/your-repo

cd .git/hooks

Step 2: Create a Pre-Commit Hook

Create a new pre-commit script:

nano pre-commit
#Paste the following script:
#!/bin/bash



# Check for trailing whitespace

if git diff --cached --check | grep -q "trailing whitespace"; then

    echo "โŒ Commit rejected: Trailing whitespace found!"

    exit 1  # Prevent commit

fi



echo "โœ… Pre-commit check passed!"

exit 0  # Allow commit

โœ… OutPut

Explanation:

  • Uses git diff --cached --check to find trailing whitespace.

  • If found, aborts the commit (exit 1).

  • If no issues, commit proceeds (exit 0).

Step 3: Make the Hook Executable

chmod +x pre-commit

โœ… OutPut

Step 4: Test the Hook

  1. Make a change with trailing whitespace:
cd /path/to/your-repo
echo "Hello, world! this is my git advanced practice  " >> file.txt  # Extra spaces at the end
git add file.txt
git commit -m "Test commit"
  1. If thereโ€™s trailing whitespace, the commit will be rejected:

โŒ Commit rejected: Trailing whitespace found!

  1. Fix the issue by removing trailing spaces, then commit again.

โœ… OutPut

Step 5: (Optional) Create a Post-Commit Hook

If you want to log commit details after every commit, create a post-commit hook:

nano post-commit

Paste this inside:

echo "๐ŸŽ‰ Commit successful! Keep up the good work! $(git rev-parse HEAD)"

Make it executable:

chmod +x post-commit

โœ… OutPut

Now, every time you commit, it will log:

โœ… Commit successful! Commit Hash: a1b2c3d

Bonus: Share Hooks Across Team

To share hooks across a team:

  1. Move them to a version-controlled directory:
    mkdir -p .githooks

    mv .git/hooks/pre-commit .githooks/

  2. Configure Git to use this directory:
    git config core.hooksPath .githooks


โœ… Challenge 7: Rebase a feature branch on top of the main branch without creating unnecessary merge commits

When working with feature branches, it's best to rebase instead of merging to keep your commit history clean. This will move your feature branch to the latest main branch without unnecessary merge commits.

Step 1: Switch to the Feature Branch

git checkout feature-branch

Step 2: Fetch the Latest Changes from the Remote Repository

git fetch origin

git checkout main

git pull origin main

Now, your main branch is up-to-date.

โœ… OutPut

Step 3: Rebase feature-branch on main

git checkout feature-branch

git rebase main
  • This moves all commits from feature-branch to start from the latest main commit.

  • It avoids unnecessary merge commits and keeps a clean history.

Step 4: Handle Conflicts (If Any)

If there are conflicts, Git will pause the rebase and show:

CONFLICT (content): Merge conflict in file.txt
  1. Manually resolve conflicts in the affected files.

  2. Mark conflicts as resolved:
    git add <resolved-file>

  3. Continue the rebase:
    git rebase --continue

  4. If needed, abort the rebase:
    git rebase --abort

Step 5: Push the Rebasing Changes

If the feature branch is already pushed to GitHub, you need to force push:

git push origin feature-branch --force

๐Ÿšจ Caution: This rewrites history. Be careful when working in a shared branch.

Example Scenario

Before Rebase (git log --oneline --graph)

* commit C (feature-branch)

* commit B (feature-branch)

| * commit M2 (main)

| * commit M1 (main)

|/

* commit A (common ancestor)

After Rebase

* commit C' (feature-branch, rebased)

* commit B' (feature-branch, rebased)

* commit M2 (main)

* commit M1 (main)

* commit A (common ancestor)

No extra merge commits. A cleaner history!

โœ… OutPut


โœ… Challenge 8: Create a branch, make multiple commits, then squash them into a single commit using git rebase -i.

We can create a branch, make multiple commits, and squash them into a single commit using git rebase -i by following these steps.

Step 1: Create a New Branch

git checkout -b feature-branch

Step 2: Make Multiple Commits

echo "First change" > file.txt

git add file.txt

git commit -m "First commit"



echo "Second change" >> file.txt

git commit -am "Second commit"



echo "Third change" >> file.txt

git commit -am "Third commit"

Now, we have three separate commits.

Check commit history:

git log --oneline -n 3

Example output:

Step 3: Start an Interactive Rebase

To squash the last 3 commits into one, run:

git rebase -i HEAD~3

Step 4: Modify the Rebase Commands

The editor will open with:

pick 67ac9ab Third commit

pick e770f3d Second commit

pick 735ee54 First commit

Change it to:

pick abc1234 Third commit

squash def5678 Second commit

squash ghi7890 First commit
  • pick โ†’ Keeps the first commit.

  • squash โ†’ Merges the next commits into the first one.

Save and close the editor.

Step 5: Edit the Commit Message

Git will prompt you to edit the commit message:

# This is a combination of 3 commits.

First commit

Second commit

Third commit

Edit this into a single meaningful commit message:

Combined all feature changes into one commit

Save and close the editor.

Step 6: Push the Squashed Commit

If you already pushed the previous commits, force push is needed:

git push origin feature-branch --force

๐Ÿšจ Caution: This rewrites history, so be careful in shared branches.

Step 7: Verify the Squash

Check commit history:

git log --oneline -n 3

#Expected output:

xyz5678 (HEAD -> feature-branch) Combined all feature changes into one commit

Now all three commits are now merged into a single commit.


Thanks for your time. I hope you enjoy my blog, please follow me on LinkedIn for more updates.

0
Subscribe to my newsletter

Read articles from GOUROB DAS directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

GOUROB DAS
GOUROB DAS

About "Hello! My name is Gourob Das, I completed my GSSOC as an open source Contributor, I completed a 4-month internship at Dpay Consultancy Services as an application developer, and completed my MCA Degree at Pondicherry University. I am highly passionate about DevOps dedicated to enhancing experiences through the power of artificial intelligence. Let's connect and collaborate on DevOps, cloud Computing development projects."Enjoy exploring the fascinating world of DevOps, constantly seeking to apply cutting-edge technology to solve real-world problems."