Git log untuk mendapatkan komitmen hanya untuk cabang tertentu

214

Saya ingin membuat daftar semua komitmen yang hanya merupakan bagian dari cabang tertentu.

Dengan berikut ini, daftar semua komit dari cabang, tetapi juga dari induk (master)

git log mybranch

Pilihan lain yang saya temukan, adalah untuk mengecualikan komit yang dapat dijangkau oleh master dan memberi saya apa yang saya inginkan, TETAPI saya ingin menghindari kebutuhan untuk mengetahui nama cabang lainnya.

git log mybranch --not master

Saya mencoba menggunakan git for-each-ref, tetapi juga mencantumkan mybranch jadi sebenarnya tidak termasuk semua:

git log mybranch --not $(git for-each-ref --format '^%(refname:short)' refs/heads/)

Memperbarui:

Saya sedang menguji opsi baru yang saya temukan beberapa waktu lalu, dan sampai sekarang sepertinya ini yang bisa saya cari:

git log --walk-reflogs mybranch

Pembaruan (2013-02-13T15: 08):

Opsi --walk-reflogs baik, tetapi saya memeriksa bahwa ada kadaluwarsa untuk reflog (default 90 hari, gc.reflogExpire ).

Saya pikir saya menemukan jawaban yang saya cari:

git log mybranch --not $(git for-each-ref --format='%(refname)' refs/heads/ | grep -v "refs/heads/mybranch")

Saya hanya menghapus cabang saat ini dari daftar cabang yang tersedia dan menggunakan daftar itu untuk dikeluarkan dari log. Dengan cara ini saya hanya mendapatkan komitmen yang hanya dapat dicapai oleh kantor saya .

dimirc
sumber
kemungkinan duplikat dengan stackoverflow.com/questions/53569
StarPinkER
Sudah melihat pertanyaan itu juga, tetapi tidak sama
dimirc
2
Apakah Anda yakin itu yang Anda inginkan? Saya merasa lebih baik memiliki target dalam pikiran: "apa yang ada di cabang saya yang tidak ada di hulu", atau "apa yang ada di cabang saya yang tidak di master". Plus, sementara git cepat dalam pemangkasan, ini akan menjadi lebih mahal karena Anda memiliki lebih banyak cabang. Saya memiliki skrip yang saya gunakan yang saya sebut "git missing" setelah perintah "missing" bzr. Anda dapat menemukannya di sini: github.com/jszakmeister/etc/blob/master/git-addons/git-missing .
John Szakmeister
1
Saya benar-benar membutuhkan ini untuk kail pasca-terima, jadi "master" tidak akan selalu menjadi cabang untuk dikecualikan
dimirc
Ya, duplikat yang disebutkan oleh StarPinkER bekerja dengan baik untuk saya: git log $ (cabang git merge-base HEAD) .. branch
charo

Jawaban:

165

Dari sepertinya Anda harus menggunakan cherry:

git cherry -v develop mybranch

Ini akan menunjukkan semua komitmen yang terkandung dalam mybranch , tetapi TIDAK dalam pengembangan . Jika Anda meninggalkan opsi terakhir ( mybranch ), itu akan membandingkan cabang saat ini sebagai gantinya.

Seperti yang ditunjukkan VonC, Anda SELALU membandingkan cabang Anda dengan cabang lain, jadi ketahui cabang Anda dan kemudian pilih yang mana untuk dibandingkan.

Smilie
sumber
4
Ini persis apa yang saya butuhkan, tetapi sepertinya harus ada perintah yang lebih intuitif (ya bahkan di dunia Git) untuk ini.
Seth
12
Anda juga git cherry -v masterdapat membandingkan cabang saat ini dengan cabang master.
Pithikos
2
Bahaya menggunakan git cherry, adalah bahwa commit hanya cocok jika file mereka berbeda antar cabang. Jika segala jenis penggabungan dilakukan yang akan membuat perbedaan berbeda antara satu cabang, dan yang lainnya, maka git cherry melihat mereka sebagai komitmen yang berbeda.
Ben
Ini hanya memberi saya fatal: Unknown commit mybranch.
Matt Arnold
1
@MattArnold Anda harus mengubah teks "mengembangkan" dan "mybranch" ke cabang yang ada di repo Anda
Smilie
40

TETAPI saya ingin menghindari kebutuhan untuk mengetahui nama cabang lainnya.

