Làm thế nào để bạn sửa một hợp nhất xấu và phát lại các cam kết tốt của bạn vào một hợp nhất cố định?


407

Tôi đã vô tình cam kết một tệp không mong muốn ( filename.origtrong khi giải quyết hợp nhất) vào kho lưu trữ của tôi một số cam kết trước đây, mà tôi không nhận thấy nó cho đến bây giờ. Tôi muốn xóa hoàn toàn các tập tin từ lịch sử kho lưu trữ.

Có thể viết lại lịch sử thay đổi filename.origkhông bao giờ được thêm vào kho lưu trữ ở nơi đầu tiên không?



Câu trả lời:


297

Vui lòng không sử dụng công thức này nếu tình huống của bạn không được mô tả trong câu hỏi. Công thức này là để sửa lỗi hợp nhất xấu và phát lại các cam kết tốt của bạn vào một hợp nhất cố định.

Mặc dù filter-branchsẽ làm những gì bạn muốn, nó là một lệnh khá phức tạp và tôi có lẽ sẽ chọn làm điều này với git rebase. Có lẽ đó là một sở thích cá nhân. filter-branchcó thể làm điều đó trong một lệnh đơn, phức tạp hơn một chút, trong khirebase giải pháp đang thực hiện các hoạt động logic tương đương từng bước một.

Hãy thử công thức sau:

# 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

(Lưu ý rằng bạn không thực sự cần một chi nhánh tạm thời, bạn có thể làm điều này với một 'TRỤ tách', nhưng bạn cần phải thực hiện một lưu ý của id cam kết tạo ra bởi các git commit --amendbước để cung cấp cho các git rebaselệnh thay vì sử dụng các chi nhánh tạm thời Tên.)


6
Sẽ không git rebase -inhanh hơn và vẫn dễ dàng chứ? $ git rebase -i <sh1-of-merge> Đánh dấu chính xác là "chỉnh sửa" $ git rm somefile.orig $ git commit --amend $ git rebase --continue Tuy nhiên vì một số lý do tôi vẫn có tệp đó ở đâu đó cuối cùng thời gian tôi đã làm điều đó Có lẽ thiếu một cái gì đó.
Wernight

12
git rebase -irất hữu ích, đặc biệt là khi bạn có nhiều thao tác rebase-y để thực hiện, nhưng thật khó để mô tả chính xác khi bạn không thực sự chỉ qua vai ai đó và có thể thấy những gì họ đang làm với trình soạn thảo của họ. Tôi sử dụng vim, nhưng không phải ai cũng hài lòng với: "ggjcesquash <Esc> jddjp: wq" và các hướng dẫn như "Chuyển dòng trên cùng sang sau dòng thứ hai hiện tại và thay đổi từ đầu tiên trên dòng bốn thành 'chỉnh sửa' bây giờ lưu và chỉnh sửa bỏ "nhanh chóng có vẻ phức tạp hơn các bước thực tế. Bạn thường kết thúc với một số --amend--continuehành động, là tốt.
CB Bailey

3
Tôi đã làm điều này nhưng một cam kết mới đã được áp dụng lại trên đầu trang đã được sửa đổi, với cùng một thông điệp. Rõ ràng git đã hợp nhất 3 cách giữa cam kết cũ, không được cung cấp có chứa tệp không mong muốn và cam kết cố định từ nhánh khác, và do đó, nó đã tạo một cam kết mới trên đầu trang cũ, để áp dụng lại tệp.

6
@UncleCJ: Tệp của bạn đã được thêm vào trong một cam kết hợp nhất chưa? Điều này quan trọng. Công thức này được thiết kế để đối phó với một cam kết hợp nhất xấu. Nó sẽ không hoạt động nếu tệp không mong muốn của bạn được thêm vào một cam kết bình thường trong lịch sử.
CB Bailey

1
Tôi ngạc nhiên về cách tôi có thể làm tất cả điều này bằng cách sử dụng smartgit và không có thiết bị đầu cuối nào cả! Cảm ơn công thức!
cregox

209

