git - क्या गिट में फ़ाइलों को स्थानांतरित/पुनर्नामित करना और उनका इतिहास बनाए रखना संभव है?
rename mv (6)
नहीं।
संक्षिप्त जवाब नहीं है , गिट में एक फ़ाइल का नाम बदलना और इतिहास को याद रखना संभव नहीं है। और यह एक दर्द है।
अफवाह यह है कि git log --follow
--find-copies-harder
काम करेगा लेकिन यह मेरे लिए काम नहीं करता है, भले ही फ़ाइल सामग्री में शून्य परिवर्तन हो, और चाल git mv
साथ बनाई गई हो।
(प्रारंभ में मैंने ग्रहण का नाम बदलने और एक ऑपरेशन में पैकेज अपडेट करने के लिए उपयोग किया था, जो भ्रमित गिट हो सकता है। लेकिन यह करना एक बहुत ही आम बात है। - अगर केवल एक mv
किया जाता है और फिर एक commit
और mv
बहुत दूर नहीं है।)
लिनस का कहना है कि आपको व्यक्तिगत रूप से एक सॉफ्टवेयर प्रोजेक्ट की पूरी सामग्री को समझना है, व्यक्तिगत फ़ाइलों को ट्रैक करने की आवश्यकता नहीं है। खैर, दुख की बात है, मेरा छोटा मस्तिष्क ऐसा नहीं कर सकता है।
यह वास्तव में कष्टप्रद है कि इतने सारे लोगों ने दिमाग में इस कथन को दोहराया है कि गिट स्वचालित रूप से चाल को ट्रैक करता है। उन्होंने मेरा समय बर्बाद कर दिया है। गिट ऐसा कोई काम नहीं करता है। डिज़ाइन द्वारा (!) गिट चाल को ट्रैक नहीं करता है।
मेरा समाधान फ़ाइलों को उनके मूल स्थानों पर वापस नामित करना है। स्रोत नियंत्रण फिट करने के लिए सॉफ़्टवेयर बदलें। गिट के साथ आपको बस पहली बार इसे गिट करने की आवश्यकता होती है।
दुर्भाग्यवश, यह एक्लिप्स को तोड़ता है, जो कि - --follow
का उपयोग करने लगता है।
git log --follow
कभी-कभी जटिल नाम इतिहास के साथ फाइलों का पूरा इतिहास नहीं दिखाता है, भले ही git log
करता है। (मुझे नहीं पता क्यों।)
(कुछ बहुत चतुर हैक्स हैं जो वापस जाते हैं और पुराने काम की सिफारिश करते हैं, लेकिन वे बल्कि डरावने हैं। emiller/git-mv-with-history -गिस्ट देखें: emiller/git-mv-with-history ।)
मैं गिट में एक प्रोजेक्ट सबट्री का नाम बदलना / स्थानांतरित करना चाहता हूं
/project/xyz
सेवा मेरे
/components/xyz
यदि मैं एक सादे git mv project components
उपयोग करता हूं, तो xyz project
लिए सभी प्रतिबद्धता इतिहास खो जाता है। क्या ऐसा करने का कोई तरीका है कि इतिहास बनाए रखा जाए?
लक्ष्य
-
git am
Exherbo उपयोग करें ( Exherbo से प्रेरित, Exherbo से उधार लिया गया) - प्रतिलिपि / स्थानांतरित फ़ाइलों का प्रतिबद्ध इतिहास जोड़ें
- एक निर्देशिका से दूसरे में
- या एक भंडार से दूसरे में
सीमा
- टैग और शाखाओं को नहीं रखा जाता है
- पथ फ़ाइल नाम पर इतिहास काटा गया है (निर्देशिका का नाम बदलें)
सारांश
- ईमेल प्रारूप में इतिहास का उपयोग करें
git log --pretty=email -p --reverse --full-index --binary
- फ़ाइल पेड़ को पुनर्गठित करें और फ़ाइल नाम अपडेट करें
- उपयोग कर नया इतिहास संलग्न करें
cat extracted-history | git am --committer-date-is-author-date
1. ईमेल प्रारूप में इतिहास निकालें
उदाहरण: file4
, file4
और file4
का इतिहास निकालें
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
के साथ संयुक्त नहीं किया जा सकता है। यही कारण है कि फ़ाइल का नाम बदलते समय इतिहास काटा जाता है (या जब मूल निर्देशिका का नाम बदल दिया जाता है)।
ईमेल प्रारूप में अस्थायी इतिहास:
/tmp/mail/dir
├── subdir
│ ├── file3
│ └── file4
└── file5
डैन बोनाचा ने इस पहले चरण में गिट लॉग जनरेशन कमांड के लूप को उलटा करने का सुझाव दिया: प्रति फ़ाइल एक बार गिट लॉग चलाने के बजाए, इसे कमांड लाइन पर फ़ाइलों की सूची के साथ एक बार चलाएं और एक एकीकृत एकीकृत लॉग उत्पन्न करें। इस तरह से कई फाइलें संशोधित होती हैं जो परिणाम में एक ही प्रतिबद्ध रहती हैं, और सभी नए काम अपने मूल सापेक्ष आदेश को बनाए रखते हैं। ध्यान दें कि (अब एकीकृत) लॉग में फ़ाइल नामों को फिर से लिखते समय इसे दूसरे चरण में परिवर्तन की आवश्यकता होती है।
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
या --find-copies-harder
। आप cut -f3-
और पूर्ण पैटर्न '{। * =>। *}' का उपयोग करके पहले दो कॉलम भी हटा सकते हैं।
find -name .git -prune -o -exec git log --pretty=tformat:'' --numstat --follow --find-copies-harder --reverse {} ';' | cut -f3- | grep '{.* => .*}'
गिट प्रतिबद्धता के साथ संचालन को बनाए रखने के बजाए नामों का पता लगाता है, ताकि आप git mv
या mv
उपयोग न करें।
लॉग कमांड एक - --follow
तर्क लेता है जो नाम बदलने से पहले इतिहास जारी रखता है, यानी, यह हेरिस्टिक्स का उपयोग करके समान सामग्री की खोज करता है:
http://git-scm.com/docs/git-log
पूर्ण इतिहास देखने के लिए, निम्न आदेश का उपयोग करें:
git log --follow ./path/to/file
फ़ाइल का नाम बदलना और इतिहास को बरकरार रखना संभव है, हालांकि यह फ़ाइल को भंडार के पूरे इतिहास में बदल दिया जाता है। यह शायद केवल जुनूनी गिट-लॉग-प्रेमी के लिए है, और इसमें कुछ गंभीर प्रभाव हैं, जिनमें निम्न शामिल हैं:
- आप एक साझा इतिहास को फिर से लिख सकते हैं, जो सबसे महत्वपूर्ण है गिट का उपयोग करते समय नहीं। अगर किसी और ने भंडार क्लोन किया है, तो आप इसे कर देंगे। सिरदर्द से बचने के लिए उन्हें फिर से क्लोन करना होगा। यह ठीक हो सकता है अगर नाम पर्याप्त महत्वपूर्ण है, लेकिन आपको इसे ध्यान से विचार करने की आवश्यकता होगी - आप एक संपूर्ण ओपनसोर्स समुदाय को परेशान कर सकते हैं!
- यदि आपने रिपॉजिटरी इतिहास में पहले पुराने नाम का उपयोग करके फ़ाइल का संदर्भ दिया है, तो आप प्रभावी रूप से पुराने संस्करणों को तोड़ रहे हैं। इसका समाधान करने के लिए, आपको थोड़ी अधिक उछाल कूदना होगा। यह असंभव नहीं है, केवल कठिन और संभवतः इसके लायक नहीं है।
अब, चूंकि आप अभी भी मेरे साथ हैं, आप शायद एक पूरी तरह से पृथक फ़ाइल का नाम बदल रहे एकल डेवलपर हैं। चलो 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
प्रत्येक पुनरावृत्ति के लिए टिकों में आदेश निष्पादित करने, शाखा में हर प्रतिबद्धता को फिर से कर देगा। जब आप ऐसा करते हैं तो सामान की बहुत सारी चीज़ें गलत हो सकती हैं। मैं आम तौर पर यह देखने के लिए परीक्षण करता हूं कि फ़ाइल मौजूद है या नहीं (अन्यथा यह अभी तक नहीं है) और फिर पेड़ को मेरी पसंद के हिसाब से करने के लिए आवश्यक कदम उठाएं। यहां आप फ़ाइलों के संदर्भों को बदलने के लिए फाइलों के माध्यम से जा सकते हैं और इसी तरह। अपने आप को बाहर करना! :)
पूरा होने पर, फ़ाइल स्थानांतरित हो जाती है और लॉग बरकरार है। आप निंजा समुद्री डाकू की तरह महसूस करते हैं।
इसके अलावा, Mkdir dir केवल तभी जरूरी है जब आप फ़ाइल को नए फ़ोल्डर में ले जाएं। यदि आपकी फ़ाइल मौजूद है, तो इतिहास में पहले इस फ़ोल्डर के निर्माण से बचें।
मैं फ़ाइलों को स्थानांतरित करता हूं और फिर करता हूं
git add -A
जो सैटेलाइट क्षेत्र में सभी हटाए गए / नई फाइलों में डाल दिया गया है। यहां गिट को पता चलता है कि फ़ाइल ले जाया गया है।
git commit -m "my message"
git push
मुझे नहीं पता क्यों, लेकिन यह मेरे लिए काम करता है।
git log --follow [file]
आपको नामों के माध्यम से इतिहास दिखाएगा।