Git - Hoàn tác cam kết đẩy


609

Tôi có một dự án trong một kho lưu trữ từ xa, được đồng bộ hóa với một kho lưu trữ cục bộ (phát triển) và một máy chủ (prod). Tôi đã thực hiện một số thay đổi được cam kết đã được đẩy lên từ xa và được lấy từ máy chủ. Bây giờ, tôi muốn hoàn tác những thay đổi đó. Vì vậy, tôi chỉ có thể git checkoutcam kết trước những thay đổi và cam kết những thay đổi mới, nhưng tôi đoán rằng sẽ có vấn đề để đẩy chúng trở lại từ xa. Bất kỳ đề nghị về cách tôi nên tiến hành?


Câu trả lời:


735

Bạn có thể hoàn nguyên các cam kết cá nhân với:

git revert <commit_hash>

Điều này sẽ tạo ra một cam kết mới hoàn nguyên các thay đổi của cam kết bạn đã chỉ định. Lưu ý rằng nó chỉ hoàn nguyên cam kết cụ thể đó và không cam kết sau đó. Nếu bạn muốn hoàn nguyên một loạt các cam kết, bạn có thể làm như thế này:

git revert <oldest_commit_hash>..<latest_commit_hash>

Nó hoàn nguyên các cam kết giữa và bao gồm các cam kết đã chỉ định.

Nhìn vào trang man git-Revert để biết thêm thông tin về git revertlệnh. Cũng xem câu trả lời này để biết thêm thông tin về hoàn nguyên cam kết.


22
Nói cách khác, nó hoàn nguyên về <old_commit_hash>;)
David

7
@mr_j Jigsaw Sử dụnggit log
gitaarik

2
Trong tài liệu git, nó nói rằng lệnh hoàn nguyên hoàn nguyên các lần xác nhận giữa các lần xác nhận đầu tiên và lần cuối (bao gồm cả lần đầu tiên và lần cuối cùng). Xem Tài liệu
Onur Demir

4
@aod là chính xác, câu trả lời này cần phải được cập nhật. API git hiện tại cho hoàn nguyên đã <oldest_commit_hash>được đưa vào danh sách hoàn nguyên
JHixson

4
với git 2.17.2 hoàn nguyên <cũ> .. <mới> không bao gồm cũ nhưng bao gồm <new>
chingis

353

Một giải pháp không giữ dấu vết của "hoàn tác".

LƯU Ý: không làm điều này nếu ai đó đã sẵn sàng thay đổi bạn (tôi sẽ chỉ sử dụng điều này trên repo cá nhân của tôi)

làm:

git reset <previous label or sha1>

điều này sẽ kiểm tra lại tất cả các bản cập nhật cục bộ (vì vậy trạng thái git sẽ liệt kê tất cả các tệp được cập nhật)

sau đó bạn "thực hiện công việc của mình" và cam kết lại các thay đổi của bạn (Lưu ý: bước này là tùy chọn)

git commit -am "blabla"

Tại thời điểm này, cây địa phương của bạn khác với điều khiển từ xa

git push -f <remote-name> <branch-name>

sẽ đẩy và buộc từ xa để xem xét việc đẩy này và loại bỏ cái trước đó (chỉ định tên từ xa và tên chi nhánh là không bắt buộc nhưng được khuyến nghị để tránh cập nhật tất cả các chi nhánh với cờ cập nhật).

!! xem ra một số thẻ vẫn có thể bị xóa cam kết !! làm thế nào để xóa-a-remote-tag


4
-a tất cả các tệp được theo dõi sẽ được cam kết -m thông báo cam kết sau
jo_

3
Chính xác những gì tôi tìm kiếm. Ai đó đã thực hiện một cam kết bị lỗi và đẩy và hoàn nguyên nó một lần nữa sau đó. Các chi nhánh không thể được hợp nhất vì điều này và tôi muốn đưa kho lưu trữ trở lại trạng thái chính xác (và xóa cam kết khỏi lịch sử vì dù sao chúng cũng bị lỗi)
tạm biệt

1
Tôi nên sử dụng "nhãn trước hoặc sha1" nào?. Tôi nên nhập cái "chính xác" cuối cùng hay cái trước đó và làm lại tất cả những thay đổi được thực hiện bởi cái đúng cuối cùng?
elysch

