จะหาผู้ปกครองที่ใกล้ที่สุดของสาขา Git ได้อย่างไร?


419

สมมติว่าฉันมีพื้นที่เก็บข้อมูลในเครื่องต่อไปนี้ที่มีแผนผังการยอมรับเช่นนี้:

master --> a
            \
             \
      develop c --> d
               \
                \
         feature f --> g --> h

masterของฉันนี้เป็นรหัสล่าสุดรุ่นเสถียร , developของฉันนี้เป็น 'ถัดไป' รหัสการเปิดตัวและfeatureเป็นคุณลักษณะใหม่ที่ถูกเตรียมไว้สำหรับdevelop

สิ่งที่ฉันต้องการที่จะสามารถทำใน repo ระยะไกลของฉันโดยใช้ hooks สำหรับการผลักดันfeatureให้ถูกปฏิเสธเว้นแต่ว่าการกระทำfเป็นลูกหลานของdevelopหัวหน้าโดยตรง คือกระทำลักษณะต้นไม้อย่างนี้เพราะคุณสมบัติที่ได้รับในgit rebased

master --> a
            \
             \
      develop c --> d
                     \
                      \
               feature f --> g --> h

ดังนั้นจึงเป็นไปได้ที่:

  • ระบุสาขาแม่ของfeature?
  • ระบุการคอมมิชชันใน parent parent ซึ่งfเป็นลูกหลานของ?

จากนั้นฉันจะตรวจสอบสิ่งที่ HEAD ของสาขาหลักและดูว่าfรุ่นก่อนตรงกับ HEAD สาขาหลักหรือไม่


คำถามนี้ควรได้รับการ rephrased เพื่อค้นหาผู้ปกครองของผู้ปกครอง
Tim Boland

คำตอบ:


347

สมมติว่าที่เก็บระยะไกลมีสำเนาของการพัฒนาสาขา (คำอธิบายเริ่มต้นของคุณอธิบายในพื้นที่เก็บข้อมูลในท้องถิ่น แต่ดูเหมือนว่ามันยังมีอยู่ในระยะไกล) คุณควรจะสามารถบรรลุสิ่งที่ฉันคิดว่าคุณต้องการ แต่วิธีการ แตกต่างจากที่คุณจินตนาการไว้เล็กน้อย

ประวัติของ Git นั้นมาจากDAG ที่กระทำ สาขา (และ“ อ้างอิง” โดยทั่วไป) เป็นเพียงป้ายชั่วคราวที่ชี้ไปที่การกระทำเฉพาะใน DAG ที่มีการเติบโตอย่างต่อเนื่อง ดังนั้นความสัมพันธ์ระหว่างสาขาอาจแตกต่างกันไปตามกาลเวลา แต่ความสัมพันธ์ระหว่างการกระทำไม่ได้

    ---o---1                foo
            \
             2---3---o      bar
                  \
                   4
                    \
                     5---6  baz

ดูเหมือนว่าbazจะเป็นไปตาม (รุ่นเก่า) barหรือไม่ แต่ถ้าเราลบbarล่ะ

    ---o---1                foo
            \
             2---3
                  \
                   4
                    \
                     5---6  baz

ตอนนี้ดูเหมือนว่าจะขึ้นอยู่กับbaz fooแต่บรรพบุรุษของbazไม่เปลี่ยนแปลงเราเพิ่งลบฉลาก (และผลที่เกิดจากการห้อย) และถ้าเราเพิ่มป้ายกำกับใหม่ที่4?

    ---o---1                foo
            \
             2---3
                  \
                   4        quux
                    \
                     5---6  baz

ตอนนี้ดูเหมือนว่าจะขึ้นอยู่กับbaz quuxถึงกระนั้นบรรพบุรุษก็ยังไม่เปลี่ยน แต่เปลี่ยนฉลากเท่านั้น

อย่างไรก็ตามหากเราถามว่า“ มีความมุ่งมั่นที่จะ6ลงมือทำ3” (สมมติ3และ6เต็มไป SHA-1 กระทำชื่อ) แล้วคำตอบจะ“ใช่” ไม่ว่าจะเป็นbarและquuxป้ายชื่อที่มีอยู่หรือไม่

ดังนั้นคุณสามารถถามคำถามเช่น“ ผู้ผลักได้กระทำการสืบเชื้อสายของเคล็ดลับปัจจุบันของสาขาที่พัฒนาแล้วหรือไม่” แต่คุณไม่สามารถถามได้อย่างน่าเชื่อถือว่า

คำถามที่น่าเชื่อถือส่วนใหญ่ที่ดูเหมือนจะใกล้เคียงกับสิ่งที่คุณต้องการคือ:

