Hoàn tác một 'git đẩy'


591

Đây là những gì tôi đã làm trên nhánh được cho là ổn định của mình ...

% git rebase master
First, rewinding head to replay your work on top of it...
Fast-forwarded alpha-0.3.0 to master.
% git status
# On branch alpha-0.3.0
# Your branch is ahead of 'origin/alpha-0.3.0' by 53 commits.
#
nothing to commit (working directory clean)
% git push
Fetching remote heads...
  refs/
  refs/heads/
  refs/tags/
  refs/remotes/
'refs/heads/master': up-to-date
updating 'refs/heads/alpha-0.3.0'
  from cc4b63bebb6e6dd04407f8788938244b78c50285
  to   83c9191dea88d146400853af5eb7555f252001b0
    done
'refs/heads/unstable': up-to-date
Updating remote server info

Đó là tất cả một sai lầm như sau này tôi nhận ra. Tôi muốn hoàn tác toàn bộ quá trình này và hoàn nguyên nhánh alpha-0.3.0 trở lại như cũ.

Tôi nên làm gì?



4
Nó không thực sự giống như vậy, hoàn tác một rebase là một kịch bản kho lưu trữ cục bộ, hoàn tác một git đẩy liên quan đến một kho lưu trữ từ xa và có thể khó khăn hơn tùy thuộc vào quyền truy cập mà bạn có.
CB Bailey

Steen - bạn nói đúng - có lẽ tôi nên cho rằng. Tôi đã tìm ra rằng kho lưu trữ may mắn mà tất cả được lấy từ nhiều hơn một nhiệm vụ quản trị viên và vì vậy thuộc về nơi này, trong đó git phía khách hàng chung là một câu hỏi stackoverflow.
Cyrus

Làm rõ nhanh - Tôi đoán nếu bạn tham khảo một cam kết git bằng một giá trị băm một phần , git sẽ cho rằng bạn đang nói về cam kết mà hàm băm bắt đầu bằng chuỗi đó?
Gershom

Câu trả lời:


943

Bạn cần đảm bảo rằng không có người dùng nào khác của kho lưu trữ này đang tìm nạp các thay đổi không chính xác hoặc cố gắng xây dựng trên đầu trang của các cam kết mà bạn muốn xóa vì bạn sắp tua lại lịch sử.

Sau đó, bạn cần 'buộc' đẩy tham chiếu cũ.

git push -f origin last_known_good_commit:branch_name

hoặc trong trường hợp của bạn

git push -f origin cc4b63bebb6:alpha-0.3.0

Bạn có thể đã receive.denyNonFastForwardsthiết lập trên kho lưu trữ từ xa. Nếu đây là trường hợp, sau đó bạn sẽ nhận được một lỗi bao gồm cụm từ [remote rejected].

Trong kịch bản này, bạn sẽ phải xóa và tạo lại nhánh.

git push origin :alpha-0.3.0
git push origin cc4b63bebb6:refs/heads/alpha-0.3.0

Nếu điều này không hoạt động - có lẽ vì bạn đã receive.denyDeletesthiết lập, thì bạn phải có quyền truy cập trực tiếp vào kho lưu trữ. Trong kho lưu trữ từ xa, sau đó bạn phải làm một cái gì đó giống như lệnh hệ thống ống nước sau đây.

git update-ref refs/heads/alpha-0.3.0 cc4b63bebb6 83c9191dea8

16
Một phản ứng hoàn hảo và được giải thích tốt - cảm ơn bạn rất nhiều. Đối với bất kỳ ai khác vấp phải điều này, vì lý do học thuật, tôi đã thử cả hai cách tiếp cận đầu tiên và cả hai đều hiệu quả - rõ ràng nếu cách đầu tiên hiệu quả, đó là cách tiếp cận sạch nhất. Nếu tôi gọi bạn 10 lần Charles, tôi sẽ làm thế. :)
Cyrus

139
Để tham khảo nhanh, dòng đầu tiên ở đây làgit push -f origin last_known_good_commit:branch_name
philfreo

5
git push -f nguồn gốc cc4b63bebb6: alpha-0.3.0 => cái này đã giúp tôi, Lưu ý alpha-0.3.0 là tên chi nhánh và cc4b63bebb6 là id xác nhận mà chúng tôi muốn hoàn nguyên. vì vậy, sau khi thực hiện lệnh này, chúng ta sẽ ở trong cc4b63bebb6 commit id.
kumar

22
Giải pháp này rất nguy hiểm nếu bạn đang làm việc trong một repo được chia sẻ. Như một cách thực hành tốt nhất, tất cả các cam kết được đẩy đến một repo từ xa được chia sẻ nên được coi là "bất biến". Thay vào đó, hãy sử dụng 'git
Revert

