git क्यों नाम दोष का नाम नहीं बदला?




blame git-blame (2)

$ pwd
/data/mdi2/classes

$ git blame -L22,+1 -- utils.js
99b7a802 mdi2/utils.js (user 2015-03-26 21:54:57 +0200 22)  #comment

$ git blame -L22,+1 99b7a802^ -- utils.js
fatal: no such path mdi2/classes/utils.js in 99b7a802^

जैसा कि आपने देखा है, फ़ाइल उस प्रतिबद्ध में अलग-अलग निर्देशिका में थी

$ git blame -L22,+1 99b7a802^ -- ../utils.js
c5105267 (user 2007-04-10 08:00:20 +0000 22)    #comment 2

डॉक्टर के बावजूद

The origin of lines is automatically followed across whole-file renames (currently there is no option to turn
       the rename-following off)

दोष का नाम नहीं है। क्यूं कर?

अद्यतन: लघु उत्तर

git blame का नाम बदला है लेकिन git blame COMMIT^ -- <filename> लिए नहीं है git blame COMMIT^ -- <filename>

लेकिन यह नाम बदलने और इतिहास के टन के माध्यम से मैन्युअल रूप से फ़ाइल नाम बदलने के लिए बहुत मुश्किल है। मुझे लगता है, इस व्यवहार को चुपचाप जीआईटीई के लिए नाम बदलने के लिए तय किया जाना चाहिए git blame COMMIT^ -- <filename> । या, कम से कम, - --follow लागू किया जाना चाहिए, तो मैं कर सकता हूं: git blame --follow COMMIT^ -- <filename>

UPDATE2: यह असंभव है। नीचे दिया गया पढ़ें।

जूनियो सी हमानो द्वारा मेलवेलिस्ट से उत्तर

git blame का नाम बदला है लेकिन git blame COMMIT^ -- <filename> लिए नहीं है git blame COMMIT^ -- <filename>

मान लें कि आपके पास अपने संस्करण v1.0 में फ़ाइल A और फ़ाइल B है।

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

git blame -C HEAD -- C

दोनों ठीक से सामग्री का पालन कर सकते हैं, लेकिन अगर आपको कहने की अनुमति दी गई थी

git blame v1.0 -- C

इसका क्या मतलब है? C में v1.0 मौजूद नहीं था। क्या आप A की सामग्री का अनुसरण करने के लिए कह रहे हैं, या फिर B? जब आपने इस कमांड में C को बताया तो आपने A को नहीं और B को कैसे बताया?

"गिट दोष" सामग्री आंदोलनों का अनुसरण करता है, और कभी भी किसी भी विशेष तरीके से "नाम" का व्यवहार नहीं करता है, क्योंकि यह सोचना बेवकूफी है कि नाम बदलना किसी तरह से विशेष है;;

जिस तरह से आप बताते हैं कि कमांड से इसकी कमांड लाइन से खुदाई शुरू करने के लिए क्या सामग्री है, प्रारंभिक बिंदु कमिट (HEAD के लिए चूक लेकिन आप COMMIT को अपने उदाहरण के रूप में दे सकते हैं) और उस शुरुआती बिंदु में पथ। जैसा कि सी को गिट को बताने का कोई मतलब नहीं है और फिर जादुई रूप से यह अनुमान लगाते हैं कि आप कुछ मामलों में ए का मतलब है और बी कुछ अन्य में। यदि v1.0 में C नहीं था, तो ऐसा करने के लिए केवल एक समझदार चीज है कि एक अनुमान लगाने के बजाय बाहर निकलें (और उपयोगकर्ता को यह बताए बिना कि यह कैसे हुआ)।


git blame का नाम --follow का अनुसरण करता है (जैसा कि यदि आप इसे देते हैं तो git log करता है)। समस्या इसका नाम बदलने के तरीके में निहित है, जो कि एक बहुत-बहुत-पूरी तरह से हैक नहीं है: जैसा कि यह एक समय में एक प्रतिबद्ध (प्रत्येक बच्चे से प्रत्येक माता-पिता के लिए) कदम रखता है, यह एक अंतर बनाता है - आप कर सकते हैं उसी तरह का एक अलग मैन्युअल रूप से बनाएं:

git diff -M SHA1^ SHA1

-और देखने के लिए जाँचता है कि क्या इस नाम का पता लगाया गया है। 1

