แสดงรายการสาขาในพื้นที่ทั้งหมดโดยไม่ต้องใช้รีโมท


92

ปัญหา: ฉันต้องการวิธีลบสาขาภายในทั้งหมดที่ฉันมีที่ไม่มีรีโมต ง่ายพอที่จะใส่ชื่อสาขาลงใน a git branch -D {branch_name}แต่ฉันจะรับรายชื่อนั้นได้อย่างไรในตอนแรก

ตัวอย่างเช่น:

ฉันสร้างสาขาใหม่โดยไม่มีรีโมท:

$ git co -b no_upstream

ฉันแสดงรายชื่อสาขาทั้งหมดของฉันและมีเพียงสาขาเดียวที่มีรีโมท

$ git branch -a
master
* no_upstream
remotes/origin/HEAD -> origin/master
remotes/origin/master

ฉันสามารถรันคำสั่งอะไรได้no_upstreamเป็นคำตอบ

ฉันวิ่งได้git rev-parse --abbrev-ref --symbolic-full-name @{u}และนั่นจะแสดงว่ามันไม่มีรีโมท:

$ git rev-parse --abbrev-ref --symbolic-full-name @{u}
error: No upstream configured for branch 'no_upstream'
error: No upstream configured for branch 'no_upstream'
fatal: ambiguous argument '@{u}': unknown revision or path not in the working tree.
Use '--' to separate paths from revisions, like this:
'git <command> [<revision>...] -- [<file>...]'

แต่เนื่องจากนี่เป็นข้อผิดพลาดจึงไม่อนุญาตให้ฉันใช้หรือไปป์ไปยังคำสั่งอื่น ฉันตั้งใจจะใช้สิ่งนี้เป็นนามแฝงของเชลล์สคริปต์git-delete-unbranchedหรืออาจจะสร้างอัญมณีที่เรียบง่ายสุด ๆ เช่นgit-branch-delete-orphans



คำตอบ:


105

ฉันเพิ่งค้นพบgit branch -vvซึ่งเป็นgit branchคำสั่งเวอร์ชัน "ละเอียดมาก"

จะส่งออกกิ่งก้านพร้อมกับสาขาระยะไกลหากมีอยู่ในรูปแบบต่อไปนี้:

  25-timeout-error-with-many-targets    206a5fa WIP: batch insert
  31-target-suggestions                 f5bdce6 [origin/31-target-suggestions] Create target suggestion for team and list on save
* 54-feedback-link                      b98e97c [origin/54-feedback-link] WIP: Feedback link in mail
  65-digest-double-publish              2de4150 WIP: publishing-state

เมื่อคุณมีผลลัพธ์ที่ได้รับการจัดรูปแบบไว้อย่างสวยงามแล้วมันก็ง่ายเหมือนกับการส่งผ่านcutและawkรับรายการของคุณ:

git branch -vv | cut -c 3- | awk '$3 !~/\[/ { print $1 }'

ผลลัพธ์ในผลลัพธ์ต่อไปนี้:

25-timeout-error-with-many-targets
65-digest-double-publish

cutส่วนเพียง normalizes ข้อมูลโดยการเอาตัวละครสองตัวแรก (รวม*) awkจากการส่งออกก่อนที่จะผ่านไปยัง

awkส่วนพิมพ์คอลัมน์แรกถ้าไม่มีวงเล็บตารางในคอลัมน์ที่สาม

โบนัส: สร้างนามแฝง

ทำให้ง่ายต่อการเรียกใช้โดยสร้างนามแฝงใน.gitconfigไฟล์ส่วนกลางของคุณ(หรือทุกที่):

[alias]
  local-branches = !git branch -vv | cut -c 3- | awk '$3 !~/\\[/ { print $1 }'

สำคัญ: ต้องใช้แบ็กสแลชในนามแฝงมิฉะนั้นคุณจะมีไฟล์ gitconfig ที่ไม่ถูกต้อง

