DEV Community

Deepika Pusala
Deepika Pusala

Posted on

Deep Git Workflows: Rebasing, Conflict Resolution & Branching Strategies Explained from Zero 🌳

🌳 Deep Git Workflows: Let's Learn from ZERO!

Git is not just git add, git commit, and git push. πŸ˜„ When multiple developers work on the same project, you need to know:

  • πŸ”€ How to combine code from different branches
  • 🧹 How to keep a clean commit history
  • βš”οΈ How to fix conflicts when two developers change the same code
  • βͺ How to undo mistakes safely
  • 🏷️ How to manage versions and releases
  • 🏒 How professional teams organize their branches

We'll learn everything with simple real-world examples, commands, and practical scenarios. Let's go! πŸš€


1. 🧱 First, Git Basics

Imagine you're building an Instagram-like Social Feed app:

SocialFeed/
β”‚
β”œβ”€β”€ frontend/
β”‚   β”œβ”€β”€ App.tsx
β”‚   └── Feed.tsx
β”‚
β”œβ”€β”€ backend/
β”‚   β”œβ”€β”€ main.py
β”‚   └── auth.py
β”‚
└── README.md
Enter fullscreen mode Exit fullscreen mode

Git helps you track changes made to these files. Some important terms:

Term Simple meaning
πŸ“ Repository (repo) Your project tracked by Git
πŸ“Έ Commit A saved snapshot of your changes
🌿 Branch An independent line of development
πŸ”€ Merge Combining changes from branches
πŸ” Rebase Replaying commits on top of another branch
βš”οΈ Conflict Git cannot automatically combine some changes
πŸ‘‰ HEAD Pointer to your current commit
☁️ Remote A copy of your repo hosted elsewhere, like GitHub

🌿 What is a branch?

Your main app works perfectly, and you want to build a login feature without disturbing it. Instead of changing main directly, you create a separate branch:

git branch feature/login     # create the branch
git switch feature/login     # move to it
Enter fullscreen mode Exit fullscreen mode

Now you can work independently, and your main branch stays unaffected until you integrate your changes.

πŸ“Œ Important: Branches are lightweight pointers to commits. They don't usually create a complete separate copy of your project.


2. πŸ”€ Git Merge vs Git Rebase

🎯 Very important for interviews and real projects!

Both bring changes from one branch into another, but they work differently.

🎬 Scenario

Your team has a main branch. You create feature/login. Both initially point to commit C. Then:

  • You make commit D in feature/login
  • Another developer makes commit E in main
       D   (feature/login)
      /
A -- B -- C -- E   (main)
Enter fullscreen mode Exit fullscreen mode

You want the latest main changes in your feature branch. Two approaches:

πŸ…°οΈ Git Merge

Merge combines two branches while preserving their existing history.

git switch feature/login
git merge main
Enter fullscreen mode Exit fullscreen mode

What happens:

  1. Git checks the changes in your feature branch
  2. Git checks the changes in main
  3. Git combines them
  4. It creates a merge commit if a normal merge requires one
       D ---- M
      /      /
A -- B -- C -- E
Enter fullscreen mode Exit fullscreen mode
  • D = your login feature commit
  • E = another developer's main commit
  • M = the merge commit connecting both histories

πŸ“š Analogy: Two people write separate book chapters. You combine both chapters and preserve who wrote what and when.

βœ… Advantages

  • Preserves complete development history
  • Doesn't rewrite existing commits
  • Safe for branches shared with other developers
  • Shows when two lines of development were combined

❌ Disadvantages

  • Can create many merge commits
  • History can get complicated when many branches are merged often

πŸ…±οΈ Git Rebase

Rebase takes your commits and replays them on top of another branch's latest commit.

git switch feature/login
git rebase main
Enter fullscreen mode Exit fullscreen mode

What happens:

  1. Git identifies the commits unique to your feature branch
  2. It temporarily sets those commits aside
  3. It moves your feature branch to the latest main commit
  4. It replays your feature commits on top

Before rebase:

       D   (feature/login)
      /
A -- B -- C -- E   (main)
Enter fullscreen mode Exit fullscreen mode

After rebase:

A -- B -- C -- E -- D'   (feature/login)
Enter fullscreen mode Exit fullscreen mode

Notice D becomes D'. Git creates a new commit with the same changes but a different commit hash.

