Git: Belirli bir taahhüde nasıl yeniden başlanır?


154

Diğer şubenin HEAD'ına değil, belirli bir taahhütte bulunmak istiyorum:

A --- B --- C          master
 \
  \-- D                topic

için

A --- B --- C          master
       \
        \-- D          topic

onun yerine

A --- B --- C          master
             \
              \-- D    topic

Bunu nasıl başarabilirim?


4
Koşmadan git checkout Bönce yapmayı denedin git rebasemi?
Peter-Paul van Gemerden

Hayır, yardım etmeli mi? rebaseÖnemli olan sadece komutun referansları .
Ondra Žižka

Yanıtlar:


98

Beğendiğiniz taahhütte geçici bir dal oluşturarak --onto parametresini kullanmaktan kaçınabilir ve sonra rebase'i basit biçiminde kullanabilirsiniz:

git branch temp master^
git checkout topic
git rebase temp
git branch -d temp

5
Bu RISC benzeri yaklaşımı daha çok seviyorum :) Deneyeceğim. Teşekkürler.
Ondra Žižka

10
Biraz farklı bir senaryoda neden benim için çalışmadığını merak ediyorum . İstediğim grup atlamak pep8 ve dayanmalıdır usta . git rebase temp(üzerinde iken grubun ) ile vazgeçmez "Mevcut şube gruplarına güncel etmektir.".
Alois Mahdal

4
Bu çözüm, konunun zaten master'a dayandığı senaryoda işe yaramaz, ancak master yapmak için bir atada yeniden temellendirmek istiyorsunuz. Bu durumda git rebase --onto <target> <from> <to>, <from> taahhüdünü belirleyebilmeniz için kullanmanız gerekir .
mirzmaster

Şubenin dayandığı aynı taahhüde yeniden sahip olmak istiyorsanız bu en kolay seçenektir.
Ash

1
Çalışıyor gibiyim ama GitLab başka bir şey söylüyor. Eğer 10 komisyonum varsa, 5 komisyonum varsa, benim 2 komisyon aldıktan sonra 8 komisyonum, 5 komisyonum olması bekleniyordu. Ancak bunun yerine bu 5'e daha fazla taahhüt ekler.
ROMANIA_engineer

67

Doğrudan bir yaklaşım bile yapabilirsiniz:

git checkout topic
git rebase <commitB>

6
Benim için bu aslında amaçlananı yapmıyor. Bildiğim kadarıyla söyleyebilirim, o "son ortak ata" üzerine rebase çalışır topicve commitB.
Dan Lenski

2
Works.Quoting Rebase ettiğim gibi değil @DanLenski, dokümanlar , It works by going to the common ancestor of the two branches (the one you’re on and the one you’re rebasing onto), getting the diff introduced by each commit of the branch you’re on, saving those diffs to temporary files, resetting the current branch to the same commit as the branch you are rebasing onto, and finally applying each change in turn. şimdi tekrar denedim ve sadece iyi çalışır gibiydi.
r0hitsharma

1
Süper kolay ve çalışıyor! Şimdi var: commitB_from_master-> topicCommit1-> topicCommit2.
Martin Konicek

Benim için işe yaramadı. Bundan önce GitLab "n önde gidiyor" dedi. Ve şimdi, "m önde gidiyor" der m > n.
ROMANIA_engineer

48

"Üzerine" seçeneğini kullanın:

git rebase --onto master^ D^ D

2
Dve D^"konu" nın son ve sondan sonrasının karması olacak mı?
Ondra Žižka

39
Sözdizimi gibidir git rebase --onto <new-parent> <old-parent>. Git üst işaretçisini farklı bir üst öğeye ayarlama konusuna bakın . Senin durumunda <new-parent> B ve <old-parent> A.
jsz

7
Her zaman 3 argümanı kullanırım: desitnation, taahhütlerin başlangıcı ve bitişi.
Adam Dymitruk

14
Bu benim için çalıştı:git rebase --onto <commit-ID> master

4
@ jsz'ın yorumu doğrudur, Simon South'un yorumunun aksine, tam tersi: git rebase --onto master <commit-ID-of-old-parent>OP için git rebase --onto B A.
gaborous

19