สำหรับบรรพบุรุษที่ได้รับการผลักดันทั้งหมด (ไม่รวมเคล็ดลับการพัฒนาในปัจจุบันและบรรพบุรุษ) ที่มีคำแนะนำปัจจุบันของการพัฒนาในฐานะผู้ปกครอง:

  • อย่างน้อยหนึ่งกระทำเช่นนี้มีอยู่?
  • คอมมิทแม่คนเดียวจะทำคอมมิทหรือเปล่า?

ซึ่งสามารถนำมาใช้เป็น:

pushedrev=...
basename=develop
if ! baserev="$(git rev-parse --verify refs/heads/"$basename" 2>/dev/null)"; then
    echo "'$basename' is missing, call for help!"
    exit 1
fi
parents_of_children_of_base="$(
  git rev-list --pretty=tformat:%P "$pushedrev" --not "$baserev" |
  grep -F "$baserev"
)"
case ",$parents_of_children_of_base" in
    ,)     echo "must descend from tip of '$basename'"
           exit 1 ;;
    ,*\ *) echo "must not merge tip of '$basename' (rebase instead)"
           exit 1 ;;
    ,*)    exit 0 ;;
esac

สิ่งนี้จะครอบคลุมบางสิ่งที่คุณต้องการ จำกัด แต่อาจไม่ใช่ทุกอย่าง

สำหรับการอ้างอิงต่อไปนี้เป็นตัวอย่างประวัติเพิ่มเติม:

    A                                   master
     \
      \                    o-----J
       \                  /       \
        \                | o---K---L
         \               |/
          C--------------D              develop
           \             |\
            F---G---H    | F'--G'--H'
                    |    |\
                    |    | o---o---o---N
                     \   \      \       \
                      \   \      o---o---P
                       \   \   
                        R---S

รหัสดังกล่าวสามารถนำมาใช้ในการปฏิเสธHและSในขณะที่การยอมรับH', J, KหรือNแต่มันจะยังยอมรับLและP(พวกเขาเกี่ยวข้องกับการผสาน แต่พวกเขาไม่ได้ผสานเคล็ดลับของการพัฒนา )

หากต้องการปฏิเสธLและPคุณสามารถเปลี่ยนคำถามและถามได้

สำหรับบรรพบุรุษที่ได้รับการผลักดันทั้งหมด (ไม่รวมเคล็ดลับการพัฒนาในปัจจุบันและบรรพบุรุษของมัน):

  • มีความมุ่งมั่นกับผู้ปกครองสองคนหรือไม่?
  • ถ้าไม่อย่างน้อยหนึ่งคอมมิชชันดังกล่าวมีเคล็ดลับปัจจุบันของการพัฒนาพาเรนต์ (เท่านั้น) หรือไม่?
pushedrev=...
basename=develop
if ! baserev="$(git rev-parse --verify refs/heads/"$basename" 2>/dev/null)"; then
    echo "'$basename' is missing, call for help!"
    exit 1
fi
parents_of_commits_beyond_base="$(
  git rev-list --pretty=tformat:%P "$pushedrev" --not "$baserev" |
  grep -v '^commit '
)"
case "$parents_of_commits_beyond_base" in
    *\ *)          echo "must not push merge commits (rebase instead)"
                   exit 1 ;;
    *"$baserev"*)  exit 0 ;;
    *)             echo "must descend from tip of '$basename'"
                   exit 1 ;;
esac

ฉันได้สิ่งนี้: git: ร้ายแรง: อาร์กิวเมนต์ที่คลุมเครือ '... ': ทั้งการแก้ไขและชื่อไฟล์ จุดประสงค์สามจุดคืออะไร
Jack Ukleja

1
@ ชไนเดอร์ฉันค่อนข้างมั่นใจว่า '... ' ตั้งใจจะเป็นตัวยึดตำแหน่งในตัวอย่างนี้: ถ้าคุณแทนที่ด้วย SHA ของการคอมมิชชันที่คุณกำลังพยายามทำการตรวจสอบนี้กับ (พูดหัวหน้าของสาขา คุณอยู่ใน) ทุกอย่างทำงานได้ดี
Daniel Brady

ขอบคุณสำหรับคำตอบที่ซับซ้อน! มันมีประโยชน์มาก ฉันต้องการขอคล้ายกัน แต่ฉันไม่ต้องการรหัสยากสำหรับชื่อสาขาการพัฒนา หมายความว่าฉันต้องการตะขอสำหรับป้องกัน rebase ไปยังสาขาอื่นที่ไม่ใช่สาขาหลัก ถ้าฉันเข้าใจคำตอบของคุณเป็นอย่างดี (ฉันยังใหม่ต่อการทุบตีและสิ่งของ) สิ่งนี้ไม่ได้ครอบคลุมอยู่ในคำตอบของคุณใช่ไหม มีวิธีทำเช่นนี้หรือไม่?
Kemeia

