Bagaimana cara memodifikasi komit yang ditentukan?

2233

Saya biasanya mengirimkan daftar komitmen untuk ditinjau. Jika saya memiliki komitmen berikut:

  1. HEAD
  2. Commit3
  3. Commit2
  4. Commit1

... Saya tahu bahwa saya dapat memodifikasi head commit git commit --amend. Tetapi bagaimana saya bisa memodifikasi Commit1, mengingat itu bukan HEADkomit?

Sam Liao
sumber
31
Lihat jawaban alternatif di sini: stackoverflow.com/a/18150592/520567 Jawaban yang Anda terima benar-benar jawaban yang tepat untuk pertanyaan Anda, tetapi jika Anda memiliki komit baru Anda siap sebelum Anda memutuskan untuk menggunakan edit, maka jawaban ini akan lebih mudah. Ini juga dapat bekerja dengan banyak komit yang ingin Anda gabungkan / squash dengan yang lebih lama.
akostadinov
6
Anda juga bisa melihat Membelah komit di Alat Git - Riwayat Penulisan Ulang untuk informasi lebih lanjut.
hakre

Jawaban:

2956

Anda dapat menggunakan git rebase . Misalnya, jika Anda ingin memodifikasi komit bbc643cd, jalankan

$ git rebase --interactive 'bbc643cd^'

Harap perhatikan tanda sisipan ^di akhir perintah, karena Anda harus benar-benar mengubah kembali ke komit sebelum yang Anda ingin modifikasi .

Di editor default, ubah pickke editdalam baris yang menyebutkan 'bbc643cd'.

Simpan file dan keluar: git akan menafsirkan dan secara otomatis menjalankan perintah dalam file. Anda akan menemukan diri Anda dalam situasi sebelumnya di mana Anda baru saja membuat komit bbc643cd.

Pada titik ini, bbc643cdadalah komit terakhir Anda dan Anda dapat dengan mudah mengubahnya : lakukan perubahan lalu komit dengan perintah:

$ git commit --all --amend --no-edit

Setelah itu, ketikkan:

$ git rebase --continue

untuk kembali ke komit HEAD sebelumnya.

PERINGATAN : Perhatikan bahwa ini akan mengubah SHA-1 dari komit itu dan juga semua anak - dengan kata lain, ini menulis ulang sejarah dari titik itu ke depan. Anda dapat memecahkan repo melakukan ini jika Anda menekan menggunakan perintahgit push --force

ZelluX
sumber
125
Opsi lain yang menarik dalam aliran ini adalah setelah Anda pindah ke komit yang ingin Anda modifikasi, alih-alih memodifikasi file dan mengamisi komit di atas (yang Anda edit), Anda mungkin ingin membagi komit itu menjadi dua komit yang berbeda. (atau bahkan lebih). Dalam hal ini, kembali ke komit untuk mengedit, dan jalankan "git reset HEAD ^". yang akan menempatkan file yang dimodifikasi dari komit ke dalam panggung. Sekarang pilih dan lakukan file apa saja sesuai keinginan. Alur ini dijelaskan dengan cukup baik di halaman manual "git-rebase". Lihat bagian "Membagi komit". bit.ly/d50w1M
Diego Pino
200
Dalam Git 1.6.6 dan yang lebih baru, Anda dapat menggunakan rewordtindakan git rebase -isebagai gantinya edit(itu secara otomatis membuka editor dan melanjutkan dengan langkah-langkah rebase lainnya; ini meniadakan penggunaan git commit --ammenddan git rebase --continueketika Anda hanya perlu mengubah pesan komit dan bukan konten. ).
Chris Johnsen
108
Perlu dicatat bahwa Anda mungkin perlu menjalankan git stashsebelum git rebasedan git stash popsesudahnya, jika Anda memiliki perubahan yang tertunda.
user123444555621
3
Apakah ada perintah shortucut untuk mengedit komit tertentu dalam rebase interaktif tanpa membuka editor, menemukan komit, menandainya komit, lalu kembali ke baris perintah?
sstur
15
Perhatikan bahwa dengan git yang lebih baru, akan lebih bijaksana untuk mengikuti instruksi yang cepat daripada menggunakan secara membabi buta di git commit --all --amend --no-editsini. Yang harus saya lakukan setelah git rebase -i ...itu adalah git commit --amendbiasanya git rebase --continue.
Eric Chen
453

