“Git pull --all” tüm yerel şubelerimi güncelleyebilir mi?


473

Genellikle en az 3 uzak şubem var: master, sahneleme ve üretim. Bu uzak şubeleri takip eden 3 yerel şubem var.

Tüm yerel şubelerimi güncellemek sıkıcı:

git fetch --all
git rebase origin/master
git checkout staging
git rebase origin/staging
git checkout production
git rebase origin/production

Sadece bir "git pull -all" yapmayı çok isterdim, ama işe yarayamadım. Görünüşe göre bir "getirme - tüm", sonra güncel çalışma dalı (hızlı ileri veya birleştirme), ancak diğer yerel dalları değil.

Hala her yerel şubeye manuel olarak geçip güncelleme yapıyorum.


8
Yerel takip kollarının otomatik olarak güncellenmesini sadece hızlı bir şekilde mi gerçekleştirmek istiyorsunuz? Ypu gerekir, becaue birleştirme çözmek zorunda kalacak çelişkili olabilir ...
Jakub Narębski

34
Bununla uğraşmak için 300 dolarlık konservatif bir zaman harcandığını varsayarsak, bu tek sayı şirketlere 77.476 görünüm sayısını kullanarak 23.242.800 $ 'a mal oldu. Şimdi bu soruyu stackoverflow.com/questions/179123/… ve diğerlerini düşünün . Vay.
Luke Puplett

16
@Luke Duyduğum ilk kişi, git'i istediğimiz şeyi yapmaya çalışmak için harcanan zamanın şirketlere para harcadığını gösteriyor. Bu basit şeyler otomatik olmalı ve o kadar basit olmalı ki, forumları okumak için bir tarayıcı açmam gerekmiyor, IMO.
Samuel

13
@LukePuplett Git konusunda SO ile ilgili Mercurial'a göre yaklaşık ~ 9 kat daha fazla soru var ve birincisinin çoğunluğu "git'te nasıl <basit işlem> yapabilirim?" Bu, git'in kötü tasarlanmış, kötü belgelenmiş, sezgisel olmadığını veya üçünün de olduğunu gösterir.
Ian Kemp

26
@IanKemp SO'nun demografisini bilmeden bu iddiada bulunmanın güvenli olduğundan emin değilim. Mercurial burada yaygın olarak kullanılmıyorsa veya kullanıcıları bunu sormak için başka forumlar kullanıyorsa, aynı sonucu görmeyi beklerim. :) Javascript'te Meclise kıyasla ~ 51 kat daha fazla soru var - bu yüzden araçları sadece bu tür metriklerle yargılamak her zaman doğru olmayabilir.
danShumway

Yanıtlar:


188

Tanımladığınız davranış pull --all, tam olarak beklendiği gibi olmakla birlikte, mutlaka yararlı değildir. Bu seçenek git fetch'e iletilir ve daha sonra sadece gerekli olan yerine tüm uzaktan kumandalardan tüm referansları alır; pulldaha sonra uygun tek dalı birleştirir (veya sizin durumunuzda yeniden temellendirir).

Diğer şubelere göz atmak isterseniz, şubelere göz atmanız gerekecek. Ve evet, birleştirme (ve yeniden bastırma) kesinlikle bir çalışma ağacı gerektirir, bu nedenle diğer dalları kontrol etmeden yapılamazlar. İsterseniz, açıkladığınız adımları bir komut dosyasına / takma ada sarabilirsiniz, ancak komutlardan &&birine katılmayı önermem, böylece bunlardan biri başarısız olursa, sürmeye çalışmaz.


2
Örnek bir komut satırı verirseniz oy kullanırım. Github'da bu sorun var. Kullanıcı arayüzünde bir şube oluşturdum. Şimdi şubeyi göstermek için yerelime ihtiyacım var. git pull --all; git branch ... argh ... komut: git branch -a
mariotti

@mariotti Yapmaya çalıştığınız şeye bağlıdır ve yorumunuzdan pek de net değildir. En iyisi yeni bir soru sormak olabilir.
Cascabel

1
Ya da @Jefromi .. bir örnek verin. Aslında sana katılıyorum.
mariotti

