Neden bu güncel Git alt ağacını itemiyorum?


88

Git alt ağacını, aralarında bazı temel kodları paylaşmak için üzerinde çalıştığım birkaç proje ile kullanıyorum. Temel kod sık sık güncellenir ve yükseltmeler projelerin herhangi birinde yapılabilir ve sonunda tümü güncellenir.

Git'in alt ağacımın güncel olduğunu bildirdiği, ancak zorlamanın reddedildiği bir sorunla karşılaştım. Örneğin:

#! git subtree pull --prefix=public/shared project-shared master
From github.com:****
* branch            master     -> FETCH_HEAD
Already up-to-date.

Eğer bastırırsam, itecek bir şey olmadığına dair bir mesaj almalıyım ... Değil mi? SAĞ? :(

#! git subtree push --prefix=public/shared project-shared master
git push using:  project-shared master
To git@github.com:***
! [rejected]        72a6157733c4e0bf22f72b443e4ad3be0bc555ce -> master (non-fast-forward)
error: failed to push some refs to 'git@github.com:***'
hint: Updates were rejected because the tip of your current branch is behind
hint: its remote counterpart. Merge the remote changes (e.g. 'git pull')
hint: before pushing again.
hint: See the 'Note about fast-forwards' in 'git push --help' for details.

Bunun nedeni ne olabilir? Neden zorlamak başarısız oluyor?


git'in sana söylediği şeyi neden yapmıyorsun: git çekme?
AlexWien

8
Git pull'un sorumla ilgisi yok. Ama evet, git pull bana güncel bir mesaj veriyor, çünkü kaynak deposunda yeni bir şey yok.
mateusz

1
Bulunduğunuz dal ana HEAD'in arkasında olduğu gibi görünüyor - örneğin, bir ... -> A -> B -> C geçmişi, burada uzak ana HEAD C konumunda, ancak mevcut dalınız A'da (veya C'ye bağlı olmayan A'nın soyundan gelen). Emin olmak için git geçmişime bakardım.
Mark Leighton Fisher

Bendede aynı sorun var. --rejoinAlt ağaç itmelerini hızlandırmak için kullanıyorum . Alt ağaç itme işleminde manuel olarak adım attığımda, çalıştırarak subtree split --rejoin, bölünmüş alt ağaç dalı yalnızca normal olarak tüm alt ağaç geçmişini içerdiğinde son yeniden katılmaya kadar geçmişe sahiptir. Benim için, hızlı ileri olmayan hatanın acil nedeni budur. Hala alt ağaç bölünmesinin neden kesilmiş bir geçmiş oluşturduğundan emin değilim.
hurrymaplelad

Yanıtlar:


99

Cevabı bu blog yorumunda buldum https://coderwall.com/p/ssxp5q

İttiğinizde "Güncel dalınızın ucu geride olduğu için güncellemeler reddedildi. Uzaktan değişiklikleri birleştirme (ör." Git çekme ")" sorunuyla karşılaşırsanız (her ne sebeple olursa olsun, özellikle git geçmişiyle uğraşıyorsanız) daha sonra git komutlarını iç içe yerleştirmeniz gerekir, böylece heroku'ya zorla itme yapabilirsiniz. ör. yukarıdaki örnek verildiğinde:

git push heroku `git subtree split --prefix pythonapp master`:master --force

8
Bu komut Windows'ta nasıl çalıştırılır? Ben alıyorumerror: unknown option 'prefix'
pilavı

3
Harika, bu sadece günümü kurtardı :)
bpipat

1
Bir çözüm sağlasa da, davranışı açıklamıyor.
klimkin

2
Doğru, ancak muhtemelen bu şekilde alt ağacın çoğu kullanımı, heroku'ya tek yönlü bir itmedir. Genel olarak, heroku, birden çok kullanıcının itip çekebileceği bir defacto git deposu olarak kabul edilmez.
Eric Woodruff

11
Cevapta hangi ilişkiyi herokuve ne olduğunu belirlemekte zorlandım pythonapp. Bunu Heroku'ya özgü dilden git push <your subtree's origin> `git subtree split --prefix=Path/to/subtree master`:master --force
çevirmek

39

Windows'ta iç içe yerleştirilmiş komut çalışmaz:

git push heroku `git subtree split --prefix pythonapp master`:master --force

Önce iç içe biti çalıştırabilirsiniz:

git subtree split --prefix pythonapp master

