क्या Git में फ़ाइलों को स्थानांतरित करना / उनका नाम बदलना और उनका इतिहास बनाए रखना संभव है?


667

मैं इसका नाम बदलकर Git में एक प्रोजेक्ट सबट्री का नाम बदलना / स्थानांतरित करना चाहूंगा

/project/xyz

सेवा

/components/xyz

अगर मैं एक सादे का उपयोग करता हूं git mv project components, तो सभी इतिहास xyz projectखो जाता है। क्या इस तरह से आगे बढ़ने का एक तरीका है कि इतिहास को बनाए रखा जाए?



2
मैं केवल यह नोट करना चाहता हूं कि मैंने फाइलसिस्टम के माध्यम से चलती फाइलों का परीक्षण किया, और (intellij के माध्यम से) कमिट करने के बाद मैं इतिहास को देखने के बाद पूरे इतिहास (इतिहास सहित जब यह एक अलग स्थान पर था) को फिर से देख सकता हूं (फिर से इंटेलीज में)। मुझे लगता है कि intellij ऐसा करने के लिए विशेष रूप से कुछ खास नहीं कर रहा है, इसलिए यह जानकर बहुत अच्छा लगा कि बहुत कम से कम इतिहास का पता लगाया जा सकता है।
बीटी

एक निर्देशिका का नाम बदलने पर Git द्वारा अनुसरण किए गए नियमों के लिए, नीचे मेरा जवाब देखें
VONC

मैंने यहाँ एक उत्तर लिखा। मैं आशा करता हूँ यह काम करेगा। stackoverflow.com/questions/10828267/…
महमुत एफे

जवाबों:


651

Git कमिट के साथ संचालन को बनाए रखने के बजाय नाम का पता लगाता है, इसलिए चाहे आप उपयोग करें git mvया mvकोई फर्क नहीं पड़ता।

logआदेश एक लेता --followतर्क यह है कि एक नाम बदलने की कार्रवाई से पहले इतिहास जारी है, यानी, यह ऐसी कोई भी सामग्री heuristics का उपयोग कर खोज करता है:

http://git-scm.com/docs/git-log

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

git log --follow ./path/to/file

63
मुझे संदेह है कि यह प्रदर्शन पर विचार है। यदि आपको पूर्ण इतिहास की आवश्यकता नहीं है, तो यह सुनिश्चित करेगा कि सामग्री को स्कैन करने में अधिक समय लगेगा। सबसे आसान तरीका है, एक उपनाम सेट करना git config alias.logf "log --follow"और बस लिखना git logf ./path/to/file
ट्रॉल्स थॉमसन

13
@TroelsThomsen इस उत्तर से जुड़े लिनुस टॉर्वाल्ड्स के इस ई-मेल से संकेत मिलता है कि यह Git का एक जानबूझकर डिजाइन विकल्प है क्योंकि यह नाम बदलने आदि की तुलना में कथित रूप से बहुत अधिक शक्तिशाली है
एमिल लुंडबर्ग

127
यह जवाब थोड़ा भ्रामक है। गिट "नाम का पता लगाता है", लेकिन खेल में बहुत देर हो चुकी है; सवाल यह पूछ रहा है कि आप गिट ट्रैक के नाम को कैसे सुनिश्चित करते हैं, और इसे पढ़ने वाला कोई भी व्यक्ति आसानी से यह अनुमान लगा सकता है कि गिट उन्हें आपके लिए स्वचालित रूप से पता लगाता है और इसे नोट करता है। ऐसा नहीं होता। Git का नाम बदलने का कोई वास्तविक नियंत्रण नहीं है, और इसके बजाय मर्ज / लॉग टूल हैं जो यह पता लगाने का प्रयास करते हैं कि क्या हुआ - और शायद ही कभी इसे सही मिलता है। लिनस का एक गलत लेकिन तुष्टिकरण का तर्क है कि जीआईटी को कभी भी सही तरीके से नहीं करना चाहिए और स्पष्ट रूप से नाम बदलें। तो, हम यहाँ फंस गए हैं।
क्रिस मोशचिनी

29
महत्वपूर्ण: यदि आप एक निर्देशिका का नाम बदलते हैं, उदाहरण के लिए, जावा पैकेज का नाम बदलने के दौरान, दो कमिट निष्पादित करना सुनिश्चित करें, पहला 'git mv {पुराना} {नया}' कमांड के लिए, सभी जावा फ़ाइलों के अपडेट के लिए दूसरा जो संदर्भ को संदर्भित करता है। पैकेज निर्देशिका को बदल दिया। अन्यथा git --follow पैरामीटर के साथ भी व्यक्तिगत फ़ाइलों को ट्रैक नहीं कर सकता है।
nn4l