यह सब ठीक है जहाँ तक यह जाता है, लेकिन इसका मतलब यह है कि git blame लिए एक नाम का पता लगाने के git blame , (एक) git diff -M यह पता लगाने में सक्षम होना चाहिए (सौभाग्य से यहाँ मामला है) और -यहाँ क्या आप समस्याओं के कारण है —यह नाम बदलना चाहिए।

उदाहरण के लिए, मान लीजिए कि ग्राफ़ कुछ इस तरह दिखता है:

A <-- B <-- ... Q <-- R <-- S <-- T

जहां प्रत्येक अपरकेस अक्षर एक कमिट का प्रतिनिधित्व करता है। आगे मान लीजिए कि कमिट R में एक फ़ाइल का नाम बदल दिया गया था, ताकि T माध्यम से R में उसका newname नाम newname जबकि Q माध्यम से A उसका नाम oldname

यदि आप git blame -- newname , तो अनुक्रम T पर शुरू होता है, S और T तुलना करता है, R और S तुलना करता है, और Q और R तुलना करता है। जब यह Q और R तुलना करता है, तो git blame नाम-परिवर्तन का पता oldname है, और Q और पूर्व के पुराने नाम oldname शुरू कर देता है, इसलिए जब यह P और Q तुलना करता है तो यह उन दो commits में oldname और oldname तुलना करता है।

यदि, दूसरी तरफ, आप git blame R^ -- newname (या git blame Q -- newname ) git blame Q -- newname ताकि अनुक्रम Q पर शुरू हो, तो उस कमिट में कोई newname नहीं है, और तुलना करते समय कोई नाम नहीं है। P और Q , और git blame बस देता है।

चाल यह है कि यदि आप एक ऐसी कमेटी से शुरू कर रहे हैं जिसमें फ़ाइल का पिछला नाम था, तो आपको पुराना नाम देना होगा:

git blame R^ -- oldname

और फिर यह सब फिर से काम करता है।

1 git diff डॉक्यूमेंटेशन में , आप देखेंगे कि एक -M विकल्प है जो यह नियंत्रित करता है कि git diff का नाम कैसे पता चलता है। blame कोड इसे थोड़ा संशोधित करता है (और वास्तव में दो पास करता है, एक -M बंद हो जाता है और दूसरा -M चालू होता है) और कुछ अलग-अलग उद्देश्यों के लिए अपने स्वयं के (अलग) -M विकल्प का उपयोग करता है, लेकिन अंततः इसका उपयोग कर रहा है एक ही कोड।

[टिप्पणी में उत्तर जोड़ने के लिए संपादित करें (स्वयं एक टिप्पणी के रूप में फिट नहीं)]:

क्या कोई उपकरण है जो मुझे फ़ाइल नाम दिखा सकता है जैसे: git renames <filename> SHA date oldname-> newname

बिलकुल नहीं, लेकिन git diff -M करीब आता है, और काफी करीब हो सकता है।

मुझे यकीन नहीं है कि आप यहां "SHA की तारीख" से क्या मतलब है, लेकिन git diff -M आपको दो SHA-1s की आपूर्ति करने और बाएं-बनाम-दाएं की तुलना करने की अनुमति देता है। केवल फ़ाइल नाम और --name-status प्राप्त करने के लिए --name-status जोड़ें। इसलिए git diff -M --name-status HEAD oldsha1 रिपोर्ट कर सकता है कि HEAD से oldsha1 बदलने के लिए, git का मानना ​​है कि आपको एक फ़ाइल को R ename करना चाहिए और पुराने नाम को "नए" नाम से रिपोर्ट करना होगा। उदाहरण के लिए, git रिपॉजिटरी में ही, वर्तमान में एक Documentation/giteveryday.txt नाम की फाइल है, जिसमें थोड़ा अलग नाम होता था:

$ git diff -M --name-status HEAD 992cb206
M       .gitignore
M       .mailmap
[...snip...]
M       Documentation/diff-options.txt
R097    Documentation/giteveryday.txt   Documentation/everyday.txt
D       Documentation/everyday.txto
[...]

