linuxlab.io
Tutorials▾
  • Linux & networking
    File system, processes, TCP/IP, BGP and OSPF
    →
  • Terraform & IaC
    HCL, state, plan/apply on a LocalStack sandbox
    →
  • Git & GitHub
    Object model, plumbing, branching, GitHub Actions
    →
All tutorials →
PricingAboutSign inCreate account
/
Intro
Lessons
Footer
linuxlab-TutorialsPricingAboutPrivacy & cookies
Copyright © 2026 LinuxLab. All rights reserved.
linuxlab.io
Tutorials▾
  • Linux & networking
    File system, processes, TCP/IP, BGP and OSPF
    →
  • Terraform & IaC
    HCL, state, plan/apply on a LocalStack sandbox
    →
  • Git & GitHub
    Object model, plumbing, branching, GitHub Actions
    →
All tutorials →
PricingAboutSign inCreate account
/
  • Introduction
  • Chapters
  • How it works
  • Lessons
  • Knowledge base
  • Interview prep
home/git/lessons/git-lab-08-1-merge-vs-rebase

lesson ── git-labs ── ~20 мин ── 7 шагов

Merge vs rebase: by hand in one repository

The goal is to see the difference between git merge and git rebase by hand. First you put two branches into the typical "they diverged" situation, then you join them one way, then you run the same scenario again the other way and compare the history graphs.

You need no real GitHub. Everything is local, in an ephemeral container with git inside. Afterward the container disappears and the repositories are deleted.

▶ интерактивный sandbox

Поднимется контейнер gitlab/git-base с git, bash, pre-commit. В браузере откроется терминал, можно сразу git init. Каждый шаг проверяется автоматически. Сеть air-gapped, github.com недоступен.

запустить sandbox →

stack ── git · bash · 256 MB RAM · air-gapped · самоуничтожается через 30 мин простоя