Bu (birçok sayıdan sonra) bir jeton döndürür, örneğin

157a66d050d7a6188f243243264c765f18bc85fb956

Bunu içeren komutta kullanın, örneğin:

git push heroku 157a66d050d7a6188f243243264c765f18bc85fb956:master --force

Bu çok daha temiz bir çözüm. Benim için çalışıyor!
Infinity

Git subtree split --prefix subtreedirectoryname master'ı çalıştırdığımda, ölümcül belirsiz bağımsız değişken 'master' alıyorum: bilinmeyen revizyon veya çalışma ağacında olmayan yol
Demodave,

Bu harika bir çözüm, daha git subtreeönce almadığım bir emir değil. Çözümünüzü kullandıktan sonra tüm depom yerine heroku'ya bir klasör dağıtabildim
pakman198

Harika çözüm ve zaman tasarrufu
Nisharg Shah

29

--ontoBayrağı kullanın :

# DOESN'T WORK: git subtree push --prefix=public/shared project-shared master --onto=project-shared/master

[DÜZENLEME: maalesef subtree pushdeğil ileriye yapar --ontoyatan üzere split, operasyon iki komutlar yapılmalıdır böylece! Bunu yaptıktan sonra, komutlarımın diğer cevaplardan birindekilerle aynı olduğunu görüyorum, ancak açıklama farklı olduğundan yine de burada bırakacağım.]

git push project-shared $(git subtree split --prefix=public/shared --onto=project-shared/master):master

Veya bash kullanmıyorsanız:

git subtree split --prefix=public/shared --onto=project-shared/master
# This will print an ID, say 0123456789abcdef0123456789abcdef,
# which you then use as follows:
git push project-shared 01234567:master

Bunu çözmek için git-subtree kaynağını inceleyerek saatler harcadım, bu yüzden umarım takdir edersiniz;)

subtree pushçalıştırarak başlar subtree split, bu da kaydetme geçmişinizi aktarmaya hazır olması gereken bir biçime yeniden yazar. Bunu yapmanın yolu, kendisine sahip public/shared/olan herhangi bir yolun önünü çıkarır ve ona sahip olmayan dosyalar hakkındaki tüm bilgileri kaldırır. Bu, sıkıştırılmamış şekilde çekseniz bile, tüm yukarı akış alt depo kayıtlarının, dosyaları çıplak yollarıyla adlandırdıkları için göz ardı edildiği anlamına gelir. (Altındaki hiçbir dosyaya dokunmayan taahhütlerpublic/shared/veya bir üst öğe ile aynı olan birleştirme kaydetmeleri de daraltılır. [DÜZENLEME: Ayrıca, o zamandan beri bazı squash algılamasını buldum, bu yüzden şimdi sadece ezilmeden çekerseniz ve daha sonra başka bir cevapta açıklanan basit birleştirme kesinleştirme çökmesi ezilmemiş yolu seçmeyi başarır ve sıkıştırılmış yolu atın.]) Sonuç olarak, göndermeye çalıştığı şeyler, birisinin gönderdiğiniz mevcut ana bilgisayar havuzuna taahhüt ettiği herhangi bir işi içerir, ancak doğrudan alt depoya veya başka bir ana bilgisayar aracılığıyla çalışan kişileri çalıştırmaz. depo.

Bununla birlikte, kullanırsanız --onto, tüm yukarı akış taahhütleri kelimesi kelimesine kullanmak için Tamam olarak kaydedilir, bu nedenle yeniden yazma işlemi, yeniden yazmak istediği bir birleştirmenin ebeveynlerinden biri olarak karşısına çıktığında, onları yeniden yazmaya çalışmak yerine tutacaktır. her zamanki gibi.


2
Bu yanıtı bana iki kez yardımcı olan yanıt olarak tavsiye ediyorum. Ve açıklama, bölmenin ve doğru yere itmenin nasıl çalıştığını anlamak için ihtiyacım olan şeydi. Teşekkür ederim.
Kamil Wozniak

2
"Proje ile paylaşılan" nedir?
Colin D

1
@ColinD "proje paylaşımlı" uzaktan kumandanın adıdır. Alınacak ve itilecek yeri yapılandırırken seçmiş olacağınız bir addır. İle uzaktan kumandaların bir listesini alabilirsiniz git remote -v.
entheh

@entheh bunun için harcadığınız saatler jsut günümü yaptı. Teşekkürler!
Haziran