Gunakan rebase interaktif yang luar biasa:

git rebase -i @~9   # Show the last 9 commits in a text editor

Temukan komit yang Anda inginkan, ubah pickke e( edit), dan simpan dan tutup file. Git akan mundur ke komitmen itu, memungkinkan Anda untuk:

  • gunakan git commit --amenduntuk membuat perubahan, atau
  • gunakan git reset @~untuk membuang komit terakhir, tetapi bukan perubahan pada file (yaitu membawa Anda ke titik di mana Anda sudah mengedit file, tetapi belum berkomitmen).

Yang terakhir berguna untuk melakukan hal-hal yang lebih kompleks seperti membelah menjadi beberapa komit.

Kemudian, jalankan git rebase --continue, dan Git akan memutar ulang perubahan berikutnya di atas komit Anda yang dimodifikasi. Anda mungkin diminta untuk memperbaiki beberapa konflik penggabungan.

Catatan: @adalah singkatan untuk HEAD, dan ~merupakan komit sebelum komit yang ditentukan.

Baca lebih lanjut tentang penulisan ulang riwayat di dokumen Git.


Jangan takut untuk rebase

ProTip ™: Jangan takut untuk bereksperimen dengan perintah "berbahaya" yang menulis ulang riwayat * - Git tidak menghapus komit Anda selama 90 hari secara default; Anda dapat menemukannya di reflog:

$ git reset @~3   # go back 3 commits
$ git reflog
c4f708b HEAD@{0}: reset: moving to @~3
2c52489 HEAD@{1}: commit: more changes
4a5246d HEAD@{2}: commit: make important changes
e8571e4 HEAD@{3}: commit: make some changes
... earlier commits ...
$ git reset 2c52489
... and you're back where you started

* Hati-hati dengan opsi seperti --harddan --forcemeskipun - mereka dapat membuang data.
* Juga, jangan menulis ulang sejarah di cabang mana pun Anda berkolaborasi.



Pada banyak sistem, git rebase -isecara default akan membuka Vim. Vim tidak berfungsi seperti kebanyakan editor teks modern, jadi lihatlah cara rebase menggunakan Vim . Jika Anda lebih suka menggunakan editor yang berbeda, ubahlah dengan git config --global core.editor your-favorite-text-editor.

Zaz
sumber
29
Di tengah jawaban Anda adalah tempat yang aneh untuk meletakkan apa yang hanya bisa saya gambarkan sebagai iklan miniture untuk VIM. Ini tidak relevan dengan pertanyaan dan hanya mengacaukan jawaban Anda.
Niat
21
@Intentss: Ah, saya bisa melihat mengapa itu tampak aneh. Alasan di balik itu adalah bahwa Vim adalah editor teks default pada banyak sistem, sehingga pengalaman pertama banyak orang dari rebasing interaktif adalah layar di mana mengetik membuat kursor terbang di semua tempat. Kemudian, mereka beralih editor mereka ke sesuatu yang lain, dan pengalaman kedua mereka dari rebasing interaktif cukup normal, tetapi membuat mereka bertanya-tanya mengapa menggunakan file teks bukan GUI. Untuk mencapai aliran dengan rebasing, Anda membutuhkan sesuatu seperti Vim, atau mode rebase Emacs.
Zaz
9
Baik. Melihat begitu banyak orang menemukan bagian itu tidak relevan, saya telah memadatkannya menjadi 3 baris dan juga menjelaskan cara mengubah editor jika perlu.
Zaz
17
Luar biasa! Saya tidak tahu Anda bisa menggunakan @sebagai singkatan HEAD. Terima kasih telah memposting ini.
James Ko
3
git reset @~persis apa yang ingin saya lakukan setelah memilih komit dengan git rebase .... Anda adalah pahlawan saya)
Agustus
79

Rebase interaktif dengan --autosquashsesuatu yang sering saya gunakan ketika saya harus memperbaiki komitmen sebelumnya lebih dalam dalam sejarah. Ini pada dasarnya mempercepat proses yang diilustrasikan jawaban ZelluX, dan sangat berguna ketika Anda memiliki lebih dari satu komit yang perlu Anda edit.

Dari dokumentasi:

--autosquash