คุณยินดีที่จะตอบคำถามที่เกี่ยวข้องหรือไม่ ฉันไม่สามารถรับรหัสของคุณเพื่อทำงานในพื้นที่เก็บข้อมูลระยะไกล นี่คือลิงค์ไปยังคำถามติดตามผลเกี่ยวกับวิธีปรับวิธีการทำงานกับที่เก็บข้อมูลระยะไกล: stackoverflow.com/questions/49619492/…
CodeMed

สิ่งนี้ไม่ได้ผลสำหรับฉันเมื่อฉันมีdevelop > release > featureฉันจะได้รับการพัฒนากลับและต้องรู้พ่อแม่ วิธีแก้ไขปัญหาของฉันคือstackoverflow.com/a/56673640/2366390
verdverm

240

เสียงสะท้อน

อีกวิธีหนึ่งในการตั้งคำถามคือ "อะไรคือความมุ่งมั่นที่ใกล้เคียงที่สุดที่อยู่ในสาขาอื่นนอกเหนือจากสาขาปัจจุบัน

วิธีแก้ปัญหา

คุณสามารถค้นหาด้วยเวทมนต์บรรทัดคำสั่งเล็กน้อย

git show-branch \
| sed "s/].*//" \
| grep "\*" \
| grep -v "$(git rev-parse --abbrev-ref HEAD)" \
| head -n1 \
| sed "s/^.*\[//" 

ด้วยawk :

git show-branch -a \
| grep '\*' \
| grep -v `git rev-parse --abbrev-ref HEAD` \
| head -n1 \
| sed 's/[^\[]*//' \
| awk 'match($0, /\[[a-zA-Z0-9\/-]+\]/) { print substr( $0, RSTART+1, RLENGTH-2 )}'

นี่คือวิธีการทำงาน:

  1. แสดงประวัติข้อความของการกระทำทั้งหมดรวมถึงสาขาระยะไกล
  2. บรรพบุรุษของการกระทำในปัจจุบันจะถูกระบุโดยดาว กรองทุกอย่างอื่น
  3. ละเว้นการกระทำทั้งหมดในสาขาปัจจุบัน
  4. ผลแรกจะเป็นสาขาบรรพบุรุษที่ใกล้ที่สุด ละเว้นผลลัพธ์อื่น ๆ
  5. ชื่อสาขาจะแสดง [ในวงเล็บ] ละเว้นทุกสิ่งที่อยู่นอกวงเล็บและวงเล็บ
  6. บางครั้งชื่อสาขาจะมีเครื่องหมาย ~ # หรือ ^ # เพื่อระบุจำนวนการคอมมิตที่อยู่ระหว่างการคอมมิตที่อ้างอิงและคำแนะนำสาขา เราไม่สนใจ ไม่สนใจพวกเขา

และผลลัพธ์

ใช้รหัสข้างบน

 A---B---D <-master
      \
       \
        C---E---I <-develop
             \
              \
               F---G---H <-topic

จะให้คุณdevelopถ้าคุณเรียกใช้จาก H และmasterถ้าคุณเรียกใช้จากฉัน

รหัสนี้มีอยู่ในส่วนสำคัญ


24
ลบ backtick ต่อท้ายที่ทำให้เกิดข้อผิดพลาด เมื่อใช้คำสั่งนี้ฉันได้รับคำเตือนจำนวนมากบ่นเกี่ยวกับแต่ละสาขาว่าcannot handle more than 25 refs
Jon L.

1
@JoeChrysler คุณคิดว่าคุณสามารถทำให้มันเป็นหนึ่งบรรทัดแทนที่จะเป็น 2 และอาจทำให้มันทำงานบน Mac ได้เนื่องจากackไม่สามารถใช้งานบน Mac ได้ (บางคนแนะนำให้แทนที่ackด้วยgrep)
nonopolarity

53
ขออภัยนั่นเป็นสิ่งที่ผิด นี่คือหนึ่งที่ถูกต้องที่ทำงานสำหรับฉัน:git show-branch | grep '*' | grep -v "$(git rev-parse --abbrev-ref HEAD)" | head -n1 | sed 's/.*\[\(.*\)\].*/\1/' | sed 's/[\^~].*//'
droidbot

15
@droidbot ดี แต่ต้องมีการจัดเรียงใหม่เพื่อหลีกเลี่ยงการลบ refs เมื่อ grep -v catch กระทำข้อความหรือชื่อสาขาของคุณเป็นส่วนหนึ่งของชื่อสาขาอื่น git show-branch | sed "s/].*//" | grep "\*" | grep -v "$(git rev-parse --abbrev-ref HEAD)" | head -n1 | sed "s/^.*\[//"
gaal

