Pindahkan penunjuk cabang ke komit yang berbeda tanpa checkout


760

Untuk memindahkan pointer cabang dari cabang yang diperiksa, seseorang dapat menggunakan git reset --hardperintah. Tetapi bagaimana cara memindahkan pointer cabang dari cabang yang tidak diperiksa untuk menunjuk komit yang berbeda (menjaga semua hal lain seperti cabang jarak jauh yang dilacak)?


11
Kedengarannya seperti yang Anda ingin lakukan adalah cabang dari komit yang berbeda dari yang dibuat sekarang. Jika pemahaman saya benar, mengapa Anda tidak membuat cabang baru dari komit yang ingin Anda buat menggunakan git branch <branch-name> <SHA-1-of-the-commit>dan membuang cabang lama?
yasouser

6
@Yasouser - Saya tidak yakin apa pun membuang "master" cabang adalah ide bagus.
Bulwersator

Jawaban:


578

Anda dapat melakukannya untuk referensi sewenang-wenang. Ini adalah cara memindahkan pointer cabang:

git update-ref -m "reset: Reset <branch> to <new commit>" refs/heads/<branch> <commit>

Bentuk umum:

git update-ref -m "reset: Reset <branch> to <new commit>" <ref> <commit>

Anda dapat memilih nits tentang pesan reflog jika Anda mau - saya yakin yang branch -fsatu berbeda dengan yang lain reset --hard, dan ini bukan keduanya.


39
Di mana pesan bagusnya? Di mana itu disimpan dan bagaimana cara membacanya nanti?
Mot

4
CATATAN: Ini tidak berfungsi pada repositori kosong. Pada repositori kosong, Anda harus menggunakan 'git branch -f master <commit>' untuk memperbarui cabang (lihat jawaban di bawah).
Juni Rhodes

37
Jika, seperti saya, Anda secara tidak sengaja menggunakan <branch> alih-alih referensi / kepala / <branch>, Anda akan berakhir dengan file baru di direktori .git Anda di .git / <branch>, dan Anda akan mendapatkan pesan seperti "refname 'master' ambigu" ketika Anda mencoba bekerja dengannya. Anda dapat menghapus file dari direktori .git Anda untuk memperbaikinya.
David Minor

34
Belum dijelaskan mengapa ini lebih baik daripada memuaskan git branch -f. Untuk lebih spesifik, metode ini tampaknya: (A) lebih sulit untuk digunakan (B) lebih sulit untuk diingat, dan (C) lebih berbahaya
Steven Lu

10
"apa sebenarnya yang dimaksud dengan referensi yang sewenang-wenang" - Cabang bukan satu-satunya jenis referensi yang menunjukkan komit. Ada tag, dan Anda juga dapat membuat referensi / whatevs / myref gaya arbitrer sendiri yang bukan cabang atau tag. Saya percaya itu juga menjawab pertanyaan Steven Lu tentang apa ini "lebih baik". Saya setuju branch -f paling sederhana jika Anda bekerja dengan branch.
Adam A

964
git branch -f <branch-name> <new-tip-commit>

24
Atau untuk referensi yang sewenang-wenang git update-ref -m "reset: Reset <branch> to <new commit>" <branch> <commit>,. (Anda dapat memilih nits tentang pesan reflog jika Anda mau - Saya percaya yang branch -fsatu berbeda dengan yang lain reset --hard, dan ini bukan salah satu dari keduanya.)
Cascabel

4
Jefromi, tolong tulis jawaban terpisah sehingga Anda bisa mendapatkan suara. :)
Mot

16
Ini adalah jawaban yang lebih baik karena menangani kasus 99% dan benar-benar sesuai dengan dokumentasi. git help branchmengatakan "-f, --force Reset <branchname> ke <startpoint> jika <branchname> sudah ada. Tanpa -f cabang git menolak untuk mengubah cabang yang ada."
AlexChaffee

