Đặt lại từ xa đến một cam kết nhất định


709

Tôi muốn loại bỏ tất cả các thay đổi được thực hiện sau khi cam kết <commit-hash>. Tôi cũng vậy:

git reset --hard <commit-hash>

Bây giờ tôi muốn làm điều tương tự với điều khiển từ xa của tôi. Tôi có thể làm cái này như thế nào? Tôi đã thực hiện một số cam kết (và đẩy) sau đó <commit-hash>và tôi chỉ muốn loại bỏ tất cả. Có phải điều gì đó đã đi sai đường khủng khiếp và tôi không muốn làm cho nó tồi tệ hơn nó đã xảy ra. ;

Về cơ bản tôi muốn tua lại của tôi origin/masterđể<commit-hash>


3
Bạn có chắc chắn rằng người dùng của bạn origin/masterchưa bị kéo và đẩy sang? Thay đổi lịch sử của kho lưu trữ công khai (tức là không cục bộ) là điều bạn muốn tránh mọi lúc.
vindia

Câu trả lời:


1252

Giả sử rằng chi nhánh của bạn được gọi mastercả ở đây và từ xa, và điều khiển từ xa của bạn được gọi là originbạn có thể làm:

 git reset --hard <commit-hash>
 git push -f origin master

Tuy nhiên, bạn nên tránh làm điều này nếu bất kỳ ai khác đang làm việc với kho lưu trữ từ xa của bạn và đã kéo các thay đổi của bạn. Trong trường hợp đó, sẽ tốt hơn là hoàn nguyên các cam kết mà bạn không muốn, sau đó đẩy như bình thường.

Cập nhật: bạn đã giải thích bên dưới rằng những người khác đã thực hiện các thay đổi mà bạn đã đẩy, vì vậy tốt hơn là tạo một cam kết mới hoàn nguyên tất cả các thay đổi đó . Có một lời giải thích hay về các lựa chọn của bạn để thực hiện điều này trong câu trả lời này từ Jakub Narębski . Cái nào thuận tiện nhất phụ thuộc vào số lần xác nhận bạn muốn hoàn nguyên và phương thức nào có ý nghĩa nhất đối với bạn.

Vì từ câu hỏi của bạn, rõ ràng là bạn đã sử dụng git reset --hardđể đặt lại masterchi nhánh của mình , bạn có thể cần phải bắt đầu bằng cách sử dụng git reset --hard ORIG_HEADđể di chuyển chi nhánh của mình trở lại vị trí trước đó. (Như mọi khi git reset --hard, đảm bảo rằng git statussạch sẽ, rằng bạn đang ở đúng nhánh và bạn biết đó git refloglà một công cụ để phục hồi các cam kết bị mất rõ ràng.) Bạn cũng nên kiểm tra ORIG_HEADcác điểm đó với đúng cam kết, với git show ORIG_HEAD.

Xử lý sự cố:

Nếu bạn nhận được một thông báo như " ! [Từ chối từ xa] a60f7d85 -> master (móc nhận trước bị từ chối) "

sau đó bạn phải cho phép viết lại lịch sử chi nhánh cho chi nhánh cụ thể. Trong BitBucket chẳng hạn, nó cho biết "Viết lại lịch sử chi nhánh không được phép". Có một hộp kiểm có tên Allow rewriting branch historymà bạn phải kiểm tra.


21
Nguy hiểm nguy hiểm: thiết lập lại này giả định rằng nhánh ( theo dõi ) tương ứng hiện đang được kiểm tra không có thay đổi không được cam kết nào mà bạn muốn giữ. Sử dụng git update-refthay vìreset --hard ; nó sẽ cho phép bạn làm tương tự mà không cần có cây làm việc / chi nhánh đã được kiểm tra
sehe

3
Tôi hiểu rồi. Nó đã được đẩy và thay đổi bởi những người khác. Vì vậy, tôi nên sử dụng revert nhưng hãy nói rằng tôi muốn hoàn nguyên 4 lần xác nhận trước đây để tôi nên làm git revert comit1; git push; git revert comit2; git push; ...hay đơn giản git revert commit4; git push?
nacho4d

1
@ nacho4d: bạn không cần phải thúc đẩy sau mỗi lần hoàn nguyên - có một mô tả hay về những việc cần làm trong câu trả lời này từ Jakub Narębski . Bạn cần phải hoàn nguyên từng cam kết đi ngược lại - chỉ cần thực hiện git revert commit4sẽ tạo ra một cam kết mới chỉ hoàn tác các thay đổi đã được đưa vào commit4. Tuy nhiên, như câu trả lời tôi đã liên kết với các điểm, bạn có thể chuyển chúng thành một cam kết duy nhất.
Mark Longair

