मैं एक पुराने भंडार से पुराने इतिहास को कैसे निकालूं?


208

मुझे डर है कि मुझे इस विशेष परिदृश्य जैसा कुछ भी नहीं मिला।

मेरे पास बहुत सारे इतिहास के साथ एक गिट रिपॉजिटरी है: 500+ शाखाएं, 500+ टैग, जो 2007 के मध्य में वापस जा रहे हैं। इसमें ~ 19,500 समाहित है। हम 1 जनवरी, 2010 से पहले के सभी इतिहास को हटाना चाहते हैं, जिससे निपटने के लिए इसे छोटा और आसान बनाया जा सके (हम एक पुरालेख भंडार में इतिहास की पूरी प्रतिलिपि रखेंगे)।

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

git filter-branch

ग्राफ्ट को शामिल करना आवश्यक होगा; यह भी आवश्यक हो सकता है कि हम जिन 200 + शाखाओं को अलग-अलग रखना चाहते हैं, उनमें से प्रत्येक का इलाज करें और फिर रेपो को एक साथ वापस करें (कुछ मैं पता है कि कैसे करना है)।

क्या कभी किसी ने ऐसा कुछ किया है? अगर मुझे कोई फर्क नहीं पड़ता 1.7.2.3 पकड़ लिया है।

जवाबों:


118

बस एक ग्राफ्ट बनाएं अपनी नई जड़ के माता-पिता के लिए बिना माता-पिता (या एक खाली प्रतिबद्ध, उदाहरण के लिए आपके भंडार का वास्तविक मूल वचन) का । उदाहरण के लिएecho "<NEW-ROOT-SHA1>" > .git/info/grafts

ग्राफ्ट बनाने के बाद, यह तुरंत प्रभावी हो जाता है; आपको यह देखने git logऔर देखने में सक्षम होना चाहिए कि अवांछित पुराने कमिट दूर चले गए हैं:

$ echo 4a46bc886318679d8b15e05aea40b83ff6c3bd47 > .git/info/grafts
$ git log --decorate | tail --lines=11
commit cb3da2d4d8c3378919844b29e815bfd5fdc0210c
Author: Your Name <your.email@example.com>
Date:   Fri May 24 14:04:10 2013 +0200

    Another message

commit 4a46bc886318679d8b15e05aea40b83ff6c3bd47 (grafted)
Author: Your Name <your.email@example.com>
Date:   Thu May 23 22:27:48 2013 +0200

    Some message

यदि सभी के रूप में इरादा है, तो आप बस एक सरल कर सकते हैं git filter-branch -- --all इसे स्थायी बनाने के ।

BEWARE: फिल्टर-ब्रांच स्टेप करने के बाद , सभी कमिट आईडी बदल गए होंगे, इसलिए पुराने रेपो का उपयोग करने वाले को कभी भी नए रेपो का उपयोग करके किसी के साथ विलय नहीं करना चाहिए।


6
मुझे git filter-branch --tag-name-filter cat -- --allटैग अपडेट करने के लिए करना था । लेकिन मुझे पुराने इतिहास की ओर इशारा करते हुए पुराने टैग भी मिले हैं जिन्हें मैं हटाना चाहता हूं। मैं उन सभी पुराने टैग से कैसे छुटकारा पा सकता हूं? अगर मैं उन्हें नहीं हटाता हूं, तो पुराना इतिहास गायब नहीं होता है और मैं इसे अभी भी देख सकता हूं gitk --all
क्रेग मैकक्वीन

9
"बस अपने नए रूट के माता-पिता के लिए बिना किसी माता-पिता के लिए एक ग्राफ्ट बनाएं" कुछ विस्तार की आवश्यकता है। मैंने कोशिश की कि "कोई माता-पिता" के लिए वाक्य रचना का पता लगाने में विफल रहा। मैनुअल पेज का दावा है कि माता-पिता की प्रतिबद्ध आईडी की आवश्यकता है; सभी शून्य का उपयोग करना मुझे एक त्रुटि देता है।
मारियस गेदमिनस

