Git reset --soft'un pratik kullanımları?


136

Git ile bir aydan biraz fazla bir süredir çalışıyorum. Nitekim dün ilk kez sıfırlamayı kullandım, ancak yazılımdan sıfırlama hala bana pek mantıklı gelmiyor.

Yazılımdan sıfırlamayı, tıpkı benim yapacağım gibi dizini veya çalışma dizinini değiştirmeden düzenlemek için kullanabileceğimi anlıyorum git commit --amend.

Bu iki komut gerçekten aynı mı ( reset --softvs commit --amend)? Birini veya diğerini pratik anlamda kullanmak için herhangi bir neden var mı? Ve daha da önemlisi, reset --softbir taahhüdü değiştirmenin dışında başka kullanımlar var mı?

Yanıtlar:


110

git resettaşıma hakkında hepsi HEAD, ve genellikle şube ref .
Soru: çalışma ağacı ve indeks ne olacak?
İle kullanıldığında --soft, hareket eder HEAD, en sık olarak dal ref ve yalnızcaHEAD .
Bu, aşağıdakilerden farklıdır commit --amend:

  • yeni bir kayıt oluşturmaz.
  • (o aslında herhangi kesinleştirme için HEAD taşıyabilirsiniz commit --amendsadece hakkındadır değil HEAD hareketli işlemek akımını yeniden yapmak izin verirken,)

Şu birleştirme örneğini buldum:

  • klasik bir birleştirme
  • alt ağaç birleştirme

hepsi bir arada (ahtapot, ikiden fazla dal birleştiği için) birleştirmeyi taahhüt eder.

Tomas "wasHamster" Carnecky "Subtree Octopus birleştirme" makalesinde şöyle açıklıyor :

  • Alt ağaç birleştirme stratejisi, bir projeyi başka bir projenin bir alt diziniyle birleştirmek ve ardından alt projeyi güncel tutmak istiyorsanız kullanılabilir. Git alt modüllerine bir alternatiftir.
  • Ahtapot birleştirme stratejisi, üç veya daha fazla dalı birleştirmek için kullanılabilir. Normal strateji yalnızca iki dalı birleştirebilir ve bundan fazlasını birleştirmeye çalışırsanız git otomatik olarak ahtapot stratejisine geri döner.

Sorun, yalnızca bir strateji seçebilmenizdir. Ancak, tüm deponun atomik olarak yeni bir sürüme güncellendiği temiz bir geçmiş elde etmek için ikisini birleştirmek istedim.

Bir süper projem var, hadi onu adlandıralım projectAve bir alt projectBdizini ile birleştirdiğim bir alt projem var projectA.

(bu alt ağaç birleştirme kısmı)

Ayrıca birkaç yerel taahhüdü sürdürüyorum.
ProjectAdüzenli olarak güncellenir, projectBher iki günde veya haftada bir yeni bir sürümü vardır ve genellikle ürününün belirli bir sürümüne bağlıdır projectA.

Her iki projeyi de güncellemeye karar verdiğimde, sadece çekmiyorum projectAve projectB bu, tüm projenin atomik bir güncellemesi olması gereken şey için iki taahhüt yaratır. .
Bunun yerine, tek bir birleştirme hangi biçerdöverler işlemek oluşturmak projectA, projectBve benim yerel kaydedilmesini .
Buradaki zor kısım, bunun bir ahtapot birleştirme (üç kafa) olması, ancak projectBalt ağaç stratejisiyle birleştirilmesi gerektiğidir . Yani yaptığım şey bu:

# Merge projectA with the default strategy:
git merge projectA/master

# Merge projectB with the subtree strategy:
git merge -s subtree projectB/master

Burada yazar a kullandı reset --hardve ardından read-treeilk iki birleştirmenin çalışma ağacına ve dizine yaptıklarını geri yüklemek için, ancak bu reset --softyardımcı olabilir:
İşe yarayan bu iki birleştirmeyi nasıl yeniden yaparım , yani çalışma ağacım ve dizinim iyi, ama bu iki kaydı kaydetmek zorunda kalmadan?

