Git không tua đi nhanh bị từ chối


88

Tôi cảm thấy như câu hỏi này đã được hỏi nhiều lần, nhưng giải pháp thường là "Tôi đã xóa thư mục và thực hiện lại công việc của mình với một thanh toán mới." Tôi đã thực hiện cam kết và đẩy nhưng nhận ra rằng tôi đã gọi sai số vé trong thông báo cam kết. Vì vậy, tôi đã tìm kiếm SO để tìm một giải pháp nhanh chóng và kết thúc nhập nội dung sau vào thiết bị đầu cuối:

$ git reset --soft HEAD^
$ git commit -m "... correct message ..."

Vấn đề duy nhất là tôi nhận được thông báo lỗi sau:

To prevent you from losing history, non-fast-forward updates were rejected
Merge the remote changes before pushing again.  See the 'Note about
fast-forwards' section of 'git push --help' for details.

Tôi đang sử dụng mô hình git-flow và đang làm việc trên nhánh phát triển. Làm cách nào để kết hợp mọi thứ lại với nhau để làm cho git vui trở lại?


Câu trả lời:


52

Lực lượng git push:

git push origin +develop

24
Đó là một giải pháp, nhưng hãy đọc bình luận của Brian Campbell để bạn hiểu mình đang làm gì trước khi sử dụng.
thelem

5
git push gốc + thạc sĩ
Aniket Thakur

Xem thêm lưu ý receive.denyNonFastForwardstrong câu trả lời của Brian Campbell : +hoặc --forcecó thể không đủ mạnh, tùy thuộc vào cách họ - dù họ là ai - đã định cấu hình kho lưu trữ Git của họ .

174

Nếu bạn đẩy một cam kết máy chủ, và sau đó viết lại rằng cam kết tại địa phương (với git reset, git rebase, git filter-branch, hoặc bất kỳ thao tác lịch sử khác), và sau đó đẩy mà viết lại cam kết trở lại lên đến máy chủ, bạn sẽ vít lên bất kỳ ai khác đã kéo. Đây là một ví dụ; nói rằng bạn đã cam kết A và đẩy nó lên máy chủ.

- * - * - A <- chủ

- * - * - A <- origin / master

Bây giờ bạn quyết định viết lại A, theo cách bạn đã đề cập, đặt lại và cam kết lại. Lưu ý rằng điều này để lại một cam kết lơ lửng, A, cuối cùng sẽ được thu gom rác vì không thể truy cập được.

- * - * - A
    \
     A '<- chủ

- * - * - A <- origin / master

Nếu ai đó khác, giả sử Fred, kéo xuống mastertừ máy chủ trong khi bạn đang làm việc này, họ sẽ có một tham chiếu đến A, mà họ có thể bắt đầu hoạt động từ đó:

- * - * - A '<- chủ

- * - * - A <- origin / master

- * - * - AB <- fred / master

Bây giờ nếu bạn có thể đẩy A 'của mình đến điểm gốc / cái, điều này sẽ tạo ra một chuyển tiếp không nhanh, nó sẽ không có A trong lịch sử của nó. Vì vậy, nếu Fred cố gắng kéo lại, anh ấy sẽ đột nhiên phải hợp nhất và sẽ giới thiệu lại cam kết A:

- * - * - A '<- chủ

- * - * - A <- origin / master

- * - * - AB- \ 
    \ * <- fred / master
     A '- /

Nếu Fred tình cờ nhận thấy điều này, thì anh ta có thể thực hiện rebase, điều này sẽ ngăn cam kết A xuất hiện trở lại. Nhưng anh ấy sẽ phải nhận thấy điều này, và nhớ làm điều này; và nếu bạn có nhiều hơn một người đã kéo A xuống, tất cả họ sẽ phải căn cứ lại để tránh nhận thêm A cam kết trong cây.

Vì vậy, nói chung không phải là một ý kiến ​​hay nếu thay đổi lịch sử trên repo mà người khác lấy từ đó. Tuy nhiên, nếu bạn tình cờ biết rằng không có ai khác đang lấy từ repo đó (ví dụ: đó là repo riêng tư của bạn hoặc bạn chỉ có một nhà phát triển khác làm việc trong dự án mà bạn có thể phối hợp dễ dàng), thì bạn có thể buộc cập nhật bằng cách chạy:

git push -f

hoặc là

git push origin +master

Cả hai điều này sẽ bỏ qua việc kiểm tra một lần đẩy không nhanh và cập nhật những gì trên máy chủ lên bản sửa đổi A 'mới của bạn, bỏ qua bản sửa đổi A để cuối cùng nó sẽ được thu gom.

Có thể lực đẩy hoàn toàn bị vô hiệu hóa với receive.denyNonFastForwardstùy chọn cấu hình. Tùy chọn này được bật theo mặc định trên các kho được chia sẻ. Trong trường hợp đó, nếu bạn thực sự, thực sự muốn thúc đẩy, tùy chọn tốt nhất là xóa nhánh và tạo lại nó, với git push origin :master; git push origin master:master. Tuy nhiên, denyNonFastForwardstùy chọn được bật vì một lý do, được mô tả ở trên; trên một kho lưu trữ được chia sẻ, điều đó có nghĩa là bây giờ tất cả những người sử dụng nó cần đảm bảo rằng họ căn cứ vào lịch sử mới.