3
một trong những ngay trước khi cam kết
eroneous

1
Chính xác những gì tôi cần. Tôi đã đẩy một nhánh để làm chủ do nhầm lẫn. Và kết quả là tôi đã có nhiều cam kết rác rưởi trong tất cả các cam kết lịch sử. Tôi chỉ thực hiện git push -fcho cam kết chính xác cuối cùng và lịch sử từ xa được dọn sạch! Cảm ơn!
Anton Rybalko

193

Những gì tôi làm trong những trường hợp này là:

  • Trong máy chủ, di chuyển con trỏ trở lại cam kết tốt đã biết cuối cùng:

    git push -f origin <last_known_good_commit>:<branch_name>
    
  • Tại địa phương, làm tương tự:

    git reset --hard <last_known_good_commit>
    #         ^^^^^^
    #         optional
    



Xem ví dụ đầy đủ về một nhánh my_new_branchmà tôi đã tạo cho mục đích này:

$ git branch
my_new_branch

Đây là lịch sử gần đây sau khi thêm một số nội dung vào myfile.py:

$ git log
commit 80143bcaaca77963a47c211a9cbe664d5448d546
Author: me
Date:   Wed Mar 23 12:48:03 2016 +0100

    Adding new stuff in myfile.py

commit b4zad078237fa48746a4feb6517fa409f6bf238e
Author: me
Date:   Tue Mar 18 12:46:59 2016 +0100

    Initial commit

Tôi muốn thoát khỏi cam kết cuối cùng, đã được thúc đẩy, vì vậy tôi chạy:

$ git push -f origin b4zad078237fa48746a4feb6517fa409f6bf238e:my_new_branch
Total 0 (delta 0), reused 0 (delta 0)
To git@github.com:me/myrepo.git
 + 80143bc...b4zad07 b4zad078237fa48746a4feb6517fa409f6bf238e -> my_new_branch (forced update)

Đẹp! Bây giờ tôi thấy tệp đã được thay đổi trên cam kết đó ( myfile.py) hiển thị trong "không được phân loại cho cam kết":

$ git status
On branch my_new_branch
Your branch is up-to-date with 'origin/my_new_branch'.

Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

    modified:   myfile.py

no changes added to commit (use "git add" and/or "git commit -a")

Vì tôi không muốn những thay đổi này, tôi cũng chỉ di chuyển con trỏ trở lại cục bộ:

$ git reset --hard b4zad078237fa48746a4feb6517fa409f6bf238e
HEAD is now at b4zad07 Initial commit

Vì vậy, bây giờ CHÍNH nằm trong cam kết trước đó, cả ở địa phương và từ xa:

$ git log
commit b4zad078237fa48746a4feb6517fa409f6bf238e
Author: me
Date:   Tue Mar 18 12:46:59 2016 +0100

    Initial commit

10
Đây là câu trả lời chính xác! đây chính xác là những gì cần thiết được thực hiện trong trường hợp của tôi nhờ vào việc học được điều gì đó mới hôm nay :)
Egli Becerra

2
Đây là câu trả lời chính xác! Nó liên quan đến các cam kết đẩy (!)!
powtac

3
Nếu bạn muốn thực sự hoàn nguyên các thay đổi (như thể bạn chưa bao giờ đẩy chúng), đây câu trả lời đúng.
Jacob

1
Câu trả lời hoàn hảo. Làm việc tốt như mong đợi!
RafiAlhamd

2
Ai đó mua cho người đàn ông này một cốc bia!
Jay Nebhwani

72

Bạn có thể REVERT (hoặc bạn cũng có thể gọi nó là XÓA ) Git Commit BOTH cục bộ và từ xa nếu bạn làm theo các bước như được đưa ra dưới đây thông qua dòng lệnh git.

Chạy lệnh sau để xem id xác nhận mà bạn muốn hoàn nguyên

git log --oneline --decorate --graph

Bạn sẽ nhận được như một ảnh chụp màn hình sau đây nhập mô tả hình ảnh ở đây

Nếu bạn cũng kiểm tra từ xa (thông qua Giao diện web) thì bạn có thể thấy rằng điều này sẽ giống như hiển thị bên dưới

nhập mô tả hình ảnh ở đây

Theo ảnh chụp màn hình hiện tại, bạn đang ở trên id id e110322, tuy nhiên, bạn muốn quay trở lại với 030bbf6 CẢ HAI ĐỊA PHƯƠNG và NHỚ .