Giới thiệu: Bạn có 5 giải pháp khả dụng

Các poster gốc nêu rõ:

Tôi đã vô tình cam kết một tệp không mong muốn ... vào kho lưu trữ của tôi một số lần xác nhận trước đây ... Tôi muốn xóa hoàn toàn tệp khỏi lịch sử kho lưu trữ.

Có thể viết lại lịch sử thay đổi filename.origkhông bao giờ được thêm vào kho lưu trữ ở nơi đầu tiên không?

Có nhiều cách khác nhau để xóa hoàn toàn lịch sử của tệp khỏi git:

  1. Sửa đổi cam kết.
  2. Đặt lại cứng (có thể cộng với một rebase).
  3. Rebase không tương tác.
  4. Cuộc nổi loạn tương tác.
  5. Lọc nhánh.

Trong trường hợp của poster gốc, việc sửa đổi cam kết không thực sự là một lựa chọn, vì anh ta đã thực hiện một số cam kết bổ sung sau đó, nhưng để hoàn thiện, tôi cũng sẽ giải thích cách thực hiện, cho bất kỳ ai khác muốn để sửa đổi cam kết trước đó của họ.

Lưu ý rằng tất cả các giải pháp này liên quan đến việc thay đổi / viết lại lịch sử / cam kết theo cách này theo cách khác, vì vậy bất kỳ ai có bản sao cũ của các cam kết sẽ phải làm thêm để đồng bộ lại lịch sử của họ với lịch sử mới.


Giải pháp 1: Cam kết sửa đổi

Nếu bạn vô tình thực hiện thay đổi (chẳng hạn như thêm tệp) trong lần xác nhận trước đó và bạn không muốn lịch sử của thay đổi đó tồn tại nữa, thì bạn có thể chỉ cần sửa đổi cam kết trước đó để xóa tệp khỏi nó:

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

Giải pháp 2: Thiết lập lại cứng (Có thể cộng với Rebase)

Giống như giải pháp số 1, nếu bạn chỉ muốn thoát khỏi cam kết trước đó, thì bạn cũng có tùy chọn đơn giản là thực hiện thiết lập lại cứng cho cha mẹ của nó:

git reset --hard HEAD^

Lệnh đó sẽ thiết lập lại chi nhánh của bạn thành cam kết cha mẹ thứ 1 trước đó .

Tuy nhiên , nếu, giống như người đăng ban đầu, bạn đã thực hiện một số cam kết sau khi cam kết bạn muốn hoàn tác thay đổi, bạn vẫn có thể sử dụng các thiết lập lại cứng để sửa đổi nó, nhưng làm như vậy cũng liên quan đến việc sử dụng rebase. Dưới đây là các bước mà bạn có thể sử dụng để sửa đổi một cam kết trở lại trong lịch sử:

# 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}

Giải pháp 3: Rebase không tương tác

Điều này sẽ hoạt động nếu bạn chỉ muốn xóa hoàn toàn một cam kết khỏi lịch sử:

# 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}

Giải pháp 4: Khởi động lại tương tác

Giải pháp này sẽ cho phép bạn thực hiện những điều tương tự như giải pháp # 2 và # 3, tức là sửa đổi hoặc xóa các cam kết trở lại trong lịch sử so với cam kết trước đó của bạn, do đó, giải pháp bạn chọn sử dụng là tùy thuộc vào bạn. Các cuộc nổi loạn tương tác không phù hợp để đánh bại hàng trăm cam kết, vì lý do hiệu suất, vì vậy tôi sẽ sử dụng các cuộc nổi loạn không tương tác hoặc giải pháp nhánh lọc (xem bên dưới) trong các tình huống đó.

Để bắt đầu rebase tương tác, sử dụng như sau:

git rebase --interactive <commit-to-amend-or-remove>~

# Or `-i` instead of the longer `--interactive`
git rebase -i <commit-to-amend-or-remove>~