3
@OlegAbrazhaev ฉันไม่รู้ว่าคุณได้รับคำตอบจากคำถามของคุณหรือไม่ ใช้นามแฝงคอมไพล์ของ: ใช้parent = "!git show-branch | grep '*' | grep -v \"$(git rev-parse --abbrev-ref HEAD)\" | head -n1 | sed 's/.*\\[\\(.*\\)\\].*/\\1/' | sed 's/[\\^~].*//' #"งานได้สำหรับฉัน
mduttondev

111

คุณสามารถลอง:

git log --graph --decorate

5
git log --graph --decorate --simplify-by-decorationที่--graphเป็นตัวเลือก
Na13-c

1
git log --graph --decorate --simplify-by-decoration --oneline
anishtain4

106

ผู้ปกครองคอมไพล์

คุณสามารถรันคำสั่งได้

git parent

เพื่อหาผู้ปกครองของสาขาถ้าคุณเพิ่ม@ Joe ไครสเลอร์คำตอบ 's เป็นนามแฝงคอมไพล์ มันจะทำให้การใช้งานง่ายขึ้น

เปิดไฟล์ gitconfig ที่อยู่"~/.gitconfig"โดยใช้โปรแกรมแก้ไขข้อความใด ๆ (สำหรับ linux) และสำหรับ Windows เส้นทาง ".gitconfig" จะอยู่ที่c:\users\your-user\.gitconfig

vim  ~/.gitconfig

เพิ่มคำสั่ง alias ต่อไปนี้ในไฟล์:

[alias]
            parent = "!git show-branch | grep '*' | grep -v \"$(git rev-parse --abbrev-ref HEAD)\" | head -n1 | sed 's/.*\\[\\(.*\\)\\].*/\\1/' | sed 's/[\\^~].*//' #"

บันทึกและออกจากโปรแกรมแก้ไข

เรียกใช้คำสั่ง git parent

แค่นั้นแหละ!


5
นี่เป็นทางออกที่ดี มันจะมีประโยชน์ในการเพิ่มเอาต์พุตตัวอย่างบางส่วนเพื่อให้มั่นใจถึงผลลัพธ์ที่คาดหวัง เมื่อฉันวิ่งฉันได้รับคำเตือนเล็กน้อยก่อนถึงบรรทัดสุดท้ายซึ่งฉันเชื่อว่าเป็นชื่อของสาขาหลัก
เทมเพลต

4
ทำงานเหมือนจับใจ! สำหรับผู้ใช้ windows. gitconfig โดยทั่วไปจะอยู่ที่ c: \ users \ your-user \ .gitconfig
zion

12
รับcannot handle more than 25 refsข้อยกเว้น
shajin

บางคนสามารถแก้ไขสิ่งนี้เพื่อจัดการกับคำเตือนได้หรือไม่ @ ตัวอย่างคุณได้ไหม
NIKHIL CM

@NIKHILCM ทำงานเหมือนแชมป์ แต่ฉันมีคำถามตรงนี้ไม่ว่าผู้ปกครองจะระบุจากที่สาขาสร้างหรืออย่างอื่น?
Hariprasath

52

ฉันมีวิธีแก้ไขปัญหาโดยรวมของคุณ (พิจารณาว่าfeatureสืบเชื้อสายมาจากส่วนปลายdevelop) แต่ไม่สามารถใช้วิธีที่คุณระบุไว้ได้

คุณสามารถใช้git branch --containsเพื่อแสดงรายการกิ่งก้านสาขาทั้งหมดที่สืบทอดมาจากส่วนปลายจากdevelopนั้นใช้grepเพื่อให้แน่ใจว่าfeatureเป็นสาขา

git branch --contains develop | grep "^ *feature$"

หากเป็นหนึ่งในนั้นก็จะพิมพ์" feature"ไปยังเอาต์พุตมาตรฐานและมีรหัสส่งคืนเป็น 0 มิฉะนั้นจะพิมพ์อะไรและมีรหัสส่งคืน 1


1
ใช้งานได้ แต่ควรสังเกตว่าอาจใช้เวลานานในที่เก็บที่มีการอ้างอิงจำนวนมาก ทำให้น้อยกว่าเหมาะอย่างยิ่งสำหรับการใช้งานเช่นตะขอรับก่อน
ebneter

ฉันกำลังมองหาสาขาเราจะเรียกมันว่า<branch>ที่ฉันแสดง: git checkout -b <branch-2>จาก ... นี่คือคำตอบ! ไม่จำเป็นต้องใช้ grep จริงๆ git branch --contains <branch>
Poopy McFartnoise

