जीआईटी इतिहास से संवेदनशील फाइलें और उनके कमिट निकालें


353

मैं GitHub पर एक Git प्रोजेक्ट लगाना चाहूंगा लेकिन इसमें संवेदनशील डेटा (उपयोगकर्ता नाम और पासवर्ड, जैसे capconrano के लिए /config/deploy.rb) के साथ कुछ फाइलें हैं।

मुझे पता है कि मैं इन फ़ाइलनामों को .gitignore में जोड़ सकता हूं , लेकिन यह Git के भीतर उनके इतिहास को नहीं हटाएगा।

मैं /. निर्देशिका को हटाकर फिर से शुरू नहीं करना चाहता।

क्या आपके गिट इतिहास में किसी विशेष फ़ाइल के सभी निशान हटाने का एक तरीका है ?



जवाबों:


448

सभी व्यावहारिक उद्देश्यों के लिए, पहली चीज जिसके बारे में आपको चिंतित होना चाहिए , वह है आपके पासवर्ड को बदलना! यह आपके प्रश्न से स्पष्ट नहीं है कि क्या आपकी गिट रिपॉजिटरी पूरी तरह से स्थानीय है या क्या आपके पास कहीं और रिमोट रिपॉजिटरी है या नहीं; यदि यह दूरस्थ है और दूसरों से सुरक्षित नहीं है, तो आपको समस्या है। यदि किसी ने इसे ठीक करने से पहले उस रिपॉजिटरी को क्लोन किया है, तो उनके पास आपके पासवर्ड की एक प्रति उनके स्थानीय मशीन पर होगी, और ऐसा कोई तरीका नहीं है कि आप उन्हें इतिहास के साथ गए अपने "निश्चित" संस्करण में अपडेट करने के लिए बाध्य कर सकें। केवल सुरक्षित चीज जो आप कर सकते हैं, वह है कि आपने अपना पासवर्ड किसी और जगह बदल दिया है।


उस रास्ते से बाहर, यहाँ यह कैसे तय करने के लिए है। GitHub ने उस प्रश्न का सटीक उत्तर दिया :

