कैसे रीसेट करें - एक उपनिर्देशिका रीसेट करें?


197

UPDATE 201 : Git 2.23 (अगस्त 2019) के साथ, एक नया आदेश है git restoreजो ऐसा करता है, स्वीकृत उत्तर देखें

अद्यतन : यह Git 1.8.3 के रूप में अधिक सहजता से काम करेगा, मेरा स्वयं का उत्तर देखें

निम्नलिखित उपयोग के मामले की कल्पना करें: मैं अपने गिट वर्किंग ट्री के एक विशिष्ट उपनिर्देशिका में सभी परिवर्तनों से छुटकारा पाना चाहता हूं, जिससे अन्य सभी उपनिर्देशिकाएं बरकरार रहें।

इस ऑपरेशन के लिए उचित Git कमांड क्या है?

नीचे दी गई स्क्रिप्ट समस्या का चित्रण करती है। How to make filesटिप्पणी के नीचे उचित कमांड डालें - वर्तमान कमांड उस फ़ाइल को पुनर्स्थापित करेगा a/c/acजिसे विरल चेकआउट द्वारा बाहर रखा जाना है। ध्यान दें कि मैं स्पष्ट रूप से बहाल नहीं करना चाहता हूं a/aऔर a/b, मैं केवल "जानता हूं" aऔर नीचे की सभी चीजों को पुनर्स्थापित करना चाहता हूं। संपादित करें : और मैं भी "नहीं जानता" b, या जो अन्य निर्देशिका के समान स्तर पर रहते हैं a

#!/bin/sh

rm -rf repo; git init repo; cd repo
for f in a b; do
  for g in a b c; do
    mkdir -p $f/$g
    touch $f/$g/$f$g
    git add $f/$g
    git commit -m "added $f/$g"
  done
done
git config core.sparsecheckout true
echo a/a > .git/info/sparse-checkout
echo a/b >> .git/info/sparse-checkout
echo b/a >> .git/info/sparse-checkout
git read-tree -m -u HEAD
echo "After read-tree:"
find * -type f

rm a/a/aa
rm a/b/ab
echo >> b/a/ba
echo "After modifying:"
find * -type f
git status

# How to make files a/* reappear without changing b and without recreating a/c?
git checkout -- a

echo "After checkout:"
git status
find * -type f

3
के बारे में क्या git stash && git stash drop?
चार्ल्सब

1
किस बारे में git checkout -- /path/to/subdir/?
इबेरू

3
@CharlesB: git stashपथ तर्क स्वीकार नहीं करता ...
krlmlr

@ साइबेबे: नोप। विरल चेकआउट द्वारा बाहर की गई फ़ाइलों को भी जोड़ देगा।
krlmlr

1
@CharlesBailey: फिर एक रेडियो बटन क्यों पढ़ा जा रहा है "विश्वसनीय और / या आधिकारिक स्रोतों से उत्तर ड्राइंग की तलाश में।" इनाम संवाद में? मैंने खुद ऐसा नहीं किया! इसके अलावा "उद्धरण रीसेट करें" (उद्धरण चिह्नों के बिना) को देखने का प्रयास करें और देखें कि पहले 3 पदों पर क्या है। निश्चित रूप से एक संदेश के लिए एक कर्नेल। मेलिंग सूची को ढूंढना अधिक कठिन होगा। - इसके अलावा, मेरे लिए यह स्पष्ट नहीं है कि यह व्यवहार बग या विशेषता है।
krlmlr

जवाबों:


163

Git 2.23 (अगस्त 2019) के साथ, आपके पास नई कमांड हैgit restore

git restore --source=HEAD --staged --worktree -- aDirectory
# or, shorter
git restore -s@ -SW  -- aDirectory

यह इंडेक्स और वर्किंग ट्री दोनों को HEADकंटेंट के साथ बदल देगा , जैसे reset --hardकि एक विशिष्ट पथ के लिए।


मूल उत्तर (2013)

नोट (जैसा कि डान फेबुलिच ने टिप्पणी की है ):

  • git checkout -- <path> एक हार्ड रीसेट नहीं करता है: यह काम करने वाले पेड़ की सामग्री को मंचित सामग्री से बदल देता है।
  • git checkout HEAD -- <path>एक पथ के लिए एक हार्ड रीसेट करता है, जो इंडेक्स और वर्किंग ट्री दोनों को कमेटी के संस्करण से बदल देता HEADहै।