Ketika pesan komit dimulai dengan "squash! ..." (atau "fixup! ..."), dan ada komit yang judulnya dimulai dengan yang sama ..., secara otomatis memodifikasi daftar todo rebase -i sehingga komit ditandai untuk squashing datang tepat setelah komit untuk dimodifikasi

Asumsikan Anda memiliki riwayat yang terlihat seperti ini:

$ git log --graph --oneline
* b42d293 Commit3
* e8adec4 Commit2
* faaf19f Commit1

dan Anda memiliki perubahan yang ingin Anda ubah menjadi Commit2 lalu komit perubahan Anda menggunakan

$ git commit -m "fixup! Commit2"

Sebagai alternatif, Anda dapat menggunakan komit-sha alih-alih pesan komit, jadi "fixup! e8adec4atau bahkan hanya awalan dari pesan komit.

Kemudian lakukan rebase interaktif pada komit sebelumnya

$ git rebase e8adec4^ -i --autosquash

editor Anda akan terbuka dengan komit yang sudah dipesan dengan benar

pick e8adec4 Commit2
fixup 54e1a99 fixup! Commit2
pick b42d293 Commit3

yang perlu Anda lakukan hanyalah menyimpan dan keluar

thrau
sumber
21
Anda juga dapat menggunakan git commit --fixup=@~bukan git commit -m "fixup! Commit2". Ini sangat berguna ketika pesan komit Anda lebih panjang dan akan sulit untuk mengetik semuanya.
Zaz
42

Lari:

$ git rebase --interactive commit_hash^

masing-masing ^menunjukkan berapa banyak komit yang ingin Anda edit, jika hanya satu (hash komit yang Anda tentukan), maka Anda tinggal menambahkan satu ^.

Menggunakan Vim Anda mengubah kata-kata pickuntuk reworduntuk komit Anda ingin perubahan, save dan keluar ( :wq). Kemudian git akan meminta Anda dengan setiap komit yang Anda tandai sebagai reword sehingga Anda dapat mengubah pesan komit.

Setiap pesan komit, Anda harus menyimpan dan keluar ( :wq) untuk pergi ke pesan komit berikutnya

Jika Anda ingin keluar tanpa menerapkan perubahan, tekan :q!

EDIT : untuk menavigasi yang vimAnda gunakan juntuk naik, kturun, hke kiri, dan lke kanan (semua ini dalam NORMALmode, tekan ESCuntuk pergi ke NORMALmode). Untuk mengedit teks, tekan iagar Anda masuk ke INSERTmode, tempat Anda memasukkan teks. Tekan ESCuntuk kembali ke NORMALmode :)

UPDATE : Berikut adalah tautan bagus dari daftar github Cara membatalkan (hampir) apa pun dengan git

betoharres
sumber
4
Bekerja dengan sempurna untuk saya. Layak disebutkan git push --force?
u01jmg3
Apa yang git push --forcedilakukan adalah menimpa komit remote dengan komit lokal Anda. Itu bukan kasus topik ini :)
betoharres
@BetuUuUu tentu saja jika komit Anda didorong ke jarak jauh dan Anda telah memodifikasi pesan komit secara lokal, Anda ingin memaksakan dorongan ke jarak jauh, bukan?
Sudip Bhandari
@SudipBhandari Itulah perasaan yang saya dapatkan. Saya tidak memaksa, dan sekarang saya memiliki cabang tambahan, mencerminkan semua komit kembali ke orang yang pesannya saya ubah, yang sangat jelek.
ruffin
2
@ greenhouse jika Anda memodifikasi dan memaksa, maka anggota tim lain kemungkinan besar akan mengalami konflik penggabungan. Jadi, Anda harus sangat berhati-hati tentang hal itu. Tetapi jika Anda memodifikasi sesuatu yang belum diambil orang lain, itu harus baik-baik saja (tidak akan menyadarinya). Jadi saya akan mempertimbangkan - memaksa sebagai pilihan terakhir dan selalu berkonsultasi dengan repo dengan anggota lain.
Tomasz Kaczmarzyk
18

Jika karena alasan tertentu Anda tidak menyukai editor interaktif, Anda dapat menggunakannya git rebase --onto.

Katakanlah Anda ingin memodifikasi Commit1. Pertama, cabang dari sebelumnya Commit1 :

git checkout -b amending [commit before Commit1]

Kedua, ambil Commit1dengan cherry-pick:

git cherry-pick Commit1

Sekarang, ubah perubahan Anda, buat Commit1':

git add ...
git commit --amend -m "new message for Commit1"

Dan akhirnya, setelah menyembunyikan perubahan lain, transplantasi sisa komitmen Anda hingga masterdi atas komitmen baru Anda:

git rebase --onto amending Commit1 master

Baca: "rebase, ke cabang amending, semua komit antara Commit1(tidak inklusif) dan master(inklusif)". Yaitu, Commit2 dan Commit3, memotong Commit1 lama sepenuhnya. Anda bisa saja memetiknya, tetapi cara ini lebih mudah.

Ingatlah untuk membersihkan cabang Anda!

git branch -d amending
Perawatan Feeping
sumber
4
Anda dapat menggunakan git checkout -b amending Commit1~1untuk mendapatkan komit sebelumnya
Arin Taylor
Apakah dua langkah pertama sama dengan git checkout -b amending Commit1?
Haoshu
16

Berdasarkan Dokumentasi

Mengubah pesan dari pesan komit yang lebih tua atau banyak

git rebase -i HEAD~3 

Di atas menampilkan daftar 3 commit terakhir pada cabang saat ini, ubah 3 ke yang lain jika Anda menginginkan lebih. Daftar ini akan terlihat mirip dengan yang berikut:

pick e499d89 Delete CNAME
pick 0c39034 Better README
pick f7fde4a Change the commit message but push the same commit.

Ganti pick dengan reword sebelum setiap pesan komit yang ingin Anda ubah. Katakanlah Anda mengubah komit kedua dalam daftar, file Anda akan terlihat seperti berikut:

pick e499d89 Delete CNAME
reword 0c39034 Better README
pick f7fde4a Change the commit message but push the same commit.

Simpan dan tutup file komit, ini akan memunculkan editor baru bagi Anda untuk mengubah pesan komit Anda, mengubah pesan komit dan menyimpan.

Finaly Angkatan-dorong komitmen diubah.

git push --force
hanya aku
sumber
Saya mendapatkan kesalahan berikut: kesalahan: Ada masalah dengan editor 'vi'. Harap berikan pesan menggunakan opsi -m atau -F.
Erick Maynard
12

Perintah yang sepenuhnya non-interaktif (1)

Saya hanya berpikir saya akan membagikan alias yang saya gunakan untuk ini. Ini didasarkan pada rebase interaktif non-interaktif . Untuk menambahkannya ke git Anda, jalankan perintah ini (penjelasan diberikan di bawah):

git config --global alias.amend-to '!f() { SHA=`git rev-parse "$1"`; git commit --fixup "$SHA" && GIT_SEQUENCE_EDITOR=true git rebase --interactive --autosquash "$SHA^"; }; f'

Keuntungan terbesar dari perintah ini adalah kenyataan bahwa itu tidak ada-vim .


(1) mengingat bahwa tidak ada konflik selama rebase, tentu saja

Pemakaian

git amend-to <REV> # e.g.
git amend-to HEAD~1
git amend-to aaaa1111

Nama itu amend-totampaknya sesuai IMHO. Bandingkan arus dengan --amend:

git add . && git commit --amend --no-edit
# vs
git add . && git amend-to <REV>

Penjelasan

  • git config --global alias.<NAME> '!<COMMAND>'- Membuat alias global git bernama <NAME>yang akan menjalankan perintah non-git<COMMAND>
  • f() { <BODY> }; f - fungsi bash "anonim".
  • SHA=`git rev-parse "$1"`; - Mengonversi argumen menjadi revisi git, dan memberikan hasilnya ke variabel SHA
  • git commit --fixup "$SHA"- fixup-commit untuk SHA. Lihat git-commitdokumen
  • GIT_SEQUENCE_EDITOR=true git rebase --interactive --autosquash "$SHA^"
    • git rebase --interactive "$SHA^" sebagian telah dicakup oleh jawaban lain.
    • --autosquashadalah apa yang digunakan bersamaan dengan git commit --fixup, lihat git-rebasedokumen untuk info lebih lanjut
    • GIT_SEQUENCE_EDITOR=trueadalah apa yang membuat semuanya menjadi non-interaktif. Peretasan ini saya pelajari dari posting blog ini .
