Làm thế nào để loại bỏ vĩnh viễn một số cam kết từ chi nhánh từ xa


490

Tôi biết đó là viết lại lịch sử đó là xấu yada yada.

Nhưng làm thế nào để loại bỏ vĩnh viễn vài cam kết từ chi nhánh từ xa?


96
Vâng, nó thực sự tệ yada yada, nhưng vì một số lý do tôi cần phải yêu thích nó.
James Morris

44
Tôi biết điều này là ngu ngốc, nhưng đôi khi shit xảy ra - như kiểm tra đăng nhập và sử dụng mật khẩu văn bản đơn giản trong mã của bạn, đó là thông tin đăng nhập thực sự. Và rất tiếc ...
frhd

6
thông tin đăng nhập thực sự .. Yeah nhắc tôi về một số whoopos
Xin chào vũ trụ


2
Tôi đã quá mệt mỏi với vấn đề học thuật này về mức độ nguy hiểm của nó và cách nó không bao giờ nên được thực hiện yada yada. Có những lúc nó tốt hơn rất nhiều để loại bỏ các thứ khỏi lịch sử git và đối phó với các xung đột / phá vỡ của các nhà phát triển khác. Nó thực sự đơn giản. Những người bỏ qua điều này có lẽ không bao giờ làm việc bên ngoài lớp học.
đè bẹp

Câu trả lời:


368

Bạn git reset --hardchi nhánh địa phương của bạn để loại bỏ các thay đổi từ cây và chỉ mục làm việc, và bạn git push --forcechi nhánh địa phương sửa đổi của bạn vào điều khiển từ xa. ( giải pháp khác ở đây , liên quan đến việc xóa chi nhánh từ xa và đẩy lại nó)

Câu trả lời SO này minh họa sự nguy hiểm của một lệnh như vậy, đặc biệt nếu mọi người phụ thuộc vào lịch sử từ xa cho các repos địa phương của riêng họ.
Bạn cần chuẩn bị để chỉ ra mọi người vào phần THU HỒI TỪ UPSTREAM REBASE của git rebasetrang man


Với Git 2.23 (tháng 8 năm 2019, chín năm sau), bạn sẽ sử dụng lệnh mới git switch.
Đó là: (thay thế bằng số lần xác nhận cần xóa)git switch -C mybranch origin/mybranch~n
n

Điều đó sẽ khôi phục chỉ mục và cây làm việc, giống như một git reset --hard.


Lạ thật. Cảm giác như tôi đã thử nó rồi. Cùng với một số nổi loạn - hoạt động như một nét duyên dáng. Cảm ơn.
Arnis Lapsa

7
@Arni: hoàn hảo rồi;) push --forceđi
VonC

