كيف يمكنك إصلاح سيئة الدمج و إعادة جيد يرتكب على ثابت دمج?

StackOverflow https://stackoverflow.com/questions/307828

سؤال

أنا بطريق الخطأ ارتكب ملف غير المرغوب فيها (filename.orig في حين حل دمج) إلى مستودع عدة يرتكب مضت دون أن يلاحظ ذلك حتى الآن.أريد تماما حذف الملف من مستودع التاريخ.

هل من الممكن كتابة تاريخ التغيير هذه filename.orig لم يكن إضافة إلى مستودع في المقام الأول ؟

هل كانت مفيدة؟

المحلول

يرجى عدم استخدام هذه الوصفة إذا كان الوضع الخاص بك ليس هو المذكور في السؤال.هذا هو وصفة لإصلاح سوء دمج ، وتعيد الخاص بك جيدة يرتكب على ثابت دمج.

على الرغم من أن filter-branch سوف تفعل ما تريد, فإنه لا بأس به الأمر تعقيدا و ربما تختار أن تفعل هذا مع git rebase.ربما تفضيل شخصي. filter-branch في واحد قليلا أكثر تعقيدا القيادة ، بينما rebase الحل هو أداء ما يعادل العمليات المنطقية خطوة واحدة في وقت واحد.

جربي الوصفة التالية:

(ملاحظة أنك لا تحتاج في الواقع مؤقت فرع ، يمكنك أن تفعل هذا مع فصل الرأس', ولكن تحتاج إلى أن تأخذ علما ارتكاب id الناتجة عن git commit --amend خطوة إلى إمدادات git rebase الأمر بدلا من استخدام مؤقت اسم الفرع.)

نصائح أخرى

مقدمة:لديك 5 الحلول المتاحة

الملصق الأصلي الدول:

أنا بطريق الخطأ ارتكب ملف غير المرغوب فيها إلى مستودع عدة يرتكب مضت...أريد تماما حذف الملف من مستودع التاريخ.

هو من الممكن كتابة تاريخ التغيير هذه filename.orig لم يكن إضافة إلى مستودع في المقام الأول ؟

هناك العديد من الطرق المختلفة لإزالة تاريخ الملف تماما من بوابة:

  1. تعديل يرتكب.
  2. من الصعب إعادة تعيين (ربما بالإضافة إلى ريبس).
  3. غير التفاعلية ريبس.
  4. التفاعلية rebases.
  5. تصفية الفروع.

في حالة الملصق الأصلي, تعديل ارتكاب ليس خيارا في حد ذاته ، حيث أنه قدم عدة إضافية يرتكب بعد ذلك ، ولكن من أجل من اكتمالها ، كما سيتم شرح كيفية القيام بذلك ، من أجل أي شخص آخر justs يريد تعديل السابقة يرتكبها.

لاحظ أن جميع هذه الحلول تتضمن تعديل/إعادة الكتابة التاريخ/يرتكب في طريقة واحدة أخرى, لذلك أي شخص مع النسخ القديمة من يرتكب سوف تضطر إلى القيام به العمل الإضافي إلى إعادة تزامن تاريخها مع تاريخ جديد.


الحل 1:تعديل يرتكب

إذا كنت غير قصد إجراء تغيير (مثل إضافة ملف) في السابق ارتكاب وأنت لا تريد من تاريخ هذا التغيير إلى وجود بعد الآن ، ثم يمكنك ببساطة تعديل السابقة تلتزم إزالة الملف من:

git rm <file>
git commit --amend --no-edit

الحل 2:من الصعب إعادة تعيين (ربما بالإضافة إلى ريبس)

مثل الحل #1, إذا كنت تريد فقط التخلص من السابق ارتكابها ، ثم لديك أيضا خيار من مجرد القيام من الصعب إعادة تعيين إلى الأم:

git reset --hard HEAD^

هذا الأمر من الصعب إعادة تعيين الخاص بك الفرع السابق 1st الأم يرتكبها.

ومع ذلك, إذا, مثل الملصق الأصلي ، لقد جعلت العديد من يرتكب بعد ارتكاب كنت تريد التراجع عن التغيير ، لا يزال بإمكانك استخدام من الصعب إعادة تعيين إلى تعديله ، ولكن ذلك ينطوي أيضا على استخدام ريبس.هنا هي الخطوات التي يمكنك استخدامها لتعديل ارتكاب المزيد من الوراء في التاريخ:


الحل 3:غير التفاعلية ريبس

هذا سوف تعمل فقط إذا كنت ترغب في إزالة يرتكبون من التاريخ تماما:


الحل 4:التفاعلية Rebases

هذا الحل سوف تسمح لك أن تفعل نفس الأشياء حلول #2 #3, أيتعديل أو إزالة يرتكب أخرى إلى الوراء في التاريخ من الخاص بك على الفور السابقة لارتكاب لذا الحل الذي اخترت استخدام نوع من متروك لكم.التفاعلية rebases ليست مناسبة تماما إلى اتخاذ مئات من يرتكب ، أسباب الأداء, لذلك أود أن استخدام غير التفاعلية rebases أو تصفية فرع الحل (انظر أدناه) في هذا النوع من الحالات.

لبدء التفاعلية ريبس ، واستخدام التالية:

وهذا سوف يسبب بوابة الترجيع ارتكاب تاريخ العودة إلى الأصل ارتكاب الذي تريد تعديله أو إزالته.ثم سوف نقدم لكم قائمة لف يرتكب في ترتيب عكسي في أي محرر بوابة لاستخدام (هذا هو همة بشكل افتراضي):

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:تصفية فروع

أخيرا, هذا الحل هو أفضل إذا كنت تريد أن يمحو تماما كل آثار ملف الوجود من التاريخ ، أي من الحلول الأخرى هي تماما حتى هذه المهمة.

التي من شأنها إزالة <file> من كل ما يرتكب ، بدءا من الجذر يرتكبها.إذا بدلا من ذلك كنت ترغب فقط في كتابة ارتكاب مجموعة HEAD~5..HEAD, ثم يمكنك تمر بأنه حجة إضافية إلى filter-branch, كما أشار في هذا الجواب:

مرة أخرى, بعد 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.

موارد إضافية

  1. برو بوابة § 6.4 أدوات بوابة - إعادة كتابة التاريخ.
  2. بوابة-فلتر-فرع(1) دليل الصفحة.
  3. بوابة الالتزام(1) دليل الصفحة.
  4. بوابة إعادة تعيين(1) دليل الصفحة.
  5. بوابة ريبس(1) دليل الصفحة.
  6. إن BFG الريبو نظافة (انظر أيضا هذا الجواب من الخالق نفسه).

إذا لم يرتكبوا أي شيء منذ ذلك الحين، فقط 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

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top