जैसा कि Ajedi32 द्वारा उत्तर दिया गया है , दोनों चेकआउट फ़ॉर्म उन फ़ाइलों को नहीं हटाते हैं जिन्हें लक्ष्य संशोधन में हटा दिया गया था
यदि आपके पास काम करने वाले पेड़ में अतिरिक्त फाइलें हैं जो HEAD में मौजूद नहीं हैं, तो git checkout HEAD -- <path>उन्हें हटाया नहीं जाएगा।

नोट: git checkout --overlay HEAD -- <path>(Git 2.22, Q1 2019) के साथ , फ़ाइलें जो इंडेक्स और वर्किंग ट्री में दिखाई देती हैं, लेकिन <tree-ish>उन्हें मैच करने के लिए नहीं हटाया जाता <tree-ish>है।

लेकिन वह चेकआउट git update-index --skip-worktreeउन (उन निर्देशिकाओं के लिए जिन्हें आप अनदेखा करना चाहते हैं) सम्मान कर सकते हैं, जैसा कि " मेरे द्वारा छीनी गई विरल चेकआउट में फिर से दिखाई देने वाली फाइलें क्यों जारी रहती हैं? "


1
कृपया स्पष्ट करें। बाद git checkout HEAD -- ., विरल चेकआउट द्वारा छोड़ी गई फाइलें फिर से दिखाई देती हैं। क्या करना git update-index --skip-worktreeचाहिए?
krlmlr

@krlmlr स्किप-वर्कट्री या मान्‍य-अपरिवर्तित, git: fallengamer.livejournal.com/93321.html , stackoverflow.com/q/13630849/6309 और stackoverflow के
VonC

@krlmlr वे लिंक आपके लिए सिर्फ संकेत देने की कोशिश करने और देखने के लिए कि क्या कोई चेकआउट अभी भी उन प्रविष्टियों को पुनर्स्थापित करेगा, एक बार उन्हें 'स्किप्ड-वर्कट्री' के रूप में चिह्नित किया गया है।
VonC

क्षमा करें, लेकिन यह हाथ में कार्य के लिए बहुत जटिल है। मुझे एक समावेशी रीसेट चाहिए, एक्सक्लूसिव नहीं। क्या वास्तव में Git में ऐसा करने का कोई अच्छा तरीका नहीं है?
krlmlr

@krlmlr no: करने के लिए सबसे अच्छा है git checkout HEAD -- <path>, और फिर उन निर्देशिकाओं को हटा दें जिन्हें पुनर्स्थापित किया गया था (लेकिन जो अभी भी विरल चेकआउट में घोषित किए गए हैं)।
VonC

126

Git डेवलपर Duy Nguyen के अनुसार, जिन्होंने कृपया इस सुविधा और एक संगतता स्विच को लागू किया है , निम्नलिखित कार्य G 1.8 % के अनुसार अपेक्षित हैं :

git checkout -- a

( aवह निर्देशिका जहां आप हार्ड-रीसेट करना चाहते हैं)। मूल व्यवहार के माध्यम से पहुँचा जा सकता है

git checkout --ignore-skip-worktree-bits -- a

5
Git विकास टीम के साथ आपके प्रयास के लिए धन्यवाद, Git में यह परिवर्तन हुआ।
डेन क्रूज़

13
और ध्यान दें कि "एक" इस मामले साधन में निर्देशिका आपको वापसी करना चाहते हैं, इसलिए यदि आप निर्देशिका आप वापस करना चाहते हैं कर रहे हैं, आदेश होना चाहिए git checkout -- .जहां .साधन वर्तमान निर्देशिका।
TheWestIsThe ...

5
मेरी ओर से एक टिप्पणी यह ​​है कि आपको पहले फ़ोल्डर को खोलना होगा git reset -- a(जहां एक निर्देशिका जिसे आप रीसेट करना चाहते हैं)
बोयेन

क्या यह भी सच नहीं है अगर आप git reset --hardपूरे रेपो को चाहते हैं?
krlmlr

और अगर आपने उस डायरेक्टरी में कोई नई फाइल जोड़ी है, तो rm -rf aपहले करें।
टोबियास फील

30

बदलने की कोशिश करें

git checkout -- a

सेवा

git checkout -- `git ls-files -m -- a`

संस्करण 1.7.0 के बाद से, Git ने स्किप-वर्कट्री ध्वज का सम्मान कियाls-files

अपने परीक्षण स्क्रिप्ट को चलाने (कुछ मामूली बदलावों के साथ git commit... आउटपुट के लिए ) git commit -qऔर :git statusgit status --short

Initialized empty Git repository in /home/user/repo/.git/
After read-tree:
a/a/aa
a/b/ab
b/a/ba
After modifying:
b/a/ba
 D a/a/aa
 D a/b/ab
 M b/a/ba