6
मामले में कोई और सोच रहा था कि यह कैसे काम करता है, यह बहुत आसान है:echo "<NEW-ROOT-HASH>" > .git/info/grafts
friederbluemle

3
मैं सहमत हूं, यह स्पष्ट करना कि एक ग्राफ्ट क्या उपयोगी होगा से अधिक होगा
चार्ल्स मार्टिन

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

130

हो सकता है कि उत्तर देने में बहुत देर हो गई हो, लेकिन जैसा कि यह पृष्ठ Google का पहला परिणाम है, यह अभी भी मददगार हो सकता है।

यदि आप अपने गिट रेपो में कुछ जगह खाली करना चाहते हैं, लेकिन अपने सभी कमिट्स (रिबेस या ग्राफ्ट) को फिर से बनाना नहीं चाहते हैं, और फिर भी उन लोगों से पुश / पुल / मर्ज करने में सक्षम हैं, जिनके पास पूर्ण रेपो है, तो आप गिट का उपयोग कर सकते हैं। क्लोन उथले क्लोन ( -depth पैरामीटर)।

; Clone the original repo into limitedRepo
git clone file:///path_to/originalRepo limitedRepo --depth=10

; Remove the original repo, to free up some space
rm -rf originalRepo
cd limitedRepo
git remote rm origin

आप इन चरणों का पालन करके अपने मौजूदा रेपो को उथले करने में सक्षम हो सकते हैं:

; Shallow to last 5 commits
git rev-parse HEAD~5 > .git/shallow

; Manually remove all other branches, tags and remotes that refers to old commits

; Prune unreachable objects
git fsck --unreachable ; Will show you the list of what will be deleted
git gc --prune=now     ; Will actually delete your data

सभी गिट स्थानीय टैग कैसे निकालें?

Ps: git के पुराने संस्करणों ने क्लोन / पुश / पुल से / shallow repos का समर्थन नहीं किया।


9
+1 यह वह जगह है Git के नए संस्करण के लिए सही जवाब। (ओह, और कृपया PPCG पर वापस आएं !)
wizzwizz4

6
आप cdउस फ़ोल्डर में कैसे जा सकते हैं जिसे अभी हटा दिया गया है? मुझे ऐसा लगता है कि यहाँ कुछ मिसिंग जानकारी है। इसके अलावा, क्या रिमोट रेपो में इन परिवर्तनों को लागू करने का कोई तरीका है?
Trogdor

4
@ जज वह अन्य शीर्ष मतदान का जवाब होगा। यदि आप स्थायी रूप से इतिहास से छुटकारा चाहते हैं तो यह उत्तर आपके लिए नहीं है। यह विशाल इतिहास के साथ काम करने के लिए है ।
कोई भी

4
मेरे अपने प्रश्न का उत्तर देने के लिए: git clone file:///Users/me/Projects/myProject myClonedProject --shallow-since=2016-09-02एक आकर्षण की तरह काम करता है!
माइक्रोक

5
@ जज आप अपने उथले रेपो को सामान्य रूप से चलाकर परिवर्तित कर सकते हैं git filter-branch -- --all। यह इसमें सभी हैश को बदल देगा लेकिन इसके बाद आप इसे एक नए रेपो में
बदल पाएंगे

61

यह विधि समझने में आसान है और ठीक काम करती है। स्क्रिप्ट का तर्क ( $1) एक संदर्भ (टैग, हैश, ...) है जिसमें आप अपना इतिहास रखना चाहते हैं।

#!/bin/bash
git checkout --orphan temp $1 # create a new branch without parent history
git commit -m "Truncated history" # create a first commit on this branch
git rebase --onto temp $1 master # now rebase the part of master branch that we want to keep onto this branch
git branch -D temp # delete the temp branch