Tôi đã sử dụng BFG Repo-Cleaner để loại bỏ một số dữ liệu nhạy cảm, khiến tôi có một nhánh "không tên" với tệp gốc trên đó, sau khi thiết lập lại cam kết mong muốn cuối cùng và khó đẩy về nguồn gốc, tất cả đều ổn (:
Rodrirokr

Lưu ý rằng URL của cam kết vẫn còn tồn tại (ít nhất là trong một thời gian) vì vậy nếu ai đó có URL của cam kết (bạn đã đưa nó cho thượng đế biết tại sao), họ sẽ có thể truy cập mã.
Mosh Feu

1
@MoshFeu Đúng: git gckhông phải lúc nào cũng chạy đủ thường xuyên ở phía xa. Ví dụ: trên GitHub: twitter.com/githubhelp/status/387926738161774592?lang=es
VonC

248

Chỉ cần lưu ý để sử dụng last_working_commit_id, khi hoàn nguyên một cam kết không hoạt động

git reset --hard <last_working_commit_id>

Vì vậy, chúng tôi không được thiết lập lại commit_idmà chúng tôi không muốn.

Sau đó, chắc chắn, chúng ta phải đẩy đến chi nhánh từ xa:

git push --force

10
Câu trả lời hoàn hảo, thanh lịch, đơn giản nhất. Tôi vừa trở lại cam kết stabe cuối cùng mà tôi cần cả ở xa và cục bộ
lauWM

2
Điều này khiến tôi mất đi những thay đổi địa phương của tôi quá. Tôi đã không mong đợi điều đó. Nhưng meh, tốt hơn là cam kết mật khẩu cá nhân của bạn để làm việc repo.
Airwavezx

3
bạn có thể lưu các thay đổi cục bộ của mình bằng git stash .... tạo một số thứ .... và git stash pop (các thay đổi cục bộ của bạn đã hoạt động trở lại)
MonTea

Điều này mang lại cho tôi lỗi là "từ xa: lỗi: từ chối các ref /
head

@Airwavezx đó là những gì git reset --hardphải làm.
Lu-ca

146

Quan trọng: Đảm bảo bạn chỉ định các nhánh nào trên "git push -f" hoặc bạn có thể vô tình sửa đổi các nhánh khác! [*]

Có ba tùy chọn hiển thị trong hướng dẫn này . Trong trường hợp liên kết bị phá vỡ, tôi sẽ để lại các bước chính ở đây.

  1. Hoàn nguyên cam kết
  2. Xóa cam kết cuối cùng
  3. Xóa cam kết khỏi danh sách

1 Hoàn nguyên cam kết đầy đủ

git revert dd61ab23

2 Xóa cam kết cuối cùng

git push <<remote>> +dd61ab23^:<<BRANCH_NAME_HERE>>

hoặc, nếu chi nhánh có sẵn tại địa phương

git reset HEAD^ --hard
git push <<remote>> -f

trong đó + dd61 ... là hàm băm cam kết và git của bạn diễn giải x ^ với tư cách là cha mẹ của x và + là một lực đẩy không nhanh chóng bắt buộc.

3 Xóa cam kết khỏi danh sách

git rebase -i dd61ab23^

Điều này sẽ mở và biên tập hiển thị một danh sách của tất cả các cam kết. Xóa cái bạn muốn thoát khỏi. Kết thúc cuộc nổi loạn và đẩy lực lượng để repo.

git rebase --continue
git push <remote_repo> <remote_branch> -f

5
Hãy chắc chắn rằng bạn chỉ định các nhánh nào trên "git đẩy <remote_Vpo> <remote_branch> -f" hoặc bạn có thể vô tình sửa đổi các nhánh khác!
Nigel Sheridan-Smith

Chỉ bước 1 và 2 đã thực hiện công việc và trả lời câu hỏi ban đầu. (Đừng chạy bước 3)
Saad Benbouzid 11/03/2016

Đây là các tùy chọn cho các kịch bản khác nhau, không phải các bước để thực hiện. Trong trường hợp của tôi, rebase tương tác (Tùy chọn 3) đã làm những gì tôi đang tìm kiếm.
Steve Blackwell

Tôi đã phải làm bước 3 mặc dù. Tại sao bạn không nên chạy @Saad này? May mắn thay, << remote >> của tôi chỉ đơn giản là 'nguồn gốc' mặc định và <remote_branch> 'chủ nhân' mặc định
Bart

30

Nếu bạn muốn xóa ví dụ các lần xác nhận cuối cùng 3, hãy chạy lệnh sau để xóa các thay đổi khỏi hệ thống tệp (cây làm việc) và lịch sử cam kết (chỉ mục) trên nhánh cục bộ của bạn:

git reset --hard HEAD~3

Sau đó chạy lệnh sau (trên máy cục bộ của bạn) để buộc nhánh từ xa viết lại lịch sử của nó:

git push --force

Xin chúc mừng! Tất cả đã được làm xong!

Một số lưu ý:

Bạn có thể truy xuất id xác nhận mong muốn bằng cách chạy

git log

Sau đó, bạn có thể thay thế HEAD~Nbằng <desired-commit-id>như thế này:

git reset --hard <desired-commit-id>

Nếu bạn muốn giữ các thay đổi trên hệ thống tệp và chỉ sửa đổi chỉ mục (lịch sử cam kết), hãy sử dụng --softcờ như thế nào git reset --soft HEAD~3. Sau đó, bạn có cơ hội kiểm tra các thay đổi mới nhất của mình và giữ hoặc bỏ tất cả hoặc một phần của chúng. Trong trường hợp sau, runnig git statushiển thị các tệp đã thay đổi kể từ đó <desired-commit-id>. Nếu bạn sử dụng --hardtùy chọn, git statussẽ cho bạn biết rằng chi nhánh địa phương của bạn giống hệt như chi nhánh từ xa. Nếu bạn không sử dụng --hardcũng không --soft, chế độ mặc định được sử dụng --mixed. Trong chế độ này, git help resetnói:

Đặt lại chỉ mục nhưng không phải cây làm việc (nghĩa là các tệp đã thay đổi được giữ nguyên nhưng không được đánh dấu cho cam kết) và báo cáo những gì chưa được cập nhật.


10

Điều này có thể là quá ít quá muộn nhưng điều giúp tôi là tùy chọn 'hạt nhân' nghe hay. Về cơ bản bằng cách sử dụng lệnh, filter-branchbạn có thể xóa tệp hoặc thay đổi một số lượng lớn tệp trong toàn bộ lịch sử git của mình.

Nó được giải thích tốt nhất ở đây .


9
Không quá muộn. Có thể trở nên hữu ích cho những kẻ lang thang có vấn đề tương tự :)
Arnis Lapsa