โบนัส: การกรองระยะไกล

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

git branch -vv | cut -c 3- | awk '$3 !~/\[origin/ { print $1 }'

อะไรที่WIP:อยู่แล้ว .. ? นั่นไม่ใช่สิ่งที่คำสั่งซ่อนสร้าง .. ?
igrek

@igrek นั่นเป็นเพียงคำนำหน้าที่ฉันใช้ในข้อความกระทำ ไม่มีอะไรเฉพาะสำหรับคอมไพล์
Jeremy Baker

เมื่อฉันทำgit branch -vvแม้ว่าสาขาที่อยู่ห่างไกลจะมีอยู่และตรงกับสาขาในพื้นที่ของฉันฉันก็จะไม่เห็น[origin/branch-name]ผลลัพธ์ข้างๆ ฉันต้องมีdiffรายชื่อสาขาสองรายการเพื่อที่จะทราบว่าอะไรเป็นของท้องถิ่นเท่านั้น
ryantuck

git branch -vv | grep -v origin/ก็เพียงพอแล้วสำหรับฉัน
อย่าตกใจ

2
นี่ไม่พลาดสาขาระยะไกลที่ทำเครื่องหมายไว้goneใช่หรือไม่?
Reid

36

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

โดยปกติแล้วสาขาท้องถิ่นเหล่านั้นควรถูกลบเมื่อรวมเข้าด้วยกันmaster(ดังที่เห็นในปัญหา git-Sweep นี้ ):

git branch --merged master | grep -v master | xargs git branch -d

สิ่งนี้ยังไม่สมบูรณ์เท่าที่คุณต้องการ แต่เป็นการเริ่มต้น

ด้วย--mergedเฉพาะสาขาที่รวมเข้ากับการคอมมิตที่มีชื่อ (เช่นสาขาที่ปลายคอมมิทสามารถเข้าถึงได้จากคอมมิตที่ระบุชื่อ) จะถูกแสดงรายการ


1
git branch -a --mergedยังรวมถึงสาขาระยะไกลโดยไม่ต้องมีสาขาในประเทศใช้
Acumenus

21

ฉันมีปัญหาที่คล้ายกัน ฉันต้องการลบสาขาในพื้นที่ทั้งหมดที่ติดตามสาขาระยะไกลที่ถูกลบไปแล้ว ฉันพบว่าgit remote prune originไม่เพียงพอที่จะเอากิ่งไม้ที่ฉันต้องการออกไป พอลบรีโมทแล้วฉันก็อยากให้โลคัลหายไปด้วย นี่คือสิ่งที่ใช้ได้ผลสำหรับฉัน:

จากของฉัน~/.gitconfig:

[alias]
  prune-branches = !git remote prune origin && git branch -vv | grep ': gone]' | awk '{print $1}' | xargs -r git branch -d

นี่คือgit config --global ...คำสั่งสำหรับเพิ่มสิ่งนี้ได้อย่างง่ายดายgit prune-branches:

git config --global alias.prune-branches '!git remote prune origin && git branch -vv | grep '"'"': gone]'"'"' | awk '"'"'{print $1}'"'"' | xargs -r git branch -d'

หมายเหตุ : ผมเปลี่ยน-dไป-Dในการกำหนดค่าที่แท้จริงของฉันเพราะฉันไม่ต้องการที่จะได้ยิน Git บ่นเกี่ยวกับการผสานรวมสาขา คุณอาจต้องการฟังก์ชันนี้เช่นกัน ในกรณีนี้ให้ใช้-Dแทน-dท้ายคำสั่งนั้น

นอกจากนี้ FWIW ไฟล์การกำหนดค่าส่วนกลางของคุณมักจะเป็น~/.gitconfigไฟล์.

(แก้ไข OS X)

ตามที่เขียนไว้สิ่งนี้ใช้ไม่ได้กับ OS X เนื่องจากการใช้งานxargs -r(ขอบคุณKorny )