# The following 2 commands are optional - they keep your git repo in good shape.
git prune --progress # delete all the objects w/o references
git gc --aggressive # aggressively collect garbage; may take a lot of time on large repos

ध्यान दें कि पुराने टैग अभी भी मौजूद रहेंगे; इसलिए आपको उन्हें मैन्युअल रूप से निकालने की आवश्यकता हो सकती है

टिप्पणी: मुझे पता है कि यह @yoyodin के रूप में लगभग समान है, लेकिन यहां कुछ महत्वपूर्ण अतिरिक्त कमांड और informations हैं। मैंने उत्तर को संपादित करने की कोशिश की, लेकिन चूँकि यह @ yoyodin के उत्तर में पर्याप्त बदलाव है, इसलिए मेरा संपादन अस्वीकार कर दिया गया, इसलिए यहाँ जानकारी है!


मैं कमांड git pruneऔर git gcकमांड के लिए दिए गए स्पष्टीकरण की सराहना करता हूं । क्या स्क्रिप्ट में बाकी कमांड्स के लिए स्पष्टीकरण है? जैसा कि यह खड़ा है, यह स्पष्ट नहीं है कि इसके लिए क्या तर्क दिए जा रहे हैं और प्रत्येक आदेश क्या कर रहा है। धन्यवाद।
user5359531

2
@ user5359531 आपकी टिप्पणी के लिए धन्यवाद, मैंने प्रत्येक कमांड के लिए कुछ और टिप्पणियां जोड़ीं। उम्मीद है की यह मदद करेगा।
क्रिस मेस

4
मर्ज सभी जगह संघर्ष करता है ... बहुत उपयोगी नहीं
Warpzit

3
@Warpzit मैं जोड़कर मर्ज संघर्ष से छुटकारा मिला -pकरने के लिए rebaseके रूप में में अन्य जवाब का सुझाव दिया, आदेश
leonbloy

1
मैंने ठीक इसका अनुसरण किया, और मुझे जो भी मिला, वह पहले की तरह ही एक नई शाखा के साथ शुरू हुआ, जैसा कि मैं चाहता था कि पहले के सभी इतिहासों के साथ मैं भी यही चाहता था। कोई इतिहास नहीं निकाला गया।
DrStrangepork

51

इस विधि का प्रयास करें कैसे Git इतिहास काटना :

#!/bin/bash
git checkout --orphan temp $1
git commit -m "Truncated history"
git rebase --onto temp $1 master
git branch -D temp

यहाँ $1SHA-1 का है प्रतिबद्ध रखने के लिए और स्क्रिप्ट नई शाखा है कि दोनों के बीच सब करता बनाएंगे चाहते $1और masterऔर सभी पुराने इतिहास गिराया जाता है। ध्यान दें कि यह सरल स्क्रिप्ट मानता है कि आपके पास मौजूदा शाखा नहीं है जिसे कहा जाता है temp। यह भी ध्यान दें कि यह स्क्रिप्ट पुराने इतिहास के लिए डेटा को साफ़ नहीं करती है। git gc --prune=all && git repack -a -f -F -dआपके द्वारा सत्यापित किए जाने के बाद चलाएं कि आप वास्तव में सभी इतिहास खोना चाहते हैं। आपको इसकी आवश्यकता भी हो सकती है, rebase --preserve-mergesलेकिन चेतावनी दी जाती है कि उस सुविधा का कार्यान्वयन सही नहीं है। यदि आप इसका उपयोग करते हैं, तो मैन्युअल रूप से परिणामों का निरीक्षण करें।


22
मैंने यह कोशिश की, लेकिन rebaseकदम में विलय संघर्ष हो गया । अजीब - मैं उम्मीद नहीं कर रहा था कि इन परिस्थितियों में मर्ज संघर्ष संभव हो सकता है।
क्रेग मैकक्वीन