यदि वह फ़ाइल जिसकी आपको परवाह है, तो आप अच्छे हैं। यहाँ दो समस्याएं हैं:

  • SHA1 ढूंढना: 992cb206 कहां से आया? यदि आपके पास पहले से ही SHA-1 है, तो यह आसान है; यदि नहीं, तो git rev-list SHA1- खोज उपकरण है; इसका प्रलेखन पढ़ें;
  • और तथ्य यह है कि एक समय में प्रत्येक कमिट के माध्यम से नाम बदलने की एक श्रृंखला के बाद, जैसा कि git blame करता है, बहुत पहले वाले ( 992cb206 / जो भी) के खिलाफ एक बहुत बाद के कमिट ( HEAD ) की तुलना में काफी अलग जवाब दे सकता है। इस मामले में, यह समान है, लेकिन यहां "समानता सूचकांक" 100 में से 97 है। यदि इसे कुछ मध्यवर्ती चरणों में बहुत अधिक संशोधित किया गया होता, तो समानता सूचकांक 50% से नीचे आ सकता है ... फिर भी, अगर हम 992cb206 से 992cb206 ( git blame रूप में) के 992cb206 बाद एक संशोधन की तुलना करने वाले थे, तो शायद उन दो फ़ाइलों के बीच समानता सूचकांक अधिक हो सकता है।

क्या आवश्यक है (और गायब है) git rev-list ही है --follow को कार्यान्वित करने के लिए, ताकि सभी कमांड जो git rev-list आंतरिक रूप से उपयोग --follow यानी, अधिकांश कमांड जो केवल एक से अधिक संशोधन पर काम करते हैं- ट्रिक कर सकते हैं। रास्ते के साथ, यह अच्छा होगा यदि यह दूसरी दिशा में काम करता है (वर्तमान में - अगर यह नया-से-पुराना है, यानी, git blame साथ ठीक काम करता है और git log साथ ठीक काम करता है जब तक आप सबसे पुराना नहीं पूछते हैं। इतिहास के साथ पहले - --reverse )।


नवीनतम git में दिलचस्प कमांड है। अपने कॉन्‍फ़िगर के आगे जोड़ें:

[alias]
    follow= "!sh -c 'git log --topo-order -u -L $2,${3:-$2}:"$1"'" -

अब आप कर सकते हैं:

$git follow <filename> <linefrom> [<lineto>]

और आप प्रत्येक <filename> को देखेंगे जो <filename> में निर्दिष्ट लाइनें बदलती हैं।

इसके अलावा आप git log कमांड के विकल्प में रुचि ले सकते हैं:

नाम से परे एक फ़ाइल के इतिहास को सूचीबद्ध करना जारी रखें (केवल एक फ़ाइल के लिए काम करता है)।

यदि आप प्रतिलिपि खोज उपयोग- -C में रुचि रखते हैं:

प्रतियों का पता लगाने के साथ-साथ नाम बदलें। यह भी देखें - शोध-प्रतियां-कठिन यदि n निर्दिष्ट है, तो इसका अर्थ -M के समान है।

-C एक ही कमिट में अलग-अलग फाइल्स देखेगा। यदि आप यह पता लगाना चाहते हैं कि कोड अलग-अलग फ़ाइल से लिया गया था जिसे इस कमिट में नहीं बदला गया था। फिर आपको --find-copies-harder विकल्प प्रदान करना चाहिए।

प्रदर्शन कारणों से, डिफ़ॉल्ट रूप से, -सी विकल्प केवल तभी प्रतियां पाता है जब कॉपी की मूल फ़ाइल को उसी बदलाव में संशोधित किया गया था। यह ध्वज प्रतिलिपि के स्रोत के लिए उम्मीदवारों के रूप में असंबद्ध फ़ाइलों का निरीक्षण करता है। यह बड़ी परियोजनाओं के लिए एक बहुत महंगा ऑपरेशन है, इसलिए सावधानी के साथ इसका उपयोग करें। एक-से अधिक विकल्प देने का समान प्रभाव होता है।

युपीडी
मैं इस उपनाम में सुधार करता हूं:

[alias]
    follow = "!bash -c '                                                 \
        if [[ $1 == \"/\"* ]]; then                                      \
            FILE=$1;                                                     \
        else                                                             \
            FILE=${GIT_PREFIX}$1;                                        \
        fi;                                                              \
        echo \"git log --topo-order -u -L $2,${3:-$2}:\\\"$FILE\\\"\";   \
        git log --topo-order -u -L $2,${3:-$2}:\"$FILE\";                \
    ' --"

अब आप ट्रैक कर सकते हैं कि लाइनों की निर्दिष्ट सीमा कैसे बदली जाती है:

git follow file_name.c 30 35

सूचना: दुर्भाग्य से गिट कार्य निर्देशिका में परिवर्तन को ध्यान में नहीं रखता है। इस प्रकार यदि आप फाइल में स्थानीय परिवर्तन करते हैं तो आपको बदलावों का follow करने से पहले इसे रोकना होगा





git-blame