9

Đơn giản hóa từ câu trả lời của pctroll, tương tự dựa trên bài đăng trên blog này .

# look up the commit id in git log or on github, e.g. 42480f3, then do
git checkout master
git checkout your_branch
git revert 42480f3
# a text editor will open, close it with ctrl+x (editor dependent)
git push origin your_branch
# or replace origin with your remote

2
Làm việc cho tôi, cảm ơn. Và tôi muốn xóa vĩnh viễn một cam kết (ví dụ: chứa pwd) khỏi lịch sử chi nhánh từ xa, làm thế nào để làm điều này?
Mỉm cười

1
Tôi cũng làm việc với tôi, nhưng tôi có cùng một câu hỏi so với Smiles, tôi không muốn bất kỳ ai nhìn thấy cam kết / sự tôn kính của tôi trong lịch sử .. làm thế nào để tôi loại bỏ điều đó?
Roberto Rodriguez

4

Đôi khi cách dễ nhất để khắc phục vấn đề này là tạo một chi nhánh mới từ nơi bạn biết mã là tốt. Sau đó, bạn có thể để lại lịch sử chi nhánh sai lầm trong trường hợp bạn cần chọn các cam kết khác từ nó sau này. Điều này cũng đảm bảo bạn không mất bất kỳ lịch sử cam kết nào.

Từ chi nhánh sai lầm địa phương của bạn:

git log

sao chép hàm băm cam kết mà bạn muốn chi nhánh ở và thoát khỏi nhật ký git

git checkout theHashYouJustCopied
git checkout -b your_new_awesome_branch

Bây giờ bạn có một chi nhánh mới theo cách bạn muốn.

Nếu bạn cũng cần giữ một cam kết cụ thể từ nhánh sai lầm không có trên nhánh mới của mình, bạn có thể chọn cherry mà bạn cần:

git checkout the_errant_branch
git log

Sao chép hàm băm cam kết của một cam kết bạn cần để kéo vào nhánh tốt và thoát khỏi nhật ký git.

git checkout your_new_awesome_branch
git cherry-pick theHashYouJustCopied

Hãy vỗ nhẹ vào lưng.


rất dễ dàng và ai quan tâm nếu bạn có một nhánh chết? tạo một chi nhánh mới và được thực hiện với nó!
Andrew Fox

Đây là một câu trả lời thực sự xuất sắc. Tôi vui vì tôi đã làm điều này thay vì các cam kết hái anh đào, hoặc thao túng chi nhánh từ xa.
Magnilex

0
 git reset --soft commit_id
 git stash save "message"
 git reset --hard commit_id
 git stash apply stash stash@{0}
 git push --force
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.