Git - bir yöntemin / işlevin değişiklik geçmişini nasıl görüntüleyebilirim?


93

Bu nedenle, bir dosyanın değişiklik geçmişinin nasıl görüntüleneceğiyle ilgili soruyu buldum, ancak bu belirli dosyanın değişiklik geçmişi çok büyük ve gerçekten yalnızca belirli bir yöntemin değişiklikleriyle ilgileniyorum. Öyleyse, yalnızca belirli bir yöntemin değişiklik geçmişini görmek mümkün olabilir mi?

Bunun kodu analiz etmek için git'e ihtiyaç duyacağını ve analizin farklı diller için farklı olacağını biliyorum, ancak yöntem / işlev bildirimleri çoğu dilde çok benzer görünüyor, bu yüzden belki birinin bu özelliği uyguladığını düşündüm.

Şu anda çalıştığım dil Objective-C ve şu anda kullandığım SCM git, ancak bu özelliğin herhangi bir SCM / dil için mevcut olup olmadığını bilmek isterim.


1
Git GSoG teklifinde böyle bir işlevsellik gördüm.
Vi.

Bahsettiğin teklif bu mu? list-archives.org/git/…
Erik B


@lpapp buradaki soru 10 ay önce sorulmuştu, diğer soru bunun kopyası olarak işaretlenmelidir (eğer bunlar kopya ise).
Dirty-flow

2
@lpapp Bunlar tamamen farklı iki soru. Bir fonksiyon adını bir dizi satıra çözümleyen bir komut dosyası yazabilir ve ardından bu satırların geçmişini almak için bu sorudaki tekniği kullanabilirsiniz, ancak kendi içinde bu soruyu yanıtlamaz.
Erik B

Yanıtlar:


100

Son sürümleri git log, -Lparametrenin özel bir biçimini öğrendi :

-L: <funcname>: <file>

İçinde belirtilen satır aralığının "<start>,<end>"(veya regex işlev adı <funcname>) gelişimini izleyin <file>. Herhangi bir yol belirtme sınırlayıcısı veremezsiniz. Bu, şu anda tek bir revizyondan başlayan bir yürüyüşle sınırlıdır, yani yalnızca sıfır veya bir pozitif revizyon argümanı verebilirsiniz. Bu seçeneği birden çok kez belirtebilirsiniz.
...
Eğer “:<funcname>”yerine verilir <start>ve <end>bu, birinci funcname hattından aralığını gösterir normal bir ifade edilmektedir maçlar olduğunu <funcname>, yukarı sonraki funcname hattına. varsa “:<funcname>”önceki -Laralığın sonundan , aksi takdirde dosyanın başlangıcından itibaren arar . “^:<funcname>”dosyanın başından itibaren arar.

Başka bir deyişle: Git'e sorarsanız git log -L :myfunction:path/to/myfile.c, şimdi o işlevin değişiklik geçmişini mutlu bir şekilde yazdıracaktır.


16
bu, kullanıma hazır amaç-c için işe yarayabilir, ancak bunu diğer diller için yapıyorsanız (ör. Python, Ruby vb.) git'in işlevi / yöntemi tanıması için bir .gitattributes dosyasına uygun yapılandırmayı eklemeniz gerekebilir. o dilde beyanlar. Python için * .py diff = python kullanın, yakut kullanımı için *
.rb

1
Git işlevi nasıl izler?
nn0p

@ nn0p Birkaç dilin sözdizimi bilgisine sahip olduğumu ve böylece bir işlevi nasıl izole edeceğimi ve değişikliklerini nasıl izleyeceğimi varsayıyorum.
JasonGenX

4
@ Samaspin'in yorumunu genişletmek, diğer diller için buradaki dokümanlara başvurabilirsiniz: git-scm.com/docs/gitattributes#_generating_diff_text
edhgoose

Bu, Scala ve Java gibi diller için ve hatta iç içe geçmiş küme parantezleri kullanan C bile çalışmaz (normal ifadeler bunu genel olarak işleyemez) ve işlev dosyada taşındığında başlangıç, bitiş formu bile çalışmaz. ve aynı işlemede değiştirildi.
Robin Green

16

Kullanılması git gui blamekomut yararlanmak zordur ve iken git log -Gve git log --pickaxeyöntem tanımı göründüğü veya onları yapılan tüm değişiklikleri listelemek için herhangi bir yol bulamadı, kaybolduğunda her gösterebilir vücutta senin yöntemin.