Thực hiện các bước sau để XÓA / REVERT Cam kết cục bộ + Từ xa


Lần đầu tiên Hoàn nguyên cục bộ để xác nhận id 030bbf6

git reset --hard 030bbf6

theo dõi bởi

git clean -f -d

Hai lệnh này làm sạch thiết lập lại lực lượng để cam kết giai đoạn 030bbf6 như hiển thị bên dưới trong ảnh chụp nhanh

nhập mô tả hình ảnh ở đây

Bây giờ nếu bạn chạy trạng thái git thì bạn sẽ thấy rằng bạn là HAI Cam kết từ nhánh từ xa như được hiển thị bên dưới nhập mô tả hình ảnh ở đây

Chạy theo sau để cập nhật chỉ mục của bạn (nếu có bất kỳ cập nhật nào). Bạn nên yêu cầu tất cả các nhà phát triển không chấp nhận bất kỳ yêu cầu kéo nào trên nhánh từ xa chính.

git fetch --all

Khi bạn đã thực hiện xong thì bạn bắt buộc phải đẩy mạnh cam kết này bằng cách sử dụng biểu tượng + ở phía trước nhánh như hình bên dưới. Tôi đã sử dụng ở đây là chủ chi nhánh, bạn có thể thay thế bằng bất kỳ

nhập mô tả hình ảnh ở đây

git push -u origin +master

Bây giờ nếu bạn thấy giao diện web của điều khiển từ xa thì cam kết cũng sẽ được hoàn nguyên.

nhập mô tả hình ảnh ở đây


61

Điều này sẽ loại bỏ các cam kết đẩy của bạn

git reset --hard 'xxxxx'

git clean -f -d

git push -f

7
Phương pháp này viết lại lịch sử để xóa cam kết. Tuyệt vời
Jesse Reza Khorasanee

2
Câu trả lời này là el Magnifeco!
Truthadjustr

3
Yêu câu trả lời, cảm ơn :)
Dzenis H.

1
Chỉ cần rõ ràng (tôi không chắc chắn): Cam kết sẽ là cam kết hiện tại sau khi hoạt động. Không phải là người cuối cùng để xóa.
Maik639

21
git revert HEAD -m 1

Trong dòng mã trên. "Đối số cuối cùng đại diện cho"

  • 1 - hoàn nguyên một cam kết.

  • 2 - hoàn nguyên hai lần xác nhận cuối cùng.

  • n - hoàn nguyên lần cuối n cam kết.

Bạn cần đẩy sau lệnh này để có hiệu lực từ xa. Bạn có các tùy chọn khác như chỉ định phạm vi cam kết hoàn nguyên. Đây là một trong những lựa chọn.


Sử dụng sau này git commit -am "COMMIT_MESSAGE" thì git pushhaygit push -f


8
Điều này không đúng - tham số -m chỉ định số lượng cha mẹ được hoàn nguyên (thường là 1 nếu bạn muốn hoàn nguyên các thay đổi đến, "của họ", thay vì 2 cho các thay đổi được hợp nhất, "của chúng tôi" - để hợp nhất 2 cam kết). Nó không liên quan gì đến số lần xác nhận được hoàn nguyên - nếu bạn muốn hoàn nguyên phạm vi cam kết, hãy sử dụnggit revert ref1..ref2
Tham khảo Null

1
Không có hiệu ứng mong muốn
Sam Tuke

3

2020 Cách đơn giản:

git reset <commit_hash>

(Băm của cam kết cuối cùng bạn muốn giữ).

Bạn sẽ giữ những thay đổi không được cam kết tại địa phương.

Nếu bạn muốn đẩy một lần nữa, bạn phải làm:

git push -f

0

Đây là cách của tôi:

Hãy nói tên chi nhánh là develop.

# Create a new temp branch based on one history commit
git checkout <last_known_good_commit_hash>
git checkout -b develop-temp

# Delete the original develop branch and 
# create a new branch with the same name based on the develop-temp branch
git branch -D develop
git checkout -b develop

# Force update this new branch
git push -f origin develop

# Remove the temp branch
git branch -D develop-temp

0

Bạn có thể làm một cái gì đó như

git push origin +<short_commit_sha>^:<branch_name>
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.