Mengapa git tidak bisa melakukan hard / soft reset dengan jalur?

142

$ git reset -- <file_path> dapat diatur ulang dengan jalur.

Namun, $ git reset (--hard|--soft) <file_path>akan melaporkan kesalahan seperti di bawah ini:

Cannot do hard|soft reset with paths.
yao
sumber

Jawaban:

147

Karena tidak ada gunanya (perintah lain sudah menyediakan fungsionalitas itu), dan itu mengurangi potensi untuk melakukan hal yang salah secara tidak sengaja.

Sebuah "hard reset" untuk sebuah jalur baru saja selesai dengan git checkout HEAD -- <path>(memeriksa versi file yang ada).

Soft reset untuk jalur tidak masuk akal.

Reset campuran untuk jalur adalah apa git reset -- <path>.

Amber
sumber
76
Secara pribadi, menurut saya git checkout -- <path>harus diganti dengan git reset --hard <path>. Ini jauh lebih masuk akal ...
vergenzt
25
git checkout -- <path>tidak melakukan hard reset; itu menggantikan isi pohon kerja dengan isi bertahap. git checkout HEAD -- <path>melakukan hard reset untuk sebuah jalur, mengganti indeks dan pohon kerja dengan versi dari komit HEAD.
Dan Fabulich
1
@EdPlunkett Er, kalimat kedua dalam jawaban memberi tahu Anda perintah apa yang menyediakan fungsionalitas tersebut.
Amber
17
-1: Checkout untuk revisi tersebut tidak akan menghapus file dari copy pekerjaan jika revisi tersebut berisi file yang dihapus. reset --harddengan jalan akan memberikan potongan yang hilang ini. Git sudah begitu kuat sehingga alasan "Kami tidak membiarkan Anda melakukan ini untuk perlindungan Anda sendiri" tidak berlaku sama sekali: Ada banyak cara untuk melakukan hal yang salah "secara tidak sengaja". Tak satu pun dari yang penting ketika Anda memilikinya git reflog.
void.pointer
1
seperti yang disebutkan oleh @ void.pointer checkout tidak akan menghapus file. Jika Anda menginginkan perilaku itu, lihat jawaban ini . Tetap saja, saya berharap suatu hari kita akan mendapatkannya git reset --hard -- <path>. Ada kasus penggunaan yang sah untuk itu.
Mariusz Pawelski
18

Anda dapat mencapai apa yang Anda coba lakukan dengan menggunakan git checkout HEAD <path>.

Yang mengatakan, pesan kesalahan yang diberikan tidak masuk akal bagi saya (karena git resetberfungsi dengan baik pada subdirektori), dan saya tidak melihat alasan mengapa git reset --hardtidak melakukan apa yang Anda minta.

Aaron Kent
sumber
menggunakan checkout tahap perubahan, yang tidak sama dengan reset --soft
worc
12

Pertanyaan bagaimana sudah dijawab , saya akan menjelaskan bagian mengapa .

Jadi, apa yang dilakukan git reset ? Bergantung pada parameter yang ditentukan, ia dapat melakukan dua hal berbeda:

  • Jika Anda menentukan jalur, itu menggantikan file yang cocok di indeks dengan file dari komit (HEAD secara default). Tindakan ini tidak mempengaruhi pohon kerja sama sekali dan biasanya digunakan sebagai kebalikan dari git add.

  • Jika Anda tidak menentukan jalur, itu akan memindahkan kepala cabang saat ini ke komit yang ditentukan dan, bersama dengan itu , secara opsional menyetel ulang indeks dan pohon kerja ke status komit itu. Ini tambahan perilaku dikendalikan oleh parameter modus:
    --soft : tidak menyentuh indeks dan pohon kerja.
    --mixed (default): mengatur ulang indeks tetapi bukan pohon kerja.
    --hard : setel ulang indeks dan pohon kerja.
    Ada juga opsi lain, lihat dokumentasi untuk daftar lengkap dan beberapa kasus penggunaan.

    Ketika Anda tidak menentukan komit, defaultnya ke HEAD, jadi git reset --softtidak akan melakukan apa-apa, karena ini adalah perintah untuk memindahkan kepala ke HEAD (ke status saat ini). git reset --hard, di sisi lain, masuk akal karena efek sampingnya , dikatakan pindahkan kepala ke HEAD dan setel ulang indeks dan pohon kerja ke HEAD.

    Saya pikir seharusnya sudah jelas sekarang mengapa operasi ini bukan untuk file tertentu berdasarkan sifatnya - ini dimaksudkan untuk memindahkan kepala cabang di tempat pertama, mengatur ulang pohon kerja dan indeks adalah fungsi sekunder.