1
Alt deponuzun adı önekle aynı olan bir dizine sahip olduğunda, örneğin alt depoyu ana depoya "libxxx" olarak eklediğinizde ve alt deponuzun da "libxxx adında bir alt dizini olduğunda bu hatanın her zaman meydana geldiğini gördüm. ". Bu durumda git, alt depodaki commit'leri yanlış bir şekilde ana depodaki commit'ler olarak değerlendirecek ve onları bölmeye çalışacaktır. Bu --ontoseçenek, git'in halihazırda alt depoda bulunan kayıtları belirlemesine yardımcı olur.
Cosyn

14

Bir gh-page dalına bir "dist" alt ağaç dağıttığınız "GitHub sayfaları" türü bir uygulama için çözüm şuna benzer bir şey olabilir

git push origin `git subtree split --prefix dist master`:gh-pages --force

Yukarıda verilen heroku örneklerinden biraz farklı göründüğü için bundan bahsediyorum. Benim "dist" klasörümün depomun ana dalında olduğunu görebilirsiniz ve sonra onu bir alt ağaç olarak kökeninde olan gh-sayfalar dalına itiyorum.


3

Bu problemle daha önce de karşılaştım ve işte bu şekilde çözdüm.

Bulduğum şey, yerel ana şubeye bağlı olmayan bir şubem olduğuydu. Bu dal var ve sadece boşlukta asılı duruyor. Sizin durumunuzda muhtemelen denir project-shared. Durumun böyle olduğunu varsayarsak ve git branchbir yerel project-sharedşubeyi gördüğünüzde , aşağıdaki işlemleri yaparak mevcut şubenize yeni taahhütler ' ekleyebilirsiniz ' project-shared:

git subtree split --prefix=public/shared --onto public-shared --branch public-shared

Anladığım kadarıyla git subtreeyeni şube oluşturmaya başlayacağız --onto, bu durumda yerel public-sharedşubeden. O zaman dal, eski public-shareddalın yerini alan bir dal yaratmak anlamına gelir .

Bu, public-sharedşubenin tüm önceki SHA'sını koruyacaktır . Son olarak, bir

git push project-shared project-shared:master

Sizin de bir project-sharedkumandanız olduğunu varsayarsak ; bu , boş project-shared daldaki yerel asmayımaster uzaktan kumandanın dalına itecektir project-shared.


3

Bunun nedeni, orijinal algoritmanın sınırlandırılmasıdır. Birleştirme işlemlerini işlerken, orijinal algoritma ilgisiz üst öğeleri kesmek için basitleştirilmiş bir kriter kullanır. Özellikle, aynı ağaca sahip bir ebeveyn olup olmadığını kontrol eder. Böyle bir üst öğe bulunursa, diğer üst öğelerin alt ağaçla ilgisi olmayan değişikliklere sahip olduğunu varsayarak, birleştirme kesinleştirme işlemini daraltır ve bunun yerine üst işlemeyi kullanır. Bazı durumlarda bu, alt ağaçta gerçek değişikliklere sahip olan geçmişin bölümlerinin atılmasına neden olabilir. Özellikle, bir alt ağaca dokunan ancak aynı alt ağaç değeriyle sonuçlanan işlem dizilerini bırakacaktır.

Bunun nasıl çalıştığını daha iyi anlamak için (kolayca yeniden üretebileceğiniz) bir örnek görelim. Şu geçmişi düşünün (satır biçimi: commit [ağaç] konusu):

% git log --graph --decorate --pretty=oneline --pretty="%h [%t] %s"
*   E [z] Merge branch 'master' into side-branch
|\
| * D [z] add dir/file2.txt
* | C [y] Revert "change dir/file1.txt"
* | B [x] change dir/file1.txt
|/
*   A [w] add dir/file1.txt

Bu örnekte, ayrılıyoruz dir. Taahhüt eder Dve Eaynı ağaca zsahip oluruz, çünkü kesinleştirmemiz vardır C, bu da sonlandırmayı geri alır B, bu yüzden B-Cdizi, dirüzerinde değişiklikler olsa bile hiçbir şey yapmaz .

Şimdi bölme yapalım. İlk önce taahhüt üzerine ayrıldık C.

% git log `git subtree split -P dir C` ...
* C' [y'] Revert "change dir/file1.txt"
* B' [x'] change dir/file1.txt
* A' [w'] add dir/file1.txt

Daha sonra taahhütte ayrılıyoruz E.