Ancak, tam da bunu yapan bir çözümü bir araya getirmek için gitattributesve textconvözelliğini kullanabilirsiniz . Bu özellikler başlangıçta ikili dosyalarla çalışmanıza yardımcı olmak için tasarlanmış olsa da, burada da aynı şekilde çalışırlar.

Anahtar, Git'in herhangi bir diff işlemi yapmadan önce ilgilendikleriniz dışındaki tüm satırları dosyadan kaldırmasını sağlamaktır. Ardından git log, git diffvb. Yalnızca ilgilendiğiniz alanı görecektir.

İşte başka bir dilde yaptıklarımın ana hatları; kendi ihtiyaçlarınız için ince ayar yapabilirsiniz.

  • Bir bağımsız değişken alan - bir kaynak dosyanın adı - ve o dosyanın yalnızca ilginç kısmını (veya hiçbiri ilginç değilse hiçbir şey) çıkaran kısa bir kabuk komut dosyası (veya başka bir program) yazın. Örneğin, sedaşağıdaki gibi kullanabilirsiniz :

    #!/bin/sh
    sed -n -e '/^int my_func(/,/^}/ p' "$1"
    
  • textconvYeni komut dosyanız için bir Git filtresi tanımlayın . (Daha gitattributesfazla ayrıntı için man sayfasına bakın.) Filtrenin adı ve komutun konumu istediğiniz herhangi bir şey olabilir.

    $ git config diff.my_filter.textconv /path/to/my_script
    
  • Git'e söz konusu dosya için farkları hesaplamadan önce bu filtreyi kullanmasını söyleyin.

    $ echo "my_file diff=my_filter" >> .gitattributes
    
  • Kullanmak Şimdi eğer -G.(not .filtre uygulandığında görünür değişiklikler üretmek tüm kaydedilmesini listelemek için), size o ediyoruz ilgilenen tam olarak bu teslimleri olacaktır. Gibi seyahatseverlerin Git adlı fark rutinleri kullanmak Başka seçenekler --patch, olacak ayrıca bu kısıtlı görünümü elde edin.

    $ git log -G. --patch my_file
    
  • Voilà!

Yapmak isteyebileceğiniz yararlı bir iyileştirme, filtre komut dosyanızın ilk argüman olarak bir yöntem adını (ve ikinci argüman olarak dosyayı) almasını sağlamaktır. Bu git config, komut dosyanızı düzenlemek yerine yalnızca çağırarak yeni bir ilgi yöntemi belirlemenizi sağlar . Örneğin şöyle diyebilirsiniz:

$ git config diff.my_filter.textconv "/path/to/my_command other_func"

Elbette, filtre komut dosyası istediğiniz her şeyi yapabilir, daha fazla argüman alabilir veya her neyse: burada gösterdiklerimin ötesinde çok fazla esneklik var.


1
Birden fazla argüman almak benim için işe yaramadı, ancak işlev adını zor işlere koymak iyi ve bu gerçekten harika!
qwertzguy

Harika, yine de birçok farklı yöntem arasında geçiş yapmanın ne kadar uygun olduğunu merak ediyorum. Ayrıca, C benzeri bir işlevi tamamen çıkarabilen bir program biliyor musunuz?
nafg

12

git log , tüm farklılıkları bulmak için '-G' seçeneği kullanılabilir.

-G Eklenen veya kaldırılan satırı verilenle eşleşen farklılıkları arayın <regex>.

Ona önem verdiğiniz işlev adının uygun bir normal ifadesini verin. Örneğin,

$ git log --oneline -G'^int commit_tree'
40d52ff make commit_tree a library function
81b50f3 Move 'builtin-*' into a 'builtin/' subdirectory
7b9c0a6 git-commit-tree: make it usable from other builtins

5
Komutu çalıştırmadım, ama bana öyle geliyor ki bu komut sadece regex ile eşleşen satıra dokunan commitleri gösteriyor, ki bu tüm metot / fonksiyon değil.
Erik B

Eğer daha fazla bağlam isterseniz değiştirebilirsiniz --onelineile-p
lfender6445

3
Peki ya yöntemde 20 satırlık bir değişiklik yapıldıysa?
nafg

+1. Benim için en iyi cevap işe yaradı, ancak yalnızca en son taahhüdü gösterdi. Muhtemelen geri tepmelerden veya işlevin birkaç kez hareket etmesinden dolayı, emin değilim. İçinde bulunduğu işlev yerine gerçek kod satırını arayarak (tek satırlık olsa da) bu yanıt, aradığım işlemi kolayca tespit etmemi sağladı. Neyse ki, genellikle yararlı commit mesajları yazarım!
Dave S