# Move the HEAD, and just the HEAD, two commits back!
git reset --soft HEAD@{2}

Şimdi, Tomas'ın çözümüne devam edebiliriz:

# Pretend that we just did an octopus merge with three heads:
echo $(git rev-parse projectA/master) > .git/MERGE_HEAD
echo $(git rev-parse projectB/master) >> .git/MERGE_HEAD

# And finally do the commit:
git commit

Yani her seferinde:

  • Sonuçta elde ettiğiniz şeyden memnunsunuz (çalışma ağacı ve dizin açısından)
  • sizi oraya götüren tüm işlemlerden memnun değilsiniz :

git reset --soft cevap.


8
Kendime not: basit bir ezme örneği git reset --soft: stackoverflow.com/questions/6869705/…
VonC

3
Yanlış şubeye gittiğinizde de yararlıdır. tüm değişiklikler hazırlık alanına geri döner ve siz doğru dalı ödünç alırken sizinle birlikte hareket eder.
smoebody

44

Kullanım Örneği - Bir dizi yerel işlemi birleştirin

"Oops. Bu üç işlem sadece bir olabilir."

Bu nedenle, son 3 (veya her neyse) işlemi geri alın (dizini veya çalışma dizinini etkilemeden). Sonra tüm değişiklikleri tek bir şekilde uygulayın.

Örneğin

> git add -A; git commit -m "Start here."
> git add -A; git commit -m "One"
> git add -A; git commit -m "Two"
> git add -A' git commit -m "Three"
> git log --oneline --graph -4 --decorate

> * da883dc (HEAD, master) Three
> * 92d3eb7 Two
> * c6e82d3 One
> * e1e8042 Start here.

> git reset --soft HEAD~3
> git log --oneline --graph -1 --decorate

> * e1e8042 Start here.

Artık tüm değişiklikleriniz korundu ve tek olarak gerçekleştirilmeye hazır.

Sorularınıza kısa cevaplar

Bu iki komut gerçekten aynı mı ( reset --softvs commit --amend)?

  • Hayır.

Birini veya diğerini pratik anlamda kullanmak için herhangi bir neden var mı?

  • commit --amend son işlemden / rm dosyalarını eklemek veya mesajını değiştirmek için.
  • reset --soft <commit> birkaç ardışık işlemi yeni bir işlemde birleştirmek için.

Ve daha da önemlisi, reset --softbir taahhüdü değiştirmenin dışında başka kullanımlar var mı?

  • Diğer cevapları görün :)

2
" reset --softBir taahhüdü değiştirmek dışında başka kullanımlar var mı - Hayır" için diğer yanıtları görün
Antony Hatchkins

Son yoruma yanıt olarak - kısmen kabul edildi, ancak tek bir taahhüdü değiştirmenin çok spesifik olduğunu söyleyebilirim . Örneğin, bir özellik yazıldıktan sonra her şeyi ezmek ve gözden geçirenler için daha yararlı olan yeni taahhütler oluşturmak isteyebilirsiniz. Yumuşak sıfırlamaların (düz dahil git reset), (a) geçmişi yeniden yazmak istediğinizde, (b) eski taahhütleri umursamadığınızda (böylece etkileşimli yeniden ödemenin karmaşasından kaçınabilirsiniz) ve (c) iyi olduğunu söyleyebilirim. birden fazla değişiklik taahhüdüne sahip olmak (aksi takdirde commit --amenddaha basittir).
johncip

18

Ben daha fazla sadece değiştirmeyi kullanmak Son için kullanıyorum.

Diyelim ki A işleminde bir hata yaptım ve sonra B işlemini yaptım. Şimdi sadece B'yi düzeltebilirim. git reset --soft HEAD^^ , A'yı düzeltirim ve yeniden işlerim ve sonra B'yi yeniden

Tabii ki, büyük taahhütler için pek uygun değil… ama yine de büyük taahhütler yapmamalısınız ;-)


