ตรวจสอบว่าไดเรกทอรีปัจจุบันเป็นที่เก็บ Git


199

ฉันกำลังเขียนสคริปต์หลายชุดสำหรับการจัดการ Git ใน zsh

ฉันจะตรวจสอบว่าไดเรกทอรีปัจจุบันเป็นที่เก็บ Git ได้อย่างไร (เมื่อฉันไม่ได้อยู่ใน Git repo ฉันไม่ต้องการรันคำสั่งจำนวนมากและได้รับคำfatal: Not a git repositoryตอบมากมาย)


คุณเคยดูไฟล์ bash completion (ใน contrib / completion / git-completion.bash) เพื่อหาแรงบันดาลใจหรือไม่? ฉันใช้คำสั่ง __git_ps1 เป็นส่วนหนึ่งของ bash prompt ในความเป็นจริงส่วนใหญ่มันจะมาภายใน zsh ฟังก์ชัน __gitdir น่าจะเป็นฟังก์ชันที่คุณต้องการ
jabbie

1
@jabbie: ทำไมคุณไม่ตอบแบบนั้นล่ะ?
อามาริลเลี่ยน

คุณเคยตรวจสอบฟังก์ชั่นการกระจาย zsh แล้วหรือยัง?
MBO


1
หมายเหตุ: ไม่มีคำตอบปัจจุบันพิจารณาตัวแปร$GIT_DIRหรือ$GIT_WORK_TREEสภาพแวดล้อมหรือวิธีการโต้ตอบ
o11c

คำตอบ:


155

คัดลอกจากไฟล์ bash เสร็จแล้วต่อไปนี้เป็นวิธีที่ไร้เดียงสาที่จะทำ

# Copyright (C) 2006,2007 Shawn O. Pearce <spearce@spearce.org>
# Conceptually based on gitcompletion (http://gitweb.hawaga.org.uk/).
# Distributed under the GNU General Public License, version 2.0.

if [ -d .git ]; then
  echo .git;
else
  git rev-parse --git-dir 2> /dev/null;
fi;

คุณสามารถห่อมันในฟังก์ชั่นหรือใช้มันในสคริปต์

รวมตัวเป็นเงื่อนไขหนึ่งบรรทัดเหมาะสำหรับbashและzsh

[ -d .git ] && echo .git || git rev-parse --git-dir > /dev/null 2>&1

3
@William Pursell ทำไมต้องแยกเมื่อคุณไม่ต้องการ? ส่วนใหญ่สำหรับความเร็วในกรณีเล็ก ๆ น้อย ๆ
jabbie

16
git rev-parse --is-inside-git-dirคำตอบที่ควรจะปรับปรุงการใช้งาน ฉันใช้เป็นการส่วนตัวgit rev-parse --is-inside-work-treeก่อนตั้งค่า PS1 ของฉัน
juliohm

12
@juliohm --is-inside-git-dirจะส่งกลับจริงถ้าคุณอยู่ใน.gitไดเรกทอรีของพื้นที่เก็บข้อมูล ฉันไม่คิดว่า OP กำลังมองหาสิ่งนั้น
nyuszika7h

7
ทั้ง--is-inside-work-treeมิได้--is-inside-git-dirจะทำงานเมื่อคุณอยู่ด้านนอกของ repo คอมไพล์ ดู: groups.google.com/forum/#!topic/git-users/dWc23LFhWxE
fisherwebdev

7
.gitนี้จะล้มเหลวถ้าไดเรกทอรีคอมไพล์เป็นอย่างอื่นที่ไม่ใช่ เพื่อความแข็งแรง, ละเว้นและการใช้งานเพียงแค่[ -d .git ] git rev-parse ...
ปีเตอร์จอห์นอควิทแลม

134

คุณสามารถใช้ได้:

git rev-parse --is-inside-work-tree

ซึ่งจะพิมพ์ 'จริง' ถ้าคุณอยู่ในต้นไม้ทำงาน repos คอมไพล์

โปรดทราบว่ายังคงส่งคืนเอาต์พุตไปยัง STDERR หากคุณอยู่นอก git repo (และไม่พิมพ์ 'false')

นำมาจากคำตอบนี้: https://stackoverflow.com/a/2044714/12983


นี่เป็นวิธีที่ง่ายที่สุดในการตรวจสอบ
calbertts

3
สิ่งนี้จะยังคงพิมพ์เท็จสำหรับที่เก็บเปลือยที่ไม่มีต้นไม้ทำงาน
noggin182

