Có cách nào để tìm ra nhánh mà một cam kết đến từ giá trị băm SHA-1 của nó không?
Điểm thưởng nếu bạn có thể cho tôi biết cách thực hiện điều này bằng Ruby Grit.
Có cách nào để tìm ra nhánh mà một cam kết đến từ giá trị băm SHA-1 của nó không?
Điểm thưởng nếu bạn có thể cho tôi biết cách thực hiện điều này bằng Ruby Grit.
Câu trả lời:
Mặc dù Dav chính xác là thông tin không được lưu trữ trực tiếp, nhưng điều đó không có nghĩa là bạn không thể tìm ra. Dưới đây là một vài điều bạn có thể làm.
git branch -a --contains <commit>
Điều này sẽ cho bạn biết tất cả các chi nhánh có cam kết nhất định trong lịch sử của họ. Rõ ràng điều này ít hữu ích hơn nếu các cam kết đã được hợp nhất.
Nếu bạn đang làm việc trong kho lưu trữ mà cam kết được thực hiện, bạn có thể tìm kiếm các reflog cho dòng cho cam kết đó. Các reflog cũ hơn 90 ngày được git-gc cắt tỉa, vì vậy nếu cam kết quá cũ, bạn sẽ không tìm thấy nó. Điều đó nói rằng, bạn có thể làm điều này:
git reflog show --all | grep a871742
để tìm cam kết a871742. Lưu ý rằng bạn PHẢI sử dụng chữ viết tắt 7 chữ số đầu tiên của cam kết. Đầu ra phải giống như thế này:
a871742 refs/heads/completion@{0}: commit (amend): mpc-completion: total rewrite
chỉ ra rằng cam kết đã được thực hiện trên nhánh "hoàn thành". Đầu ra mặc định hiển thị băm cam kết viết tắt, vì vậy hãy chắc chắn không tìm kiếm băm đầy đủ nếu không bạn sẽ không tìm thấy gì.
git reflog show
thực ra chỉ là một bí danh cho git log -g --abbrev-commit --pretty=oneline
, vì vậy nếu bạn muốn tìm hiểu về định dạng đầu ra để làm cho những thứ khác nhau có sẵn cho grep cho, đó là điểm khởi đầu của bạn!
Nếu bạn không làm việc trong kho lưu trữ nơi cam kết được thực hiện, cách tốt nhất bạn có thể làm trong trường hợp này là kiểm tra các reflog và tìm thấy khi cam kết lần đầu tiên được đưa vào kho lưu trữ của bạn; với bất kỳ may mắn nào, bạn đã lấy được chi nhánh mà nó đã cam kết. Điều này phức tạp hơn một chút, bởi vì bạn không thể đi bộ cả cây cam kết và reflog đồng thời. Bạn muốn phân tích đầu ra reflog, kiểm tra từng hàm băm để xem nó có chứa cam kết mong muốn hay không.
Điều này phụ thuộc vào quy trình công việc, nhưng với quy trình công việc tốt, các cam kết được thực hiện trên các nhánh phát triển sau đó được hợp nhất. Bạn có thể làm điều này:
git log --merges <commit>..
để xem các cam kết hợp nhất có cam kết đã cho như một tổ tiên. (Nếu cam kết chỉ được hợp nhất một lần, thì lần đầu tiên sẽ là sự hợp nhất mà bạn theo sau; nếu không, bạn sẽ phải kiểm tra một vài, tôi cho rằng.
Nếu bạn muốn có thể tin tưởng vào việc này, bạn có thể muốn sử dụng --no-ff
tùy chọn git merge
để buộc hợp nhất tạo cam kết ngay cả trong trường hợp chuyển tiếp nhanh. (Tuy nhiên, đừng quá háo hức. Điều đó có thể trở nên khó hiểu nếu bị lạm dụng.) Câu trả lời của VonC cho một câu hỏi liên quan được xây dựng một cách hữu ích về chủ đề này.
git describe
là đủ, cho các thẻ (chú thích) có thể được xem là quan trọng hơn so với các chi nhánh.
--no-ff
tùy chọn để đảm bảo luôn có một cam kết hợp nhất, vì vậy bạn luôn có thể theo dõi đường dẫn của một cam kết nhất định khi nó được hợp nhất với chủ.
-a
cờ vào lệnh đầu tiên, ví dụ:git branch -a --contains <commit>
-r
.
merge --no-ff
để ghi lại tên chi nhánh một cách đáng tin cậy khi bạn hợp nhất. Nhưng nếu không, hãy nghĩ tên chi nhánh là nhãn ngắn tạm thời và cam kết mô tả là tên vĩnh viễn. "Cái tên ngắn nào chúng ta đã đề cập đến trong quá trình phát triển?" thực sự không nên là một câu hỏi quan trọng như "cam kết này làm gì?"
Lệnh đơn giản này hoạt động như một bùa mê:
git name-rev <SHA>
Ví dụ: trong đó nhánh thử nghiệm là tên nhánh):
git name-rev 651ad3a
251ad3a remotes/origin/test-branch
Ngay cả điều này đang làm việc cho các kịch bản phức tạp, như:
origin/branchA/
/branchB
/commit<SHA1>
/commit<SHA2>
Ở đây git name-rev commit<SHA2>
trả về nhánhB .
git name-rev --name-only <SHA>
hữu ích hơn khi chỉ lấy tên chi nhánh. Câu hỏi của tôi ... Nó có thể trả lại nhiều hơn một chi nhánh trong mọi trường hợp không?
Cập nhật tháng 12 năm 2013:
git-what-branch
(Kịch bản Perl, xem bên dưới) dường như không còn được duy trì nữa.git-when-merged
là một thay thế được viết bằng Python, nó hoạt động rất tốt đối với tôi.
Nó dựa trên " Tìm cam kết hợp nhất bao gồm một cam kết cụ thể ".
git when-merged [OPTIONS] COMMIT [BRANCH...]
Tìm khi một cam kết được sáp nhập vào một hoặc nhiều chi nhánh.
Tìm cam kết hợp nhất được đưaCOMMIT
vào CHI NHÁNH (es) đã chỉ định.Cụ thể, hãy tìm cam kết lâu đời nhất trong lịch sử cha mẹ đầu tiên
BRANCH
có chứaCOMMIT
tổ tiên.
Câu trả lời gốc tháng 9 năm 2010:
Sebastien Douche chỉ twitted (16 phút trước câu trả lời SO này):
git-what-Branch : Khám phá nhánh nào được cam kết hoặc cách nó đến nhánh được đặt tên
Đây là một kịch bản Perl từ Seth Robertson có vẻ rất thú vị:
TÓM TẮC
git-what-branch [--allref] [--all] [--topo-order | --date-order ]
[--quiet] [--reference-branch=branchname] [--reference=reference]
<commit-hash/tag>...
TỔNG QUAT
Hãy cho chúng tôi (theo mặc định) đường dẫn nhân quả và hợp nhất sớm nhất để thực hiện cam kết được yêu cầu đến một nhánh được đặt tên. Nếu một cam kết được thực hiện trực tiếp trên một nhánh có tên, đó rõ ràng là con đường sớm nhất.
Theo con đường nhân quả sớm nhất, chúng tôi có nghĩa là con đường hợp nhất thành một nhánh được đặt tên sớm nhất, theo thời gian cam kết (trừ khi
--topo-order
được chỉ định).HIỆU SUẤT
Nếu nhiều nhánh (ví dụ hàng trăm) chứa cam kết, hệ thống có thể mất nhiều thời gian (đối với một cam kết cụ thể trong cây Linux, phải mất 8 giây để khám phá một nhánh, nhưng có hơn 200 nhánh ứng cử viên) để theo dõi đường dẫn đến từng cam kết.
Lựa chọn một cụ thể--reference-branch --reference tag
để kiểm tra sẽ nhanh hơn hàng trăm lần (nếu bạn có hàng trăm chi nhánh ứng cử viên).VÍ DỤ
# 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
[...]
Chương trình này không tính đến các tác động của việc chọn cam kết quan tâm, chỉ hợp nhất các hoạt động.
git-what-branch
dường như không được duy trì nữa. git-khi-sáp nhập là một thay thế được viết bằng Python hoạt động rất tốt đối với tôi.
Ví dụ: để tìm thấy c0118fa
cam kết đó đến từ 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
Bạn nên chạy đi:
git log c0118fa..HEAD --ancestry-path --merges
Và cuộn xuống để tìm cam kết hợp nhất cuối cùng . Đó là:
commit a435005445a6752dfe788b8d994e155b3cd9778f
Merge: 0953cac a06cc29
Author: Eugen Konkov
Date: Sat Oct 1 00:54:18 2016 +0300
Merge branch 'redesign_interactions' into clean_api
Cập nhật
Hoặc chỉ một lệnh:
git log c0118fa..HEAD --ancestry-path --merges --oneline --color | tail -n 1
git merge -m"Any String Here"
sẽ che khuất thông tin chi nhánh nguồn và đích.
Merge: f6b70fa d58bdcb
. Bạn có thể đặt tên cho cam kết hợp nhất của bạn như bạn với. Tôi sẽ không có vấn đề gì
git branch --contains <ref>
là lệnh "sứ" rõ ràng nhất để làm điều này. Nếu bạn muốn làm một cái gì đó tương tự chỉ với các lệnh "ống nước":
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 từ câu trả lời SO này )
khichar.anil bao gồm hầu hết điều này trong câu trả lời của mình.
Tôi chỉ thêm cờ sẽ xóa các thẻ khỏi danh sách tên sửa đổi. Điều này cho chúng ta:
git name-rev --name-only --exclude=tags/* $SHA
Tùy chọn của một người nghèo là sử dụng công cụ tig
1 trên HEAD
, tìm kiếm cam kết và sau đó theo dõi trực quan dòng từ cam kết đó sao lưu cho đến khi nhìn thấy một cam kết hợp nhất. Thông báo hợp nhất mặc định sẽ chỉ định nhánh nào sẽ được hợp nhất vào đâu :)
1 Tig là giao diện chế độ văn bản dựa trên ncurses cho Git. Nó hoạt động chủ yếu như một trình duyệt kho Git, nhưng nó cũng có thể hỗ trợ trong việc thay đổi các cam kết ở cấp độ khối và hoạt động như một máy nhắn tin cho đầu ra từ các lệnh Git khác nhau.
Như một thử nghiệm, tôi đã thực hiện một hook hook sau cam kết lưu trữ thông tin về nhánh hiện đang được kiểm tra trong siêu dữ liệu cam kết. Tôi cũng sửa đổi một chút gitk để hiển thị thông tin đó.
Bạn có thể kiểm tra nó ở đây: https://github.com/pajp/branch-info-commits
Tôi giải quyết vấn đề tương tự ( đường ống đa chức năng Jenkins ) - chỉ có thông tin cam kết và cố gắng tìm một tên chi nhánh nơi cam kết này ban đầu xuất phát. Nó phải làm việc cho các chi nhánh từ xa, bản sao địa phương không có sẵn.
Đây là những gì tôi làm việc với:
git rev-parse HEAD | xargs git name-rev
Tùy chọn bạn có thể tước đầu ra:
git rev-parse HEAD | xargs git name-rev | cut -d' ' -f2 | sed 's/remotes\/origin\///g'
Nếu OP đang cố gắng xác định lịch sử đã đi qua một nhánh khi một cam kết cụ thể được tạo ra ("tìm hiểu chi nhánh mà một cam kết đến từ giá trị băm SHA-1 của nó"), thì không có reflog thì không có các bản ghi trong cơ sở dữ liệu đối tượng Git cho thấy nhánh được đặt tên bị ràng buộc với lịch sử cam kết.
(Tôi đã đăng bài này dưới dạng câu trả lời để trả lời nhận xét.)
Hy vọng kịch bản này minh họa quan điểm của tôi:
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;
Đầu ra cho thấy thiếu bất kỳ cách nào để biết liệu cam kết với 'Thêm F1' đến từ nhánh b1 hoặc b2 từ bản sao từ xa / tmp / r2.
(Dòng cuối cùng của đầu ra ở đây)
+ 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
và git log 086c9ce..HEAD --ancestry-path --merges --oneline --color | tail -n 1
lệnh cho cả hai trường hợp là gì?
$ git log HEAD^1..HEAD --ancestry-path --merges --oneline --color | tail -n 1
sản lượng nào 376142d merge branches
và $ git log HEAD^2..HEAD --ancestry-path --merges --oneline --color | tail -n 1
sản lượng nào 376142d merge branches
- hiển thị tóm tắt cam kết hợp nhất, mà (như tôi đã khẳng định) có thể được ghi đè khi hợp nhất được tạo, có thể làm mờ lịch sử chi nhánh của hợp nhất.
Sử dụng dưới đây nếu bạn quan tâm đến trạng thái thoát vỏ:
branch-current
- tên của chi nhánh hiện tạibranch-names
- tên chi nhánh sạch (một trên mỗi dòng)branch-name
- Đảm bảo rằng chỉ có một chi nhánh được trả về từ branch-names
Cả hai branch-name
và branch-names
chấp nhận một cam kết làm đối số và mặc định HEAD
nếu không được đưa ra.
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
.Do trạng thái thoát, chúng có thể được xây dựng một cách an toàn. Ví dụ: để có được điều khiển từ xa được sử dụng để tìm nạp:
remote-fetch = !"branch=$(git branch-name \"$1\") && git config branch.\"$branch\".remote || echo origin #"
Để tìm chi nhánh địa phương:
grep -lR YOUR_COMMIT .git/refs/heads | sed 's/.git\/refs\/heads\///g'
Để tìm chi nhánh từ xa:
grep -lR $commit .git/refs/remotes | sed 's/.git\/refs\/remotes\///g'