Điều này sẽ khiến git tua lại lịch sử cam kết trở lại cha mẹ của cam kết mà bạn muốn sửa đổi hoặc xóa. Sau đó, nó sẽ hiển thị cho bạn một danh sách các cam kết tua lại theo thứ tự ngược trong bất kỳ git biên tập nào được đặt để sử dụng (đây là Vim theo mặc định):

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)

Cam kết mà bạn muốn sửa đổi hoặc xóa sẽ nằm ở đầu danh sách này. Để xóa nó, chỉ cần xóa dòng của nó trong danh sách. Nếu không, thay thế "chọn" bằng "chỉnh sửa" trên dòng thứ 1 , như vậy:

edit 00ddaac Add symlinks for executables
pick 03fa071 Set `push.default` to `simple`

Tiếp theo, nhập git rebase --continue. Nếu bạn chọn xóa hoàn toàn cam kết, thì đó là tất cả những gì bạn cần làm (ngoài xác minh, xem bước cuối cùng cho giải pháp này). Mặt khác, nếu bạn muốn sửa đổi cam kết, thì git sẽ áp dụng lại cam kết và sau đó tạm dừng rebase.

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

Tại thời điểm này, bạn có thể xóa tệp và sửa đổi cam kết, sau đó tiếp tục rebase:

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

Đó là nó. Bước cuối cùng, cho dù bạn đã sửa đổi cam kết hoặc loại bỏ hoàn toàn cam kết, thì luôn luôn nên xác minh rằng không có thay đổi bất ngờ nào được thực hiện cho chi nhánh của bạn bằng cách phân biệt nó với trạng thái của nó trước khi rebase:

git diff master@{1}

Giải pháp 5: Lọc các nhánh

Cuối cùng, giải pháp này là tốt nhất nếu bạn muốn xóa sạch hoàn toàn mọi dấu vết về sự tồn tại của tệp khỏi lịch sử và không có giải pháp nào khác hoàn toàn phù hợp với nhiệm vụ.

git filter-branch --index-filter \
'git rm --cached --ignore-unmatch <file>'

Điều đó sẽ loại bỏ <file>khỏi tất cả các cam kết, bắt đầu từ cam kết gốc. Nếu thay vào đó, bạn chỉ muốn viết lại phạm vi cam kết HEAD~5..HEAD, thì bạn có thể chuyển nó dưới dạng một đối số bổ sung filter-branch, như được chỉ ra trong câu trả lời này :

git filter-branch --index-filter \
'git rm --cached --ignore-unmatch <file>' HEAD~5..HEAD

Một lần nữa, sau khi filter-branchhoàn thành, thường là một ý tưởng tốt để xác minh rằng không có thay đổi bất ngờ nào khác bằng cách làm khác nhánh của bạn với trạng thái trước đó trước thao tác lọc:

git diff master@{1}

Bộ lọc thay thế chi nhánh: BFG Repo Cleaner

Tôi đã nghe nói rằng công cụ BFG Repo Cleaner chạy nhanh hơn git filter-branch, vì vậy bạn cũng có thể muốn kiểm tra xem đó là một tùy chọn. Nó thậm chí còn được đề cập chính thức trong tài liệu nhánh lọc như một sự thay thế khả thi:

git-filter-Branch cho phép bạn tạo các bản ghi lại theo kịch bản shell phức tạp trong lịch sử Git của bạn, nhưng bạn có thể không cần sự linh hoạt này nếu bạn chỉ cần xóa dữ liệu không mong muốn như các tệp lớn hoặc mật khẩu. Đối với các hoạt động đó, bạn có thể muốn xem xét BFG Repo-Cleaner , một giải pháp thay thế dựa trên JVM cho nhánh bộ lọc git, thường nhanh hơn ít nhất 10-50 lần cho các trường hợp sử dụng đó và với các đặc điểm khá khác nhau:

  • Bất kỳ phiên bản cụ thể của một tập tin được làm sạch chính xác một lần . BFG, không giống như chi nhánh git-filter, không cho bạn cơ hội xử lý một tệp khác nhau dựa trên vị trí hoặc thời điểm cam kết trong lịch sử của bạn. Hạn chế này cho phép hiệu quả lợi ích cốt lõi của BFG, và rất phù hợp với nhiệm vụ của làm sạch dữ liệu xấu - bạn không quan tâm nơi các dữ liệu xấu là, bạn chỉ muốn nó biến mất .

  • Theo mặc định, BFG tận dụng tối đa các máy đa lõi, song song xóa sạch các cây tệp cam kết. Làm sạch git-filter-branch cam kết liên tục (tức là một cách đơn ren), mặc dù nó có thể viết các bộ lọc bao gồm parallellism riêng của họ, trong kịch bản thực hiện với nhau cam kết.

  • Các tùy chọn lệnh hạn chế hơn nhiều so với nhánh bộ lọc git và chỉ dành riêng cho các tác vụ xóa dữ liệu không mong muốn - ví dụ : --strip-blobs-bigger-than 1M.