44
हालांकि लिनुस शायद बहुत कम गलतियाँ करता है, यह एक प्रतीत होता है। बस एक फ़ोल्डर का नाम बदलने से एक विशाल डेल्टा GitHub पर अपलोड होने का कारण बनता है। जो मुझे अपने फ़ोल्डर्स का नाम बदलने के बारे में सतर्क करता है ... लेकिन यह एक प्रोग्रामर के लिए एक बहुत बड़ी सीधी जैकेट है। कभी-कभी, मुझे किसी चीज़ के अर्थ को फिर से परिभाषित करना या चीजों को कैसे वर्गीकृत किया जाता है, इसे बदलना होगा। लिनुस: "दूसरे शब्दों में, मैं सही हूं। मैं हमेशा सही हूं, लेकिन कभी-कभी मैं अन्य समय की तुलना में अधिक सही हूं। टीएम)। " ... मुझे उस पर अपना संदेह है।
गाबे हेल्समर

94

यह है संभव फ़ाइल का नाम बदलने और इतिहास बनाए रखने के लिए, हालांकि यह फ़ाइल भंडार के पूरे इतिहास में नाम बदलने की कारण बनता है। यह शायद केवल जुनूनी गिट-लॉग-प्रेमियों के लिए है, और इनमें कुछ गंभीर निहितार्थ भी शामिल हैं:

  • आप एक साझा इतिहास को फिर से लिख सकते हैं, जो कि Git का उपयोग करते समय सबसे महत्वपूर्ण DON'T नहीं है। यदि किसी और ने रिपॉजिटरी पर क्लोन किया है, तो आप इसे ऐसा करते हुए तोड़ देंगे। सिरदर्द से बचने के लिए उन्हें फिर से क्लोन करना होगा। यह ठीक हो सकता है यदि नाम काफी महत्वपूर्ण है, लेकिन आपको इस पर सावधानी से विचार करने की आवश्यकता होगी - आप संपूर्ण ओपनसोर्स समुदाय को परेशान कर सकते हैं!
  • यदि आपने पुराने इतिहास में पुराने नाम का उपयोग करके फ़ाइल को संदर्भित किया है, तो आप प्रभावी रूप से पुराने संस्करणों को तोड़ रहे हैं। यह उपाय करने के लिए, आपको थोड़ा अधिक कूद कूद करना होगा। यह असंभव नहीं है, बस थकाऊ और संभवतः इसके लायक नहीं है।

अब, चूंकि आप अभी भी मेरे साथ हैं, आप एक अकेले एकल डेवलपर हैं जो पूरी तरह से अलग फ़ाइल का नाम बदल रहा है। चलो एक फ़ाइल का उपयोग कर चलते हैं filter-tree!

मान लें कि आप किसी फ़ाइल oldको किसी फ़ोल्डर में स्थानांतरित करने जा रहे हैं dirऔर उसे नाम देंnew

यह किया जा सकता है git mv old dir/new && git add -u dir/new, लेकिन जो इतिहास को तोड़ता है।

बजाय:

git filter-branch --tree-filter 'if [ -f old ]; then mkdir dir && mv old dir/new; fi' HEAD

प्रत्येक पुनरावृत्ति के लिए टिक्स में कमांड निष्पादित करते हुए, शाखा में हर कमिट को फिर से करेगा । ऐसा करने पर बहुत सारी चीजें गलत हो सकती हैं। मैं आम तौर पर यह देखने के लिए परीक्षण करता हूं कि क्या फ़ाइल मौजूद है (अन्यथा इसे स्थानांतरित करने के लिए अभी तक नहीं है) और फिर मेरी पसंद के अनुसार पेड़ को जूता करने के लिए आवश्यक कदम उठाएं। यहाँ आप फाइल के संदर्भ में परिवर्तन करने के लिए फ़ाइलों के माध्यम से sed कर सकते हैं। अपने आप को बाहर करना! :)

पूर्ण होने पर, फ़ाइल ले जाया जाता है और लॉग बरकरार है। आप एक निंजा समुद्री डाकू की तरह लग रहा है।

इसके अलावा, यदि आप फ़ाइल को नए फ़ोल्डर में ले जाते हैं, तो mkdir dir केवल आवश्यक है। अगर पहले के इतिहास में इस फ़ोल्डर के निर्माण से बचने जाएगा की तुलना में अपने फ़ाइल मौजूद है।


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

7
@Vincent आप बिलकुल सही हैं, और मैंने इस समाधान के बारे में जितना हो सके उतना स्पष्ट होने की कोशिश की। मुझे भी लगता है कि हम इस मामले में "इतिहास" शब्द के दो अर्थों के बारे में बात कर रहे हैं, मैं दोनों की सराहना करता हूं।
14ystein Steimler

6
मुझे लगता है कि ऐसी परिस्थितियाँ हैं जहाँ किसी को इसकी आवश्यकता हो सकती है। कहो कि मैंने अपनी व्यक्तिगत शाखा में कुछ विकसित किया है, जिसे अब मैं ऊपर की तरफ मिलाना चाहता हूं। लेकिन मुझे पता है, फ़ाइल नाम उपयुक्त नहीं है, इसलिए मैं इसे अपनी पूरी व्यक्तिगत शाखा के लिए बदल देता हूं। इस तरह मैं एक साफ-सुथरा उचित इतिहास रख सकता हूं और शुरू से इसका सही नाम है।
user2291758

