Mercurial: bagaimana mengubah komit terakhir?

211

Saya mencari counter-part git commit --amenddi Mercurial, yaitu cara untuk mengubah komit yang terkait dengan copy pekerjaan saya. Saya hanya tertarik pada komit terakhir, bukan komit sebelumnya yang arbitrer.

Persyaratan untuk mengubah prosedur ini adalah:

  • jika memungkinkan, seharusnya tidak memerlukan ekstensi apa pun. Itu harus tidak memerlukan ekstensi non-standar , yaitu ekstensi yang tidak datang dengan instalasi Mercurial resmi.

  • jika komit untuk mengubah adalah salah satu kepala cabang saya saat ini, tidak ada kepala baru yang harus dibuat. Jika komit bukan head, head baru dapat dibuat.

  • prosedur harus aman dengan cara bahwa jika karena alasan apa pun perubahan gagal, saya ingin memiliki copy pekerjaan dan keadaan repositori yang sama dipulihkan seperti sebelum perubahan. Dengan kata lain, jika amandemen itu sendiri dapat gagal, harus ada prosedur gagal-aman untuk mengembalikan copy pekerjaan dan keadaan repositori. Saya mengacu pada "kegagalan" yang terletak pada sifat amend-prosedur (seperti misalnya konflik), bukan untuk masalah terkait sistem file (seperti pembatasan akses, tidak dapat mengunci file untuk menulis, ... )

Pembaruan (1):

  • prosedur harus automatable , sehingga dapat dilakukan oleh klien GUI tanpa diperlukan interaksi pengguna.

Pembaruan (2):

  • file dalam direktori kerja tidak boleh disentuh (mungkin ada kunci sistem file pada file yang dimodifikasi tertentu). Ini terutama berarti, bahwa pendekatan yang mungkin mungkin tidak memerlukan direktori kerja yang bersih.
mstrap
sumber

Jawaban:

289

Dengan rilis Mercurial 2.2 , Anda dapat menggunakan --amendopsi dengan hg commituntuk memperbarui komit terakhir dengan direktori kerja saat ini

Dari referensi baris perintah :

Bendera --amend dapat digunakan untuk mengubah induk dari direktori kerja dengan komit baru yang berisi perubahan pada induk di samping yang saat ini dilaporkan oleh status hg, jika ada. Komit lama disimpan dalam bundel cadangan di .hg / strip-backup (lihat hg bantuan bundel dan hg membantu melepaskan ikatan tentang cara mengembalikannya).

Pesan, pengguna dan tanggal diambil dari komit yang diamandemen kecuali ditentukan. Ketika pesan tidak ditentukan pada baris perintah, editor akan terbuka dengan pesan dari komit yang diubah.

Yang hebat adalah bahwa mekanisme ini "aman", karena ia bergantung pada fitur "Fase" yang relatif baru untuk mencegah pembaruan yang akan mengubah riwayat yang sudah tersedia di luar repositori lokal.

Chris Phillips
sumber
2
Jawaban yang bagus! Ekstensi evolusi eksperimental memungkinkan Anda mengubah amandemen tanpa kepala secara aman . Komit lama akan ditandai usang dan disembunyikan. Dengan server non-penerbitan, Anda bahkan dapat melakukan ini dengan aman setelah Anda mendorong perubahan.
Martin Geisler
5
Untuk hanya memperbarui pesan pada komit terakhir: hg commit --amend -m "ini pesan baru saya"
Jay Sheth
52

Anda memiliki 3 opsi untuk mengedit komit di Mercurial:

  1. hg strip --keep --rev -1batalkan komit terakhir, sehingga Anda dapat melakukannya lagi (lihat jawaban ini untuk informasi lebih lanjut).

  2. Menggunakan ekstensi MQ , yang dikirimkan bersama Mercurial

  3. Bahkan jika itu tidak dikirim dengan Mercurial, ekstensi Histedit layak disebutkan

Anda juga dapat melihat halaman Editing History dari wiki Mercurial.

Singkatnya, pengeditan riwayat sangat sulit dan tidak dianjurkan . Dan jika Anda sudah mendorong perubahan Anda, hampir tidak ada yang dapat Anda lakukan, kecuali jika Anda memiliki kontrol penuh terhadap semua klon lainnya.

Saya tidak terlalu terbiasa dengan git commit --amendperintah itu, tetapi AFAIK, Histedit adalah pendekatan yang tampaknya paling dekat, tetapi sayangnya itu tidak dikirimkan bersama Mercurial. MQ sangat rumit untuk digunakan, tetapi Anda dapat melakukan hampir semua hal dengan itu.