2
git commit --allow-empty -m "Truncate history"यदि आपके द्वारा चेक आउट की गई किसी भी फ़ाइल में नहीं है तो उपयोग करें ।
फ्राइडेरब्लुमेले

2
मैं इसे दूरस्थ मास्टर को कैसे वापस धकेलूं? जब मैं ऐसा करता हूं तो मैं पुराने और नए इतिहास को समाप्त करता हूं।
रस्टेक्स

1
'टेम्प' क्या माना जाता है? क्या आप इसके लिए एक तर्क के रूप में पारित करने वाले हैं? क्या इस बात का उदाहरण है कि जब आप वास्तव में इन्हें चलाते हैं तो ये कमांड क्या दिखते हैं? धन्यवाद।
user5359531

1
मेरा मानना ​​है कि $ 1 कमिट हैश है। (लिंक्ड लेख में दिए गए अधिक विवरण हैं)।
क्रिस नोलेट

34

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


हां, मुझे लगता है कि आप शायद वही कर सकते हैं जो हम चाहते थे, अगर आपने अलग पूर्ण इतिहास शाखा के रूप में अच्छी तरह से देखा। (हम भंडार को सिकोड़ने की कोशिश कर रहे थे।)
इबनेट

1
मैं जवाब से दूर साइट द्वारा हतोत्साहित किया गया था; लेकिन यह GitScm साइट और ट्यूटोरियल से लिंक करता है जो बहुत अच्छी तरह से लिखा गया है और ओपी के प्रश्न के बिंदु पर सीधे लगता है।
थोरसुमोनर

@ThorSummoner इसके बारे में क्षमा करें! मैं उत्तर को थोड़ा और पूरी तरह से साइट पर विकसित करूँगा
जेफ बोमैन

दुर्भाग्य से यह इतिहास के पुनर्लेखन का विकल्प नहीं है। लेख की शुरुआत में एक भ्रमित करने वाला वाक्य है जिसने शायद यह छाप दी। क्या इस जवाब से हटाया जा सकता है? आप इस लेख में देखेंगे कि लेखक छंटनी की गई शाखा के इतिहास को फिर से लिखता है, लेकिन वह विरासत के "इतिहास" शाखा का उपयोग करने का एक तरीका प्रस्तावित करता है git replace। मेरा मानना ​​है कि यह एक अन्य प्रश्न पर सही किया गया था जहां आपने यह उत्तर पोस्ट किया था।
मिच

1
की चर्चा git replaceबनाम git graftपर किया जाता है stackoverflow.com/q/6800692/873282
koppor

25

आप चाहते हैं रखने के नदी के ऊपर के साथ भंडार पूरा इतिहास है, लेकिन स्थानीय छोटे checkouts, के साथ एक उथले क्लोन कर git clone --depth=1 [repo]

एक कमिट पुश करने के बाद, आप कर सकते हैं

  1. git fetch --depth=1पुराने कमिट करने के लिए। यह पुराने कामों और उनकी वस्तुओं को अगम्य बनाता है।
  2. git reflog expire --expire-unreachable=now --all। सभी पुराने आवागमन और उनकी वस्तुओं को समाप्त करने के लिए
  3. git gc --aggressive --prune=all पुरानी वस्तुओं को हटाने के लिए

यह भी देखें कि एक कमिट के बाद स्थानीय गिट इतिहास को कैसे हटाया जाए?

ध्यान दें कि आप इस "उथले" भंडार को कहीं और नहीं धकेल सकते हैं: "उथले अद्यतन की अनुमति नहीं है"। Git दूरस्थ URL बदलने के बाद रिमोट अस्वीकृत (उथले अपडेट की अनुमति नहीं) देखें । यदि आप ऐसा चाहते हैं, तो आपको ग्राफ्टिंग के साथ रहना होगा।


1
बिंदु संख्या 1. ने मेरे लिए अंतर बनाया। चीयर्स
क्लैप्स