3
@ user2291758 मेरा उपयोग मामला है। ये अधिक शक्तिशाली git कमांड खतरनाक होते हैं लेकिन इसका मतलब यह नहीं है कि आपके पास बहुत आकर्षक उपयोग के मामले नहीं हैं यदि आप जानते हैं कि आप क्या कर रहे हैं!
फिलीपि

1
यदि संभव हो, तो --index-filterनाम बदलने के लिए उपयोग करना बहुत तेज़ होगा क्योंकि पेड़ को हर कमिट पर चेक आउट और बैक नहीं करना होगा। --index-filterप्रत्येक प्रतिबद्ध सूचकांक पर सीधे कार्य करता है।
थॉमस गुयोट-सायननेस्ट

87

नहीं।

संक्षिप्त उत्तर सं है । गिट में एक फ़ाइल का नाम बदलना और इतिहास को याद रखना संभव नहीं है। और यह एक दर्द है।

अफवाह में यह है कि git log --follow--find-copies-harderकाम करेगा, लेकिन यह मेरे लिए काम नहीं करता है, भले ही फ़ाइल सामग्री में शून्य परिवर्तन हो, और चाल के साथ बनाया गया हो git mv

(शुरू में मैंने एक ऑपरेशन में पैकेजों का नाम बदलने और अपडेट करने के लिए एक्लिप्स का इस्तेमाल किया था, जो शायद गिट को भ्रमित कर सकता है। लेकिन ऐसा करना एक बहुत ही सामान्य बात है। --followऐसा लगता है कि केवल एक mvप्रदर्शन किया जाता है और फिर ए commitऔर mvबहुत दूर नहीं है।

लिनुस का कहना है कि आपको सॉफ्टवेयर प्रोजेक्ट की संपूर्ण सामग्री को समग्र रूप से समझने की आवश्यकता है, व्यक्तिगत फ़ाइलों को ट्रैक करने की आवश्यकता नहीं है। खैर, दुख की बात है कि मेरा छोटा दिमाग ऐसा नहीं कर सकता है।

यह वास्तव में कष्टप्रद है कि इतने सारे लोगों ने मन से इस कथन को दोहराया है कि गिट स्वचालित रूप से चालें चलता है। उन्होंने मेरा समय बर्बाद किया है। Git ऐसी कोई बात नहीं करता है। डिजाइन (!) द्वारा चाल बिल्कुल भी ट्रैक नहीं करती है।

मेरा समाधान फ़ाइलों को उनके मूल स्थानों पर वापस नाम देना है। स्रोत नियंत्रण फिट करने के लिए सॉफ़्टवेयर बदलें। Git के साथ आपको बस पहली बार "git" करने की आवश्यकता प्रतीत होती है।

दुर्भाग्य से, यह ग्रहण को तोड़ता है, जो उपयोग करने के लिए लगता है --followgit log --followकभी-कभी जटिल नाम बदलने वाले इतिहास के साथ फ़ाइलों का पूरा इतिहास नहीं दिखाते हैं git log। (मुझे नहीं पता क्यों।)

(कुछ बहुत चालाक हैक हैं जो वापस जाते हैं और पुराने काम को फिर से जोड़ते हैं, लेकिन वे भयावह हैं। GitHub- Gist देखें: एमिलर / git-mv-with-history ।)


2
मुझे लगता है आप सही हैं। मैं अपने Laravel 5 प्रोजेक्ट के लिए स्रोत को पुन: स्वरूपित करने के लिए php-cs-fixer का उपयोग करने की कोशिश कर रहा था, लेकिन यह ऐप फ़ोल्डर के लोअरकेस मान का मिलान करने के लिए नेमस्पेस क्लॉस के कैपिटलाइज़ेशन को बदलने पर जोर देता है। लेकिन नामस्थान (या संगीतकार ऑटोलॉड्स) केवल कैमलकेस के साथ काम करते हैं। मुझे फ़ोल्डर के कैपिटलाइज़ेशन को ऐप में बदलने की आवश्यकता है लेकिन इससे मेरे परिवर्तन खो जाते हैं। यह उदाहरणों में सबसे तुच्छ है, लेकिन दिखाता है कि कैसे git अनुमानी नाम परिवर्तन के सबसे सरल का भी पालन करने में सक्षम नहीं है (--follow और --find-प्रतियां-नियम नियम होना चाहिए, अपवाद नहीं)।
ज़ैक मॉरिस

6
git -1, तोड़फोड़ +1
कोस्मिन

क्या यह अभी भी सच है? यही कारण है कि मेरे लिए अब tfs के साथ रहने के लिए, एक स्थानांतरित / नामांकित फ़ाइल के इतिहास को रखना एक बड़ी परियोजना में होना चाहिए।
सेसर

@ केसर यदि "इतिहास को याद रखें" से उनका तात्पर्य है, "लॉग देखने के दौरान नाम बदलें" (जो कि एकमात्र उपयोगी चीज है जिसे हमें ध्यान देना चाहिए), तो यह कभी भी सच नहीं था ! गिट का नाम "रिकॉर्ड" नहीं है, लेकिन उपकरण आसानी से उनका पता लगा सकते हैं और हमें नाम और चाल के साथ प्रस्तुत कर सकते हैं। यदि किसी के लिए "यह काम नहीं करता है", तो उसे अपने द्वारा उपयोग किए जा रहे उपकरणों को बदलना चाहिए। बहुत सारे अद्भुत गिट GUI हैं जिनमें यह क्षमता है।
मोहम्मद देहघन

छोटा जवाब हां है। Git current version "git log --follow" को भी सपोर्ट करता है। और मैं
लिखूंगा

42
git log --follow [file]

नाम बदलने के माध्यम से आपको इतिहास दिखाएगा।


29
ऐसा प्रतीत होता है कि फ़ाइल को संशोधित करने से पहले आपको केवल नाम बदलने की आवश्यकता है। यदि आप फ़ाइल (शेल में) को स्थानांतरित करते हैं और फिर इसे बदलते हैं, तो सभी दांव बंद हो जाते हैं।
योयो

22
@ योयो: ऐसा इसलिए है क्योंकि गिट नाम बदलने पर नज़र नहीं रखता है, यह उन्हें पता लगाता है। एक git mvमूल रूप से एक करता है git rm && git add। 90% समान होने पर फ़ाइल का नाम बदलने पर विचार करने के लिए -M90/ जैसे विकल्प --find-renames=90हैं।
vdboor

22

मैं करता हूँ:

git mv {old} {new}
git add -u {new}

3
-U मुझे कुछ भी नहीं लगता है, क्या यह इतिहास को अद्यतन करने के लिए माना जाता है?
जेरेमी

1
शायद आप -Aइसके बजाय व्यवहार चाहते हैं ? फिर से, यहाँ देखें: git-scm.com/docs/git-add
James M. Greene

1
यह फ़ाइलों को जोड़ता है, हालांकि यह इतिहास को अपडेट नहीं करता है ताकि 'git लॉग फाइल नाम' पूरा इतिहास दिखाता है। यदि आप अभी भी --follow विकल्प का उपयोग करते हैं तो यह केवल पूर्ण इतिहास दिखाता है।
जेरेमी

3
मैंने एक जटिल रिफ्लेक्टर किया जिसमें एक डायरेक्टरी शामिल थी (mv का उपयोग करते हुए, gv mv का नहीं) और फिर बदले हुए फ़ाइलों में बहुत सारे #include रास्तों को बदल दिया। git को इतिहास को ट्रैक करने के लिए पर्याप्त समानता नहीं मिली। लेकिन git add -u सिर्फ वह चीज थी जिसकी मुझे जरूरत थी। git स्टेटस अब "बदला हुआ" इंगित करता है जहां पहले "हटाए गए" और "नई फ़ाइल" दिखाया गया था।
एंडीजोस्ट

1
एसओ पर बहुत सारे सवाल हैं जो उद्देश्य को संबोधित करते हैं git add -u। Git डॉक्स अनहेल्दी होते हैं, और अंतिम स्थान है जो मैं देखना चाहता हूं। यहां एक पोस्ट दिखाया जा git add -uरहा है: stackoverflow.com/a/2117202
17

17

मैं इसका नाम बदलकर Git में एक प्रोजेक्ट सबट्री का नाम बदलना / स्थानांतरित करना चाहूंगा

/project/xyz

सेवा

/ घटकों / xyz

यदि मैं एक सादे का उपयोग करता हूं git mv project components, तो xyzपरियोजना के लिए सभी प्रतिबद्ध इतिहास खो जाता है।

नहीं (8 साल बाद, Git 2.19, Q3 2018), क्योंकि Git डायरेक्टरी नाम का पता लगा लेगा , और यह अब प्रलेखित है।

देखें प्रतिबद्ध b00bf1c , 1634688 , कमिटमेंट 0661e49 , 4d34dff कमिटमेंट , 983f464 कमिटमेंट , c840e1a कमिटमेंट , 9929430 (27 जून 2018), और d4e8062 कमिट करें , 5dacd4a (25 जून 2018) Elijah Newrennewren द्वारा ( )
( जूनियो सी gitsterहमानो द्वारा विलय - - में 0ce5a69 , 24 जुलाई 2018)

अब इसमें समझाया गया है Documentation/technical/directory-rename-detection.txt:

उदाहरण:

जब सभी x/a, x/bऔर x/cमें चले गए हैं z/a, z/bऔर z/c, यह संभावना है कि x/dइस बीच में जोड़ा गया है कि यह भी z/dसंकेत है कि पूरी निर्देशिका ' x' के लिए ले जाया गया 'ले जाना zचाहते हैं।

लेकिन वे कई अन्य मामले हैं, जैसे:

इतिहास का एक पक्ष नाम बदल जाता है x -> z, और दूसरा कुछ फ़ाइल का नाम बदल देता है x/e, जिससे मर्ज की आवश्यकता एक सकर्मक नाम बदलने की होती है।

निर्देशिका नाम का पता लगाने को आसान बनाने के लिए, उन नियमों को Git द्वारा लागू किया जाता है:

एक नया बुनियादी नियम सीमा जब निर्देशिका का पता लगाने का नाम लागू होता है:

  1. यदि किसी दी गई निर्देशिका अभी भी मर्ज के दोनों ओर मौजूद है, तो हम इसका नाम बदला हुआ नहीं मानते हैं।
  2. यदि नाम बदलने वाली फ़ाइलों के सबसेट के पास रास्ते में एक फ़ाइल या निर्देशिका है (या एक दूसरे के रास्ते में होगी), उन विशिष्ट उप-पथों के लिए निर्देशिका का नाम बदलकर "बंद करें" और उपयोगकर्ता को संघर्ष की रिपोर्ट करें ।
  3. यदि इतिहास के दूसरे पक्ष ने एक निर्देशिका का नाम बदलकर उस पथ का नाम बदल दिया है, जो इतिहास के आपके पक्ष का नाम बदलकर किया गया है, तो किसी भी अंतर्निहित निर्देशिका के नाम के लिए इतिहास के दूसरे पक्ष से उस विशेष नाम को अनदेखा करें (लेकिन उपयोगकर्ता को चेतावनी दें)।

आप बहुत सारे परीक्षण देख सकते हैं t/t6043-merge-rename-directories.sh, जो यह भी बताते हैं कि:

  • क) अगर नाम एक निर्देशिका को दो या दो से अधिक अन्य में विभाजित करता है, तो सबसे अधिक नाम वाले निर्देशिका, "जीत"।
  • ख) किसी पथ के लिए निर्देशिका-नाम-पता लगाने से बचें, यदि वह मार्ग किसी मर्ज के दोनों ओर नाम बदलने का स्रोत है।
  • ग) यदि केवल इतिहास के दूसरे पक्ष का नाम बदलकर कर रहे हैं, तो निहित निर्देशिका नामों पर लागू होता है।

