ลองนึกภาพประวัติศาสตร์ต่อไปนี้:
c---e---g--- feature
/ \
-a---b---d---f---h--- master
ฉันจะค้นหาได้อย่างไรเมื่อคอมมิชชัน "c" ถูกรวมเข้ากับมาสเตอร์ (เช่นค้นหาผสานการกระทำ "h")
ลองนึกภาพประวัติศาสตร์ต่อไปนี้:
c---e---g--- feature
/ \
-a---b---d---f---h--- master
ฉันจะค้นหาได้อย่างไรเมื่อคอมมิชชัน "c" ถูกรวมเข้ากับมาสเตอร์ (เช่นค้นหาผสานการกระทำ "h")
คำตอบ:
ตัวอย่างของคุณแสดงให้เห็นว่าสาขาfeatureยังคงมีอยู่
ในกรณีhนั้นคือผลลัพธ์สุดท้ายของ:
git log master ^feature --ancestry-path
หากสาขาfeatureไม่สามารถใช้งานได้อีกต่อไปคุณสามารถแสดงการรวมการกระทำในบรรทัดประวัติระหว่างcและmaster:
git log <SHA-1_for_c>..master --ancestry-path --merges
นี้จะ แต่ยังแสดงให้เห็นการผสานทั้งหมดที่เกิดขึ้นหลังจากที่hและระหว่างeและบนgfeature
การเปรียบเทียบผลลัพธ์ของคำสั่งต่อไปนี้:
git rev-list <SHA-1_for_c>..master --ancestry-path
git rev-list <SHA-1_for_c>..master --first-parent
จะให้ SHA-1 ของคุณhเหมือนกับแถวสุดท้าย
หากคุณมีให้คุณสามารถใช้comm -1 -2กับผลลัพธ์เหล่านี้ หากคุณใช้ msysgit คุณสามารถใช้รหัส Perl ต่อไปนี้เพื่อเปรียบเทียบ:
perl -ne 'print if ($seen{$_} .= @ARGV) =~ /10$/' file1 file2
(รหัส Perl จากhttp://www.cyberciti.biz/faq/command-to-display-lines-common-in-files/ซึ่งเอามาจาก "ใครบางคนที่กลุ่มข่าว comp.unix.shell")
ดูกระบวนการทดแทนหากคุณต้องการทำให้เป็นหนึ่งซับ
masterถูกรวมเข้าด้วยกันfeatureจากนั้นfeatureจะถูกรวมเข้าด้วยกันmasterเป็นแบบกรอไปข้างหน้า ( featureแทนที่ด้วยเคล็ดลับmaster) สาเหตุนั้น--first-parentจะส่งคืนผู้ปกครองผิดหรือเปล่า?
comm -1 -2แต่มันใช้งานไม่ได้ commทำงานบนเส้นที่เรียงลำดับเท่านั้น (perl one-liner ใช้งานได้แม้ว่าฉันจะอ่านไม่ออก)
git find-merge h master(ไม่คืนสิ่งใด แต่ควรคืนค่า h), git find-merge d master(คืนค่า f แต่ควรคืนค่า d), git find-merge c feature(คืนค่า e แต่ควรคืนค่า g)
เพิ่มลงในของคุณ~/.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'"
จากนั้นคุณสามารถใช้ชื่อแทนดังนี้:
# current branch
git find-merge <SHA-1>
# specify master
git find-merge <SHA-1> master
เมื่อต้องการดูข้อความรวมของการกระทำและรายละเอียดอื่น ๆ ให้ใช้git show-mergeกับอาร์กิวเมนต์เดียวกัน
(ขึ้นอยู่กับคำตอบของ GauthierขอบคุณRosen Matevและjavabrettสำหรับการแก้ไขปัญหาด้วยsort)
sort -k2 | uniq -f1 -d | sort -n | tail -1 | cut -f2การค้นหาไม่ถูกต้องแถวสุดท้ายเหมือนกัน นี่คือตัวอย่างที่มันล้มเหลว
16db9fef5c581ab0c56137d04ef08ef1bf82b0b7ที่นี่เมื่อฉันเรียกใช้งานในการวางของคุณนั่นเป็นสิ่งที่ไม่คาดคิดหรือ คุณใช้ระบบปฏิบัติการอะไร
29c40c3a3b33196d4e79793bd8e503a03753bad1
git-get-mergeจะค้นหาและแสดงการรวมที่คุณกำลังมองหา:
pip install git-get-merge
git get-merge <SHA-1>
คำสั่งจะติดตามลูก ๆ ของการคอมมิทที่กำหนดไว้จนกว่าจะพบการรวมเข้ากับสาขาอื่น
นั่นคือเพื่อสรุปโพสต์ของ 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
แก้ไข: เพราะสิ่งนี้ใช้การทดแทนกระบวนการ " <()" มันเข้ากันไม่ได้กับ POSIX และอาจใช้ไม่ได้กับเชลล์ของคุณ มันทำงานร่วมกับbashหรือzshแม้ว่า
<()ไม่รองรับ POSIX คุณจำเป็นต้องใช้bash, zshหรือเปลือกสนับสนุนเปลี่ยนตัวกระบวนการ ฉันแก้ไขคำตอบของฉัน
ฉันต้องทำสิ่งนี้และพบว่าgit-when-merged(ซึ่งอ้างอิงคำถาม SO นี้จริง ๆ แต่ Michael Haggerty ไม่เคยเพิ่มการอ้างอิงถึงสคริปต์ Python ที่ดีมากของเขาที่นี่) ดังนั้นตอนนี้ฉันมี
จากคำตอบที่ยอดเยี่ยมของ Gauthier เราไม่จำเป็นต้องใช้commเพื่อเปรียบเทียบรายการ เนื่องจากเรากำลังค้นหาผลลัพธ์สุดท้าย--ancestry-pathที่มีอยู่ใน--first-parentนั้นเราสามารถ grep สำหรับผลลัพธ์ในผลลัพธ์ของอดีต:
git rev-list <SHA>..master --ancestry-path | grep -f <(git rev-list <SHA>..master --first-parent) | tail -1
หรือเพื่ออะไรที่เร็วและนำกลับมาใช้ใหม่ได้นี่คือฟังก์ชันที่จะเข้ามา.bashrc:
function git-find-merge() {
git rev-list $1..master --ancestry-path | grep -f <(git rev-list $1..master --first-parent) | tail -1
}
commไม่ทำงานเมื่อไม่มีการเรียงลำดับอินพุต
~/bin/git-find-mergeผมใช้ด้านล่างสคริปต์ทุบตีซึ่งผมสถานที่เส้นทาง มันขึ้นอยู่กับคำตอบของ Gauthierและคำตอบของ evilstreak ที่มีการปรับแต่งเล็กน้อยเพื่อจัดการกับมุมกล่อง commพ่นเมื่ออินพุตไม่ได้ถูกจัดเรียง grep -fทำงานได้อย่างสมบูรณ์แบบ
กรณีมุม:
~/bin/git-find-merge สคริปต์:
#!/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
ซึ่งให้ฉันทำสิ่งนี้:
(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
สคริปต์นี้ยังมีอยู่บน GitHub
git log --topo-order
จากนั้นค้นหาการผสานแรกก่อนที่จะส่ง
ความคิดของฉันในรุ่น ruby ของ @ robinst ทำงานได้เร็วขึ้นสองเท่า (ซึ่งเป็นสิ่งสำคัญเมื่อค้นหาการกระทำที่เก่ามาก)
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
คุณสามารถใช้มันได้ดังนี้:
ruby find-commit.rb SHA master
คุณสามารถลองสิ่งนี้ ความคิดคือการวนซ้ำทุกการกระทำรวมและดูว่าการกระทำ "c" สามารถเข้าถึงได้จากหนึ่งในพวกเขา:
$ 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