यदि प्रोग्राम में परिवर्तन नहीं हुए हैं तो मैं कैसे निर्धारित करूं?


226

एक मेकफाइल में, मैं कुछ क्रियाओं को करना चाहता हूँ यदि कोई अनपेक्षित परिवर्तन हैं (या तो कार्यशील ट्री या इंडेक्स में)। सबसे साफ और सबसे कुशल तरीका क्या है? एक आदेश जो एक मामले में शून्य का रिटर्न मान और दूसरे में गैर-शून्य मेरे उद्देश्यों के अनुरूप होगा।

मैं git statusआउटपुट को चला और पाइप कर सकता हूं grep, लेकिन मुझे लगता है कि बेहतर तरीका होना चाहिए।


जवाबों:


288

अद्यतन : ओपी डैनियल स्टटज़बाक टिप्पणियों में बताते हैं कि इस साधारण आदेश git diff-indexने उनके लिए काम किया:

git update-index --refresh 
git diff-index --quiet HEAD --

( nornagon ने टिप्पणियों में उल्लेख किया है कि, अगर ऐसी फाइलें हैं जिन्हें छुआ गया है, लेकिन जिनकी सामग्री सूचकांक में समान है, तो आपको git update-index --refreshपहले चलाने की आवश्यकता होगी git diff-index, अन्यथा diff-indexगलत रिपोर्ट देगी कि पेड़ गंदा है)

तब आप देख सकते हैं कि " कैसे जांच करें कि क्या कोई कमांड सफल हुई? "

git diff-index --quiet HEAD -- || echo "untracked"; // do something about it

नोट: जैसा कि एंथोनी सॉटिले ने टिप्पणी की है

git diff-index HEAD ...ऐसी शाखा पर विफल हो जाएगा, जिसमें कोई कमिट नहीं है (जैसे कि एक नया इनिशियलाइज़ रिपॉजिटरी)।
एक वर्कअराउंड मैंने पाया हैgit diff-index $(git write-tree) ...

और टिप्पणियों मेंharidsv इंगित करता है कि एक नई फ़ाइल पर इसे एक अंतर के रूप में नहीं पता चलता है। लगता है कि सुरक्षित दृष्टिकोण पहले फ़ाइल युक्ति पर चलाया जाता है और फिर यह देखने के लिए उपयोग किया जाता है कि कुछ भी चलने से पहले अनुक्रमणिका में जोड़ा गया है या नहीं ।git diff-files
git addgit diff-indexgit commit

git add ${file_args} && \
git diff-index --cached --quiet HEAD || git commit -m '${commit_msg}'

और टिप्पणियों में 6502 रिपोर्ट:

एक समस्या जिसका मुझे सामना करना पड़ा, वह git diff-indexयह बताएगी कि वास्तव में मतभेद हैं जब फ़ाइलों के टाइमस्टैम्प के अलावा कोई नहीं होता है। एक बार
चलाने git diffसे समस्या हल हो जाती है (आश्चर्यजनक रूप से पर्याप्त है, git diffवास्तव में सैंडबॉक्स की सामग्री को बदल देता है, जिसका अर्थ है यहां .git/index)

ये टाइमस्टैम्प समस्याएँ तब भी हो सकती हैं यदि git docker में चल रही हो


मूल उत्तर:

"प्रोग्रामेटिकली" का अर्थ है कभी भी चीनी मिट्टी के बरतन आदेशों पर भरोसा न करें
हमेशा प्लंबिंग कमांड पर भरोसा करें

विकल्पों के लिए " Git के साथ एक गंदे सूचकांक या अनटैक की गई फ़ाइलों की जाँच " भी देखें (जैसे git status --porcelain)

आप नए " require_clean_work_treeफ़ंक्शन " से प्रेरणा ले सकते हैं जिसे हम बोलते हैं ;) (अक्टूबर 2010 की शुरुआत में)

require_clean_work_tree () {
    # Update the index
    git update-index -q --ignore-submodules --refresh
    err=0

    # Disallow unstaged changes in the working tree
    if ! git diff-files --quiet --ignore-submodules --
    then
        echo >&2 "cannot $1: you have unstaged changes."
        git diff-files --name-status -r --ignore-submodules -- >&2
        err=1
    fi

    # Disallow uncommitted changes in the index
    if ! git diff-index --cached --quiet HEAD --ignore-submodules --
    then
        echo >&2 "cannot $1: your index contains uncommitted changes."
        git diff-index --cached --name-status -r --ignore-submodules HEAD -- >&2
        err=1
    fi

    if [ $err = 1 ]
    then
        echo >&2 "Please commit or stash them."
        exit 1
    fi
}

12
"स्क्रिप्टिंग के लिए पाइपलाइन बनाम चीनी मिट्टी के बरतन" सिद्धांत एक सबक यह है कि जेकब Narębski ": बार-बार मुझे बताया था Git में मौजूदा परियोजना के लिए सभी लॉग सूची कैसे? " ", Git: दिन-ब-दिन बदलाव का ", ...
VonC