15

उद्देश्य

  • का प्रयोग करें (से प्रेरित Smar , से उधार Exherbo )git am
  • कॉपी / स्थानांतरित फ़ाइलों की प्रतिबद्ध इतिहास जोड़ें
  • एक डायरेक्टरी से दूसरी में
  • या एक रिपॉजिटरी से दूसरे में

सीमा

  • टैग और शाखाएँ नहीं रखी जाती हैं
  • इतिहास पथ फ़ाइल नाम (निर्देशिका नाम बदलें) पर कट जाता है

सारांश

  1. ईमेल प्रारूप का उपयोग करके इतिहास निकालें
    git log --pretty=email -p --reverse --full-index --binary
  2. फ़ाइल ट्री को पुनर्गठित करें और फ़ाइल नाम अपडेट करें
  3. नए इतिहास का उपयोग कर जोड़ें
    cat extracted-history | git am --committer-date-is-author-date

1. ईमेल प्रारूप में इतिहास निकालें

उदाहरण: का इतिहास निकालें file3, file4औरfile5

my_repo
├── dirA
│   ├── file1
│   └── file2
├── dirB            ^
│   ├── subdir      | To be moved
│   │   ├── file3   | with history
│   │   └── file4   | 
│   └── file5       v
└── dirC
    ├── file6
    └── file7