Saya rasa ini tidak mungkin: cabang di Git selalu didasarkan pada yang lain atau setidaknya pada komit lain, seperti yang dijelaskan dalam " git diff tidak cukup menunjukkan ":

masukkan deskripsi gambar di sini

Anda memerlukan titik referensi untuk log Anda untuk menunjukkan komitmen yang tepat.

Seperti disebutkan dalam " GIT - Di mana saya cabang? ":

cabang hanyalah petunjuk untuk komit tertentu dalam DAG

Jadi, bahkan jika git log master..mybranchsatu jawaban, itu masih akan menunjukkan terlalu banyak komitmen, jika mybranchdidasarkan pada myotherbranch, itu sendiri berdasarkanmaster .

Untuk menemukan referensi itu (asal cabang Anda), Anda hanya dapat menguraikan komit dan melihat di cabang mana mereka, seperti yang terlihat di:

VONC
sumber
26

Saya akhirnya menemukan cara untuk melakukan apa yang diinginkan OP. Sesederhana:

git log --graph [branchname]

Perintah akan menampilkan semua komit yang dapat dijangkau dari cabang yang disediakan dalam format grafik. Tetapi, Anda dapat dengan mudah memfilter semua komit pada cabang itu dengan melihat grafik komit yang* merupakan karakter pertama di baris komit.

Sebagai contoh, mari kita lihat kutipan git log --graph masterrepo GitHub di cakephp di bawah ini:

D:\Web Folder\cakephp>git log --graph master
*   commit 8314c2ff833280bbc7102cb6d4fcf62240cd3ac4
|\  Merge: c3f45e8 0459a35
| | Author: José Lorenzo Rodríguez <[email protected]>
| | Date:   Tue Aug 30 08:01:59 2016 +0200
| |
| |     Merge pull request #9367 from cakephp/fewer-allocations
| |
| |     Do fewer allocations for simple default values.
| |
| * commit 0459a35689fec80bd8dca41e31d244a126d9e15e
| | Author: Mark Story <[email protected]>
| | Date:   Mon Aug 29 22:21:16 2016 -0400
| |
| |     The action should only be defaulted when there are no patterns
| |
| |     Only default the action name when there is no default & no pattern
| |     defined.
| |
| * commit 80c123b9dbd1c1b3301ec1270adc6c07824aeb5c
| | Author: Mark Story <[email protected]>
| | Date:   Sun Aug 28 22:35:20 2016 -0400
| |
| |     Do fewer allocations for simple default values.
| |
| |     Don't allocate arrays when we are only assigning a single array key
| |     value.
| |
* |   commit c3f45e811e4b49fe27624b57c3eb8f4721a4323b
|\ \  Merge: 10e5734 43178fd
| |/  Author: Mark Story <[email protected]>
|/|   Date:   Mon Aug 29 22:15:30 2016 -0400
| |
| |       Merge pull request #9322 from cakephp/add-email-assertions
| |
| |       Add email assertions trait
| |
| * commit 43178fd55d7ef9a42706279fa275bb783063cf34
| | Author: Jad Bitar <[email protected]>
| | Date:   Mon Aug 29 17:43:29 2016 -0400
| |
| |     Fix `@since` in new files docblocks
| |

Seperti yang Anda lihat, hanya komit 8314c2ff833280bbc7102cb6d4fcf62240cd3ac4dan c3f45e811e4b49fe27624b57c3eb8f4721a4323bmemiliki *karakter pertama di garis komit. Komit-komit itu berasal dari cabang utama sedangkan empat lainnya dari beberapa cabang lain.

Lukman
sumber
11

Perintah shell berikut harus melakukan apa yang Anda inginkan:

git log --all --not $(git rev-list --no-walk --exclude=refs/heads/mybranch --all)

Peringatan

Jika Anda telah mybranchmemeriksa, perintah di atas tidak akan berfungsi. Itu karena komit mybranchjuga dapat dijangkau HEAD, jadi Git tidak menganggap komit itu unik mybranch. Agar berfungsi saat mybranchdicentang, Anda juga harus menambahkan pengecualian untuk HEAD:

git log --all --not $(git rev-list --no-walk \
    --exclude=refs/heads/mybranch \
    --exclude=HEAD \
    --all)

Namun, Anda tidak boleh mengecualikan HEADkecuali mybranchdiperiksa, jika tidak Anda berisiko menunjukkan komitmen yang tidak eksklusif untukmybranch .