3
@mariotti Bu cevabın amacı, yerleşik komutların OP'nin istediği şeyi gerçekten yapmamasıdır, bu nedenle adımların sırası gereklidir. Bu adımları otomatikleştirmek mümkündür (örneğin, John'un cevabına bakınız), ancak yapılması gerekir. Yapmaya çalıştığınız şey OP ile tamamen aynıysa, verilecek gerçekten bir örnek yok ve farklı bir şey yapmaya çalışıyorsanız, yeni bir soru sormalısınız - StackOverflow böyle çalışır! (Ve yorumunuz net değil, ama en iyi tahminim burada OP'den farklı bir şey istemeniz, bu yüzden evet, yeni soru.)
Cascabel

Evet, biraz farklı bir şey. Ama cevabınız sadece içerik için mükemmeldi. Ve sadece cevabınız yüzünden sormam gerekmeyebilir. Just: Kabul edilen cevap git-up komutunu kullanır, ki bu sadece git komut satırına bir arayüzdür (sanırım). Git komutlarının birkaç satırında bunu açıkça yapabileceğinizi umuyordum. Geçerli cevap git DEĞİLDİR.
mariotti

206

Kullandığım syncalt komutunu ait göbeğine bu otomatikleştirmek için. Bende var , bu yüzden alias git=hubyazdığım .bash_profilekomut:

git sync

Bu, eşleşen bir yukarı akış dalı olan tüm yerel dalları güncelleştirir. Man sayfasından:

  • Yerel şube eskiyse, hızlı ileri sarın;
  • Yerel şubede baskısız iş varsa, uyarın;
  • Şube birleşmiş gibi görünüyorsa ve akış yukarı şubesi silinmişse silin.

Ayrıca, geçerli dalda saklanan / kaldırılmamış taahhüt edilmemiş değişiklikleri de yönetir.

Git-up adlı benzer bir araç kullanıyordum , ancak artık korunmuyor ve git syncneredeyse aynı şeyi yapıyor.


15
Peki ya Windows?
Menekşe Zürafa

6
@ TrentonD.Adams taahhüt tarihleri ​​ve yazar tarihleri ​​farklı kavramlardır. Rebase, yayınlanma tarihini değiştirir ancak yazar tarihini değiştirmez (yazar tarihinin de değiştiği çakışmalar hariç). Yazar tarihi, taahhüt ağacının ne zaman yazıldığını yansıtır ve sorunsuz bir yeniden pazarlama sırasında değişmemelidir. Teslim tarihi değişir çünkü rebase her zaman yeni bir taahhüt oluşturur. Dolayısıyla, taahhüt tarihleri ​​her zaman doğru sırada olacaktır.
Dev

16
Git-up'ın otomatik yeniden basma davranışını kapatmak için çalıştırın git config --global git-up.rebase.auto false.
Dan Loewenherz

18
@MaxYankov Yeniden paylaşılan paylaşılan tarih genellikle kaçınılmalıdır, bir çekme sırasında yerel taahhütleri yeniden bastırmada yanlış bir şey yoktur.
Dev

23
Yerel taahhütleri yeniden oluşturmak, geçmişi yeniden yazmak ve gerçekte olduğundan daha basit hale getirmektir. Rebase ile kendinizi otomatik olarak birleştirilen, ancak derlemeyen veya daha kötüsü derleyen, ancak çalışmayan kodlarla bulabilirsiniz. Birleştirme, çalışma şeklinizi kabul eder: değişiklikleri uyguladınız ve diğer insanların değişikliklerini dahil etmeden önce bunları test ettiniz ve birleştirme taahhüdü çok yararlı bir nokta: farklı sayfaların birlikte güzel oynadığından emin olduğunuz yer burası. Yeniden inşası, bu sürecin asla gerçekleşmediğini gösteriyor, ki bu doğru değil ve çok tehlikeli bir uygulamadır.
Max Yankov

39

Bu sorunun neredeyse 3 yaşında olduğunu biliyorum, ama kendime aynı soruyu sordum ve herhangi bir hazır çözüm bulamadım. Böylece, kendime özel bir git komut kabuğu betiği oluşturdum.

İşte gidiyor, git-ffwd-updatescript aşağıdakileri yapıyor ...

  1. bir git remote updatelates devir almak için
  2. daha sonra git remote showuzak bir dalı izleyen yerel dalların bir listesini almak için kullanılır (örn.git pull )
  3. sonra kontrol eder git rev-list --count <REMOTE_BRANCH>..<LOCAL_BRANCH> yerel şubenin uzaktan kumandanın arkasında ne kadar taahhütte bulunduğunu (ve bunun tersi)
  4. Yerel şube 1 veya daha fazla önde ise, YAPILAMAZ hızlı iletilmesi ve ihtiyaçları birleştirilmiş veya elle rebased için
  5. yerel şube 0 önde ise ve 1 veya daha fazla sayıda komisyon varsa, hızlı ileri git branch -f <LOCAL_BRANCH> -t <REMOTE_BRANCH>

komut dosyası şöyle çağrılabilir:

$ git ffwd-update
Fetching origin
 branch bigcouch was 10 commit(s) behind of origin/bigcouch. resetting local branch to remote
 branch develop was 3 commit(s) behind of origin/develop. resetting local branch to remote
 branch master is 6 commit(s) behind and 1 commit(s) ahead of origin/master. could not be fast-forwarded

Komut dosyasının tamamı, olarak kaydedilmeli git-ffwd-updateve üzerinde olması gerekir PATH.

#!/bin/bash

main() {
  REMOTES="$@";
  if [ -z "$REMOTES" ]; then
    REMOTES=$(git remote);
  fi
  REMOTES=$(echo "$REMOTES" | xargs -n1 echo)
  CLB=$(git rev-parse --abbrev-ref HEAD);
  echo "$REMOTES" | while read REMOTE; do
    git remote update $REMOTE
    git remote show $REMOTE -n \
    | awk '/merges with remote/{print $5" "$1}' \
    | while read RB LB; do
      ARB="refs/remotes/$REMOTE/$RB";
      ALB="refs/heads/$LB";
      NBEHIND=$(( $(git rev-list --count $ALB..$ARB 2>/dev/null) +0));
      NAHEAD=$(( $(git rev-list --count $ARB..$ALB 2>/dev/null) +0));
      if [ "$NBEHIND" -gt 0 ]; then
        if [ "$NAHEAD" -gt 0 ]; then
          echo " branch $LB is $NBEHIND commit(s) behind and $NAHEAD commit(s) ahead of $REMOTE/$RB. could not be fast-forwarded";
        elif [ "$LB" = "$CLB" ]; then
          echo " branch $LB was $NBEHIND commit(s) behind of $REMOTE/$RB. fast-forward merge";
          git merge -q $ARB;
        else
          echo " branch $LB was $NBEHIND commit(s) behind of $REMOTE/$RB. resetting local branch to remote";
          git branch -f $LB -t $ARB >/dev/null;
        fi
      fi
    done
  done
}

main $@

1
Bu senaryo için teşekkürler. Birisi bu komut dosyasını windows toplu işine dönüştürebilir mi?
Saariko

@Saariko git'i normal bir windows kabuğunda neden kullanmıyorsunuz? Cygwin gibi bir şey kullanırsanız, bu komut dosyası iyi çalışmalıdır ... (test
etmedim

@RyanWilcox teşekkürler, her (iş-) gün gibi kullanıyorum ... ;-) Git ile ilgili daha fazla komut dosyası ve takma ad için nokta dosyalarıma bakmak isteyebilirsiniz: github.com/muhqu/dotfiles
muhqu

