Batalkan bagian dari perubahan git yang tidak dipentaskan

158

Bagaimana cara membatalkan bagian dari perubahan git saya yang tidak dipentaskan, tetapi membiarkan sisanya sebagai tidak panggung? Cara saya menemukan adalah:

git commit --interactive
# Choose the parts I want to delete
# Commit the changes
git stash
git rebase -i master # (I am an ancestor of master)
# Delete the line of the most recent commit
git stash apply

Ini berfungsi, tetapi alangkah baiknya jika ada sesuatu seperti git commit --interactivehanya untuk mengembalikan perubahan. Adakah metode yang lebih baik?

penilai
sumber

Jawaban:

265

Anda dapat menggunakan git checkout -p, yang memungkinkan Anda memilih setiap bakhil dari perbedaan antara copy pekerjaan Anda dan indeks untuk dikembalikan. Demikian juga, git add -pmemungkinkan Anda untuk memilih bakhil untuk ditambahkan ke indeks, dan git reset -pmemungkinkan Anda untuk memilih bakhil individual dari perbedaan antara indeks dan HEAD untuk mundur dari indeks.

$ git checkout -p file/to/partially/revert
# or ...
$ git checkout -p .

Jika Anda ingin memotret repositori git Anda sebelumnya untuk menyimpan perubahan ini sebelum mengembalikannya, saya ingin melakukannya:

$ git stash; git stash apply

Jika Anda sering menggunakannya, Anda mungkin ingin menggunakannya:

[alias]
    checkpoint = !git stash; git stash apply

Mengembalikan bakhil atau garis individual dapat lebih mudah jika Anda menggunakan mode atau plugin editor yang baik, yang dapat memberikan dukungan untuk memilih jalur yang akan dikembalikan secara langsung, karena -pterkadang terkadang agak canggung untuk digunakan. Saya menggunakan Magit , mode Emacs yang sangat membantu untuk bekerja dengan Git. Di Magit, Anda dapat menjalankan magit-status, menemukan perbedaan untuk perubahan yang ingin Anda kembalikan, pilih garis yang ingin Anda kembalikan (atau cukup tempatkan kursor pada bakhil yang ingin Anda kembalikan jika Anda ingin mengembalikan sebongkah pada suatu waktu alih-alih satu baris pada satu waktu), dan tekan kuntuk mengembalikan garis-garis tertentu. Saya sangat merekomendasikan Magit jika Anda menggunakan Emacs.

Brian Campbell
sumber
Saya pikir ini sama rumitnya dengan solusi yang awalnya saya buat, tapi saya pikir solusi asli saya memiliki manfaat menyelamatkan garis yang dihapus selama 30 hari karena mereka berkomitmen. Saya berpikir mungkin akan lebih baik untuk memiliki skrip shell yang ditulis di sekitarnya.
penanggung jawab
1
Maaf, saya baru sadar itu git checkoutjuga memiliki -pbendera, yang melakukan persis apa yang Anda minta dalam satu perintah. Permintaan maaf untuk serangkaian langkah kompleks sebelumnya; Anda bisa menggunakannya git checkout -p. Sejauh menyimpan barang, sebelum melakukan sesuatu yang berpotensi merusak, saya sering melakukan git stash; git stash apply(atau membuat alias yang melakukan itu git checkpointatau sesuatu) untuk merekam pohon saat ini di simpanan sehingga saya bisa kembali ke pohon itu jika ada yang salah.
Brian Campbell
Ini dia solusinya! Sejauh alias, saya pikir sesuatu seperti git commit -a -m "Backup Commit" --edit; git reset HEAD^ akan lebih baik, karena dengan begitu tidak akan mengotori keadaan simpanan saya, yang mungkin saya gunakan untuk sesuatu yang lain. Kemudian, selama Anda memiliki SHA1, Anda dapat memilihnya dalam 30 hari ke depan. --Edit memungkinkan Anda menambahkan info ke pesan komit untuk membantu Anda menemukan SHA1 nanti jika Anda menginginkannya. Di sisi lain, ini akan mengotori reflog git, jadi saya kira itu adalah tradeoff berdasarkan apa yang Anda lakukan.
penanggung jawab
Alias ​​pos pemeriksaan tidak berfungsi untuk saya: hanya perintah pertama yang dijalankan, bukan yang kedua. Itu menyedihkan, karena saya akan menyukainya. Saya menggunakan git versi 1.7.10.4.
Fabien
Apakah ada cara untuk membuat git checkout -ptidak menerapkan tambalan ke indeks tetapi hanya menampilkannya?
Geremia
28
git diff > patchfile