1
jww - so với mọi thứ khác, git là công cụ kiểm soát nguồn hiệu quả và giàu tính năng nhất hiện có. Mỗi đội sử dụng nó khác nhau. Thật đáng để dành một ngày cuối tuần để chơi xung quanh với một kho lưu trữ mới và trải qua tất cả các tình huống phổ biến. Một khi bạn đã dành thời gian làm việc với nó, việc phát triển sẽ bớt căng thẳng hơn rất nhiều.
user1491819

165

Tôi tin rằng bạn cũng có thể làm điều này:

git checkout alpha-0.3.0
git reset --hard cc4b63bebb6
git push origin +alpha-0.3.0

Phương pháp này rất giống với phương pháp cuối cùng, ngoại trừ bạn không phải loay hoay trong repo từ xa.


9
Điều này cũng làm việc với tôi, nhưng đáng chú ý là điều này sẽ "viết lại" lịch sử trên điều khiển từ xa. Đây có thể là những gì bạn muốn, nhưng nó có thể không!
Tom

3
+1 cho câu trả lời này thực sự đã giúp tôi. Tôi cũng muốn thêm (và làm cho mọi thứ rõ ràng) rằng ID cam kết (xuất hiện sau --hardtham số "") phải là ID của bất kỳ cam kết nào bạn muốn đặt lại chi nhánh của mình.
Michael Dautermann

1
Viết lại lịch sử một cách độc đáo ... bất cứ ai có thể thực hiện các thay đổi, tôi chỉ đảm bảo rằng họ đã làm git reset --hard [commit_id]như vậy để chúng tôi không gây rối với sự liên tục trong không gian thời gian.
Mẫu cuộc sống ngoài hành tinh

9
+ Cho trong "git đẩy gốc + alpha-0.3.0" là gì?
jpierson

1
@jpierson +buộc việc đẩy diễn ra, tương tự như -f(nhưng hơi khác: stackoverflow.com/a/25937833/1757149 ). Không có nó, nếu bạn cố gắng git push origin alpha-0.3.0đẩy sẽ thất bại : Updates were rejected because the tip of your current branch is behind.
A__

106

git revert ít nguy hiểm hơn một số phương pháp được đề xuất ở đây:

prompt> git revert 35f6af6f77f116ef922e3d75bc80a4a466f92650
[master 71738a9] Revert "Issue #482 - Fixed bug."
 4 files changed, 30 insertions(+), 42 deletions(-)
prompt> git status
# On branch master
# Your branch is ahead of 'origin/master' by 1 commit.
#
nothing to commit (working directory clean)
prompt>

Thay thế 35f6af6f77f116ef922e3d75bc80a4a466f92650 bằng cam kết của riêng bạn.


2
Làm cách nào để đến với ID 35f6af6f77f116ef922e3d75bc80a4a466f92650? Câu trả lời này sẽ tốt hơn nếu bạn có thể giải thích điều đó.
Volomike

2
@Volomike (và các nhà phát triển của tương lai), câu hỏi này mô tả nhiều cách để có được nó: kiểm soát phiên bản và câu hỏi băm trên SO
Jaime

Đây là câu trả lời đúng, vì với "git reset", bạn không thể đẩy (Cập nhật đã bị từ chối vì phần đầu của chi nhánh hiện tại của bạn nằm phía sau đối tác từ xa) hoặc bạn cần buộc lực kéo không thực sự sạch.
Thomas Decaux

Điều này đã làm việc cho tôi. Tuy nhiên, hãy cẩn thận vì hoàn nguyên sẽ hoàn nguyên tất cả các thay đổi trong tệp cục bộ của bạn.
dùng1941537

Tôi đã chọn cách tiếp cận này nhiều lần nhưng tôi cũng sử dụng git rebase -i <id-before-last-good-commit> để thực hiện một rebase tương tác và làm sạch lịch sử như được đề xuất ở đây, stackoverflow.com/questions/5189560/ .
Ernesto Allely

35

Giải pháp được chấp nhận (từ @charles bailey) rất nguy hiểm nếu bạn đang làm việc trong một repo được chia sẻ.

Như một cách thực hành tốt nhất, tất cả các cam kết được đẩy đến một repo từ xa được chia sẻ nên được coi là "bất biến". Thay vào đó, hãy sử dụng 'git Revert': http://www.kernel.org/pub/software/scm/git/docs/user-manual.html#fixing-mistakes

https://git-scm.com/book/be/v2/Git-Basics-Undceed-Things


Chính xác thì hướng dẫn bạn đang kê đơn là gì? Bạn dường như chỉ có liên kết cũ.
jww