Yukarıdaki jsz tarafından yapılan yorum bana tonlarca acı kazandırdı, bu yüzden herhangi bir taahhüdün üzerine herhangi bir taahhüdü yeniden oluşturmak / taşımak için kullandığım adım adım bir tarif:

  1. Yeniden temel alınacak (taşınacak) dalın önceki bir dallanma noktasını bulun - buna yaşlı ebeveyn deyin. Yukarıdaki örnekte bu A
  2. Üstünde şubeyi taşımak istediğiniz bağlılığı bulun - yeni ebeveyn olarak adlandırın. Sınavda B
  3. Şubenizde olmanız gerekir (taşıdığınız kişi):
  4. Rebase'inizi uygulayın: git rebase --onto <new parent> <old parent>

Yukarıdaki örnekte bu kadar basit:

   git checkout topic
   git rebase --onto B A

6
Bu doğru cevap olmalı. Ben kullanımı hariç git rebase --onto B master, bkz cevabım daha kapsamlı açıklama için.
Zack Morris

Benim için iyi olmadı. Birbirini takip eden 2 taahhüt seçtim (sonuncusu mevcut dalda olan master'dan ve ilk olarak mevcut dalda olmayan master'dan). Ben 100 arkasında - 10 önde, 99 arkasında - 10 önde, şimdi 105 - 13 önde.
ROMANIA_engineer

İşe yaramadığını duyduğuma üzüldüm. Şubeleriniz biraz sapmış gibi görünüyor - şubeleri bu çok farklılıkla yeniden oluşturmaya çalışmadan önce ezmeyi öneriyorum.
Nestor Milyaev

11

Konu Çözümü

Gönderilen soruyu cevaplamak için doğru komut aşağıdakilerden herhangi biri olabilir (şubenin topiczaten teslim alınmış olduğu varsayılarak ):

git rebase --onto B master
git rebase --onto master~1 master
git rebase --onto B A
git rebase --onto B C
git rebase --onto B

Eğer topicteslim edilmez, sadece ekleme topic(sonuncusu hariç) komutuna şöyle:

git rebase --onto B master topic

Alternatif olarak, ilk önce şubeye göz atın:

git checkout topic

Herhangi Bir Taahhüt Dizesini Hedef Taahhütüne Rebase

Belgelere atfedilen, ihtiyacımız olan komutun temel formu:

git rebase --onto <Target> [<Upstream> [<Branch>]]

<Branch>isteğe bağlıdır ve tüm yaptığı komutun geri kalanını çalıştırmadan önce belirtilen dalı denetler. Rebase yapmak istediğiniz şubeyi daha önce kontrol ettiyseniz, buna ihtiyacınız yoktur. <Upstream>Belirtmek için belirtmiş olmanız gerekir, <Branch>yoksa git belirttiğinizi düşünecektir <Upstream>.

<Target>taahhütler dizimize ekleyeceğimiz taahhüt. Bir şube adı verirken, o şubenin ana taahhütlerini belirlersiniz. <Target>taşınan taahhüt dizesinde bulunmayacak herhangi bir taahhüt olabilir. Örneğin:

A --- B --- C --- D         master
      \
       \-- X --- Y --- Z    feature

Tüm özellik dalı taşımak için, seçemezsiniz X, Y, Z, veya featureolduğu gibi <Target>bu yana tüm taşınıyor grup içinde kaydedilmesini vardır.

<Upstream>özeldir çünkü iki farklı anlama gelebilir. Teslim edilen dalın atası olan bir taahhüt ise, o zaman kesme noktası olarak hizmet eder. Ben sağlanan örnekte, bu değil bir şey olurdu C, Dya da master. Teslim <Upstream>edilen şubenin başı taşınacak olana kadar tüm taahhütler .

Ancak, <Upstream>bir ata değilse , git, teslim alınmış dalda ortak bir ata bulana kadar (ve eğer bulamazsa iptal edilir), zinciri belirtilen işleme göre yedekler. Bizim durumumuzda, bir In <Upstream>ait B, C, Dya masterolacak işlemek tüm sonuç Bkesim noktası olarak hizmet veren. <Upstream>kendisi isteğe bağlı bir komuttur ve belirtilmezse, git kullanıma alınan dalın üst kısmına bakar ve bu da girmeye eşdeğerdir master.

Git, keseceği ve taşıyacağı taahhütleri seçtiğine göre, bunları <Target>hedefe uygulanmış olanları atlamak için uygular .

İlginç Örnekler ve Sonuçlar