Demikian pula, jika Anda memiliki cabang jarak jauh bernama origin/mybranchyang sesuai dengan mybranchcabang lokal , Anda harus mengecualikannya:

git log --all --not $(git rev-list --no-walk \
    --exclude=refs/heads/mybranch \
    --exclude=refs/remotes/origin/mybranch \
    --all)

Dan jika cabang jarak jauh adalah cabang default untuk repositori jarak jauh (biasanya hanya berlaku untuk origin/master), Anda juga harus mengecualikan origin/HEAD:

git log --all --not $(git rev-list --no-walk \
    --exclude=refs/heads/mybranch \
    --exclude=refs/remotes/origin/mybranch \
    --exclude=refs/remotes/origin/HEAD \
    --all)

Jika cabang Anda dicentang, dan ada cabang jarak jauh, dan cabang jarak jauh adalah default untuk repositori jarak jauh, maka Anda akhirnya tidak termasuk banyak:

git log --all --not $(git rev-list --no-walk \
    --exclude=refs/heads/mybranch \
    --exclude=HEAD
    --exclude=refs/remotes/origin/mybranch \
    --exclude=refs/remotes/origin/HEAD \
    --all)

Penjelasan

The git rev-listperintah adalah tingkat rendah (pipa) perintah yang berjalan revisi yang diberikan dan kesedihan pengidentifikasi SHA1 ditemui. Anggap itu setara dengangit log kecuali hanya menunjukkan SHA1 — tidak ada pesan log, tidak ada nama penulis, tidak ada cap waktu, tidak ada yang "mewah".

The --no-walkpilihan, seperti namanya, mencegah git rev-listdari berjalan rantai keturunan. Jadi, jika Anda mengetiknya git rev-list --no-walk mybranchhanya akan mencetak satu pengidentifikasi SHA1: pengenal komit ujung mybranchcabang.

The --exclude=refs/heads/mybranch --allargumen memberitahu git rev-listmulai dari setiap referensi kecuali refs/heads/mybranch.

Jadi, ketika Anda menjalankan git rev-list --no-walk --exclude=refs/heads/mybranch --all, Git mencetak pengidentifikasi SHA1 dari komit tip dari masing-masing referensi kecuali untuk refs/heads/mybranch. Ini komit dan nenek moyang mereka adalah komit Anda tidak tertarik-ini komit Anda lakukan tidak ingin Anda lihat.

The lainnya komit adalah orang-orang yang ingin Anda lihat, jadi kami mengumpulkan output dari git rev-list --no-walk --exclude=refs/heads/mybranch --alldan memberitahu Git untuk menunjukkan segala sesuatu tetapi mereka komit dan nenek moyang mereka.

Itu --no-walk Argumen diperlukan untuk repositori besar (dan optimasi untuk repositori kecil): Tanpa itu, Git akan harus mencetak, dan shell akan harus mengumpulkan (dan simpan dalam memori) lebih banyak melakukan pengidentifikasi dari yang diperlukan. Dengan repositori besar, jumlah komit yang dikumpulkan dapat dengan mudah melebihi batas argumen baris perintah shell.

Git bug?

Saya berharap yang berikut ini berfungsi:

git log --all --not --exclude=refs/heads/mybranch --all

tetapi tidak. Saya menduga ini adalah bug di Git, tapi mungkin itu disengaja.

Richard Hansen
sumber
Penjelasan yang bagus. +1
VonC
5
Saya datang ke sini ingin tahu bagaimana melakukan tugas Mercurial hg log -b <branch>. Saya tidak mengerti mengapa orang mengatakan git tidak ramah. / s
weberc2
Saya tidak tahu mengapa git log --all --not --exclude=refs/heads/mybranch --alltidak berhasil tetapi git log refs/heads/mybranch --not --exclude=refs/heads/mybranch --alltidak, dengan peringatan yang sama tentang mengecualikan KEPALA dan asal.
Ben C
8

Jawaban cepat:

git log $(git merge-base master b2)..HEAD

