Saya baru di kompleksitas bercabang Git. Saya selalu bekerja pada satu cabang dan melakukan perubahan dan kemudian secara berkala mendorong ke asal saya yang jauh.
Di suatu tempat baru-baru ini, saya melakukan reset beberapa file untuk membuatnya keluar dari pementasan komit, dan kemudian melakukan rebase -i
untuk menghilangkan beberapa komit lokal baru-baru ini. Sekarang saya dalam keadaan saya tidak begitu mengerti.
Di wilayah kerja saya, git log
tunjukkan persis apa yang saya harapkan - saya berada di kereta yang tepat dengan komitmen yang tidak ingin saya lewati, dan yang baru di sana, dll.
Tapi saya hanya mendorong ke repositori jarak jauh, dan apa yang berbeda - beberapa komitmen yang saya bunuh dalam rebase didorong, dan yang baru dilakukan secara lokal tidak ada.
Saya pikir "master / origin" terlepas dari HEAD, tapi saya tidak 100% jelas tentang apa artinya, bagaimana memvisualisasikannya dengan alat-alat baris perintah, dan bagaimana cara memperbaikinya.
I did a reset of some files to get them out of commit staging
sebagian? maaf untuk pertanyaannya :)Jawaban:
Pertama, mari kita perjelas apa itu HEAD dan apa artinya ketika itu dilepaskan.
HEAD adalah nama simbolis untuk komit yang sedang diperiksa. Ketika KEPALA tidak terlepas (situasi "normal" 1 : Anda memiliki cabang diperiksa), KEPALA sebenarnya menunjuk ke "ref" cabang dan cabang menunjuk ke komit. Dengan demikian, KEPALA “dilampirkan” ke cabang. Saat Anda membuat komit baru, cabang yang ditunjuk HEAD diperbarui untuk menunjukkan komit baru. KEPALA mengikuti secara otomatis karena hanya menunjuk ke cabang.
git symbolic-ref HEAD
hasilrefs/heads/master
Cabang bernama "master" diperiksa.
git rev-parse refs/heads/master
yield17a02998078923f2d62811326d130de991d1a95a
Komit adalah ujung atau "kepala" saat ini dari cabang master.
git rev-parse HEAD
juga menghasilkan17a02998078923f2d62811326d130de991d1a95a
Ini adalah apa artinya menjadi "ref simbolik". Itu menunjuk ke suatu objek melalui beberapa referensi lain.
(Rujukan simbol pada awalnya diimplementasikan sebagai tautan simbolik, tetapi kemudian diubah menjadi file biasa dengan interpretasi ekstra sehingga dapat digunakan pada platform yang tidak memiliki symlink.)
Kami memiliki
HEAD
→refs/heads/master
→17a02998078923f2d62811326d130de991d1a95a
Ketika HEAD dilepaskan, itu menunjuk langsung ke sebuah komit — bukannya secara tidak langsung menunjuk satu melalui cabang. Anda dapat menganggap KEPALA lepas sebagai cabang yang tidak disebutkan namanya.
git symbolic-ref HEAD
gagal denganfatal: ref HEAD is not a symbolic ref
git rev-parse HEAD
imbal hasil17a02998078923f2d62811326d130de991d1a95a
Karena ini bukan referensi simbolis, ia harus menunjuk langsung ke komit itu sendiri.
Kami punya
HEAD
→17a02998078923f2d62811326d130de991d1a95a
Yang penting untuk diingat dengan HEAD terpisah adalah bahwa jika komit itu menunjuk sebaliknya direferensikan (tidak ada referensi lain yang bisa mencapainya), maka itu akan menjadi "menggantung" ketika Anda checkout beberapa komit lainnya. Akhirnya, komitmen yang menggantung seperti itu akan dipangkas melalui proses pengumpulan sampah (secara default, mereka disimpan setidaknya selama 2 minggu dan dapat disimpan lebih lama dengan direferensikan oleh reflog HEAD).
1 Tidak apa-apa untuk melakukan pekerjaan "normal" dengan KEPALA terpisah, Anda hanya perlu melacak apa yang Anda lakukan untuk menghindari memancing sejarah yang hilang dari reflog.
Langkah menengah rebase interaktif dilakukan dengan KEPALA terpisah (sebagian untuk menghindari mencemari reflog cabang aktif). Jika Anda menyelesaikan operasi rebase penuh, itu akan memperbarui cabang asli Anda dengan hasil kumulatif operasi rebase dan pasang kembali HEAD ke cabang asli. Dugaan saya adalah bahwa Anda tidak pernah sepenuhnya menyelesaikan proses rebase; ini akan membuat Anda dengan KEPALA lepas yang menunjuk ke komit yang baru saja diproses oleh operasi rebase.
Untuk pulih dari situasi Anda, Anda harus membuat cabang yang menunjuk ke komit yang saat ini ditunjuk oleh KEPALA Anda yang terlepas:
(dua perintah ini dapat disingkat
git checkout -b temp
)Ini akan memasang kembali KEPALA Anda ke
temp
cabang baru .Selanjutnya, Anda harus membandingkan komit saat ini (dan riwayatnya) dengan cabang normal tempat Anda diharapkan bekerja:
(Anda mungkin ingin bereksperimen dengan opsi log: tambahkan
-p
, tinggalkan--pretty=…
untuk melihat seluruh pesan log, dll.)Jika
temp
cabang baru Anda terlihat bagus, Anda mungkin ingin memperbarui (misalnya)master
untuk mengarahkannya:(dua perintah ini dapat disingkat
git checkout -B master temp
)Anda kemudian dapat menghapus cabang sementara:
Akhirnya, Anda mungkin ingin mendorong sejarah yang dibangun kembali:
Anda mungkin perlu menambahkan
--force
ke akhir perintah ini untuk mendorong jika cabang jauh tidak dapat "fast-forwarded" ke komit baru (yaitu Anda menjatuhkan, atau menulis ulang beberapa komit yang ada, atau menulis ulang sedikit sejarah).Jika Anda berada di tengah-tengah operasi rebase, Anda mungkin harus membersihkannya. Anda dapat memeriksa apakah rebase sedang dalam proses dengan mencari direktori
.git/rebase-merge/
. Anda dapat secara manual membersihkan rebase yang sedang berlangsung dengan hanya menghapus direktori itu (mis. Jika Anda tidak lagi mengingat tujuan dan konteks operasi rebase aktif). Biasanya Anda akan menggunakangit rebase --abort
, tetapi itu melakukan beberapa pengaturan ulang ekstra yang mungkin ingin Anda hindari (memindahkan HEAD kembali ke cabang asli dan mengatur ulang kembali ke komit asli, yang akan membatalkan beberapa pekerjaan yang kami lakukan di atas).sumber
man git-symbolic-ref
: "Di masa lalu,.git/HEAD
ada tautan simbolik yang menunjukrefs/heads/master
. Ketika kami ingin beralih ke cabang lain, kami melakukannyaln -sf refs/heads/newbranch .git/HEAD
, dan ketika kami ingin mencari tahu di cabang mana kami berada, kami melakukannyareadlink .git/HEAD
. Tetapi tautan simbolik tidak sepenuhnya portabel. , jadi mereka sekarang sudah usang dan referensi simbolis (seperti dijelaskan di atas) digunakan secara default. "git branch -f master HEAD && git checkout master
sudah cukup - dengan asumsi tujuan Anda adalah mempertahankan kepala Anda saat ini tetapi untuk menetapkannya sebagaimaster
. Tujuan lain juga masuk akal, dan meminta resep lain.Lakukan ini:
Atau, jika Anda memiliki perubahan yang ingin Anda pertahankan, lakukan ini:
sumber
git reset
harus datang dengan peringatan "Jika Anda tidak tahu apa yang Anda lakukan, hentikan itu". Baru saja pulih dari satu jam ketakutan berpikir aku kehilangan minggu terakhir pekerjaan. Terima kasih!Saya mengalami masalah ini dan ketika saya membaca di bagian atas pilih jawaban:
Saya berpikir: Ah-ha! Jika
HEAD
nama simbolis untuk checkout checkout currenlty, saya dapat mendamaikannyamaster
dengan rebasing terhadapmaster
:Perintah ini:
master
HEAD
kembali ke titikHEAD
divergen darimaster
master
Hasil akhirnya adalah bahwa semua komit yang masuk
HEAD
tetapi tidakmaster
kemudian juga masukmaster
.master
tetap diperiksa.Mengenai remote:
Riwayat jarak jauh tidak lagi dapat diteruskan dengan cepat menggunakan riwayat lokal Anda. Anda harus memaksa-tekan (
git push -f
) untuk menimpa riwayat jarak jauh. Jika Anda memiliki kolaborator, biasanya masuk akal untuk mengoordinasikan ini dengan mereka sehingga semua orang ada di halaman yang sama.Setelah Anda mendorong
master
ke jarak jauhorigin
, cabang pelacakan jarak jauh Andaorigin/master
akan diperbarui untuk menunjuk ke komit yang sama denganmaster
.sumber
git reflog
kemudian setel ulang cabang Anda ke komit itu dengangit rest —hard $commit
Lihat di sini untuk penjelasan dasar kepala terpisah:
http://git-scm.com/docs/git-checkout
Baris perintah untuk memvisualisasikannya:
atau
Anda akan mendapatkan output seperti di bawah ini:
The
* (no branch)
menunjukkan Anda berada di kepala terpisah.Anda bisa datang ke negara ini dengan melakukan
git checkout somecommit
dll. Dan itu akan memperingatkan Anda dengan yang berikut:Sekarang, untuk menjadikannya master:
Lakukan
git reflog
atau bahkan adilgit log
dan catat komitmen Anda. Sekaranggit checkout master
dangit merge
komitmen.Edit:
Untuk menambahkan, gunakan
git rebase -i
tidak hanya untuk menghapus / membunuh komit yang tidak Anda butuhkan, tetapi juga untuk mengeditnya. Sebutkan "edit" di daftar komit dan Anda akan dapat mengubah komit Anda dan kemudian mengeluarkan agit rebase --continue
untuk melanjutkan. Ini akan memastikan bahwa Anda tidak pernah datang ke KEPALA yang terpisah.sumber
Dapatkan komitmen terpisah Anda ke cabangnya sendiri
Cukup jalankan
git checkout -b mynewbranch
.Kemudian jalankan
git log
, dan Anda akan melihat bahwa komit sekarang adaHEAD
di cabang baru ini.sumber
mynewbranch
lampiran?jika Anda baru saja menguasai cabang dan ingin kembali ke "mengembangkan" atau fitur lakukan saja ini:
Catatan: memeriksa asal / berkembang .
Anda berada dalam kondisi KEPALA terpisah . Anda dapat melihat-lihat, membuat perubahan eksperimental, dan mengkomitnya, dan Anda dapat membuang semua komitmen yang Anda buat dalam kondisi ini tanpa memengaruhi cabang apa pun dengan melakukan checkout lain ...
kemudian
Berhasil :)
sumber
Jika Anda ingin mendorong KEPALA terlepas saat ini (periksa
git log
sebelumnya), coba:untuk mengirim KEPALA terlepas Anda ke cabang master di asal. Jika dorongan Anda ditolak, coba
git pull origin master
dulu untuk mendapatkan perubahan dari asal. Jika Anda tidak peduli dengan perubahan dari asal dan ditolak, karena Anda melakukan rebase yang disengaja dan Anda ingin mengganti asal / master dengan cabang yang saat ini terlepas - maka Anda dapat memaksanya (-f
). Jika Anda kehilangan beberapa akses ke komit sebelumnya, Anda selalu dapat berlarigit reflog
untuk melihat riwayat dari semua cabang.Untuk kembali ke cabang master, sambil menyimpan perubahan, coba perintah berikut:
Lihat: Git: "Saat ini tidak di cabang mana pun." Apakah ada cara mudah untuk kembali ke cabang, sambil menjaga perubahan?
sumber
Saya menemukan pertanyaan ini ketika mencari
You are in 'detached HEAD' state.
Setelah menganalisis apa yang telah saya lakukan untuk sampai ke sini, dibandingkan dengan apa yang telah saya lakukan di masa lalu, saya menemukan bahwa saya telah membuat kesalahan.
Aliran normal saya adalah:
Kali ini saya lakukan:
Masalahnya adalah saya tidak sengaja melakukannya:
Daripada:
Cara mengatasinya (dalam situasi saya) hanyalah menjalankan perintah di atas dan kemudian melanjutkan aliran:
sumber
Berikut ini berfungsi untuk saya (hanya menggunakan master cabang):
Yang pertama mendorong HEAD yang terlepas ke asal yang jauh.
Yang kedua pindah ke master cabang.
Yang ketiga memulihkan HEAD yang menjadi terikat pada master cabang.
Masalah mungkin timbul pada perintah pertama jika dorongan ditolak. Tapi ini tidak lagi menjadi masalah kepala terpisah, tetapi adalah tentang fakta bahwa KEPALA terpisah tidak menyadari beberapa perubahan jarak jauh.
sumber
Saya baru saja mengalami masalah ini hari ini dan saya cukup yakin saya menyelesaikannya dengan melakukan:
Saya berada di komputer kerja ketika saya menemukan cara untuk melakukan ini, dan sekarang saya mengalami masalah yang sama pada komputer pribadi saya. Jadi harus menunggu sampai Senin ketika saya kembali ke komputer kerja untuk melihat bagaimana saya melakukannya.
sumber
Jika Anda benar-benar yakin KEPALA adalah kondisi yang baik:
Anda mungkin tidak bisa mendorong ke asal, karena tuan Anda telah menyimpang dari asal. Jika Anda yakin tidak ada orang lain yang menggunakan repo, Anda dapat mendorong-paksa:
Paling berguna jika Anda menggunakan cabang fitur yang tidak digunakan orang lain.
sumber
Yang harus Anda lakukan adalah 'git checkout [nama-cabang]' di mana [nama-cabang] adalah nama cabang asli tempat Anda masuk ke kondisi kepala yang terpisah. (Terlepas dari asdfasdf) akan hilang.
Jadi misalnya, di cabang 'dev' Anda checkout komit asdfasd14314 ->
Anda sekarang dalam kondisi kepala yang terpisah
'git branch' akan mencantumkan sesuatu seperti ->
tetapi untuk keluar dari kondisi kepala terpisah dan kembali ke dev ->
dan kemudian 'git branch' akan menampilkan ->
tapi itu tentu saja jika Anda tidak berniat menjaga perubahan dari keadaan kepala terpisah tapi saya menemukan diri saya melakukan ini banyak tidak bermaksud untuk membuat perubahan tetapi hanya untuk melihat komit sebelumnya
sumber
Seperti yang ditunjukkan oleh Chris, saya mengikuti situasi
git symbolic-ref HEAD
gagal denganfatal: ref HEAD is not a symbolic ref
Namun
git rev-parse refs/heads/master
menunjuk komit yang baik dari mana saya bisa memulihkan (Dalam kasus saya komit terakhir dan Anda dapat melihat komit itu dengan menggunakangit show [SHA]
Saya melakukan banyak hal yang berantakan setelah itu, tetapi yang tampaknya telah diperbaiki hanyalah,
git symbolic-ref HEAD refs/heads/master
Dan kepala terpasang kembali!
sumber
Alih-alih melakukan
git checkout origin/master
kerjakan saja
git checkout master
kemudian
git branch
akan mengkonfirmasi cabang Anda.sumber
Saya memiliki masalah ini hari ini, di mana saya telah memperbarui submodule, tetapi tidak di cabang mana pun. Saya sudah berkomitmen, jadi menyembunyikan, checkout, melepas tidak akan berhasil. Saya akhirnya memilih ceri komit kepala terpisah. Jadi segera setelah saya melakukan (ketika push gagal), saya lakukan:
Pikiranku berbunyi: Aku berada di kepala yang terpisah, tetapi aku ingin menjadi tuan. Dengan asumsi keadaan saya yang terpisah tidak jauh berbeda dari master, jika saya bisa menerapkan komit saya kepada master, saya akan siap. Inilah yang dilakukan oleh pemetik ceri.
sumber
Jika Anda melakukan beberapa komit di atas master dan hanya ingin "mundur menggabungkan" di
master
sana (yaitu Anda inginmaster
menunjuk keHEAD
), satu-baris adalah:master
, bahkan jika sudah ada (yang seperti bergerakmaster
dan itulah yang kita inginkan).HEAD
, di mana Anda berada.master
sesudahnya.Saya menemukan ini sangat berguna dalam kasus sub-repositori, yang juga sering berada dalam keadaan terpisah.
sumber
Saya memiliki masalah yang sama dan saya telah mengatasinya dengan melalui langkah-langkah berikut.
Jika Anda perlu menyimpan perubahan Anda
git checkout master
perintah untuk mengembalikan Anda ke cabang master.git checkout -b changes
dangit checkout -B master changes
Jika Anda tidak membutuhkan perubahan Anda
Untuk menghapus semua file yang tidak terlacak dari menjalankan cabang Anda
git clean -df
.Maka Anda perlu menghapus semua perubahan yang tidak bertahap dalam repositori Anda. Untuk melakukan itu, Anda harus menjalankan
git checkout --
Akhirnya Anda harus meletakkan cabang Anda kembali ke cabang master dengan menggunakan
git checkout master
perintah.sumber
Bagi saya itu semudah menghapus cabang lokal lagi, karena saya tidak punya komitmen lokal yang ingin saya dorong:
Jadi saya melakukannya:
Dan kemudian memeriksa cabang lagi:
sumber
Ketika saya secara pribadi menemukan diri saya dalam situasi ketika ternyata saya membuat beberapa perubahan sementara saya tidak berada
master
(yaituHEAD
terpisah tepat di atasmaster
dan tidak ada komitmen di antaranya) menyimpan mungkin membantu:sumber
Dengan kata sederhana, status HEAD terlepas berarti Anda tidak dicentang ke HEAD (atau tip) cabang apa pun .
Pahami dengan Contoh
Cabang di sebagian besar kasus adalah urutan beberapa komit seperti:
Komit 1: master -> branch_HEAD (123be6a76168aca712aea16076e971c23835f8ca)
Berkomit 2: master -> 123be6a76168aca712aea16076e971c23835f8ca -> branch_HEAD (100644a76168aca712aea16076e971c23835f8ca)
Seperti yang dapat Anda lihat di atas jika urutan komit, cabang Anda menunjuk komit terbaru Anda. Jadi dalam hal ini jika Anda checkout untuk melakukan 123be6a76168aca712aea16076e971c23835f8ca maka Anda akan berada dalam kondisi kepala terpisah sejak KEPALA poin cabang Anda ke 100644a76168aca712aea16076e971c23835f8ca dan secara teknis Anda akan check out di KEPALA cabang. Karenanya, Anda berada dalam kondisi HEAD yang terpisah.
Penjelasan Teoritis
Dalam Blog ini jelas menyatakan repositori Git adalah pohon komitmen, dengan masing-masing komit menunjuk ke leluhurnya dengan masing-masing pointer komit diperbarui dan pointer ke masing-masing cabang disimpan dalam sub-direktori .git / ref. Tag disimpan dalam .git / ref / tag dan cabang disimpan dalam .git / ref / kepala. Jika Anda melihat salah satu file, Anda akan menemukan setiap tag terkait dengan satu file, dengan hash komit 40 karakter dan seperti yang dijelaskan di atas oleh @Chris Johnsen dan @Yaroslav Nikitenko, Anda dapat memeriksa referensi ini.
sumber
Saya masuk ke keadaan yang benar-benar konyol, saya ragu orang lain akan menemukan ini berguna .... tetapi untuk berjaga-jaga
yang akhirnya saya perbaiki
sumber
Ini bekerja dengan baik untuk saya:
1.
git stash
untuk menyimpan modifikasi lokal AndaJika Anda ingin membuang perubahan,
git clean -df
git checkout -- .
git clean menghapus semua file yang tidak terlacak (peringatan: sementara itu tidak akan menghapus file yang diabaikan yang disebutkan secara langsung di .gitignore, itu dapat menghapus file yang diabaikan yang berada di folder) dan checkout git menghapus semua perubahan yang tidak bertahap.
2.
git checkout master
untuk beralih ke cabang utama (Dengan asumsi Anda ingin menggunakan master)3.
git pull
untuk menarik komit terakhir dari cabang master4.
git status
untuk memeriksa semuanya tampak hebatsumber
Dalam kasus saya, saya berlari
git status
, dan saya melihat bahwa saya memiliki beberapa file yang tidak terlacak dalam direktori kerja saya.Untuk membuat rebase bekerja, saya hanya perlu membersihkannya (karena saya tidak membutuhkannya).
sumber
Jika Anda menggunakan EGit di Eclipse: anggap master Anda adalah cabang pengembangan utama Anda
Setelah ini, Anda harus dapat melampirkan kembali ke master-asal.
sumber
Saya memiliki masalah yang sama. Saya menyimpan perubahan saya dengan
git stash
dan sulit mengatur ulang cabang di lokal ke komit sebelumnya (saya pikir itu menyebabkan itu) kemudian melakukangit pull
dan saya tidak mendapatkan kepala itu terlepas sekarang. Jangan lupagit stash apply
lakukan perubahan Anda lagi.sumber
sumber