Kemudian edit patchfile dan hapus bagian yang tidak ingin Anda batalkan, lalu:

patch -R < patchfile
octoberblu3
sumber
6
Namun, jawaban ini sangat mengagumkan dalam kesederhanaan dan kemudahan penggunaannya. +1
tholy
Yang dihasilkan patchfiletampak hebat di vim dan itu sangat membantu!
Bily
Sempurna. Dapat mengkonfirmasi juga berfungsi di bawah Windows dengan Cygwin dan Ubuntu bash for windows.
Checo R
1
Catatan, Anda juga dapat menggunakan git apply -Rsebagai gantinya patch(hanya untuk tetap berada di ranah git, atau jika patchtidak tersedia)
user1556435
patch: **** malformed patch at line 41: @@ -428,9 +443,9 @@ you should place your code here."
HappyFace
5

Anda bisa melakukannya

git checkout master -- path/to/file

Untuk setiap file yang ingin Anda atur ulang.

Drew Hoskins
sumber
Atau gunakan KEPALA di tempat master jika bekerja di cabang. Seperti yang tertulis di laporan 'git status' (setidaknya dalam versi terbaru).
Jonathan Leffler
1

Bagaimana tentang

  1. Mundur file yang terpengaruh dengan perubahan dari indeks
  2. gunakan git add -puntuk hanya menambahkan kembali perubahan yang Anda inginkan ke indeks.
Abizern
sumber
1

Ketika saya menjalankan 'git status', ia mengatakan:

$ git status
# On branch fr/fr.002
# Changed but not updated:
#   (use "git add <file>..." to update what will be committed)
#   (use "git checkout -- <file>..." to discard changes in working directory)
#
#   modified:   makefile
#
no changes added to commit (use "git add" and/or "git commit -a")
$

Jadi, untuk membatalkan pengeditan yang tidak dipentaskan, saya disuruh menjalankan:

git checkout -- makefile
Jonathan Leffler
sumber
3
Saya pikir dia bertanya-tanya tentang cara mengembalikan bakhil individual, bukan seluruh file sekaligus. Ini, tentu saja, solusinya jika Anda hanya perlu membatalkan semua perubahan dalam file.
Brian Campbell
Yup - Saya curiga Anda benar. Opsi 'git checkout -p' dan 'git add -p' tampaknya seperti yang diinginkan - seperti yang Anda katakan.
Jonathan Leffler
1

Jawaban Brian Campbell membuat crash git saya, versi 1.9.2.msysgit.0, karena alasan yang tidak diketahui, jadi pendekatan saya adalah mem-stage hunks yang ingin saya pertahankan, membuang perubahan pada copy pekerjaan, lalu unstage.

$ git add -p
   ... select the hunks to keep
$ git checkout -- .
$ git reset HEAD .
G-Wiz
sumber
1
Ada juga git stash -p. Anda bisa melakukannya git stash -p; git reset --hard; git stash pop. Ini secara efektif sama dengan apa yang Anda lakukan kecuali Anda tidak perlu menulis pesan komit.
penanggung jawab
@asmeurer bersorak. Milik saya tidak memerlukan pesan komit, tetapi mungkin lebih masuk akal untuk menggunakan simpanan daripada indeks untuk ini.
G-Wiz
0

Anda dapat melakukan git checkoutdan memberinya nama nama bagian yang ingin Anda batalkan.

Andrew
sumber