44

มันใช้งานได้ดีสำหรับฉัน

git show-branch | grep '*' | grep -v "$(git rev-parse --abbrev-ref HEAD)" | head -n1 | sed 's/.*\[\(.*\)\].*/\1/' | sed 's/[\^~].*//'

คำตอบที่สุภาพจาก: @droidbot และ @Jistanidiot


ใช่ แต่บางครั้งมันทำให้คุณ "แตกท่อ" จาก grep
Vladislav Rastrusny

1
*ไม่ใช่ regex ที่เหมาะสมในการส่งผ่านไปยัง grep ควรใช้grep -F '*'หรือgrep '\*'แทน ทางออกที่ดีเป็นอย่างอื่น
arielf

ฉันไม่ได้ผลลัพธ์
Sandip Subedi

เหมาะกับฉัน ....
roottraveller

11

เนื่องจากไม่มีคำตอบข้างต้นที่ทำงานในพื้นที่เก็บข้อมูลของเราฉันต้องการแบ่งปันวิธีของตัวเองโดยใช้การผสานล่าสุดในgit log:

#!/bin/bash
git log --oneline --merges "$@" | grep into | sed 's/.* into //g' | uniq --count | head -n 10

ใส่ไว้ในสคริปต์ชื่อgit-last-mergesซึ่งยังยอมรับชื่อสาขาเป็นอาร์กิวเมนต์ (แทนสาขาปัจจุบัน) เช่นเดียวกับgit logข้อโต้แย้งอื่น ๆ

จากผลลัพธ์เราสามารถตรวจจับสาขาแม่ (es) ด้วยตนเองตามอนุสัญญาการแยกสาขาของตัวเองและจำนวนการผสานจากแต่ละสาขา

แก้ไข: หากคุณใช้git rebaseกับสาขาย่อยบ่อย ๆ (และการผสานถูกส่งต่ออย่างรวดเร็วบ่อยครั้งดังนั้นจึงไม่รวมการคอมมิชชันมากเกินไป) คำตอบนี้ใช้งานไม่ได้ดังนั้นฉันจึงเขียนสคริปต์เพื่อนับการกระทำล่วงหน้า (ปกติและผสาน) และหลังการคอมมิชชัน (ไม่ควรมีการรวมในสาขาหลัก) ในทุกสาขาเปรียบเทียบกับสาขาปัจจุบัน เพียงเรียกใช้สคริปต์นี้และแจ้งให้เราทราบว่าเหมาะกับคุณหรือไม่

#!/bin/bash
HEAD="`git rev-parse --abbrev-ref HEAD`"
echo "Comparing to $HEAD"
printf "%12s  %12s   %10s     %s\n" "Behind" "BehindMerge" "Ahead" "Branch"
git branch | grep -v '^*' | sed 's/^\* //g' | while read branch ; do
    ahead_merge_count=`git log --oneline --merges $branch ^$HEAD | wc -l`
    if [[ $ahead_merge_count != 0 ]] ; then
        continue
    fi
    ahead_count=`git log --oneline --no-merges $branch ^$HEAD | wc -l`
    behind_count=`git log --oneline --no-merges ^$branch $HEAD | wc -l`
    behind_merge_count=`git log --oneline --merges ^$branch $HEAD | wc -l`
    behind="-$behind_count"
    behind_merge="-M$behind_merge_count"
    ahead="+$ahead_count"
    printf "%12s  %12s   %10s     %s\n" "$behind" "$behind_merge" "$ahead" "$branch"
done | sort -n

ขอบคุณ แม้ว่านี้อาจไม่สามารถทำงานได้เป็นอย่างดีถ้าคุณใช้rebaseบ่อย (และผสานกำลังfast-forwarded บ่อย) ฉันจะแก้ไขคำตอบของฉันหากฉันพบทางออกที่ดีกว่า
saeedgnu

1
เพียง? ตอบจนถึงที่ทำงานอย่างสมเหตุสมผลสำหรับฉันในกรณีที่สาขาปัจจุบันเป็นหลัก โซลูชันอื่น ๆ ส่วนใหญ่ให้ผลลัพธ์แบบสุ่ม (และไม่ถูกต้องอย่างชัดเจน) ในกรณีขอบนี้เป็นที่ยอมรับซึ่งไม่มีสาขาหลักที่แท้จริง
arielf

นี่เป็นคำตอบเดียวที่เหมาะกับฉัน ในการรับพาเรนต์แรกแทนที่จะเป็นรายการ 10 รายการแรกคุณสามารถใช้สิ่งนี้: git log --oneline --merges "$@" | grep into | sed 's/.* into //g' | uniq --count | head -n 1 | cut -d ' ' -f 8
lots0logs

10

