Beralih cabang Git tanpa pembayaran file


100

Apakah mungkin di Git untuk beralih ke cabang lain tanpa memeriksa semua file?

Setelah berpindah cabang, saya perlu menghapus semua file, membuat ulang, berkomitmen dan beralih kembali. Jadi memeriksa file hanya membuang-buang waktu (dan ada sekitar 14.000 file - ini adalah operasi yang lama).

Untuk memperjelas:

Saya membutuhkan semua ini untuk mengunggah dokumentasi ke GitHub.

Saya memiliki repositori dengan cabang gh-pages . Ketika saya membangun kembali dokumentasi secara lokal, saya menyalinnya ke direktori repositori, mengkomit dan mendorong ke GitHub. Tetapi saya tidak senang, karena saya memiliki dua salinan dokumentasi secara lokal. Dan saya memutuskan untuk membuat cabang kosong dan setelah melakukan, beralih ke mengosongkan dan menghapus file. Tetapi beralih kembali adalah operasi yang lama - jadi saya mengajukan pertanyaan ini.

Saya tahu bahwa saya dapat meninggalkan cabang gh-pages dan menghapus file, tetapi saya tidak suka pohon kerja yang kotor.


Berapa lama "panjang" untukmu? Platform apa yang Anda kerjakan? Apakah Anda bekerja melalui jaringan seperti dengan NFS atau berbagi file lainnya?
Greg Hewgill

Apa tujuan latihan ini? Apakah Anda ingin memiliki dua cabang, satu dengan komit mendetail, yang kedua hanya merekam perubahan besar (berbutir kasar)?
Jakub Narębski

Mungkin lebih murah untuk membuat klon sementara (atau permanen?) Dari copy pekerjaan Anda. Jawaban terkait saya dan Langgan menunjukkan bagaimana ini bekerja bahkan sebagai subdirektori dari repositori utama.
krlmlr

Jawaban:


106

Ya, Anda bisa melakukan ini.

git symbolic-ref HEAD refs/heads/otherbranch

Jika Anda perlu berkomitmen pada cabang ini, Anda juga ingin mengatur ulang indeks jika tidak, Anda akan berakhir melakukan sesuatu berdasarkan cabang yang terakhir diperiksa.

git reset

1
Gunakan echo "ebff34ffb665de0694872dceabe0edeaf50ec5a9" > .git/HEADdiikuti dengan git resetuntuk menunjuk ke referensi alih-alih cabang.
cadorn

1
Menulis langsung ke file HEAD kurang bisa diandalkan. Bagaimana jika Anda berada di subdir? Untuk kepala yang terlepas (kepala mengarah ke SHA1 secara langsung), coba ini: git update-ref HEAD refs/heads/otherbranch
Alexander Bird

2
Jika Anda ingin memeriksa ke cabang baru dari cabang saat ini, cara lain untuk melakukannya adalah dengan 1. git stash2. git checkout -b otherBranch3.git stash pop
Winny

@AlexanderBird: git update-refberguna, tetapi juga menggerakkan ujung cabang saat ini.
tomekwi

47

Hanya menggunakan perintah git dasar:

Jawaban ini sedikit lebih panjang daripada Charles, tetapi hanya terdiri dari perintah git dasar yang dapat saya pahami dan ingat, menghilangkan kebutuhan untuk terus mencarinya.

Tandai lokasi Anda saat ini (lakukan terlebih dahulu jika perlu):

git checkout -b temp

Setel ulang (memindahkan) penanda ke cabang lain tanpa mengubah dir yang berfungsi:

git reset <branch where you want to go>

sekarang temp dan cabang lainnya menunjuk ke komit yang sama, dan direktori kerja Anda tidak tersentuh.

git checkout <branch where you want to go>

karena HEAD Anda sudah menunjuk ke komit yang sama, dir kerja tidak tersentuh

git branch -d temp

Perhatikan bahwa perintah ini juga tersedia dari klien grafis mana pun.


7
Saya lebih memilih git reset --soft <branch where you want to go>untuk menghindari memperbarui indeks
JoelFan

