sadece yerel git taahhütlerinizin bazılarını nasıl zorlarsınız?


160

Diyelim ki 5 yerel taahhüt var. Sadece 2 tanesini merkezileştirilmiş bir repoya itmek istiyorum (SVN tarzı iş akışı kullanarak). Bunu nasıl yaparım?

Bu işe yaramadı:

git checkout HEAD~3  #set head to three commits ago
git push #attempt push from that head

Bu, 5 yerel taahhüdün tamamını zorlar.

Ben gerçekten benim taahhütlerimi geri almak için git reset yapabilirim, ardından git stash ve sonra git push - ama zaten yazılmış taahhüt mesajları var ve dosyaları organize ve onları tekrarlamak istemiyorum.

Benim hissim, itme veya sıfırlama için geçen bazı bayrakların işe yarayacağıdır.

Eğer yardımcı olursa, benim git config'ım

[ramanujan:~/myrepo/.git]$cat config 
[core]
        repositoryformatversion = 0
        filemode = true
        bare = false
        logallrefupdates = true
[remote "origin"]
        url = ssh://server/git/myrepo.git
        fetch = +refs/heads/*:refs/remotes/origin/*
[branch "master"]
        remote = origin
        merge = refs/heads/master

Yanıtlar:


192

Taahhütlerinizin ana dalda olduğunu ve bunları uzak ana şubeye göndermek istediğinizi varsayarsak:

$ git push origin master~3:master

Git-svn kullanıyorsanız:

$ git svn dcommit master~3

Git-svn durumunda, bir taahhüt beklediği için HEAD ~ 3'ü de kullanabilirsiniz. Düz git durumunda, şube adını kullanmanız gerekir, çünkü HEAD refspec'de düzgün değerlendirilmez.

Ayrıca aşağıdakilere daha uzun bir yaklaşım getirebilirsiniz:

$ git checkout -b tocommit HEAD~3
$ git push origin tocommit:master

Bu tür bir iş akışı alışkanlığı kazanıyorsanız, çalışmanızı ayrı bir dalda yapmayı düşünmelisiniz. Sonra şöyle bir şey yapabilirsiniz:

$ git checkout master
$ git merge working~3
$ git push origin master:master

"Origin master: master" kısmının muhtemelen kurulumunuz için isteğe bağlı olduğunu unutmayın.


14
Not: kullanmak zorunda değilsiniz master~3. İçin herhangi bir referans, istenen "kadar" tamamlama olarak eşit, geçerli bir şekildedir HEAD~3veya HEAD~~~, ya da belirli bir SHS veya işlemek etiket bir etiket.
Kaz

2
İyi şeyler. Yine de bir uyarı: bu örnekler başlangıç ​​ustasına doğru gidiyor. Bu çözümü kopyalayıp yapıştırıyorsanız, yanlışlıkla ana dalı güncelleyebilirsiniz. (Tabii ki, her zaman dikkatli olmalı ve bir komut vermeden önce komutunuzu iki kez kontrol etmelisiniz git push...)
nofinator

Bunun taahhüdü zorladığı görülüyor, ancak dalı uzaktan eklemiyor.
Nateowami

@Nateowami master, refspec'in uzak tarafı dışında başka bir şey belirtmeniz gerekecek, örneğingit push origin tocommit:newbramch
Ryan Graham

Anlıyorum. Şube adı zaten yerel olarak mevcuttu; Sanırım bundan hoşlanmadı. Uzaktan kumandanın henüz şube adı yoktu.
Nateowami

16

Yaptığım şey "iş" adı verilen yerel bir dalda çalışmak. Bu dal, yukarı akış deposuna zorlamak istemediğim tüm geçici taahhütleri (geçici çözümler veya özel oluşturma seçenekleri veya herhangi bir şey gibi) içerir. Ben bunu uygun kaydedilmesini kiraz almak, ana dalına geçiş işlemek istiyorum o zaman ne zaman, o dal üzerinde uzak çalışmak yapmak daha sonra usta itmek, işlemek istiyoruz.

Akış yukarıdan ana dalımdaki değişiklikleri aldıktan sonra, ben git checkout workvegit rebase master . Bu, tüm yerel değişikliklerimi tarihin sonunda olacak şekilde yeniden yazar.

Aslında git svnbu iş akışı ile kullanıyorum , bu yüzden "itme" işlemi içerir git svn dcommit. Ben de tigusta metin için uygun taahhütleri kiraz seçmek için güzel bir metin modu gui depo görüntüleyici kullanın.


git svn dcommit ile, dcommit'e kadar bir taahhüt belirtebilirsiniz, bu nedenle istenen etki git-svn ile oldukça önemsizdir.
Ryan Graham

Bu yaklaşımın dezavantajları vardır (burada özetlenmiştir stackoverflow.com/a/881014/1116674 ). İyi bir alternatif, üzerinde çalıştığınız her özellik için dallar ve bir workdal oluşturmaktır. Ardından, belirli dalları birleştirirsiniz, masterböylece üzerlerindeki geçmişi kaybetmezsiniz. İle çalışırken work, tüm dallarınızı içine birleştirirsiniz. Daha fazla yük, ancak bazı durumlarda buna değebilir.
Hudon

16

Varsayılan olarak git-push tüm dalları iter. Bunu yaptığınızda:

 git checkout HEAD~3  #set head to three commits ago
 git push #attempt push from that head

Ayrılmış bir HEAD'e (herhangi bir dalda değilsiniz) geçersiniz ve daha sonra yerel master (hala olduğu yerde) dahil olmak üzere tüm dalları uzak master'a itersiniz.

Manuel çözüm:

 git push origin HEAD:master

Tüm dalları kafa karıştırıcı (ve tehlikeli!) Zorlama varsayılan davranışını bulursanız, bunu ~ / .gitconfig dosyanıza ekleyin:

 [remote.origin]
    push = HEAD

Sonra sadece bulunduğunuz şube itilir. Örneğinizde (ayrılmış bir kafa), yanlışlıkla yanlış taahhütleri yerine göndermek yerine bu hata mesajına sahip olursunuz:

 error: unable to push to unqualified destination: HEAD

10

Kısa cevap:

git push <latest commit SHA1 until you want commits to be pushed>

Örnekler:

git push fc47b2

git push HEAD~2

Uzun cevap:

Taahhütler, bir ebeveyn / çocuk mekanizmasına sahip bir zincir olarak birbirine bağlıdır. Böylece, bir taahhüdü zorlamak aynı zamanda tüm ebeveyn taahhütlerini uzaktan bilmediği yerlerde bu taahhüde iter . Bu, git pushgeçerli taahhüdünüz olduğunda örtük olarak yapılır : önceki komutların tümü de itilir çünkü bu komut şuna eşdeğerdir:git push HEAD .

Bu yüzden soru , belirli bir taahhüdü nasıl zorlanır? ve bu spesifik taahhüt, örneğin HEAD ~ 2 olabilir.

Eğer itmek istediğiniz taahhütler ardışık değilse, sadece belirli bir itmedengit rebase -i önce a ile yeniden sipariş verin .


5

1) İsterseniz taahhütlerinizi yeniden sıralamak için "git rebase" kullanın.

git rebase -i

Bu komut düzenleyicinizde böyle bir şey görüntüler (vim kullanıyorum)

pick 4791291 commitA
pick a2bdfbd commitB
pick c3d4961 commitC
pick aa1cefc commitD
pick 9781434 commitE

# Rebase ..............
#
# Commands:
#  p, pick = use commit
#  r, reword = use commit, but edit the commit message
#  e, edit = use commit, but stop for amending
#  s, squash = use commit, but meld into previous commit
#  f, fixup = like "squash", but discard this commit's log message
#  x, exec = run command (the rest of the line) using shell
#
# These lines can be re-ordered; they are executed from top to bottom.
#
# If you remove a line here THAT COMMIT WILL BE LOST.
#
# However, if you remove everything, the rebase will be aborted.
#
# Note that empty commits are commented out




^G Get Help         ^O WriteOut         ^R Read File        ^Y Prev Page                ^K Cut Text         ^C Cur Pos
^X Exit             ^J Justify          ^W Where Is         ^V Next Page            ^U UnCut Text       ^T To Spell

2) Basit kesim macunu ile taahhütlerinizi seçiminize göre yeniden düzenleyin. Yeni siparişin

9781434 kesinleştirme seç

c3d4961 hizmetini seçme

4791291 taahhüdü seç

aa1cefc taahhüdü seç

a2bdfbd taahhütünü seç

Bu değişiklikleri düzenleyicinizde yapın ve ctrl + O (writeOut) tuşlarına basın

Ya da kullanabilirsiniz

git rebase -i HEAD~<commitNumber>

Yeni diziyi

git log

3) Şimdi kullanın

git push <remoteName> <commit SHA>:<remoteBranchName>

Uzakta (orijin) yalnızca bir dal ve yerelde (ana) bir şube varsa,

git push <commit SHA>
git push aa1cefc

Bu, commandB ve commandD'yi zorlar.

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.