πŸ“š Analogy: You wrote your chapter based on an old draft. Your colleague updates the main book. Instead of attaching your old chapter on the side, you reapply it on top of the updated book.

βœ… Advantages

  • Cleaner, linear history
  • Avoids unnecessary merge commits
  • History is easier to read
  • Great before merging feature branches

❌ Disadvantages

  • Rewrites commit history
  • Can cause problems if others already use those commits
  • Conflicts may need resolving while replaying commits

βš–οΈ Merge vs Rebase: Comparison

Feature Merge Rebase
History Preserves history Rewrites commit history
Merge commit Often created Not created by rebase itself
Commit hashes Existing commits remain Replayed commits get new hashes
Shape Can be non-linear Usually linear
Shared branches Generally safe Risky if commits are shared
Main purpose Combine histories Reapply commits on a new base

🧠 Remember: Merge = preserve history. Rebase = cleaner, rewritten history.

Use merge when:

  • You're combining changes from shared branches
  • You want to preserve the complete history
  • Your team prefers explicit merge records

Use rebase when:

  • You're updating your own feature branch with the latest main
  • You want a clean commit history
  • Your commits haven't been shared with others

🚨 Golden rule: Never casually rebase commits that other developers have already based their work on.


3. 🧹 Interactive Rebase

Suppose you made these commits while building login:

1. Created login component
2. Fixed login button
3. Fixed login button again
4. Added validation
5. Small CSS correction
Enter fullscreen mode Exit fullscreen mode

Showing this to your mentor? Messy! 😬 You may want to combine, reorder, edit, or remove commits. That's interactive rebase: it lets you edit your commit history.

git rebase -i HEAD~5
Enter fullscreen mode Exit fullscreen mode
  • git rebase β†’ rebase operation
  • -i β†’ interactive mode
  • HEAD~5 β†’ the last 5 commits (including HEAD)

Git opens an editor with something like:

pick a123 Created login component
pick b234 Fixed login button
pick c345 Fixed login button again
pick d456 Added validation
pick e567 Small CSS correction
Enter fullscreen mode Exit fullscreen mode

You edit the instructions. Here are the important commands:

πŸ…°οΈ pick: keep the commit as is

pick a123 Created login component
Enter fullscreen mode Exit fullscreen mode

πŸ…±οΈ squash: combine with the previous commit (keep both messages)

pick a123 Created login component
pick b234 Fixed login button
squash c345 Fixed login button again
Enter fullscreen mode Exit fullscreen mode

Result could be: Created login component and fixed login button. Use it to turn many small commits into one meaningful commit.

πŸ…² fixup: combine, but discard the later message

pick a123 Created login component
fixup b234 Fixed login button
Enter fullscreen mode Exit fullscreen mode
  • squash = combine changes and messages
  • fixup = combine changes, discard the later message

πŸ…³ reword: change only the commit message

reword a123 login changes
Enter fullscreen mode Exit fullscreen mode

Old: login changes β†’ New: Implemented user login API. The code stays the same.

πŸ…΄ edit: pause the rebase at that commit

edit a123 Created login component
Enter fullscreen mode Exit fullscreen mode

Then modify the code or amend:

git add .
git commit --amend
git rebase --continue
Enter fullscreen mode Exit fullscreen mode

πŸ…΅ drop: remove the commit

drop b234 Fixed login button
Enter fullscreen mode Exit fullscreen mode

⚠️ Dropping a commit also removes its changes from the resulting history unless they exist elsewhere.

πŸ…Ά Reorder commits

Just change the order of the lines:

# Before
pick a123 Created login component
pick b234 Added validation
pick c345 Added styling

# After
pick c345 Added styling
pick a123 Created login component
pick b234 Added validation
Enter fullscreen mode Exit fullscreen mode

Git tries to replay them in the new order. Reordering can cause conflicts if later commits depend on earlier ones.

πŸ“‹ Interactive rebase summary

Command Meaning
pick Keep commit
reword Change commit message
edit Pause and modify commit
squash Combine commits and messages
fixup Combine commits, discard later message
drop Remove commit

πŸ’‘ Practical example: squash five small auth commits into one clean commit: Implemented authentication with login validation.


4. βš”οΈ Resolving Git Merge Conflicts

🎯 Extremely important in real projects!