32

Một cách để làm điều đó mà không làm mất các thay đổi bạn muốn:

git reset cc4b63b 
git stash
git push -f origin alpha-0.3.0
git stash pop

Sau đó, bạn có thể chọn các tập tin bạn muốn đẩy


19

Một cách khác để làm điều này:

  1. tạo một chi nhánh khác
  2. kiểm tra cam kết trước đó trên chi nhánh đó bằng cách sử dụng "git checkout"
  3. đẩy chi nhánh mới.
  4. xóa chi nhánh cũ và đẩy xóa (sử dụng git push origin --delete <branch_name>)
  5. đổi tên nhánh mới thành nhánh cũ
  6. đẩy lại.

2
Đây là một giải pháp thực sự khi bạn đã cam kết sai trong repo
Illarion Kovalchuk

17
git push origin +7f6d03:master

Điều này sẽ hoàn nguyên repo của bạn để số cam kết được đề cập


2
Đây là câu trả lời thẳng nhất. Bạn là một người tiết kiệm sống.
Ekundayo Blessing Funminiyi

2
Hãy nhớ rằng, điều đó sẽ không thiết lập lại các tập tin cục bộ của bạn.
K-Gun

11

Hoàn tác nhiều cam kết thiết lập lại git - cho 0ad5a7a6 (Chỉ cần cung cấp hàm băm SHA1)

Hoàn tác cam kết cuối cùng

git reset --hard HEAD ~ 1 (thay đổi cho lần xác nhận cuối cùng sẽ bị xóa) git reset --soft HEAD ~ 1 (những thay đổi đối với lần xác nhận cuối cùng sẽ có sẵn khi sửa đổi cục bộ không được cam kết)


9

Kịch bản 1 : Nếu bạn muốn hoàn tác cam kết cuối cùng, hãy nói 8123b7e04b3, bên dưới là lệnh (cách này hiệu quả với tôi):

git push origin +8123b7e04b3^:<branch_name>

Đầu ra trông như dưới đây:

Total 0 (delta 0), reused 0 (delta 0)
To https://testlocation/code.git
 + 8123b7e...92bc500 8123b7e04b3^ -> master (forced update)

Thông tin bổ sung: Kịch bản 2 : Trong một số trường hợp, bạn có thể muốn hoàn nguyên lại những gì bạn vừa hoàn tác (về cơ bản hoàn tác hoàn tác) thông qua lệnh trước đó, sau đó sử dụng lệnh bên dưới:

git reset --hard 8123b7e04b3

Đầu ra:

HEAD is now at cc6206c Comment_that_was_entered_for_commit

Thêm thông tin tại đây: https://github.com/blog/2019-how-to-undo-al most-anything-with-git


Kịch bản 1 nên câu trả lời được chấp nhận vì câu hỏi không chỉ định cam kết nào cần xóa. Câu trả lời được chấp nhận chỉ xóa các cam kết cuối cùng . Câu trả lời này xóa bất kỳ cam kết.
Đaminh Cerisano

0

Các câu trả lời hiện có là tốt và chính xác, tuy nhiên nếu bạn cần hoàn tác pushnhưng:

  1. Bạn muốn giữ các xác nhận cục bộ hoặc bạn muốn giữ các thay đổi không được cam kết
  2. Bạn không biết có bao nhiêu cam kết bạn vừa đẩy

Sử dụng lệnh này để hoàn nguyên thay đổi cho ref:

git push -f origin refs/remotes/origin/<branch>@{1}:<branch>

-2

Nếu bạn muốn bỏ qua cam kết cuối cùng mà bạn vừa đẩy trong nhánh từ xa: điều này sẽ không xóa cam kết mà chỉ bỏ qua nó bằng cách di chuyển con trỏ git đến cam kết trước đó, được giới thiệu bởi HEAD ^ hoặc HEAD ^ 1

git push origin +HEAD^:branch

Nhưng nếu bạn đã thúc đẩy cam kết này và những người khác đã rút chi nhánh. Trong trường hợp này, viết lại lịch sử chi nhánh của bạn là điều không mong muốn và thay vào đó bạn nên hoàn nguyên cam kết này:

git revert <SHA-1>
git push origin branch

1
Đúng! điều này làm việc như một cơ duyên khi làm việc với github. cảm ơn.
cukabeka

Câu hỏi là về "đẩy" thì nó liên quan đến nhánh Remote. Không để di chuyển TRƯỚC về một cam kết có nghĩa là bỏ qua lần cam kết cuối cùng chỉ cần làm điều này: git đẩy gốc + ĐẦU ^: your_branch
mkebri
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.