Bu başlangıç ​​noktasını kullanarak:

A --- B --- C --- D --- E         master
            \
             \-- X --- Y --- Z    feature
  • git rebase --onto D A feature
    Kaydedilmesini geçerli olacaktır B, C, X, Y, Zişlemeye Dve atlama sonunda Bve Conlar zaten uygulanmış çünkü.

  • git rebase --onto C X feature
    Taahhütleri uygular Yve Ztaahhüt eder C, taahhütleri etkili bir şekilde silerX


4

Daha basit bir çözüm git rebase <SHA1 of B> topic. Bu nerede olursanız olun çalışır HEAD.

Bu davranışı git rebase doc'den doğrulayabiliriz

<upstream>Karşı karşıya olmak için yukarı yönlü şube. Sadece mevcut bir şube adı değil, geçerli herhangi bir taahhüt olabilir . Geçerli dal için yapılandırılmış yukarı akış varsayılanı.


topicYukarıdaki komutta SHA1'den de bahsedersem ne olacağını düşünüyor olabilirsiniz ?

git rebase <SHA1 of B> <SHA1 of topic>

Bu da işe yarayacak, ancak rebase Topicbu şekilde oluşturulan yeni şubeye işaret HEADetmeyecek ve müstakil durumda olacaktır. Yani buradan eski el ile silmelisinizTopic ve rebase tarafından oluşturulan yeni dalda yeni bir şube referansı oluşturmanız .


3

Yukarıda açıklanan çözümlerin bir karışımını kullandım:

$ git branch temp <specific sha1>
$ git rebase --onto temp master topic
$ git branch -d temp

Okumayı ve anlamayı çok daha kolay buldum. Kabul edilen çözüm beni birleşme çatışmasına götürüyor (elle düzeltmek için çok tembel):

$ git rebase temp
First, rewinding head to replay your work on top of it...
Applying: <git comment>
Using index info to reconstruct a base tree...
M       pom.xml
.git/rebase-apply/patch:10: trailing whitespace.
    <some code>
.git/rebase-apply/patch:17: trailing whitespace.
        <some other code>
warning: 2 lines add whitespace errors.
Falling back to patching base and 3-way merge...
Auto-merging pom.xml
CONFLICT (content): Merge conflict in pom.xml
error: Failed to merge in the changes.
Patch failed at 0001 <git comment>
The copy of the patch that failed is found in: .git/rebase-apply/patch

When you have resolved this problem, run "git rebase --continue".
If you prefer to skip this patch, run "git rebase --skip" instead.
To check out the original branch and stop rebasing, run "git rebase --abort".

1
Burada da, en popüler 2 cevabı kullandığımda birkaç dosya çakıştı (yani r0hitsharma ve Dymitruk tarafından)
Oliver

3

Yeniden temellendirme çok temel olduğundan, burada Nestor Milyaev'in cevabının bir uzantısı var . Birleştiren jsz en ve Simon Güney'in yorumlarına Adam Dymitruk cevabı çalışır bu komutu verir topicbakılmaksızın gelen o dalları olmadığı şube masterşube yılların taahhüt Aveya C:

git checkout topic
git rebase --onto <commit-B> <pre-rebase-A-or-post-rebase-C-or-base-branch-name>

Son argümanın gerekli olduğunu unutmayın (aksi takdirde şubenizi taahhütte bulunmak için geri sarar B ).

Örnekler:

# if topic branches from master commit A:
git checkout topic
git rebase --onto <commit-B> <commit-A>
# if topic branches from master commit C:
git checkout topic
git rebase --onto <commit-B> <commit-C>
# regardless of whether topic branches from master commit A or C:
git checkout topic
git rebase --onto <commit-B> master

Bu yüzden son komut tipik olarak kullandığım komuttur.


-2

Bunu yapmanın başka bir yolu var ya da sadece bir taahhütten daha fazlasına geri dönmek istiyorsanız.

nTaahhüt sayısına geri dönmek için bir örnek :

git branch topic master~n

Bu soru uğruna, bu da yapılabilir:

git branch topic master~1

Komut mükemmel bir şekilde çalışıyor git version 2.7.4. Başka bir sürümde test etmedim.


Bunu dallanma hakkında bir soru olarak mı yorumladınız? Bu aslında yeniden temellendirme ile ilgili bir soru.
NetherGranite
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.