A merge conflict happens when Git cannot automatically decide how to combine changes from different branches. Git is good at combining changes, but sometimes it needs human help.

🎬 Real-life example

main has this in auth.py:

def login():
    return "Login successful"
Enter fullscreen mode Exit fullscreen mode

Another developer changes that line in main:

def login():
    return "Welcome back!"
Enter fullscreen mode Exit fullscreen mode

You change the same line in your feature branch:

def login():
    return "User authenticated successfully"
Enter fullscreen mode Exit fullscreen mode

Now you run:

git merge main
Enter fullscreen mode Exit fullscreen mode

Both branches changed the same part of the same file. Git doesn't know your intention, so it reports a conflict. πŸ’₯

πŸ‘€ How does a conflict look?

Git edits your file like this:

def login():
<<<<<<< HEAD
    return "User authenticated successfully"
=======
    return "Welcome back!"
>>>>>>> main
Enter fullscreen mode Exit fullscreen mode
Marker Meaning
<<<<<<< HEAD Start of your current branch's version
======= Separates the two versions
>>>>>>> main End of the incoming branch's version
  • Above ======= β†’ your current branch's change
  • Below ======= β†’ the incoming branch's change

πŸ› οΈ How to resolve it

Say you want to keep your version. Manually delete the three marker lines and keep the final correct code:

def login():
    return "User authenticated successfully"
Enter fullscreen mode Exit fullscreen mode

Then:

git add auth.py     # tells Git you resolved this file
git commit          # completes the merge commit
Enter fullscreen mode Exit fullscreen mode

πŸ” Resolving a conflict during a rebase

# 1. Open the conflicted file and fix the code

# 2. Mark it as resolved
git add auth.py

# 3. Continue the rebase
git rebase --continue
Enter fullscreen mode Exit fullscreen mode

Want to cancel?

git rebase --abort     # cancel a rebase
git merge --abort      # cancel a merge
Enter fullscreen mode Exit fullscreen mode

⚠️ HEAD and incoming changes: during a normal merge, HEAD is your current branch and the incoming version comes from the branch you're merging. During a rebase, Git is replaying commits, so the terminology can be confusing. Don't blindly assume ours and theirs mean what you expect.

πŸ›‘οΈ How to prevent conflicts

  1. Frequently pull or rebase the latest changes from main
  2. Communicate with teammates about which files you're modifying
  3. Avoid unnecessarily large changes in one branch
  4. Keep commits small and focused
  5. Resolve conflicts early, not at the end

πŸ’‘ Remember: A conflict is not a Git error. It's Git asking you to make a decision.


5. πŸ—„οΈ Git Stash

You're working on login and have changed:

frontend/Login.tsx
backend/auth.py
Enter fullscreen mode Exit fullscreen mode

Suddenly your mentor says: "Please switch to main and fix this production bug right now!" 😱 But your changes are unfinished, and you don't want to commit incomplete code.

πŸ“Œ Git stash temporarily stores your uncommitted changes so you get a clean working directory. Think of it as putting unfinished work into a temporary drawer πŸ—„οΈ.

A. Save your changes

git stash
git switch main      # now you can switch safely
Enter fullscreen mode Exit fullscreen mode

B. View your stashes

git stash list
Enter fullscreen mode Exit fullscreen mode
stash@{0}: WIP on feature/login
stash@{1}: WIP on feature/profile
Enter fullscreen mode Exit fullscreen mode

(WIP = Work In Progress)

C. Restore your changes

git stash apply     # restore the latest stash, KEEP it in the list
git stash pop       # restore the latest stash, REMOVE it from the list
Enter fullscreen mode Exit fullscreen mode

D. Stash with a message

git stash push -m "Login feature work"
Enter fullscreen mode Exit fullscreen mode

E. Delete stashes

git stash drop stash@{0}   # delete one stash
git stash clear            # delete ALL stashes (careful!)
Enter fullscreen mode Exit fullscreen mode

F. Stash untracked files too

By default, git stash does not include untracked files (like a brand-new backend/new_auth_service.py). Use:

git stash -u
Enter fullscreen mode Exit fullscreen mode

πŸ“‹ Stash summary

Command Purpose
git stash Temporarily save tracked changes
git stash -u Also save untracked files
git stash list View saved stashes
git stash apply Restore but keep the stash
git stash pop Restore and remove the stash
git stash drop Delete a particular stash
git stash clear Delete all stashes