Dethariel
sumber
1
Satu juga dapat membuat amend-tomenangani file yang tidak dipentaskan: git config --global alias.amend-to '!f() { SHA=git rev-parse "$ 1"; git stash -k && git commit --fixup "$SHA" && GIT_SEQUENCE_EDITOR=true git rebase --interactive --autosquash "$SHA^" && git stash pop; }; f'
Dethariel
2
Salah satu perhatian dengan metode ini adalah dapat menerapkan perbaikan yang tidak terkait.
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
Bukankah poin dari pertanyaan untuk mengubah pesan komit? Karena jawaban ini tidak membahas itu, atau setidaknya tidak secara langsung.
wytten
@wytten pertanyaannya tidak bertanya tentang mengubah pesan komit, ini tentang memodifikasi komit yang bukan KEPALA. Jadi jawaban untuk pertanyaan Anda adalah "tidak, itu bukan inti dari pertanyaan"
Dethariel
Saya bingung, jadi bagaimana cara mengubah pesan komit?
ggb667
8

Sunting rebase interaktif otomatis diikuti dengan komit kembalikan yang siap untuk dilakukan

Saya menemukan diri saya cukup sering melakukan commit di masa lalu sehingga saya menulis skrip untuk itu.

Inilah alur kerjanya:

  1. git commit-edit <commit-hash>
    

    Ini akan menjatuhkan Anda pada komit yang ingin Anda edit.

  2. Perbaiki dan tampilkan komit sesuai keinginan Anda.

    (Anda mungkin ingin menggunakan git stash saveuntuk menyimpan file yang tidak Anda lakukan)

  3. Ulangi komit dengan --amend, misalnya:

    git commit --amend
    
  4. Lengkapi rebase:

    git rebase --continue
    

Agar cara di atas berfungsi, masukkan skrip di bawah ini ke dalam file yang dapat dieksekusi yang dipanggil git-commit-editdi suatu tempat di $PATH:

#!/bin/bash

set -euo pipefail

