Metode yang berbeda di bawah ini adalah pragmatis, berguna, cara untuk bekerja menyimpulkan suatu kemungkinan jawaban, tapi mari kita perhatikan bahwa di git pertanyaan itu sendiri adalah kesalahpahaman, komit tidak datang dari cabang. Cabang datang dan pergi, mereka bergerak, hanya berkomitmen mewakili sejarah repo yang sebenarnya. Kemudian lagi, ini bukan cara untuk mengatakan solusi di bawah ini buruk. Ketahuilah bahwa tidak ada dari mereka yang memberikan jawaban yang sepenuhnya dapat dipercaya, yang tidak dapat diperoleh dengan desain di git. (Kasus sederhana dihapus cabang: Saya bercabang, saya komit dua kali, saya menggabungkan ke cabang lain, saya menghapus cabang pertama. Dari mana komit "berasal"?
RomainValeri
1
Saya memiliki kasus di mana saya secara eksplisit menarik kedalaman 1 clone dangkal dari tag. Ini murah dan mudah dan efisien ... dan sampai sekarang melakukan semua yang saya inginkan dengan indah. Sekarang saya ingin tahu di cabang mana tag itu berada, saya disembunyikan, setidaknya untuk detail itu. Anda tidak bisa selalu pulang, lol
Paul Hodges
Jawaban:
865
Walaupun Dav benar bahwa informasi itu tidak disimpan secara langsung, itu tidak berarti Anda tidak akan pernah bisa mengetahuinya. Berikut ini beberapa hal yang dapat Anda lakukan.
Temukan cabang tempat komit aktif
git branch -a --contains <commit>
Ini akan memberi tahu Anda semua cabang yang memiliki komit yang diberikan dalam sejarahnya. Jelas ini kurang berguna jika komit sudah digabung.
Cari reflog
Jika Anda bekerja di repositori tempat komit dibuat, Anda bisa mencari reflog untuk baris komit itu. Reflog yang lebih dari 90 hari dipangkas oleh git-gc, jadi jika komitnya terlalu tua, Anda tidak akan menemukannya. Yang mengatakan, Anda bisa melakukan ini:
git reflog show --all | grep a871742
untuk menemukan komit a871742. Perhatikan bahwa Anda HARUS menggunakan 7 digit pertama komit. Outputnya harus seperti ini:
a871742 refs/heads/completion@{0}: commit (amend): mpc-completion: total rewrite
menunjukkan bahwa komit dibuat pada cabang "selesai". Output default menunjukkan hash komit yang disingkat, jadi pastikan untuk tidak mencari hash lengkap atau Anda tidak akan menemukan apa pun.
git reflog showsebenarnya hanya alias untuk git log -g --abbrev-commit --pretty=oneline, jadi jika Anda ingin mengutak-atik format output untuk membuat hal-hal yang berbeda tersedia, itulah titik awal Anda!
Jika Anda tidak bekerja di repositori tempat komit dibuat, hal terbaik yang dapat Anda lakukan dalam hal ini adalah memeriksa reflog dan temukan kapan komit pertama kali diperkenalkan ke repositori Anda; dengan sedikit keberuntungan, Anda mengambil cabang yang telah dijanjikannya. Ini sedikit lebih rumit, karena Anda tidak dapat berjalan baik di pohon komit maupun reflog secara bersamaan. Anda ingin mem-parsing keluaran reflog, memeriksa setiap hash untuk melihat apakah itu berisi komit yang diinginkan atau tidak.
Temukan komit gabungan selanjutnya
Ini tergantung alur kerja, tetapi dengan alur kerja yang baik, komit dibuat pada cabang pengembangan yang kemudian digabungkan. Anda bisa melakukan ini:
git log --merges <commit>..
untuk melihat menggabungkan komit yang memiliki komit yang diberikan sebagai leluhur. (Jika komit hanya digabung satu kali, komit pertama yang harus Anda gabungkan; jika tidak, Anda harus memeriksa beberapa, saya kira.) Pesan komit gabung harus berisi nama cabang yang digabungkan.
Jika Anda ingin dapat mengandalkan melakukan ini, Anda mungkin ingin menggunakan --no-ffopsi git mergeuntuk memaksa menggabungkan penciptaan komit bahkan dalam kasus fast-forward. (Namun, jangan terlalu bersemangat. Itu bisa menjadi membingungkan jika terlalu sering digunakan.) Jawaban VonC untuk pertanyaan terkait sangat membantu menguraikan topik ini.
+1. Tidak adanya informasi untuk masalah khusus itu membuat Anda bertanya-tanya apakah itu sebenarnya masalah? Cabang dapat berubah, diubah namanya atau dihapus kapan saja. Mungkin git describesudah cukup, karena tag (beranotasi) dapat dilihat lebih penting daripada cabang.
VonC
9
Saya setuju - cabang dimaksudkan untuk menjadi ringan dan fleksibel. Jika Anda mengadopsi alur kerja di mana informasi itu menjadi penting, Anda bisa menggunakan --no-ffopsi untuk memastikan selalu ada komit gabungan, jadi Anda selalu bisa melacak jalur komit yang diberikan saat digabungkan ke master.
Cascabel
32
FYI, jika Anda ingin menemukan komit yang hanya ada di remote, tambahkan -abendera ke perintah pertama misalnyagit branch -a --contains <commit>
Jonathan Day
8
@ JonathanDay: Tidak, itu akan menemukan commit di cabang mana pun. Jika Anda hanya ingin yang di remote, gunakan -r.
Cascabel
7
@SimonTewsi Seperti yang saya katakan, jika ini benar-benar masalah, gunakan merge --no-ffuntuk merekam nama cabang dengan andal saat Anda bergabung. Tetapi sebaliknya, anggaplah nama cabang sebagai label pendek sementara, dan lakukan deskripsi sebagai yang permanen. "Nama pendek apa yang kita sebutkan dengan ini selama pengembangan?" seharusnya tidak menjadi pertanyaan yang sama pentingnya dengan "apa yang dilakukan oleh komitmen ini?"
Dan hanya butuh 8 tahun untuk solusi sempurna ini. Terima kasih!
S1J0
6
Saya menemukan git name-rev --name-only <SHA>lebih bermanfaat untuk mendapatkan hanya nama cabang. Pertanyaan saya ... Apakah bisa mengembalikan lebih dari satu cabang dalam keadaan apa pun?
git-what-branch(Perl script, lihat di bawah) tampaknya tidak dipertahankan lagi.
git-when-mergedadalah alternatif yang ditulis dengan Python yang bekerja sangat baik untuk saya.
Beri tahu kami (secara default) jalur kausal awal dari commit dan merger untuk menyebabkan komit yang diminta masuk ke cabang bernama. Jika komit dibuat langsung pada cabang bernama, itu jelas merupakan jalur paling awal.
Dengan jalur sebab akibat paling awal, yang kami maksud adalah jalur yang bergabung ke cabang bernama paling awal, dengan waktu komit (kecuali --topo-orderditentukan).
KINERJA
Jika banyak cabang (mis. Ratusan) berisi komit, sistem mungkin membutuhkan waktu lama (untuk komit tertentu di pohon Linux, butuh 8 detik untuk menjelajahi cabang, tetapi ada lebih dari 200 cabang kandidat) untuk melacak jalur. untuk setiap komit.
Pemilihan tertentu --reference-branch --reference taguntuk diperiksa akan ratusan kali lebih cepat (jika Anda memiliki ratusan kandidat cabang).
CONTOH
# 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
[...]
Program ini tidak memperhitungkan efek memetik bunga, hanya menggabungkan operasi.
git-what-branchsepertinya tidak dipertahankan lagi. git-when-merger adalah alternatif yang ditulis dengan Python yang bekerja sangat baik untuk saya.
sschuberth
@ schuberthth terima kasih atas pembaruan ini. Saya telah memasukkan komentar Anda dalam jawaban untuk lebih banyak visibilitas.
VonC
37
Misalnya, untuk mengetahui bahwa c0118fakomit berasal dari 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
Anda harus menjalankan:
git log c0118fa..HEAD --ancestry-path --merges
Dan gulir ke bawah untuk menemukan komit gabungan terakhir . Yang mana:
commit a435005445a6752dfe788b8d994e155b3cd9778f
Merge: 0953cac a06cc29
Author: Eugen Konkov
Date: Sat Oct 1 00:54:18 2016 +0300
Merge branch 'redesign_interactions' into clean_api
Ini adalah satu-satunya solusi yang memberi saya hasil yang diinginkan. Saya mencoba sisanya.
perajin
Catatan ini hanya berfungsi jika ringkasan komit gabungan berisi nama cabang yang digunakan dalam gabungan, yang biasanya mereka lakukan. Namun git merge -m"Any String Here"akan mengaburkan sumber dan informasi cabang target.
qneill
@qneill: Tidak, penggabungan selalu memiliki info tentang cabang digabung: Merge: f6b70fa d58bdcb. Anda dapat memberi nama komit gabungan Anda dengan Anda. Saya tidak akan memiliki masalah
Eugen Konkov
1
@EugenKonkov begitu cabang-cabang telah melewati penggabungan, sejarah tentang jalur mana dalam grafik tempat asalnya ditinggalkan di reflog, tetapi tidak dalam database objek git. Saya memposting jawaban yang mencoba menjelaskan apa yang saya katakan
qneill
Versi UPD bekerja untuk saya, perintah sederhana yang menemukan komit asli
vpalmu
9
git branch --contains <ref>adalah perintah "porselen" yang paling jelas untuk melakukan ini. Jika Anda ingin melakukan sesuatu yang serupa dengan hanya perintah "plumbing":
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
Saya memperbarui deskripsi. Terima kasih atas umpan baliknya.
phyatt
4
Pilihan orang miskin adalah menggunakan alat tig1 pada HEAD, mencari komit, dan kemudian secara visual mengikuti garis dari komit itu kembali sampai komit gabungan terlihat. Pesan penggabungan default harus menentukan cabang apa yang digabungkan ke tempat :)
1 Tig adalah antarmuka mode teks berbasis ncurses untuk Git. Berfungsi terutama sebagai browser repositori Git, tetapi juga dapat membantu dalam melakukan perubahan untuk komit di tingkat chunk dan bertindak sebagai pager untuk output dari berbagai perintah Git.
Sebagai percobaan, saya membuat kait pasca-komit yang menyimpan informasi tentang cabang yang saat ini diperiksa dalam metadata komit. Saya juga sedikit memodifikasi gitk untuk menunjukkan informasi itu.
Sejujurnya, saya tidak tahu ada catatan git ketika saya menulis itu. Ya, menggunakan git note untuk mencapai hal yang sama mungkin merupakan ide yang lebih baik.
pajp
3
Saya berurusan dengan masalah yang sama ( pipa multibranch Jenkins ) - hanya memiliki komit informasi dan mencoba mencari nama cabang dari mana komit ini berasal. Ini harus berfungsi untuk cabang jarak jauh, salinan lokal tidak tersedia.
Inilah yang saya kerjakan:
git rev-parse HEAD | xargs git name-rev
Secara opsional, Anda dapat menghapus output:
git rev-parse HEAD | xargs git name-rev | cut -d' ' -f2 | sed 's/remotes\/origin\///g'
Jika OP sedang mencoba untuk menentukan sejarah yang dilalui oleh cabang ketika komit tertentu dibuat ("cari tahu dari mana cabang komit berasal dari diberi nilai hash SHA-1"), maka tanpa reflog tidak ada catatan dalam database objek Git yang menunjukkan apa yang bernama cabang terikat dengan apa yang melakukan histori.
(Saya memposting ini sebagai jawaban sebagai balasan atas komentar.)
Dan untuk apa output git log 80c10e5..HEAD --ancestry-path --merges --oneline --color | tail -n 1dan git log 086c9ce..HEAD --ancestry-path --merges --oneline --color | tail -n 1perintah untuk kedua kasus?
Eugen Konkov
SHA tentu saja berubah sewaktu-waktu perintah dijalankan, untuk membalas perintah Anda, saya menggunakan HEAD ^ 1 dan HEAD ^ 2 pada proses baru. Perintah dan outputnya adalah: $ git log HEAD^1..HEAD --ancestry-path --merges --oneline --color | tail -n 1yang menghasilkan 376142d merge branchesdan $ git log HEAD^2..HEAD --ancestry-path --merges --oneline --color | tail -n 1yang menghasilkan 376142d merge branches - yang menunjukkan ringkasan komit gabung, yang (seperti yang saya nyatakan) dapat ditimpa ketika penggabungan dibuat, mungkin mengaburkan sejarah cabang penggabungan.
qneill
0
TL; DR:
Gunakan di bawah ini jika Anda peduli tentang status keluar shell:
branch-current - nama cabang saat ini
branch-names - nama cabang bersih (satu per baris)
branch-name - Pastikan hanya satu cabang yang dikembalikan branch-names
Keduanya branch-namedan branch-namesmenerima komit sebagai argumen, dan default ke HEADjika tidak ada yang diberikan.
Saya tidak benar-benar ingin membatalkan ini, karena sebenarnya memang benar bahwa git tidak secara permanen menyimpan informasi itu, tetapi sangat mungkin untuk mencari tahu. Lihat jawaban saya.
Jawaban:
Walaupun Dav benar bahwa informasi itu tidak disimpan secara langsung, itu tidak berarti Anda tidak akan pernah bisa mengetahuinya. Berikut ini beberapa hal yang dapat Anda lakukan.
Temukan cabang tempat komit aktif
Ini akan memberi tahu Anda semua cabang yang memiliki komit yang diberikan dalam sejarahnya. Jelas ini kurang berguna jika komit sudah digabung.
Cari reflog
Jika Anda bekerja di repositori tempat komit dibuat, Anda bisa mencari reflog untuk baris komit itu. Reflog yang lebih dari 90 hari dipangkas oleh git-gc, jadi jika komitnya terlalu tua, Anda tidak akan menemukannya. Yang mengatakan, Anda bisa melakukan ini:
untuk menemukan komit a871742. Perhatikan bahwa Anda HARUS menggunakan 7 digit pertama komit. Outputnya harus seperti ini:
menunjukkan bahwa komit dibuat pada cabang "selesai". Output default menunjukkan hash komit yang disingkat, jadi pastikan untuk tidak mencari hash lengkap atau Anda tidak akan menemukan apa pun.
git reflog show
sebenarnya hanya alias untukgit log -g --abbrev-commit --pretty=oneline
, jadi jika Anda ingin mengutak-atik format output untuk membuat hal-hal yang berbeda tersedia, itulah titik awal Anda!Jika Anda tidak bekerja di repositori tempat komit dibuat, hal terbaik yang dapat Anda lakukan dalam hal ini adalah memeriksa reflog dan temukan kapan komit pertama kali diperkenalkan ke repositori Anda; dengan sedikit keberuntungan, Anda mengambil cabang yang telah dijanjikannya. Ini sedikit lebih rumit, karena Anda tidak dapat berjalan baik di pohon komit maupun reflog secara bersamaan. Anda ingin mem-parsing keluaran reflog, memeriksa setiap hash untuk melihat apakah itu berisi komit yang diinginkan atau tidak.
Temukan komit gabungan selanjutnya
Ini tergantung alur kerja, tetapi dengan alur kerja yang baik, komit dibuat pada cabang pengembangan yang kemudian digabungkan. Anda bisa melakukan ini:
untuk melihat menggabungkan komit yang memiliki komit yang diberikan sebagai leluhur. (Jika komit hanya digabung satu kali, komit pertama yang harus Anda gabungkan; jika tidak, Anda harus memeriksa beberapa, saya kira.) Pesan komit gabung harus berisi nama cabang yang digabungkan.
Jika Anda ingin dapat mengandalkan melakukan ini, Anda mungkin ingin menggunakan
--no-ff
opsigit merge
untuk memaksa menggabungkan penciptaan komit bahkan dalam kasus fast-forward. (Namun, jangan terlalu bersemangat. Itu bisa menjadi membingungkan jika terlalu sering digunakan.) Jawaban VonC untuk pertanyaan terkait sangat membantu menguraikan topik ini.sumber
git describe
sudah cukup, karena tag (beranotasi) dapat dilihat lebih penting daripada cabang.--no-ff
opsi untuk memastikan selalu ada komit gabungan, jadi Anda selalu bisa melacak jalur komit yang diberikan saat digabungkan ke master.-a
bendera ke perintah pertama misalnyagit branch -a --contains <commit>
-r
.merge --no-ff
untuk merekam nama cabang dengan andal saat Anda bergabung. Tetapi sebaliknya, anggaplah nama cabang sebagai label pendek sementara, dan lakukan deskripsi sebagai yang permanen. "Nama pendek apa yang kita sebutkan dengan ini selama pengembangan?" seharusnya tidak menjadi pertanyaan yang sama pentingnya dengan "apa yang dilakukan oleh komitmen ini?"Perintah sederhana ini bekerja seperti mantra:
git name-rev <SHA>
Misalnya (di mana cabang uji adalah nama cabang):
Bahkan ini berfungsi untuk skenario kompleks, seperti:
Di sini
git name-rev commit<SHA2>
mengembalikan branchB .sumber
git name-rev --name-only <SHA>
lebih bermanfaat untuk mendapatkan hanya nama cabang. Pertanyaan saya ... Apakah bisa mengembalikan lebih dari satu cabang dalam keadaan apa pun?Pembaruan Desember 2013:
komentar sschuberth
Ini didasarkan pada " Temukan komit gabungan yang menyertakan komit tertentu ".
Jawaban asli September 2010:
Sebastien Douche baru saja twit (16 menit sebelum jawaban SO ini):
Ini adalah skrip Perl dari Seth Robertson yang tampaknya sangat menarik:
sumber
git-what-branch
sepertinya tidak dipertahankan lagi. git-when-merger adalah alternatif yang ditulis dengan Python yang bekerja sangat baik untuk saya.Misalnya, untuk mengetahui bahwa
c0118fa
komit berasal dariredesign_interactions
:Anda harus menjalankan:
Dan gulir ke bawah untuk menemukan komit gabungan terakhir . Yang mana:
Memperbarui
Atau hanya satu perintah:
sumber
git merge -m"Any String Here"
akan mengaburkan sumber dan informasi cabang target.Merge: f6b70fa d58bdcb
. Anda dapat memberi nama komit gabungan Anda dengan Anda. Saya tidak akan memiliki masalahgit branch --contains <ref>
adalah perintah "porselen" yang paling jelas untuk melakukan ini. Jika Anda ingin melakukan sesuatu yang serupa dengan hanya perintah "plumbing":(crosspost dari jawaban SO ini )
sumber
khichar.anil membahas sebagian besar ini dalam jawabannya.
Saya hanya menambahkan bendera yang akan menghapus tag dari daftar nama revisi. Ini memberi kita:
sumber
Pilihan orang miskin adalah menggunakan alat
tig
1 padaHEAD
, mencari komit, dan kemudian secara visual mengikuti garis dari komit itu kembali sampai komit gabungan terlihat. Pesan penggabungan default harus menentukan cabang apa yang digabungkan ke tempat :)sumber
Sebagai percobaan, saya membuat kait pasca-komit yang menyimpan informasi tentang cabang yang saat ini diperiksa dalam metadata komit. Saya juga sedikit memodifikasi gitk untuk menunjukkan informasi itu.
Anda dapat memeriksanya di sini: https://github.com/pajp/branch-info-commits
sumber
Saya berurusan dengan masalah yang sama ( pipa multibranch Jenkins ) - hanya memiliki komit informasi dan mencoba mencari nama cabang dari mana komit ini berasal. Ini harus berfungsi untuk cabang jarak jauh, salinan lokal tidak tersedia.
Inilah yang saya kerjakan:
Secara opsional, Anda dapat menghapus output:
sumber
Saya pikir seseorang harus menghadapi masalah yang sama yang tidak dapat menemukan cabang, meskipun sebenarnya ada di satu cabang.
Anda sebaiknya menarik semua terlebih dahulu:
Kemudian lakukan pencarian cabang:
atau:
sumber
Jika OP sedang mencoba untuk menentukan sejarah yang dilalui oleh cabang ketika komit tertentu dibuat ("cari tahu dari mana cabang komit berasal dari diberi nilai hash SHA-1"), maka tanpa reflog tidak ada catatan dalam database objek Git yang menunjukkan apa yang bernama cabang terikat dengan apa yang melakukan histori.
(Saya memposting ini sebagai jawaban sebagai balasan atas komentar.)
Semoga skrip ini mengilustrasikan poin saya:
Output menunjukkan kurangnya cara untuk mengetahui apakah komit dengan 'Add f1' berasal dari cabang b1 atau b2 dari remote clone / tmp / r2.
(Baris terakhir dari output di sini)
sumber
git log 80c10e5..HEAD --ancestry-path --merges --oneline --color | tail -n 1
dangit log 086c9ce..HEAD --ancestry-path --merges --oneline --color | tail -n 1
perintah untuk kedua kasus?$ git log HEAD^1..HEAD --ancestry-path --merges --oneline --color | tail -n 1
yang menghasilkan376142d merge branches
dan$ git log HEAD^2..HEAD --ancestry-path --merges --oneline --color | tail -n 1
yang menghasilkan376142d merge branches
- yang menunjukkan ringkasan komit gabung, yang (seperti yang saya nyatakan) dapat ditimpa ketika penggabungan dibuat, mungkin mengaburkan sejarah cabang penggabungan.TL; DR:
Gunakan di bawah ini jika Anda peduli tentang status keluar shell:
branch-current
- nama cabang saat inibranch-names
- nama cabang bersih (satu per baris)branch-name
- Pastikan hanya satu cabang yang dikembalikanbranch-names
Keduanya
branch-name
danbranch-names
menerima komit sebagai argumen, dan default keHEAD
jika tidak ada yang diberikan.Alias berguna dalam skrip
Komit hanya dapat dicapai dari satu cabang saja
0
.Berkomitmen terjangkau dari banyak cabang
1
.Karena status keluar, ini dapat dibangun dengan aman. Misalnya, untuk membuat remote digunakan untuk mengambil:
sumber
Untuk menemukan cabang lokal:
Untuk menemukan cabang jarak jauh:
sumber
Selain mencari melalui semua pohon sampai Anda menemukan hash yang cocok, tidak.
sumber