Katakanlah:

  1. Bahwa Anda memiliki cabang utama

  2. Lakukan beberapa komitmen

  3. Anda membuat cabang bernama b2

  4. Lakukan git log -n1; komit Id adalah basis gabungan antara b2 dan master

  5. Lakukan beberapa komit di b2

  6. git log akan menampilkan riwayat log Anda dari b2 dan master

  7. Gunakan rentang komit, jika Anda tidak terbiasa dengan konsep ini, saya mengundang Anda ke google atau menumpuknya melimpah,

    Untuk konteks aktual Anda, Anda dapat melakukannya misalnya

    git log commitID_FOO..comitID_BAR
    

    ".." adalah operator jangkauan untuk perintah log.

    Itu artinya, dalam bentuk sederhana, beri saya semua log lebih baru daripada commitID_FOO ...

  8. Lihat pada titik # 4, basis gabungan

    Jadi: git log COMMITID_mergeBASE..HEADakan menunjukkan perbedaannya

  9. Git dapat mengambil basis gabungan untuk Anda seperti ini

    git merge-base b2 master
    
  10. Akhirnya Anda bisa melakukannya:

    git log $(git merge-base master b2)..HEAD
    
Frederic Nault
sumber
4

Anda dapat mencoba sesuatu seperti ini:

#!/bin/bash

all_but()
{
    target="$(git rev-parse $1)"
    echo "$target --not"
    git for-each-ref --shell --format="ref=%(refname)" refs/heads | \
    while read entry
    do
        eval "$entry"

        test "$ref" != "$target" && echo "$ref"
    done
}

git log $(all_but $1)

Atau, meminjam dari resep dalam Panduan Pengguna Git :

#!/bin/bash
git log $1 --not $( git show-ref --heads | cut -d' ' -f2 | grep -v "^$1" )
John Szakmeister
sumber
+1. Saya menulis dalam jawaban saya bahwa Anda perlu menguraikan komitmen untuk menemukan asal-usul cabang Anda, dan Anda tampaknya telah melakukan hal itu.
VonC
Sudahkah Anda menggunakan log --walk-reflogs? Saya membaca tentang opsi ini dan memberi saya hasil yang saya butuhkan sampai sekarang, (masih dalam pengujian)
dimirc
@dimirc Reflogs adalah binatang yang berbeda secara bersamaan. Ini mencatat poin cabang dari waktu ke waktu, umumnya untuk tujuan pemulihan. Saya tidak yakin apa yang Anda lakukan di kiriman pasca-terima Anda, tetapi mungkin jika Anda menjelaskannya, orang-orang dapat memberikan jawaban yang lebih masuk akal untuk masalah Anda.
John Szakmeister
Saya hanya perlu mem-parsing / memeriksa semua pesan komit dengan cepat. Kasing yang ingin saya bahas adalah jika seseorang mendorong beberapa komit pada master dan membuat cabang baru dengan banyak komit juga. Kait pasca-terima perlu memeriksa perubahan yang dilakukan untuk kedua referensi / cabang, misalnya master dan cabang baru, saya perlu mengetahui batasan-batasan untuk cabang baru untuk menghindari penguraian pesan komit dua kali, karena bisa komit dari master.
dimirc
1
Baik. Maka saya pikir pendekatan di atas yang saya uraikan benar-benar adalah yang Anda inginkan. Dengan reflog, entri akan jatuh setelah beberapa periode waktu, dan saya pikir itu akan menyebabkan Anda sakit kepala. Anda mungkin ingin melihat menggunakan git show-ref --tagsjuga.
John Szakmeister
4
git rev-list --exclude=master --branches --no-walk

akan mencantumkan tip dari setiap cabang yang tidak master.

git rev-list master --not $(git rev-list --exclude=master --branches --no-walk)

akan mencantumkan setiap komit dalam mastersejarah yang tidak ada dalam sejarah cabang lain.

Urutan penting untuk opsi yang mengatur pipa filter untuk pemilihan komit, jadi --branchesharus mengikuti pola pengecualian apa pun yang seharusnya diterapkan, dan --no-walkharus mengikuti filter yang memasok komit rev-list tidak boleh berjalan.

jthill
sumber
4

Ini akan menampilkan komit pada cabang saat ini. Jika ada argumen yang dilewatkan, itu hanya menghasilkan hash.

git_show_all_commits_only_on_this_branch

#!/bin/bash
function show_help()
{
  ME=$(basename $0)
  IT=$(cat <<EOF
  
  usage: $ME {NEWER_BRANCH} {OLDER_BRANCH} {VERBOSE}
  
  Compares 2 different branches, and lists the commits found only 
  in the first branch (newest branch). 

  e.g. 
  
  $ME         -> default. compares current branch to master
  $ME B1      -> compares branch B1 to master
  $ME B1 B2   -> compares branch B1 to B2
  $ME B1 B2 V -> compares branch B1 to B2, and displays commit messages
  
  )
  echo "$IT"
  exit
}