⚠️ Stash is temporary storage, not a permanent backup. Don't use it as a replacement for meaningful commits.


6. πŸ’ Git Cherry-Pick

You're working on the profile feature. Your teammate works on login and makes three commits:

Commit A: Created login page
Commit B: Fixed login validation
Commit C: Updated login styling
Enter fullscreen mode Exit fullscreen mode

You only need the validation fix (B). You don't want to merge the whole login branch because it has other unfinished changes.

πŸ“Œ Cherry-pick takes a specific commit from another branch and applies its changes to your current branch. Like picking one item from a basket instead of taking the whole basket. 🧺

Step 1: find the commit ID

git log --oneline
Enter fullscreen mode Exit fullscreen mode
c345 Updated login styling
b234 Fixed login validation
a123 Created login page
Enter fullscreen mode Exit fullscreen mode

Step 2: switch to your branch

git switch feature/profile
Enter fullscreen mode Exit fullscreen mode

Step 3: cherry-pick

git cherry-pick b234
Enter fullscreen mode Exit fullscreen mode

Git applies the changes from b234 to your current branch, creating a new commit with the same changes but a different hash.

Conflict? Resolve it manually, then:

git add .
git cherry-pick --continue

# or cancel:
git cherry-pick --abort
Enter fullscreen mode Exit fullscreen mode

πŸ†š Merge vs Cherry-pick

Merge Cherry-pick
Combines branch histories Applies selected commit changes
Usually brings multiple commits Can bring a specific commit
Useful for integrating branches Useful for reusing individual fixes

πŸ’‘ Real-world use: a teammate fixes a critical auth bug in one branch. You cherry-pick just that fix into a release branch without merging their unfinished work.


7. βͺ Git Revert vs Git Reset

🎯 Must know before working on shared repositories!

You accidentally committed bad code and want to undo it. Git offers two major approaches, and they work very differently.

πŸ…°οΈ Git Revert

Revert creates a new commit that reverses the changes of an earlier commit. It does not delete the original commit.

Before:  A -- B -- C -- D          (D introduced a bug)

git revert D

After:   A -- B -- C -- D -- E     (E undoes D)
Enter fullscreen mode Exit fullscreen mode
  • D = the original incorrect change
  • E = the new commit that undoes D

The original history is preserved. This is especially useful on shared branches like main.

git revert <commit-id>
Enter fullscreen mode Exit fullscreen mode

πŸ…±οΈ Git Reset

Reset moves your current branch pointer (HEAD) to an earlier commit. Depending on the mode, it also changes your staging area and working directory.

First, the three Git areas:

Area Simple meaning
πŸ“ Working directory Where you edit your actual files
🎭 Staging area Where you prepare changes using git add
πŸ“¦ Repository Where your commits are stored

1️⃣ Soft reset

git reset --soft HEAD~1
Enter fullscreen mode Exit fullscreen mode
  • Removes the latest commit from branch history
  • Keeps changes staged
  • Your code is preserved

Use when: you want to combine the last commit with other changes into a new commit.

2️⃣ Mixed reset (the default)

git reset --mixed HEAD~1
Enter fullscreen mode Exit fullscreen mode
  • Removes the latest commit
  • Unstages the changes
  • Keeps your code in the working directory

Use when: you want to modify some files before committing again.

3️⃣ Hard reset 🚨

git reset --hard HEAD~1
Enter fullscreen mode Exit fullscreen mode
  • Moves HEAD back one commit
  • Resets the staging area
  • Resets tracked files in your working directory to match the target commit

🚨 Destructive! You can permanently lose uncommitted work, and recovering discarded commits is not guaranteed.

πŸ“Š Soft vs Mixed vs Hard

Reset type Commit Staging area Working directory
Soft Removed from branch Changes kept Changes kept
Mixed Removed from branch Changes unstaged Changes kept
Hard Removed from branch Reset Reset

🧠 Easy memory trick:

  • Soft: keep everything staged
  • Mixed: keep the code, unstage it
  • Hard: discard tracked changes to match the target commit

βš”οΈ Revert vs Reset: the biggest difference

Feature Revert Reset
How it works Creates a reversing commit Moves the branch pointer
Original commit Preserved Removed from current branch history
History Preserved Rewritten
Shared main branch Usually safe βœ… Risky ⚠️
Best for Undoing shared changes Reorganizing local history