krtek
sumber
1
Saya tidak yakin mengapa saya melewatkan rollback, tetapi tampaknya melakukan (hampir) apa yang saya inginkan. Satu-satunya masalah adalah, ketika sebuah file telah dihapus untuk komit asli saya dan telah dibangkitkan untuk komit saya diubah: sebelum rollback itu akan tidak berversi, setelah rollback, itu akan dijadwalkan untuk dihapus (tetapi file itu masih ada di direktori kerja)
mstrap
@Marc Saya tidak yakin saya mengerti masalah Anda, tetapi lihatlah pada perintah forget, saya pikir itulah yang Anda cari.
krtek
Saya tidak berpikir "lupa" akan membantu di sini. Inilah masalahnya secara lebih rinci: (1) Saya sedang revisi 2 (2) Hapus "file" dan ada beberapa perubahan lainnya (3) Komit perubahan, sehingga revisi 3 (4) Sekarang saya akan berubah pikiran dan memutuskan "file" tidak boleh dihapus dari komit, jadi saya ingin mengubah revisi 3. Karenanya, saya akan menambahkan kembali "file" yang sekarang tidak berversi (5) Sekarang saya melakukan rollback: itu akan mengatur ulang dirstate dan tandai " file "seperti yang dihapus. (6) Saat melakukan "hg commit" lagi sekarang, "file" akan tetap dihapus, meskipun seharusnya tidak lagi. Bagaimana perbaikan otomatis untuk itu terlihat?
mstrap
1
Untuk bagian otomatis saya tidak tahu, tetapi Anda bisa lakukan hg revert myfileuntuk membatalkan penghapusan. Mungkin menambahkan kembali dengan hg addfile setelah rollbackjuga berfungsi.
krtek
3
Saya setuju bahwa pengeditan riwayat perubahan yang dipublikasikan harus dihindari, tetapi pengeditan riwayat lokal saya adalah salah satu hal penting dari DVCS. MQ dengan qimportnya adalah penyuntingan riwayat murni, AFAICT.
mstrap
38

Setara GUI untuk hg commit --amend:

Ini juga berfungsi dari GUI TortoiseHG (Saya menggunakan v2.5):

Swich ke tampilan 'Komit' atau, di tampilan meja kerja, pilih entri 'direktori kerja'. Tombol 'Komit' memiliki opsi bernama 'Ubah revisi saat ini' (klik panah tarik-turun tombol untuk menemukannya).

masukkan deskripsi gambar di sini

          ||
          ||
          \/

masukkan deskripsi gambar di sini

Kaisar peringatan :

Opsi tambahan ini hanya akan diaktifkan jika versi lincah setidaknya 2.2.0, dan jika revisi saat ini tidak bersifat publik, bukan tambalan dan tidak memiliki anak. [...]

Mengklik tombol akan memanggil 'komit - ubah' untuk 'mengubah' revisi.

Info lebih lanjut tentang ini di saluran dev THG

Cristian Diaconescu
sumber
Terima kasih banyak. THG cukup pintar untuk secara default pesan komit (ubah) ke pesan dari komit sebelumnya - hanya apa yang saya inginkan.
UuDdLrLrSs
7

Saya selaras dengan apa yang telah ditulis krtek. Lebih khusus solusi 1:

Asumsi:

  • Anda telah melakukan satu perubahan (!) tetapi belum mendorongnya
  • Anda ingin memodifikasi perubahan ini (mis. menambah, menghapus atau mengubah file dan / atau pesan komit)

Larutan:

  • gunakan hg rollbackuntuk membatalkan komit terakhir
  • komit lagi dengan perubahan baru di tempat

Kembalikan benar-benar membatalkan operasi terakhir. Caranya cukup sederhana: operasi normal di HG hanya akan ditambahkan ke file; ini termasuk komit. Mercurial melacak panjang file dari transaksi terakhir dan karena itu dapat sepenuhnya membatalkan satu langkah dengan memotong file kembali ke panjang sebelumnya.

Lucero
sumber
1
Terima kasih atas solusi penyetelan (1); hanya ada masalah kecil yang tersisa dengan rollback, silakan lihat komentar saya di solusi krtek.
mstrap
8
Satu hal yang perlu ditekankan pada rollback, karena menarik perhatian orang, adalah transaksi terakhir pada repo yang dibatalkan, bukan komit terakhir. Jadi, jika ada hal lain yang menyebabkan penulisan ke repo, kembalikan tidak akan membantu. Ini hal yang halus tetapi penting untuk diingat. MQ dan histedit dapat membantu setelah jendela rollback ditutup, tetapi masih hanya sampai pada titik tertentu.
Paul S
7

Dengan asumsi bahwa Anda belum menyebarkan perubahan Anda, inilah yang dapat Anda lakukan.

  • Tambahkan ke .hgrc Anda:

    [extensions]
    mq =
    
  • Dalam repositori Anda:

    hg qimport -r0:tip
    hg qpop -a
    

    Tentu saja Anda tidak perlu memulai dengan revisi nol atau pop semua patch, untuk cukup satu pop ( hg qpop) sudah cukup (lihat di bawah).

  • hapus entri terakhir dalam .hg/patches/seriesfile, atau tambalan yang tidak Anda sukai. Pengubahan urutan juga dimungkinkan.

  • hg qpush -a; hg qfinish -a
  • hapus .difffile - file (patch yang belum diaplikasikan) yang masih dalam .hg / patch (harus ada dalam case Anda).

