มีวิธีการรับไดเรกทอรีราก git ในคำสั่งเดียว?


669

Mercurial มีวิธีการพิมพ์ไดเรกทอรีรูท (ที่มี. hg) ผ่านทาง

hg root

มีบางสิ่งที่เทียบเท่าใน git เพื่อรับไดเรกทอรีที่มีไดเรกทอรี. git หรือไม่


สคริปต์ที่ดี Emil ฉันทำให้สคริปต์พร้อมใช้งานออนไลน์และอนุญาตให้เพิ่มความเป็นไปได้ในการเพิ่มไฟล์ / ไดเรกทอรีเป็นอาร์กิวเมนต์ github.com/Dieterbe/git-scripts/commit/…
Dieter_be

นอกจากนี้สำหรับทุกคนที่อยากรู้อยากเห็นหรือการค้นหาbzr rootถูกนำมาใช้อย่างมากใน Bazaar
Kristopher Ives

โปรดรับทราบของ'GCD: Git-Aware 'cd' เทียบกับพื้นที่เก็บข้อมูลที่มีรากอัตโนมัติเสร็จที่jeetworks.org/node/52
Micha Wiedenmann


1
@MichaWiedenmann: ลิงก์นั้นตาย
d33tah

คำตอบ:


1111

ใช่:

git rev-parse --show-toplevel

หากคุณต้องการทำซ้ำคำสั่ง Git โดยตรงคุณสามารถสร้างนามแฝงได้ :

git config --global alias.root 'rev-parse --show-toplevel'

และตอนนี้จะทำงานเช่นเดียวกับที่git roothg root


หมายเหตุ : ใน submodule สิ่งนี้จะแสดงไดเร็กทอรีรูทของsubmoduleและไม่ใช่ที่เก็บพาเรนต์ หากคุณใช้ Git> = 2.13 ขึ้นไปมีวิธีที่submodules สามารถแสดงไดเรกทอรีรากของ superproject หากคอมไพล์ของคุณเก่ากว่านี้ให้ดูคำตอบอื่น ๆ


148
ฉันมักจะกำหนดดังนั้นฉันสามารถทำสิ่งที่ชอบgit config --global alias.exec '!exec ' git exec makeใช้งานได้เนื่องจากเชลล์นามแฝงนั้นจะถูกเรียกใช้งานในไดเรกทอรีระดับบนสุดเสมอ
Daniel Brockman

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

14
Smal caveat ด้วยโซลูชันนี้ - มันจะติดตามลิงก์สัญลักษณ์ใด ๆ ดังนั้นถ้าคุณอยู่ใน~/my.proj/foo/barและ~/my.projเป็น symlinked ไปที่คำสั่งดังกล่าวจะย้ายคุณไป~/src/my.proj ~/src/my.projอาจเป็นปัญหาหากสิ่งที่คุณต้องการทำหลังจากนั้นไม่ใช่ผู้ไม่เชื่อเรื่องพระเจ้า
Franci Penov

3
ฉันจะใช้สิ่งนี้จากภายในตะขอคอมไพล์ได้อย่างไร โดยเฉพาะฉันทำเบ็ดการโพสต์ผสานและฉันต้องได้รับไดเรกทอรีรากที่แท้จริงของ repo git ท้องถิ่น
ดีเร็ก

12
วิธีแก้ปัญหานี้ (และอื่น ๆ อีกมากมายในหน้านี้ที่ฉันได้ลอง) ไม่ทำงานภายในตะขอคอมไพล์ เพื่อให้แม่นยำยิ่งขึ้นมันไม่ทำงานเมื่อคุณอยู่ใน.gitไดเรกทอรีของโครงการ
เดนนิส

97

manหน้าgit-config(ภายใต้นามแฝง ) พูดว่า:

หากส่วนขยาย alias ถูกเติมหน้าด้วยเครื่องหมายอัศเจรีย์จะถูกใช้เป็นคำสั่งเชลล์ [... ] โปรดทราบว่าคำสั่งเชลล์จะถูกดำเนินการจากไดเรกทอรีระดับบนสุดของที่เก็บซึ่งอาจไม่จำเป็นต้องเป็นไดเรกทอรีปัจจุบัน

