Apakah ada cara untuk mengetahui dari mana sebuah commit berasal dari nilai hash SHA-1-nya ?
Poin bonus jika Anda dapat memberi tahu saya cara melakukannya menggunakan Ruby Grit.
Apakah ada cara untuk mengetahui dari mana sebuah commit berasal dari nilai hash SHA-1-nya ?
Poin bonus jika Anda dapat memberi tahu saya cara melakukannya menggunakan Ruby Grit.
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.
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.
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 show
sebenarnya 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.
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-ff
opsi git 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.
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):
git name-rev 651ad3a
251ad3a remotes/origin/test-branch
Bahkan ini berfungsi untuk skenario kompleks, seperti:
origin/branchA/
/branchB
/commit<SHA1>
/commit<SHA2>
Di sini git name-rev commit<SHA2>
mengembalikan branchB .
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:
git-what-branch
(Perl script, lihat di bawah) tampaknya tidak dipertahankan lagi.git-when-merged
adalah alternatif yang ditulis dengan Python yang bekerja sangat baik untuk saya.
Ini didasarkan pada " Temukan komit gabungan yang menyertakan komit tertentu ".
git when-merged [OPTIONS] COMMIT [BRANCH...]
Temukan ketika komit digabung menjadi satu atau beberapa cabang.
Temukan komit gabungan yang dibawaCOMMIT
ke dalam CABANG tertentu (es).Secara khusus, cari komit tertua pada sejarah orang tua pertama
BRANCH
yang berisiCOMMIT
leluhur.
Jawaban asli September 2010:
Sebastien Douche baru saja twit (16 menit sebelum jawaban SO ini):
git-what-branch : Temukan cabang apa yang digunakan komit, atau bagaimana ia sampai ke cabang bernama
Ini adalah skrip Perl dari Seth Robertson yang tampaknya sangat menarik:
RINGKASAN
git-what-branch [--allref] [--all] [--topo-order | --date-order ]
[--quiet] [--reference-branch=branchname] [--reference=reference]
<commit-hash/tag>...
GAMBARAN
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-order
ditentukan).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 tag
untuk 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-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 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
Memperbarui
Atau hanya satu perintah:
git log c0118fa..HEAD --ancestry-path --merges --oneline --color | tail -n 1
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 masalah
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
(crosspost dari jawaban SO ini )
khichar.anil membahas sebagian besar ini dalam jawabannya.
Saya hanya menambahkan bendera yang akan menghapus tag dari daftar nama revisi. Ini memberi kita:
git name-rev --name-only --exclude=tags/* $SHA
Pilihan orang miskin adalah menggunakan alat tig
1 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.
Anda dapat memeriksanya di sini: https://github.com/pajp/branch-info-commits
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'
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:
git pull --all
Kemudian lakukan pencarian cabang:
git name-rev <SHA>
atau:
git branch --contains <SHA>
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:
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;
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)
+ 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
git log 80c10e5..HEAD --ancestry-path --merges --oneline --color | tail -n 1
dan git 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 menghasilkan 376142d merge branches
dan $ git log HEAD^2..HEAD --ancestry-path --merges --oneline --color | tail -n 1
yang menghasilkan 376142d merge branches
- yang menunjukkan ringkasan komit gabung, yang (seperti yang saya nyatakan) dapat ditimpa ketika penggabungan dibuat, mungkin mengaburkan sejarah cabang penggabungan.
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 dikembalikan branch-names
Keduanya branch-name
dan branch-names
menerima komit sebagai argumen, dan default ke HEAD
jika tidak ada yang diberikan.
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\" #"
% git branch-name eae13ea
master
% echo $?
0
0
.% git branch-name 4bc6188
Multiple branches:
attempt-extract
master%
% echo $?
1
1
.Karena status keluar, ini dapat dibangun dengan aman. Misalnya, untuk membuat remote digunakan untuk mengambil:
remote-fetch = !"branch=$(git branch-name \"$1\") && git config branch.\"$branch\".remote || echo origin #"
Untuk menemukan cabang lokal:
grep -lR YOUR_COMMIT .git/refs/heads | sed 's/.git\/refs\/heads\///g'
Untuk menemukan cabang jarak jauh:
grep -lR $commit .git/refs/remotes | sed 's/.git\/refs\/remotes\///g'
Selain mencari melalui semua pohon sampai Anda menemukan hash yang cocok, tidak.