गंतव्य सेट / साफ़ करें

export historydir=/tmp/mail/dir       # Absolute path
rm -rf "$historydir"    # Caution when cleaning the folder

ईमेल प्रारूप में प्रत्येक फ़ाइल का इतिहास निकालें

cd my_repo/dirB
find -name .git -prune -o -type d -o -exec bash -c 'mkdir -p "$historydir/${0%/*}" && git log --pretty=email -p --stat --reverse --full-index --binary -- "$0" > "$historydir/$0"' {} ';'

दुर्भाग्य से विकल्प --followया --find-copies-harderके साथ जोड़ा नहीं जा सकता --reverse। यही कारण है कि जब फ़ाइल का नाम बदला जाता है (या जब एक मूल निर्देशिका का नाम बदला जाता है) तो इतिहास कट जाता है।

ईमेल प्रारूप में अस्थायी इतिहास:

/tmp/mail/dir
    ├── subdir
    │   ├── file3
    │   └── file4
    └── file5

Dan Bonachea इस पहले चरण में git लॉग जनरेशन कमांड के छोरों को पलटने का सुझाव देता है: प्रति फ़ाइल एक बार git लॉग चलाने के बजाय, इसे कमांड लाइन पर फ़ाइलों की सूची के साथ ठीक एक बार चलाएं और एक एकीकृत लॉग जेनरेट करें। यह तरीका बताता है कि परिणाम में एक से अधिक फ़ाइलों को संशोधित करने के लिए एक ही प्रतिबद्ध है, और सभी नए कमिट अपने मूल सापेक्ष क्रम को बनाए रखते हैं। ध्यान दें कि नीचे (अब एकीकृत) लॉग में फ़ाइल नाम को पुन: लिखने पर दूसरे चरण में भी बदलाव की आवश्यकता है।