18
लिंक सुझाव के कुछ क्लिक करने के बाद, मैंने पाया कि मैं क्या देख रहा था: git diff-index --quiet HEAD
डैनियल स्टुट्ज़बाक

11
@DanielStutzbach: यदि आपके पास HEADकार्यशील निर्देशिका में एक फ़ाइल है, तो वह विफल हो सकती है । बेहतर उपयोग git diff-index --quiet HEAD --
डेविड ओंगारो

7
और फिर भी git status --helpराज्यों में मैनुअल : - चीनी मिट्टी के बरतन स्क्रिप्ट के लिए एक आसान-से-पार्स प्रारूप में आउटपुट दें। यह लघु आउटपुट के समान है, लेकिन Git संस्करणों में स्थिर रहेगा और उपयोगकर्ता कॉन्फ़िगरेशन की परवाह किए बिना। जानकारी के लिए नीचे देखें।
एड रान्डेल

7
@VonC कि वास्तव में कोई मतलब नहीं है। इस तरह से आप हर चीज को इसके उलट कर सकते हैं। - चीनी मिट्टी के बरतन आपको यह आभास देता है कि यह जल्द ही टूटने वाला है। यदि ऐसा नहीं है, तो इसे प्लंबिंग कहा जाना चाहिए, न कि चीनी मिट्टी के बरतन। का उपयोग करते हुए - चीनी मिट्टी के बरतन आपकी स्क्रिप्ट को तोड़ने का कारण बनता है, जो इसे प्रस्तुत नहीं करता है एक चीनी मिट्टी के बरतन स्क्रिप्ट;; यदि आप अपनी स्क्रिप्ट को तोड़ना चाहते हैं, तो आपको - चीनी मिट्टी के बरतन का उपयोग नहीं करना चाहिए !!। तो यह पूरी तरह से समझ से बाहर है और हर किसी को फेंक देता है।
Xennex81

104

जबकि अन्य समाधान बहुत गहन हैं, यदि आप वास्तव में जल्दी और गंदे कुछ चाहते हैं, तो कुछ इस तरह की कोशिश करें:

[[ -z $(git status -s) ]]

यह सिर्फ यह जांचता है कि स्टेटस सारांश में कोई आउटपुट है या नहीं।


7
मेरे लिये कार्य करता है। उलटा (आप परिवर्तन है) के लिए उपयोग करें, उदाहरण के लिए अगर `[[-n $ (git स्थिति -s)]]; उसके बाद ... Fi`
aaron

यह काम करता है, लेकिन क्या आप बता सकते हैं कि [[ ... ]]वाक्यविन्यास वास्तव में क्या कर रहा है? मैंने पहले कभी ऐसा कुछ नहीं देखा।
GMA