After checkout:
 M b/a/ba
a/a/aa
a/c/ac
a/b/ab
b/a/ba

प्रस्तावित checkoutपरिवर्तन आउटपुट के साथ अपना परीक्षण स्क्रिप्ट चलाना :

Initialized empty Git repository in /home/user/repo/.git/
After read-tree:
a/a/aa
a/b/ab
b/a/ba
After modifying:
b/a/ba
 D a/a/aa
 D a/b/ab
 M b/a/ba
After checkout:
 M b/a/ba
a/a/aa
a/b/ab
b/a/ba

बढ़िया है। लेकिन git checkoutपहली जगह में "स्किप-वर्कट्री" बिट का सम्मान नहीं करना चाहिए ?
krlmlr

की एक त्वरित समीक्षा checkout.cऔर tree.cप्रकट नहीं करती है कि स्किप-वर्कट्री ध्वज का उपयोग किया जाता है।
डैन क्रूज़

यह अभ्यास में उपयोगी होने के लिए पर्याप्त सरल है, भले ही मुझे इस आदेश के लिए बैश उपनाम स्थापित करना होगा। Duy Nguyen ने Git mailing लिस्ट में मेरे संदेश का जवाब दिया है, आइए देखें कि क्या अधिक उपयोगकर्ता के अनुकूल विकल्प जल्द ही पॉप हो जाएगा।
krlmlr

18

केवल परिवर्तनों को त्यागने के मामले के लिए, git checkout -- path/याgit checkout HEAD -- path/ अन्य उत्तरों द्वारा सुझाए गए आदेश महान काम करते हैं। हालाँकि, जब आप HEAD के अलावा किसी संशोधन को निर्देशिका को रीसेट करना चाहते हैं, तो उस समाधान में एक महत्वपूर्ण समस्या है: यह उन फ़ाइलों को नहीं हटाता है जिन्हें लक्ष्य संशोधन में हटा दिया गया था।

इसलिए इसके बजाय, मैंने निम्नलिखित कमांड का उपयोग करना शुरू कर दिया है:

git diff --cached commit -- subdir | git apply -R --index

यह टारगेट कमिट और इंडेक्स के बीच के अंतर का पता लगाकर काम करता है, फिर उस डिफरेंस को वर्किंग डायरेक्टरी और इंडेक्स में बदल देता है। मूल रूप से, इसका मतलब है कि यह सूचकांक की सामग्री को आपके द्वारा निर्दिष्ट संशोधन की सामग्री से मेल खाता है। git diffपथ तर्क लेने वाला तथ्य आपको इस प्रभाव को एक विशिष्ट फ़ाइल या निर्देशिका तक सीमित करने की अनुमति देता है।

चूंकि यह आदेश काफी लंबा है और मैं इसे अक्सर उपयोग करने की योजना बना रहा हूं, मैंने इसके लिए एक उपनाम स्थापित किया है जिसे मैंने नाम दिया है reset-checkout:

git config --global alias.reset-checkout '!f() { git diff --cached "$@" | git apply -R --index; }; f'

आप इसे इस तरह से उपयोग कर सकते हैं:

git reset-checkout 451a9a4 -- path/to/directory

या केवल:

git reset-checkout 451a9a4

मैंने कल आपकी टिप्पणी देखी और आज प्रयोग किया। आपका उपनाम मददगार है। +1
वॉनसी

यह विकल्प कैसे git checkout --overlay HEAD -- <path>आदेश देता है कि @VonC उसके उत्तर में उल्लेख करता है?
एहतेश चौधरी

1
@EesheshChoudhury ध्यान दें कि git checkout --overlay HEAD -- <path>अभी तक जारी नहीं किया गया है (Git 2.22 को Q2 2019 में जारी किया जाएगा)
VonC

5

मैं यहाँ एक भयानक विकल्प पेश करने जा रहा हूँ, क्योंकि मुझे नहीं पता कि कैसे git के सिवाय कुछ भी करना है add commitऔर push, यहाँ बताया गया है कि कैसे मैं एक "" वापस "उपनिर्देशिका:

मैंने अपने स्थानीय पीसी पर एक नया रिपॉजिटरी शुरू किया, उस पूरी चीज़ को वापस कर दिया जिस पर मैं कोड कॉपी करना चाहता था और फिर उन फाइलों को मेरी वर्किंग डायरेक्टरी, add commit pushएट वॉयला पर कॉपी कर दिया । खिलाड़ी से नफरत मत करो, हम सभी से ज्यादा चालाक होने के लिए मिस्टर टोरवाल्ड्स से नफरत करते हैं।