3
git commit --fixup HEAD^^ git rebase --autosquash HEAD~Xda iyi çalışıyor.
Niklas

3
git rebase --interactive HEAD^^burada hem A hem de B'yi düzenlemeyi seçersiniz . Bu şekilde A ve B'nin commit mesajlarını saklar, gerekirse bunları da değiştirebilirsiniz.
Paul Pladijs

2
A'ya sıfırladıktan sonra B'yi nasıl yeniden uygulayabilirim?
northben

1
Muhtemelen daha az işe yarayan başka bir yol: git günlüğünüzü kontrol edin, B'nin commit karmasını alın, sonra git reset Adeğişiklikleri yapın ve ekleyin git commit --amend,, git cherry-pick <B-commit-hash>.
naught101

15

Başka bir potansiyel kullanım, saklamaya bir alternatiftir (bazı insanlar bunu sevmez, bkz. Https://codingkilledthecat.wordpress.com/2012/04/27/git-stash-pop-consaceful-harmful/ . ).

Örneğin, bir dalda çalışıyorsam ve acilen master üzerinde bir şeyi düzeltmem gerekiyorsa, şunu yapabilirim:

git commit -am "In progress."

sonra ödeme ustası ve düzeltmeyi yapın. İşim bittiğinde şubeme dönüyorum ve yapıyorum

git reset --soft HEAD~1

kaldığım yerden çalışmaya devam etmek.


3
Güncelleme (artık git'i daha iyi anladığıma göre): --softdeğişikliklerin hemen hazırlanmasını gerçekten önemsemediğiniz sürece, burada aslında gereksizdir. Şimdi sadece git reset HEAD~bunu yaparken kullanıyorum . Ben varsa ben dalları geçmek gerekir ve bu şekilde tutmak istediğinizde bazı değişiklikler daha sonra yapmam, sahnelenen git commit -m "staged changes"sonra, git commit -am "unstaged changes"daha sonra, git reset HEAD~ardından git reset --soft HEAD~tamamen çalışma durumuna geri yüklemek için. Dürüst olmak gerekirse, her ikisini de artık bildiğim kadarıyla çok daha az yapıyorum git-worktree:)
deltacrux

7

git reset --softDizininizde ve çalışma ağacınızda yaptığınız değişiklikler için üst öğe olarak sahip olmak istediğiniz sürümü değiştirmek için kullanabilirsiniz . Bunun yararlı olduğu durumlar nadirdir. Bazen çalışma ağacınızdaki değişikliklerin farklı bir dala ait olması gerektiğine karar verebilirsiniz. Ya da bunu, birkaç kaydı bire indirgemek için basit bir yol olarak kullanabilirsiniz (squash / katlama işlemine benzer).

Pratik bir örnek için VonC'nin bu cevabına bakın: Git'teki ilk iki işlemi ezmek mi?


Bu daha önce bulamadığım iyi bir soru. Ancak sıfırlama yazılımını kullanarak değişiklikleri başka bir şubeye nasıl koyacağımı göremediğimden emin değilim. Yani, Şubeyi kontrol ettim, sonra kullanıyorum git reset --soft anotherBranchve orada taahhüt ediyorum ? Fakat gerçekten ckeckout dalı değişmez, bu nedenle taahhüt edecektir Şubesi veya anotherBranch ?
AJJ

Bunu yaparken git checkout kullanmamanız önemlidir çünkü bu ağacınızı değiştirecektir. Git reset --soft'u sadece HEAD'in işaret ettiği revizyonu değiştirmenin bir yolu olarak düşünün.
Johannes Rudolph

7

Çalışmanıza farklı bir makinede devam etmek istediğinizde olası bir kullanım olabilir. Şu şekilde çalışır:

  1. Zula benzeri bir ada sahip yeni bir şubeye göz atın,

    git checkout -b <branchname>_stash
    
  2. Zula dalınızı yukarı itin,

    git push -u origin <branchname>_stash
    
  3. Diğer makinenize geçin.

  4. Hem zulanızı hem de mevcut şubelerinizi aşağı çekin,

    git checkout <branchname>_stash; git checkout <branchname>
    
  5. Şimdi mevcut şubenizde olmalısınız. Zula dalındaki değişiklikleri birleştirin,

    git merge <branchname>_stash
    
  6. Mevcut şubenizi birleştirmeden önce yumuşak sıfırlayın,

    git reset --soft HEAD^
    
  7. Zula dalınızı çıkarın,

    git branch -d <branchname>_stash
    
  8. Ayrıca zula dalınızı orijinden çıkarın,

    git push origin :<branchname>_stash
    
  9. Normalde saklamışsınız gibi değişikliklerinizle çalışmaya devam edin.

Bence gelecekte GitHub ve işbirliği. bu "uzaktan saklama" işlevini daha az adımda sunmalıdır.


2
İlk makinenizdeki ilk saklama ve pop işleminin tamamen gereksiz olduğunu belirtmek isterim, doğrudan kirli bir çalışma kopyasından yeni bir şube oluşturabilir, işleyebilir ve ardından değişiklikleri uzaktan kumandaya aktarabilirsiniz.

7

Pratik bir kullanım, yerel deponuzu zaten taahhüt ettiyseniz (yani git commit -m), o zaman git reset --soft HEAD ~ 1 yaparak bu son işlemi tersine çevirebilirsiniz.

Ayrıca bilginiz için, değişikliklerinizi zaten hazırladıysanız (yani git add ile), o zaman git reset --mixed HEAD yaparak aşamalamayı tersine çevirebilirsiniz - ya da ben de sık sık kullandımgit reset

son olarak git reset --hard , yerel değişiklikleriniz dahil her şeyi siler. ~ After başlığı size yukarıdan kaç commit yapacağınızı söyler.


1
git reset --soft HEAD ~1Bana verir fatal: Cannot do soft reset with paths.Bence olurdu böylece BAŞ sonra boşluk kaldırmak için gerekmez düşünüyorumgit reset --soft HEAD~1
Andrew Lohr

6

Kullanmanın harika bir nedeni ' git reset --soft <sha1>' HEADçıplak bir depoda hareket etmektir .

--mixedVeya kullanmayı denerseniz--hard seçeneğini , mevcut olmayan ağacı ve / veya dizini değiştirmeye ve çalıştırmaya çalıştığınız için bir hata alırsınız.

Not: Bunu doğrudan çıplak depodan yapmanız gerekecektir.

Not Yine: Çıplak depoda sıfırlamak istediğiniz şubenin aktif şube olduğundan emin olmanız gerekecektir. Değilse, depoya doğrudan erişiminiz olduğunda aktif şubeyi çıplak bir depoda nasıl güncelleyeceğiniz konusunda VonC'nin cevabını izleyin .


1
Önceki cevabınızda belirtildiği gibi ( stackoverflow.com/questions/4624881/… ), bu, çıplak depoya (burada bahsettiğiniz) doğrudan erişiminiz olduğunda geçerlidir. +1 olsa da.
VonC

@VonC Evet, kesinlikle doğru ve notu eklediğiniz için teşekkürler! Sıfırlamaların doğrudan depodan yapıldığını varsaydığım için eklemeyi unutuyorum. Ayrıca kişinin çıplak depoda sıfırlamak istediği şubenin aktif şubesi olduğunu varsayıyorum. Şube aktif şubesi değilse, aktif şubeyi çıplak depolar için nasıl güncelleyeceğiniz konusunda cevabınıza göre güncelleme yapmanız gerekir ( stackoverflow.com/questions/3301956/… ). Cevabı aktif şube bilgileriyle de güncelleyeceğim. Tekrar teşekkürler!!!
Hazok

2

SourceTree, sadece istediğiniz bitleri aşamalandırmak için oldukça uygun bir arayüze sahip bir git GUI'dir. Uygun bir revizyonu değiştirmek için uzaktan benzer bir şeye sahip değildir.

Bu yüzden git reset --soft HEAD~1çok daha faydalıdırcommit --amend bu senaryoda. İşlemi geri alabilir, tüm değişiklikleri hazırlama alanına geri alabilir ve SourceTree kullanarak aşamalı bitleri değiştirmeye devam edebilirim.

Gerçekten, bana öyle geliyor ki commit --amend, bu ikisinin daha fazlalıklı komutu, ancak git git ve biraz farklı şeyler yapan benzer komutlardan çekinmiyor.


1

Bu konudaki cevapları gerçekten beğenmeme rağmen, kullanıyorum git reset --soft biraz farklı ama yine de çok pratik bir senaryo için kullanıyorum.

Son işlememden sonra değişiklikleri (aşamalı ve aşamalı olmayan) göstermek için iyi bir diff aracı olan geliştirme için bir IDE kullanıyorum. Şimdi, görevlerimin çoğu birden fazla işlem içeriyor. Örneğin, belirli bir görevi tamamlamak için 5 taahhütte bulunduğumu varsayalım. Son kaydetmedeki değişikliklerime bakmak için 1-5 arasındaki her artımlı kaydetme sırasında IDE'deki diff aracını kullanıyorum. Taahhütte bulunmadan önce değişikliklerimi gözden geçirmenin çok yararlı bir yolunu buluyorum.

Ancak görevimin sonunda, tüm değişikliklerimi birlikte görmek istediğimde (1. işlemden önce), bir çekme isteğinde bulunmadan önce kendi kendine kod incelemesi yapmak istediğimde, yalnızca önceki işlemimdeki değişiklikleri görürüm (işlemden sonra) 4) ve mevcut görevimin tüm taahhütlerinden değişmez.

Bu yüzden git reset --soft HEAD~44 kaydetmeye geri dönüyorum. Bu, tüm değişiklikleri birlikte görmemi sağlıyor. Değişikliklerimden emin olduğumda, bunu git reset HEAD@{1}kendimden emin bir şekilde yapabilir ve uzağa itebilirim.


1
... sonra yapmak git add --patchve git commitsen başından beri ne yaptığını bilsen inşa olurdu dizi işlemek inşa etmek defalarca. İlk taahhütleriniz, masanızdaki notlar veya bir notun ilk taslağı gibidir, bunlar, yayınlanmak için değil, düşüncenizi düzenlemek için oradadır.
jthill

Hey, önerdiğin şeyi tam olarak anlayamadım.
Havalı Coder

1
Hemen yerine yapmanın o git reset @{1}ilk taslak serisini geri, bunun yerine bir for-yayında serisi oluşturabilir git add -pve git commit.
jthill

Evet doğru. Diğer bir yol (genellikle takip ettiğim yol) upstream / master üzerinde yeniden ödeme yapmak ve taahhütleri tek bir taneye sıkıştırmaktır.
Havalı Coder

1

Başka bir kullanım durumu da, bir çekme isteğinde diğer şubeyi kendinizle değiştirmek istediğiniz zamandır, örneğin, geliştirmede A, B, C özelliklerine sahip bir yazılımınız olduğunu varsayalım.

Bir sonraki sürümle geliştiriyorsunuz ve siz:

  • B özelliği kaldırıldı

  • D özelliği eklendi

Süreçte, B özelliği için yeni eklenen düzeltmeler geliştirin

Geliştirmeyi bir sonrakine birleştirebilirsiniz, ancak bu bazen karmaşık olabilir, ancak git reset --soft origin/developdeğişikliklerinizle bir taahhüt de kullanabilir ve oluşturabilirsiniz ve dal, çakışmalar olmadan birleştirilebilir ve değişikliklerinizi saklayabilir .

Bunun git reset --softkullanışlı bir komut olduğu ortaya çıktı . Ben şahsen bunu, "WIP" gibi "tamamlanmış işi" olmayan commit'leri ezmek için kullanıyorum, bu yüzden pull talebini açtığımda, tüm taahhütlerim anlaşılabilir.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.