كيف يمكنك إصلاح سيئة الدمج و إعادة جيد يرتكب على ثابت دمج?
-
08-07-2019 - |
سؤال
أنا بطريق الخطأ ارتكب ملف غير المرغوب فيها (filename.orig
في حين حل دمج) إلى مستودع عدة يرتكب مضت دون أن يلاحظ ذلك حتى الآن.أريد تماما حذف الملف من مستودع التاريخ.
هل من الممكن كتابة تاريخ التغيير هذه filename.orig
لم يكن إضافة إلى مستودع في المقام الأول ؟
المحلول
يرجى عدم استخدام هذه الوصفة إذا كان الوضع الخاص بك ليس هو المذكور في السؤال.هذا هو وصفة لإصلاح سوء دمج ، وتعيد الخاص بك جيدة يرتكب على ثابت دمج.
على الرغم من أن filter-branch
سوف تفعل ما تريد, فإنه لا بأس به الأمر تعقيدا و ربما تختار أن تفعل هذا مع git rebase
.ربما تفضيل شخصي. filter-branch
في واحد قليلا أكثر تعقيدا القيادة ، بينما rebase
الحل هو أداء ما يعادل العمليات المنطقية خطوة واحدة في وقت واحد.
جربي الوصفة التالية:
# create and check out a temporary branch at the location of the bad merge
git checkout -b tmpfix <sha1-of-merge>
# remove the incorrectly added file
git rm somefile.orig
# commit the amended merge
git commit --amend
# go back to the master branch
git checkout master
# replant the master branch onto the corrected merge
git rebase tmpfix
# delete the temporary branch
git branch -d tmpfix
(ملاحظة أنك لا تحتاج في الواقع مؤقت فرع ، يمكنك أن تفعل هذا مع فصل الرأس', ولكن تحتاج إلى أن تأخذ علما ارتكاب id الناتجة عن git commit --amend
خطوة إلى إمدادات git rebase
الأمر بدلا من استخدام مؤقت اسم الفرع.)
نصائح أخرى
مقدمة:لديك 5 الحلول المتاحة
الملصق الأصلي الدول:
أنا بطريق الخطأ ارتكب ملف غير المرغوب فيها إلى مستودع عدة يرتكب مضت...أريد تماما حذف الملف من مستودع التاريخ.
هو من الممكن كتابة تاريخ التغيير هذه
filename.orig
لم يكن إضافة إلى مستودع في المقام الأول ؟
هناك العديد من الطرق المختلفة لإزالة تاريخ الملف تماما من بوابة:
- تعديل يرتكب.
- من الصعب إعادة تعيين (ربما بالإضافة إلى ريبس).
- غير التفاعلية ريبس.
- التفاعلية rebases.
- تصفية الفروع.
في حالة الملصق الأصلي, تعديل ارتكاب ليس خيارا في حد ذاته ، حيث أنه قدم عدة إضافية يرتكب بعد ذلك ، ولكن من أجل من اكتمالها ، كما سيتم شرح كيفية القيام بذلك ، من أجل أي شخص آخر justs يريد تعديل السابقة يرتكبها.
لاحظ أن جميع هذه الحلول تتضمن تعديل/إعادة الكتابة التاريخ/يرتكب في طريقة واحدة أخرى, لذلك أي شخص مع النسخ القديمة من يرتكب سوف تضطر إلى القيام به العمل الإضافي إلى إعادة تزامن تاريخها مع تاريخ جديد.
الحل 1:تعديل يرتكب
إذا كنت غير قصد إجراء تغيير (مثل إضافة ملف) في السابق ارتكاب وأنت لا تريد من تاريخ هذا التغيير إلى وجود بعد الآن ، ثم يمكنك ببساطة تعديل السابقة تلتزم إزالة الملف من:
git rm <file>
git commit --amend --no-edit
الحل 2:من الصعب إعادة تعيين (ربما بالإضافة إلى ريبس)
مثل الحل #1, إذا كنت تريد فقط التخلص من السابق ارتكابها ، ثم لديك أيضا خيار من مجرد القيام من الصعب إعادة تعيين إلى الأم:
git reset --hard HEAD^
هذا الأمر من الصعب إعادة تعيين الخاص بك الفرع السابق 1st الأم يرتكبها.
ومع ذلك, إذا, مثل الملصق الأصلي ، لقد جعلت العديد من يرتكب بعد ارتكاب كنت تريد التراجع عن التغيير ، لا يزال بإمكانك استخدام من الصعب إعادة تعيين إلى تعديله ، ولكن ذلك ينطوي أيضا على استخدام ريبس.هنا هي الخطوات التي يمكنك استخدامها لتعديل ارتكاب المزيد من الوراء في التاريخ:
# Create a new branch at the commit you want to amend
git checkout -b temp <commit>
# Amend the commit
git rm <file>
git commit --amend --no-edit
# Rebase your previous branch onto this new commit, starting from the old-commit
git rebase --preserve-merges --onto temp <old-commit> master
# Verify your changes
git diff master@{1}
الحل 3:غير التفاعلية ريبس
هذا سوف تعمل فقط إذا كنت ترغب في إزالة يرتكبون من التاريخ تماما:
# Create a new branch at the parent-commit of the commit that you want to remove
git branch temp <parent-commit>
# Rebase onto the parent-commit, starting from the commit-to-remove
git rebase --preserve-merges --onto temp <commit-to-remove> master
# Or use `-p` insteda of the longer `--preserve-merges`
git rebase -p --onto temp <commit-to-remove> master
# Verify your changes
git diff master@{1}
الحل 4:التفاعلية Rebases
هذا الحل سوف تسمح لك أن تفعل نفس الأشياء حلول #2 #3, أيتعديل أو إزالة يرتكب أخرى إلى الوراء في التاريخ من الخاص بك على الفور السابقة لارتكاب لذا الحل الذي اخترت استخدام نوع من متروك لكم.التفاعلية rebases ليست مناسبة تماما إلى اتخاذ مئات من يرتكب ، أسباب الأداء, لذلك أود أن استخدام غير التفاعلية rebases أو تصفية فرع الحل (انظر أدناه) في هذا النوع من الحالات.
لبدء التفاعلية ريبس ، واستخدام التالية:
git rebase --interactive <commit-to-amend-or-remove>~
# Or `-i` instead of the longer `--interactive`
git rebase -i <commit-to-amend-or-remove>~
وهذا سوف يسبب بوابة الترجيع ارتكاب تاريخ العودة إلى الأصل ارتكاب الذي تريد تعديله أو إزالته.ثم سوف نقدم لكم قائمة لف يرتكب في ترتيب عكسي في أي محرر بوابة لاستخدام (هذا هو همة بشكل افتراضي):
pick 00ddaac Add symlinks for executables
pick 03fa071 Set `push.default` to `simple`
pick 7668f34 Modify Bash config to use Homebrew recommended PATH
pick 475593a Add global .gitignore file for OS X
pick 1b7f496 Add alias for Dr Java to Bash config (OS X)
ارتكاب الذي ترغب في تعديل أو إزالة سوف يكون في الجزء العلوي من هذه القائمة.إلى إزالته ، ببساطة حذف خط في القائمة.وإلا محل "اختيار" مع "تحرير" في 1st خط, مثل ذلك:
edit 00ddaac Add symlinks for executables
pick 03fa071 Set `push.default` to `simple`
ثم أدخل git rebase --continue
.إذا اخترت إزالة ارتكاب تماما ،
ثم أنه كل ما عليك القيام به (بخلاف التحقق ، راجع الخطوة النهائية على
هذا الحل).إذا, من ناحية أخرى, أردت تعديل يرتكبون ثم git
سوف تطبيق لارتكاب ثم وقفة ريبس.
Stopped at 00ddaacab0a85d9989217dd9fe9e1b317ed069ac... Add symlinks
You can amend the commit now, with
git commit --amend
Once you are satisfied with your changes, run
git rebase --continue
عند هذه النقطة يمكنك إزالة ملف تعديل ارتكابها ، ثم مواصلة ريبس:
git rm <file>
git commit --amend --no-edit
git rebase --continue
هذا هو.كخطوة نهائية ، ما إذا كان يمكنك تعديل ارتكاب أو إزالته تماما, انها دائما فكرة جيدة للتحقق من أنه لا توجد تغييرات غير متوقعة قدمت إلى فرع من diffing مع الدولة قبل ريبس:
git diff master@{1}
الحل 5:تصفية فروع
أخيرا, هذا الحل هو أفضل إذا كنت تريد أن يمحو تماما كل آثار ملف الوجود من التاريخ ، أي من الحلول الأخرى هي تماما حتى هذه المهمة.
git filter-branch --index-filter \
'git rm --cached --ignore-unmatch <file>'
التي من شأنها إزالة <file>
من كل ما يرتكب ، بدءا من الجذر يرتكبها.إذا
بدلا من ذلك كنت ترغب فقط في كتابة ارتكاب مجموعة HEAD~5..HEAD
, ثم يمكنك
تمر بأنه حجة إضافية إلى filter-branch
, كما أشار في
هذا الجواب:
git filter-branch --index-filter \
'git rm --cached --ignore-unmatch <file>' HEAD~5..HEAD
مرة أخرى, بعد filter-branch
كاملة, انها عادة ما تكون فكرة جيدة للتحقق من
بأن هناك تغييرات غير متوقعة من قبل diffing الفرع الخاص بك مع
حالته السابقة قبل تصفية العملية:
git diff master@{1}
تصفية فرع البديلة:BFG الريبو نظافة
لقد سمعت أن BFG الريبو نظافة أداة يعمل بشكل أسرع من git filter-branch
, لذلك قد ترغب في التحقق من ذلك كخيار أيضا. حتى انه ذكر رسميا في تصفية-فرع توثيق كبديل عملي:
بوابة-فلتر-فرع يسمح لك لجعل مجمع قذيفة كتابتها كتابة من بوابة التاريخ, ولكن ربما كنت لا تحتاج إلى هذه المرونة إذا أنت ببساطة إزالة البيانات غير المرغوب فيها مثل الملفات الكبيرة أو كلمات السر.هذه العمليات قد ترغب في النظر في إن BFG الريبو-نظافة, ، JVM على أساس بديل git-فلتر-فرع عادة ما لا يقل عن 10-50x أسرع تلك حالات الاستخدام ، مع خصائص مختلفة تماما:
أي نسخة من الملف يتم تنظيف بالضبط مرة واحدة.إن BFG, على عكس بوابة-فلتر-فرع لا نقدم لك الفرصة للتعامل مع ملف بشكل مختلف استنادا إلى أين أو متى ارتكبت في إطار الخاص بك التاريخ.هذا القيد يعطي الأداء الأساسية فائدة BFG و هي مناسبة تماما أن مهمة تطهير البيانات السيئة - لا الرعاية حيث السيئة البيانات ، فقط تريد ذلك ذهب.
افتراضيا BFG يأخذ الاستفادة الكاملة من أجهزة متعددة النوى ، التطهير ارتكاب ملف الأشجار في نفس الوقت.بوابة-فلتر-فرع ينظف يرتكب بالتتابع (أي في ترابط واحد الطريقة) ، على الرغم من أنه هو من الممكن أن أكتب الفلاتر التي تشمل بهم parallellism ، الكتابات تنفيذها ضد كل من يرتكبها.
على الأمر الخيارات بكثير أكثر تقييدا من بوابة تصفية فرع مخصص فقط مهام إزالة البيانات غير المرغوب فيها - هـ.g:
--strip-blobs-bigger-than 1M
.
موارد إضافية
إذا لم يرتكبوا أي شيء منذ ذلك الحين، فقط git rm
الملف وgit commit --amend
.
إذا كان لديك
git filter-branch \
--index-filter 'git rm --cached --ignore-unmatch path/to/file/filename.orig' merge-point..HEAD
وسوف تذهب من خلال كل تغيير من merge-point
إلى HEAD
، حذف filename.orig وإعادة كتابة التغيير. باستخدام --ignore-unmatch
يعني أن الأمر لا تفشل إذا لسبب filename.orig مفقود من التغيير. هذه هي الطريقة الموصى بها من باب الأمثلة في بوابة تصفية فرع الصفحة رجل .
ملحوظة لمستخدمي ويندوز: مسار الملف يجب استخدام خطوط مائلة إلى الأمام
هذا هو أفضل وسيلة:
http://github.com/guides/completely-remove-a-file-from-all-revisions
فقط تأكد من النسخ الاحتياطي على نسخ من الملفات أولا.
تحرير
تحرير من قبل النيون حصلت للأسف رفض أثناء الاستعراض.
انظر نونس دون آخر, قد تحتوي على معلومات مفيدة!
E. g.لإزالة جميع *.gz
الملفات عن طريق الخطأ ارتكبت في git:
$ du -sh .git ==> e.g. 100M
$ git filter-branch --index-filter 'git rm --cached --ignore-unmatch *.gz' HEAD
$ git push origin master --force
$ rm -rf .git/refs/original/
$ git reflog expire --expire=now --all
$ git gc --prune=now
$ git gc --aggressive --prune=now
التي لا تزال لم يكن العمل بالنسبة لي ؟ (أنا حاليا في بوابة النسخة 1.7.6.1)
$ du -sh .git ==> e.g. 100M
لست متأكدا لماذا, منذ لم يكن لدي سوى سيد واحد فرع.على أي حال, أنا أخيرا حصلت بوابة الريبو حقا تنظيف عن طريق دفع جديدة فارغة وعارية git, على سبيل المثال
$ git init --bare /path/to/newcleanrepo.git
$ git push /path/to/newcleanrepo.git master
$ du -sh /path/to/newcleanrepo.git ==> e.g. 5M
(نعم!)
ثم استنساخ هذا دليل جديد وانتقلت أكثر من ذلك .بوابة المجلد إلى هذا واحد.على سبيل المثال
$ mv .git ../large_dot_git
$ git clone /path/to/newcleanrepo.git ../tmpdir
$ mv ../tmpdir/.git .
$ du -sh .git ==> e.g. 5M
(نعم!أخيرا تنظيف!)
بعد التحقق من أن كل شيء على ما يرام, ثم يمكنك حذف ../large_dot_git
و ../tmpdir
الدلائل (ربما في بضعة أسابيع أو شهر من الآن ، فقط في حالة...)
إعادة كتابة بوابة التاريخ مطالب تغيير جميع المتضررين ارتكاب معرفات ، وهكذا كل من عمل على هذا المشروع سوف تحتاج إلى حذف النسخ القديمة من الريبو ، هل من جديد استنساخ بعد تنظيفها التاريخ.المزيد من الناس المضايقات ، كلما كنت في حاجة الى سبب وجيه للقيام بذلك - الخاص بك زائدة الملف ليس حقا يسبب مشكلة ، ولكن فقط إذا لك هي العمل على المشروع ، قد وكذلك تنظيف بوابة التاريخ إذا كنت تريد!
أن تجعل من السهل ممكن ، أنصح باستخدام BFG الريبو-نظافة, أسهل, أسرع بديل git-filter-branch
مصممة خصيصا لإزالة الملفات من بوابة التاريخ.إحدى الطرق التي يجعل حياتك أسهل هنا هو أنه في الواقع مقابض كل الحكام بشكل افتراضي (جميع العلامات الفروع ، الخ) لكنه أيضا 10 - 50x بشكل أسرع.
يجب أن بعناية اتبع الخطوات هنا: http://rtyley.github.com/bfg-repo-cleaner/#usage - ولكن بت الأساسية هي هذه:تحميل BFG جرة (يتطلب جافا 6 أو أعلى) و تشغيل هذا الأمر:
$ java -jar bfg.jar --delete-files filename.orig my-repo.git
الخاص بك كامل مستودع التاريخ سيتم فحص أي ملف اسمه filename.orig
(هذا ليس في أحدث ارتكاب) سيتم إزالتها.هذا هو أسهل بكثير من استخدام git-filter-branch
أن تفعل الشيء نفسه!
الإفصاح الكامل:أنا صاحب BFG الريبو-نظافة.
You should probably clone your repository first.
Remove your file from all branches history:
git filter-branch --tree-filter 'rm -f filename.orig' -- --all
Remove your file just from the current branch:
git filter-branch --tree-filter 'rm -f filename.orig' -- --HEAD
Lastly you should run to remove empty commits:
git filter-branch -f --prune-empty -- --all
وفقط أن أضيف أن لحل تشارلز بيلي، كنت مجرد بوابة rebase -i لإزالة الملفات غير المرغوب فيها من قبل ارتكابها وعملت مثل السحر. الخطوات:
# Pick your commit with 'e'
$ git rebase -i
# Perform as many removes as necessary
$ git rm project/code/file.txt
# amend the commit
$ git commit --amend
# continue with rebase
$ git rebase --continue
واقترح إن أبسط طريقة لقد وجدت من قبل leontalbot
(كتعليق)، والذي هو <وأ href = "http://www.zyxware.com/articles/4027/how-to-delete-files-permanently- من-عن بعد GIT-مستودعات الخاص بك المحلية و"يختلط =" "> آخر نوفولو نشرتها Anoopjohn . أعتقد قيمته الفضاء الخاصة بها كإجابة:
و(I تحويلها إلى برنامج نصي باش)
#!/bin/bash
if [[ $1 == "" ]]; then
echo "Usage: $0 FILE_OR_DIR [remote]";
echo "FILE_OR_DIR: the file or directory you want to remove from history"
echo "if 'remote' argument is set, it will also push to remote repository."
exit;
fi
FOLDERNAME_OR_FILENAME=$1;
#The important part starts here: ------------------------
git filter-branch -f --index-filter "git rm -rf --cached --ignore-unmatch $FOLDERNAME_OR_FILENAME" -- --all
rm -rf .git/refs/original/
git reflog expire --expire=now --all
git gc --prune=now
git gc --aggressive --prune=now
if [[ $2 == "remote" ]]; then
git push --all --force
fi
echo "Done."
وجميع الاعتمادات تذهب إلى Annopjohn
، وleontalbot
لافتا من ذلك.
<قوية> ملاحظة
كن على علم أن السيناريو لا يشمل التحقق من صحة، لذلك تأكد من أنك لا يخطئ وأنه لديك نسخة احتياطية في حالة حدوث خطأ ما. لأنها عملت لي، ولكن قد لا يعمل في وضعك. استخدامه مع تحذير (اتبع الرابط إذا كنت تريد أن تعرف ما يجري).
وبالتأكيد، git filter-branch
هو الطريق للذهاب.
للأسف، وهذا لن يكون كافيا لإزالة filename.orig
من الريبو الخاصة بك، كما أنه يمكن أن يزال من الممكن الرجوع إليها بواسطة العلامات، وإدخالات reflog، أجهزة التحكم عن بعد وهلم جرا.
وأوصي إزالة جميع هذه المراجع أيضا، ثم استدعاء جامع القمامة. يمكنك استخدام البرنامج النصي git forget-blob
من <لأ href = "https://ownyourbits.com/2017/01/18/completely-remove-a-file-from-a-git-repository-with-git-forget-blob/ "يختلط =" نوفولو noreferrer "> هذا الموقع لتفعل كل هذا في خطوة واحدة.
وgit forget-blob filename.orig
إذا كان هو آخر ارتكاب تريد تنظيف، حاولت مع النسخة بوابة 2.14.3 (أبل بوابة 98):
touch empty
git init
git add empty
git commit -m init
# 92K .git
du -hs .git
dd if=/dev/random of=./random bs=1m count=5
git add random
git commit -m mistake
# 5.1M .git
du -hs .git
git reset --hard HEAD^
git reflog expire --expire=now --all
git gc --prune=now
# 92K .git
du -hs .git
وهذا ما git filter-branch
صمم ل.
ويمكنك أيضا استخدام:
وgit reset HEAD file/path