21

मुझे यह समझने के लिए कि मुझे क्या करना है, कई उत्तर और कुछ अन्य जानकारी पढ़ने की जरूरत है।

1. एक निश्चित कमिटमेंट की तुलना में पुरानी सभी चीजों को अनदेखा करें

फ़ाइल .git/info/graftsएक प्रतिबद्ध के लिए नकली माता-पिता को परिभाषित कर सकती है। सिर्फ एक प्रतिबद्ध आईडी के साथ एक लाइन, कहती है कि कमिट में माता-पिता नहीं हैं। अगर हम यह कहना चाहते हैं कि हम केवल पिछले 2000 के बारे में परवाह करते हैं, हम टाइप कर सकते हैं:

git rev-parse HEAD~2000 > .git/info/grafts

git Rev-parse हमें वर्तमान की 2000 वीं माता-पिता की प्रतिबद्ध आईडी देता है। उपर्युक्त कमांड अगर मौजूद है तो ग्राफ्ट फाइल को ओवरराइट कर देगा। अगर यह पहले है की जाँच करें।

2. गिट इतिहास को फिर से लिखना (वैकल्पिक)

यदि आप इस नकली नकली माता-पिता को असली बनाना चाहते हैं, तो दौड़ें:

git filter-branch -- --all

यह सभी कमिट आईडी बदल देगा। इस रिपॉजिटरी की हर कॉपी को जबरदस्ती अपडेट करना होगा।

3. डिस्क स्थान को साफ करें

मैंने चरण 2 नहीं किया, क्योंकि मैं चाहता था कि मेरी प्रति अपस्ट्रीम के साथ संगत रहे। मैं बस कुछ डिस्क स्थान बचाना चाहता था। सभी पुराने कमिट को भूलने के लिए:

git prune
git gc

वैकल्पिक: उथली प्रतियां

यदि आपके पास किसी अन्य रिपॉजिटरी की उथली प्रति है और बस कुछ डिस्क स्थान बचाना चाहते हैं, तो आप अपडेट कर सकते हैं .git/shallow। लेकिन सावधान रहें कि कुछ भी पहले से कमिट नहीं कर रहा है। तो आप कुछ इस तरह से चला सकते हैं:

git fetch --prune
git rev-parse HEAD~2000 > .git/shallow
git prune
git gc

उथले में प्रवेश एक ग्राफ्ट की तरह काम करता है। लेकिन एक ही समय में ग्राफ्ट और उथले का उपयोग न करने के लिए सावधान रहें। कम से कम, वहाँ एक ही प्रविष्टि नहीं है, यह विफल हो जाएगा।

यदि आपके पास अभी भी कुछ पुराने संदर्भ (टैग, शाखाएं, रिमोट हेड) हैं जो पुराने कमिट्स की ओर इशारा करते हैं, तो उन्हें साफ नहीं किया जाएगा और आप अधिक डिस्क स्थान नहीं बचाएंगे।


<GIT_DIR> / info / graft के लिए समर्थन को हटा दिया गया है और भविष्य के Git संस्करण में हटा दिया जाएगा।
डैनी

कृपया git replaceइसके बजाय उपयोग करने पर विचार करें । देखें stackoverflow.com/questions/6800692/...
जोएल AZEMAR

3

जब रिबास या हेड / मास्टर को धक्का दिया जाए तो यह त्रुटि हो सकती है

remote: GitLab: You are not allowed to access some of the refs!
To git@giturl:main/xyz.git
 ! [remote rejected] master -> master (pre-receive hook declined)
error: failed to push some refs to 'git@giturl:main/xyz.git'

गिट डैशबोर्ड में इस मुद्दे को हल करने के लिए "संरक्षित शाखाओं" से मास्टर शाखा को हटा देना चाहिए

यहां छवि विवरण दर्ज करें