pengguna
sumber
jelas bahwa reset dimaksudkan untuk memindahkan kepala cabang di tempat pertama, tetapi karena ini memiliki fungsionalitas tambahan untuk mengatur ulang pohon kerja dan indeks untuk seluruh komit dan fungsionalitas mengatur ulang indeks untuk file tertentu, mengapa tidak? memiliki fungsionalitas untuk mengatur ulang pohon kerja untuk file tertentu? Saya yakin itulah yang diminta OP.
Danilo Souza Morães
Mungkin karena fungsionalitas itu (mengatur ulang pohon kerja untuk file tertentu) sudah tersedia sebagai git checkoutperintah? Dan melakukan penyetelan ulang untuk melakukan hal yang sama akan semakin membingungkan pengguna. Jawaban saya adalah --hardopsi itu tidak berlaku untuk file tertentu karena ini adalah mode untuk reset cabang, bukan reset indeks. Dan reset pohon yang berfungsi dinamai checkout, seperti yang dapat Anda baca di jawaban lain. Semua itu hanyalah desain antarmuka pengguna Git yang buruk, IMHO.
pengguna
Membandingkan opsi pertama dengan git checkout: git reset --menyetel indeks saja, sementara git checkout --menyetel pohon kerja saja?
seeker_of_bacon
3

Ada alasan yang sangat penting di balik itu: prinsip checkoutdanreset .

Dalam istilah Git, checkout berarti "membawa ke pohon kerja saat ini". Dan dengan git checkoutkita dapat mengisi pohon kerja dengan data dari area manapun , baik itu dari komit di repositori atau file individual dari komit atau area pementasan (yang bahkan merupakan default).

Sebaliknya, git reset tidak memiliki peran ini. Seperti namanya, ini akan mengatur ulang ref saat ini tetapi selalu memiliki repositori sebagai sumber, terlepas dari "jangkauan" (--soft, --mixed atau --hard).

Rekap:

  • checkout : Dari mana saja (indeks / repo komit) -> pohon kerja
  • reset : Repo commit -> Overwrite HEAD (dan secara opsional indeks dan pohon kerja)

Oleh karena itu, apa yang bisa sedikit membingungkan adalah keberadaan git reset COMMIT -- filessejak "menimpa HEAD" hanya dengan beberapa file tidak masuk akal!

Dengan tidak adanya penjelasan resmi, saya hanya dapat berspekulasi bahwa pengembang git menemukan bahwa resetitu masih merupakan nama terbaik dari sebuah perintah untuk membuang perubahan yang dibuat pada area pementasan dan, mengingat satu-satunya sumber data adalah repositori, maka " mari kita perpanjang fungsionalitas "daripada membuat perintah baru.

Jadi entah bagaimana git reset -- <files>sudah agak luar biasa: itu tidak akan menimpa HEAD. IMHO semua variasi seperti itu akan menjadi pengecualian. Bahkan jika kita dapat membayangkan sebuah --hardversi, versi lain (misalnya --soft) tidak akan masuk akal.

F Pereira
sumber
Saya suka jawaban ini. Sungguh, git reset -- <files>merasa seperti ditambahkan karena ini adalah fitur yang berguna tetapi tidak ada yang yakin di mana perintah itu harus diletakkan. Untungnya sekarang kami memiliki lebih banyak fitur waras git restoreyang memiliki fungsionalitas git checkout -- <path> git checkout <commit> -- <path>dan git reset [<commit>] -- <path>dengan default yang jauh lebih waras dan bahkan lebih banyak fitur yang tidak dapat Anda lakukan sebelumnya (Bertentangan dengan apa yang dikatakan jawaban yang diterima. Sekarang Anda akhirnya dapat dengan mudah memulihkan hanya pohon yang berfungsi, tanpa menyentuh indeks).
Mariusz Pawelski
3

Pastikan Anda memberi garis miring antara origin atau upstream (source) dan cabang sebenarnya:

git reset --hard origin/branch

atau

git reset --hard upstream/branch`
Pascal Nitcheu
sumber
0

Penjelasan

The git resetpengguna daftar 3 cara doa:

  • 2 adalah file-bijaksana: Ini tidak mempengaruhi pohon kerja , tetapi hanya beroperasi pada file dalam indeks yang ditentukan oleh <paths>:

    • git reset [-q] [<tree-ish>] [--] <paths>..
    • git reset (--patch | -p) [<tree-ish>] [--] [<paths>...]
  • 1 adalah komitmen-bijaksana: Beroperasi pada semua file yang direferensikan <commit>, dan dapat mempengaruhi pohon kerja:

    • git reset [<mode>] [<commit>]

Tidak ada mode pemanggilan yang hanya beroperasi pada file tertentu dan memengaruhi pohon kerja.

Solusi

Jika Anda ingin keduanya:

  • Setel ulang versi indeks / cache dari sebuah file
  • Periksa file (yaitu, buat pohon kerja cocok dengan indeks dan versi komit)

Anda dapat menggunakan alias ini di file konfigurasi git Anda:

[alias]
  reco   = !"cd \"${GIT_PREFIX:-.}\" && git reset \"$@\" && git checkout \"$@\" && git status --short #"  # Avoid: "fatal: Cannot do hard reset with paths."

Anda kemudian dapat melakukan salah satu dari:

$ git reco <paths>

$ git reco <branch/commit> <paths>

$ git reco -- <paths>

(Mnenonic untuk reco: reset && check out)

Tom Hale
sumber
-2

git reset --soft HEAD ~ 1 nama file membatalkan komit tetapi perubahan tetap di lokal. nama file bisa - untuk semua file yang dikomit

Peiti Li
sumber
6
fatalCannot do soft reset with paths.
alt