2
@ git statusइस परीक्षा में रिटर्न कोड वास्तव में नजरअंदाज कर दिया जाता है। यह केवल आउटपुट को देखता है। की जाँच करें इस बैश संबंधित पेज बारे में अधिक जानकारी के लिए [, [[और कैसे बैश में काम करता है परीक्षण।
नेप्थर

2
यह लगभग सही उत्तर है, लेकिन स्क्रिप्ट के लिए --porcelainपैरामीटर का उपयोग करना बेहतर है जैसा कि यहां
Mariusz Pawelski

2
आप git status -s -uallअनटैक की गई फ़ाइलों को शामिल करने के लिए उपयोग करना चाह सकते हैं ।
बारफिन

59

git diff --exit-codeयदि कोई परिवर्तन हो, तो नॉनज़रो लौट आएगा; git diff --quietकोई आउटपुट नहीं है। चूंकि आप काम करने वाले पेड़ और सूचकांक के लिए जांचना चाहते हैं, उपयोग करें

git diff --quiet && git diff --cached --quiet

या

git diff --quiet HEAD

या तो कोई आपको बताएगा कि क्या बिना परिवर्तन किए हुए परिवर्तन हैं या नहीं।


6
वे समकक्ष नहीं हैं। सिंगल कमांड git diff --quite HEADआपको केवल यह बताएगा कि क्या कार्य करने वाला पेड़ साफ है, न कि सूचकांक साफ है। उदाहरण के लिए, यदि fileHEAD ~ और HEAD के बीच में परिवर्तन किया गया था, तो उसके बाद git reset HEAD~ -- file, यह अभी भी 0 से बाहर निकलेगा, हालांकि सूचकांक में मौजूद परिवर्तन (wt == HEAD, लेकिन index! = HEAD) हैं।
क्रिस जॉन्सन

2
चेतावनी, यह git rm, AFAICS के साथ मचान क्षेत्र से हटाए गए फ़ाइलों को नहीं पकड़ेगा।
nmr

24
नई (अनट्रैक) फ़ाइलों का पता नहीं लगा है git diff --quiet && git diff --cached --quiet
4LegsDrivenCat

17

@ नेप्थर के उत्तर पर विस्तार:

if [[ -z $(git status -s) ]]
then
  echo "tree is clean"
else
  echo "tree is dirty, please commit changes before running this"
  exit
fi

1
यह अच्छा है; मैं इसका परीक्षण करके एकल फ़ाइलों को ऑटोकॉमिट करने के लिए उपयोग करता हूं $(git status -s "$file")और फिर elseक्लॉज मेंgit add "$file"; git commit -m "your autocommit process" "$file"
toddkaufmann

यदि आप git status -sऐसा git status --porcelain ; git clean -ndकरते हैं, तो इसके बजाय, कबाड़ निर्देशिकाएं भी यहां दिखाई देंगी, जो अदृश्य हैं git status
इकोमानोट

4

जैसा कि अन्य उत्तर में कहा गया है, जैसा कि इस तरह के आदेश के लिए सरल है:

git diff-index --quiet HEAD --

यदि आप अंतिम दो डैश छोड़ते हैं, तो यदि आपके पास कोई फ़ाइल है तो कमांड विफल हो जाएगी HEAD

उदाहरण:

#!/bin/bash
set -e
echo -n "Checking if there are uncommited changes... "
trap 'echo -e "\033[0;31mFAILED\033[0m"' ERR
git diff-index --quiet HEAD --
trap - ERR
echo -e "\033[0;32mAll set!\033[0m"

# continue as planned...

Word of caution: यह कमांड अनट्रैक फाइल्स को अनदेखा करता है।


2
जैसा कि उस उत्तर में टिप्पणियों में बताया गया है, यह
खोजता है

नहीं, यह अनुक्रमणिका फ़ाइलों में नए जोड़े का पता लगाता है। बस जाँच की गई।
sanmai

प्रश्न देखें। अनट्रैक की गई फ़ाइलें परिवर्तन नहीं हैंgit addऔर git cleanबचाव के लिए
sanmai

4

मैंने अस्थिर और मंचित फ़ाइलों को सूचीबद्ध करने के लिए कुछ आसान git उपनाम बनाए:

git config --global alias.unstaged 'diff --name-only'
git config --global alias.staged 'diff --name-only --cached'

तब आप आसानी से ऐसी चीजें कर सकते हैं:

[[ -n "$(git unstaged)" ]] && echo unstaged files || echo NO unstaged files
[[ -n "$(git staged)" ]] && echo staged files || echo NO staged files

आप अपने PATHनाम पर कहीं एक स्क्रिप्ट बनाकर इसे और अधिक पठनीय बना सकते हैं git-has:

#!/bin/bash
[[ $(git "$@" | wc -c) -ne 0 ]]

अब उपरोक्त उदाहरणों को सरल बनाया जा सकता है:

git has unstaged && echo unstaged files || echo NO unstaged files
git has staged && echo staged files || echo NO staged files

पूर्णता के लिए यहां अनियोजित और उपेक्षित फ़ाइलों के लिए समान उपनाम हैं:

git config --global alias.untracked 'ls-files --exclude-standard --others'
git config --global alias.ignored 'ls-files --exclude-standard --others --ignored'

2

अजगर और GitPython पैकेज के साथ:

import git
git.Repo(path).is_dirty(untracked_files=True)

रिटर्न सही है अगर रिपॉजिटरी साफ नहीं है


इसने अन्य टिप्पणियों में उल्लेखित कुछ "टाइमस्टैम्प" मुद्दों से परहेज किया
जेसन

1
ध्यान दें कि GitPython सिर्फ git CLI का उपयोग कर रहा है। यदि आप सेट LOGLEVEL=DEBUGकरते हैं, तो आप इसे चलाने के लिए उपयोग करके सभी पॉपेन कमांड देखेंगेgit diff
जेसन

-3

यहाँ सबसे अच्छा, सबसे साफ तरीका है।

function git_dirty {
    text=$(git status)
    changed_text="Changes to be committed"
    untracked_files="Untracked files"

    dirty=false

    if [[ ${text} = *"$changed_text"* ]];then
        dirty=true
    fi

    if [[ ${text} = *"$untracked_files"* ]];then
        dirty=true
    fi

    echo $dirty
}

4
नहीं, यह सबसे अच्छा नहीं है। git statusएक 'पोर्सिलेन' कमांड है। लिपियों में चीनी मिट्टी के बरतन आदेशों का उपयोग न करें क्योंकि वे गिट संस्करणों के बीच बदल सकते हैं। इसके बजाय 'प्लंबिंग' कमांड का उपयोग करें।
स्पूडर

3
मुझे लगता है कि यदि आपने इसे उपयोग करने के लिए अपडेट किया है git status --porcelain(जो इस उद्देश्य के लिए है - एक स्थिर प्रारूप जिसे आप स्क्रिप्ट में पार्स कर सकते हैं), संभवतः -z (न्यूलाइन के बजाय अशक्त-पृथक)? आप इस विचार के साथ कुछ उपयोगी कर सकते हैं? । @ codyc4321 देख stackoverflow.com/questions/6976473/... जानकारी के लिए
msouth
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.