तब आप इस कमांड को चला सकते हैं

git push -f origin master

या

git rebase --onto temp $1 master

0

यहाँ बहुत सारे उत्तर हैं जो वर्तमान नहीं हैं और कुछ पूरी तरह से परिणामों की व्याख्या नहीं करते हैं। यहाँ नवीनतम git 2.26 का उपयोग करके इतिहास को ट्रिम करने के लिए मेरे लिए क्या काम किया गया है:

सबसे पहले एक डमी कमिट बनाएं। यह कमिट आपके छंटे हुए रेपो में पहली कमिट के रूप में दिखाई देगा। आपको इसकी आवश्यकता है क्योंकि यह प्रतिबद्ध आपके द्वारा रखे जा रहे इतिहास के लिए सभी आधार फ़ाइलों को रखेगा। SHA उस कमिट के पिछले कमिटमेंट की आईडी है जिसे आप रखना चाहते हैं (इस उदाहरण में, 8365366)। स्ट्रिंग 'इनिशियल' पहली प्रतिबद्ध के संदेश के रूप में दिखाई देगी। यदि आप Windows का उपयोग कर रहे हैं, तो Git Bash कमांड प्रॉम्प्ट से कमांड टाइप करें।

# 8365366 is id of parent commit after which you want to preserve history
echo 'Initial' | git commit-tree 8365366^{tree}

उदाहरण के लिए, ऊपर SHA प्रिंट करेगा, d10f7503bc1ec9d367da15b540887730db862023

अब बस टाइप करें:

# d10f750 is commit ID from previous command
git rebase --onto d10f750 8365366

यह पहले सभी फाइलों को 8365366डमी कमिट में कमिट-ऑफ कर देगा d10f750। फिर यह 8365366 के शीर्ष के बाद सभी कमिट्स वापस खेलेंगे d10f750। आखिरकारmaster ब्रांच पॉइंटर को पिछली बार खेले गए बैक में अपडेट किया जाएगा।

अब यदि आप इन छंटनी किए गए रेपो को धक्का देना चाहते हैं, तो बस करें git push -f

कुछ बातों को ध्यान में रखना (ये अन्य तरीकों के साथ-साथ इस एक पर लागू होता है): टैग को स्थानांतरित नहीं किया जाता है। जबकि कमिट आईडी और टाइमस्टैम्प संरक्षित हैं, आप गिटहब को कमल के शीर्ष पर इन कमिट्स को दिखाते हैं Commits on XY date

सौभाग्य से, कटे हुए इतिहास को "संग्रह" के रूप में रखना संभव है और बाद में आप संग्रहित रेपो के साथ वापस छंटनी किए गए रेपो में शामिल हो सकते हैं। ऐसा करने के लिए, इस गाइड को देखें ।


-3

आप डाइरेक्ट, फाइल्स और डायर से जुड़ी पूरी हिस्ट्री को डिलीट कर सकते हैं या नीचे बताए गए जार का इस्तेमाल करके फाइल [इसे डाउनलोड कर सकते हैं] और कमांड्स

bfg.jar फ़ाइल: https://rtyley.github.io/bfg-repo-cleaner/

git clone --bare repo-url cd repo_dir java -jar bfg.jar --delete-folder folder_name git reflog expire --expire = now --all && git gc-prune = now --aggressive git push --mirror repo_url


-10
  1. git data को हटा दें, rm .गित
  2. git init
  3. एक रिमोट जोड़ें
  4. बल धक्का

6
यह सभी इतिहास को हटाने के लिए काम करेगा, लेकिन उसने जो पूछा उसके लिए नहीं: 2010 से इतिहास को बनाए रखें
क्रिस मेस

1
बस धन्यवाद कहने के लिए के रूप में यह मुझे मेरी स्थिति में मदद की है, भले ही यह हो सकता है के लिए सवाल सही जवाब नहीं हो चाहता था
apnerve
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.