Jika Anda tidak ingin untuk mengambil kembali semua patch Anda, Anda dapat mengeditnya dengan menggunakan hg qimport -r0:tip(atau serupa), kemudian mengedit hal-hal dan menggunakan hg qrefreshuntuk menggabungkan perubahan ke dalam patch paling atas pada stack Anda. Baca hg help qrefresh.

Dengan mengedit .hg/patches/series, Anda bahkan dapat menghapus beberapa tambalan, atau menyusun ulang sebagian. Jika revisi terakhir Anda adalah 99, Anda dapat menggunakannya hg qimport -r98:tip; hg qpop; [edit series file]; hg qpush -a; hg qfinish -a.

Tentu saja, prosedur ini sangat tidak dianjurkan dan berisiko . Buat cadangan semua sebelum Anda melakukan ini!

Sebagai seorang sidenote, saya telah melakukannya miliaran kali pada repositori khusus-pribadi.

hochl
sumber
Saya juga telah mempertimbangkan untuk menggunakan mq-extension, tetapi membutuhkan cukup banyak operasi yang beberapa di antaranya mungkin gagal (misalnya jika file biner terlibat). Selain itu, harus mengedit .hg / patch / series tidak akan dapat diterima, karena prosedur ini harus digunakan dalam klien GUI (Saya telah memperbarui persyaratan di atas)
mstrap
Hmmm, maaf ini bukan untuk Anda, di repositori pribadi ini benar-benar tendangan (dengan cadangan - saya sudah gemuk-hancur rep dengan itu ^^). Cukup keren untuk menggabungkan tambalan menjadi satu sebelum mendorong perubahan lokal menggunakan hg qfold, btw
hochl
+1 untuk menggunakan MQ, tapi saya pikir Anda sudah berlebihan. Dia hanya bertanya tentang mengubah komit terakhir. Impor itu juga akan lunas begitu menyentuh gabungan. 'qimport -r tip; <edit barang>; qrefresh -e; qfin -a 'akan melakukan pekerjaannya (-e untuk mengedit pesan commit)
Paul S
benar, gabungan adalah masalah, saya biasanya hanya memunculkan satu tambalan dan digunakan hg import -r<prev>:tip. Sayangnya tidak ada jalan pintas untuk versi sebelumnya, seperti di subversi.
hochl
2

Versi terbaru dari Mercurial termasuk evolveekstensi yang menyediakan hg amendperintah. Ini memungkinkan untuk mengubah komit tanpa kehilangan riwayat pra-ubah dalam kontrol versi Anda.

hg ubah [OPSI] ... [FILE] ...

alias: menyegarkan

menggabungkan perubahan dengan pembaruan dan menggantinya dengan yang baru

Commits a new changeset incorporating both the changes to the given files
and all the changes from the current parent changeset into the repository.

See 'hg commit' for details about committing changes.

If you don't specify -m, the parent's message will be reused.

Behind the scenes, Mercurial first commits the update as a regular child
of the current parent. Then it creates a new commit on the parent's
parents with the updated contents. Then it changes the working copy parent
to this new combined changeset. Finally, the old changeset and its update
are hidden from 'hg log' (unless you use --hidden with log).

Lihat https://www.mercurial-scm.org/doc/evolution/user-guide.html#example-3-amend-a-changeset-with-evolve untuk deskripsi lengkap evolveekstensi.

Karl Bartel
sumber
Menggunakan kembali pesan komit yang sama adalah fitur yang bagus!
buka
1

Mungkin tidak menyelesaikan semua masalah dalam pertanyaan awal, tetapi karena ini tampaknya menjadi pos de facto tentang bagaimana mercurial dapat mengubah komitmen sebelumnya, saya akan menambahkan informasi senilai 2 sen saya.

Jika Anda seperti saya, dan hanya ingin mengubah pesan komit sebelumnya (memperbaiki kesalahan ketik dll) tanpa menambahkan file, ini akan berfungsi

hg commit -X 'glob:**' --amend

Tanpa menyertakan atau mengecualikan pola hg commitakan secara default menyertakan semua file dalam direktori kerja. Pola penerapan -X 'glob:**'akan mengecualikan semua file yang mungkin, hanya memungkinkan untuk mengubah pesan komit.

Secara fungsional sama dengan git commit --amendketika tidak ada file dalam indeks / stage.

kaskelotti
sumber
0

Solusi lain bisa menggunakan uncommitperintah untuk mengecualikan file tertentu dari komit saat ini.

hg uncommit [file/directory]

Ini sangat membantu ketika Anda ingin menjaga komit saat ini dan membatalkan beberapa file dari komit (terutama bermanfaat untuk yang files/directoriestelah dihapus).

Sam Liao
sumber