script_name=${0##*/}

warn () { printf '%s: %s\n' "$script_name" "$*" >&2; }
die () { warn "$@"; exit 1; }

[[ $# -ge 2 ]] && die "Expected single commit to edit. Defaults to HEAD~"

# Default to editing the parent of the most recent commit
# The most recent commit can be edited with `git commit --amend`
commit=$(git rev-parse --short "${1:-HEAD~}")
message=$(git log -1 --format='%h %s' "$commit")

if [[ $OSTYPE =~ ^darwin ]]; then
  sed_inplace=(sed -Ei "")
else
  sed_inplace=(sed -Ei)
fi

export GIT_SEQUENCE_EDITOR="${sed_inplace[*]} "' "s/^pick ('"$commit"' .*)/edit \\1/"'
git rebase --quiet --interactive --autostash --autosquash "$commit"~
git reset --quiet @~ "$(git rev-parse --show-toplevel)"  # Reset the cache of the toplevel directory to the previous commit
git commit --quiet --amend --no-edit --allow-empty  #  Commit an empty commit so that that cache diffs are un-reversed

echo
echo "Editing commit: $message" >&2
echo
Tom Hale
sumber
7

Datang ke pendekatan ini (dan mungkin persis sama dengan menggunakan rebase interaktif) tetapi bagi saya itu agak mudah.

Catatan: Saya menyajikan pendekatan ini demi ilustrasi apa yang dapat Anda lakukan daripada alternatif sehari-hari. Karena memiliki banyak langkah (dan mungkin beberapa peringatan.)

Katakanlah Anda ingin mengubah komit 0dan Anda sedang aktiffeature-branch

some-commit---0---1---2---(feature-branch)HEAD

Periksa komitmen ini dan buat a quick-branch. Anda juga dapat mengkloning cabang fitur Anda sebagai titik pemulihan (sebelum memulai).

?(git checkout -b feature-branch-backup)
git checkout 0
git checkout -b quick-branch

Anda sekarang akan memiliki sesuatu seperti ini:

0(quick-branch)HEAD---1---2---(feature-branch)

Panggung berubah, sembunyikan yang lainnya.

git add ./example.txt
git stash

Lakukan perubahan dan checkout kembali ke feature-branch

git commit --amend
git checkout feature-branch

Anda sekarang akan memiliki sesuatu seperti ini:

some-commit---0---1---2---(feature-branch)HEAD
           \
             ---0'(quick-branch)

Rebase feature-branchke quick-branch(menyelesaikan konflik di sepanjang jalan). Terapkan simpanan dan hapus quick-branch.

git rebase quick-branch
git stash pop
git branch -D quick-branch

Dan Anda berakhir dengan:

some-commit---0'---1'---2'---HEAD(feature-branch)

Git tidak akan menggandakan (walaupun saya tidak bisa mengatakan sampai sejauh mana) 0 komit ketika rebasing.

Catatan: semua hash komit diubah mulai dari komit yang semula ingin kami ubah.

Olga
sumber
6

Untuk mendapatkan perintah non-interaktif, letakkan skrip dengan konten ini di PATH Anda:

#!/bin/sh
#
# git-fixup
# Use staged changes to modify a specified commit
set -e
cmt=$(git rev-parse $1)
git commit --fixup="$cmt"
GIT_EDITOR=true git rebase -i --autosquash "$cmt~1"

Gunakan dengan mengatur perubahan Anda (dengan git add) dan kemudian jalankan git fixup <commit-to-modify>. Tentu saja, itu akan tetap interaktif jika Anda mendapat konflik.

Pelle Nilsson
sumber
1
Ini bekerja dengan baik. Saya menambahkan beberapa fungsi tambahan untuk melakukan perbaikan sedikit demi sedikit dari pohon kotor untuk menyempurnakan set komit. `dirtydiff = $ (git diff); if ["$ {dirtydiff}"! = ""]; lalu gema "Menyimpan pohon kotor"> & 2; simpanan git; fi;
Simon Feltman
6

git stash+ rebaseotomatisasi

Ketika saya perlu memodifikasi komit lama berkali-kali untuk ulasan Gerrit, saya sudah melakukan:

git-amend-old() (
  # Stash, apply to past commit, and rebase the current branch on to of the result.
  current_branch="$(git rev-parse --abbrev-ref HEAD)"
  apply_to="$1"
  git stash
  git checkout "$apply_to"
  git stash apply
  git add -u
  git commit --amend --no-edit
  new_sha="$(git log --format="%H" -n 1)"
  git checkout "$current_branch"
  git rebase --onto "$new_sha" "$apply_to"
)

GitHub hulu .

Pemakaian:

  • memodifikasi file sumber, tidak perlu git addjika sudah di repo
  • git-amend-old $old_sha

Saya suka ini --autosquashkarena tidak menghancurkan perbaikan yang tidak terkait lainnya.

Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
sumber
Solusi yang sangat bagus, ini harus menjadi opsi default git amenduntuk menerapkan perubahan pada komit tertentu dengan menggunakan simpanan saat ini, sangat pintar!
caiohamamura
5

Saya memecahkan ini,

1) dengan membuat komit baru dengan perubahan yang saya inginkan ..

r8gs4r commit 0

2) saya tahu komit mana yang harus saya gabungkan. yaitu komit 3.

jadi, git rebase -i HEAD~4# 4 mewakili komit terbaru (di sini komit 3 ada di posisi ke-4)

3) dalam rebase interaktif, komit terbaru akan terletak di bagian bawah. itu akan terlihat sama,

pick q6ade6 commit 3
pick vr43de commit 2
pick ac123d commit 1
pick r8gs4r commit 0

4) di sini kita perlu mengatur ulang komit jika Anda ingin bergabung dengan komit tertentu. seharusnya seperti,

parent
|_child

pick q6ade6 commit 3
f r8gs4r commit 0
pick vr43de commit 2
pick ac123d commit 1

setelah mengatur ulang Anda perlu mengganti p pickdengan f( fixup akan bergabung tanpa pesan komit) atau s( squash menggabungkan dengan pesan komit dapat berubah dalam waktu berjalan)

dan kemudian simpan pohonmu.

sekarang bergabung dilakukan dengan komit yang ada.

Catatan: Ini bukan metode yang lebih disukai kecuali Anda mempertahankannya sendiri. jika Anda memiliki ukuran tim besar, itu bukan metode yang dapat diterima untuk menulis ulang pohon git akan berakhir dengan konflik yang Anda tahu tidak akan terjadi. jika Anda ingin menjaga kebersihan pohon dengan komitmen yang lebih sedikit dapat mencoba ini dan jika tim kecilnya tidak disukai .....

Mohideen bin Mohammed
sumber
Ini adalah solusi yang bagus jika Anda tidak ingin melakukan modifikasi langsung selama rebase interaktif.
Dunatotatos
4

Pilihan terbaik adalah menggunakan "perintah rebase interaktif" .

The git rebaseperintah yang sangat kuat. Ini memungkinkan Anda untuk mengedit pesan komit , menggabungkan komit, menyusun ulang mereka ... dll.

Setiap kali Anda mengubah komit, SHA baru akan dibuat untuk setiap komit terlepas dari konten yang akan diubah atau tidak! Anda harus berhati-hati ketika menggunakan perintah ini karena mungkin memiliki implikasi drastis terutama jika Anda bekerja dalam kolaborasi dengan pengembang lain. Mereka mungkin mulai bekerja dengan komit Anda saat Anda rebasing beberapa. Setelah Anda memaksa untuk mendorong komit, mereka akan tidak sinkron dan Anda mungkin mengetahui kemudian dalam situasi yang berantakan. Jadi hati-hati!

Dianjurkan untuk membuat backupcabang sebelum rebasing sehingga setiap kali Anda menemukan hal-hal di luar kendali Anda dapat kembali ke keadaan sebelumnya.

Sekarang bagaimana cara menggunakan perintah ini?

git rebase -i <base> 

-iberdiri untuk "interaktif" . Perhatikan bahwa Anda dapat melakukan rebase dalam mode non-interaktif. ex:

#interactivly rebase the n commits from the current position, n is a given number(2,3 ...etc)
git rebase -i HEAD~n 

HEADmenunjukkan lokasi Anda saat ini (bisa juga nama cabang atau melakukan SHA). The ~nberarti "n beforeé, sehingga HEAD~nakan menjadi daftar 'n' komit sebelum yang Anda sedang.

git rebase memiliki perintah berbeda seperti:

  • patau pickuntuk tetap berkomitmen seperti apa adanya.
  • ratau reword: untuk menyimpan konten komit tetapi ubah pesan komit.
  • satau squash: untuk menggabungkan perubahan komit ini ke komit sebelumnya (komit di atasnya dalam daftar).
  • ... dll.

    Catatan: Lebih baik membuat Git bekerja dengan editor kode Anda untuk membuatnya lebih sederhana. Seperti misalnya jika Anda menggunakan kode visual yang dapat Anda tambahkan seperti ini git config --global core.editor "code --wait". Atau Anda dapat mencari di Google bagaimana menghubungkan Anda dengan editor kode yang Anda sukai dengan GIT.

Contoh git rebase

Saya ingin mengubah 2 komitmen terakhir yang saya lakukan sehingga saya memproses seperti ini:

  1. Tampilkan komitmen saat ini:
    #This to show all the commits on one line
    $git log --oneline
    4f3d0c8 (HEAD -> documentation) docs: Add project description and included files"
    4d95e08 docs: Add created date and project title"
    eaf7978 (origin/master , origin/HEAD, master) Inital commit
    46a5819 Create README.md
    
  2. Sekarang saya gunakan git rebaseuntuk mengubah 2 pesan komit terakhir: $git rebase -i HEAD~2 Ini membuka editor kode dan menunjukkan ini:

    pick 4d95e08 docs: Add created date and project title
    pick 4f3d0c8 docs: Add project description and included files
    
    # Rebase eaf7978..4f3d0c8 onto eaf7978 (2 commands)
    #
    # Commands:
    # p, pick <commit> = use commit
    # r, reword <commit> = use commit, but edit the commit message
    ...
    

    Karena saya ingin mengubah pesan komit untuk 2 commit ini. Jadi saya akan mengetik ratau rewordmenggantikan pick. Kemudian Simpan file dan tutup tab. Catatan yang rebasedieksekusi dalam proses multi-langkah sehingga langkah selanjutnya adalah memperbarui pesan. Perhatikan juga bahwa komit ditampilkan dalam urutan kronologis terbalik sehingga komit terakhir ditampilkan di komit tersebut dan komit pertama di baris pertama dan seterusnya.

  3. Perbarui pesan: Perbarui pesan pertama:

    docs: Add created date and project title to the documentation "README.md"
    
    # Please enter the commit message for your changes. Lines starting
    # with '#' will be ignored, and an empty message aborts the commit.
    ...
    

    simpan dan tutup Edit pesan kedua

    docs: Add project description and included files to the documentation "README.md"
    
    # Please enter the commit message for your changes. Lines starting
    # with '#' will be ignored, and an empty message aborts the commit.
    ...
    

    Simpan dan tutup.

  4. Anda akan mendapatkan pesan seperti ini di akhir rebase: Successfully rebased and updated refs/heads/documentationyang berarti Anda berhasil. Anda dapat menampilkan perubahan:

    5dff827 (HEAD -> documentation) docs: Add project description and included files to the documentation "README.md"
    4585c68 docs: Add created date and project title to the documentation "README.md"
    eaf7978 (origin/master, origin/HEAD, master) Inital commit
    46a5819 Create README.md
    

    Saya berharap ini dapat membantu pengguna baru :).

DINA TAKLIT
sumber
2

Bagi saya itu untuk menghapus beberapa kredensial dari repo. Saya mencoba rebasing dan bertemu dengan banyak konflik yang tampaknya tidak berhubungan sepanjang jalan ketika mencoba untuk rebase - lanjutkan. Jangan repot-repot mencoba rebase sendiri, gunakan alat yang disebut BFG (brew install bfg) di mac.

Pelet
sumber
0

Jika Anda belum mendorong komit maka Anda dapat kembali ke komit sebelumnya menggunakan git reset HEAD^[1,2,3,4...]

Sebagai contoh

git commit <file1> -m "Updated files 1 and 2"
git commit <file3> -m "Updated file 3"

Ups, lupa menambahkan file2 ke komit pertama ...

git reset HEAD^1 // because I only need to go back 1 commit

git add <file2>

Ini akan menambahkan file2 ke komit pertama.

rharvey
sumber
0

Nah, solusi ini mungkin terdengar sangat konyol, tetapi dapat menyelamatkan Anda dalam kondisi tertentu.

Seorang teman saya secara tidak sengaja melakukan beberapa file besar (empat file yang dihasilkan secara otomatis, masing-masing berukuran antara 3GB hingga 5GB) dan kemudian membuat beberapa kode tambahan sebelum menyadari masalah yang git pushtidak berfungsi lagi!

File-file telah terdaftar .gitignoretetapi setelah mengganti nama folder kontainer, mereka terkena dan berkomitmen! Dan sekarang ada beberapa komitmen lebih dari kode di atas itu, tetapi pushberjalan selamanya (mencoba mengunggah data GB!) Dan akhirnya akan gagal karena batas ukuran file Github .

Masalah dengan rebase interaktif atau yang serupa adalah bahwa mereka akan berurusan dengan mencari-cari file besar ini dan akan mengambil selamanya untuk melakukan apa pun. Namun demikian, setelah menghabiskan hampir satu jam di CLI, kami tidak yakin apakah file (dan delta) benar-benar dihapus dari sejarah atau tidak dimasukkan dalam komitmen saat ini. Dorongan itu tidak berhasil dan teman saya benar-benar macet.

Jadi, solusi yang saya temukan adalah:

  1. Ganti nama folder git saat ini menjadi ~/Project-old.
  2. Klon folder git lagi dari github (ke ~/Project).
  3. Checkout ke cabang yang sama.
  4. Secara manual cp -rfile dari ~/Project-oldfolder ke ~/Project.
  5. Pastikan file besar, yang tidak perlu diperiksa adalah mved, dan dimasukkan .gitignoredengan benar.
  6. Pastikan juga Anda tidak menimpa .gitfolder yang baru saja dikloning ~/Projectoleh yang lama. Di situlah log sejarah yang bermasalah tinggal!
  7. Sekarang tinjau perubahannya. Itu harus merupakan gabungan dari semua commit terbaru, tidak termasuk file yang bermasalah.
  8. Akhirnya komit perubahan, dan senang bisa pushdiedit.

Masalah terbesar dengan solusi ini adalah, ini berkaitan dengan menyalin beberapa file secara manual, dan juga menggabungkan semua commit terbaru menjadi satu (jelas dengan hash-commit baru.) B

Manfaat besar adalah, sangat jelas dalam setiap langkah, ini bekerja sangat baik untuk file besar (serta yang sensitif) , dan tidak meninggalkan jejak dalam sejarah!

Aidin
sumber