Bir Git taahhüdünün hangi şubeden geldiğini bulma


649

SHA-1 karma değeri göz önüne alındığında, bir taahhüdün hangi şubeden geldiğini öğrenmenin bir yolu var mı ?

Bonus puanları Ruby Grit kullanarak bunu nasıl başaracağımı söyleyebilirsen bonus puanları.


4
Aşağıda farklı yöntem yollarını çalışan, kullanışlı pragmatik olan anlaması bir muhtemel cevap, ancak sorunun kendisi bir yanlış anlama git de, kaydedilmesini dallardan gelmez notu edelim. Şubeler gelir ve gider, hareket ederler, sadece taahhütler gerçek repo tarihini temsil eder. Sonra tekrar, bu çözümlerin kötü olduğunu söylemenin bir yolu değildir. Sadece hiçbirinin git'de tasarımla elde edilemeyen tamamen güvenilir bir cevap vermediğini bilin . (Basit bir dava dalları silinir: Ben şubesi, iki kez taahhüt, başka bir şubeye birleştiriyorum, ilk dalı
siliyorum. Taahhüt

1
Açıkça bir etiketten derinlik 1 sığ klon çekmek bir durum var. Ucuz ve kolay ve verimli ... ve şimdiye kadar istediğim her şeyi güzelce yaptım. Artık etiketin hangi dalda olduğunu bilmek istiyorum, en azından bu ayrıntı için ıslatılıyorum. Her zaman eve gidemezsin, lol
Paul Hodges

Yanıtlar:


864

Dav, bilgilerin doğrudan saklanmadığı konusunda doğru olsa da, bu asla bulamayacağınız anlamına gelmez. İşte yapabileceğiniz birkaç şey.

Taahhüdün bulunduğu şubeleri bulun

git branch -a --contains <commit>

Bu, tarihlerinde belirli bir taahhütte bulunan tüm şubeleri size söyleyecektir. Açıkçası, taahhüt zaten birleştirilmişse bu daha az yararlıdır.

Refloglarda ara

Taahhüdün yapıldığı depoda çalışıyorsanız, söz konusu taahhüt için satırda refloglarda arama yapabilirsiniz. 90 günden eski refloglar git-gc tarafından budanır, bu nedenle taahhüt çok eski ise bulamazsınız. Bununla birlikte şunları yapabilirsiniz:

git reflog show --all | grep a871742

taahhüt a871742 bulmak için. Taahhüdün ilk 7 rakamını kısaltmanız GEREKİR. Çıktı şu şekilde olmalıdır:

a871742 refs/heads/completion@{0}: commit (amend): mpc-completion: total rewrite

bu taahhüt şube "tamamlanması" üzerine yapıldığını gösterir. Varsayılan çıktı kısaltılmış kesin karmaları gösterir, bu nedenle tam karmayı aramamaya dikkat edin yoksa hiçbir şey bulamazsınız.

git reflog showaslında sadece bir takma addır git log -g --abbrev-commit --pretty=oneline, bu nedenle grep için farklı şeyler yapmak için çıktı formatıyla uğraşmak istiyorsanız, başlangıç ​​noktanız budur!

Taahhüdün yapıldığı depoda çalışmıyorsanız, bu durumda yapabileceğiniz en iyi şey reflogları incelemek ve taahhüdün deponuza ilk ne zaman tanıtıldığını bulmaktır; herhangi bir şansla, taahhüt ettiği şubeyi getirdin. Bu biraz daha karmaşıktır, çünkü hem taahhüt ağacını hem de reflogları aynı anda yürüyemezsiniz. İstenen taahhüdü içerip içermediğini görmek için her karma değerini inceleyerek reflog çıktısını ayrıştırmak istersiniz.

Sonraki birleştirme taahhüdü bulun

Bu iş akışına bağlıdır, ancak iyi iş akışlarıyla, daha sonra birleştirilen geliştirme dallarında taahhütler yapılır. Bunu yapabilirsiniz:

git log --merges <commit>..