วิธีแก้ปัญหา

การแก้ปัญหาขึ้นอยู่กับgit show-branchไม่ได้ค่อนข้างทำงานสำหรับฉัน (ดูด้านล่าง) ดังนั้นฉันได้ทำงานร่วมกันกับคนที่อยู่บนพื้นฐานgit logและจบลงด้วยนี้

git log --decorate --simplify-by-decoration --oneline \ # selects only commits with a branch or tag
      | grep -v "(HEAD" \                               # removes current head (and branch)
      | head -n1 \                                      # selects only the closest decoration
      | sed 's/.* (\(.*\)) .*/\1/' \                    # filters out everything but decorations
      | sed 's/\(.*\), .*/\1/' \                        # picks only the first decoration
      | sed 's/origin\///'                              # strips "origin/" from the decoration

ข้อ จำกัด และคำเตือน

  • HEAD สามารถถอดออกได้ (เครื่องมือ CI จำนวนมากทำเพื่อให้แน่ใจว่าพวกเขาสร้างการกระทำที่ถูกต้องในสาขาที่กำหนด) แต่ สาขาต้นกำเนิดและสาขาท้องถิ่นจะต้องมีทั้งที่ตราไว้หรือ "เหนือ"หัวปัจจุบัน
  • จะต้องไม่มีแท็ก (ฉันเข้าใจ; ฉันไม่ได้ทดสอบสคริปต์ในการคอมมิทด้วยแท็กระหว่างสาขาย่อยและสาขาหลัก)
  • สคริปต์อาศัยความจริง"หัว"นั้นถูกระบุว่าเป็นการตกแต่งครั้งแรกโดยlogคำสั่ง
  • ใช้สคริปต์ในmasterและdevelopผล (ส่วนใหญ่) ใน<SHA> Initial commit

ผลที่ได้

 A---B---D---E---F <-origin/master, master
      \      \
       \      \
        \      G---H---I <- origin/hotfix, hotfix
         \
          \
           J---K---L <-origin/develop, develop
                \
                 \
                  M---N---O <-origin/feature/a, feature/a
                       \   \
                        \   \
                         \   P---Q---R <-origin/feature/b, feature/b
                          \
                           \
                            S---T---U <-origin/feature/c, feature/c

แม้จะมีสาขาในท้องถิ่น (เช่นเท่านั้น origin/topicตั้งแต่การกระทำOได้ถูกเช็กเอาต์โดยตรงโดย SHA) แต่สคริปต์ควรพิมพ์ดังนี้:

  • สำหรับการกระทำG, H,I (สาขาhotfix) →master
  • สำหรับการกระทำM, N,O (สาขาfeature/a) →develop
  • สำหรับการกระทำS, T,U (สาขาfeature/c) →develop
  • สำหรับการกระทำP, Q,R (สาขาfeature/b) →feature/a
  • สำหรับการกระทำJ, K,L (สาขาdevelop) → <sha> Initial commit*
  • สำหรับการกระทำB, D, E,F (สาขาmaster) →<sha> Initial commit

* - หรือ masterถ้าความdevelopมุ่งมั่นอยู่ด้านบนสุดของหัวหน้า (~ อาจารย์จะสามารถส่งต่อได้อย่างรวดเร็วเพื่อพัฒนา)


ทำไมถึงไม่แสดงสาขาให้ฉัน

วิธีแก้ปัญหาที่git show-branchพิสูจน์แล้วว่าไม่น่าเชื่อถือสำหรับฉันในสถานการณ์ต่อไปนี้:

  • HEAD แฝด - รวมถึงกรณีส่วนใหญ่ที่ถอดออกหมายถึงการเปลี่ยนgrep '\*' \ 'grep'! ' \ - และนั่นเป็นเพียงจุดเริ่มต้นของปัญหาทั้งหมด
  • เรียกใช้สคริปต์บนmasterและdevelopผลในการdevelopและ `` ตามลำดับ
  • สาขาในmasterสาขา ( hotfix/สาขา) จบลงด้วยการdevelopเป็นผู้ปกครองเนื่องจากmasterผู้ปกครองสาขาที่ใกล้ที่สุดของพวกเขาถูกทำเครื่องหมายด้วย!แทน*ด้วยเหตุผล

2
เฉพาะคำตอบที่ใช้งานได้ - ในฐานะนามแฝงคอมไพล์:"!git log --decorate --simplify-by-decoration --oneline | grep -v '(HEAD' | head -n1 | sed 's/.* (\\(.*\\)) .*/\\1/' | sed 's/\\(.*\\), .*/\\1/' | sed 's/origin\\///'"
Ian Kemp

8