7
Saya setuju dengan strategi Anda untuk menghindari perintah git plumbing dan lebih menyukai yang porselen.
pengguna64141

26

Di v2.24 git switchadalah sesuatu seperti brankas git checkout.
Karenanya saya mengganti nama alias di bawah ini menjadi git hopuntuk
"lompat di cabang tanpa mengubah worktree"

Untuk kepentingan pembaca:

Meskipun menurut saya solusi Charles Bailey adalah yang benar, solusi ini memerlukan penyesuaian saat beralih ke sesuatu, yang bukan merupakan cabang lokal. Juga harus ada cara bagaimana melakukannya dengan perintah biasa yang mudah dimengerti. Inilah yang saya dapatkan:

git checkout --detach
git reset --soft commitish
git checkout commitish

Dijelaskan:

  • git checkout --detachsama seperti git checkout HEAD^{}yang meninggalkan cabang saat ini dan beralih ke "status kepala terpisah". Jadi modifikasi selanjutnya HEADtidak lagi mempengaruhi cabang manapun. Melepas HEADtidak mempengaruhi worktree maupun indeks.
  • git reset --soft commitishlalu pindah HEADke SHA yang diberikan commitish. Jika Anda ingin memperbarui indeks juga, tinggalkan --soft, tetapi saya tidak menyarankan untuk melakukannya. Ini, sekali lagi, tidak menyentuh worktree, dan ( --soft) bukan indeks.
  • git checkout commitishkemudian menempel HEADpada commitish(cabang) yang diberikan lagi. (Jika commitishSHA tidak ada yang terjadi.) Ini, juga, tidak mempengaruhi indeks atau pohon kerja.

Solusi ini menerima semua yang mengacu pada komit, jadi ini ideal untuk beberapa gitalias. Di rev-parsebawah ini hanyalah tes untuk memastikan, tidak ada yang putus dalam rantai, sehingga kesalahan ketik tidak secara tidak sengaja beralih ke status kepala terpisah (pemulihan kesalahan akan jauh lebih kompleks).

Ini mengarah ke git hop treeishalias berikut :

git config --global alias.hop '!f() { git rev-parse --verify "$*" && git checkout "HEAD^{}" && git reset --soft "$*" && git checkout "$*"; }; f'

FYI, Anda dapat menemukannya di daftar gitalias saya .


Apakah Anda tidak ingin menggunakan $@daripada $*? Perbedaannya adalah bahwa $ @ dengan argumen kutipan tidak perlu diperluas, yang memiliki spasi di dalamnya.
kyb