Tài nguyên bổ sung

  1. Pro Git § 6.4 Công cụ Git - Lịch sử viết lại .
  2. git-filter-Branch (1) Trang hướng dẫn .
  3. git-commit (1) Trang hướng dẫn .
  4. git-reset (1) Trang hướng dẫn .
  5. git-rebase (1) Trang hướng dẫn .
  6. BFG Repo Cleaner (xem thêm câu trả lời này từ chính người sáng tạo ).

filter-branchgây ra tính toán lại của băm? Nếu một nhóm làm việc với một repo trong đó một tệp lớn cần được lọc, làm thế nào để họ làm điều này để mọi người kết thúc với cùng một trạng thái của repo?
YakovL

@YakovL. Tất cả mọi thứ tính toán lại băm. Thực tế cam kết là bất biến. Nó tạo ra một lịch sử hoàn toàn mới và di chuyển con trỏ nhánh của bạn đến nó. Cách duy nhất để đảm bảo tất cả mọi người có cùng một lịch sử là thiết lập lại cứng.
Nhà vật lý điên

118

Nếu bạn chưa cam kết bất cứ điều gì kể từ đó, chỉ cần git rmcác tập tin và git commit --amend.

Nếu bạn có

git filter-branch \
--index-filter 'git rm --cached --ignore-unmatch path/to/file/filename.orig' merge-point..HEAD

sẽ đi qua từng thay đổi từ merge-pointđến HEAD, xóa filename.orig và viết lại thay đổi. Sử dụng --ignore-unmatchcó nghĩa là lệnh sẽ không thất bại nếu vì một số lý do filename.orig bị thiếu trong một thay đổi. Đó là cách được đề xuất từ ​​phần Ví dụ trong trang man git-filter-Branch .

Lưu ý cho người dùng Windows: Đường dẫn tệp phải sử dụng dấu gạch chéo


3
Cảm ơn! nhánh bộ lọc git làm việc cho tôi trong đó ví dụ rebase được đưa ra như một câu trả lời không: Các bước dường như hoạt động, nhưng sau đó đẩy không thành công. Đã kéo, sau đó đẩy thành công, nhưng tập tin vẫn còn xung quanh. Đã cố gắng làm lại các bước rebase và sau đó nó trở nên lộn xộn với các xung đột hợp nhất. Mặc dù vậy, tôi đã sử dụng một lệnh bộ lọc nhánh khác một chút, "Phương pháp cải tiến" được đưa ra ở đây: github.com/guides/completely-remove-a-file-from-all-revutions git filter-Branch -f --index- bộ lọc 'git update-index - ghi tên tập tin' <giới thiệu-sửa đổi-sha1> .. ĐẦU
nguyên tử

1
Tôi không chắc cái nào là phương pháp cải tiến . Tài liệu chính thức của Git git-filter-branchdường như đưa ra cái đầu tiên.
Wernight

5
Hãy xem zyxware.com/articles/4027/ Từ Tôi thấy đó là giải pháp hoàn chỉnh và thẳng tiến nhất có liên quanfilter-branch
leontalbot