โปรดจำไว้ว่าตามที่อธิบายไว้ใน"Git: ค้นหาว่าสาขาใดกระทำการส่งข้อมูล"คุณไม่สามารถระบุสาขาที่กระทำการส่งได้อย่างง่ายดาย (สาขาสามารถเปลี่ยนชื่อย้ายลบลบ ... ) แม้ว่าgit branch --contains <commit>จะเป็นการเริ่มต้น

  • คุณสามารถย้อนกลับจากคอมมิทถึงคอมมิชชันจนกว่าgit branch --contains <commit>จะไม่มีลิสต์featureสาขาและลิสต์developสาขา
  • เปรียบเทียบที่กระทำ SHA1 กับ /refs/heads/develop

หากทั้งสองยอมรับการจับคู่ id คุณก็พร้อมที่จะไป (นั่นหมายความว่าfeatureสาขานั้นมีต้นกำเนิดอยู่ที่ HEAD of develop)


6

เวทมนตร์บรรทัดคำสั่งของ JoeChrysler สามารถทำให้ง่ายขึ้น นี่คือตรรกะของ Joe - เพื่อความกะทัดรัดฉันได้แนะนำพารามิเตอร์ที่มีชื่อcur_branchแทนที่การแทนที่คำสั่ง`git rev-parse --abbrev-ref HEAD`ในทั้งสองเวอร์ชัน ที่สามารถเริ่มต้นได้เช่น:

cur_branch=$(git rev-parse --abbrev-ref HEAD)

จากนั้นต่อไปนี้เป็นขั้นตอนของ Joe:

git show-branch -a           |
  grep '\*'                  | # we want only lines that contain an asterisk
  grep -v "$cur_branch"      | # but also don't contain the current branch
  head -n1                   | # and only the first such line
  sed 's/.*\[\(.*\)\].*/\1/' | # really, just the part of the line between []
  sed 's/[\^~].*//'            # and with any relative refs (^, ~n) removed

เราสามารถทำสิ่งเดียวกันให้สำเร็จได้ด้วยตัวกรองคำสั่งทั้งห้าทั้งหมดในคำสั่งที่ค่อนข้างง่ายawk:

git show-branch -a |
  awk -F'[]^~[]' '/\*/ && !/'"$cur_branch"'/ {print $2;exit}'  

ที่แบ่งลงเช่นนี้

-F'[]^~[]' 