2. फ़ाइल ट्री को पुनर्गठित करें और फ़ाइल नाम अपडेट करें

मान लीजिए आप इन तीन फाइलों को इस अन्य रेपो में स्थानांतरित करना चाहते हैं (वही रेपो हो सकता है)।

my_other_repo
├── dirF
│   ├── file55
│   └── file56
├── dirB              # New tree
│   ├── dirB1         # from subdir
│   │   ├── file33    # from file3
│   │   └── file44    # from file4
│   └── dirB2         # new dir
│        └── file5    # from file5
└── dirH
    └── file77

इसलिए अपनी फ़ाइलों को पुनर्गठित करें:

cd /tmp/mail/dir
mkdir -p dirB/dirB1
mv subdir/file3 dirB/dirB1/file33
mv subdir/file4 dirB/dirB1/file44
mkdir -p dirB/dirB2
mv file5 dirB/dirB2

आपका अस्थायी इतिहास अब है:

/tmp/mail/dir
    └── dirB
        ├── dirB1
        │   ├── file33
        │   └── file44
        └── dirB2
             └── file5

इतिहास के भीतर फ़ाइल नाम भी बदलें:

cd "$historydir"
find * -type f -exec bash -c 'sed "/^diff --git a\|^--- a\|^+++ b/s:\( [ab]\)/[^ ]*:\1/$0:g" -i "$0"' {} ';'

3. नया इतिहास लागू करें

आपका अन्य रेपो है:

my_other_repo
├── dirF
│   ├── file55
│   └── file56
└── dirH
    └── file77

अस्थायी इतिहास फ़ाइलों से लागू करें:

cd my_other_repo
find "$historydir" -type f -exec cat {} + | git am --committer-date-is-author-date

--committer-date-is-author-dateमूल प्रतिबद्ध समय-टिकटों ( डैन बोनासिया की टिप्पणी) को संरक्षित करता है ।

आपका अन्य रेपो अब है:

my_other_repo
├── dirF
│   ├── file55
│   └── file56
├── dirB
│   ├── dirB1
│   │   ├── file33
│   │   └── file44
│   └── dirB2
│        └── file5
└── dirH
    └── file77

git statusधकेले जाने के लिए तैयार कमिट्स की मात्रा देखने के लिए उपयोग करें :-)


एक्स्ट्रा ट्रिक: अपने रेपो के अंदर बदला हुआ / स्थानांतरित फ़ाइलों की जाँच करें

फ़ाइलों का नाम बदलने के लिए:

find -name .git -prune -o -exec git log --pretty=tformat:'' --numstat --follow {} ';' | grep '=>'

अधिक अनुकूलन: आप git logविकल्पों का उपयोग करके कमांड को पूरा कर सकते हैं --find-copies-harderया --reverse। आप cut -f3-पूर्ण पैटर्न '{*। * =>। *}} का उपयोग करके और पहले वाले दो कॉलम भी निकाल सकते हैं ।

find -name .git -prune -o -exec git log --pretty=tformat:'' --numstat --follow --find-copies-harder --reverse {} ';' | cut -f3- | grep '{.* => .*}'

4
BEWARE: यह तकनीक विभाजन करती है जो 2 या अधिक फाइलों को अलग-अलग खंडित-कमिट में बदल देती है, और इसके बाद फाइलनाम पर छांट कर उनके क्रम को तोड़ देती है (इसलिए एक मूल प्रतिबद्ध के टुकड़े रैखिक इतिहास में आसन्न नहीं दिखाई देते हैं)। इसलिए परिणामी इतिहास फ़ाइल-दर-फ़ाइल आधार पर केवल "सही" है। यदि आप एक से अधिक फ़ाइल ले जा रहे हैं, तो परिणामी इतिहास में कोई भी नया नहीं चलता है, जो कभी-कभी मूल रेपो के इतिहास में मौजूद फ़ाइलों की संगत स्नैपशॉट का प्रतिनिधित्व करता है।
डैन बोनासिया

2
हाय @DanBonachea। आपकी दिलचस्प प्रतिक्रिया के लिए धन्यवाद। मैंने सफलतापूर्वक इस तकनीक का उपयोग करके कई फ़ाइलों वाले कुछ रिपोज़ को माइग्रेट किया है (यहां तक ​​कि नामांकित फ़ाइलों और निर्देशिकाओं में स्थानांतरित फ़ाइलों के साथ)। आप इस उत्तर में क्या बदलने का सुझाव देते हैं। क्या आपको लगता है कि हमें इस तकनीक की सीमाओं को समझाते हुए इस उत्तर के शीर्ष पर एक चेतावनी बैनर जोड़ना चाहिए? चीयर्स
ओलीब्रे