2
@atomicules, nếu bạn cố gắng đẩy repo cục bộ sang điều khiển từ xa, git sẽ khăng khăng kéo từ xa trước, vì nó có những thay đổi mà bạn không có cục bộ. Bạn có thể sử dụng cờ - Force để đẩy đến điều khiển từ xa - nó sẽ xóa hoàn toàn các tệp khỏi đó. Nhưng hãy cẩn thận, đảm bảo bạn sẽ không ép buộc ghi đè lên một cái gì đó ngoài các tệp.
sol0mka

1
Hãy nhớ sử dụng "chứ không phải 'khi sử dụng Windows, hoặc bạn sẽ gặp phải lỗi "sửa đổi xấu" không đúng cách.
cz

49

Đây là cách tốt nhất:
http://github.com/guides/completely-remove-a-file-from-all-revutions

Chỉ cần chắc chắn sao lưu các bản sao của các tập tin đầu tiên.

BIÊN TẬP

Chỉnh sửa bởi neon đã không may bị từ chối trong quá trình xem xét.
Xem bài đăng Neons dưới đây, nó có thể chứa thông tin hữu ích!


Ví dụ: để xóa tất cả *.gzcác tệp vô tình cam kết vào kho 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

Điều đó vẫn không làm việc cho tôi? (Tôi hiện đang ở phiên bản git 1.7.6.1)

$ du -sh .git ==> e.g. 100M

Không chắc tại sao, vì tôi chỉ có MỘT nhánh chính. Dù sao, cuối cùng tôi cũng đã dọn dẹp được git repo của mình bằng cách đẩy vào một kho git trống và trống mới, vd

$ git init --bare /path/to/newcleanrepo.git
$ git push /path/to/newcleanrepo.git master
$ du -sh /path/to/newcleanrepo.git ==> e.g. 5M 

(Đúng!)

Sau đó, tôi sao chép nó vào một thư mục mới và chuyển qua thư mục .git của nó vào thư mục này. ví dụ

$ mv .git ../large_dot_git
$ git clone /path/to/newcleanrepo.git ../tmpdir
$ mv ../tmpdir/.git .
$ du -sh .git ==> e.g. 5M 

(yeah! cuối cùng đã được làm sạch!)

Sau khi xác minh rằng tất cả đều ổn, sau đó bạn có thể xóa các thư mục ../large_dot_git../tmpdirthư mục (có thể trong vài tuần hoặc vài tháng kể từ bây giờ, chỉ trong trường hợp ...)


1
Điều này làm việc cho tôi trước khi "Điều đó vẫn không làm việc cho tôi?" bình luận
shadi

Câu trả lời tuyệt vời, nhưng đề nghị thêm --prune-emptyvào lệnh bộ lọc nhánh.
ideaman42

27

Viết lại lịch sử Git yêu cầu thay đổi tất cả các id cam kết bị ảnh hưởng, và vì vậy mọi người đang làm việc trong dự án sẽ cần xóa các bản sao cũ của repo và tạo một bản sao mới sau khi bạn xóa lịch sử. Càng nhiều người bất tiện, bạn càng cần một lý do chính đáng để làm điều đó - tập tin thừa của bạn không thực sự gây ra vấn đề, nhưng nếu chỉ có bạn làm việc trong dự án, bạn cũng có thể xóa sạch lịch sử Git nếu bạn muốn đến!

Để làm cho nó dễ dàng nhất có thể, tôi khuyên bạn nên sử dụng BFG Repo-Cleaner , một cách thay thế đơn giản hơn, nhanh hơn để git-filter-branchđược thiết kế đặc biệt để xóa các tệp khỏi lịch sử Git. Một cách mà nó làm cho cuộc sống của bạn dễ dàng hơn ở đây là nó thực sự xử lý tất cả các ref theo mặc định (tất cả các thẻ, chi nhánh, v.v.) nhưng nó cũng 10 - 50x nhanh hơn lần.

Bạn nên cẩn thận làm theo các bước ở đây: http://rtyley.github.com/bfg-repo-cleaner/#usage - nhưng bit cốt lõi chỉ là thế này: tải xuống tệp BFG (yêu cầu Java 6 trở lên) và chạy lệnh này :