12
Saya lakukan git branch -f master <hash>dan ia memberi tahu saya fatal: Cannot force update the current branch.Ummmm saya harus melakukan apa sekarang, periksa beberapa cabang acak lain sebelum saya diizinkan untuk menggunakan perintah ini?
Qwertie

20
Ini tidak akan berfungsi jika cabang yang Anda coba pindahkan adalah cabang Anda saat ini ( HEADmenunjuk ke sana).
Vladimir Panteleev

135

Anda juga dapat melewati git reset --hardreferensi komit.

Sebagai contoh:

git checkout branch-name
git reset --hard new-tip-commit

Saya menemukan saya melakukan sesuatu seperti ini secara semi-sering:

Dengan asumsi sejarah ini

$ git log --decorate --oneline --graph
* 3daed46 (HEAD, master) New thing I shouldn't have committed to master
* a0d9687 This is the commit that I actually want to be master

# Backup my latest commit to a wip branch
$ git branch wip_doing_stuff

# Ditch that commit on this branch
$ git reset --hard HEAD^

# Now my changes are in a new branch
$ git log --decorate --oneline --graph
* 3daed46 (wip_doing_stuff) New thing I shouldn't have committed to master
* a0d9687 (HEAD, master) This is the commit that I actually want to be master

Ini paling masuk akal karena biasanya orang menggunakan HEAD atau HEAD ^ untuk memindahkan ujung cabang ke masa lalu. Jadi ini konsisten untuk menentukan komit ke depan.
justingordon

11
Ini bagus jika pohon kerja Anda bersih. Jika Anda memiliki banyak perubahan bertahap atau tidak bertahap, mungkin lebih baik melakukannya git update-refseperti yang dibahas di atas.
kutu buku yang dibayar

16
Apakah Anda memperhatikan bahwa "jawaban" Anda tidak menambahkan apa pun yang bukan merupakan bagian dari pertanyaan ?? - OP mengatakan: jika dicentang ... Anda dapat menggunakan git reset --hard ...Tidak perlu mengulanginya di sini! :-(
Robert Siemer

6
@Robert: Saya tidak setuju. Pertanyaannya tidak mengatakan bagaimana menggunakannya dan ini benar. Senang rasanya tidak harus pergi mencari bagaimana caranya.
Wilson F

7
@ WillsonF, mungkin itu baik bagi Anda untuk menemukan ini di sini, tetapi tidak menjawab pertanyaan sama sekali. Mungkin itu adalah jawaban dari beberapa pertanyaan lain, tetapi ini salah .
Robert Siemer

52

Hanya untuk memperkaya diskusi, jika Anda ingin memindahkan myBranchcabang ke komit Anda saat ini , cukup hapus argumen kedua setelahnya-f

Contoh:

git branch -f myBranch


Saya biasanya melakukan ini ketika saya rebasedalam keadaan HEAD Terpisah :)


13

Dalam gitk --all:

  • klik kanan pada komit yang Anda inginkan
  • -> buat cabang baru
  • masukkan nama cabang yang ada
  • tekan kembali pada dialog yang mengkonfirmasi penggantian cabang lama dari nama itu .

Berhati-hatilah bahwa menciptakan kembali alih-alih memodifikasi cabang yang ada akan kehilangan informasi pelacakan cabang . (Ini umumnya bukan masalah untuk kasus penggunaan sederhana di mana hanya ada satu remote dan cabang lokal Anda memiliki nama yang sama dengan cabang terkait di remote. Lihat komentar untuk detail lebih lanjut, terima kasih @mbdevpl untuk menunjukkan downside ini.)

Akan keren jika gitkmemiliki fitur di mana kotak dialog memiliki 3 opsi: menimpa, memodifikasi yang ada, atau membatalkan.