@muhqu Senaryonuzu kullanmaya çalışıyorum ve neden ilk kez çalıştığını bilmiyorum ama şu anda "beklendiği gibi" çalışmıyor. Örneğin, bir göz atın bu . Senaryonuzu çalıştırdıktan sonra master neden hala geride kaldı?
BPL

1
@muhqu Daha yeni git sürümlerinde, -t ve -l öğelerinin tek bir git branchçağrıda birlikte kullanılması beklenmez . Aramayı değiştirmek için -l'yi kaldırdım git branch -f $LB -t $ARB >/dev/null;ve şimdi komut dosyası olması gerektiği gibi çalışıyor.
Radek Liska

24

Otomatikleştirmek o kadar zor değil:

#!/bin/sh
# Usage: fetchall.sh branch ...

set -x
git fetch --all
for branch in "$@"; do
    git checkout "$branch"      || exit 1
    git rebase "origin/$branch" || exit 1
done

4
Komut dosyalarında takma ad kullanmamak en iyisidir. Bu aslında hiçbir şey getirmez, sadece önceden getirilmiş içeriğe dayanır. Sen değişmelidir git rebase origin/$branchiçin git pullo (tahminen kökeni) uygun izleme şubesinden alıp bunu böylece, ve birleştirme veya Rebase ya yapılandırma ile belirlenen.
Cascabel

@Jefromi: Unuttum fetch. Düzenlediniz; OP ne olursa olsun ekstra özellikler / düzeltmeler.
Fred Foo

8
Hala kullanmak isteyeceğinizi pull(veya kontrol edebileceğinizi) düşünüyorum branch.<branch>.rebase, böylece normal olarak çekilecek şekilde ayarlanmış bir dalı yanlışlıkla birleştirmezsiniz (birleştirir).
Cascabel

1
Kullanmayı düşünün set -eyerine || exit 1ilk hatada tercüman çıkış yapmak.
crishoj

18

Bu hala otomatik değil, çünkü bir seçenek olsaydı - ve bunun sadece hızlı ileri güncellemeler için olabileceğinden emin olmak için bazı kontroller olmalı (bu yüzden manuel olarak bir çekme yapmak çok daha güvenlidir!), ancak uyarılar bir yana:

git fetch origin
git update-ref refs/heads/other-branch origin/other-branch

yerel şubenizin konumunu kontrol etmek zorunda kalmadan güncellemek için.

Not: mevcut şube konumunuzu kaybedecek ve menşeinin kolunun bulunduğu yere taşıyacaksınız, yani birleştirmeniz gerekirse veri kaybedeceksiniz!


1
Tam da aradığım çözüm buydu. Genellikle birden çok dalda unpushed değişiklik yok ve sadece çeşitli yerel şubelerimi uzaktan kumanda ile eşleşecek şekilde güncellemek istiyorum. Bu çözüm her zamanki silme / yeniden ödeme yöntemimden çok daha güzel!
Dave Knight

1
tek bir komutta birleştirildi:git fetch origin other-branch:other-branch
fabb

12

Burada çok sayıda cevap var, ancak git-fetchyerel ref'yi doğrudan güncellemek için kullananlar yok , bu da şubeleri kontrol etmekten çok daha basit ve daha güvenligit-update-ref .

Burada git-fetchgüncel olmayan dalları güncellemek git pull --ff-onlyiçin ve mevcut şube için kullanıyoruz. O:

  • Şubelerin kontrol edilmesini gerektirmez
  • Şubeleri yalnızca hızlı yönlendirilebiliyorsa günceller
  • Hızlı ilerleyemediğinde rapor verir

ve işte burada:

#!/bin/bash
currentbranchref="$(git symbolic-ref HEAD 2>&-)"
git branch -r | grep -v ' -> ' | while read remotebranch
do
    # Split <remote>/<branch> into remote and branchref parts
    remote="${remotebranch%%/*}"
    branchref="refs/heads/${remotebranch#*/}"

    if [ "$branchref" == "$currentbranchref" ]
    then
        echo "Updating current branch $branchref from $remote..."
        git pull --ff-only
    else
        echo "Updating non-current ref $branchref from $remote..."
        git fetch "$remote" "$branchref:$branchref"
    fi
done

Manpage'ten git-fetch:

   <refspec>
       The format of a <refspec> parameter is an optional plus +, followed by the source ref <src>,
       followed by a colon :, followed by the destination ref <dst>.

       The remote ref that matches <src> is fetched, and if <dst> is not empty string, the local ref
       that matches it is fast-forwarded using <src>. If the optional plus + is used, the local ref is
       updated even if it does not result in a fast-forward update.

Belirleyerek git fetch <remote> <ref>:<ref>(herhangi bir+ ) , yerel ref'yi yalnızca hızlı yönlendirilebildiğinde güncelleyen bir getirme alırız.

Not : Bu, yerel ve uzak dalların aynı şekilde adlandırıldığını (ve tüm şubeleri izlemek istediğinizi) varsayar, hangi yerel şubeleriniz ve izlemek için ayarlandıkları hakkında gerçekten bilgi kullanmalıdır.


1
"Şubeleri yalnızca hızlı yönlendirilebiliyorsa güncelleştirir" - hızlı ileri sarmanın önemi nedir? Tüm şubelerimdeki en son kaynakları istiyorsam neden hızlı iletmeyi önemsemem ya da etmemeliyim? Git ve Fanboy'lara beni güldüren bu gibi şeyler. Bunu tek bir komutla yapamazsınız. Bunun c*nyerine (1 yerine) adımları uygulamanız gerekir ; burada ctekrarlanan komutların nsayısı ve dalların sayısıdır.
jww