1
@Mark Tôi đã chạy git reset --hardnhưng tôi đã xóa cục bộ của mình và lấy lại từ nguồn gốc để tôi có thể thực hiện git revert ...Nghi ngờ của tôi bây giờ là: tôi có phải hoàn nguyên từng cam kết và đẩy (từng cái một) hay chỉ hoàn nguyên cam kết đầu tiên sau đúng chỉ cam kết?
nacho4d

1
@sehe: thật khó để sử dụng vì bạn cần sử dụng tên ref đầy đủ và vì vậy mọi người dễ dàng xả rác .gitthư mục của họ với các ref mà họ không có ý định tạo. Tôi đã sai khi nói rằng không có kiểm tra an toàn, mặc dù. Bạn có thể tìm thấy phân loại thành các lệnh "ống nước" và "sứ" trong trang git man .
Đánh dấu Longair

123

Sử dụng các câu trả lời khác nếu bạn không nhớ mất các thay đổi cục bộ. Phương pháp này vẫn có thể phá hỏng điều khiển từ xa của bạn nếu bạn chọn băm xác nhận sai để quay lại.

Nếu bạn chỉ muốn làm cho điều khiển từ xa khớp với một cam kết ở bất cứ đâu trong repo địa phương của bạn:

  1. Không được đặt lại.
  2. Sử dụng git logđể tìm các cam kết bạn muốn từ xa. git log -pđể xem thay đổi, hoặc git log --graph --all --oneline --decorateđể xem một cây nhỏ gọn.
  3. Sao chép hàm băm của cam kết hoặc thẻ của nó hoặc tên của chi nhánh nếu đó là mẹo.
  4. Chạy một lệnh như:

    git push --force <remote> <commit-ish>:<the remote branch>
    

    ví dụ

    git push --force origin 606fdfaa33af1844c86f4267a136d4666e576cdc:master
    

    hoặc là

    git push --force staging v2.4.0b2:releases
    