4

एक रीसेट सामान्य रूप से सब कुछ बदल देगा, लेकिन आप git stashजो आप रखना चाहते हैं, उसे चुनने के लिए उपयोग कर सकते हैं । जैसा कि आपने उल्लेख किया है, stashएक पथ को सीधे स्वीकार नहीं करता है, लेकिन इसका उपयोग अभी भी --keep-indexध्वज के साथ एक विशिष्ट पथ रखने के लिए किया जा सकता है । आपके उदाहरण में, आप b डायरेक्टरी को स्‍टैश करेंगे, फिर बाकी सब को रीसेट कर देंगे।

# How to make files a/* reappear without changing b and without recreating a/c?
git add b               #add the directory you want to keep
git stash --keep-index  #stash anything that isn't added
git reset               #unstage the b directory
git stash drop          #clean up the stash (optional)

यह आपको एक ऐसे बिंदु पर ले जाता है, जहां आपकी स्क्रिप्ट का अंतिम भाग इसे आउटपुट करेगा:

After checkout:
# On branch master
# Changes not staged for commit:
#
#   modified:   b/a/ba
#
no changes added to commit (use "git add" and/or "git commit -a")
a/a/aa
a/b/ab
b/a/ba

मेरा मानना ​​है कि यह लक्ष्य परिणाम था (बी संशोधित किया गया है, एक / * फाइलें वापस आ गई हैं, एक / सी को फिर से बनाया नहीं गया है)।

यह दृष्टिकोण बहुत लचीला होने का अतिरिक्त लाभ है; आप एक निर्देशिका में विशिष्ट फ़ाइलों को जोड़ना चाहते हैं, लेकिन अन्य लोगों को नहीं, जैसा कि आप ठीक-ठीक प्राप्त कर सकते हैं।


यह अच्छा है, लेकिन मुझे git addछोड़कर सब कुछ करना होगा a, है ना? व्यवहार में कठिन लगता है।
krlmlr

1
@krlmlr वास्तव में नहीं। आप कर सकते हैं git add .तो git reset aके अलावा सब कुछ जोड़ने के लिए a
जोनाथन व्रन

1
@krlmlr इसके अलावा, यह ध्यान देने योग्य है कि git addहटाई गई फ़ाइलों को नहीं जोड़ता है। इसलिए, यदि आप केवल हटाई गई फ़ाइलों को पुनर्प्राप्त कर रहे हैं, तो git add .सभी संशोधित फ़ाइलें जोड़ देंगे, लेकिन हटाए गए नहीं।
जोनाथन व्रन

3

यदि उपनिर्देशिका का आकार विशेष रूप से विशाल नहीं है, और आप सीएलआई से दूर रहना चाहते हैं, तो यहां उप-निर्देशिका को मैन्युअल रूप से रीसेट करने का एक त्वरित समाधान है :

  1. मास्टर शाखा में स्विच करें और रीसेट करने के लिए उप-निर्देशिका की प्रतिलिपि बनाएँ।
  2. अब अपनी सुविधा शाखा में वापस जाएँ और उप-निर्देशिका को उस प्रति के साथ प्रतिस्थापित करें जिसे आपने अभी चरण 1 में बनाया था।
  3. परिवर्तन करें।

चीयर्स। आप बस मैन्युअल रूप से अपनी सुविधा शाखा में उप-निर्देशिका को मास्टर शाखा के समान रीसेट करें !!


मुझे इस उत्तर के लिए कोई वोट नहीं मिला, लेकिन कभी-कभी यह सफलता का सबसे सरल गारंटी मार्ग है।
मुकदमा

1

Ajedi32 का उत्तर वह है जिसे मैं ढूंढ रहा था लेकिन कुछ कमिट के लिए मैं इस त्रुटि में भाग गया:

error: cannot apply binary patch to 'path/to/directory' without full index line

हो सकता है क्योंकि निर्देशिका की कुछ फाइलें बाइनरी फाइलें हैं। Git diff कमांड में '--binary' विकल्प को जोड़ने पर इसे ठीक किया जाता है:

git diff --binary --cached commit -- path/to/directory | git apply -R --index

0

व्हाट अबाउट

subdir=thesubdir
for fn in $(find $subdir); do
  git ls-files --error-unmatch $fn 2>/dev/null >/dev/null;
  if [ "$?" = "1" ]; then
    continue;
  fi
  echo "Restoring $fn";
  git show HEAD:$fn > $fn;
done 
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.