$ java -jar bfg.jar --delete-files filename.orig my-repo.git

Toàn bộ lịch sử kho lưu trữ của bạn sẽ được quét và bất kỳ tệp nào có tên filename.orig(không nằm trong cam kết mới nhất của bạn ) sẽ bị xóa. Điều này là dễ dàng hơn đáng kể so với việc sử dụng git-filter-branchđể làm điều tương tự!

Tiết lộ đầy đủ: Tôi là tác giả của BFG Repo-Cleaner.


4
Đây là một công cụ tuyệt vời: một lệnh duy nhất, nó tạo ra đầu ra rất rõ ràng và cung cấp một tệp nhật ký phù hợp với mọi cam kết cũ với lệnh mới . Tôi không thích cài đặt Java nhưng điều này đáng giá.
mikemaccana

Đây là điều duy nhất làm việc cho tôi nhưng đó là vì tôi đã không làm việc chính xác với nhánh lọc git. :-)
Kevin LaBranche

14
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

1
Mặc dù tất cả các câu trả lời dường như nằm trên rãnh của bộ lọc, nhưng câu trả lời này nêu bật cách làm sạch TẤT CẢ các nhánh trong lịch sử của bạn.
Cameron Lowell Palmer

4

Chỉ cần thêm nó vào giải pháp của Charles Bailey, tôi chỉ sử dụng một gase rebase -i để xóa các tệp không mong muốn khỏi một cam kết trước đó và nó hoạt động như một bùa mê. Các bước:

# 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

4

Cách đơn giản nhất mà tôi tìm thấy được đề xuất bởi leontalbot(như một bình luận), đó là một bài đăng được xuất bản bởi Anoopjohn . Tôi nghĩ rằng giá trị của nó không gian riêng của nó như là một câu trả lời:

(Tôi đã chuyển đổi nó thành tập lệnh bash)

#!/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."

Tất cả các khoản tín dụng đi đến Annopjohn, và để leontalbotchỉ ra nó.

GHI CHÚ

Xin lưu ý rằng tập lệnh không bao gồm các xác nhận hợp lệ, vì vậy hãy chắc chắn rằng bạn không mắc lỗi và bạn có bản sao lưu trong trường hợp có sự cố. Nó làm việc cho tôi, nhưng nó có thể không hoạt động trong tình huống của bạn. SỬ DỤNG CNTT VỚI THẬN TRỌNG (theo liên kết nếu bạn muốn biết chuyện gì đang xảy ra).


3

Chắc chắn, git filter-branchlà con đường để đi.

Đáng buồn thay, điều này sẽ không đủ để loại bỏ hoàn toàn filename.origkhỏi repo của bạn, vì nó vẫn có thể được tham chiếu bởi các thẻ, từ chối các mục, điều khiển từ xa, v.v.

Tôi cũng khuyên bạn nên xóa tất cả các tham chiếu này, và sau đó gọi trình thu gom rác. Bạn có thể sử dụng git forget-blobtập lệnh từ trang web này để thực hiện tất cả điều này trong một bước.

git forget-blob filename.orig


1

Nếu đó là cam kết mới nhất mà bạn muốn dọn dẹp, tôi đã thử với phiên bản git 2.14.3 (Apple Git-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 reflog expire --expire=now --all; git gc --prune=nowlà một điều rất xấu để làm. Trừ khi bạn hết dung lượng đĩa, hãy để git rác thu thập các cam kết này sau một vài tuần
avmohan

Cảm ơn đã chỉ ra rằng. Repo của tôi đã được gửi với nhiều tệp nhị phân lớn và repo được sao lưu hoàn toàn mỗi đêm. Vì vậy, tôi chỉ muốn mỗi bit ra khỏi nó;)
clarkttfu


-1

Bạn cũng có thể dùng:

git reset HEAD file/path


3
Nếu tệp đã được thêm vào một cam kết thì điều này thậm chí không xóa tệp khỏi chỉ mục, nó chỉ đặt lại chỉ mục thành phiên bản CHÍNH của tệp.
CB Bailey
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.