Önceki cevapların çoğu tehlikeli bir şekilde yanlıştır!
Bunu yapma:
git branch -t newbranch
git reset --hard HEAD~3
git checkout newbranch
Bir dahaki sefere koştuğunuzda git rebase
(veya git pull --rebase
) bu 3 taahhüt sessizce atılacaktır newbranch
! (aşağıdaki açıklamaya bakınız)
Bunun yerine şunu yapın:
git reset --keep HEAD~3
git checkout -t -b newbranch
git cherry-pick ..HEAD@{2}
- Önce 3 En son kaydedilmesini atar (
--keep
gibidir --hard
, ancak daha güvenli olarak atmak uzakta kararsız değişiklikler ziyade başarısız).
- Sonra çatallanır
newbranch
.
- Sonra bu 3 taahhüdü tekrar yerine getirir
newbranch
. Artık bir şube tarafından başvurulan konum nedeniyle, seyahatseverlerin Git en kullanarak bunu yapmaz reflog : HEAD@{2}
o taahhüt olduğunu HEAD
biz 1. teslim önce 2 operasyon öncesine yani ifade etmek için kullanılır newbranch
ve 2. kullanılan git reset
3 kaydedilmesini atmak.
Uyarı: reflog varsayılan olarak etkindir, ancak manuel olarak devre dışı bıraktıysanız (örn. "Çıplak" git deposu kullanarak), çalıştırdıktan sonra 3 işlemi geri alamazsınız git reset --keep HEAD~3
.
Reflog'a güvenmeyen bir alternatif:
# newbranch will omit the 3 most recent commits.
git checkout -b newbranch HEAD~3
git branch --set-upstream-to=oldbranch
# Cherry-picks the extra commits from oldbranch.
git cherry-pick ..oldbranch
# Discards the 3 most recent commits from oldbranch.
git branch --force oldbranch oldbranch~3
(tercih ederseniz @{-1}
- daha önce teslim alınmış dal - yerine yazabilirsiniz oldbranch
).
Teknik açıklama
git rebase
İlk örnekten sonra neden 3 taahhüdü iptal edesiniz? Çünkü git rebase
hiçbir argüman, --fork-point
varsayılan olarak, yerel itme kuvvetini zorlanan yukarı akış dalına karşı sağlam olmaya çalışmak için kullanır seçeneği etkinleştirir .
Diyelim ki M1, M2, M3 taahhütlerini aldığında orijin / master dallı, sonra üç taahhütte bulundun:
M1--M2--M3 <-- origin/master
\
T1--T2--T3 <-- topic
ama sonra birisi M2'yi çıkarmak için başlangıç noktasını / ustayı zorlayarak tarihi yeniden yazar:
M1--M3' <-- origin/master
\
M2--M3--T1--T2--T3 <-- topic
Yerel refleksinizi kullanarak git rebase
, başlangıç / ana dalın daha önceki bir enkarnasyonundan çatallandığınızı ve dolayısıyla M2 ve M3 taahhütlerinin gerçekten konu dalınızın bir parçası olmadığını görebilirsiniz. Bu nedenle, M2, akış yukarı daldan kaldırıldığından, konu dalı yeniden oluşturulduktan sonra artık konu dalınızda istemediğinizi varsayar:
M1--M3' <-- origin/master
\
T1'--T2'--T3' <-- topic (rebased)
Bu davranış mantıklıdır ve genellikle yeniden basarken yapılacak doğru şeydir.
Bu yüzden aşağıdaki komutların başarısız olmasının nedeni:
git branch -t newbranch
git reset --hard HEAD~3
git checkout newbranch
çünkü reflogları yanlış durumda bırakırlar. Git newbranch
, 3 komutu içeren bir revizyonda yukarı akış dalını çatalladığını görür , daha sonra reset --hard
taahhütleri kaldırmak için yukarı akış tarihini yeniden yazar ve böylece bir daha çalıştırdığınızda git rebase
bunları yukarı akıştan kaldırılan diğer herhangi bir taahhüt gibi atar.
Ancak bu özel durumda, bu 3 taahhüdün konu dalının bir parçası olarak değerlendirilmesini istiyoruz. Bunu başarmak için, 3 taahhüdü içermeyen daha önceki revizyonda yukarı akış yönünü kesmemiz gerekir. Benim önerdiğim çözümler bunu yapıyor, bu yüzden ikisi de reflog'u doğru durumda bırakıyor.
Daha fazla ayrıntı --fork-point
için git rebase ve git merge-base docs içindeki tanımına bakın .