% git log `git subtree split -P dir E` ...
* D' [z'] add dir/file2.txt
* A' [w'] add dir/file1.txt

Evet, iki kaydı kaybettik. Bu, ikinci bölünmeyi itmeye çalışırken hataya neden olur, çünkü zaten başlangıç ​​noktasına giren bu iki işleme sahip değildir.

Genellikle bu hatayı kullanarak tolere edebilirsiniz push --force, çünkü bırakılan taahhütler genellikle bunlarda kritik bilgiler içermez. Uzun vadede, hatanın düzeltilmesi gerekir, böylece bölünmüş geçmiş aslında tüm işlemlere sahip olur,dir beklendiği gibi . Düzeltmenin, gizli bağımlılıklar için ebeveyn taahhütlerinin daha derin bir analizini içermesini beklerdim.

Referans için, orijinal kodun davranıştan sorumlu kısmı burada verilmiştir.

copy_or_skip()
  ...
  for parent in $newparents; do
      ptree=$(toptree_for_commit $parent) || exit $?
      [ -z "$ptree" ] && continue
      if [ "$ptree" = "$tree" ]; then
          # an identical parent could be used in place of this rev.
          identical="$parent"
      else
          nonidentical="$parent"
      fi
  ...
  if [ -n "$identical" ]; then
      echo $identical
  else
      copy_commit $rev $tree "$p" || exit $?
  fi

hata 2020-05-09 (Sat) itibariyle düzeltildi mi? @klimkin
halfmoonhalf

hata düzeltildi. bkz: Contrib / subtree: "alt ağaç ayırma" atlanan-birleştirme hatasını düzeltme. github.com/git/git/commit/…
halfmoonhalf

0

Eric Woodruff'un cevabı bana yardımcı olmadı, ancak aşağıdakiler yardımcı oldu:

Genellikle '--squash' seçeneğiyle 'git subtree pull' yaparım. Görünüşe göre bu, işleri uzlaştırmayı zorlaştırdı, bu yüzden bu sefer ezmeden bir alt ağaç çekimi yapmam, bazı çatışmaları çözmem ve sonra itmem gerekiyordu.

Ezilmiş çekmenin herhangi bir çelişki ortaya çıkarmadığını eklemeliyim, bana her şeyin yolunda olduğunu söyledi.


0

Başka bir [basit] çözüm, eğer yapabiliyorsanız başka bir commit yaparak uzaktan kumandanın başını ilerletmektir. Bu gelişmiş kafayı yerel alt ağaca çektikten sonra, ondan tekrar itebileceksiniz.


1
Yerel alt ağaçla senkronize olmayan uzak depodaki aynı sorunu tam olarak bu şekilde çözdüm.
Aidas Bendoraitis

0

Yerel değişiklikleri uzak alt ağaç deposuna zorlayabilirsiniz

git push subtree_remote_address.git `git subtree split --prefix=subtree_folder`:refs/heads/branch --force

0

Chris Jordan'ın çözümüne dayalı olarak Windows kullanıcıları için hızlı bir powershell

$id = git subtree split --prefix pythonapp master
Write-Host "Id is: $id"
Invoke-Expression "git push heroku $id`:master --force"

0

İşte @ entheh'in söylediklerine dayanarak yazdıklarım buydu.

for /f "delims=" %%b in ('git subtree split --prefix [name-of-your-directory-on-the-file-system-you-setup] -b [name-of-your-subtree-branch]') do @set token=%%b
git push [alias-for-your-subtree] %token%:[name-of-your-subtree-branch] --force

pause

0

Bu sorun da vardı. İşte en iyi yanıtlara göre yaptığım şey:

Verilen:

#! git subtree push --prefix=public/shared project-shared master
git push using:  project-shared master
To git@github.com:***
! [rejected]        72a6157733c4e0bf22f72b443e4ad3be0bc555ce -> master (non-fast-forward)
error: failed to push some refs to 'git@github.com:***'
hint: Updates were rejected because the tip of your current branch is behind
hint: its remote counterpart. Merge the remote changes (e.g. 'git pull')
hint: before pushing again.
hint: See the 'Note about fast-forwards' in 'git push --help' for details.

Şunu girin:

git push <origin> 72a6157733c4e0bf22f72b443e4ad3be0bc555ce:<branch> --force

'Git subtree push' tarafından çıkarılan belirtecin 'git push'ta kullanıldığını unutmayın.

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.