สิ่งนี้ไม่พิจารณาถึงไดเร็กทอรีย่อย ฉันต้องการตรวจสอบว่าgit rev-parse --show-toplevelตรงกับโฟลเดอร์ย่อยที่ฉันกำลังตรวจสอบหรือไม่
alper

คำตอบที่เลือกไม่ได้พิมพ์อะไรเลย อันนี้ใช้ได้ผล
ScottyBlades

48

ใช้ git rev-parse --git-dir

ถ้า git rev-parse --git-dir> / dev / null 2> & 1; แล้วก็
  : # นี่เป็นที่เก็บ git ที่ถูกต้อง (แต่ใช้งานได้ในปัจจุบัน
    # ไดเรกทอรีอาจไม่ใช่ระดับสูงสุด
    # ตรวจสอบผลลัพธ์ของคำสั่ง git rev-parse หากคุณสนใจ)
อื่น
  : # นี่ไม่ใช่ที่เก็บ git
Fi

27

หรือคุณสามารถทำสิ่งนี้:

inside_git_repo="$(git rev-parse --is-inside-work-tree 2>/dev/null)"

if [ "$inside_git_repo" ]; then
  echo "inside git repo"
else
  echo "not in git repo"
fi

2
ฉันชอบอันนี้เพราะมันทำงานจากไดเรคทอรีย่อยด้วย
joehanna


7

ไม่แน่ใจว่ามีวิธีการเข้าถึง / เอกสารที่เปิดเผยต่อสาธารณะหรือไม่ (มีฟังก์ชั่น git ภายในซึ่งคุณสามารถใช้ / ใช้ในทางที่ผิดได้ในแหล่ง git เอง)

คุณสามารถทำสิ่งที่ชอบ;

if ! git ls-files >& /dev/null; then
  echo "not in git"
fi

7

ตามคำตอบของ @Alex Cory :

[ "$(git rev-parse --is-inside-work-tree 2>/dev/null)" == "true" ]

ไม่มีการดำเนินการซ้ำซ้อนและทำงานใน-eโหมด

  • ตามที่ @ go2null ตั้งข้อสังเกตสิ่งนี้จะไม่ทำงานใน repo เปล่า หากคุณต้องการทำงานกับ repo เปล่าไม่ว่าด้วยเหตุผลใดคุณสามารถตรวจสอบว่าgit rev-parseประสบความสำเร็จหรือไม่โดยไม่สนใจเอาท์พุท
    • ฉันไม่คิดว่านี่เป็นข้อเสียเปรียบเพราะบรรทัดข้างต้นมีไว้สำหรับการเขียนสคริปต์และgitคำสั่งทั้งหมดจะใช้ได้ภายใน worktree เท่านั้น ดังนั้นเพื่อวัตถุประสงค์ในการเขียนสคริปต์คุณมักจะสนใจที่จะไม่เพียง แต่อยู่ใน "git repo" แต่อยู่ใน worktree

นี้ล้มเหลวภายในของคอมไพล์เปลือย repo
go2null