verilen taahhüde sahip birleştirme taahhütlerini bir ata olarak görmek. (Taahhüt yalnızca bir kez birleştirildiyse, birincisi peşinde olduğunuz birleştirme olmalıdır; aksi takdirde birkaçını incelemeniz gerekir, sanırım. Birleştirme taahhüdü mesajı birleştirilen şube adını içermelidir.

Bunu yapmaya güvenmek istiyorsanız , hızlı ileri durumda bile birleştirme taahhüdü oluşturmaya zorlamak --no-ffseçeneğini kullanabilirsiniz git merge. (Yine de çok istekli olmayın. Aşırı kullanılırsa bu biraz şaşırtabilir.) VonC'nin ilgili bir soruya vereceği cevap bu konuyu faydalı bir şekilde detaylandırıyor.


5
+1. Belirli bir konu için bilgi eksikliği, bunun gerçekten bir sorun olup olmadığını merak ediyor mu? Şubeler herhangi bir zamanda değiştirilebilir, yeniden adlandırılabilir veya silinebilir. Olabilir git describe(açıklamalı) etiketleri dalları daha önemli olarak görülebilir için, yeterlidir.
VonC

9
Kesinlikle katılıyorum - şubeler hafif ve esnek olmalı. Bu bilgilerin önemli hale geldiği bir iş akışını benimserseniz, --no-ffseçeneği her zaman bir birleştirme taahhüdü olduğundan emin olmak için kullanabilirsiniz , böylece belirli bir taahhüdün yolunu her zaman ana yolla birleştirilirken izleyebilirsiniz.
Cascabel

32
FYI, yalnızca uzaktan kumandada var olan taahhütleri bulmak istiyorsanız, -abayrağı ilk komuta ekleyin, örneğingit branch -a --contains <commit>
Jonathan Day

8
@JonathanDay: Hayır, herhangi bir şubede taahhüt bulacaktır. Yalnızca uzaktan kumandadakileri istiyorsanız kullanın -r.
Cascabel

7
@SimonTewsi Dediğim gibi, gerçekten bir sorun merge --no-ffvarsa, birleştirdiğinizde şube adını güvenilir bir şekilde kaydetmek için kullanın . Ancak aksi halde, şube adlarını geçici kısa etiketler olarak düşünün ve açıklamaları kalıcı olanlar olarak kabul edin. "Geliştirme sırasında buna hangi kısa adı verdik?" "bu taahhüt ne işe yarar?" kadar önemli bir soru olmamalıdır.
Cascabel

154

Bu basit komut bir cazibe gibi çalışır:

git name-rev <SHA>

Örneğin (burada test dalı şube adıdır):

git name-rev 651ad3a
251ad3a remotes/origin/test-branch

Bu bile, aşağıdaki gibi karmaşık senaryolar için çalışıyor:

origin/branchA/
              /branchB
                      /commit<SHA1>
                                   /commit<SHA2>

Burada branchBgit name-rev commit<SHA2> döndürür .


3
Günümü kurtardın. Bu mükemmel bir çözüm.
Taco

7
Ve bu mükemmel çözüm için sadece 8 yıl sürdü. Teşekkürler!
S1J0

6
git name-rev --name-only <SHA>Sadece şube adını almak için daha yararlı buldum . Sorum ... Her durumda birden fazla şubeye geri dönebilir mi?
Dean Kayton

1
Bu en iyi cevap olmalı.
JCollier

1
Nazik sözleriniz için @JCollier'a teşekkür ederiz.
khichar.anil

47

Aralık 2013 Güncellemesi:

sschuberth yorumlar

git-what-branch(Perl betiği, aşağıya bakın) artık korunmuyor gibi görünüyor. git-when-mergedPython'da yazılmış ve benim için çok iyi çalışan bir alternatif.

" Belirli bir taahhüdü içeren birleştirme taahhüdü bul " u temel alır .

git when-merged [OPTIONS] COMMIT [BRANCH...]

Bir taahhüdün bir veya daha fazla şubeye ne zaman birleştirildiğini bulun. Belirtilen BRANCH'lara
getirilen birleştirme taahhüdünü bulun COMMIT.

Özellikle, ata olarak BRANCHiçeren ilk ebeveyn geçmişindeki en eski taahhüdü arayın COMMIT.


Orijinal cevap Eylül 2010:

Sebastien Douche yeni cevap verdi (bu SO cevabından 16 dakika önce):

git-what-branch : Bir taahhüdün hangi şubede olduğunu veya adlandırılmış bir şubeye nasıl geldiğini keşfedin

Bu bir Perl komut gelen Seth Robertson çok ilginç görünüyor:

ÖZET

git-what-branch [--allref] [--all] [--topo-order | --date-order ]
[--quiet] [--reference-branch=branchname] [--reference=reference]
<commit-hash/tag>...

GENEL BAKIŞ

Bize (varsayılan olarak) talep edilen taahhüdün adlandırılmış bir şubeye girmesine neden olmak için en erken taahhüt ve birleşmenin yolunu söyleyin. Doğrudan adlandırılmış bir dalda bir taahhüt yapılmışsa, bu en erken yoldur.

En erken nedensel yolla, --topo-orderbelirtilen zamandaki bir şubeye en erken, kesinleştirme süresiyle ( belirtilmedikçe) birleşen yolu kastediyoruz .

VERİM

Birçok şube (örneğin yüzlerce) taahhüt içeriyorsa, sistem uzun sürebilir (Linux ağacında belirli bir taahhüt için, bir dalı keşfetmek 8 saniye sürdü, ancak yolu izlemek için 200'den fazla aday dalı vardı) her taahhüt için.
İncelemek için belirli bir seçim --reference-branch --reference tagyüzlerce kez daha hızlı olacaktır (yüzlerce aday şubeniz varsa).

ÖRNEKLER

 # git-what-branch --all 1f9c381fa3e0b9b9042e310c69df87eaf9b46ea4
 1f9c381fa3e0b9b9042e310c69df87eaf9b46ea4 first merged onto master using the following minimal temporal path:
   v2.6.12-rc3-450-g1f9c381 merged up at v2.6.12-rc3-590-gbfd4bda (Thu May  5 08:59:37 2005)
   v2.6.12-rc3-590-gbfd4bda merged up at v2.6.12-rc3-461-g84e48b6 (Tue May  3 18:27:24 2005)
   v2.6.12-rc3-461-g84e48b6 is on master
   v2.6.12-rc3-461-g84e48b6 is on v2.6.12-n
   [...]

Bu program kiraz toplama ilgisinin taahhüdünü dikkate almaz, sadece birleştirme işlemleri.


4
git-what-branchartık bakımlı görünmüyor. git-when-merged , Python'da yazılmış ve benim için çok iyi çalışan bir alternatif.
sschuberth

@sschuberth bu güncelleme için teşekkür ederim. Daha fazla görünürlük için yorumunuzu cevaba ekledim.
VonC

37

Örneğin, bu c0118fataahhüdü bulmak için redesign_interactions:

* ccfd449 (HEAD -> develop) Require to return undef if no digits found
*   93dd5ff Merge pull request #4 from KES777/clean_api
|\
| * 39d82d1 Fix tc0118faests for debugging debugger internals
| * ed67179 Move &push_frame out of core
| * 2fd84b5 Do not lose info about call point
| * 3ab09a2 Improve debugger output: Show info about emitted events
| *   a435005 Merge branch 'redesign_interactions' into clean_api
| |\
| | * a06cc29 Code comments
| | * d5d6266 Remove copy/paste code
| | * c0118fa Allow command to choose how continue interaction
| | * 19cb534 Emit &interact event

Koşmalısın:

git log c0118fa..HEAD --ancestry-path --merges

Ve son birleştirme işlemini bulmak için aşağı kaydırın . Hangisi:

commit a435005445a6752dfe788b8d994e155b3cd9778f
Merge: 0953cac a06cc29
Author: Eugen Konkov
Date:   Sat Oct 1 00:54:18 2016 +0300

    Merge branch 'redesign_interactions' into clean_api

Güncelleme

Veya sadece bir komut:

git log c0118fa..HEAD --ancestry-path --merges --oneline --color | tail -n 1

4
Bana istenen sonucu veren tek çözüm buydu. Gerisini denedim.
crafter

Bunun yalnızca birleştirme taahhüdü özetleri, varsayılan olarak genellikle birleştirme işlemlerinde kullanılan şube adlarını içeriyorsa işe yarar. Ancak git merge -m"Any String Here"kaynak ve hedef şube bilgisini gizleyecektir.
qneill

@qneill: Hayır, birleştirme hep birleştirilmiş dalları hakkında bilgi vardır: Merge: f6b70fa d58bdcb. Birleştirme taahhüdünüzü istediğiniz gibi adlandırabilirsiniz.
Önemli

1
@EugenKonkov dallar birleştirmeyi geçtikten sonra, grafikte hangi yoldan geldiklerinin geçmişi reflogda bırakılır, ancak git nesnesi veritabanında kalmaz. Ne dediğimi açıklamaya çalışan bir cevap gönderdim
qneill

UPD sürümü benim için çalışıyor, orijinal taahhüdü bulan basit komut
vpalmu

9

git branch --contains <ref>bunu yapmak için en belirgin "porselen" komutudur. Sadece "sıhhi tesisat" komutlarıyla benzer bir şey yapmak istiyorsanız:

COMMIT=$(git rev-parse <ref>) # expands hash if needed
for BRANCH in $(git for-each-ref --format "%(refname)" refs/heads); do
  if $(git rev-list $BRANCH | fgrep -q $COMMIT); then
    echo $BRANCH
  fi
done

( bu SO cevabından çapraz yazı )


6

khichar.anil bunun çoğunu cevabında ele aldı.

Sadece etiketleri düzeltme adları listesinden kaldıracak bayrağı ekliyorum. Bu bize şunları verir:

git name-rev --name-only --exclude=tags/* $SHA

İkinci cümlede bir şey eksik gibi görünüyor.
Peter Mortensen

Açıklamayı güncelledim. Geri bildirim için teşekkürler.
phyatt

4

Zayıf bir adamın seçenek kullanmaktır aracı tig1 tarihinde HEAD, taahhüt aramak ve sonra görsel olarak yedeklemek bir birleştirme görülür kesinleştirme kadar taahhüt bundan çizgiyi izleyin. Varsayılan birleştirme iletisi hangi dalın nereye birleştirileceğini belirtmelidir :)

1 Tig, Git için ncurses tabanlı bir metin modu arayüzüdür. Temel olarak Git depo tarayıcısı olarak işlev görür, ancak yığın düzeyinde taahhüt için değişikliklerin hazırlanmasına da yardımcı olabilir ve çeşitli Git komutlarından çıktı almak için bir çağrı cihazı görevi görebilir.


3

Bir deneme olarak, taahhütlü meta verilerdeki şu anda teslim alınmış dal hakkındaki bilgileri saklayan bir taahhüt sonrası kanca yaptım. Ben de bu bilgiyi göstermek için gitk'i biraz değiştirdim.

Buradan kontrol edebilirsiniz: https://github.com/pajp/branch-info-commits


1
Ancak meta veri eklemek istiyorsanız, neden taahhüt başlıklarıyla uğraşmak yerine git notlarını kullanmıyorsunuz? Bkz. Stackoverflow.com/questions/5212957/… , stackoverflow.com/questions/7298749/… veya stackoverflow.com/questions/7101158/…
VonC

Dürüst olmak gerekirse, bunu yazarken git notlarının olduğunu bilmiyordum. Evet, aynı şeyi elde etmek için git notlarını kullanmak muhtemelen daha iyi bir fikirdir.
pajp

3

Aynı problemle ilgileniyorum ( Jenkins çok şubeli boru hattı) - sadece bilgi edinme ve bu taahhüdün nereden geldiği bir şube adı bulmaya çalışıyorum. Uzak dallar için çalışmalıdır, yerel kopyalar kullanılamaz.

Ben bununla çalışıyorum:

git rev-parse HEAD | xargs git name-rev

İsteğe bağlı olarak çıktıyı çıkarabilirsiniz:

git rev-parse HEAD | xargs git name-rev | cut -d' ' -f2 | sed 's/remotes\/origin\///g'

0

Sanırım birisi bir şubede var olmasına rağmen, dalı bulamayan aynı problemle yüzleşmelidir.

Önce hepsini çeksen iyi olur:

git pull --all

Sonra şube araması yapın:

git name-rev <SHA>

veya:

git branch --contains <SHA>

0

OP belirli bir taahhüt oluşturulduğunda bir dal tarafından geçilen tarihi belirlemeye çalışıyorsa ("SHA-1 karma değeri verildiğinde bir taahhüdün hangi şubeden geldiğini öğrenin"), o zaman reflog olmadan herhangi bir şey yoktur. Git nesnesi veritabanında hangi dalın hangi işlem geçmişine bağlı olduğunu gösteren kayıtları kaydeder .

(Bunu bir yoruma yanıt olarak yanıt olarak gönderdim.)

Umarım bu senaryo benim açımdan göstermektedir:

rm -rf /tmp/r1 /tmp/r2; mkdir /tmp/r1; cd /tmp/r1
git init; git config user.name n; git config user.email e@x.io
git commit -m"empty" --allow-empty; git branch -m b1; git branch b2
git checkout b1; touch f1; git add f1; git commit -m"Add f1"
git checkout b2; touch f2; git add f2; git commit -m"Add f2"
git merge -m"merge branches" b1; git checkout b1; git merge b2
git clone /tmp/r1 /tmp/r2; cd /tmp/r2; git fetch origin b2:b2
set -x;
cd /tmp/r1; git log --oneline --graph --decorate; git reflog b1; git reflog b2;
cd /tmp/r2; git log --oneline --graph --decorate; git reflog b1; git reflog b2;

Çıktı, 'f1 ekle' ile kesinleştirmenin uzak klon / tmp / r2'den b1 veya b2 dalından gelip gelmediğini bilmenin herhangi bir yolunun olmadığını gösterir.

(Çıktının son satırları burada)

+ cd /tmp/r1
+ git log --oneline --graph --decorate
*   f0c707d (HEAD, b2, b1) merge branches
|\
| * 086c9ce Add f1
* | 80c10e5 Add f2
|/
* 18feb84 empty
+ git reflog b1
f0c707d b1@{0}: merge b2: Fast-forward
086c9ce b1@{1}: commit: Add f1
18feb84 b1@{2}: Branch: renamed refs/heads/master to refs/heads/b1
18feb84 b1@{3}: commit (initial): empty
+ git reflog b2
f0c707d b2@{0}: merge b1: Merge made by the 'recursive' strategy.
80c10e5 b2@{1}: commit: Add f2
18feb84 b2@{2}: branch: Created from b1
+ cd /tmp/r2
+ git log --oneline --graph --decorate
*   f0c707d (HEAD, origin/b2, origin/b1, origin/HEAD, b2, b1) merge branches
|\
| * 086c9ce Add f1
* | 80c10e5 Add f2
|/
* 18feb84 empty
+ git reflog b1
f0c707d b1@{0}: clone: from /tmp/r1
+ git reflog b2
f0c707d b2@{0}: fetch origin b2:b2: storing head

Her iki durumda da çıktı git log 80c10e5..HEAD --ancestry-path --merges --oneline --color | tail -n 1ve git log 086c9ce..HEAD --ancestry-path --merges --oneline --color | tail -n 1komutlar nelerdir?
Eugen Konkov

Tabii ki SHA'lar komutlar her çalıştırıldığında değişir, komutlarınızı yerine getirmek için yeni bir çalıştırmada HEAD ^ 1 ve HEAD ^ 2 kullandım . Komutlar ve çıktılar: $ git log HEAD^1..HEAD --ancestry-path --merges --oneline --color | tail -n 1hangi verim 376142d merge branchesve $ git log HEAD^2..HEAD --ancestry-path --merges --oneline --color | tail -n 1hangi verim 376142d merge branches - birleştirme taahhüdü özetini gösterir, birleştirme oluşturulduğunda (iddia ettiğim gibi) üzerine yazılabilir, muhtemelen birleştirme dalının geçmişini gizler.
qneill

0

TL; DR:

Kabuk çıkış durumlarını önemsiyorsanız aşağıdakileri kullanın:

  • branch-current - geçerli şubenin adı
  • branch-names - şube adlarını temizle (her satıra bir tane)
  • branch-name - Yalnızca bir şubenin iade edildiğinden emin olun. branch-names

Her ikisi de branch-nameve branch-namesbir taahhüdü argüman olarak kabul eder ve varsayılan değer HEADhiçbiri verilmezse kabul edilir.


Komut dosyalarında yararlı takma adlar

branch-current = "symbolic-ref --short HEAD"  # https://stackoverflow.com/a/19585361/5353461
branch-names = !"[ -z \"$1\" ] && git branch-current 2>/dev/null || git branch --format='%(refname:short)' --contains \"${1:-HEAD}\" #"  # https://stackoverflow.com/a/19585361/5353461
branch-name = !"br=$(git branch-names \"$1\") && case \"$br\" in *$'\\n'*) printf \"Multiple branches:\\n%s\" \"$br\">&2; exit 1;; esac; echo \"$br\" #"

Yalnızca tek bir şubeden erişilebilir

% git branch-name eae13ea
master
% echo $?
0
  • Çıktı STDOUT için
  • Çık değeridir 0.

Birden çok şubeden ulaşılabilir taahhüt

% git branch-name 4bc6188
Multiple branches:
attempt-extract
master%
% echo $?
1
  • Çıktı STDERR
  • Çıkış değeri 1.

Çıkış durumu nedeniyle, bunlar güvenli bir şekilde inşa edilebilir. Örneğin, uzaktan kumandayı getirme amacıyla kullanmak için:

remote-fetch = !"branch=$(git branch-name \"$1\") && git config branch.\"$branch\".remote || echo origin #"

-1

Yerel şubeyi bulmak için:

grep -lR YOUR_COMMIT .git/refs/heads | sed 's/.git\/refs\/heads\///g'

Uzak dalı bulmak için:

grep -lR $commit .git/refs/remotes | sed 's/.git\/refs\/remotes\///g'

1
örneklerinizin bazı açıklamaları harika olacak
Eugen Konkov

-4

Eşleşen bir karma bulana kadar ağacın tamamında arama yapmanın yanı sıra, hayır.


7
Bunu gerçekten düşürmek istemiyorum, çünkü kesinlikle git'in bu bilgileri kalıcı olarak saklamadığı doğrudur, ancak yine de bulmak çok sık mümkündür. Cevabımı gör.
Cascabel
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.