Hãy tưởng tượng lịch sử sau đây:
c---e---g--- feature
/ \
-a---b---d---f---h--- master
Làm thế nào tôi có thể tìm thấy khi cam kết "c" đã được hợp nhất thành chủ (nghĩa là tìm cam kết hợp nhất "h")?
Hãy tưởng tượng lịch sử sau đây:
c---e---g--- feature
/ \
-a---b---d---f---h--- master
Làm thế nào tôi có thể tìm thấy khi cam kết "c" đã được hợp nhất thành chủ (nghĩa là tìm cam kết hợp nhất "h")?
Câu trả lời:
Ví dụ của bạn cho thấy chi nhánh feature
vẫn có sẵn.
Trong trường hợp đó h
là kết quả cuối cùng của:
git log master ^feature --ancestry-path
Nếu chi nhánh feature
không còn khả dụng nữa, bạn có thể hiển thị các cam kết hợp nhất trong dòng lịch sử giữa c
và master
:
git log <SHA-1_for_c>..master --ancestry-path --merges
Tuy nhiên, điều này cũng sẽ hiển thị tất cả các sự hợp nhất đã xảy ra sau h
và giữa e
và g
trên feature
.
So sánh kết quả của các lệnh sau:
git rev-list <SHA-1_for_c>..master --ancestry-path
git rev-list <SHA-1_for_c>..master --first-parent
sẽ cung cấp cho bạn SHA-1 h
là hàng cuối cùng.
Nếu bạn có sẵn, bạn có thể sử dụng comm -1 -2
trên các kết quả này. Nếu bạn đang sử dụng msysgit, bạn có thể sử dụng mã perl sau đây để so sánh:
perl -ne 'print if ($seen{$_} .= @ARGV) =~ /10$/' file1 file2
(mã perl từ http://www.cyberciti.biz/faq/command-to-display-lines-common-in-files/ , lấy từ "ai đó trong nhóm tin comp.unix.shell").
Xem thay thế quá trình nếu bạn muốn làm cho nó một lót.
master
được sáp nhập vào feature
, sau đó ngay lập tức feature
được hợp nhất thành master
một chuyển tiếp nhanh (mẹo feature
thay thế master
). Điều đó sẽ gây ra --first-parent
trả lại sai cha mẹ?
comm -1 -2
nhưng nó không hoạt động. comm
chỉ hoạt động trên các dòng được sắp xếp. (Công cụ một lớp perl hoạt động, mặc dù tôi không thể đọc nó.)
git find-merge h master
(trả về không có gì nhưng nên trả về h), git find-merge d master
(trả về f nhưng nên trả về d), git find-merge c feature
(trả về e nhưng nên trả về g).
Thêm phần này vào ~/.gitconfig
:
[alias]
find-merge = "!sh -c 'commit=$0 && branch=${1:-HEAD} && (git rev-list $commit..$branch --ancestry-path | cat -n; git rev-list $commit..$branch --first-parent | cat -n) | sort -k2 -s | uniq -f1 -d | sort -n | tail -1 | cut -f2'"
show-merge = "!sh -c 'merge=$(git find-merge $0 $1) && [ -n \"$merge\" ] && git show $merge'"
Sau đó, bạn có thể sử dụng các bí danh như thế này:
# current branch
git find-merge <SHA-1>
# specify master
git find-merge <SHA-1> master
Để xem thông điệp của cam kết hợp nhất và các chi tiết khác, hãy sử dụng git show-merge
với cùng các đối số.
(Dựa trên câu trả lời của Gauthier . Cảm ơn Rosen Matev và javabrett đã sửa lỗi sort
.)
sort -k2 | uniq -f1 -d | sort -n | tail -1 | cut -f2
không tìm thấy chính xác hàng cuối cùng. Đây là một ví dụ khi nó thất bại.
16db9fef5c581ab0c56137d04ef08ef1bf82b0b7
ở đây khi tôi chạy nó trên dán của bạn, điều đó không được mong đợi? Bạn đang dùng hệ điều hành nào?
29c40c3a3b33196d4e79793bd8e503a03753bad1
git-get-merge sẽ định vị và hiển thị cam kết hợp nhất mà bạn đang tìm kiếm:
pip install git-get-merge
git get-merge <SHA-1>
Lệnh theo các con của cam kết đã cho cho đến khi hợp nhất vào một nhánh khác (có lẽ là chủ) được tìm thấy.
Đó là, để tóm tắt bài đăng của Gauthier:
perl -ne 'print if ($seen{$_} .= @ARGV) =~ /10$/' <(git rev-list --ancestry-path <SHA-1_for_c>..master) <(git rev-list --first-parent <SHA-1_for_c>..master) | tail -n 1
EDIT: bởi vì điều này sử dụng thay thế quá trình " <()
", nó không tương thích POSIX và nó có thể không hoạt động với trình bao của bạn. Nó hoạt động với bash
hoặc zsh
mặc dù.
<()
không tương thích POSIX. Bạn cần sử dụng bash
, zsh
hoặc một vỏ hỗ trợ quá trình thay thế . Tôi chỉnh sửa câu trả lời của tôi cho phù hợp.
Tôi cần phải làm điều này, và bằng cách nào đó đã tìm thấy git-when-merged
(thực sự tham khảo câu hỏi SO này, nhưng Michael Haggerty không bao giờ thêm một tài liệu tham khảo cho kịch bản Python rất hay của mình ở đây). Vì vậy, bây giờ tôi có.
Dựa trên câu trả lời tuyệt vời của Gauthier, chúng tôi không cần sử dụng comm
để so sánh các danh sách. Vì chúng tôi đang tìm kiếm kết quả cuối cùng --ancestry-path
cũng nằm trong đó --first-parent
, chúng tôi chỉ có thể grep cho kết quả sau trong kết quả đầu ra:
git rev-list <SHA>..master --ancestry-path | grep -f <(git rev-list <SHA>..master --first-parent) | tail -1
Hoặc đối với một cái gì đó linh hoạt và có thể tái sử dụng, đây là một chức năng để bật vào .bashrc
:
function git-find-merge() {
git rev-list $1..master --ancestry-path | grep -f <(git rev-list $1..master --first-parent) | tail -1
}
comm
không hoạt động khi đầu vào không được sắp xếp.
Đối với đám đông Ruby, có git-whence . Rất dễ.
$ gem install git-whence
$ git whence 1234567
234557 Merge pull request #203 from branch/pathway
Tôi sử dụng tập lệnh bash bên dưới mà tôi đặt tại đường dẫn ~/bin/git-find-merge
. Nó dựa trên câu trả lời của Gauthier và câu trả lời của evilstreak với một vài điều chỉnh để xử lý các trường hợp góc. comm
ném khi đầu vào không được sắp xếp. grep -f
hoạt động hoàn hảo.
Trường hợp góc:
~/bin/git-find-merge
kịch bản:
#!/bin/bash
commit=$1
if [ -z $commit ]; then
echo 1>&2 "fatal: commit is required"
exit 1
fi
commit=$(git rev-parse $commit)
branch=${2-@}
# if branch points to commit (both are same), then return commit
if [ $commit == $(git rev-parse $branch) ]; then
git log -1 $commit
exit
fi
# if commit is a merge commit on first-parent path of branch,
# then return commit
# if commit is a NON-merge commit on first-parent path of branch,
# then return branch as it's either a ff merge or commit is only on branch
# and there is not a good way to figure out the right commit
if [[ $(git log --first-parent --pretty='%P' $commit..$branch | \
cut -d' ' -f1 | \
grep $commit | wc -l) -eq 1 ]]; then
if [ $(git show -s --format="%P" $commit | wc -w) -gt 1 ]; then
# if commit is a merge commit
git log -1 $commit
else
# if commit is a NON-merge commit
echo 1>&2 ""
echo 1>&2 "error: returning the branch commit (ff merge or commit only on branch)"
echo 1>&2 ""
git log -1 $branch
fi
exit
fi
# 1st common commit from bottom of first-parent and ancestry-path
merge=$(grep -f \
<(git rev-list --first-parent $commit..$branch) \
<(git rev-list --ancestry-path $commit..$branch) \
| tail -1)
if [ ! -z $merge ]; then
git log -1 $merge
exit
fi
# merge commit not found
echo 1>&2 "fatal: no merge commit found"
exit 1
Cho phép tôi làm điều này:
(master)
$ git find-merge <commit> # to find when commit merged to current branch
$ git find-merge <branch> # to find when branch merged to current branch
$ git find-merge <commit> pu # to find when commit merged to pu branch
Kịch bản này cũng có sẵn trên github của tôi .
Phiên bản ruby của tôi về ý tưởng @ robinst, hoạt động nhanh hơn gấp đôi (điều này rất quan trọng khi tìm kiếm cam kết rất cũ).
find-commit.rb
commit = ARGV[0]
master = ARGV[1] || 'origin/master'
unless commit
puts "Usage: find-commit.rb commit [master-branch]"
puts "Will show commit that merged <commit> into <master-branch>"
exit 1
end
parents = `git rev-list #{commit}..#{master} --reverse --first-parent --merges`.split("\n")
ancestry = `git rev-list #{commit}..#{master} --reverse --ancestry-path --merges`.split("\n")
merge = (parents & ancestry)[0]
if merge
system "git show #{merge}"
else
puts "#{master} doesn't include #{commit}"
exit 2
end
Bạn chỉ có thể sử dụng nó như thế này:
ruby find-commit.rb SHA master
Bạn có thể thử một cái gì đó như thế này. Ý tưởng là lặp đi lặp lại qua tất cả các cam kết hợp nhất và xem liệu cam kết "c" có thể truy cập được từ một trong số chúng không:
$ git log --merges --format='%h' master | while read mergecommit; do
if git log --format='%h' $mergecommit|grep -q $c; then
echo $mergecommit;
break
fi
done
git rev-list <SHA-1_for_c>..master --ancestry-path --merges
Tôi đã phải làm điều này nhiều lần (cảm ơn mọi người đã trả lời câu hỏi này!), Và cuối cùng tôi đã viết một kịch bản (sử dụng phương pháp Gauthier) mà tôi có thể thêm vào bộ sưu tập tiện ích git nhỏ của mình. Bạn có thể tìm thấy nó ở đây: https://github.com/mwoehlke/git-utils/blob/master/bin/git-merge-point .