Trên một kho lưu trữ được chia sẻ, tốt hơn là chỉ cần đẩy các cam kết mới lên trên để khắc phục bất kỳ sự cố nào bạn gặp phải; bạn có thể sử dụng git revertđể tạo các cam kết sẽ hoàn tác các thay đổi của các cam kết trước đó.


trình độ học vấn tuyệt vời, và cuối cùng thì bạn đã nhận được lệnh, nhưng nhánh của tôi có tên là development (dựa trên git-flow), và anh chàng kia đã đưa ra +developlệnh của anh ta - vì vậy, séc sẽ thuộc về anh ta. Bạn đã có một số thiên văn điểm anyway: P
rynmrtn

7
Hoặc sử dụng ít khó hiểugit push --force
Bennett McElwee

3
@Panique Bạn đang cố gắng cho phép nhiều người làm việc trên một cơ sở mã lớn, phức tạp cùng một lúc mà không chặn lẫn nhau (chỉ cho phép một người làm việc trên nó cùng một lúc) và không có các thay đổi ghi đè lên nhau. Bạn cần mỗi người có thể thực hiện các thay đổi một cách độc lập và hợp nhất các thay đổi đó. Sáp nhập (dù thủ công hay tự động) có thể gây ra các vấn đề không mong muốn; vì vậy bạn muốn giữ lại càng nhiều thông tin càng tốt để có thể tìm ra điều gì đã xảy ra nếu nó xảy ra sai sót. Điều này thực chất là phức tạp; nó không bẩn, chỉ là một vấn đề khó.
Brian Campbell

Tôi đã thử cả tùy chọn -f và + để viết lại lịch sử repo từ xa. Trong cả hai tùy chọn, tôi gặp phải sự cố không tua đi nhanh. [5:05 PM] $ git push -f origin local_A: remote_A Đếm đối tượng: 35, xong. Nén Delta sử dụng tối đa 2 luồng. Nén các đối tượng: 100% (18/18), đã xong. Đối tượng viết: 100% (21/21), 7.41 KiB, thực hiện. Tổng số 21 (delta 9), điều khiển từ xa 0 (delta 0) được sử dụng lại: Để tránh mất lịch sử, các bản cập nhật không chuyển tiếp nhanh đã bị từ chối. Hợp nhất các thay đổi từ xa (ví dụ: 'git pull') trước khi đẩy lại. Xem phần 'Lưu ý về chuyển tiếp nhanh' của 'git push --help' để biết chi tiết.
Srikanth

4
@Srikanth Có thể vô hiệu hóa hoàn toàn việc đẩy bắt buộc bằng receive.denyNonFastForwardstùy chọn cấu hình. Tùy chọn này được bật theo mặc định trên các kho được chia sẻ. Trong trường hợp đó, nếu bạn thực sự, thực sự muốn thúc đẩy, tùy chọn tốt nhất là xóa nhánh và tạo lại nó, với git push origin :remote_A; git push origin local_A:remote_A. Nhưng hãy đọc những gì tôi đã viết ở trên về lý do tại sao lại là một ý tưởng tồi khi thực hiện loại quy trình công việc này trên một kho lưu trữ được chia sẻ. Bạn nên cố gắng chỉ làm điều này nếu bạn có điều gì đó gây ra vấn đề nghiêm trọng trong cam kết mà bạn đang cố gắng loại bỏ hoặc viết lại.
Brian Campbell

14

Bạn có thể phải làm một git pull, mà CÓ THỂ tự động hợp nhất nội dung cho bạn. Sau đó, bạn có thể cam kết lại. Nếu bạn có xung đột, nó sẽ nhắc bạn giải quyết chúng.

Hãy nhớ rằng, bạn phải chỉ định nhánh nào sẽ kéo từ nếu bạn chưa cập nhật gitconfig của mình để chỉ định ...

Ví dụ:

git pull origin develop:develop

Vẫn còn tức giận về việc không tua đi nhanh. Bất kỳ suy nghĩ về cách buộc nó hợp nhất? ! [rejected] develop -> develop (non-fast-forward)
rynmrtn

Tôi nghĩ công tắc là -f nhưng tôi có thể sai. kernel.org/pub/software/scm/git/docs/git-pull.html
Tony

Điều này một phần hoạt động. Tôi không nhìn thấy các bản cập nhật trên github, mặc dù (nó cho thấy cam kết trước đó như mới nhất ngay cả với một git push origin develop)
rynmrtn

7

Tôi đã sử dụng EGit và tôi cũng gặp phải vấn đề này. Chỉ cần thử đến rebasechi nhánh hiện tại và Nó đã hoạt động.

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.