แบ่งบรรทัดลงในช่องที่], ^, ~และ[ตัวอักษร

/\*/                      

ค้นหาบรรทัดที่มีเครื่องหมายดอกจัน

&& !/'"$cur_branch"'/

... แต่ไม่ใช่ชื่อสาขาปัจจุบัน

{ print $2;               

เมื่อคุณพบบรรทัดดังกล่าวให้พิมพ์ฟิลด์ที่สอง (นั่นคือส่วนที่เกิดขึ้นครั้งแรกและครั้งที่สองของตัวคั่นฟิลด์ของเรา) สำหรับชื่อสาขาที่เรียบง่ายนั่นจะเป็นสิ่งที่อยู่ระหว่างวงเล็บ สำหรับการอ้างอิงที่มีการข้ามแบบสัมพันธ์จะเป็นเพียงชื่อที่ไม่มีตัวแก้ไข ดังนั้นชุดตัวคั่นฟิลด์ของเราจึงจัดการกับทั้งสองsedคำสั่ง

  exit }

จากนั้นออกทันที head -n 1ซึ่งหมายความว่ามันเคยประมวลผลการจับคู่สายแรกดังนั้นเราจึงไม่จำเป็นต้องท่อส่งออกผ่าน


3
โปรดทราบว่าบางสาขาอาจหายไปจากผลลัพธ์เนื่องจากอ้างอิงมากเกินไป พวกเขาจะแสดงเป็นคำเตือนใน stderr แทน
Zitrax

5

นี่คือการใช้ PowerShell สำหรับโซลูชันของ Mark Reed:

git show-branch -a | where-object { $_.Contains('*') -eq $true} | Where-object {$_.Contains($branchName) -ne $true } | select -first 1 | % {$_ -replace('.*\[(.*)\].*','$1')} | % { $_ -replace('[\^~].*','') }

5

ฉันไม่ได้บอกว่านี่เป็นวิธีที่ดีในการแก้ปัญหานี้ แต่นี่ดูเหมือนจะเป็นประโยชน์สำหรับฉัน

git branch --contains $(cat .git/ORIG_HEAD) ปัญหาที่เกิดขึ้นคือการเปิดไฟล์กำลังมองเข้าไปในการทำงานภายในของคอมไพล์ดังนั้นจึงไม่จำเป็นต้องรองรับการส่งต่อ (หรือเข้ากันได้ย้อนหลัง)


3

การติดตั้งข้ามแพลตฟอร์มกับ Ant

    <exec executable="git" outputproperty="currentBranch">
        <arg value="rev-parse" />  
        <arg value="--abbrev-ref" />  
        <arg value="HEAD" />  
    </exec>

    <exec executable="git" outputproperty="showBranchOutput">
        <arg value="show-branch" />  
        <arg value="-a" />  
    </exec>

    <loadresource property="baseBranch">
      <propertyresource name="showBranchOutput"/>
          <filterchain>
            <linecontains>
              <contains value="*"/>
            </linecontains>
            <linecontains negate="true">
              <contains value="${currentBranch}"/>
            </linecontains>
            <headfilter lines="1"/>
            <tokenfilter>
                <replaceregex pattern=".*\[(.*)\].*" replace="\1"/>
                <replaceregex pattern="[\^~].*" replace=""/>
            </tokenfilter>
          </filterchain>
    </loadresource>

    <echo message="${currentBranch} ${baseBranch}" />

2

@ Mark Reed: คุณควรเพิ่มว่าบรรทัด commit ไม่ควรมีเพียงเครื่องหมายดอกจัน แต่เริ่มด้วยเครื่องหมายดอกจัน! มิฉะนั้นส่งข้อความที่มีเครื่องหมายดอกจันรวมอยู่ในบรรทัดที่ตรงกัน ดังนั้นควรเป็น:

git show-branch -a | awk -F'[]^~[]' '/^\*/ && !/'"$current_branch"'/ {print $2;exit}'

หรือรุ่นยาว:

git show-branch -a           |
  awk '^\*'                  | # we want only lines that contain an asterisk
  awk -v "$current_branch"   | # but also don't contain the current branch
  head -n1                   | # and only the first such line
  sed 's/.*\[\(.*\)\].*/\1/' | # really, just the part of the line between []
  sed 's/[\^~].*//'            # and with any relative refs (^, ~n) removed`

2
vbc=$(git rev-parse --abbrev-ref HEAD)
vbc_col=$(( $(git show-branch | grep '^[^\[]*\*' | head -1 | cut -d* -f1 | wc -c) - 1 )) 
swimming_lane_start_row=$(( $(git show-branch | grep -n "^[\-]*$" | cut -d: -f1) + 1 )) 
git show-branch | tail -n +$swimming_lane_start_row | grep -v "^[^\[]*\[$vbc" | grep "^.\{$vbc_col\}[^ ]" | head -n1 | sed 's/.*\[\(.*\)\].*/\1/' | sed 's/[\^~].*//'

บรรลุจุดสิ้นสุดเช่นเดียวกับคำตอบของ Mark Reed แต่ใช้วิธีการที่ปลอดภัยกว่ามากซึ่งไม่ได้ทำงานผิดปกติในหลาย ๆ สถานการณ์:

  1. การคอมมิชชันสุดท้ายของสาขาพาเรนต์เป็นการผสานทำให้คอลัมน์- ไม่แสดง*
  2. ข้อความคอมมิทประกอบด้วยชื่อสาขา
  3. ข้อความคอมมิทประกอบด้วย *

0

ทุกคนที่ต้องการทำวันนี้ - แอปพลิเคชั่น SourceTree ของ Atlassian แสดงให้คุณเห็นภาพที่ชัดเจนว่าสาขาของคุณเกี่ยวข้องกันอย่างไรเช่นที่ที่พวกเขาเริ่มต้นและที่พวกเขานั่งอยู่ในลำดับการกระทำ (เช่นหัวหน้าหรือ 4 หลัง) .


0

หากคุณใช้ต้นทรีมาดูรายละเอียดการส่งของคุณ> ผู้ปกครอง> จากนั้นคุณจะเห็นจำนวนการขีดเส้นใต้ (ลิงก์)


0

ทางเลือก: git rev-list master | grep "$(git rev-list HEAD)" | head -1

รับค่าคอมมิชชันล่าสุดที่เป็นทั้งสาขาของฉันและmaster(หรือสาขาใดก็ตามที่คุณต้องการระบุ)


0

สิ่งนี้ไม่ได้ผลสำหรับฉันเมื่อฉันทำบางอย่างเช่นdevelop > release-v1.0.0 > feature-fooมันจะกลับไปสู่การพัฒนาทราบว่ามีการรีบูตเกี่ยวข้องไม่แน่ใจว่านั่นคือการรวมปัญหาของฉัน ...

ต่อไปนี้ให้แฮชคอมมิทที่ถูกต้องสำหรับฉัน

git log --decorate \
  | grep 'commit' \
  | grep 'origin/' \
  | head -n 2 \
  | tail -n 1 \
  | awk '{ print $2 }' \
  | tr -d "\n"
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.