Sadece git'te aşamalı değişiklikler saklamak mümkün mü?


365

Sadece sahnelediğim değişiklikleri saklamamın bir yolu var mı? Sorun yaşadığım senaryo, belirli bir zamanda birkaç hata üzerinde çalıştığımda ve birkaç değişmemiş değişiklik olduğunda. Kodları onaylanıncaya kadar bu dosyaları tek tek hazırlayabilmek, .patch dosyalarımı oluşturmak ve saklamak istiyorum. Bu şekilde, onaylandığında tüm (geçerli) oturumumu saklayabilir, bu hatayı açıp kodu itebilirim.

Buna yanlış mı gidiyorum? Git'in sürecimi basitleştirmek için başka şekillerde nasıl çalışabileceğini yanlış mı anlıyorum?


Evet, muhtemelen bu duruma girmek için yanlış şeyler yapıyorsunuz. Hala faydalı bir soru. Bir sonraki düzeltmeye başlamadan önce gerçekten saklamak veya dallamak zorundasınız. Teğet, cevap stackoverflow.com/a/50692885 muhtemelen git'te bunu halletmenin daha iyi bir yoludur. Stash ile uğraşmak, çalışma alanımdan yukarı doğru taahhütte bulunursam, sık sık garip şeyler yapar.
Samuel Åslund

Yanıtlar:


470

Evet, ÇİFT STASH ile mümkün

  1. İhtiyacınız olan tüm dosyalarınızı saklayın.
  2. Koş git stash --keep-index. Bu komut TÜM değişikliklerinizle birlikte bir stash oluşturacak ( aşamalı ve etiketsiz ), ancak aşamalı değişiklikleri çalışma dizininizde bırakacaktır (hala durum aşamasındadır).
  3. Çalıştırmak git stash push -m "good stash"
  4. Artık reklam "good stash"gelmiştir SADECE dosyaları düzenledi .

Şimdi stash'tan önce işaretlenmemiş dosyalara ihtiyacınız varsa, ilk stash'ı ( ile oluşturulmuş olan--keep-index ) uygulayın ve şimdi stash yaptığınız dosyaları kaldırabilirsiniz "good stash".

Zevk almak


Alt modüllerdeki evrelendirilmemiş olsalar bile değişiklikleri saklar. Bunun etrafında bir yol var mı?
16:45

1
bu bir şekilde tüm yeni dosyaları (hatta aşamalı) dışarıda bıraktı.
Aurimas

8
@Aurimas, yeni dosyaları saklamak için -uanahtarı kullanmanız gerekir .
Gyromite

2
ilk saklamak yeniden uygulamak ve sadece değişmeden sadece geri almak değişmezlik değişiklikleri kullanmak git stash apply --indexseçeneği. Bu, un (aşamalı) durumunuzu korumaya çalışır. Çalışma ağacından istenmeyen değişiklikleri kaldırmak artık daha kolay.
otomo

Tam olarak bu cevabın söylediklerini yapmak zorunda olmasam da, --keep-index bayrağını bilmek çok yardımcı oldu.
Aaron Krauss

128

En son git ile --patchseçeneği kullanabilirsiniz

git stash push --patch  

git stash save --patch   # for older git versions

Ve git sizden dosyalarınızdaki her değişikliği saklamak isteyip istemediğinizi soracaktır.
Sadece cevap veriyorsun yveyan

ÇİFT STASH
için UPD Takma Adı :

git config --global alias.stash-staged '!bash -c "git stash --keep-index; git stash push -m "staged" --keep-index; git stash pop stash@{1}"'

Şimdi dosyalarınızı aşamalı olarak çalıştırabilirsiniz git stash-staged.
Sonuç olarak , hazırladığınız dosyalar saklanır .

Aşamalı dosyaları saklamak istemiyorsanız ve bunları saklamak istiyorsanız. Ardından başka bir takma ad ekleyebilir ve çalıştırabilirsiniz git move-staged:

git config --global alias.move-staged '!bash -c "git stash-staged;git commit -m "temp"; git stash; git reset --hard HEAD^; git stash pop"'

17
Teknik olarak soruyu cevaplamıyor - ancak seçici saklamayı sağlayan gerçekten güzel bir teknik.
alexreardon