แทนที่จะเป็นการตรวจสอบผลลัพธ์จะเป็นการดีกว่าถ้าจะตรวจสอบค่าส่งคืน อย่าเรียกใช้[เลย แค่ทำif git rev-parse --is-inside-work-tree; then ... (ด้วยการเปลี่ยนเส้นทางตามที่ต้องการ)
William Pursell

1
@WilliamPursell กำลังตรวจสอบค่าการออกไม่ทำงานที่นี่: stackoverflow.com/questions/2180270//
ivan_pozdeev

@Ivan_pozdeev ขึ้นอยู่กับคำจำกัดความของคุณของ "งาน" ในกรณีนี้ฉันจะบอกว่าการตรวจสอบค่าส่งคืนใช้งานได้ในขณะที่การตรวจสอบผลลัพธ์ไม่ได้ ในทั้งสองกรณีจากมุมมองของแนวปฏิบัติที่ดีที่สุดสำหรับการเขียนโค้ดในเชลล์มันเหมาะสมกว่าที่จะตรวจสอบค่าส่งคืน
วิลเลียม Pursell

@WilliamPursell หากคุณอ่านความคิดเห็นที่เชื่อมโยงคุณจะรู้ว่าสิ่งที่ฉันหมายถึงโดย "ไม่ทำงาน" ที่นี่
ivan_pozdeev

6

อีกวิธีคือตรวจสอบรหัสออกของคำสั่ง

git rev-parse 2> /dev/null; [ $? == 0 ] && echo 1

สิ่งนี้จะพิมพ์ 1 หากคุณอยู่ในโฟลเดอร์ที่เก็บ git


โปรดทราบว่านี่จะมี rc 0 แม้ว่าคุณจะอยู่ใน.gitไดเรกทอรีซึ่งคุณอาจต้องการหรือไม่ต้องการ
ivan_pozdeev

เขียนโดย Git อย่างสุขสบายเพื่อให้คุณสามารถปิดไฟล์ที่คุณไม่ต้องการgit rev-parse 2>&-ได้
jthill

4

คำตอบนี้ยังมีฟังก์ชั่นตัวอย่างเปลือก POSIX และตัวอย่างการใช้งานเพื่อเสริม @ jabbie ของคำตอบ

is_inside_git_repo() {
    git rev-parse --is-inside-work-tree >/dev/null 2>&1
}

gitผลตอบแทน errorlevel 0ถ้ามันเป็นภายในเก็บคอมไพล์อื่นก็จะส่งกลับ 128errorlevel (นอกจากนี้มันจะส่งกลับtrueหรือfalseถ้ามันอยู่ในพื้นที่เก็บข้อมูล git)

ตัวอย่างการใช้งาน

for repo in *; do
    # skip files
    [ -d "$repo" ] || continue
    # run commands in subshell so each loop starts in the current dir
    (
        cd "$repo"
        # skip plain directories
        is_inside_git_repo || continue
        printf '== %s ==\n' "$repo"
        git remote update --prune 'origin' # example command
        # other commands here
    )
done

ไม่เพียงพอ ภายใน.gitก็จะประสบความสำเร็จ falseแต่พิมพ์
ivan_pozdeev

@ivan_pozdeev: หากgit rev-parse --is-inside-work-treeผลตอบแทนtrueหรือfalseแล้วมันคือภายใน repo คอมไพล์และนั่นคือสิ่งที่กลับมาทำงาน นั่นคือฟังก์ชั่นถูกต้อง
go2null

เพื่อขยายดูคำอธิบายในคำตอบค่าที่ส่งคืนจาก git จะถูกละเว้นข้อผิดพลาดระดับคือสิ่งที่ใช้
go2null

2

มันใช้งานได้สำหรับฉัน คุณยังคงได้รับข้อผิดพลาด แต่ยังง่ายต่อการปราบปราม มันยังใช้งานได้จากภายในโฟลเดอร์ย่อย!

สถานะ git> / dev / null 2> & 1 && echo Hello World!

คุณสามารถใส่สิ่งนี้ในคำสั่ง if แล้วถ้าคุณต้องการทำตามเงื่อนไขเพิ่มเติม


2
ดีพอสำหรับหลายกรณีบางที แต่มันล้มเหลวใน repo คอมไพล์เปลือย
Wildcard

3
git statusได้ช้ามากใน repo ใหญ่ / เก่า ฉันจะไม่ใช้มันเพื่อจุดประสงค์นี้
henrebotha

1

ทำไมไม่ใช้รหัสออก? หากมีการเก็บคอมไพล์ที่มีอยู่ในไดเรกทอรีปัจจุบันแล้วgit branchและgit tagคำสั่งส่งคืนรหัสทางออกของ 0; มิฉะนั้นจะส่งคืนรหัสการออกที่ไม่เป็นศูนย์ ด้วยวิธีนี้คุณสามารถกำหนดได้ว่ามีที่เก็บ git อยู่หรือไม่ เพียงแค่คุณสามารถเรียกใช้:

git tag > /dev/null 2>&1 && [ $? -eq 0 ]

Advantage : Flexibe มันใช้งานได้กับที่เก็บข้อมูลทั้งแบบเปลือยและไม่เปลือยและใน sh, zsh และ bash

คำอธิบาย

  1. git tag: การรับแท็กของที่เก็บเพื่อพิจารณาว่ามีอยู่หรือไม่
  2. > /dev/null 2>&1: การป้องกันไม่ให้พิมพ์อะไรรวมถึงเอาต์พุตปกติและข้อผิดพลาด
  3. [ $? -eq 0 ]: ตรวจสอบว่าคำสั่งก่อนหน้านี้กลับมาพร้อมกับรหัสออก 0 หรือไม่ อย่างที่คุณอาจรู้ว่าทางออกที่ไม่เป็นศูนย์ทุกครั้งหมายถึงบางสิ่งที่ไม่ดีเกิดขึ้น $?ได้รับรหัสทางออกของคำสั่งก่อนหน้าและ[, -eqและ]ดำเนินการเปรียบเทียบ

ตัวอย่างเช่นคุณสามารถสร้างไฟล์ที่check-git-repoมีชื่อด้วยเนื้อหาต่อไปนี้ทำให้สามารถเรียกใช้และรันได้:

#!/bin/sh

if git tag > /dev/null 2>&1 && [ $? -eq 0 ]; then
    echo "Repository exists!";
else
    echo "No repository here.";
fi

0

# ตรวจสอบว่า repo คอมไพล์

if [ $(git rev-parse --is-inside-work-tree) = true ]; then
    echo "yes, is a git repo"
    git pull
else
    echo "no, is not a git repo"
    git clone url --depth 1
fi

นี่ไม่ใช่วิธีปฏิบัติที่ดีที่สุด หากทำงานนอกไดเรกทอรีทำงานคุณจะได้รับ "fatal: ไม่ใช่ที่เก็บ git (หรือไดเรกทอรีหลัก): .git" เขียนบน stderr และ "no ไม่ใช่ git repo" บน stdout ไม่จำเป็นต้องเรียกใช้[ที่นี่เลย เพียงทำ:if git rev-parse --is-inside-work-tree > /dev/null 2>&1; then ....
วิลเลียม Pursell

ในกรณีของฉันฉันพอใจกับสิ่งนี้และฉันต้องการติดตามความผิดพลาดนี้ในบันทึกของฉัน ไชโย!
Pascal Andy

0
if ! [[ $(pwd) = *.git/* || $(pwd) = *.git ]]; then 
  if type -P git >/dev/null; then
    ! git rev-parse --is-inside-work-tree >/dev/null 2>&1 || {
     printf '\n%s\n\n' "GIT repository detected." && git status
    }
  fi
fi

ขอบคุณivan_pozdeevตอนนี้ฉันมีการทดสอบว่าในไดเรกทอรี. git รหัสจะไม่ทำงานดังนั้นจึงไม่มีข้อผิดพลาดที่พิมพ์ออกมาหรือสถานะการออกที่ผิดพลาด

การทดสอบ " ! [[$ (pwd) = .git / || $ (pwd) = * .git]] " "ทดสอบว่าคุณไม่ได้อยู่ใน. git repo แล้วมันจะเรียกใช้คำสั่ง git คำสั่งชนิด builtin ใช้เพื่อตรวจสอบว่าคุณได้ติดตั้งคอมไพล์หรืออยู่ใน PATH ของคุณหรือไม่ ดูประเภทความช่วยเหลือ


0

เป็นอย่างไรบ้าง:

if git status -s 2>/dev/null;then
    echo "this is a git repo"
else
    echo "this is NOT a git repo"
fi

-1

คุณสามารถเพิ่มหรือเปลี่ยน $ PS1 คุณใน zshrc ของคุณกับหนึ่งหรืออีกเครื่องมือคอมไพล์พรอมต์ วิธีนี้ช่วยให้คุณทราบว่าคุณอยู่ใน git repo อย่างสะดวกและอยู่ในสถานะ repo


3
คำถามทั้งหมดของ OP คือทำอย่างไรภายในสคริปต์
Andrew C

และ __git_ps1 ไม่สามารถใช้จากภายในสคริปต์ได้อย่างไร จุดทั้งหมดของ git-prompt คือการตรวจสอบสถานะ git ของไดเรกทอรีปัจจุบันซึ่งเป็นสิ่งที่ถูกถาม
jxqz

-1
! git rev-parse --is-inside-work-tree >/dev/null 2>&1 || { 
  printf '%s\n\n' "GIT repository detected." && git status
}

ตัว! negates ดังนั้นแม้ว่าคุณจะเรียกใช้ในไดเรกทอรีที่ไม่ใช่ repo คอมไพล์มันจะไม่ให้ข้อผิดพลาดร้ายแรงบางอย่าง

> / dev / null 2> & 1จะส่งข้อความไปยัง/ dev / nullตั้งแต่คุณเพียงแค่หลังจากสถานะออก {}มีการจัดกลุ่มคำสั่งเพื่อให้คำสั่งทั้งหมดหลังจาก|| จะทำงานถ้า git rev-parse ประสบความสำเร็จตั้งแต่เราใช้! ซึ่งทำให้สถานะทางออกของ git rev-parse ขาดหายไป printfเป็นเพียงการพิมพ์ข้อความและคอมไพล์สถานะบางอย่างที่จะพิมพ์สถานะของธุรกรรมซื้อคืนที่

ห่อไว้ในฟังก์ชั่นหรือวางไว้ในสคริปต์ หวังว่านี่จะช่วยได้


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