विंडोज उपयोगकर्ताओं के लिए ध्यान दें : इस कमांड में एकल के बजाय दोहरे उद्धरण (") का उपयोग करें

git filter-branch --index-filter \
'git update-index --remove PATH-TO-YOUR-FILE-WITH-SENSITIVE-DATA' <introduction-revision-sha1>..HEAD
git push --force --verbose --dry-run
git push --force

अपडेट 2019:

यह FAQ से वर्तमान कोड है:

  git filter-branch --force --index-filter \
  "git rm --cached --ignore-unmatch PATH-TO-YOUR-FILE-WITH-SENSITIVE-DATA" \
  --prune-empty --tag-name-filter cat -- --all
  git push --force --verbose --dry-run
  git push --force

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

इसे ठीक करने के लिए, उन्हें या तो अपने मौजूदा रिपॉजिटरी को हटाना होगा और इसे फिर से क्लोन करना होगा, या गिट-रिबेस मैनपेज में "रिकवरिंग फ्रॉम UPSTREAM REBASE" के तहत निर्देशों का पालन करना होगा ।

युक्ति : निष्पादित करेंgit rebase --interactive


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

git commit -a --amend

वह आपके द्वारा किए गए किसी भी नए परिवर्तन के साथ पिछली प्रतिबद्ध को संशोधित करेगा, जिसमें संपूर्ण फ़ाइल निष्कासन भी शामिल है git rm। यदि इतिहास में परिवर्तन आगे पीछे हो जाते हैं लेकिन फिर भी दूरस्थ रिपॉजिटरी में नहीं धकेल दिए जाते हैं, तो आप एक इंटरैक्टिव रिबेस कर सकते हैं:

git rebase -i origin/master

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

$EDITOR file-to-fix
git commit -a --amend
git rebase --continue

संवेदनशील जानकारी के साथ प्रत्येक परिवर्तन के लिए। आखिरकार, आप अपनी शाखा पर वापस आ जाएंगे, और आप नए परिवर्तनों को सुरक्षित रूप से धकेल सकते हैं।


5
बिल्कुल सही दोस्त, यह एक महान जवाब है। तुम मेरा दिन बचाओ।
झज्जरू

18
बस एक बिट जोड़ने के लिए - विंडोज पर, आपको एकल के बजाय दोहरे उद्धरण (") का उपयोग करना चाहिए।
ripper234

4
यह काम करने के लिए मिला। मैं अनुवादों में खो गया था। मैंने यहाँ कमांड के बजाय लिंक का उपयोग किया है। इसके अलावा, विंडोज कमांड ने ripper234 उल्लेखों के रूप में दोहरे उद्धरण चिह्नों की आवश्यकता को समाप्त किया, मिगडस के रूप में पूर्ण पथ का सुझाव दिया, और "\" वर्णों को शामिल नहीं किया जो कि लिंक को नई लाइन रैपिंग संकेतक के रूप में चिपकाया गया था। अंतिम कमान कुछ इस तरह दिखती थी: git फ़िल्टर-शाखा --force --index- फ़िल्टर "git rm --cached --ignore-unmatch src [प्रोजेक्ट] [फ़ाइल]। [ext]" --prune-blank -tag- नाम-फ़िल्टर बिल्ली - --all
एरिक स्वानसन

3
आपके filter-branchकोड और आपके द्वारा लिंक किए गए github पृष्ठ में कुछ ठोस अंतर प्रतीत होते हैं । जैसे उनकी तीसरी पंक्ति --prune-empty --tag-name-filter cat -- --all। क्या समाधान बदल गया है या मुझे कुछ याद आ रहा है?
जियोथेट्री

2
यह समाधान काफी अच्छा लग रहा है, लेकिन अगर मैंने प्रारंभिक प्रतिबद्ध में हटाने के लिए फ़ाइल पेश की <introduction-revision-sha1>..HEADहै तो यह काम नहीं करता है। यह केवल दूसरी प्रतिबद्ध से फाइल को निकालता है। (मैं कमिट की सीमा में प्रारंभिक कमिट को कैसे शामिल करूँ?) सेव का तरीका यहाँ बताया गया है: help.github.com/articles/… git filter-branch --force --index-filter \ 'git rm --cached --ignore-unmatch PATH-TO-YOUR-FILE-WITH-SENSITIVE-DATA' \ --prune-empty --tag-name-filter cat -- --all
white_gecko

91

आपके पासवर्ड को बदलना एक अच्छा विचार है, लेकिन आपके रेपो के इतिहास से पासवर्ड को हटाने की प्रक्रिया के लिए, मैं BFG रेपो-क्लीनर की सलाह देता हूं , जो एक तेज़, सरल विकल्प हैgit-filter-branch निजी डेटा को हटाने के स्पष्ट रूप से डिज़ाइन किया गया ।

private.txtपासवर्ड इत्यादि सूचीबद्ध करने वाली एक फ़ाइल बनाएँ , जिसे आप निकालना चाहते हैं (प्रति पंक्ति एक प्रविष्टि) और फिर इस कमांड को चलाएं:

$ java -jar bfg.jar  --replace-text private.txt  my-repo.git

आपके रेपो के इतिहास में एक थ्रेसहोल्ड आकार (डिफ़ॉल्ट रूप से 1MB) के तहत सभी फाइलें स्कैन की जाएंगी, और किसी भी मिलान स्ट्रिंग (जो कि आपकी नवीनतम प्रतिबद्ध में नहीं है ) को स्ट्रिंग "*** REMOVED ***" से बदल दिया जाएगा। फिर आप git gcमृत डेटा को दूर करने के लिए उपयोग कर सकते हैं :

$ git gc --prune=now --aggressive

बीएफजी आम तौर पर चलने की तुलना में 10-50 गुना तेज होता है git-filter-branchऔर विकल्प सरल और इन दो सामान्य उपयोग के मामलों के अनुरूप होते हैं:

  • क्रेजी बिग फाइल्स को हटाना
  • पासवर्ड, क्रेडेंशियल्स और अन्य निजी डेटा हटाना

पूरा खुलासा: मैं बीएफजी रेपो-क्लीनर का लेखक हूं।


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

6
यह यहीं एक बड़ी जीत है। एक जोड़े की कोशिश के बाद, मैं एक निजी रेपो से संवेदनशील जानकारी युक्त स्ट्रिप कमिट्स का उपयोग करने में सक्षम था और संशोधित इतिहास के साथ रिमोट रेपो को बलपूर्वक अपडेट करता था। एक ओर ध्यान दें कि आपको यह सुनिश्चित करना होगा कि आपका रेपो (HEAD) का सिरा अपने आप में कोई संवेदनशील डेटा से साफ न हो क्योंकि यह प्रतिबद्ध "संरक्षित" माना जाता है और इस उपकरण द्वारा संशोधित नहीं किया जाएगा। यदि ऐसा नहीं है, बस स्वच्छ / मैन्युअल रूप से बदल सकते हैं और git commit। अन्यथा, डेवलपर के टूलबॉक्स में नए टूल के लिए +1 :)
मैट बोरजा

1
@ हेनरिदव मेरी हालिया टिप्पणी के अनुसार, यह आपके आवेदन को नहीं तोड़ना चाहिए जैसा कि आप अनुमान लगा सकते हैं, यह मानते हुए कि आपका आवेदन वर्तमान में आपकी शाखा के शीर्ष पर स्थित है (यानी नवीनतम प्रतिबद्ध)। यह टूल स्पष्ट रूप These are your protected commits, and so their contents will NOT be alteredसे आपके बाकी के कमिट इतिहास को ट्रेस और संशोधित करते हुए आपके अंतिम प्रतिबद्ध के लिए रिपोर्ट करेगा । यदि आपको रोलबैक करने की आवश्यकता है, तो हां, ***REMOVED***आपको केवल उस कमिटमेंट की खोज करने की आवश्यकता है जिसे आपने अभी वापस रोल किया है।
मैट बोरजा

1
बीएफजी के लिए +1 (यदि आपके पास जावा स्थापित है या इसे स्थापित करने में कोई आपत्ति नहीं है)। एक पकड़ यह है कि BFG एक फ़ाइल को हटाने से इंकार कर देता है यदि वह HEAD में निहित है। इसलिए बेहतर होगा कि पहले एक कमिट करें जहां वांछित फाइलें हटाई जाएंगी और उसके बाद ही बीएफजी चलेगा। उसके बाद आप उस अंतिम कमिट को वापस कर सकते हैं, अब यह एक चीज़ नहीं बदलता है।
Fr0sT

1
इसे वास्तव में सही उत्तर के रूप में स्वीकार किया जाना चाहिए। यह बॉक्स पर क्या कहता है!
गॉजोरिस

21

यदि आपने गिटहब पर धकेल दिया है, तो जोर लगाना पर्याप्त नहीं है, रिपॉजिटरी या संपर्क समर्थन को हटा दें

यहां तक ​​कि अगर आप बलपूर्वक एक सेकंड बाद में धक्का देते हैं, तो यह पर्याप्त नहीं है जैसा कि नीचे बताया गया है।

कार्रवाई के केवल मान्य पाठ्यक्रम हैं:

  • क्या पासवर्ड की तरह एक अस्थिर क्रेडेंशियल लीक हुआ है?

    • हाँ: अपने पासवर्ड को तुरंत संशोधित करें, और अधिक OAuth और API कुंजियों का उपयोग करने पर विचार करें!
    • नहीं (नग्न तस्वीरें):

      • क्या आप परवाह करते हैं कि रिपॉजिटरी में सभी मुद्दों को नंगा किया जाए?

        • नहीं: रिपॉजिटरी हटाएं
        • हाँ:

          • सहयोग टीम से संपर्क करें
          • यदि रिसाव आपके लिए बहुत महत्वपूर्ण है, इस बिंदु पर कि आप कुछ रिपॉजिटरी डाउनटाइम प्राप्त करने के लिए तैयार हैं, तो इसे लीक करने की संभावना कम है, इसे निजी बनाएं जबकि आप जवाब देने के लिए गिटहब समर्थन की प्रतीक्षा करते हैं

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

  • गिटहब लंबे समय तक झूलता रहता है।

    यदि आप उनसे संपर्क करते हैं तो GitHub स्टाफ के पास ऐसे झूलने वाले कमिट्स को हटाने की शक्ति है।

    मैंने पहले हाथ का अनुभव किया जब मैंने सभी GitHub को एक रेपो के लिए ईमेल भेजा, उन्होंने मुझे इसे नीचे ले जाने के लिए कहा, तो मैंने किया, और उन्होंने किया gcहालाँकि , डेटा को हटाने वाले अनुरोधों को हटाना पड़ता है, क्योंकि इसके कारण शुरुआती टेकडाउन के बाद रेपो डेटा एक वर्ष तक सुलभ रहता है।

    डैंग्लिंग कमिट्स को इसके माध्यम से देखा जा सकता है:

    उस समय स्रोत को प्राप्त करने का एक सुविधाजनक तरीका डाउनलोड ज़िप विधि का उपयोग करना है, जो किसी भी संदर्भ को स्वीकार कर सकता है, जैसे: https://github.com/cirosantilli/myrepo/archive/SHA.zip

  • यह संभव है कि लापता SHAs को प्राप्त किया जाए:

    • साथ एपीआई घटनाओं की सूची type": "PushEvent"। जैसे मेरा: https://api.github.com/users/cirosantilli/events/public ( Wayback machine )
    • अधिक आसानी से कभी-कभी, सामग्री को हटाने का प्रयास करने वाले पुल अनुरोधों के SHAs को देखकर
  • Http://ghtorrent.org/ और https://www.githubarchive.org/ जैसे स्क्रैपर हैं जो नियमित रूप से GitHub डेटा को पूल करते हैं और इसे कहीं और स्टोर करते हैं।

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

आप फिर भी धक्का सिर्फ बल के बजाय भंडार को हटाते हैं, प्रतिबद्ध तुरंत एपीआई से भी गायब हो जाते हैं और 404 देना, जैसे है https://api.github.com/repos/cirosantilli/test-dangling-delete/commits/8c08448b5fbf0f891696819f3b2b2d653f7a3824 यह काम करता है यहां तक ​​कि अगर आप एक ही नाम के साथ एक और रिपॉजिटरी को फिर से बनाते हैं।

इसका परीक्षण करने के लिए, मैंने एक रेपो बनाया है: https://github.com/cirosantilli/test-dangling और किया:

git init
git remote add origin git@github.com:cirosantilli/test-dangling.git

touch a
git add .
git commit -m 0
git push

touch b
git add .
git commit -m 1
git push

touch c
git rm b
git add .
git commit --amend --no-edit
git push -f

यह भी देखें: GitHub से झूलते कमेंट को कैसे हटाएं?


20

मैं डेविड अंडरहिल की इस स्क्रिप्ट की सिफारिश करता हूं , मेरे लिए एक आकर्षण की तरह काम किया।

यह इन आदेशों को इसके अलावा निकलने वाली गंदगी को साफ करने के लिए नाटाकाडो की फ़िल्टर-शाखा में जोड़ता है:

rm -rf .git/refs/original/
git reflog expire --all
git gc --aggressive --prune

पूरी स्क्रिप्ट (डेविड अंडरहिल का सारा श्रेय)

#!/bin/bash
set -o errexit

# Author: David Underhill
# Script to permanently delete files/folders from your git repository.  To use 
# it, cd to your repository's root and then run the script with a list of paths
# you want to delete, e.g., git-delete-history path1 path2

if [ $# -eq 0 ]; then
    exit 0
fi

# make sure we're at the root of git repo
if [ ! -d .git ]; then
    echo "Error: must run this script from the root of a git repository"
    exit 1
fi

# remove all paths passed as arguments from the history of the repo
files=$@
git filter-branch --index-filter \
"git rm -rf --cached --ignore-unmatch $files" HEAD

# remove the temporary history git-filter-branch
# otherwise leaves behind for a long time
rm -rf .git/refs/original/ && \
git reflog expire --all && \
git gc --aggressive --prune

पिछले दो कमांड बेहतर हो सकते हैं यदि निम्न में बदल जाए:

git reflog expire --expire=now --all && \
git gc --aggressive --prune=now

1
ध्यान दें कि आपके एक्सपायर और प्रून का उपयोग गलत है, यदि आप तारीख निर्दिष्ट नहीं करते हैं तो यह प्रून के लिए 2 सप्ताह से अधिक पुराने सभी डिफॉल्ट्स को डिफॉल्ट करता है। आप जो चाहते हैं, वह सब कुछ करता है:git gc --aggressive --prune=now
एडम पार्किं

@ एडम पार्किन मैं उत्तर को कोड में छोड़ने जा रहा हूं क्योंकि यह डेविड अंडरहिल की साइट पर स्क्रिप्ट से है, आप वहां टिप्पणी कर सकते हैं और यदि वह इसे बदलता है तो मैं इस उत्तर को बदल दूंगा क्योंकि मैं वास्तव में नहीं जानता कि कुंआ। प्रीने से पहले एक्सपायर कमांड इसे प्रभावित नहीं करता है?
जेसन गोएमाट

1
@MarkusUnterwaditzer: वह व्यक्ति कमिट किए गए कमिट के लिए काम नहीं करेगा।
मैक्स बेइकिर्च

हो सकता है कि आपको सिर्फ अपने जवाब में सभी कमांड डालनी चाहिए; यह बहुत अधिक सुसंगत होगा और अलग-अलग पदों के मानसिक संयोजन की आवश्यकता नहीं होगी :)
एंड्रयू माओ

9

स्पष्ट होना: स्वीकृत उत्तर सही है। पहले कोशिश करो। हालांकि, यह कुछ उपयोग के मामलों के लिए अनावश्यक रूप से जटिल हो सकता है, खासकर यदि आप 'घातक: खराब संशोधन --prune-blank' जैसी अप्रिय त्रुटियों का सामना करते हैं, या वास्तव में अपने रेपो के इतिहास की परवाह नहीं करते हैं।

एक विकल्प यह होगा:

  1. परियोजना की आधार शाखा के लिए सी.डी.
  2. संवेदनशील कोड / फ़ाइल निकालें
  3. rm -rf .git / # अपने कोड से सभी git जानकारी निकालें
  4. Github पर जाएं और अपनी रिपॉजिटरी हटाएं
  5. अपने कोड को नए रिपॉजिटरी तक पहुँचाने के लिए इस गाइड का अनुसरण करें जैसा कि आप सामान्य रूप से करेंगे - https://help.github.com/articles/adding-an-existing-project-to-github-use-the-command-line/

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

इसे परमाणु विकल्प कहें।


9

आप उपयोग कर सकते हैं git forget-blob

उपयोग बहुत सरल है git forget-blob file-to-forget। आप यहाँ अधिक जानकारी प्राप्त कर सकते हैं

https://ownyourbits.com/2017/01/18/completely-remove-a-file-from-a-git-repository-with-git-forget-blob/

यह आपके इतिहास के सभी कमिट, रीफ़्लॉग, टैग इत्यादि से गायब हो जाएगा

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

स्टैक ओवरफ्लो से योगदानकर्ताओं को क्रेडिट जो मुझे इसे एक साथ रखने की अनुमति देता है


8

यहाँ खिड़कियों में मेरा समाधान है

git फ़िल्टर-शाखा - tree-filter "rm -f 'फाइलर / फ़ाइल नाम'" HEAD

git पुश --फोर्स

सुनिश्चित करें कि रास्ता सही है अन्यथा यह काम नहीं करेगा

मुझे उम्मीद है यह मदद करेगा


8

फ़िल्टर-शाखा का उपयोग करें :

git filter-branch --force --index-filter 'git rm --cached --ignore-unmatch *file_path_relative_to_git_repo*' --prune-empty --tag-name-filter cat -- --all

git push origin *branch_name* -f

3

मुझे ऐसा करने के लिए कुछ बार डेट करना पड़ा है। ध्यान दें कि यह केवल एक बार में 1 फ़ाइल पर काम करता है।

  1. सभी कमिटों की एक सूची प्राप्त करें जो एक फाइल को संशोधित करती है। नीचे वाला पहला कमिट करेगा:

    git log --pretty=oneline --branches -- pathToFile

  2. इतिहास से फ़ाइल को निकालने के लिए पहले कम से कम sha1 और पिछले कमांड से फाइल करने के लिए पथ का उपयोग करें, और उन्हें इस कमांड में भरें:

    git filter-branch --index-filter 'git rm --cached --ignore-unmatch <path-to-file>' -- <sha1-where-the-file-was-first-added>..


3

तो, यह कुछ इस तरह दिखता है:

git rm --cached /config/deploy.rb
echo /config/deploy.rb >> .gitignore

ट्रैक फ़ाइल के लिए कैश को git से निकालें और उस फ़ाइल को .gitignoreसूची में जोड़ें


2

अपने एंड्रॉइड प्रोजेक्ट में मैंने ऐप / src / main / res / values ​​/ folder में अलग xml फ़ाइल के रूप में admob_keys.xml की थी । इस संवेदनशील फ़ाइल को निकालने के लिए मैंने स्क्रिप्ट के नीचे उपयोग किया और पूरी तरह से काम किया।

git filter-branch --force --index-filter \
'git rm --cached --ignore-unmatch  app/src/main/res/values/admob_keys.xml' \
--prune-empty --tag-name-filter cat -- --all
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.