@jww Dünyanın en çok kullandığı VCS olduğunda "Git'e ve Fanboy'larına gülmek" yardımcı olmaz. Ama konuya giriyorum ... Bu tür bir "küresel çekme" senaryosu bağlamında, güncel olmayan şubelerde birleşme çatışmaları varsa değişiklik yapmaya çalışmamak ihtiyatlı.
Ville

Bu yardımcı oldu, teşekkür ederim. Tek şey ben değiştim bu yüzden, (ilgilenmiyorum hangi olanlar dahil) her uzak şube için yerel bir şube oluşturulmuş olmasıydı değil gibi yaptım git branch -r | grep -v ' -> ' | while read remotebranchetmek git branch -r | grep -v ' -> ' | grep -f <(git branch | cut -c 3- | awk '{print "\\S*/"$0"$"}') | while read remotebranchZaten yerel olarak sahip dalları için sınırlamak için. Ayrıca git fetch --prune, başlangıçta bir şey yapmadan önce uzak dallar listesini güncellemek için bir uyarı ekledim .
Nate Cook

11

Bu sorun çözülmedi (henüz), en azından kolay / komut dosyası olmadan: Junio ​​C Hamano'nun durumu açıklayan ve basit bir çözüm çağrısı yapan git posta listesindeki bu gönderiye bakın.

En büyük mantık şuna ihtiyacınız olmamasıdır:

Eski olmayan git (yani v1.5.0 veya daha yeni) ile artık uzaktan kumandayı izleyen yerel "dev" olmanız için hiçbir neden yoktur. Sadece bakmak ve görmek istiyorsanız, uzaktan izleme kolunu doğrudan " git checkout origin/dev" ile ayrılmış bir HEAD üzerinden kontrol edebilirsiniz .

Bu, kullanıcılar için uygun hale getirmemiz gereken tek durumun, yerel değişiklikleriniz olduğunda veya bazılarını almayı planladığınızda uzak olanları "izleyen" yerel şubeleri ele almak olduğu anlamına gelir.

"Dev" kaldırmayı izlemek için işaretlenmiş "dev" üzerinde yerel değişiklikleriniz varsa ve "dev" den farklı bir daldaysanız, " git fetch" uzaktan izlemeyi "dev" güncelledikten sonra hiçbir şey yapmamalıyız . Yine de hızlı ilerlemeyecek

Çözüm çağrısı , orijinal poster talep edilen gibi, hızlı yönlendirme ile güncel tutmak yerine, artık uzaktan izleme dallarını takip eden yerel şubeleri budamak için bir seçenek veya harici komut dosyası için yapıldı .

Peki git branch --prune --remote=<upstream>yerel dallar üzerinde yinelenen " "

(1) mevcut şube değildir; ve
(2) <upstream> 'den alınan bir dalı izlemek için işaretlenmiş olması; ve
(3) tek başına herhangi bir taahhüdü yoktur;

o şube kaldırılsın mı? " git remote --prune-local-forks <upstream>" de iyidir; Hangi komutun özelliği bu kadar fazla uyguladığı umurumda değil.

Not: git 2.10'dan itibaren böyle bir çözüm yoktur. Not ogit remote prunealt komutu vegit fetch --pruneartık değil parça dalını uzaktan izleme yerel şube (bunlar için uzaktan izleme şube memba dalıdır) kaldırılmasıyla ilgili, uzaktan var olduğunu dalı için uzaktan izleme dalı kaldırma konusunda bulunmaktadır.


