แสดงเฉพาะ hunks ที่เกี่ยวข้องของ diff / patch ตาม regexp


20

git log -G<regex> -pเป็นเครื่องมือที่ยอดเยี่ยมในการค้นหาประวัติของ codebase สำหรับการเปลี่ยนแปลงที่ตรงกับรูปแบบที่ระบุ อย่างไรก็ตามมันอาจเป็นเรื่องยากที่จะค้นหาก้อนใหญ่ที่เกี่ยวข้องในเอาท์พุท diff / patch ในทะเลของนักล่าที่ไม่เกี่ยวข้องส่วนใหญ่

แน่นอนว่าเป็นไปได้ที่จะค้นหาผลลัพธ์ของgit logสตริง / regex ดั้งเดิม แต่ก็มีน้อยที่จะลดเสียงรบกวนที่มองเห็นและการเบี่ยงเบนของการเปลี่ยนแปลงที่ไม่เกี่ยวข้องจำนวนมาก

อ่านต่อgit logไปฉันเห็นว่ามันมี--pickaxe-allซึ่งตรงข้ามกับสิ่งที่ฉันต้องการ: มันขยายเอาต์พุต (ไปยังชุดการเปลี่ยนแปลงทั้งหมด) ในขณะที่ฉันต้องการ จำกัด (เฉพาะก้อนใหญ่)

โดยพื้นฐานแล้วฉันกำลังมองหาวิธี "แยกแยะ" อย่างชาญฉลาด "ในการแยก diff / patch ลงใน hunks แต่ละอันแล้วทำการค้นหากับแต่ละก้อนใหญ่ (กำหนดเป้าหมายเพียงแค่บรรทัดที่เปลี่ยนไป) ทิ้งกลุ่ม hunks ที่ไม่ตรงกัน ที่ทำ

มีเครื่องมือเช่นที่ฉันอธิบายอยู่หรือไม่? มีวิธีการที่ดีกว่าในการได้รับการจับคู่หรือได้รับผลกระทบหรือไม่?

งานวิจัยเริ่มแรกที่ฉันทำ ...

  • หากเป็นไปได้ที่จะgrepส่งออก diff / patch และทำให้ค่าตัวเลือกบริบทเป็นแบบไดนามิก - พูดผ่าน regexps แทนการนับจำนวนบรรทัด - ซึ่งอาจพอเพียง แต่grepไม่ได้สร้างแบบนั้นอย่างแน่นอน (หรือฉันไม่จำเป็นต้องขอคุณสมบัตินั้น)

  • ฉันพบชุดpatchutilsซึ่งฟังดูคล้ายกับความต้องการของฉัน แต่หลังจากอ่านmanหน้าเว็บแล้วเครื่องมือจะไม่ปรากฏขึ้นเพื่อจัดการกับการจับคู่ของนักล่าตาม regexps (พวกเขาสามารถรับรายชื่อนักล่าได้แม้ว่า ... )

  • ในที่สุดฉันก็เจอกับsplitpatch.rbซึ่งดูเหมือนว่าจะจัดการกับการแยกวิเคราะห์ของแพทช์ได้ดี แต่มันจะต้องมีการปรับปรุงอย่างมากเพื่อจัดการแพทช์การอ่านผ่านstdinจับคู่ hunks ที่ต้องการแล้วส่งออก hunks


1
ไม่ใช่ exacly ที่คุณถาม แต่ลอง git log -Gfoo | น้อยลง + / foo
James Youngman

คำตอบ:


7

ที่นี่/programming//a/35434714/5305907อธิบายวิธีการทำสิ่งที่คุณกำลังมองหา ได้อย่างมีประสิทธิภาพ:

git diff -U1 | grepdiff 'console' --output-matching=hunk

มันจะแสดงเฉพาะนักล่าที่ตรงกับสตริง "คอนโซล" ที่ระบุ


ขอบคุณ grepdiffเป็นสิ่งที่ฉันต้องการ ฉันต้องพลาดตัวเลือกการจับคู่ก้อนใหญ่! อย่างไรก็ตาม ... ข้อมูลการคอมไพล์ถูกปล้นgrepdiffดังนั้นเมื่อคุณค้นหาก้อนใหญ่ที่เกี่ยวข้องคุณจะต้อง Div ศักดิ์สิทธิ์ sha จากวัตถุ / blob sha ในส่วนหัว diff ซึ่งเป็นการดำเนินการที่ค่อนข้างแพง (ดูstackoverflow.com/a/223890/2284440 ) มันจะเป็นอย่างไรgit find-object SHA --reverse | head -1 | cut -c 1-7 | { read sha ; git log -1 $sha; }
wrksprfct