-rคือการป้องกันxargsจากการทำงานgit branch -dโดยไม่มีชื่อสาขาซึ่งจะส่งผลให้เกิดข้อผิดพลาด " fatal: branch name required" หากคุณไม่ทราบข้อความแสดงข้อผิดพลาดคุณสามารถลบ-rอาร์กิวเมนต์xargsและคุณพร้อมแล้ว

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

นี่คือgit configบรรทัดกับifne:

git config --global alias.prune-branches '!git remote prune origin && git branch -vv | grep '"'"': gone]'"'"' | awk '"'"'{print $1}'"'"' | ifne xargs git branch -d'

1
เป็นไปได้ไหมที่จะแปลงสิ่งนี้เป็นคำสั่ง "git config --global ... " จากคำสั่ง / วิธีที่จะวิกิพีเดียสำหรับหุ่นมุมมองมันเป็นเรื่องง่ายที่จะผ่านในแทนที่จะพูดว่า "หาไฟล์คอมไพล์ปรับแต่งของคุณใช้โปรแกรมแก้ไขเพื่อแก้ไขคำสั่งเรียกใช้แล้ว"
คาน Ekanath

โปรดทราบว่าxargs -r ไม่ทำงานบน OSX
Korny

ดีแล้วที่รู้. ฉันไม่รู้ว่าตัวเลือก "no run if empty" จะเป็นอย่างไรสำหรับ OSX
Karl Wilbur

18

แก้ไขล่าช้า:

ดีกว่าคือ

git for-each-ref  --format='%(refname:short) %(upstream)'  refs/heads \
| awk '$2 !~/^refs\/remotes/'

บน GNU / อะไรก็ได้

for b in `git branch|sed s,..,,`; do
    git config --get branch.$b.remote|sed Q1 && echo git branch -D $b
done

หากมีมากกว่ากำมือของสาขามีแนวโน้มที่มีต้องการจะวิธีที่ดีกว่าการใช้comm -23ในการส่งออกของและgit branch|sed|sortgit config -l|sed|sort


1
@nmr s / git. * Q1 / test $ (git config - get branch. $ b.remote | sed q | wc -1) = 1 /
jthill

15

สิ่งนี้ใช้ได้กับฉัน:

git branch -vv | grep -v origin

(หากรีโมตของคุณตั้งชื่อสิ่งอื่นที่ไม่ใช่จุดกำเนิดให้แทนที่สิ่งนั้น)

นี่จะแสดงรายการสาขาทั้งหมดที่ไม่ได้ติดตามรีโมตซึ่งดูเหมือนสิ่งที่คุณกำลังมองหา


2
รายการนี้จะสาขาที่จะต้องใช้ระยะไกล git fetch --pruneแต่ไม่ได้อีกต่อไปแม้ว่าคุณจะทำงาน
RusinaRange

2
IMO ควรมองหา ": gone]" แทนที่จะกรอง "ต้นทาง" ออกไป
fiorentinoing

4