Lütfen bağlantıları göndermek yerine , bağlantıları referans olarak kullanarak gerçek içeriği yayınlayın . Bu bağlantı şimdi öldü. Çok kötü, umut verici geliyordu. (Bu cevabın 2009'dan geldiğini anlıyorum, bu yüzden gelecekteki referans için bir not.)
michael

teşekkürler (ve vay, yıllar sonra hızlı tepki). Şimdi bu iş parçacığı bir "olduğunu görürüz için çağrı ", benim özgün yanlış okuyup aksine basit bir çözüm " sağlayan basit bir çözüm".
michael

@michael_n: genişletilmiş ... hmm, şimdi gönderinin tam olarak istenen çözümle ilgili olmadığını görüyorum, ancak sorun hakkındaydı (XY probleminin olduğu varsayılarak).
Jakub Narębski

Hmm, koparılmış kafa ile bakmak daha kolay yapılmalıdır, özellikle de yararlı bilgiler göstermelidir Durum ve alllow çalışma alanını bazı geri bildirimlerle hızlı bir şekilde iletmek için (çekilen taahhütler gibi). Sonra salt yerel şubelerin yerini alacaktı.
eckes

9

Burada birçok kabul edilebilir cevap var, ancak tesisatın bir kısmı başlatılmayanlara biraz opak olabilir. Kolayca özelleştirilebilen çok daha basit bir örnek:

$ cat ~/bin/git/git-update-all
#!/bin/bash
# Update all local branches, checking out each branch in succession.
# Eventually returns to the original branch. Use "-n" for dry-run.
git_update_all() {
  local run br
  br=$(git name-rev --name-only HEAD 2>/dev/null)
  [ "$1" = "-n" ] && shift && run=echo

  for x in $( git branch | cut -c3- ) ; do
     $run git checkout $x && $run git pull --ff-only || return 2
  done

  [ ${#br} -gt 0 ] && $run git checkout "$br"
}

git_update_all "$@"

Eğer eklerseniz ~/bin/gitsizin için PATH(dosya olduğunu varsayarak ~/bin/git/git-update-all), sadece çalıştırabilirsiniz:

$ git update-all

Teşekkürler! bana bash ile oynarken bir saat kurtardın ...
8ctopus

5

Ekle Bu senaryoyu için .profileMac OS X:

# Usage:
#   `git-pull-all` to pull all your local branches from origin
#   `git-pull-all remote` to pull all your local branches from a named remote

function git-pull-all() {
    START=$(git symbolic-ref --short -q HEAD);
    for branch in $(git branch | sed 's/^.//'); do
        git checkout $branch;
        git pull ${1:-origin} $branch || break;
    done;
    git checkout $START;
};

function git-push-all() {
    git push --all ${1:-origin};
};

1
Bu önce tüm değişiklikleri saklamalı ve sonra geri yüklememeli mi?
Mel

5

İşte iyi bir cevap: Tüm git dalları nasıl getirilir

for remote in `git branch -r`; do git branch --track $remote; done
git pull --all

Neden yapmak öneriyorsun git fetchve git pullbunun yerine sadece bir, git pull?
syntagma

Teşekkürler. Çekme, tüm uzaktan kumandalardan tüm dalları getiriyor gibi görünüyor. Değiştirildi
milkovsky

8
Bu, tüm uzaktan kumandaları getirecek, ancak yalnızca geçerli dalı birleştirecektir. 10 uzaktan kumandanız varsa, her birini manuel olarak kontrol etmeniz ve birleştirmeniz gerekir.
mpoisot

Bunu yaptığınızda tüm uzak şubeler origin/önek ile yerel olarak oluşturulur
Yassine ElBadaoui

3

GitBash için yazdığım bir senaryo . Aşağıdakileri gerçekleştirir:

  • Varsayılan olarak başlangıç ​​noktasını izlemek üzere ayarlanan tüm dallar için başlangıç ​​noktasından çekilir, istenirse farklı bir uzaktan kumanda belirtmenize olanak tanır.
  • Geçerli dalınız kirli bir durumdaysa, değişikliklerinizi saklar ve sonunda bu değişiklikleri geri yüklemeye çalışır.
  • Uzak bir dalı izlemek için ayarlanmış her yerel şube için:
    • git checkout branch
    • git pull origin
  • Son olarak, sizi orijinal şubenize döndürür ve durumunuzu geri yükler.

** Bunu kullanıyorum ama tamamen test etmedim, kendi sorumluluğumda kullanın. Bu komut dosyasının bir örneğini burada .bash_alias dosyasında görebilirsiniz .

    # Do a pull on all branches that are tracking a remote branches, will from origin by default.
    # If current branch is dirty, will stash changes and reply after pull.
    # Usage: pullall [remoteName]
    alias pullall=pullAll
    function pullAll (){
     # if -h then show help
     if [[ $1 == '-h' ]]
    then
      echo "Description: Pulls new changes from upstream on all branches that are tracking remotes."
      echo 
      echo "Usage: "
      echo "- Default: pullall"
      echo "- Specify upstream to pull from: pullall [upstreamName]"
      echo "- Help: pull-all -h"
    else

     # default remote to origin
     remote="origin"
     if [ $1 != "" ]
     then
       remote=$1
     fi

     # list all branches that are tracking remote
     # git branch -vv : list branches with their upstreams
     # grep origin : keep only items that have upstream of origin
     # sed "s/^.."... : remove leading *
     # sed "s/^"..... : remove leading white spaces
     # cut -d" "..... : cut on spaces, take first item
     # cut -d splits on space, -f1 grabs first item
     branches=($(git branch -vv | grep $remote | sed "s/^[ *]*//" | sed "s/^[ /t]*//" | cut -d" " -f1))

     # get starting branch name
     startingBranch=$(git rev-parse --abbrev-ref HEAD)

     # get starting stash size
     startingStashSize=$(git stash list | wc -l)

     echo "Saving starting branch state: $startingBranch"
     git stash

     # get the new stash size
     newStashSize=$(git stash list | wc -l)

     # for each branch in the array of remote tracking branches
     for branch in ${branches[*]}
     do
       echo "Switching to $branch"
       git checkout $branch

       echo "Pulling $remote"
       git pull $remote

     done

     echo "Switching back to $startingBranch"
     git checkout $startingBranch

     # compare before and after stash size to see if anything was stashed
     if [ "$startingStashSize" -lt "$newStashSize" ]
     then
       echo "Restoring branch state"
       git stash pop
     fi
    fi
    }

Eşdeğer bir Windows bat dosyası sağlayabilir misiniz?
Jaffy

1
@Jaffy Ellerimde ne kadar zamanım olduğundan emin değilim ve toplu işte süper akıcı değilim ama bir şans verebilirim. İlerlememi buraya göndereceğim, belki diğerleri içeri girip yardımcı olabilir?
philosowaffle

3

Windows kullanıyorsanız , Python için bir klon olan PyGitUp'ı kullanabilirsiniz git-up. Sen kullanarak yükleyebilir pip ile pip install --user git-upveya yoluyla Scoop kullanarakscoop install git-up

[4]


3

Sadece güncellenmiş bir cevap gönderiyoruz. git-upartık korunmuyor ve belgeleri okursanız , işlevin artık git'te kullanılabildiğinden bahsediyorlar .

Git 2.9 itibariyle git pull --rebase --autostash temel olarak aynı şeyi yapar.

Buna göre, Git 2.9 veya sonraki bir sürüme güncelleme yaparsanız git-up yüklemek yerine bu takma adı kullanabilirsiniz:

git config --global alias.up 'pull --rebase --autostash'

Bunu git pullGit 2.9'dan itibaren de ayarlayabilirsiniz (teşekkürler @VonC lütfen cevabını buradan görebilirsiniz )

git config --global pull.rebase true
git config --global rebase.autoStash true

1
Takma ada gerek yok. Doğru yapılandırma ile basit bir git çekme yeterlidir: stackoverflow.com/a/40067353/6309
VonC

Büyük çağrı sayesinde dışarı @VonC cevabımı güncellenen :) ayrıca bir PR gönderebiliyor git-uponlar söz etmeyin çünkü dokümantasyon
aug

Bu, tüm yerel şubeleri bir kerede güncellemez, bu yüzden çoğunlukla kullandım git-up.
ray

Belgeler güncellendi git-up:)
Ağustos

3

Bu sorunun aynı meselesiyle karşılaştım ...

Kendimi merak, benim .bashrcdosya içinde küçük bir takma ad işlevi yaptım :

gitPullAll() {
    for branch in `git branch | sed -E 's/^\*/ /' | awk '{print $1}'`; do
        git checkout $branch
        git pull -p
        printf "\n"
    done
    echo "Done"
}

Benim için çalıştı (:


2

Eğer hakemler / kafa / usta hızlı-iletilebilir ref / uzaktan kumanda / foo / ustası , çıkış

git merge-base refs/heads/master refs/remotes/foo/master

SHA1 kimliğini döndürmelidir refs / heads / master'ın işaret . Bununla, hiçbir aktarma işlemi uygulanmamış tüm yerel şubeleri otomatik olarak güncelleyen bir komut dosyası oluşturabilirsiniz.

Bu küçük kabuk betiği ( git-can-ff olarak adlandırdım ) nasıl yapılabileceğini gösterir.

#!/bin/sh

set -x

usage() {
    echo "usage: $(basename $0) <from-ref> <to-ref>" >&2
    exit 2
}

[ $# -ne 2 ] && usage

FROM_REF=$1
TO_REF=$2

FROM_HASH=$(git show-ref --hash $FROM_REF)
TO_HASH=$(git show-ref --hash $TO_REF)
BASE_HASH=$(git merge-base $FROM_REF $TO_REF)

if [ "$BASE_HASH" = "$FROM_HASH" -o \
     "$BASE_HASH" = "$FROM_REF" ]; then
    exit 0
else
    exit 1
fi

Bu yorumdan ne ima ediyorsunuz?
hillu

Kendim hillu önerdiği senaryoyu yazamıyorum ve git-merge-base kullanmak için git bilgimden yeterince emin değilim.
Norman Ramsey 10'09

2
Korkarım ki modeli bu kadar nazikçe kullanmak için yeterince iyi anlamıyorum. Bir insanın ticarete geçmek istemesi yeterlidir.
Norman Ramsey

Tommi Virtanen'in "bilgisayar bilimcileri için git" başlıklı makalesini şahsen git modelini ve terminolojisini tanımakta oldukça yararlı buldum.
hillu

2

Matt Connolly'nin cevabını tamamlamak için bu, şubeyi kontrol etmeden hızlı iletilebilen yerel şube referanslarını güncellemenin daha güvenli bir yoludur. Hızlı iletilemeyen (yani saptırılmış olmayan) dalları güncellemez ve şu anda kullanıma alınmış olan dalı güncellemez (çünkü o zaman çalışma kopyası da güncellenmelidir).

git fetch

head="$(git symbolic-ref HEAD)"
git for-each-ref --format="%(refname) %(upstream)" refs/heads | while read ref up; do
    if [ -n "$up" -a "$ref" != "$head" ]; then
        mine="$(git rev-parse "$ref")"
        theirs="$(git rev-parse "$up")"
        base="$(git merge-base "$ref" "$up")"
        if [ "$mine" != "$theirs" -a "$mine" == "$base" ]; then
            git update-ref "$ref" "$theirs"
        fi
    fi
done

2

Yalnızca adları olan şubeleri yukarı akış dallarıyla eşleştiren biraz farklı bir komut dosyası. Hızlı ileri sarma mümkünse mevcut dalı da günceller.

Koşarak tüm dallarınızın akış yukarı dallarının doğru ayarlandığından emin olun git branch -vv. Akış yukarı dalınıgit branch -u origin/yourbanchname

Bir dosyaya kopyalayıp yapıştırın ve chmod 755:

#!/bin/sh

curbranch=$(git rev-parse --abbrev-ref HEAD)

for branch in $(git for-each-ref refs/heads --format="%(refname:short)"); do
        upbranch=$(git config --get branch.$branch.merge | sed 's:refs/heads/::');
        if [ "$branch" = "$upbranch" ]; then
                if [ "$branch" = "$curbranch" ]; then
                        echo Fast forwarding current branch $curbranch
                        git merge --ff-only origin/$upbranch
                else
                        echo Fast forwarding $branch with origin/$upbranch
                        git fetch . origin/$upbranch:$branch
                fi
        fi
done;

2

Aşağıdaki bir astar, mümkünse bir akış yukarı dalı olan tüm dalları hızlı bir şekilde iletir ve aksi halde bir hata yazdırır:

git branch \
  --format "%(if)%(upstream:short)%(then)git push . %(upstream:short):%(refname:short)%(end)" |
  sh

O nasıl çalışır?

git branchKomutu ile özel bir biçim kullanır . Bir akış yukarı dalı olan her dal için, aşağıdaki desenle bir çizgi yazdırır:

git push . <remote-ref>:<branch>

Bu doğrudan sh(dal isimlerinin iyi biçimlendirilmiş olduğu varsayılarak) konulabilir . Atla| sh o ne yaptığını görmek için.

Uyarılar

Tek astar uzaktan kumandanızla temas etmez. Bir git fetchveya git fetch --allçalıştırmadan önce sorun.

Şu anda kullanıma alınmış şube, aşağıdaki gibi bir mesajla güncellenmeyecek

! [remote rejected] origin/master -> master (branch is currently checked out)

Bunun için düzenli olarak başvurabilirsiniz git pull --ff-only.

takma ad

Sizin için aşağıdakileri ekleyin .gitconfigböylece git fftgerçekleştirir bu komut:

[alias]
        fft = !sh -c 'git branch --format \"%(if)%(upstream:short)%(then)git push . %(upstream:short):%(refname:short)%(end)\" | sh' -

Ayrıca bkz .gitconfig. Takma ad "hızlı ileri izleme (şubeler)" için bir kısayol.


Ben kullanıyor olacaktır düşünüyorum ama bu, güzel bir çözümdür @John tarafından propsed soluction 's iyi çıkış için. hub
Didier L

Bu hızlı, basit ve aslında işe yarıyor! Şaşkın olsa git pushda tamamen beklediğiniz ne tersidir. Sırrı ne?
BrandonLWhite

@BrandonLWhite: Soruyu anlamıyorum. Ne bekliyorsun git push?
krlmlr

git pushyükleme semantiği var - Yukarı doğru göndermek istediğim yerel olarak bazı taahhütlerim var. git pullsemantik indiriyor - Yerel şubeme bazı yukarı akış uzaktan taahhütleri almak istiyorum. Uzaktan kumandadan lokal olarak yeni taahhütlerin indirilmesi hakkında konuştuğumuzdan git pull, bariz bir seçim. Ama hayır, bu hile kullanıyor git push. Nasıl yok git pushbenim yerel şubesine uzak değişiklikleri çekerek neden ?!
BrandonLWhite

git pushbir hızlı ileri güncelleme olduğu sürece yerel şubeleri güncellemek için de kullanılabilir.
krlmlr

1

@Larsmans'ın senaryosu biraz gelişti:

#!/bin/sh

set -x
CURRENT=`git rev-parse --abbrev-ref HEAD`
git fetch --all
for branch in "$@"; do
  if ["$branch" -ne "$CURRENT"]; then
    git checkout "$branch" || exit 1
    git rebase "origin/$branch" || exit 1
  fi
done
git checkout "$CURRENT" || exit 1
git rebase "origin/$CURRENT" || exit 1

Bu, bittikten sonra, çalışan kopyayı aynı şubeden teslim alır komut dosyası çağrılmadan .

git pullversiyon:

#!/bin/sh

set -x
CURRENT=`git rev-parse --abbrev-ref HEAD`
git fetch --all
for branch in "$@"; do
  if ["$branch" -ne "$CURRENT"]; then
    git checkout "$branch" || exit 1
    git pull || exit 1
  fi
done
git checkout "$CURRENT" || exit 1
git pull || exit 1

1

Görünüşe göre birçokları benzer çözümlere katkıda bulundu, ancak bulduğum şeyi paylaşacağımı ve başkalarını katkıda bulunmaya davet edeceğimi düşündüm. Bu çözüm güzel bir renkli çıktıya sahiptir, mevcut çalışma dizininizi incelikle işler ve hızlıdır çünkü herhangi bir ödeme yapmaz ve çalışma dizininizi inceden inceye bırakır. Ayrıca, git dışında bağımlılığı olmayan bir kabuk betiğidir. (şu ana kadar yalnızca OSX'te test edilmiştir)

#!/usr/bin/env bash

gitup(){    
RED='\033[33;31m'
YELLO='\033[33;33m'
GREEN='\033[33;32m'
NC='\033[0m' # No Color

HEAD=$(git rev-parse HEAD)
CHANGED=$(git status --porcelain | wc -l)

echo "Fetching..."
git fetch --all --prune &>/dev/null
for branch in `git for-each-ref --format='%(refname:short)' refs/heads`; do

    LOCAL=$(git rev-parse --quiet --verify $branch)
    if [ "$HEAD" = "$LOCAL" ] && [ $CHANGED -gt 0 ]; then
        echo -e "${YELLO}WORKING${NC}\t\t$branch"
    elif git rev-parse --verify --quiet $branch@{u}&>/dev/null; then
        REMOTE=$(git rev-parse --quiet --verify $branch@{u})
        BASE=$(git merge-base $branch $branch@{u})

        if [ "$LOCAL" = "$REMOTE" ]; then
           echo -e "${GREEN}OK${NC}\t\t$branch" 
        elif [ "$LOCAL" = "$BASE" ]; then
            if [ "$HEAD" = "$LOCAL" ]; then
                git merge $REMOTE&>/dev/null
            else
                git branch -f $branch $REMOTE
            fi
            echo -e "${GREEN}UPDATED${NC}\t\t$branch"
        elif [ "$REMOTE" = "$BASE" ]; then
            echo -e "${RED}AHEAD${NC}\t\t$branch"
        else
            echo -e "${RED}DIVERGED${NC}\t\t$branch"
        fi
    else
        echo -e "${RED}NO REMOTE${NC}\t$branch"
    fi
done
}

https://github.com/davestimpert/gitup

Üzgünüm, yukarıdaki diğer araçla aynı adı buldum.


2
Bunu yazan sen misin? Eğer öyleyse, lütfen bağlantınızı açıklayın, yani bize bununla nasıl ilişkili olduğunuzu söyleyin. Daha fazla bilgi için lütfen bununla ilgili daha fazla bilgi edinin. Özellikle söyleme - göster! ; Komut dosyanızın hangi bölümlerini ve sorunu nasıl / neden çözdüğünü bize bildirin.
Keale

1
Evet yazdım. Hızlı bir şekilde yapıştırmak için yukarıdaki kaynağı .bashrc veya .zshrc dosyasına ekledim.
Stimp

Bu güzel bir çözüm ve iyi çalışıyor. Kimse haber almamış mıydı?
Ville

1

Aşağıdaki komut dosyası kullanılarak yapılabilir ... Önce tüm dalları ve kasaları tek tek alır ve kendi kendine günceller.

#!/bin/bash
git branch -r | grep -v '\->' | while read remote; do git branch --track 
"${remote#origin/}" "$remote"; done

set -x
CURRENT=`git rev-parse --abbrev-ref HEAD`
git fetch --all
branch_name=$(git branch | awk '{print $1" "}' | grep -v '*' | xargs)
for branch in $branch_name; do
   git checkout "$branch" || exit 1
   git rebase "origin/$branch" || exit 1
   git pull origin $branch|| exit 1
done
git checkout "$CURRENT" || exit 1
git pull || exit 1

Cevabınızı puanlamak için biraz açıklama ekleyin
fool-dev

1

Bunu sadece bir git komutuyla yapamazsınız, ancak bir bash satırı ile otomatikleştirebilirsiniz.

Tüm dalları tek bir satırla güvenli bir şekilde güncellemek için yaptığım şey:

git fetch --all && for branch in $(git branch | sed '/*/{$q;h;d};$G' | tr -d '*') ; do git checkout $branch && git merge --ff-only || break ; done
  • Bir dalı hızlı ileri alamazsa veya bir hatayla karşılaşamazsa, kontrolü geri alıp manuel olarak birleştirebilmeniz için sizi durdurup sizi o dalda bırakacaktır.

  • Tüm şubeler hızlı yönlendirilebiliyorsa, o anda bulunduğunuz şubeyle sona erecek ve sizi güncellemeden önce bulunduğunuz yerde bırakacaktır.

açıklamalar:

Daha iyi okunabilirlik için birkaç satıra bölünebilir:

git fetch --all && \
for branch in $(git branch | sed '/*/{$q;h;d};$G' | tr -d '*')
    do git checkout $branch && \
    git merge --ff-only || break
done
  1. git fetch --all && ... => Tüm uzaktan kumandalardaki tüm referansları alır ve hata yoksa sonraki komutla devam eder.

  2. git branch | sed '/*/{$q;h;d};$G' | tr -d '*'=> Çıkışında itibaren git branch, sedbir satırı almak *ve sonunda (o kadar geçerli dal son güncelleme olacağını) taşıyın. Sonra trsadece *.

  3. for branch in $(...) ; do git checkout $branch && git merge --ff-only || break ; done=> Önceki komuttan elde edilen her dal adı için bu dalı kontrol edin ve bir hızlı ileri alma ile birleştirmeyi deneyin. Başarısız olursa breakçağrılır ve komut burada durur.

Tabii ki, yerine git merge --ff-onlyile git rebaseİstediğin buysa.

Son olarak, bir diğer ad olarak bashrc'nize koyabilirsiniz :

alias git-pull-all='git fetch --all && for branch in $(git branch | sed '\''/*/{$q;h;d};$G'\'' | tr -d "*") ; do git checkout $branch && git merge --ff-only || break ; done'

Ya da 've' ile uğraşmaktan korkuyorsanız ya da editörünüzde sözdizimsel okunabilirliği korumayı tercih ediyorsanız, bunu bir işlev olarak ilan edebilirsiniz:

git-pull-all()
{
    git fetch --all && for branch in $(git branch | sed '/*/{$q;h;d};$G' | tr -d '*') ; do git checkout $branch && git merge --ff-only || break ; done
}

Bonus:

sed '/*/{$q;h;d};$G'Parça hakkında açıklama yapmak isteyenler için :

  • /*/=> A ile satırı arayın *.

  • {$q => Son satırdaysa, çık (mevcut dal zaten listede sonuncu olduğu için hiçbir şey yapmamız gerekmez).

  • ;h;d} => Aksi takdirde, satırı bekletme arabelleğinde saklayın ve geçerli liste konumunda silin.

  • ;$G => Son satıra ulaştığında, tutma arabelleğinin içeriğini ekleyin.


Sen sonsuz çizgilerin ve tüm delilik önleyebilirsiniz &&ayarlayarak set -escript üst.
Mart'ta

0

“Git pull --all” tüm yerel şubelerimi güncelleyebilir mi?

Hayır bu olamaz. Hızlı yönlendirme için, sadece bunu yapmak için küçük bir araç yazdım. https://github.com/changyuheng/git-fast-forward-all

Bu aracın avantajları:

  1. Bir depoda birden fazla uzaktan kumanda desteği. ( hub syncşu anda birden fazla uzaktan kumandayı desteklemiyor.)
  2. Yerel şube ve ilgili uzaktan izleme branşında farklı isimlere sahip destekler.
  3. Her dal için uzaktan kumanda sağlayan diğer komut dosyalarından çok daha hızlı.
  4. Hataya meyilli regex ayrıştırma / düzenleme yok.

1
Düğmesini kullanarak ağa çarpmaktan kaçınabilirsiniz git fetch . refspec. .Geçerli deposundan yerine uzak birinden almaya söylüyor.
sarıl

-1

Git 2.9 itibariyle:

git pull --rebase --autostash

Bkz. Https://git-scm.com/docs/git-rebase

İşlem başlamadan önce otomatik olarak geçici bir zulası oluşturun ve işlem bittikten sonra uygulayın. Bu, kirli bir çalışma ağacında rebase çalıştırabileceğiniz anlamına gelir. Bununla birlikte, dikkatli kullanın: başarılı bir tekrardan sonraki son saklanma uygulaması önemsiz çatışmalara neden olabilir.


-1

Aslında git ile version 1.8.3.1çalışır:

[root@test test]# git br
* master
  release/0.1
  update
[root@test test]# git pull --rebase
remote: Enumerating objects: 9, done.
remote: Counting objects: 100% (9/9), done.
remote: Compressing objects: 100% (9/9), done.
remote: Total 9 (delta 2), reused 0 (delta 0)
Unpacking objects: 100% (9/9), done.
From http://xxx/scm/csdx/test-git
   d32ca6d..2caa393  release/0.1 -> origin/release/0.1
Current branch master is up to date.
[root@test test]# git --version
git version 1.8.3.1

Ana dalda, diğer tüm dalları güncelleyebilirsiniz. @Cascabel

Hangi sürümü kırmak / düzeltmek bilmiyorum, 2.17 (ki ben kullanmak), çalışabilir.

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.