Which one should you use?

  • Pushed a faulty commit to the team's main? β†’ git revert <commit-id>, because others may already have the original commit.
  • Made an accidental commit locally and haven't pushed? β†’ git reset --soft HEAD~1 (or another mode).

πŸ† Golden rule: shared/published history β†’ prefer revert. Your own unpublished local history β†’ reset can be useful.

πŸ“ HEAD~1 means the first parent of the current commit. Merge commits have multiple parents, so reverting a merge commit needs extra care, usually git revert -m.


8. 🏷️ Git Tags: Tagging Releases

Your app evolves through milestones:

  • Version 1.0: basic feed
  • Version 1.1: login and authentication
  • Version 1.2: comments and likes
  • Version 2.0: major redesign

How do you mark these in Git? With tags.

πŸ“Œ A Git tag is a label attached to a specific commit. It marks important points in history, especially software releases.

Commit A -- Commit B -- Commit C -- Commit D
                          ↑                 ↑
                        v1.0              v2.0
Enter fullscreen mode Exit fullscreen mode

A. Lightweight tag

git tag v1.0
Enter fullscreen mode Exit fullscreen mode

B. Annotated tag (preferred for releases)

git tag -a v1.0 -m "First stable release"
Enter fullscreen mode Exit fullscreen mode

It stores extra info: tag name, tagger's information, date, and message.

C. View tags

git tag
Enter fullscreen mode Exit fullscreen mode

D. Tag an older commit

git tag -a v1.0 <commit-id> -m "First stable release"
Enter fullscreen mode Exit fullscreen mode

E. Push tags to GitHub

Creating a tag locally doesn't send it to GitHub automatically.

git push origin v1.0        # push one tag
git push origin --tags      # push all tags
Enter fullscreen mode Exit fullscreen mode

F. Delete a tag

git tag -d v1.0                    # delete locally
git push origin --delete v1.0      # delete remotely
Enter fullscreen mode Exit fullscreen mode

πŸ”’ Semantic Versioning (SemVer)

Versions like 1.2.3 follow MAJOR.MINOR.PATCH:

Part Meaning
1 MAJOR Breaking changes πŸ’₯
2 MINOR New compatible features ✨
3 PATCH Bug fixes 🩹
Version Meaning
1.0.0 First stable release
1.1.0 Added a new feature
1.1.1 Fixed a bug
2.0.0 Introduced breaking changes

🎯 Interview point: tags are labels for specific commits, whereas branches are movable pointers that normally advance as new commits are added.


9. 🏒 Git Branching Strategies

You work in a company with 10 developers: login, profile, notifications, feed, comments. If everyone changes main directly, chaos! 😡 Teams use branching strategies. Three popular ones:

  1. πŸ›οΈ Git Flow
  2. πŸ™ GitHub Flow
  3. πŸš„ Trunk-Based Development

πŸ›οΈ A. Git Flow (structured)

A strategy with multiple long-lived and short-lived branches. Useful for projects with scheduled releases and separate development, testing, and production workflows. It has five branch types:

Branch Purpose
🟒 main Production-ready code. Only stable, released versions
πŸ”΅ develop Integration branch for upcoming features
🌿 feature/* One per feature (e.g. feature/login), created from develop and merged back into develop
πŸ“¦ release/* Release preparation (e.g. release/1.0): final testing, bug fixes, version updates. Merged into main and usually back into develop
πŸš‘ hotfix/* Critical production fixes (e.g. hotfix/login-security), created from main and merged into main and develop
main      ●─────────────────────●─────────────●──────▢
           \                   β†— (release)     ↑
            \                 /                β”‚ hotfix
develop      ●──●──────●─────●──────────●──────●──────▢
                 \    β†—
                  ●──●   feature/login
Enter fullscreen mode Exit fullscreen mode

(The diagram is conceptual. Real Git Flow merges create more detailed history.)

βœ… Advantages

  • Clear separation between development and production
  • Suitable for planned releases
  • Supports hotfixes and release stabilization

❌ Disadvantages

  • More branches to manage
  • More complicated workflow
  • Can slow down teams that release frequently

πŸ™ B. GitHub Flow (simple and widely used)

Uses just:

  • main
  • Short-lived feature branches
  • Pull Requests (PRs)

How it works:

# Step 1: start from main
git switch main
git pull origin main

# Step 2: create a feature branch
git switch -c feature/login

# Step 3: make changes and commit
git add .
git commit -m "Add login functionality"

# Step 4: push your branch
git push -u origin feature/login
Enter fullscreen mode Exit fullscreen mode

Step 5: create a Pull Request on GitHub. Teammates can review code, add comments, suggest improvements, request changes, or approve.

Step 6: merge the PR once it's approved and checks pass.

Step 7: delete the feature branch. 🧹

βœ… Advantages

  • Simple workflow
  • Easy collaboration
  • Supports CI/CD
  • Less branch management

❌ Disadvantages

  • Requires good automated testing and code review
  • main must stay stable
  • Teams need to coordinate deployments and releases

πŸš„ C. Trunk-Based Development

The trunk is the main development line, usually main. Developers integrate small changes into main frequently instead of keeping long-lived feature branches. They may use very short-lived branches, or even commit directly to the trunk when the team's workflow permits.

git switch main
git pull origin main

git switch -c feature/login

# Make small changes

git add .
git commit -m "Add login validation"

git push -u origin feature/login
Enter fullscreen mode Exit fullscreen mode

The branch is reviewed and integrated quickly.

🚩 What are Feature Flags?

Your notification feature isn't ready for users, but you want its code in main. Keep it disabled with a flag:

ENABLE_NOTIFICATIONS = False

if ENABLE_NOTIFICATIONS:
    show_notifications()
Enter fullscreen mode Exit fullscreen mode

When it's ready, you enable it. Real applications generally use proper configuration or feature-flag services instead of hardcoding flags.

βœ… Advantages

  • Frequent integration
  • Fewer large, complicated merges
  • Faster feedback
  • Supports continuous delivery
  • Avoids long-lived branch problems

❌ Disadvantages

  • Requires strong automated testing
  • Developers must integrate small changes frequently
  • Incomplete features need careful isolation
  • Requires good CI/CD practices

πŸ“Š Compare all three

Feature Git Flow πŸ›οΈ GitHub Flow πŸ™ Trunk-Based πŸš„
main branch Yes Yes Yes
develop branch Yes Usually no No
Feature branches Yes Yes Short-lived or none
Complexity High Low Low to moderate
Integration Around feature/release milestones Through PRs Very frequent
Best for Scheduled releases Web apps and teams using PRs Continuous delivery
  • Git Flow: more structured, multiple branches, scheduled releases
  • GitHub Flow: main + feature branches + Pull Requests
  • Trunk-Based: integrate small changes into main frequently

πŸ’‘ For a typical small team building a web app, GitHub Flow is a straightforward starting point. Trunk-Based Development shines when you have strong automated testing and deployment practices.


10. πŸ“– Clean, Readable Git History as Documentation

One of the most underrated Git concepts! Imagine joining a company and opening its commit history:

1. changes
2. final changes
3. fixed
4. updated
5. test
6. again fixed
7. new changes
Enter fullscreen mode Exit fullscreen mode

Can you tell what was built? Probably not. 😡 Now compare:

1. Add user authentication API
2. Implement password hashing using Argon2
3. Add session expiration handling
4. Fix login validation for invalid credentials
5. Add cursor-based pagination to home feed
6. Implement post like and unlike endpoints
Enter fullscreen mode Exit fullscreen mode

Much better! ✨ That's why clean history matters.

✍️ What makes a good commit message?

git commit -m "Add user authentication API"
Enter fullscreen mode Exit fullscreen mode

A good message is short, meaningful, specific, and describes the change.

❌ Bad βœ… Good
changes Add user profile API
fixed Fix login validation error
updated code Add pagination to home feed
final Implement password hashing
test Add unit tests for auth service

βš›οΈ What is atomic committing?

Atomic = small and focused. One commit should ideally represent one logical change. Don't mash login API, profile API, a migration, UI styling, and a notification service into one giant commit. Instead:

Commit 1: Add login API
Commit 2: Implement password hashing
Commit 3: Add profile update endpoint
Commit 4: Add profile validation tests
Enter fullscreen mode Exit fullscreen mode

This makes debugging and code review much easier.

πŸ” Useful commands for reading history

git log                          # full history
git log --oneline                # compact history
git log --oneline --graph --all  # history as a graph
git log --stat                   # which files changed per commit
git log -p                       # actual changes per commit
git show <commit-id>             # inspect one commit
Enter fullscreen mode Exit fullscreen mode

πŸ€” Why is Git history "documentation"?

Someone asks: "Why did we change the authentication logic last month?" You search the history and find Fix session validation for expired access tokens, then inspect the commit to see exactly what changed. History helps answer:

  • What was changed?
  • When was it changed?
  • Why? (if the commit or PR explains the reason)
  • Which files were affected?
  • Which developer contributed it?

πŸ“ Git history doesn't replace proper project documentation, but it's a valuable record of development decisions.


11. 🧡 A Real Team Workflow, Start to Finish

Your mentor says: "Implement the user profile update API." Here's a professional workflow:

Step 1: get the latest code

git switch main
git pull origin main
Enter fullscreen mode Exit fullscreen mode

Step 2: create your feature branch

git switch -c feature/profile-update
Enter fullscreen mode Exit fullscreen mode

Step 3: develop your feature

backend/
    api/
        profile.py
    services/
        profile_service.py
    schemas/
        profile_schema.py
Enter fullscreen mode Exit fullscreen mode

Step 4: check your changes

git status     # modified, staged and untracked files
git diff       # the actual changes
Enter fullscreen mode Exit fullscreen mode

Step 5: commit

git add .
git commit -m "Add user profile update API"
Enter fullscreen mode Exit fullscreen mode

Step 6: update your branch if main has changed

git fetch origin
git rebase origin/main
Enter fullscreen mode Exit fullscreen mode

git fetch downloads remote updates without integrating them. git rebase replays your local commits on top of the latest remote main. If there are conflicts, resolve them and run:

git add .
git rebase --continue
Enter fullscreen mode Exit fullscreen mode

Step 7: push your feature branch

git push -u origin feature/profile-update
Enter fullscreen mode Exit fullscreen mode

If you rebased commits that were already pushed to your own feature branch, you may need:

git push --force-with-lease
Enter fullscreen mode Exit fullscreen mode

This is safer than --force because it checks that the remote branch hasn't moved unexpectedly. Still, coordinate with teammates before rewriting a shared branch.

Step 8: create a Pull Request

On GitHub: feature/profile-update β†’ main. Your teammates review the changes.

Step 9: merge the Pull Request

After approval and successful checks, merge using your team's chosen merge method.

Step 10: tag the release

git tag -a v1.2.0 -m "Release version 1.2.0"
git push origin v1.2.0
Enter fullscreen mode Exit fullscreen mode

πŸŽ‰ You've followed a complete professional Git workflow!


12. πŸ“‹ Quick Revision: Important Git Commands

Requirement Command
Check current branch git branch --show-current
List branches git branch
Create branch git branch feature/name
Switch branch git switch branch-name
Create and switch git switch -c feature/name
Merge git merge main
Rebase git rebase main
Interactive rebase git rebase -i HEAD~5
Abort rebase git rebase --abort
Continue rebase git rebase --continue
View conflicts git status
Save changes temporarily git stash
Restore stash git stash pop
View stashes git stash list
Apply a specific commit git cherry-pick commit-id
Undo a commit safely git revert commit-id
Soft reset git reset --soft HEAD~1
Mixed reset git reset --mixed HEAD~1
Hard reset git reset --hard HEAD~1
View history git log --oneline --graph --all
Create release tag git tag -a v1.0 -m "Release"
Push a tag git push origin v1.0
Download remote updates git fetch origin
Push branch git push origin branch-name

13. 🎀 Interview Questions

Q1. What is the difference between Git merge and Git rebase?
Merge combines branches while preserving their existing history, often creating a merge commit. Rebase replays commits on top of another branch, creating new commit hashes and generally a linear history.

Q2. What is interactive rebase?
It lets us modify commit history. We can squash, reorder, edit, reword or drop commits.

Q3. What is a merge conflict?
It occurs when Git cannot automatically combine changes, usually because different branches modify overlapping parts of a file. We manually resolve the changes and mark the files as resolved.

Q4. What is Git stash?
It temporarily saves uncommitted changes and cleans the working directory so we can switch branches or work on something else.

Q5. What is cherry-pick?
It applies a specific commit from another branch to our current branch without merging the entire branch.

Q6. What is the difference between revert and reset?
Revert creates a new commit that reverses an earlier commit, preserving history. Reset moves the branch pointer to an earlier commit and can remove commits from the current branch history.

Q7. Explain soft, mixed and hard reset.

  • Soft: keeps changes staged
  • Mixed: keeps changes unstaged
  • Hard: discards tracked-file changes to match the target commit

Q8. What are Git tags?
Labels attached to specific commits, commonly used to mark software releases such as v1.0.0.

Q9. What is Git Flow?
A structured branching strategy using main, develop, feature, release and hotfix branches.

Q10. What is GitHub Flow?
A simple workflow using main, short-lived feature branches and Pull Requests.

Q11. What is Trunk-Based Development?
A development approach where developers integrate small changes into the main development branch frequently, using short-lived branches or direct integration.

Q12. Why is clean Git history important?
It makes the project easier to understand, review, debug and maintain. Meaningful commits act as a record of development changes and decisions.


14. πŸ§ͺ Test Your Understanding!

Try these before peeking at the answers! ❀️

  1. You want to combine your feature branch with main while preserving the branch history. Which operation?

    • A) Rebase
    • B) Merge
    • C) Reset
  2. You made five small commits and want to combine them into one meaningful commit.

    • A) Cherry-pick
    • B) Git stash
    • C) Interactive rebase
  3. Your mentor asks you to switch branches, but your current changes are unfinished and uncommitted.

    • A) Git stash
    • B) Git revert
    • C) Git tag
  4. You need only one bug-fix commit from another developer's branch.

    • A) Merge
    • B) Cherry-pick
    • C) Hard reset
  5. A faulty commit has already been pushed to the shared main branch. What's generally safest?

    • A) git reset --hard
    • B) git revert
    • C) git stash clear
  6. You want to undo the last local commit but keep all changes staged.

    • A) git reset --soft HEAD~1
    • B) git reset --hard HEAD~1
    • C) git revert HEAD
  7. Which branching strategy uses main, develop, feature, release and hotfix branches?

    • A) GitHub Flow
    • B) Trunk-Based Development
    • C) Git Flow
  8. What is a Git tag commonly used for?

    • A) Temporary storage
    • B) Marking software releases
    • C) Resolving merge conflicts

πŸ‘€ Click to reveal answers
  1. B: Merge preserves branch history
  2. C: Interactive rebase lets you squash commits
  3. A: Git stash saves unfinished work temporarily
  4. B: Cherry-pick applies one specific commit
  5. B: git revert adds a new undoing commit and doesn't rewrite shared history
  6. A: git reset --soft HEAD~1 removes the commit but keeps changes staged
  7. C: Git Flow
  8. B: Tags mark specific commits, such as releases


15. 🧠 The Most Important Concept: Rewriting vs Preserving History

There are two philosophies for managing Git history:

1️⃣ Preserve history: merge / revert

  • Keeps the original development history
  • Shows how branches were integrated
  • Useful for shared team branches
  • Revert records corrections instead of erasing previous commits

2️⃣ Rewrite history: rebase / reset

  • Can create a clean, linear history
  • Can combine unnecessary commits
  • Can remove unpublished commits
  • Needs care when commits are already shared

πŸ“– Merge tells the story of how the team worked together. Rebase tells the story in a cleaner, reorganized sequence. Neither is universally better. The right choice depends on your team's workflow, whether the commits are shared, and how important preserving the original history is.


πŸ—ΊοΈ Recommended Learning Order

Don't try to memorize every command in one sitting. Learn in this order:

  1. 🌿 Branching and switching
  2. πŸ”€ Merge vs rebase
  3. βš”οΈ Merge conflict resolution
  4. πŸ—„οΈ Git stash
  5. πŸ’ Cherry-pick
  6. βͺ Revert vs reset
  7. 🧹 Interactive rebase
  8. 🏷️ Tags and branching strategies
  9. πŸ“– Clean commit history

πŸš€ What's Next?

Practice in a small dummy GitHub repo: create branches, intentionally cause conflicts, resolve them, squash commits, and revert a mistake. You'll learn far more from doing than from reading commands! πŸ’‘

If this post helped you, drop a ❀️ or πŸ¦„ and share it with a friend learning Git. Happy coding! πŸ‘©β€πŸ’»βœ¨

Top comments (0)