ดังนั้นใน UNIX คุณสามารถทำได้:

git config --global --add alias.root '!pwd'

2
ดังนั้นถ้าคุณมีคำสั่ง "git root" คุณจะใส่คำสั่งนั้นในนามแฝงได้อย่างไร? ถ้าฉันใส่ไว้ในของฉัน.zshrcและฉันกำหนด `alias cg =" cd $ (git root) "ส่วน $ () จะได้รับการประเมิน ณ แหล่งเวลาและชี้ไปที่ ~ / dotfiles เสมอเพราะเป็นที่ที่ zshrc ของฉันอยู่ .
zelk

2
@cormacrelf คุณไม่ได้ใส่ไว้ในชื่อแทนเชลล์ คุณสามารถวางไว้ในฟังก์ชั่นเชลล์หรือสคริปต์
Conrad Meyer

4
@cormacrelf ใส่ไว้ในเครื่องหมายคำพูดเดี่ยวแทนที่จะเป็นเครื่องหมายคำพูดคู่แล้วจะไม่ขยายในเวลาที่กำหนด แต่ที่รันไทม์
clacke

3
@ Mechanicalsnail จริงเหรอ? ดังนั้นสิ่งที่คุณคาดหวังให้ทำนอก repo
Alois Mahdal

1
@AloisMahdal จริง ๆ แล้วสำหรับฉันมันไม่ได้ล้มเหลวนอก repo เพียงรายงาน cwd
justinpitts

90

ได้--show-toplevelเพียงไม่นานมารับการเพิ่มgit rev-parseหรือทำไมไม่มีใครเอ่ยถึงมันได้หรือไม่

จากgit rev-parseหน้าคน:

   --show-toplevel
       Show the absolute path of the top-level directory.

1
ขอบคุณที่ชี้นำสิ่งนี้; หากไม่มีความช่วยเหลือของคุณมันคงเป็นเรื่องยากสำหรับฉันที่จะคาดเดาgit-rev-parseเพราะชื่อของมันบอกว่ามันเกี่ยวกับการประมวลผลข้อกำหนดการแก้ไข BTW ฉันยินดีที่จะเห็นgit --work-treeงานที่คล้ายกับgit --exec-path[=<path>]: "หากไม่มีเส้นทางที่ได้รับ git จะพิมพ์การตั้งค่าปัจจุบัน"; อย่างน้อย IMO ก็เป็นสถานที่ที่เหมาะสมสำหรับการค้นหาคุณลักษณะดังกล่าว
imz - Ivan Zakharyaschev

4
โดยเฉพาะคุณสามารถใช้นามแฝงroot = rev-parse --show-toplevelใน gitconfig ของคุณ
หอยทากเชิงกล

2
กล่าวอีกนัยหนึ่งคุณสามารถทำgit config --global alias.root "rev-parse --show-toplevel"และจากนั้นgit rootจะสามารถทำงาน
nonopolarity

@ RyanTheLeach git rev-parse --show-toplevelทำงานเมื่อฉันพยายามใน submodule มันพิมพ์ dir รากของ submodule คอมไพล์ มันพิมพ์อะไรให้คุณ
wisbucky

2
ฉันสับสนว่าทำไมคำตอบนี้ซ้ำคำตอบด้านบน ปรากฎว่าคำตอบที่ถูกแก้ไขจาก--show-cdupถึง--show-top-levelในกุมภาพันธ์ 2011 (หลังจากส่งคำตอบนี้)
wisbucky

54

แล้ว " git rev-parse --git-dir" ล่ะ

F:\prog\git\test\copyMerge\dirWithConflicts>git rev-parse --git-dir
F:/prog/git/test/copyMerge/.git

--git-dirตัวเลือกที่ดูเหมือนว่าจะทำงาน

จากหน้าคู่มือ git rev-parse :

--git-dir

    Show $GIT_DIR if defined else show the path to the .git directory.

คุณสามารถดูได้ในสคริปต์นี้git setup-shนี้

หากคุณอยู่ในโฟลเดอร์ submodule ด้วย Git> = 2.13ให้ใช้ :

git rev-parse --show-superproject-working-tree

หากคุณกำลังใช้git rev-parse --show-toplevel, ให้แน่ใจว่ามันอยู่กับ Git 2.25+ (ไตรมาสที่ 1 ปี 2020)


3
โอ้เดี๋ยวก่อนนี่อยู่ใกล้ แต่มันได้รับจริง. git dir ไม่ใช่ฐานของ repo คอมไพล์ นอกจากนี้ไดเรกทอรี. git อาจอยู่ที่อื่นดังนั้นนี่ไม่ใช่สิ่งที่ฉันต้องการ
wojo

2
ใช่ฉันเห็นแล้วว่าคุณกำลังมองหาอะไรอยู่ --show-cdup เหมาะสมกว่านั้น ฉันทิ้งคำตอบไว้เพื่อแสดงความแตกต่างระหว่างสองตัวเลือก
VonC

2
นอกจากนี้ยังปรากฏว่าคำสั่งนี้ให้เส้นทางสัมพัทธ์.gitหากคุณอยู่ในไดเรกทอรีรากแล้ว (อย่างน้อยก็ทำใน msysgit)
Blair Holloway

2
+1 นี่เป็นคำตอบเดียวที่ตอบคำถามเดิม "รับไดเรกทอรีที่มีไดเรกทอรี. git หรือไม่" น่าขบขันที่เห็นว่า OP เองพูดถึง "ไดเรกทอรี. git อาจเป็นที่อื่น"
FabienAndre

1
นี่เป็นทางออกเดียวที่ทำงานบน windows และให้ผลการแยกวิเคราะห์เมื่อใช้ submodules git (เช่น c: \ repositories \ myrepo \ .git \ modules \ mysubmodule) ทำให้เป็นโซลูชันที่มีประสิทธิภาพที่สุดโดยเฉพาะในสคริปต์ที่ใช้ซ้ำได้
chriskelly

36

เขียนคำตอบง่ายๆที่นี่เพื่อเราจะได้ใช้

git root

ในการทำงานเพียงกำหนดค่า git ของคุณโดยใช้

git config --global alias.root "rev-parse --show-toplevel"

และจากนั้นคุณอาจต้องการเพิ่มสิ่งต่อไปนี้ใน~/.bashrc:

alias cdroot='cd $(git root)'

เพื่อให้คุณสามารถใช้cdrootเพื่อไปด้านบนสุดของ repo ของคุณ


ดีมาก! สะดวกที่สุด!
scravy

คำตอบที่ดีขอบคุณ!
AVarf

26

หากคุณอยู่ในระดับบนสุดแล้วหรือไม่อยู่ในพื้นที่เก็บข้อมูล git cd $(git rev-parse --show-cdup)คุณจะได้กลับบ้าน (แค่ cd) cd ./$(git rev-parse --show-cdup)เป็นวิธีหนึ่งในการแก้ไขที่


7
cd "$(git rev-parse --show-cdup)"อีกตัวเลือกหนึ่งคือการพูดมัน งานนี้เพราะจะนำคุณไม่มีที่ไหนเลยแทนที่จะกลับcd "" $HOMEและเป็นแนวปฏิบัติที่ดีที่สุดในการเสนอราคาการร้องขอ $ () ต่อไปในกรณีที่พวกเขาแสดงผลลัพธ์ด้วยช่องว่าง (ไม่ใช่ว่าคำสั่งนี้จะเกิดขึ้นในกรณีนี้)
ctrueden

คำตอบนี้ทำงานได้ดีแม้ว่าคุณเปลี่ยนไดเรกทอรีที่คุณคอมไพล์ซื้อคืนผ่าน symlink บางส่วนของตัวอย่างอื่น ๆ จะไม่ได้ทำงานตามที่คาดไว้เมื่อ repo คอมไพล์ของคุณอยู่ภายใต้การ symlink $PWDขณะที่พวกเขาไม่สามารถแก้ไดเรกทอรีรากคอมไพล์ของเทียบกับทุบตี ตัวอย่างนี้จะแก้ปัญหารากคอมไพล์ญาติไปแทน$PWD realpath $PWD
ดาเมียนÓ Ceallaigh

16

ในการคำนวณพา ธ สัมบูรณ์ของไดเรกทอรีราก git ปัจจุบันพูดเพื่อใช้ในเชลล์สคริปต์ใช้ชุดของ readlink และ git rev-parse นี้:

gitroot=$(readlink -f ./$(git rev-parse --show-cdup))

git-rev-parse --show-cdupให้จำนวนที่ถูกต้องของ ".. " เพื่อไปยังรูทจาก cwd ของคุณหรือสตริงว่างถ้าคุณอยู่ที่รูท จากนั้นเติม "./" เพื่อจัดการกับสตริงตัวพิมพ์ว่างและใช้ readlink -fเพื่อแปลเป็นพา ธ แบบเต็ม

คุณสามารถสร้างgit-rootคำสั่งใน PATH ของคุณเป็นเชลล์สคริปต์เพื่อใช้เทคนิคนี้:

cat > ~/bin/git-root << EOF
#!/bin/sh -e
cdup=$(git rev-parse --show-cdup)
exec readlink -f ./$cdup
EOF
chmod 755 ~/bin/git-root

(ด้านบนสามารถวางลงในเทอร์มินัลเพื่อสร้าง git-root และตั้งค่าบิตรันสคริปต์จริงอยู่ในบรรทัดที่ 2, 3 และ 4)

และจากนั้นคุณจะสามารถเรียกใช้git rootเพื่อรับรูทของทรีปัจจุบันของคุณ โปรดทราบว่าในเชลล์สคริปต์ให้ใช้ "-e" เพื่อทำให้เชลล์ออกหากการแยกวิเคราะห์ซ้ำล้มเหลวเพื่อให้คุณสามารถรับสถานะการออกและข้อความแสดงข้อผิดพลาดได้อย่างถูกต้องหากคุณไม่ได้อยู่ในไดเรกทอรี git


2
ตัวอย่างของคุณจะผิดพลาดหากเส้นทางไดเรกทอรี git "root" มีช่องว่าง มักจะใช้แทนการแฮ็กชอบ"$(git rev-parse ...)" ./$(git rev-parse ...)
Mikko Rantalainen

readlink -fไม่ทำงานเหมือนกันใน BSD ดูSO นี้เพื่อแก้ไขปัญหา python -c 'import os, sys; print(os.path.realpath(sys.argv[1]))' "$(git rev-parse --show-cdup)"คำตอบหลามอาจจะทำงานได้โดยไม่ต้องติดตั้งอะไร:
Bluu

16

git rev-parse --show-cdupเป็นคนอื่นได้ตั้งข้อสังเกตหลักของการแก้ปัญหาคือการใช้งาน อย่างไรก็ตามมีที่อยู่บางกรณีที่จะอยู่:

  1. เมื่อ cwd เป็นรากของแผนผังการทำงานแล้วคำสั่งจะให้สตริงว่าง
    ที่จริงแล้วมันสร้างบรรทัดว่าง แต่การทดแทนคำสั่งถอดแถบตัวแบ่งบรรทัดต่อท้าย ผลลัพธ์สุดท้ายคือสตริงว่าง

    คำตอบส่วนใหญ่แนะนำให้ prepending ส่งออกที่มี./เพื่อให้การส่งออกที่ว่างเปล่ากลายเป็นก่อนที่จะเลี้ยง"./"cd

  2. เมื่อ GIT_WORK_TREE ถูกตั้งค่าเป็นตำแหน่งที่ไม่ใช่พาเรนต์ของ cwd เอาต์พุตอาจเป็นชื่อพา ธ สัมบูรณ์

    การเตรียม./เป็นสิ่งที่ผิดในสถานการณ์นี้ ถ้า a ./ถูกผนวกเข้ากับพา ธ สัมบูรณ์มันจะกลายเป็นพา ธ สัมพัทธ์ (และจะอ้างถึงตำแหน่งเดียวกันหาก cwd เป็นไดเรกทอรีรูทของระบบ)

  3. ผลลัพธ์อาจมีช่องว่าง

    กรณีนี้ใช้เฉพาะในกรณีที่สอง แต่มีการแก้ไขที่ง่าย: ใช้เครื่องหมายคำพูดคู่รอบการทดแทนคำสั่ง (และการใช้ค่าในภายหลัง)

ดังที่คำตอบอื่น ๆ ได้บันทึกไว้เราสามารถทำได้cd "./$(git rev-parse --show-cdup)"แต่การแบ่งในกรณีขอบที่สอง (และกรณีขอบที่สามหากเราไม่ใส่เครื่องหมายคำพูดคู่)

เชลล์จำนวนมากถือว่าcd ""เป็น no-op ดังนั้นสำหรับเชลล์เหล่านั้นที่เราสามารถทำได้cd "$(git rev-parse --show-cdup)"(เครื่องหมายอัญประกาศคู่ปกป้องสตริงว่างเป็นอาร์กิวเมนต์ในเคส edge แรกและเก็บ whitespace ในเคส edge ที่สาม) POSIX บอกว่าผลลัพธ์ของcd ""ไม่ได้ระบุไว้ดังนั้นจึงเป็นการดีที่สุดที่จะหลีกเลี่ยงการตั้งสมมติฐานนี้

วิธีการแก้ปัญหาที่ใช้งานได้ในทุกกรณีข้างต้นต้องใช้การทดสอบบางอย่าง เสร็จสิ้นอย่างชัดเจนอาจมีลักษณะเช่นนี้:

cdup="$(git rev-parse --show-cdup)" && test -n "$cdup" && cd "$cdup"

ไม่cdทำสำหรับเคสตัวแรก

หากเป็นที่ยอมรับให้รันcd .สำหรับเคสขอบแรกดังนั้นเงื่อนไขสามารถทำได้ในการขยายพารามิเตอร์:

cdup="$(git rev-parse --show-cdup)" && cd "${cdup:-.}"

ทำไมคุณไม่ใช้ "git config --global --add alias.root '! pwd'" และเชลล์ alias gitroot = 'cd git root' ซึ่งเป็นคำตอบที่คุณใช้?
Jason Axelson

1
การใช้นามแฝงอาจเป็นไปไม่ได้เช่นหากคุณต้องการสคริปต์และไม่สามารถพึ่งพานามแฝงที่กำหนดเองได้
blueyed

1
โมดูลย่อยเป็นอีกมุมหนึ่ง
Ryan The Leach

14

ในกรณีที่คุณกำลังป้อนเส้นทางนี้ไปยัง Git เองให้ใช้ :/

# this adds the whole working tree from any directory in the repo
git add :/

# and is equal to
git add $(git rev-parse --show-toplevel)

12

คำตอบสั้น ๆ ที่ใช้งานได้กับ submodules, hooks, และภายใน .gitไดเรกทอรี

นี่คือคำตอบสั้น ๆ ที่คนส่วนใหญ่ต้องการ:

r=$(git rev-parse --git-dir) && r=$(cd "$r" && pwd)/ && echo "${r%%/.git/*}"

สิ่งนี้จะทำงานที่ใดก็ได้ในแผนผังการทำงาน git (รวมถึงภายใน.gitไดเรกทอรี) แต่สมมติว่ามีการเรียกไดเรกทอรีเก็บข้อมูล.git(ซึ่งเป็นค่าเริ่มต้น) ด้วย submodules สิ่งนี้จะไปที่รูทของพื้นที่เก็บข้อมูลด้านนอกสุด

หากคุณต้องการไปที่รูทของการใช้ submodule ปัจจุบัน:

echo $(r=$(git rev-parse --show-toplevel) && ([[ -n $r ]] && echo "$r" || (cd $(git rev-parse --git-dir)/.. && pwd) ))

ในการดำเนินการคำสั่งในรูท submodule ของคุณอย่างง่ายดายภายใต้[alias]ของคุณ.gitconfigให้เพิ่ม

sh = "!f() { root=$(pwd)/ && cd ${root%%/.git/*} && git rev-parse && exec \"$@\"; }; f"

สิ่งนี้ช่วยให้คุณทำสิ่งต่าง ๆ เช่น git sh ag <string>

โซลูชันที่แข็งแกร่งซึ่งรองรับชื่อแตกต่างกันหรือภายนอก.gitหรือ$GIT_DIRไดเรกทอรี

โปรดทราบว่า$GIT_DIRอาจชี้ที่ภายนอก (และไม่ถูกเรียก.git ) ดังนั้นจึงจำเป็นต้องมีการตรวจสอบเพิ่มเติม

ใส่สิ่งนี้ใน.bashrc:

# Print the name of the git working tree's root directory
function git_root() {
  local root first_commit
  # git displays its own error if not in a repository
  root=$(git rev-parse --show-toplevel) || return
  if [[ -n $root ]]; then
    echo $root
    return
  elif [[ $(git rev-parse --is-inside-git-dir) = true ]]; then
    # We're inside the .git directory
    # Store the commit id of the first commit to compare later
    # It's possible that $GIT_DIR points somewhere not inside the repo
    first_commit=$(git rev-list --parents HEAD | tail -1) ||
      echo "$0: Can't get initial commit" 2>&1 && false && return
    root=$(git rev-parse --git-dir)/.. &&
      # subshell so we don't change the user's working directory
    ( cd "$root" &&
      if [[ $(git rev-list --parents HEAD | tail -1) = $first_commit ]]; then
        pwd
      else
        echo "$FUNCNAME: git directory is not inside its repository" 2>&1
        false
      fi
    )
  else
    echo "$FUNCNAME: Can't determine repository root" 2>&1
    false
  fi
}

# Change working directory to git repository root
function cd_git_root() {
  local root
  root=$(git_root) || return 1  # git_root will print any errors
  cd "$root"
}

ดำเนินการได้โดยการพิมพ์git_root(หลังจากรีสตาร์ทเปลือกของคุณ: exec bash)


รหัสนี้จะถูกรหัสตรวจสอบที่ฟังก์ชั่นทุบตีที่แข็งแกร่งที่จะหารากของพื้นที่เก็บข้อมูลคอมไพล์ ดูการอัพเดต
Tom Hale

ดี ซับซ้อนกว่าที่ฉันเสนอเมื่อ 7 ปีที่แล้ว ( stackoverflow.com/a/958125/6309 ) แต่ก็ยัง +1
VonC

1
คำตอบที่สั้นกว่าสำหรับเส้นเหล่านั้นคือ: (root=$(git rev-parse --git-dir)/ && cd ${root%%/.git/*} && git rev-parse && pwd)แต่สิ่งนี้ไม่ครอบคลุม$GIT_DIRs ภายนอกที่มีชื่ออื่นที่ไม่ใช่.git
Tom Hale

ฉันสงสัยว่าสิ่งนี้คำนึงถึงหลาย worktrees ที่เป็นไปได้ใน git 2.5+ ( stackoverflow.com/a/30185564/6309 )
VonC

ลิงก์แสดงความคิดเห็นของคุณไปที่ "ฟังก์ชั่น Robust bash เพื่อค้นหารูท ... " ตอนนี้ให้ 404
ErikE

8

หากต้องการแก้ไข "git config" ให้ตอบเพียงเล็กน้อย:

git config --global --add alias.root '!pwd -P'

และทำความสะอาดเส้นทาง ดีมาก.


7

หากคุณกำลังมองหานามแฝงที่ดีในการทำเช่นนี้และไม่ระเบิดcdถ้าคุณไม่ได้อยู่ในคอมไพล์ git:

alias ..g='git rev-parse && cd "$(git rev-parse --show-cdup)"'


6

นามแฝงของเชลล์นี้ทำงานได้ไม่ว่าคุณจะอยู่ในส่วนย่อย git หรือที่ระดับบนสุด:

alias gr='[ ! -z `git rev-parse --show-toplevel` ] && cd `git rev-parse --show-toplevel || pwd`'

อัปเดตเพื่อใช้ไวยากรณ์ที่ทันสมัยแทน backticks:

alias gr='[ ! -z $(git rev-parse --show-toplevel) ] && cd $(git rev-parse --show-toplevel || pwd)'

5
alias git-root='cd \`git rev-parse --git-dir\`; cd ..'

ทุกอย่างอื่นล้มเหลวในบางจุดไม่ว่าจะไปที่ไดเรกทอรีบ้านหรือเพียงแค่ความล้มเหลวอย่างน่าสังเวช นี่เป็นวิธีที่เร็วและสั้นที่สุดในการกลับไปที่ GIT_DIR


ดูเหมือนว่า 'git rev-parse --git-dir' เป็นคำตอบที่สะอาดที่สุด
Stabledog

3
นี้ล้มเหลวเมื่อ$GIT_DIRถูกถอดออกจาก workingtree โดยใช้.git-Files gitdir: SOMEPATHและ ดังนั้นนี้ล้มเหลวสำหรับ submodules เกินไปที่มี$GIT_DIR .git/modules/SUBMODULEPATH
Tino

5

นี่คือสคริปต์ที่ฉันเขียนที่จัดการทั้งสองกรณี: 1) ที่เก็บพร้อมเวิร์กสเปซ 2) ที่เก็บเปลือย

https://gist.github.com/jdsumsion/6282953

git-root (ไฟล์ปฏิบัติการในเส้นทางของคุณ):

#!/bin/bash
GIT_DIR=`git rev-parse --git-dir` &&
(
  if [ `basename $GIT_DIR` = ".git" ]; then
    # handle normal git repos (with a .git dir)
    cd $GIT_DIR/..
  else
    # handle bare git repos (the repo IS a xxx.git dir)
    cd $GIT_DIR
  fi
  pwd
)

หวังว่านี่จะเป็นประโยชน์


1
Keith ขอบคุณสำหรับคำแนะนำฉันได้รวมสคริปต์ไว้
jdsumsion

ที่จริงฉัน upvote คำตอบสูงสุดเพราะฉันรู้git execว่าความคิดที่เป็นประโยชน์มากขึ้นในที่เก็บที่ไม่ได้เปลือย อย่างไรก็ตามสคริปต์นี้ในคำตอบของฉันจัดการกับกรณีที่ไม่ได้รับการเปลือยและไม่ถูกต้องซึ่งอาจเป็นประโยชน์กับใครบางคนดังนั้นฉันจึงทิ้งคำตอบไว้ที่นี่
jdsumsion

1
อย่างไรก็ตามเรื่องนี้ล้มเหลวภายในgit submodules ที่มีสิ่งที่ต้องการ$GIT_DIR /.git/modules/SUBMODULEนอกจากนี้คุณสมมติว่า.gitไดเรกทอรีเป็นส่วนหนึ่งของ worktree ในกรณีที่ไม่ใช่แบบเปลือย
Tino

4
$ git config alias.root '!pwd'
# then you have:
$ git root

ชื่อแทนนี้จะล้มเหลวในระดับโลก ใช้สิ่งนี้แทน (ใน ~ / .gitconfig): [alias] findroot = "!f () { [[ -d ".git" ]] && echo "Found git in [pwd ]" && exit 0; cd .. && echo "IN pwd" && f;}; f"
FractalSpace

ทำไม downvote โปรดเน้นข้อผิดพลาดใด ๆ หรือแนะนำการปรับปรุงแทน
FractalSpace

1
สำหรับฉันgit config --global alias.root '!pwd'ทำงาน ฉันไม่สามารถมองเห็นกรณีใด ๆ ที่มันทำหน้าที่แตกต่างจากตัวแปรที่ไม่ใช่สากล (Unix, git 1.7.10.4) BTW: คุณfindrootต้องการ a /.gitเพื่อหลีกเลี่ยงการเรียกซ้ำที่ไม่สิ้นสุด
Tino

4

ตั้งแต่Git 2.13.0มันสนับสนุนตัวเลือกใหม่เพื่อแสดงเส้นทางของโครงการรากซึ่งทำงานได้แม้จะถูกใช้จากภายใน submodule:

git rev-parse --show-superproject-working-tree

git-scm.com/docs/… . น่าสนใจ ฉันต้องพลาดมันไป +1
VonC

3
เตือนว่า: "ไม่มีผลอะไรถ้าที่เก็บข้อมูลปัจจุบันไม่ได้ใช้เป็น submodule โดยโครงการใด ๆ "
VonC

ขอบคุณสำหรับความคิดเห็น! ฉันไม่ได้สังเกตว่า
Jordi Vilalta Prat

2

เชลล์นามแฝงที่กำหนดค่าล่วงหน้าใน Shell Frameworks

หากคุณใช้เชลล์เฟรมเวิร์กอาจมีสมนามเชลล์อยู่แล้ว:

  • $ grtในoh-my-zsh (68k) ( cd $(git rev-parse --show-toplevel || echo "."))
  • $ git-rootในprezto (8.8k) (แสดงเส้นทางไปยังรากของต้นไม้ที่ทำงาน)
  • $ g.. zimfw (1k) (เปลี่ยนไดเรกทอรีปัจจุบันเป็นระดับบนสุดของแผนผังการทำงาน)

1

ฉันต้องการขยายความคิดเห็นที่ยอดเยี่ยมของ Daniel Brockman

การกำหนดgit config --global alias.exec '!exec 'อนุญาตให้คุณทำสิ่งต่าง ๆ เช่นgit exec makeในฐานะman git-configรัฐ:

หากส่วนขยาย alias ถูกเติมหน้าด้วยเครื่องหมายอัศเจรีย์จะถูกใช้เป็นคำสั่งเชลล์ [... ] โปรดทราบว่าคำสั่งเชลล์จะถูกดำเนินการจากไดเรกทอรีระดับบนสุดของที่เก็บซึ่งอาจไม่จำเป็นต้องเป็นไดเรกทอรีปัจจุบัน

นอกจากนี้ยังมีประโยชน์ที่จะรู้ว่า$GIT_PREFIXจะเป็นเส้นทางไปยังไดเรกทอรีปัจจุบันเทียบกับไดเรกทอรีระดับบนสุดของที่เก็บ แต่รู้ว่ามันเป็นเพียงครึ่งหนึ่งของการต่อสู้™ การขยายตัวแปรเชลล์ทำให้ใช้งานค่อนข้างยาก ดังนั้นฉันแนะนำให้ใช้bash -cดังนี้:

git exec bash -c 'ls -l $GIT_PREFIX'

คำสั่งอื่น ๆ ได้แก่ :

git exec pwd
git exec make

1

ในกรณีที่ทุกคนต้องการวิธีที่เป็นไปตาม POSIX ในการทำเช่นนี้โดยไม่จำเป็นต้องgitปฏิบัติการได้:

git-root:

#$1: Path to child directory
git_root_recurse_parent() {
    # Check if cwd is a git root directory
    if [ -d .git/objects -a -d .git/refs -a -f .git/HEAD ] ; then
        pwd
        return 0
    fi

    # Check if recursion should end (typically if cwd is /)
    if [ "${1}" = "$(pwd)" ] ; then
        return 1
    fi

    # Check parent directory in the same way
    local cwd=$(pwd)
    cd ..
    git_root_recurse_parent "${cwd}"
}

git_root_recurse_parent

หากคุณเพียงต้องการให้การทำงานเป็นส่วนหนึ่งของสคริปต์ให้ลบ shebang และแทนที่git_root_recurse_parentบรรทัดสุดท้ายด้วย:

git_root() {
    (git_root_recurse_parent)
}

Caveat: ถ้านี่ไม่ได้ถูกเรียกใน repo คอมไพล์การเรียกซ้ำจะไม่สิ้นสุดเลย
AH

@AH ifคำสั่งที่สองควรจะตรวจสอบว่าคุณได้เปลี่ยนไดเรกทอรีในการสอบถามซ้ำ หากยังคงอยู่ในไดเรกทอรีเดียวกันมันจะถือว่าคุณติดอยู่ที่ใดที่หนึ่ง (เช่น/) และเบรกซ้ำ ข้อผิดพลาดได้รับการแก้ไขและควรทำงานได้ตามที่คาดไว้ ขอบคุณที่ชี้นำ
swalog

0

ต้องแก้ปัญหานี้ด้วยตัวเองวันนี้ แก้ไขใน C # ตามที่ฉันต้องการสำหรับโปรแกรม แต่ฉันคิดว่ามันสามารถเขียนใหม่ได้อย่างง่ายดาย พิจารณาโดเมนสาธารณะนี้

public static string GetGitRoot (string file_path) {

    file_path = System.IO.Path.GetDirectoryName (file_path);

    while (file_path != null) {

        if (Directory.Exists (System.IO.Path.Combine (file_path, ".git")))
            return file_path;

        file_path = Directory.GetParent (file_path).FullName;

    }

    return null;

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