Tôi sử dụng bí danh thuận tiện ( git go) để xem lịch sử như trong bước 2, có thể được thêm vào như vậy:

    git config --global alias.go 'log --graph --all --decorate --oneline'`

3
Biểu đồ là một mẹo rất hay, tôi chỉ cần thêm -5 để chỉ nhận được n cam kết cuối cùng, đó là một cây khổng lồ khác. Ngoài ra, tránh thiết lập lại chỉ là những gì tôi đang tìm kiếm. Tuyệt vời
AlexanderD

@AlexanderD Bạn cũng có thể thêm bí danh vào Git chứ không phải vỏ của bạn, vì vậy nó hoạt động ở mọi nơi. Git hiểu các bí danh và hoàn thành tab từ lệnh đầy đủ để bạn có thể thêm đối số. git config --global alias.graph 'log --graph --all --decorate --oneline'ít lộn xộn hơn và bạn vẫn có thể giới hạn nó, ví dụ:git graph -5
Walf

Đây là hoàn hảo. Tôi đã luôn luôn gây rối địa phương của tôi. Đây chính xác là những gì tôi cần sau khi vô tình đẩy dàn dựng của mình lên sống :( Cảm ơn!
Jake

1
Trên Windows, nhập qđể thoát nhật ký git. 2 phút tôi sẽ không bao giờ quay lại.
dst3p

1
@ dst3p Đó là trên mọi nền tảng, bạn đời. Chương trình máy nhắn tin thường lessqlà cách thông thường để thoát khỏi chương trình. Git Bash giống như một thiết bị đầu cuối * nix.
Walf

63

Tôi đã giải quyết vấn đề như của bạn bằng các lệnh này:

git reset --hard <commit-hash> 
git push -f <remote> <local branch>:<remote branch> 

13

Trên GitLab, bạn có thể phải đặt chi nhánh của mình thành không được bảo vệ trước khi thực hiện việc này. Bạn có thể làm điều này trong [repo]> Cài đặt> Kho lưu trữ> Chi nhánh được bảo vệ. Sau đó, phương pháp từ câu trả lời của Mark hoạt động.

git reset --hard <commit-hash>
git push -f origin master

10

Nếu bạn muốn có phiên bản trước của tệp, tôi khuyên bạn nên sử dụng kiểm tra git.

git checkout <commit-hash>

Làm điều này sẽ gửi lại cho bạn đúng lúc, nó không ảnh hưởng đến trạng thái hiện tại của dự án của bạn, bạn có thể đến tuyến chính kiểm tra git

nhưng khi bạn thêm một tệp trong đối số, tệp đó sẽ được đưa trở lại cho bạn từ lần trước đến thời gian dự án hiện tại của bạn, tức là dự án hiện tại của bạn đã bị thay đổi và cần phải được cam kết.

git checkout <commit-hash> -- file_name
git add .
git commit -m 'file brought from previous time'
git push

Ưu điểm của việc này là nó không xóa lịch sử và cũng không hoàn nguyên một thay đổi mã cụ thể (git Revert)

Kiểm tra thêm tại đây https://www.atlassian.com/git/tutorials/undceed-changes#git-checkout


Đây là một câu trả lời tuyệt vời: nó hoạt động, thời gian và rất an toàn; nếu bạn làm hỏng nó, nó dễ dàng quay trở lại.
bob

8

Hai xu của tôi cho các câu trả lời trước: nếu

git push --force <remote> <the-hash>:<the remote branch>

vẫn không hoạt động, bạn có thể muốn chỉnh sửa <your-remote-repo>.git/configphần nhận của tệp:

[receive]
  #denyNonFastforwards = true
  denyNonFastforwards = false

Thật hữu ích khi biết cách định cấu hình một điều khiển từ xa để cho phép đẩy không nhanh vì hầu hết các câu trả lời dường như giả định một dịch vụ từ xa như github hoặc bitbucket.
strongbutgood

2

Nếu chi nhánh của bạn không phát triển hoặc sản xuất, cách dễ nhất để đạt được điều này là đặt lại một cam kết nhất định tại địa phương và tạo một chi nhánh mới từ đó. Bạn có thể dùng:

kiểm tra git 000000

(trong đó 000000 là id xác nhận nơi bạn muốn đến) trong nhánh có vấn đề của bạn và sau đó chỉ cần tạo một nhánh mới:

git từ xa thêm [name_of_your_remote]

Sau đó, bạn có thể tạo một PR mới và tất cả sẽ hoạt động tốt!


1

Làm một điều, nhận được SHA cam kết không. chẳng hạn như 87c9808 và sau đó,

  1. tự di chuyển, đó là đầu của bạn đến cam kết được chỉ định (bằng cách thực hiện thiết lập lại git - xin chào 89cef43 // đề cập đến số của bạn ở đây)
  2. Tiếp theo thực hiện một số thay đổi trong một tệp ngẫu nhiên, để git sẽ yêu cầu bạn cam kết điều đó cục bộ và sau đó từ xa Vì vậy, điều bạn cần làm bây giờ là. sau khi áp dụng thay đổi git commit -a -m "bản dùng thử"
  3. Bây giờ đẩy cam kết sau (nếu điều này đã được cam kết cục bộ) bởi git push origin master
  4. Bây giờ những gì git sẽ yêu cầu từ bạn là

lỗi: không thể đẩy một số giới thiệu đến ' https://github.com/YOURREPOSITORY/AndroidExperiment.git ': Các cập nhật đã bị từ chối vì mẹo của chi nhánh hiện tại của bạn nằm sau gợi ý: đối tác từ xa của nó. Tích hợp các thay đổi từ xa (ví dụ: gợi ý: 'git pull ...') trước khi đẩy lại. **

  1. Vì vậy, bây giờ những gì bạn có thể làm là

git push --force origin master

  1. Và do đó, tôi hy vọng nó hoạt động :)

1

Sourcetree: đặt lại từ xa đến một cam kết nhất định

  1. Nếu bạn đã đẩy một cam kết xấu đến điều khiển từ xa (nguồn gốc / tính năng / 1337_MyAw đũaFeature) như hình dưới đây

Đi đến điều khiển từ xa

  1. Chuyển đến Từ xa> nguồn gốc> tính năng> 1337_MyAw đũaFeature
  2. Nhấp chuột phải và chọn "Xóa nguồn gốc / tính năng / 1337_MyAw đũaFeature" (Hoặc thay đổi tên của nó nếu bạn muốn sao lưu và bỏ qua bước 4.)
  3. Nhấp vào "Buộc xóa" và "OK".

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

  1. Chọn cam kết cũ hơn của bạn và chọn "Đặt lại chi nhánh hiện tại cho cam kết này"
  2. Chọn chế độ bạn muốn có (Khó nếu bạn không muốn thay đổi cuối cùng của mình) và "OK".

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

  1. Đẩy cam kết này sang nguồn gốc / tính năng mới / 1337_MyAw đũaFeature nhập mô tả hình ảnh ở đây

  2. Chi nhánh tính năng cục bộ và chi nhánh tính năng từ xa của bạn hiện nằm trên cam kết trước đó (của sự lựa chọn của bạn) nhập mô tả hình ảnh ở đây

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.