1
@kyb Trik fungsi dicuri dari jawaban SO lain . Dan $@secara definitif tidak dimaksudkan di sini. $*digunakan sebagai pengganti $1, sehingga git switch -f bmenjadi sama dengan git switch '-f b'yang seharusnya menjadi kesalahan. Dengan cara ini saya dapat mempersingkat alias dengan meninggalkan beberapa penanganan kesalahan seperti!f() { [ 1 = $# ] || { echo 'WTF!'; return 1; }; ..
Tino

Solusi yang sangat bagus. Terutama, itu bisa digunakan untuk cabang-cabang terpencil!
Nils-o-mat

14

Bukankah solusi yang lebih baik untuk memiliki dua direktori kerja (dua area kerja) dengan satu repositori, atau bahkan dua repositori?

Ada alat git-new-workdir di contrib/bagian untuk membantu Anda melakukannya.


Apakah git-new-workdir sama dengan perintah worktree git sendiri? Saya menggunakan worktree ketika saya ingin melakukan checkout sebuah cabang ke folder yang berbeda (tanpa harus mengkloning seluruh repo).
Ryuu

The git-new-worktreemendahului Script git worktreesubcommand; perintah ini tidak tersedia saat jawabannya ditulis. Script tersebut misalnya membutuhkan dukungan symlink; IMHO lebih baik menggunakan dukungan asli.
Jakub Narębski

8

Saya pikir Anda sedang mencari perintah pipa ledeng git read-tree. Ini akan memperbarui indeks tetapi tidak akan memperbarui file apa pun di direktori kerja Anda. Misalnya, anggaplah branchnama cabang yang akan dibaca:

git read-tree branch

Jika Anda ingin kemudian berkomitmen ke cabang yang baru saja Anda baca, Anda juga perlu:

git symbolic-ref HEAD refs / heads / branch

tidak, saya hanya perlu beralih cabang, tidak ada perubahan lain - jadi simbolik-ref cukup baik
tig

read-treemenghasilkan error: fatal: Not a valid object name branchjika tidak ada apa git switch branchbelum
Andry

7

Anda dapat menimpa file HEAD Anda dengan nama cabang yang berbeda:

echo "ref: refs / heads / MyOtherBranch"> .git / HEAD


13
Mungkin lebih baik menggunakan perintah ref-simbolik untuk melakukan ini untuk Anda: git symbolic-ref HEAD refs/heads/MyOtherBranch kernel.org/pub/software/scm/git/docs/git-symbolic-ref.html
Greg Hewgill

@GregHewgill, ini adalah satu-satunya cara yang saya tahu untuk memindahkan HEAD ke hash commit. Bisakah kamu melakukan itu dengan git symbolic-ref?
tomekwi

0

Dengan begitu banyak file, Anda mungkin lebih baik menyimpan dua repo, satu untuk setiap cabang. Anda dapat melakukan perubahan bolak-balik sesuai kebutuhan. Ini tidak akan terlalu mengejutkan daripada mencoba memainkan trik penyakit kudis dengan git.


Anda dapat menggunakan git-new-worktreeuntuk itu sebagai gantinya (dalam contrib/)
Jakub Narębski

Saya sering melakukan hal serupa, yaitu menyalin direktori lokal saya sebelum melakukan "hal-hal menakutkan" sebagai pemula (seperti mengganti cabang, dll). Saya akan mendorong orang-orang untuk mengikuti rute itu sampai Anda merasa percaya diri dengan git-fu Anda, tetapi menjauhinya jika memungkinkan. Menyimpan dua repo yang berbeda tidak apa-apa, tetapi menambahkan lapisan kerumitan dan tidak membiarkan Anda memanfaatkan banyak fitur berguna git (penggabungan, pengambilan ceri, dll).
David

0

Jika Anda hanya mencoba mengubah tempat titik cabang jarak jauh, Anda dapat melakukannya dengan "git push" tanpa menyentuh salinan lokal Anda.

http://kernel.org/pub/software/scm/git/docs/git-push.html

Format parameter <refspec> adalah plus + opsional, diikuti oleh sumber ref <src>, diikuti oleh titik dua:, diikuti oleh ref tujuan <dst>. Ini digunakan untuk menentukan dengan objek <src> apa <dst> ref dalam repositori jarak jauh akan diperbarui.

misalnya, untuk memperbarui foo untuk melakukan c5f7eba lakukan hal berikut:

git push origin c5f7eba:foo

Tidak yakin apakah itu yang Anda cari atau tidak.


Pertanyaannya sudah mendapat jawaban: stackoverflow.com/questions/1282639/…
tig

0

dapat Anda manfaatkan

      1. git checkout -f <new-branch>
      2. git cherry-pick -x <previous-branch-commit-id>

before-branch-commit-id adalah komit dari mana Anda ingin menyalin data lama.


0

Atau cukup gunakan file tambalan untuk menambal dari cabang Anda yang lain ke master Anda

git diff otherbranch master > ~/tmp/otherbranch.diff
git checkout master
git apply ~/tmp/otherbranch.diff

-1

katakanlah Anda ingin berada di cabang A, tetapi dengan file dari cabang B

temukan ref komit saat ini dari cabang A dengan git log, misalnya "99ce9a2",

git checkout A
git reset --hard B
git reset 99ce9a2

Anda sekarang harus berada di cabang A, dengan struktur folder yang sesuai dengan B, yang muncul sebagai perubahan tidak bertahap (Riwayat A tidak berubah).

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.