ยังทราบว่ามีรุ่น golanggrepdiffซึ่งเป็นกระดูกเปล่ามากขึ้นในแง่ของการขัดแย้งได้รับการยอมรับ โปรดทราบว่าเมื่อก้อนใหญ่ที่จับคู่เป็นก้อนสุดท้ายใน diff มันรวมส่วนหัวคอมมิทคอมไพล์ของคอมมิทต่อไปนี้ - สิ่งที่ทำให้ฉันสับสนจนฉันไม่รู้ว่าเกิดอะไรขึ้น!
wrksprfct

0

ไม่ใช่สิ่งที่คุณต้องการอย่างแน่นอน แต่วิธีหนึ่งในการ grep ผ่าน hunks คือโหมดเพิ่มการโต้ตอบ คุณต้องตรวจสอบคอมมิชชันหลังจากที่แพทช์ที่คุณสนใจ

git checkout COMMIT_ID

จากนั้นย้อนกลับไปอีกหนึ่งขั้นใน VCS แต่ไม่ใช่ในไดเรกทอรีทำงาน

git reset --soft HEAD^

(ณ จุดนี้ความแตกต่างระหว่างดัชนีและไดเรกทอรีการทำงานจะสอดคล้องกับแพทช์ที่คุณสนใจ)

git add -pตอนนี้คุณสามารถดำเนินการ นี้จะเปิดตัวเซสชันการโต้ตอบซึ่งมี/ตัวเลือกที่ช่วยให้คุณค้นหาตำแหน่งที่มีบางบรรทัดที่ตรงกับ regex มีประโยชน์อย่างยิ่งหากคุณต้องการประมวลผลแพตช์เหล่านั้น (เช่นการเตรียมเชอร์รี่เลือกบางส่วน)

น่าเสียดายที่อย่างน้อยตอนนี้/คำสั่งadd -pใช้งานได้ในไฟล์เดียวดังนั้นคุณอาจต้องข้ามไฟล์ที่ไม่เกี่ยวข้องหลายไฟล์


0

สร้างขึ้นจากคำตอบข้างต้นโดย @nagu และคำตอบอื่น ๆ ที่เชื่อมโยงกันฉันสามารถไปgit log -Gแสดงเฉพาะนักล่าที่เกี่ยวข้องได้

  1. สร้างสคริปต์เป็นอันดับแรกใน $ PATH ด้วยเนื้อหานี้:

    #!/bin/bash
    
    # pickaxe-diff : external diff driver for Git.
    #                To be used with the pickaxe options (git [log|show|diff[.*] [-S|-G])
    #                to only show hunks containing the searched string/regex.
    
    path=$1
    old_file=$2
    old_hex=$3
    old_mode=$4
    new_file=$5
    new_hex=$6
    new_mode=$7
    
    filtered_diff=$(diff -u -p $old_file $new_file | \
                    grepdiff "$GREPDIFF_REGEX" --output-matching=hunk | \
                    grep -v -e '+++ ' -e '--- ')
    
    a_path="a/$path"
    b_path="b/$path"
    
    echo "diff --git $a_path $b_path"
    echo "index $old_hex..$new_hex $old_mode"
    echo "--- $a_path"
    echo "+++ $b_path"
    echo "$filtered_diff"
  2. โทรgit log -Gและบอก Git ให้ใช้pickaxe-diffสคริปต์เป็นไดร์เวอร์ diff ภายนอก:

    export GREPDIFF_REGEX=<string>; 
    GIT_EXTERNAL_DIFF=pickaxe-diff git log -p --ext-diff -G $GREPDIFF_REGEX

    สิ่งนี้จะใช้สคริปต์ pickaxe-diff เพียงเพื่อสร้าง diffs ดังนั้นส่วนที่เหลือของgit logเอาท์พุท (กระทำแฮชข้อความ ฯลฯ ) จะไม่ถูกแตะต้อง

Caveat
วิธีการทำงานของ Gax pickaxe คือมัน จำกัด เอาท์พุทเป็นไฟล์ที่นักล่าเปลี่ยนสตริง / regex ที่กำหนด ซึ่งหมายความว่าหากก้อนใหญ่อื่นในไฟล์เหล่านี้ยังมีสตริงการค้นหา / regex แต่ไม่เปลี่ยนแปลงมันจะยังคงแสดงด้วยสคริปต์ข้างต้น นี่เป็นข้อ จำกัด ของ grepdiff มีการร้องขอแบบเปิดที่โครงการ patchutils เพื่อเพิ่มการ--only-matchingตั้งค่าสถานะเป็น grepdiff ซึ่งจะให้ฟังก์ชันที่จำเป็นในการกรอง hunks เหล่านี้อย่างถูกต้อง


ฉันเขียนบทความเกี่ยวกับโซลูชันของฉันในกระทู้นี้

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.