ฉันสังเคราะห์คำสั่ง Git ของตัวเองเพื่อรับorigin/***: goneกิ่งก้าน:

git remote prune origin && git branch -vv | cut -c 3- | grep ': gone]' | awk '{print $1}' | xargs -n1 -r echo git branch -d

git remote prune origin && git branch -vv จะพิมพ์สาขาในโหมด verbose

cut -c 3- จะลบอักขระตัวแรกออก

grep ': gone]'จะพิมพ์เฉพาะสาขาระยะไกลที่หายไป

awk '{print $1}' จะพิมพ์ชื่อสาขา

xargs -n1 -r echo git branch -dจะพิมพ์git branch -dคำสั่งเพื่อลบกิ่งไม้ (-n1 จะจัดการหนึ่งคำสั่งต่อครั้ง -r เพื่อหลีกเลี่ยงการออกคำสั่งหากไม่มีสาขาอยู่)

คำแนะนำ:ลบคำสั่ง "echo" เพื่อเรียกใช้คำสั่งแทนการพิมพ์อย่างเดียวฉันทิ้งสิ่งนี้ไว้ในคำสั่งเพื่อตรวจสอบคำสั่งก่อนออกเป็นคอมไพล์

คำแนะนำ 2:ปัญหาในgit branch -Dกรณีที่คุณแน่ใจว่าต้องการลบสาขาที่ไม่ได้ผสานเท่านั้น


จากนี้ฉันทำคอมไพล์
fiorentinoing

1
นี่คือไกลโดยทางออกที่สะอาดที่ฉันได้พบดี! ฉันไม่เคยใช้เวลาศึกษามาawkก่อนฉันไม่รู้ว่าคุณทำได้
adamjc

2

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

$verboseList = @(git branch -vv)
foreach ($line in $verboseList)
{
    # Get the branch name
    $branch = [regex]::Match($line, "\s(\S+)\s").Captures.Groups[1].Value
    # Check if the line contains text to indicate if the remote is deleted
    $remoteGone = $line.Contains(": gone]")
    # Check if the line does not contain text to indicate it is a tracking branch (i.e., it's local)
    $isLocal = !($line.Contains("[origin/"))
    if ($remoteGone -or $isLocal)
    {
        # Print the branch name
        $branch
    }
}

0

การรวมคำตอบบางส่วนที่มีอยู่:

[alias]
        branch-local = !git branch -vv | cut -c 3- | egrep '([0-9a-f]{7} [^[])|(: gone\\])' | sed -E 's/(^.+[0-9a-f]{7} (\\[.+\\])?).*$/\\1/'

เช่น:

$ git branch-local
autogen_autoreconf      fcfb1c6 [github/autogen_autoreconf: gone]
autotools_documentation 72dc477 [github/autotools_documentation: gone]
cray-mpich-messy        2196f4b
epel-sphinx             cfda770
lammps                  07d96a7 [github/lammps: gone]
lark-error              9ab5d6c [github/lark-error: gone]
no-root2                c3894d1
openmpi-cray            69326cf [github/openmpi-cray: gone]
shellcheck-cleanup      40d90ec
travis-python36         cde072e
update_vagrant_default  4f69f47 [github/update_vagrant_default: gone]
web-docs                e73b4a8

0

คำตอบที่มีอยู่ดูเหมือนจะไม่เหมาะกับฉัน

นี่คือวิธีแก้ปัญหาของฉันในการแสดงรายการสาขาในพื้นที่ที่ไม่ได้อยู่ห่างไกล

comm -13 <(git branch -r | sed 's/origin\/\(.*\)/\1/g' | cut -c 3-) <(git branch | cut -c 3-)

และนี่คือคำอธิบายวิธีการทำงาน:

  1. พิจารณารายชื่อสาขาระยะไกลทั้งหมด (ไม่มี "ต้นทาง /" หรือช่องว่างนำหน้า) git branch -r | sed 's/origin\/\(.*\)/\1/g' | cut -c 3-

  2. พิจารณารายชื่อสาขาในพื้นที่ทั้งหมด (ไม่มีเครื่องหมายดอกจันหรือช่องว่างนำหน้า) git branch | cut -c 3-

  3. เปรียบเทียบสองรายการนี้และแสดงอะไรในรายการ 2 (สาขาในพื้นที่ของฉัน) ที่ไม่อยู่ในรายการ 1 (รายชื่อสาขาระยะไกล) comm -13 <(git branch -r | sed 's/origin\/\(.*\)/\1/g' | cut -c 3-) <(git branch | cut -c 3-)

comm สามารถใช้การรวมกันของแฟล็ก -1, -2 และ -3 เพื่อระบุว่าไฟล์ใดที่จะระงับบรรทัดจาก (ไม่ซ้ำกับไฟล์ 1 ไม่ซ้ำกับไฟล์ 2 หรือร่วมกันทั้งสอง)

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