Build CoreOrdered learning track

Interactive Rebase for Series Engineering

Learn Git In Action - Part 024

Menggunakan interactive rebase untuk membentuk patch series yang reviewable, bisectable, auditable, dan aman sebelum masuk shared history.

10 min read1860 words
PrevNext
Lesson 24126 lesson track24–68 Build Core
#git#interactive-rebase#history-rewrite#patch-series+1 more

Part 024 — Interactive Rebase for Series Engineering

Interactive rebase adalah salah satu skill Git yang paling membedakan engineer biasa dengan engineer yang bisa mendesain history.

Bukan karena history harus selalu cantik. Tapi karena history adalah interface untuk:

  • reviewer;
  • future debugger;
  • release manager;
  • incident responder;
  • auditor;
  • maintainer maintenance branch;
  • engineer baru yang membaca alasan perubahan.

Interactive rebase memungkinkan kamu mengubah patch series sebelum menjadi public history.

git rebase -i origin/main

Command ini bukan sekadar "squash commit". Itu hanya satu fitur kecil. Interactive rebase adalah editor untuk urutan perubahan.


1. Mental Model

Rebase biasa:

Replay commit series di atas base baru.

Interactive rebase:

Replay commit series di atas base baru, tetapi beri engineer kesempatan mengedit rencana replay.

Rencana replay itu disebut todo list.

Contoh:

pick a1b2c3d add payment rule table
pick b2c3d4e add repository method
pick c3d4e5f wire rule evaluation service
pick d4e5f6a fix typo
pick e5f6a7b address review comment

Kamu bisa mengubahnya menjadi:

pick a1b2c3d add payment rule table
pick b2c3d4e add repository method
pick c3d4e5f wire rule evaluation service
fixup d4e5f6a fix typo
fixup e5f6a7b address review comment

Hasilnya bukan cuma lebih pendek. Hasilnya adalah patch series yang lebih mudah dibaca.


2. Interactive Rebase adalah Rewrite

Semua command interactive rebase yang mengubah commit akan menciptakan commit baru.

Mengubah message? Commit baru.

Mengubah isi commit? Commit baru.

Mengubah urutan? Commit baru.

Squash? Commit baru.

Drop? Commit hilang dari rewritten branch.

Konsekuensi:

KonsekuensiArtinya
SHA berubahCI dan review status lama tidak otomatis valid
signed commit berubahperlu sign ulang jika policy mewajibkan
branch remote perlu updatebiasanya push --force-with-lease
collaborator bisa terdampakjangan rewrite shared branch sembarangan
reflog pentingrecovery anchor jika rewrite salah

Aturan dasar:

Interactive rebase adalah alat untuk private/rewriteable history. Jangan gunakan secara sembarangan pada history yang sudah dikonsumsi orang lain.


3. Todo List sebagai Program

Todo list interactive rebase bisa dipikirkan sebagai program kecil.

pick    = replay commit as-is
reword  = replay commit, edit message
edit    = replay commit, stop so engineer can change it
squash  = combine commit into previous commit and edit message
fixup   = combine commit into previous commit, discard fixup message
exec    = run shell command
break   = stop here
 drop   = remove commit
label   = label current HEAD
reset   = reset HEAD to label
merge   = create merge commit in rebase script

Tidak semua tim butuh semua command. Untuk usage harian, yang paling penting:

  • pick;
  • reword;
  • edit;
  • squash;
  • fixup;
  • drop;
  • exec.

Untuk topology-preserving rebase, label, reset, dan merge muncul pada --rebase-merges, yang akan dibahas di part berikutnya.


4. Menentukan Range yang Benar

Ini sumber error terbesar.

git rebase -i HEAD~5

berarti edit 5 commit terakhir.

Tapi untuk branch feature, lebih aman memakai upstream/base eksplisit:

git fetch origin
git rebase -i origin/main

Artinya edit commit yang ada di branch saat ini tetapi belum ada di origin/main.

Sebelum menjalankan:

git log --oneline --decorate origin/main..HEAD

Pastikan daftar commit itulah yang ingin diedit.

Jika branch dibuat dari base lain:

git merge-base HEAD origin/main

Inspect graph:

git log --oneline --graph --decorate --boundary origin/main...HEAD

Jangan memakai HEAD~N jika kamu tidak yakin jumlah commit dan boundary-nya.


5. Safety Anchor

Sebelum interactive rebase besar:

git branch backup/$(git branch --show-current)-before-irebase

Setelah itu baru:

git rebase -i origin/main

Jika hasil salah:

git reset --hard backup/feature-before-irebase

Atau lebih aman:

git switch -c feature-recovered backup/feature-before-irebase

Backup branch murah. Kehilangan patch series mahal.


6. Reword: Mengubah Message Tanpa Mengubah Patch

Todo:

reword a1b2c3d add payment rule stuff
pick b2c3d4e add repository method

Gunakan reword ketika patch benar, tetapi message buruk.

Contoh message buruk:

fix

Message lebih baik:

Add payment rule table

Introduce payment_rule table to persist jurisdiction-specific
threshold configuration used by the enforcement rule evaluator.

The table is intentionally separated from payment_event so rules can be
versioned without rewriting historical payment events.

Kapan reword tepat:

  • subject terlalu vague;
  • body tidak menjelaskan reason;
  • issue reference kurang;
  • migration risk perlu dicatat;
  • commit perlu trailer;
  • typo message saja.

Kapan tidak cukup:

  • patch commit mencampur concern;
  • commit terlalu besar;
  • patch salah;
  • perlu split commit.

7. Edit: Berhenti di Commit Tertentu

Todo:

pick a1b2c3d add payment rule table
edit b2c3d4e add repository method
pick c3d4e5f wire service

Saat sampai commit b2c3d4e, Git berhenti.

Kamu bisa:

  • mengubah file;
  • amend commit;
  • split commit;
  • menjalankan test;
  • inspect state.

Workflow amend:

# rebase berhenti pada commit yang ditandai edit
# lakukan perubahan
vim src/main/java/.../PaymentRuleRepository.java

git add -p
git commit --amend

git rebase --continue

Jika ingin lanjut tanpa perubahan:

git rebase --continue

Jika ingin abort:

git rebase --abort

8. Squash vs Fixup

Dua command ini sama-sama menggabungkan commit ke commit sebelumnya.

pick   a1b2c3d add payment rule table
squash b2c3d4e add indexes
fixup  c3d4e5f fix typo in migration

Perbedaan:

CommandMessage commit yang digabung
squashmessage ikut dibawa dan editor dibuka
fixupmessage commit fixup dibuang

Gunakan squash jika commit kedua punya message yang mengandung informasi penting.

Gunakan fixup jika commit kedua hanya koreksi kecil.

Contoh:

pick 111 add payment rule table
fixup 222 fix migration typo
fixup 333 address review comment

Hasilnya satu commit bersih.


9. Autosquash Workflow

Daripada manual memindahkan commit fixup, gunakan:

git commit --fixup <target-commit>

Contoh:

git log --oneline
# a1b2c3d add payment rule table

# setelah memperbaiki typo pada commit itu
git add db/migration/V20260707__payment_rule.sql
git commit --fixup a1b2c3d

Lalu:

git rebase -i --autosquash origin/main

Git akan mengatur todo list agar fixup commit ditempatkan setelah target dan ditandai fixup.

Config praktis:

git config --global rebase.autoSquash true

Setelah itu:

git rebase -i origin/main

akan autosquash secara default untuk interactive rebase.


10. Split Commit

Misal satu commit terlalu besar:

abc1234 implement payment rules and refactor user service

Kamu ingin split menjadi:

1. Add payment rule schema
2. Add payment rule repository
3. Wire payment rule evaluator
4. Refactor user service naming

Workflow:

git rebase -i origin/main

Tandai commit sebagai edit:

edit abc1234 implement payment rules and refactor user service

Saat rebase berhenti:

# kembalikan commit ke unstaged changes, tetapi tetap pertahankan working tree
git reset HEAD^

Sekarang perubahan commit itu kembali menjadi working tree changes.

Bentuk commit baru:

git add -p db/migration/
git commit -m "Add payment rule schema"

git add -p src/main/java/.../PaymentRuleRepository.java
git commit -m "Add payment rule repository"

git add -p src/main/java/.../PaymentRuleEvaluator.java
git commit -m "Wire payment rule evaluator"

git add -p src/main/java/.../UserService.java
git commit -m "Refactor user service naming"

# lanjut rebase
git rebase --continue

Hasilnya patch series lebih reviewable dan bisectable.


11. Reorder Commit

Todo list bisa diubah urutannya.

Sebelum:

pick 111 wire service
pick 222 add repository
pick 333 add database schema

Ini buruk karena service bergantung pada repository, repository bergantung pada schema.

Setelah reorder:

pick 333 add database schema
pick 222 add repository
pick 111 wire service

Reorder harus menjaga dependency.

Checklist sebelum reorder:

1. Apakah commit baru bisa compile setelah setiap step?
2. Apakah test relevan bisa jalan pada setiap step?
3. Apakah commit berikutnya bergantung pada file dari commit sebelumnya?
4. Apakah migration dan model order sudah benar?
5. Apakah rename/refactor dipisah dari behavior change?

Reorder yang bagus meningkatkan bisectability. Reorder yang asal membuat intermediate commit rusak.


12. Drop Commit

Todo:

pick 111 add schema
 drop 222 debug logging
pick 333 add repository

Atau hapus line commit dari todo list.

Gunakan drop untuk:

  • debug commit;
  • experiment yang tidak jadi;
  • duplicate patch;
  • commit yang sudah upstream;
  • accidental file change.

Jangan drop jika belum yakin patch tidak dibutuhkan.

Inspect dulu:

git show 222
git log --cherry-pick --right-only --oneline origin/main...HEAD

Untuk auditability, lebih baik drop private commit sebelum PR daripada mengirim commit noise lalu revert.


13. Exec: Test Setiap Commit

exec menjalankan command pada titik tertentu di rebase.

Contoh:

git rebase -i --exec './gradlew test' origin/main

Todo menjadi kira-kira:

pick 111 add schema
exec ./gradlew test
pick 222 add repository
exec ./gradlew test
pick 333 wire service
exec ./gradlew test

Gunakan untuk memastikan setiap commit compile/test.

Untuk test cepat:

git rebase -i --exec './gradlew test --tests PaymentRuleEvaluatorTest' origin/main

Trade-off:

BenefitCost
commit series bisectablelebih lambat
bug ditemukan tepat di commit penyebabcommand harus deterministic
review confidence naikflaky test mengganggu rebase

Jika exec gagal:

# fix issue
git add -p
git commit --amend

git rebase --continue

14. Break: Stop untuk Inspect Manual

break menghentikan rebase pada titik tertentu.

pick 111 add schema
pick 222 add repository
break
pick 333 wire service

Gunakan jika kamu ingin:

  • menjalankan manual verification;
  • inspect generated files;
  • menjalankan database migration;
  • melihat intermediate state;
  • menunggu command eksternal.

Lanjut:

git rebase --continue

15. Membentuk Commit Series dari WIP Mess

Scenario realistis:

- schema berubah
- service berubah
- test berubah
- typo fix
- debug logging
- refactor unrelated
- review feedback

Goal:

1. Add payment rule schema
2. Add payment rule repository
3. Add payment rule evaluator
4. Add API validation for payment rule
5. Add tests for payment rule evaluation

Workflow:

# pastikan branch private
git fetch origin
git branch backup/feature-before-cleanup

git rebase -i origin/main

Gunakan kombinasi:

  • reorder dependency;
  • squash fixup ke target;
  • drop debug commit;
  • edit commit besar;
  • split commit;
  • reword message;
  • exec test.

Hasil akhir harus bisa dijelaskan sebagai narrative:

schema -> persistence -> domain behavior -> API -> test

Bukan:

stuff -> fix -> more stuff -> oops -> review -> final final

16. Series Engineering Principles

Patch series yang baik memenuhi beberapa properti.

16.1 Locally Coherent

Setiap commit punya satu reason.

Buruk:

Add payment rule evaluator and rename user fields

Baik:

Add payment rule evaluator
Refactor user field naming

16.2 Dependency Ordered

Foundation muncul sebelum consumer.

schema -> repository -> service -> controller -> tests

16.3 Reviewable

Reviewer bisa membaca commit satu per satu tanpa menyimpan terlalu banyak state mental.

16.4 Bisectable

Idealnya setiap commit compile dan test relevan pass.

Tidak semua repo bisa menjamin 100%, tapi series engineering harus menuju ke sana.

16.5 Auditable

Commit message menjelaskan reason, bukan hanya change.

16.6 Revertable

Jika commit perlu dibalik, blast radius jelas.


17. Anti-Patterns

Anti-patternKenapa burukPerbaikan
squash semua commit jadi satu giant commitreview sulit, revert kasarbentuk logical commits
keep semua WIP commithistory noise, debugging susahautosquash/fixup
reorder tanpa testintermediate state rusakgunakan exec
rebase shared branch diam-diamcollaborator brokenprotokol atau hindari
drop commit tanpa inspectperubahan hilanggit show, backup branch
hide behavior change dalam refactor commitreviewer miss semantic riskpisahkan refactor dari behavior
resolve conflict asal compiledomain invariant bisa rusaktest dan review semantic
force push tanpa explanationreviewer kehilangan contextsummary + range-diff

18. Interactive Rebase dan Conflict

Conflict saat interactive rebase sama seperti rebase biasa: Git sedang replay commit satu per satu.

Saat conflict:

git status
git show REBASE_HEAD
git diff
git ls-files -u

REBASE_HEAD menunjukkan commit yang sedang direplay.

Resolve:

# edit files

git add <resolved-files>
git rebase --continue

Jika commit yang direplay ternyata tidak dibutuhkan:

git rebase --skip

Tapi inspect dulu:

git show REBASE_HEAD

Abort:

git rebase --abort

19. Updating the Todo Mid-Rebase

Jika di tengah rebase kamu sadar urutan masih salah:

git rebase --edit-todo

Gunakan untuk:

  • mengubah pick menjadi edit;
  • drop commit yang ternyata duplicate;
  • menambah exec;
  • memperbaiki urutan commit yang belum direplay.

Jangan edit todo sembarangan setelah conflict jika kamu belum memahami posisi rebase.

Inspect:

git status
git log --oneline --decorate --graph --all -20

20. --autosquash dengan Review Feedback

Review feedback sering menghasilkan commit seperti:

fix typo
address review
fix tests
more cleanup

Workflow yang lebih baik:

# perbaikan untuk commit schema
git add db/migration/...
git commit --fixup <schema-commit>

# perbaikan untuk commit service
git add src/main/java/.../PaymentRuleEvaluator.java
git commit --fixup <service-commit>

# setelah feedback selesai
git rebase -i --autosquash origin/main

Keuntungan:

  • feedback tidak hilang;
  • commit final tetap bersih;
  • target perubahan jelas;
  • reviewer bisa pakai range-diff setelah rewrite.

Setelah push:

git push --force-with-lease

Komentar PR yang baik:

Rebased and autosquashed review feedback.
Main changes:
- folded migration index fix into schema commit
- folded evaluator null-handling into evaluator commit
- no intended behavior change outside PaymentRuleEvaluator
Range-diff is attached below.

21. Range-Diff Setelah Interactive Rebase

Sebelum rewrite:

git branch backup/before-review-cleanup

Setelah rewrite:

git range-diff origin/main...backup/before-review-cleanup origin/main...HEAD

Gunakan hasilnya untuk melihat:

  • commit mana yang berubah;
  • commit mana yang drop;
  • commit mana yang reorder;
  • apakah patch berubah besar;
  • apakah cleanup hanya kosmetik atau semantic.

Untuk PR besar, range-diff adalah courtesy ke reviewer.


22. Interactive Rebase untuk Regulated Systems

Dalam sistem regulated, history bukan hanya developer convenience. History bisa menjadi evidence.

