Ön notlar
Buradaki gözlem, çalışmaya başladıktan sonra branch1( branch2önce farklı bir şubeye geçmenin iyi olacağını unutma ya da fark etmeme ), koşmanız:
git checkout branch2
Bazen Git "Tamam, şimdi branş2'desin!" Diyor. Bazen Git, "Bunu yapamam, bazı değişikliklerinizi kaybederim" der.
Git Eğer olmaz bunu yapalım bir yere kalıcı onları kurtarmak için, değişiklikleri işlemek zorunda. Bunları git stashkaydetmek için kullanmak isteyebilirsiniz ; bu onun için tasarlanmış şeylerden biri. Not olduğu git stash saveveya git stash pushgerçekte anlamı "Tüm Değişiklikleri uygulayın, ama hiç hiçbir dalda sonra şimdi nerede çıkarın." Bu, geçiş yapmayı mümkün kılar: Artık devam eden değişiklikleriniz yok. Daha sonra git stash applybunları değiştirdikten sonra yapabilirsiniz .
Kenar çubuğu: git stash saveeski sözdizimidir; git stash pushGit sürüm 2.13'te, argümanlarla ilgili bazı sorunları düzeltmek git stashve yeni seçeneklere izin vermek için tanıtıldı . Temel şekillerde kullanıldığında her ikisi de aynı şeyi yapar.
İsterseniz burada okumayı bırakabilirsiniz!
Git Eğer olmaz sen dönelim Zaten bir çare vardır: kullanılmasını git stashveya git commit; veya değişikliklerinizin yeniden oluşturulması önemsizse, git checkout -fzorlamak için kullanın . Bu cevap, Git'in bazı değişiklikler yapmaya başlamış olsanız bile size ne zaman izin vereceği ile ilgilidir git checkout branch2. Neden bazen çalışıyor , diğer zamanlarda çalışmıyor ?
Buradaki kural bir yönden basit, diğerinde karmaşık / açıklaması zor:
Yalnızca söz konusu anahtarlama bu değişikliklerin hızlandırılmasını gerektirmiyorsa, çalışma ağacında taahhüt edilmemiş değişikliklerle dalları değiştirebilirsiniz.
Bu - ve bunun hala basitleştirilmiş olduğunu lütfen unutmayın; kademeli git adds, git rms ve benzeri bazı ekstra zor köşe vakaları var - varsayalım branch1. A git checkout branch2bunu yapmak zorunda olurdu:
- Her dosya için olduğu içinde
branch1ve değil de branch2, 1 dosyası bu kaldır.
- Her dosya için olduğu içinde
branch2ve değil de branch1, (uygun içeriği ile) bu dosyayı oluşturun.
- Her iki dalda bulunan her dosya için, sürüm
branch2farklıysa, çalışma ağacı sürümünü güncelleyin.
Bu adımların her biri, çalışma ağacınızdaki bir şeyi tıkayabilir:
- Çalışma ağacındaki sürüm, işlenen sürümle aynı ise, bir dosyayı kaldırmak "güvenlidir"
branch1; değişiklik yaptıysanız "güvensiz" olur.
branch2Şu anda mevcut değilse, dosya göründüğü gibi oluşturmak "güvenlidir". 2 Varsa, ancak "yanlış" içeriğe sahipse "güvensizdir".
- Ve elbette, iş ağacı sürümü zaten taahhüt edilmişse, bir dosyanın çalışma ağacı sürümünü farklı bir sürümle değiştirmek "güvenlidir"
branch1.
Yeni bir şube ( git checkout -b newbranch) oluşturmak her zaman "güvenli" olarak kabul edilir: bu işlemin bir parçası olarak çalışma ağacına hiçbir dosya eklenmeyecek, kaldırılmayacak veya değiştirilmeyecek ve indeks / aşamalandırma alanına da dokunulmayacaktır. (Uyarı: Yeni dalın başlangıç noktasını değiştirmeden yeni bir dal oluştururken güvenlidir; ancak başka bir argüman eklerseniz, örneğin git checkout -b newbranch different-start-point, bu, bir şeyleri değiştirmek zorunda kalabilirsiniz different-start-point. Git daha sonra ödeme güvenliği kurallarını her zamanki gibi uygulayacaktır. .)
1 Bunun için, bir dosyanın bir dalda olmasının ne anlama geldiğini tanımlamamız gerekir; bu da, sözcük dalının doğru tanımlanmasını gerektirir . (Ayrıca bkz tam olarak "dalında" tarafından ne demek? ) Burada, gerçekten ortalama ne taahhüt hangi dal-name giderir: kimin yolu bir dosya olup içinde ise bir karma üretir. Bu dosya değil de bunun yerine bir hata mesajı alırsanız. Dizininizdeki veya çalışma ağacınızdaki yolun varlığı, bu özel soruyu yanıtlarken alakalı değildir. Böylece, burada sır her birinin sonucunu incelemektir.P branch1git rev-parse branch1:Pbranch1Pgit rev-parsebranch-name:path. Dosya en fazla bir dalda "içeride" olduğu için bu başarısız olur veya bize iki karma kimliği verir. İki karma kimliği aynı ise, dosya her iki dalda da aynıdır. Değişiklik gerekmez. Karma kimlikleri farklıysa, dosya iki dalda farklıdır ve dalları değiştirmek için değiştirilmesi gerekir.
Buradaki temel kavram, taahhütlerdeki dosyaların sonsuza dek dondurulmuş olmasıdır. Düzenleyeceğiniz dosyalar dondurulmuş değil . En azından başlangıçta, sadece iki donmuş komisyon arasındaki uyumsuzluklara bakıyoruz. Ne yazık ki, biz-veya Git-da dosyalarla uğraşmak zorunda değildir sen uzak geçmek için gidiyoruz ve taahhüt içinde olan sen geçiş gidiyoruz işlemek içinde. Bu, geriye kalan komplikasyonlara yol açar, çünkü dosyalar üzerinde çalıştığımız bu iki dondurulmuş taahhütün varlığına gerek kalmadan indekste ve / veya çalışma ağacında da bulunabilir.
2 Zaten "doğru içerikler" ile zaten mevcutsa, "güvenli sıralama" olarak kabul edilebilir, böylece Git'in bunu yaratması gerekmez. Git'in buna izin veren en azından bazı sürümlerini hatırlıyorum, ancak şimdi test etmek Git 1.8.5.4'te "güvensiz" olarak kabul edildiğini gösteriyor. Aynı argüman, değiştirilecek şubeyle eşleşecek şekilde değiştirilen değiştirilmiş bir dosya için de geçerlidir. Yine de, 1.8.5.4 sadece "üzerine yazılacak" diyor. Teknik notların sonuna da bakın: Git'i ilk sürüm 1.5.s'de kullanmaya başladığımdan beri okuma ağacı kurallarının değiştiğini düşünmediğim için belleğim arızalı olabilir.
Değişikliklerin aşamalı veya düzensiz olması önemli mi?
Evet, bazı açılardan. Özellikle, bir değişikliği aşamalıp çalışma ağacı dosyasını "kaldırabilirsiniz". İşte iki dalda bir dosya, branch1ve içinde farklı branch2:
$ git show branch1:inboth
this file is in both branches
$ git show branch2:inboth
this file is in both branches
but it has more stuff in branch2 now
$ git checkout branch1
Switched to branch 'branch1'
$ echo 'but it has more stuff in branch2 now' >> inboth
Bu noktada, çalışıyor olsak da , çalışan ağaç dosyası içindeki dosyayla inbotheşleşir . Bu değişiklik taahhüt için hazırlanmamıştır, bu da şudur :branch2branch1git status --short
$ git status --short
M inboth
Space-then-M, "değiştirilmiş ancak aşamalı değil" anlamına gelir (veya daha kesin olarak, çalışma ağacı kopyası aşamalı / dizin kopyasından farklıdır).
$ git checkout branch2
error: Your local changes ...
Tamam, şimdi zaten bildiğimiz çalışma ağacı kopyasını da kopyayla eşleştirelim branch2.
$ git add inboth
$ git status --short
M inboth
$ git checkout branch2
Switched to branch 'branch2'
Burada aşamalı ve çalışan kopyaların ikisi de içinde olanlarla eşleşti branch2, bu yüzden kasaya izin verildi.
Bir adım daha deneyelim:
$ git checkout branch1
Switched to branch 'branch1'
$ cat inboth
this file is in both branches
Yaptığım değişiklik artık aşamalandırma alanından kayboluyor (çünkü ödeme aşamalandırma alanı içerisinden yazıyor). Bu biraz köşe davası. Değişiklik gitmiş değil, ancak bunu sahnelenen olduğu gerçeği, bir gitti.
Şube kopyasından farklı olarak dosyanın üçüncü bir varyantını hazırlayalım, ardından çalışma kopyasını geçerli dal sürümüyle eşleşecek şekilde ayarlayalım:
$ echo 'staged version different from all' > inboth
$ git add inboth
$ git show branch1:inboth > inboth
$ git status --short
MM inboth
MBurada iki s: aşamalı dosya HEADdosyadan ve çalışma ağacı dosyası aşamalı dosyadan farklıdır. Çalışma ağacı sürümü branch1(aka HEAD) sürümüyle eşleşiyor :
$ git diff HEAD
$
Ancak git checkoutödeme işlemine izin vermeyecektir:
$ git checkout branch2
error: Your local changes ...
branch2Sürümü çalışan sürüm olarak ayarlayalım :
$ git show branch2:inboth > inboth
$ git status --short
MM inboth
$ git diff HEAD
diff --git a/inboth b/inboth
index ecb07f7..aee20fb 100644
--- a/inboth
+++ b/inboth
@@ -1 +1,2 @@
this file is in both branches
+but it has more stuff in branch2 now
$ git diff branch2 -- inboth
$ git checkout branch2
error: Your local changes ...
Geçerli çalışan kopya branch2, içindeki kopyayla eşleşse de , hazırlanan dosya eşleşmez , bu nedenle git checkoutbu kopya kaybolur ve git checkoutreddedilir.
Teknik notlar - sadece delicesine meraklı olanlar için :-)
Tüm bunların altında yatan uygulama mekanizması Git'in dizinidir . "Hazırlama alanı" olarak da adlandırılan dizin, bir sonraki taahhüdü oluşturduğunuz yerdir : geçerli taahhüdü, yani, şimdi teslim aldığınız her şeyi eşleştirmeye başlar ve her git adddosya açışınızda dizin sürümünü değiştirirsiniz çalışma ağacında ne varsa.
Unutmayın, çalışma ağacı dosyalarınız üzerinde çalıştığınız yerdir. Burada, taahhütlerde ve dizinde olduğu gibi sadece Git için yararlı olan bazı özel formlardan ziyade normal formları vardır. Bir dosyayı ayıklamak Yani gelen bir işlemeye aracılığıyla iş ağaca daha sonra endeksi, vb. Değiştirdikten sonra git add, dizine getirin. Yani aslında her dosya için üç yer vardır: mevcut işlem, dizin ve çalışma ağacı.
Eğer çalıştırdığınızda git checkout branch2, Git kapakları altından ne karşılaştırmaktır ucu taahhüt ait branch2akım işlemek ve şimdi dizinde hem de her ne kadar. Şu an orada bulunan dosyalarla eşleşen Git, yalnız bırakılabilir. Hepsi el değmemiş. Her iki işlemde de aynı olan herhangi bir dosya , Git'i de yalnız bırakabilir - bunlar da dalları değiştirmenize izin veren dosyalardır.
Git anahtarlama dahil Git'in çoğu, bu dizin nedeniyle nispeten hızlıdır . Aslında dizinde olan her dosyanın kendisi değil, her dosyanın karmasıdır . Dosyanın kendisinin kopyası Git'in depoda bir blob nesnesi olarak adlandırdığı şekilde saklanır . Bu, dosyaların komisyonlarda nasıl depolandığına benzer: komisyonlar aslında dosyaları içermez, sadece Git'i her dosyanın karma kimliğine yönlendirir. Böylece Git, X ve Y'nin aynı dosyaya sahip olup olmadığına karar vermek için şu anda 160 bit uzunluğundaki karma kimlikleri karşılaştırabilir . Daha sonra bu karma kimlikleri dizindeki karma kimliğiyle de karşılaştırabilir.
Yukarıdaki tüm tuhaf köşe vakalarına yol açan şey budur. Her ikisinin de dosyası olan X ve Y taahhütlerimiz var path/to/name.txtve için bir dizin girişimiz var path/to/name.txt. Belki her üç karma eşleşir. Belki ikisi eşleşir, biri eşleşmez. Belki üçü de farklıdır. Ayrıca, bunun another/file.txtyalnızca X veya yalnızca Y'de olduğunu ve şimdi dizinde olduğunu veya olmadığını gösterir. Bu çeşitli vakaların her biri kendi ayrı değerlendirilmesi gerekir: Git gelmez ihtiyaç dosyayı kopyalamak dan endeksi taahhüt veya gelen anahtara, dizinden çıkarmak için X için Y ? Eğer öyleyse, o da vardırdosyayı çalışma ağacına kopyalayın veya çalışma ağacından kaldırın. Ve eğer o davasını s, endeks ve iş-ağaç versiyonları daha iyi maçı taahhüt sürümleri en az biri vardı; aksi halde Git bazı verileri tıkayacaktır.
(Tüm kurallar, git checkoutbeklediğiniz gibi belgelerde değil , git read-tree"İki Ağaç Birleştirme" bölümü altında yer alan belgelerde açıklanmıştır .)
git checkout -m, çalışma ağacınızı ve dizin değişikliklerinizi yeni kasada birleştiren de var .