11

Yapabileceğiniz en yakın şey, dosyadaki işlevinizin konumunu belirlemektir (örneğin, işlevinizin i_am_buggy241-263 satırlarında olduğunu söyleyin foo/bar.c), ardından şu etkiye sahip bir şey çalıştırın:

git log -p -L 200,300:foo/bar.c

Bu daha az (veya eşdeğer bir çağrı cihazı) açacaktır. Artık yazabilir /i_am_buggy(veya çağrı cihazınızın eşdeğerini) ve değişikliklere adım atmaya başlayabilirsiniz.

Kod stilinize bağlı olarak bu bile işe yarayabilir:

git log -p -L /int i_am_buggy\(/,+30:foo/bar.c

Bu, aramayı o normal ifadenin (ideal olarak işlev bildiriminiz) ilk isabetinden sonraki otuz satırla sınırlar. Son argüman aynı zamanda bir normal ifade de olabilir, ancak bunu regexp'ler ile saptamak daha güçlü bir önerme olur.


Tatlı! Bilginize, bu Git v1.8.4 sürümünde yeni. (Sanırım yükseltmeliyim.) Daha kesin bir çözüm güzel olsa da ... birisinin Paul Whittaker'ın cevabını yazması gibi.
Greg Price

@GregPrice Görünüşe göre aramanın kenarları normal ifadeler bile olabilir , bu nedenle en azından az çok kesin bir başlangıç ​​noktasına sahip olabilirsiniz.
badp

Vay vay. Aslında: kendi regexp'inizi yazmak yerine, sadece -L ":int myfunc:foo/bar.c"o isimdeki işlevi söyleyebilir ve sınırlayabilirsiniz. Bu harika - işaretçi için teşekkürler! Şimdi, eğer sadece işlev algılama biraz daha güvenilir olsaydı ...
Greg Price

3

Doğru yol, eckes cevabındagit log -L :function:path/to/file açıklandığı gibi kullanmaktır .

Buna ek olarak, işleviniz çok uzunsa, bu satırlardan yalnızca birine dokunan her işlem için, tüm işlev satırlarını değil, yalnızca çeşitli commit'lerin getirdiği değişiklikleri görmek isteyebilirsiniz. Normalin diffyaptığı gibi.

Normalde git logile farklılıkları görüntüleyebilir -p, ancak bu ile çalışmaz -L. Dolayısıyla, grep git log -Lbunları bağlamsallaştırmak için yalnızca ilgili satırları ve commits / files başlıklarını göstermeniz gerekir. Buradaki hile --color, bir normal ifadeyle anahtar ekleyerek yalnızca uç renkli satırları eşleştirmektir . En sonunda:

git log -L :function:path/to/file --color | grep --color=never -E -e "^(^[\[[0-9;]*[a-zA-Z])+" -3

Bunun ^[gerçek olması gerektiğini unutmayın ^[. Bunları ^ V ^ [bash, yani Ctrl+ V, Ctrl+ tuşlarına basarak yazabilirsiniz [. Referans burada .

Ayrıca son -3anahtar, eşleşen her satırdan önce ve sonra 3 satır çıktı bağlamı yazdırmaya izin verir. İhtiyaçlarınıza göre ayarlamak isteyebilirsiniz.


2

git blame size dosyanın her satırını en son kimin değiştirdiğini gösterir; İşlevinizin dışındaki satırların geçmişini almaktan kaçınmak için incelenecek satırları belirtebilirsiniz.


4
ile git gui blameeski revizyonlarda gezinebilirsiniz.
Vi.

0
  1. Eckes'in cevabında ve git doc'tagit log -L :<funcname>:<file> gösterildiği gibi işlev geçmişini göster

    Hiçbir şey göstermezse , dosyaya dilinizi desteklemek için benzer bir şey eklemek için Özel bir hunk-başlık tanımlama'ya bakın .*.java diff=java.gitattributes

  2. İle kaydetmeler arasındaki işlev geçmişini göster git log commit1..commit2 -L :functionName:filePath

  3. Aşırı yüklenmiş işlev geçmişini göster (aynı ada sahip ancak farklı parametrelere sahip birçok işlev olabilir) git log -L :sum\(double:filepath

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.