if [ "$1" == "help" ]
then
  show_help
fi

# Show commit msgs if any arg passed for arg 3
if [ "$3" ]
then
  OPT="-v"
fi

# get branch names
OLDER_BRANCH=${2:-"master"}
if [ -z "$1" ]
then
  NEWER_BRANCH=$(git rev-parse --abbrev-ref HEAD)
else
  NEWER_BRANCH=$1
fi

if [ "$NEWER_BRANCH" == "$OLDER_BRANCH" ]
then
  echo "  Please supply 2 different branches to compare!"
  show_help
fi

OUT=$(\git cherry $OPT $OLDER_BRANCH $NEWER_BRANCH)

if [ -z "$OUT" ]
then
  echo "No differences found. The branches $NEWER_BRANCH and $OLDER_BRANCH are in sync."
  exit;
fi

if [ "$OPT" == "-v" ]
then
  echo "$OUT"
else
  echo "$OUT" | awk '{print $2}'
fi
Taman Brad
sumber
1
Ini menghasilkan sekitar 100 pesan log yang tidak relevan bagi saya.
Arlie Stephens
Hai @ArlieStephens - saya sudah mencobanya dan sepertinya masih bekerja untuk saya? Saya baru saja menambahkan bantuan dan lebih banyak pesan kesalahan ke atas. Biarkan saya tahu bagaimana kelanjutannya!
Brad Parks
Menarik. Melihat kode seperti yang Anda miliki sekarang, saya pikir mungkin sesederhana aslinya dengan asumsi bahwa cabang yang saya pedulikan berasal dari master. Dengan kode saat ini, saya bisa menentukan cabang induk secara eksplisit. (IIRC, cabang dev saya berasal dari cabang rilis, bukan master.)
Arlie Stephens
@ArlieStephens - ya saya tidak berpikir saya mengubah fungsi apa pun .... Saya memperbaruinya sekali lagi dan membuat dokumen sedikit lebih tepat setelah beberapa pengujian lokal ... dan menambahkan opsi "verbose" yang ada di sana sebelumnya, tapi saya tidak mendokumentasikannya
Brad Parks
3

Saya menggunakan perintah berikut:

git shortlog --no-merges --graph --abbrev-commit master..<mybranch>

atau

git log --no-merges --graph --oneline --decorate master..<mybranch>
Alex
sumber
1

Saya menemukan pendekatan ini relatif mudah.

Checkout ke cabang dan dari

  1. Lari

    git rev-list --simplify-by-decoration -2 HEAD
    

Ini hanya akan menyediakan dua SHA:

1) komit terakhir dari cabang [C1]

2) dan komit induk ke komit pertama cabang [C2]

  1. Sekarang jalankan

    git log --decorate --pretty=oneline --reverse --name-status <C2>..<C1>
    

Di sini C1 dan C2 adalah dua string yang akan Anda dapatkan ketika Anda menjalankan perintah pertama. Masukkan nilai-nilai ini tanpa <> dalam perintah kedua.

Ini akan memberikan daftar riwayat perubahan file dalam cabang.

Mustkeem K
sumber
Jika Anda membaca tiga baris pertama dari pertanyaan, Anda akan melihat bahwa penulis mencantumkan perintah yang tepat ini dan menjelaskan mengapa itu bukan yang mereka cari
black_fm
Ah @black_fm saya membuat beberapa perubahan dalam jawaban. Anda dapat memilihnya jika Anda merasa berguna sekarang. :)
Mustkeem K
0

Dalam situasi saya, kami menggunakan Git Flow dan GitHub. Yang perlu Anda lakukan adalah: Bandingkan cabang fitur Anda dengan cabang pengembangan Anda di GitHub.

Ini akan menunjukkan komit yang hanya dibuat untuk cabang fitur Anda.

Sebagai contoh:

https://github.com/your_repo/compare/develop...feature_branch_name

peterpengnz
sumber
Saya setuju bahwa ketika Anda masuk ke situasi "Saya ingin melihat seperti apa permintaan tarikan akan terlihat", solusi terbaik sering kali diabaikan gitdan alih-alih menggunakan GitHub untuk hanya membuat permintaan tarikan atau membandingkan cabang.
pkamb