6
Kabul ediyorum, bu iyi, ama burada soru ile ilgili fikir bir şey yapmak istediğim değişiklikleri (görünüşte orijinal olarak taahhüt etmek, ama şimdi saklamak istiyorum) sahnelemek için ZORUNLU yaptım. hepsini yeniden yap.
Steven Lu

4
yeni oluşturulan dosyalar için çalışmaz (yalnızca değiştirilmiş dosyalar üzerinde çalışır)
Derek Liang

@DerekLiang: Yeni oluşturulan dosyalar hiç izlenmez. Muhtemelen -u|--include-untrackedseçeneğini işaretlemelisinizgit-stash
Eugen Konkov

2
Gönderen docs : " save : Bu seçenek lehine kullanımdan kaldırıldı git zulası itme . O pathspecs alamaz ve herhangi seçenek olmayan argümanları mesajı oluşturmasıdır 'zula itme' farklıdır."
Borjovsky

53

Sadece şu anda sahnelenen şeyleri saklayan ve diğer her şeyi bırakan bir senaryo hazırladım. Çok fazla ilgisiz değişiklik yapmaya başladığımda bu harika. Sadece istenen taahhüd ile ilgili olmayan şeyleri hazırlayın ve saklayın.

(Başlangıç ​​noktası için Bartłomiej'e teşekkürler)

#!/bin/bash

#Stash everything temporarily.  Keep staged files, discard everything else after stashing.
git stash --keep-index

#Stash everything that remains (only the staged files should remain)  This is the stash we want to keep, so give it a name.
git stash save "$1"

#Apply the original stash to get us back to where we started.
git stash apply stash@{1}

#Create a temporary patch to reverse the originally staged changes and apply it
git stash show -p | git apply -R

#Delete the temporary stash
git stash drop stash@{1}


3
Bu harika! Komut satırına bir tane girmezlerse
bulundum

1
Git 2.23.0 ile hiç çalışmaz.
thnee

Teşekkürler, onu iptal ettim ve burada bir takma ada dönüştürdüm: stackoverflow.com/a/60875067/430128 .
Raman

34

TL; DR Hemen eklemek -- $(git diff --staged --name-only)için git için <pathspec>parametre

İşte basit bir astar:

git stash -- $(git diff --staged --name-only)

Ve bir mesaj eklemek için:

git stash push -m "My work in progress" -- $(git diff --staged --name-only)

V2.17.1 ve v2.21.0.windows.1 üzerinde test edilmiştir

Sınırlamalar:

  • Hazırlanmış dosya yoksa, bunun her şeyi saklayacağını lütfen unutmayın.
  • Ayrıca, yalnızca kısmen aşamalı bir dosyanız varsa (diğer bir deyişle, yalnızca bazı değiştirilen satırlar, diğer bazı değiştirilen satırlar değilken hazırlanır), tüm dosya saklanır (sabit olmayan satırlar dahil).

6
Bu durumun açıklanan en iyi seçenek olduğunu düşünüyorum: anlaşılması kolay ve kara büyü yok!
Luis

1
Bu oldukça düzenli. Sonunda bir takma ad oluşturdum!
Kalpesh Panchal

'em oy comin 😉
Somo S.

@KalpeshPanchal takma adınızı paylaşabilir misiniz? Nasıl kaçacağından emin değilim, bu yüzden doğru yorumlamıyor.
Igor Nadj


15

Aynı şeyi başarmak için ...

  1. Yalnızca üzerinde çalışmak istediğiniz dosyaları hazırlayın.
  2. git commit -m 'temp'
  3. git add .
  4. git stash
  5. git reset HEAD~1

Boom. İstemediğiniz dosyalar saklanır. İstediğiniz dosyaların hepsi sizin için hazır.


3
Bu kolayca en iyi cevap ve hatırlaması en kolay
Kevin

9

Bu senaryoda, her sorun için yeni dallar oluşturmayı tercih ediyorum. Bir önek temp / kullanıyorum, bu şubeleri daha sonra silebileceğimi biliyorum.

git checkout -b temp/bug1

Hata1'i düzelten ve teslim eden dosyaları hazırlayın.

git checkout -b temp/bug2

Daha sonra kirazları gerektiği gibi ilgili dallardan alabilir ve bir çekme talebi gönderebilirsiniz.


2
Süslü saklanma sesleri bilmek güzel olsa da, pratikte bu bir yaklaşım gibi görünüyor.
ryanjdillon

1
Geçici gitme işlemini bir birleştirme-tamamlama işlemi için "git cherry-pick tmpCommit" veya "kesinleştirme olmadan değişiklikleri almak için" git merge tmpCommit "+" git reset HEAD ^ "kullanın.
Samuel Åslund

1
Bu cevabın bazen gösterdiği gibi, verilen teknikle nasıl elde etmek yerine doğrudan ne elde etmek istediğinizi sormak daha iyidir. Geçici dallar ve kiraz toplama karmaşık durumlarda kullanışlıdır.
Güney Ozsan

bir dosyayı kısmen sahnelediyseniz, orijinal şubeye geri dönüp tekrar açmadan önce değişikliklerinizi saklamanız gerekir
jan-glx

6

Neden belirli bir hata için değişikliği yapmıyorsunuz ve bu taahhüt ve selefinden bir yama oluşturmuyorsunuz?

# hackhackhack, fix two unrelated bugs
git add -p                   # add hunks of first bug
git commit -m 'fix bug #123' # create commit #1
git add -p                   # add hunks of second bug
git commit -m 'fix bug #321' # create commit #2

Ardından, uygun yamaları oluşturmak için şunu kullanın git format-patch:

git format-patch HEAD^^

Bu iki dosya oluşturur: 0001-fix-bug-123.patchve0002-fix-bug-321.patch

Veya her hata için ayrı dallar oluşturabilirsiniz, böylece hata düzeltmelerini tek tek birleştirebilir veya yeniden çözebilir, hatta çalışmazlarsa silebilirsiniz.


2

git stash --keep-index iyi bir çözümdür ... ancak Git 2.23'te (3. Çeyrek 2019) düzeltilen kaldırılan yollarda düzgün çalışmadıysa

Bakınız Thomas Gummerer ( ) tarafından b932f6a (16 Tem 2019 ) . (Göre Birleştirilmiş - Junio Cı Hamano - içinde f8aee85 tamamlama 2019 25 Tem)tgummerer
gitster

stash: ile kaldırılan dosyaların işlenmesi düzeltildi --keep-index

git stash push --keep-index dizinde eklenmiş olan tüm değişiklikleri hem dizinde hem de diskte tutması gerekir.

Şu anda bir dosya dizinden kaldırıldığında bu doğru davranmıyor.
Diskte silinmiş tutmak yerine ** - keep-index şu anda dosyayı geri yükler. **

Bu davranışı git checkout, dizin ve çalışma ağacına sadakatle geri yükleyebilen yer paylaşımsız modda ' ' kullanarak düzeltin .
Bu aynı zamanda kodu basitleştirir.

İzlenmeyen dosya dizinde silinmiş bir dosyayla aynı ada sahipse, izlenmeyen dosyaların üzerine yazılacağını unutmayın.


2

Git'te yalnızca dizini (aşamalı değişiklikler) saklamak olması gerekenden daha zordur. @ Joe'nun iyi çalışmasına cevap buldum ve küçük bir varyasyonunu bu takma ada dönüştürdüm:

stash-index = "!f() { \
  git stash push --quiet --keep-index -m \"temp for stash-index\" && \
  git stash push \"$@\" && \
  git stash pop --quiet stash@{1} && \
  git stash show -p | git apply -R; }; f"

Hem aşamalı hem de değişmemiş değişiklikleri geçici bir depoya iterek aşamalı değişiklikleri yalnız bırakır. Ardından, aşamalı değişiklikleri saklamak istediğimiz zulası olan zulasına iter. Takma ada iletilen bağımsız değişkenler, --message "whatever"bu stash komutuna eklenecektir. Son olarak, orijinal durumu geri yüklemek ve geçici saklamayı kaldırmak için geçici saklayıcı açılır ve son olarak saklanan değişiklikleri bir ters yama uygulaması aracılığıyla çalışma dizininden "kaldırır".

Sadece saklanmayan değişimleri (takma ad stash-working) saklama zıt problemi için bu cevaba bakınız .


1

Aynı anda birkaç böcek üzerinde çalışmak kesinlikle gerekli mi? "Aynı anda" demek istediğim "dosyaların aynı anda birden çok hata için düzenlenmesi." Çünkü buna kesinlikle ihtiyacınız olmadığı sürece, ortamınızdaki her seferinde sadece bir hata üzerinde çalışacağım. Bu şekilde karmaşık şubeleri / aşamaları yönetmekten çok daha kolay bulduğum yerel şubeleri ve rebase'i kullanabilirsiniz.

Diyelim ki usta B işinde. Şimdi hata # 1 üzerinde çalışın.

git checkout -b bug1

Şimdi şube hata 1'de. Bazı değişiklikler yapın, taahhüt edin, kod incelemesini bekleyin. Bu yereldir, bu yüzden kimseyi etkilemezsiniz ve git diffs'den bir yama yapmak yeterince kolay olmalıdır.

A-B < master
   \
    C < bug1

Şimdi bug2 üzerinde çalışıyorsunuz. İle master yapmaya geri dön git checkout master. Yeni bir dal yap git checkout -b bug2. Değişiklik yapın, taahhüt edin, kod incelemesini bekleyin.

    D < bug2
   /
A-B < master
   \
    C < bug1

İncelemeyi beklerken başkasının E & F'yi ustalıkla taahhüt ettiğini varsayalım.

    D < bug2
   /
A-B-E-F < master
   \
    C < bug1

Kodunuz onaylandığında, aşağıdaki adımlarla ustalaşmak için kodu yeniden oluşturabilirsiniz:

git checkout bug1
git rebase master
git checkout master
git merge bug1

Bu aşağıdakilerle sonuçlanacaktır:

    D < bug2
   /
A-B-E-F-C' < master, bug1

Ardından, yerel bug1 dalınızı itebilir, silebilir ve yola çıkabilirsiniz. Çalışma alanınızdaki her seferinde bir hata, ancak yerel dalları kullanarak deponuz birden çok hatayı işleyebilir. Ve bu karmaşık bir sahne / stash dansı önler.

Yorumlarda ctote'nin sorusuna cevap verin:

Her hata için saklamaya geri dönebilir ve bir seferde yalnızca bir hata ile çalışabilirsiniz. En azından sahneleme sorununu kurtarır. Ama bunu denedikten sonra, kişisel olarak zahmetli buluyorum. Zımbalar git günlük grafiğinde biraz dağınıktır. Ve daha da önemlisi, bir şeyi mahvederseniz, geri dönemezsiniz. Kirli bir çalışma dizininiz varsa ve bir zulayı açarsanız, o pop'u "geri alamazsınız". Mevcut taahhütleri bertaraf etmek çok daha zordur.

Yani git rebase -i.

Bir dalı diğerine yeniden adlandırdığınızda, etkileşimli olarak yapabilirsiniz (-i bayrağı). Bunu yaptığınızda, her taahhütte ne yapmak istediğinizi seçme seçeneğiniz vardır. Pro Git, HTML biçiminde de çevrimiçi olan ve yeniden bastırma ve ezme konusunda güzel bir bölüme sahip harika bir kitap:

http://git-scm.com/book/ch6-4.html

Kolaylık sağlamak için örneklerini aynen çalacağım. Aşağıdaki işlem geçmişine sahip olduğunuzu varsayın ve bug1'i master'a yeniden oluşturmak ve ezmek istediğinizi varsayalım:

    F < bug2
   /
A-B-G-H < master
   \
    C-D-E < bug1

İşte yazarken görecekleriniz git rebase -i master bug1

pick f7f3f6d changed my name a bit
pick 310154e updated README formatting and added blame
pick a5f4a0d added cat-file
#
# Commands:
#  p, pick = use commit
#  e, edit = use commit, but stop for amending
#  s, squash = use commit, but meld into previous commit
#
# If you remove a line here THAT COMMIT WILL BE LOST.
# However, if you remove everything, the rebase will be aborted.
#

Bir dalın tüm taahhütlerini tek bir taahhütte ezmek için, ilk taahhüdü "pick" olarak saklayın ve sonraki tüm "pick" girişlerini "squash" veya basitçe "s" ile değiştirin. İşlem mesajını da değiştirme fırsatı elde edersiniz.

pick f7f3f6d changed my name a bit
s 310154e updated README formatting and added blame
s a5f4a0d added cat-file
#
# Commands:
#  p, pick = use commit
#  e, edit = use commit, but stop for amending
#  s, squash = use commit, but meld into previous commit

Yani evet, ezmek biraz acı verici, ama yine de ağır miktarda saklamak için tavsiye ederim.


1
Detaylı yazı için teşekkürler! Bu, birçok sorunumu kesin olarak çözüyor - gördüğüm tek sorun şu anki ekibimizin tüm teslimatları tek bir taahhütte tutmamızı istedi. :(
MrDuk

1
Üretim geçmişinde çalışma geçmişinize ihtiyaç duymuyorlarsa veya istemiyorlarsa sorun değil: şubeleri birleştirmek yerine diffs uygulayarak izleme ana geçmişinizi daha az yapın. Gerçek birleştirilmiş geçmişe sahip dekore edilmiş bir ana dalı nasıl tutacağınızı ve gerçek işinizi bundan nasıl yapacağınızı öğrenebilirsiniz, böylece doğru farkları oluşturmayı otomatikleştirmek kolay olacaktır.
jthill

2
git checkout master; git checkout -b bug2Bunun kısaltılabileceğini unutmayın git checkout -b bug2 master. Aynı şey git checkout bug1; git rebase master; git checkout master; git merge bug1, aynıdır git rebase master bug1; git push . bug1:master( pushhile belli değildir)
knittl

1
Süslü biçimlendirmeyi kullanabilmek için yukarıda ana cevapta saklamak için bir yol verdim
Mike Monkiewicz

6
İndirdim çünkü bu asıl soruya cevap vermiyor. Bir şey üzerinde çalışan bir şubedeyim ve entegrasyon şubesine ayrı ayrı taahhüt edilmesi gerektiğini düşündüğüm bir değişiklik yaptım. Yapmak istediğim tek şey, mevcut "devam eden çalışma" dalım yerine başka bir dala geçip ayrı ayrı işlem yapabilmek için bu değişikliği ve saklamaktır. (Uyarı, git önde gidiyor.) Bunun yapılması çok zor; Bunun yaygın bir olay olduğunu hayal etmeliyim . (Bir dalda çalışmak ve yapılması gereken hızlı bir değişikliği tespit etmek ve ilk olarak geçiş yapmayı unutmak.)
jpmc26

0

Mike Monkiewicz cevabı hakkındaki yorumlarınızdan daha basit bir model kullanmanızı öneririz: Düzenli geliştirme dalları kullanın, ancak ana dalınızda tek bir taahhüt almak için birleştirme işleminin kabak seçeneğini kullanın:

git checkout -b bug1    # create the development branch
* hack hack hack *      # do some work
git commit
* hack hack hack *
git commit
* hack hack hack *
git commit
* hack hack hack *
git commit
git checkout master     # go back to the master branch
git merge --squash bug1 # merge the work back
git commit              # commit the merge (don't forget
                        #    to change the default commit message)
git branch -D bug1      # remove the development branch

Bu prosedürün avantajı, normal git iş akışını kullanabilmenizdir.


Bu cevabın nasıl yardımcı olabileceğini göremiyorum. Orijinal soru ile ilgili değildir.
frapen

0

TL; DR ;git stash-staged

Bir takma ad oluşturduktan sonra:

git config --global alias.stash-staged '!bash -c "git stash -- \$(git diff --staged --name-only)"'

İşte git difflistesini döndürür --stageddosyaları --name-only
Ve sonra bu listeyi geçmesi pathspeciçin git stashcommad.

Gönderen man git stash:

git stash [--] [<pathspec>...]

<pathspec>...
   The new stash entry records the modified states only for the files
   that match the pathspec. The index entries and working tree
   files are then rolled back to the state in HEAD only for these
   files, too, leaving files that do not match the pathspec intact.


-1

Yanlışlıkla yapılan bir değişikliği, özellikle birden fazla dosyanın silinmesini önlemek için aşağıdakileri yapın:

git add <stuff to keep> && git stash --keep-index && git stash drop

başka bir deyişle, bok saklamak ve tamamen saklamak ile atmak.

Git 2.17.1 sürümünde test edildi


yorumsuz bir downvote ne bana ne de bir sonraki okuyucu için yararlı ... zaenks huysuz anon. Bu tek astarla ilgili bir sorun hayal edebiliyorum: Dizine tüm istenen değişiklikleri eklemeyi unutmamak çok dikkatli olmalı, aksi takdirde bu önemli değişiklikler de silinecektir. Fakat yine de, herhangi bir klips aracının dikkatsiz kullanımı, en kötü durumda kişinin değerli zamanı ve işi için çok tehlikeli olabilir.
wmax
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.