Шаги

  1. 01

    Create a repo with two diverging branches

    You build a minimal repository with one shared commit, then split into two branches and make one commit on each. This is the classic "main moved ahead while I worked on feature" situation.

    bash
    cd /home/student/work
    mkdir merge-vs-rebase && cd merge-vs-rebase
    git init
    echo "v1" > file.txt
    git add file.txt
    git commit -m "init"
    git switch -c feature                # -c = create a branch and switch to it
    echo "feature line" >> file.txt      # >> append, does not overwrite v1
    git commit -am "feature: add line"   # -a stage tracked files, -m message
    git switch main
    echo "main line" >> file.txt
    git commit -am "main: add line"

    Now main and feature have diverged from the shared init commit.

    подсказка

    One command per line. If something is off, read the error.

    ✓ Two diverging commits from a common ancestor. Ready for the experiment.

  2. 02

    Look at the graph before merging

    The graph shows the shape of the history. Run:

    bash
    git log --oneline --graph --all   # --graph = ASCII graph, --all = show all refs

    It should show:

    * <sha> (main) main: add line
    | * <sha> (feature) feature: add line
    |/
    * <sha> init

    This is a V-shaped divergence from init. Remember the shape; you compare it after merge and after rebase.

    подсказка

    If you see nothing, make sure you are in /home/student/work/merge-vs-rebase.

    ✓ The V shape is visible. Next, merge.

  3. 03

    Merge feature into main

    You are on main. Merge feature:

    bash
    git merge feature             # both branches moved, so this is a three-way merge with a conflict

    An editor opens with the default merge-commit message. Save it without edits (Ctrl-O, Enter, Ctrl-X in nano). There is a conflict in file.txt: the same file was edited in two places. Open file.txt, delete the markers <<<<<<<, =======, >>>>>>>, and keep both lines in some order. Save.

    bash
    git add file.txt              # mark the conflict as resolved
    git commit                    # without -m: opens the editor with the merge message

    Save the merge-commit message again.

    подсказка

    A conflict is normal. Open nano with `nano file.txt`.

    ✓ The merge commit is created. Look at the new graph.

  4. 04

    Look at the graph after merge

    bash
    git log --oneline --graph --all

    Now you see:

    *   <sha> (HEAD -> main) Merge branch 'feature'
    |\
    | * <sha> (feature) feature: add line
    * | <sha> main: add line
    |/
    * <sha> init

    Compare it with what you had before the merge. The old commits are still there, a merge commit was added on top, and the history pulls back into one point. That is a merge: the history is kept exactly as it was, plus a seam.

    ✓ The graph with the merge commit is visible. Next you roll back and do the same with rebase.

  5. 05

    Reset the state back to the divergence

    To try rebase on the same situation, return main to its "one commit after init" state. You need two commits: init and main: add line. A merge commit sits on top right now, and it has to go.

    bash
    git reset --hard HEAD~1       # drop the last commit (merge), wipe the working tree too
    git log --oneline

    You should be left with main: add line and init. Leave feature alone, it sits off to the side.

    подсказка

    `git reset --hard HEAD~1` drops the single last commit (merge) and loses it.

    ✓ main is back to where it was before the merge. Ready for rebase.

  6. 06

    Rebase feature onto main

    Now switch to feature and rebase onto main:

    bash
    git switch feature
    git rebase main               # replay the feature commits on top of main

    Another conflict in file.txt (the same cause as in the merge step). Open the file:

    bash
    nano file.txt

    Inside you see a block with conflict markers: seven angle brackets in a row (<<<<<<<), equals signs (=======), and angle brackets again (>>>>>>>). Right now the file looks roughly like this:

    v1
    <<<<<<< HEAD
    main line
    =======
    feature line
    >>>>>>> 699c3b1 (feature: add line)

    Delete all three marker lines (<<<<<<<, =======, >>>>>>>) and keep the main line and feature line lines. You want exactly this, three lines, with no angle brackets and no equals signs:

    v1
    main line
    feature line

    Save (Ctrl-O, Enter, Ctrl-X). Now mark the conflict resolved and continue the rebase:

    bash
    git add file.txt              # mark the conflict as resolved
    git rebase --continue         # after a conflict use --continue, not commit

    An editor opens with the message of the replayed commit. Save it without edits. The rebase finishes.

    подсказка

    If verify is red, here are the three most common causes. Check them in order: 1. file.txt still has the markers `<<<<<<<`, `=======`, `>>>>>>>`. Open `nano file.txt`, remove them by hand, and keep three lines with no brackets. Then `git add file.txt` and `git rebase --continue`. 2. You ran `git commit` instead of `git rebase --continue`, which does not finish the rebase. Run `git status`; if you see "interactive rebase in progress", finish it with `git rebase --continue`. 3. The rebase is not done yet (there are uncommitted edits). `git status` tells you what is left.

    ✓ Rebase finished. The graph changes a lot.

  7. 07

    Look at the graph after rebase

    bash
    git log --oneline --graph --all

    You see:

    * <sha> (HEAD -> feature) feature: add line
    * <sha> (main) main: add line
    * <sha> init

    A fully linear history. No merge commit, no V shape. The commit "feature: add line" now sits on top of main: add line, with a different SHA, because its base commit changed.

    That is a rebase: your branch is rewritten as if it had branched off the fresh main from the start.

    ✓ A linear history. You saw the difference by hand. Chapter 8 has more.

Что ты узнал

Merge keeps the history as it was, at the cost of a merge commit. Rebase replays on top, at the cost of new SHAs. The graph git log --oneline --graph --all shows the difference at a glance.

команды

  • git log --oneline --graph --allsee the branches and their shape
  • git merge featuremerge feature into the current branch (with a merge commit)
  • git rebase mainreplay the current branch on top of main
  • git reflogif you get lost, roll back through the reflog

концепции

  • · merge does not rewrite commits, it only adds
  • · rebase changes SHAs, you need a force-push if the branch is published
  • · the graph answers 'what happened' without guessing

← предыдущая

Atomic commits: add -p and amend

следующая →

Undoing: reset, revert, reflog

Footer
linuxlab-
Copyright © 2026 LinuxLab. All rights reserved.
Tutorials
Pricing
About
Privacy & cookies