Bahkan jika Anda biasanya pecandu baris perintah seperti saya, git guidan gitkdirancang cukup baik untuk subset penggunaan git yang mereka izinkan. Saya sangat merekomendasikan menggunakannya untuk apa yang mereka kuasai (yaitu secara selektif mementaskan orang bakhil ke dalam / keluar dari indeks di git gui, dan juga hanya melakukan komitmen. (Ctrl-s untuk menambahkan tanda-off: baris, ctrl-enter untuk melakukan .)

gitk sangat bagus untuk melacak beberapa cabang saat Anda menyortir perubahan Anda menjadi seri tambalan yang bagus untuk dikirim ke hulu, atau apa pun di mana Anda perlu melacak apa yang Anda lakukan di tengah-tengah dengan beberapa cabang.

Saya bahkan tidak memiliki browser file grafis terbuka, tapi saya suka gitk / git gui.


1
Begitu mudah! Saya mungkin baru saja mengkonversi dari gitg ke gitk.
Michael Cole

Dengan cara ini, bagaimanapun, informasi cabang pelacakan hilang.
mbdevpl

@ mbdevpl: Saya bukan ahli git. Saya pikir saya mengerti apa yang Anda maksud, tetapi bukan implikasinya. Saya sudah sering menggunakan ini, dan masih bisa mendorong cabang-cabang itu ke cabang dengan nama yang sama di remote. Apa hubungan antara cabang dan cabang pelacak jarak jauh untuk Anda?
Peter Cordes

@ mbdevpl: apakah sebagian besar hanya penting ketika cabang lokal Anda memiliki nama yang berbeda dari cabang jarak jauh yang dilacaknya ?
Peter Cordes

1
@PeterCordes Ineed, ketika nama cabang tidak cocok itu penting. Juga ketika ada lebih dari satu remote. Juga ketika Anda menggunakan git prompt untuk menampilkan status cabang, itu akan menunjukkan jarak komit ke cabang pelacakan Anda (jika disetel). Juga, git statusoutput terpengaruh. Selain itu, dalam beberapa kasus git fetchdan git pushtidak akan berfungsi tanpa menentukan jarak jauh secara eksplisit jika Anda tidak menetapkan cabang pelacakan. Saya tidak tahu tentang semua kasing, tetapi bagi saya aturan umum adalah untuk kenyamanan dan kecepatan kerja, lebih baik untuk memiliki cabang pelacakan agar.
mbdevpl


4

Jujur, saya terkejut bagaimana tidak ada yang memikirkan git pushperintah:

git push -f . <destination>:<branch>

Titik (.) Merujuk ke repositori lokal, dan Anda mungkin memerlukan opsi -f karena tujuan bisa "di belakang rekan jauh" .

Meskipun perintah ini digunakan untuk menyimpan perubahan Anda di server Anda, hasilnya persis sama seperti jika memindahkan cabang jarak jauh ( <branch>) ke komit yang sama dengan cabang lokal ( <destination>)


Anda juga dapat melakukan ini tanpa -fmenghindari menabrak sesuatu yang lokal; misalnya, git fetch origin && git push . origin/develop:developadalah versi gagal-cepat yang tidak perlu checkoutgit checkout develop && git pull --ff-only
btown

1

Buka file .git/refs/heads/<your_branch_name>, dan ubah hash yang tersimpan di sana menjadi hash di mana Anda ingin memindahkan kepala cabang Anda. Cukup edit dan simpan file dengan editor teks apa pun. Pastikan saja cabang yang akan dimodifikasi bukan yang aktif saat ini.

Penafian: Mungkin bukan cara yang disarankan untuk melakukannya, tetapi menyelesaikan pekerjaan.


1
Tidak yakin apakah ini cara yang kacau atau jahat untuk melakukannya. 🤔 😉
Keith Russell

@KeithRussell mungkin keduanya: P
Guillermo Gutiérrez

0

Dalam hal komit yang ingin Anda tunjukkan berada di depan cabang saat ini (yang seharusnya menjadi kasus kecuali jika Anda ingin membatalkan komitmen terakhir dari cabang saat ini), Anda dapat melakukan:

git merge <commit>

Tanya pertanyaan tentang apa yang harus dilakukan jika cabang tidak dicentang.
Keith Russell

Ups, saya melewatkan poin itu. Dalam hal ini Anda dapat melakukan git push . <commit>:<branch>seperti yang disarankan.
Jean Paul
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.