2
मैंने चरण 1 में git लॉग जनरेशन कमांड के छोरों को हटाकर समस्या से बचने के लिए इस तकनीक को अनुकूलित किया। Ie। प्रति फ़ाइल एक बार गिट लॉग चलाने के बजाय, इसे कमांड लाइन पर फ़ाइलों की सूची के साथ एक बार चलाएं और एक एकीकृत लॉग उत्पन्न करें। यह तरीका बताता है कि परिणाम में 2 या अधिक फाइलें संशोधित की गई हैं, और सभी नए कमिट अपने मूल सापेक्ष क्रम को बनाए रखते हैं। नोट यह भी चरण 2 में परिवर्तन की आवश्यकता होती है, जब (अब एकीकृत) लॉग में फाइलनाम को फिर से लिखना। मैंने मूल प्रतिबद्ध टाइमस्टैम्प को संरक्षित करने के लिए git am --committer-date-is-author-date का भी उपयोग किया।
दान बोनाचिया

1
आपके प्रयोग और साझा करने के लिए धन्यवाद। मैंने अन्य पाठकों के लिए उत्तर को थोड़ा अपडेट किया है। हालाँकि मुझे आपकी प्रोसेसिंग का परीक्षण करने में समय लगा है। यदि आप कमांड लाइनों के उदाहरण प्रदान करना चाहते हैं तो कृपया इस उत्तर को संपादित करने के लिए स्वतंत्र महसूस करें। चीयर्स;)
ओलिब्रे

4

मैंने मूल निर्देशिका में कोड ले जाने और इतिहास को बनाए रखने के लिए इस बहु-चरण प्रक्रिया का पालन किया।

चरण 0: सुरक्षित रखने के लिए 'मास्टर' से एक शाखा 'इतिहास' बनाया गया

चरण 1: इतिहास को फिर से लिखने के लिए गिट-फिल्टर-रेपो टूल का इस्तेमाल किया। नीचे दिए गए इस कमांड ने फोल्डर 'FolderwithContentOfInterest' को एक स्तर तक बढ़ा दिया और संबंधित कमिट इतिहास को संशोधित किया

git filter-repo --path-rename ParentFolder/FolderwithContentOfInterest/:FolderwithContentOfInterest/ --force

चरण 2: इस समय तक GitHub रिपॉजिटरी ने अपने दूरस्थ रिपॉजिटरी पथ को खो दिया। जोड़ा गया दूरस्थ संदर्भ

git remote add origin git@github.com:MyCompany/MyRepo.git

चरण 3: रिपॉजिटरी पर जानकारी खींचो

git pull

चरण 4: स्थानीय खोई हुई शाखा को मूल शाखा से कनेक्ट करें

git branch --set-upstream-to=origin/history history

चरण 5: यदि संकेत दिया जाए तो फ़ोल्डर संरचना के लिए पता मर्ज संघर्ष

चरण 6: धक्का !!

git push

नोट: संशोधित इतिहास और स्थानांतरित फ़ोल्डर पहले से ही प्रतिबद्ध हैं। enter code here

किया हुआ। इतिहास को अक्षुण्ण रखते हुए अभिभावक / वांछित निर्देशिका के लिए कोड चलता है!


2

जबकि Git का मुख्य भाग, Git प्लंबिंग का नाम नहीं रखता है, आप जिस इतिहास को Git लॉग "पोर्सिलेन" के साथ प्रदर्शित करते हैं यदि आप चाहें तो उनका पता लगा सकते हैं।

किसी दिए गए git logउपयोग -M विकल्प के लिए:

git लॉग -p -M

Git के वर्तमान संस्करण के साथ।

यह अन्य कमांड के लिए भी काम करता है git diff

तुलनाओं को कम या ज्यादा कठोर बनाने के विकल्प हैं। यदि आप एक ही समय में फ़ाइल में महत्वपूर्ण परिवर्तन किए बिना किसी फ़ाइल का नाम बदलते हैं, तो यह गेट लॉग और दोस्तों के नाम बदलने का पता लगाने में आसान बनाता है। इस कारण से कुछ लोग एक कमेटी में फाइलों का नाम बदलकर दूसरे में बदल देते हैं।

सीपीयू के उपयोग में एक लागत होती है जब भी आप पूछते हैं कि जीआईटी ने कहां फाइलों का नाम बदला है, इसलिए आप इसका उपयोग करते हैं या नहीं, और कब, आप पर निर्भर है।

यदि आप अपने इतिहास को हमेशा एक विशेष रिपॉजिटरी में आपके नाम का पता लगाना चाहते हैं, जिसका आप उपयोग कर सकते हैं:

git config diff.renames १

एक डायरेक्टरी से दूसरी डायरेक्टरी में जाने वाली फाइलों का पता लगाया जाता है। यहाँ एक उदाहरण है:

commit c3ee8dfb01e357eba1ab18003be1490a46325992
Author: John S. Gruber <JohnSGruber@gmail.com>
Date:   Wed Feb 22 22:20:19 2017 -0500

    test rename again

diff --git a/yyy/power.py b/zzz/power.py
similarity index 100%
rename from yyy/power.py
rename to zzz/power.py

commit ae181377154eca800832087500c258a20c95d1c3
Author: John S. Gruber <JohnSGruber@gmail.com>
Date:   Wed Feb 22 22:19:17 2017 -0500

    rename test

diff --git a/power.py b/yyy/power.py
similarity index 100%
rename from power.py
rename to yyy/power.py

कृपया ध्यान दें कि यह काम करता है जब भी आप अंतर का उपयोग कर रहे हैं, न कि केवल साथ git log। उदाहरण के लिए:

$ git diff HEAD c3ee8df
diff --git a/power.py b/zzz/power.py
similarity index 100%
rename from power.py
rename to zzz/power.py

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

 $ git merge -v master
 Auto-merging single
 Merge made by the 'recursive' strategy.
  one => single | 4 ++++
  1 file changed, 4 insertions(+)
  rename one => single (67%)

परिणाम एक कार्यशील निर्देशिका थी जिसका नाम बदला गया था और दोनों पाठ परिवर्तन किए गए थे। इसलिए गिट के लिए यह संभव है कि वह इस तथ्य के बावजूद सही काम करे कि वह नाम बदलने को स्पष्ट रूप से ट्रैक नहीं करता है।

यह एक पुराने प्रश्न का देर से उत्तर है, इसलिए उस समय Git संस्करण के लिए अन्य उत्तर सही हो सकते हैं।


1

पहले एक नाम बदलने के साथ एक स्टैंडअलोन कमिट बनाएं।

फिर अलग-अलग प्रतिबद्ध में रखी गई फ़ाइल सामग्री में कोई भी परिवर्तन।


1

निर्देशिका या फ़ाइल का नाम बदलने के लिए (मुझे जटिल मामलों के बारे में अधिक जानकारी नहीं है, इसलिए कुछ चेतावनी हो सकती है):

git filter-repo --path-rename OLD_NAME:NEW_NAME

फाइलों में एक निर्देशिका का नाम बदलने के लिए जो इसका उल्लेख करते हैं (कॉलबैक का उपयोग करना संभव है, लेकिन मुझे नहीं पता कि कैसे)

git filter-repo --replace-text expressions.txt

expressions.txtएक फाइल है, जैसे लाइनों से भरा है literal:OLD_NAME==>NEW_NAME(यह संभव है कि पायथन की आरई के साथ regex:या ग्लोब के साथ प्रयोग करें glob:)।

आवागमन के संदेशों में एक निर्देशिका का नाम बदलने के लिए:

git-filter-repo --message-callback 'return message.replace(b"OLD_NAME", b"NEW_NAME")'

पायथन की नियमित अभिव्यक्तियों का भी समर्थन किया जाता है, लेकिन उन्हें पायथन में स्वयं लिखा जाना चाहिए।

यदि रिपॉजिटरी मूल है, तो रिमोट के बिना, आपको --forceफिर से लिखने के लिए बाध्य करना होगा । (ऐसा करने से पहले आप अपने रिपॉजिटरी का बैकअप बनाना चाह सकते हैं।)

यदि आप refs को संरक्षित नहीं करना चाहते हैं (वे Git GUI के शाखा इतिहास में प्रदर्शित किए जाएंगे), तो आपको जोड़ना होगा --replace-refs delete-no-add


0

बस फ़ाइल को स्थानांतरित करें और उसके साथ चरणबद्ध करें:

git add .

प्रतिबद्ध होने से पहले आप स्थिति देख सकते हैं:

git status

यह दिखाएगा:

Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
        renamed:    old-folder/file.txt -> new-folder/file.txt

मैंने Git संस्करण 2.26.1 के साथ परीक्षण किया।

GitHub हेल्प पेज से निकाला गया ।


-3

मैं फाइलें घुमाता हूं और फिर करता हूं

git add -A

जो सभी हटाए गए / नई फ़ाइलों को संतृप्त क्षेत्र में रखता है। यहाँ git को पता चलता है कि फ़ाइल ले जाया गया है।

git commit -m "my message"
git push

मुझे नहीं पता क्यों लेकिन यह मेरे लिए काम करता है।


यहां ट्रिक यह है कि आपको एक भी अक्षर नहीं बदलना है, भले ही आप कुछ बदल दें और Ctrl + Z दबाएं, इतिहास टूट जाएगा। एसओ उस मामले में यदि आप कुछ लिखते हैं, तो फ़ाइल को वापस लाते हैं, और इसे फिर से आगे बढ़ाते हैं और इसके लिए एक जोड़-> प्रतिबद्ध करते हैं।
ज़ेलियन २०'१
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.