Gunakan interactive rebase sebelum perubahan masuk protected branch untuk memastikan:

  • commit message punya reason;
  • migration risk tercatat;
  • approval boundary jelas;
  • issue/ticket reference ada;
  • security-sensitive change tidak tersembunyi;
  • generated artifact tidak bercampur dengan source change;
  • release note boundary mudah ditarik.

Tapi setelah masuk protected branch:

  • jangan rewrite tanpa change-control;
  • gunakan revert untuk compensation;
  • jaga tag/release identity immutable;
  • simpan audit trail untuk force update jika exceptional rewrite diperlukan.

23. Practical Example: Refactor + Behavior Change

Awal messy series:

111 change payment service
222 rename stuff
333 fix test
444 add rule validation
555 fix typo

Masalah:

  • refactor bercampur behavior;
  • test fix tidak jelas targetnya;
  • typo commit noise;
  • validation datang setelah service berubah.

Target series:

111 Refactor payment service naming without behavior change
222 Add payment rule validation
333 Add tests for payment rule validation

Interactive todo:

reword 222 rename stuff
edit   111 change payment service
fixup  555 fix typo
pick   444 add rule validation
fixup  333 fix test

Mungkin perlu split commit 111:

git reset HEAD^
# stage only rename/refactor
git add -p src/main/java/.../PaymentService.java
git commit -m "Refactor payment service naming without behavior change"

# stage behavior part separately if any
git add -p
git commit -m "Add payment rule validation"

git rebase --continue

Lalu test:

./gradlew test --tests PaymentRuleValidationTest

24. Practical Example: Commit Message Repair

Todo:

reword 111 fix
reword 222 update
reword 333 final

Target messages:

Add payment rule persistence model

Add the PaymentRule entity and repository mapping used by the enforcement
rule evaluator. This commit intentionally does not wire evaluation behavior yet.

Add jurisdiction-aware payment threshold evaluation

Introduce evaluation logic for jurisdiction-specific payment thresholds.
The evaluator returns a deterministic decision object so later workflow steps
can persist both result and reason.

Add regression tests for payment threshold evaluation

Cover boundary values, unsupported jurisdiction fallback, and disabled rule
handling.

Message yang baik membuat git log menjadi debugging tool, bukan sekadar timestamp list.


25. Practical Example: Test Every Commit

git rebase -i --exec './gradlew test --tests PaymentRule*' origin/main

Jika commit kedua gagal test, rebase berhenti.

Fix:

vim src/test/java/.../PaymentRuleEvaluatorTest.java
git add -p
git commit --amend --no-edit
git rebase --continue

Hasil: series lebih kuat untuk bisect.

Jika test flaky, jangan lanjut seolah aman. Tandai flaky test sebagai problem terpisah atau gunakan test deterministic yang lebih kecil untuk exec.


26. Public Push Protocol Setelah Rewrite

Setelah interactive rebase pada branch PR:

git push --force-with-lease

Jangan pakai:

git push --force

kecuali kamu benar-benar memahami dan mengendalikan remote ref state.

Setelah push, tulis ringkasan:

I rewrote the branch to clean up the patch series.
No intended behavior change except the validation fix requested in review.
I folded typo/test fixes into their target commits.
CI should rerun on the new SHA.

Untuk perubahan besar:

git range-diff origin/main...backup/before-irebase origin/main...HEAD

Paste ringkasan, bukan dump panjang jika terlalu besar.


27. Recovery Playbook

Jika todo salah dan rebase belum selesai:

git rebase --abort

Jika rebase selesai tapi hasil salah:

git reflog

Cari entry sebelum rebase:

HEAD@{5}: rebase (start): checkout origin/main
HEAD@{6}: commit: previous feature tip

Recover:

git branch recovery/before-bad-irebase HEAD@{6}

Compare:

git range-diff origin/main...recovery/before-bad-irebase origin/main...HEAD

Reset jika yakin:

git reset --hard recovery/before-bad-irebase

Push recovery jika remote sudah terlanjur rewrite:

git push --force-with-lease

Koordinasikan dengan reviewer/collaborator.


28. Visual Mental Model


29. Team Policy Recommendations

A strong team Git handbook should define:

1. Interactive rebase is encouraged before PR review if branch is private.
2. Interactive rebase after review is allowed, but large rewrites require explanation.
3. Protected branches must not be rewritten except by explicit incident/migration procedure.
4. Use --force-with-lease, not --force, for PR branch updates.
5. Autosquash fixup commits before merge unless team intentionally preserves review commits.
6. For large PRs, provide range-diff after major rewrite.
7. Do not hide behavior changes inside refactor cleanup.
8. CI must run on the final rewritten commit SHA.

This turns Git from personal habit into organizational reliability.


30. Lab: Clean a Messy Branch

mkdir /tmp/git-irebase-lab
cd /tmp/git-irebase-lab
git init

echo "base" > app.txt
git add app.txt
git commit -m "Initial app"

git switch -c feature

echo "schema" > schema.sql
git add schema.sql
git commit -m "stuff"

echo "repo" > repo.txt
git add repo.txt
git commit -m "more stuff"

echo "typo" >> schema.sql
git add schema.sql
git commit -m "fix typo"

echo "service" > service.txt
git add service.txt
git commit -m "final"

Buat backup:

git branch backup/before-cleanup

Mulai interactive rebase:

git rebase -i main

Ubah todo menjadi:

reword <schema-commit> stuff
fixup  <typo-commit> fix typo
reword <repo-commit> more stuff
reword <service-commit> final

Target message:

Add schema placeholder
Add repository placeholder
Add service placeholder

Bandingkan:

git log --oneline backup/before-cleanup
git log --oneline HEAD

git range-diff main...backup/before-cleanup main...HEAD

31. Lab: Split a Commit

mkdir /tmp/git-split-commit-lab
cd /tmp/git-split-commit-lab
git init

echo "base" > README.md
git add README.md
git commit -m "Initial commit"

git switch -c feature

echo "schema" > schema.sql
echo "repository" > repository.txt
echo "service" > service.txt
git add .
git commit -m "Implement payment rule feature"

Mulai:

git rebase -i main

Tandai commit sebagai edit.

Saat berhenti:

git reset HEAD^

git add schema.sql
git commit -m "Add payment rule schema"

git add repository.txt
git commit -m "Add payment rule repository"

git add service.txt
git commit -m "Add payment rule service"

git rebase --continue

Verifikasi:

git log --oneline --reverse main..HEAD

32. Engineering Invariant

Interactive rebase yang baik menjaga invariant berikut:

The final branch should express the same intended work as a smaller,
ordered, reviewable, testable, and auditable patch series.

Jika interactive rebase membuat history terlihat bersih tetapi menyembunyikan risiko, itu gagal.

Clean history bukan tujuan utama. Understandable history adalah tujuan utama.


33. Ringkasan

Interactive rebase adalah alat untuk membentuk commit series sebelum history menjadi shared.

Gunakan untuk:

  • reword message;
  • squash/fixup noise;
  • split commit besar;
  • reorder dependency;
  • drop accidental commit;
  • test setiap commit;
  • menyiapkan PR yang reviewer-friendly;
  • meningkatkan bisectability dan auditability.

Jangan gunakan untuk:

  • rewrite protected branch diam-diam;
  • menyembunyikan semantic change;
  • memutihkan history incident;
  • menghapus evidence release;
  • force push tanpa protokol.

Setelah menguasai rebase mental model dan interactive rebase, kamu mulai memperlakukan Git history sebagai artefak engineering, bukan sisa aktivitas coding.

Part berikutnya membahas rebase merges dan topology preservation: kapan linear history tidak cukup, dan bagaimana mempertahankan bentuk graph saat rewrite.


Referensi

  • Git documentation: git rebase
  • Git documentation: git commit --fixup, --squash
  • Pro Git: Git Tools — Rewriting History
  • Pro Git: Git Branching — Rebasing
  • Git documentation: git range-diff
Lesson Recap

You just completed lesson 24 in build core. Use the series map if you want to review the broader track, or continue directly into the next lesson while the context is still warm.

Continue The Track

Keep the momentum while the lesson is still fresh. Move backward for review or continue forward into the next concept.