Làm thế nào để tôi buộc một lực đẩy Git đúng cách?


1274

Tôi đã thiết lập một repo "chính" không từ xa và nhân bản nó vào máy tính của mình. Tôi đã thực hiện một số thay đổi cục bộ, cập nhật kho lưu trữ cục bộ của mình và đẩy các thay đổi trở lại repo từ xa. Mọi thứ đều ổn cho đến thời điểm đó.

Bây giờ, tôi đã phải thay đổi một cái gì đó trong repo từ xa. Sau đó, tôi đã thay đổi một cái gì đó trong repo địa phương của tôi. Tôi nhận ra rằng việc thay đổi repo từ xa là không cần thiết. Vì vậy, tôi đã cố gắng git pushtừ repo địa phương của tôi đến repo từ xa của tôi, nhưng tôi đã gặp một lỗi như:

Để ngăn bạn khỏi mất lịch sử, các bản cập nhật không chuyển tiếp đã bị từ chối Hợp nhất các thay đổi từ xa trước khi đẩy lại. Xem phần 'Lưu ý về chuyển tiếp nhanh' git push --helpđể biết chi tiết.

Tôi nghĩ rằng có lẽ một

git push --force

sẽ buộc bản sao cục bộ của tôi đẩy các thay đổi sang từ xa và làm cho nó giống nhau. Nó không bắt buộc cập nhật , nhưng khi tôi quay lại repo từ xa và thực hiện một cam kết, tôi nhận thấy rằng các tệp chứa các thay đổi lỗi thời (những cái mà repo từ xa chính trước đây đã có).

Như tôi đã đề cập trong các ý kiến ​​cho một trong những câu trả lời :

[Tôi] đã cố gắng ép buộc, nhưng khi quay trở lại máy chủ chính để lưu các thay đổi, tôi sẽ bị dàn dựng lỗi thời. Vì vậy, khi tôi cam kết các kho lưu trữ không giống nhau. Và khi tôi cố gắng sử dụng git đẩy một lần nữa, tôi cũng gặp lỗi tương tự.

Làm thế nào tôi có thể khắc phục vấn đề này?


4
Bạn sẽ sớm (git1.8.5, Q4 2013) có thể làm một git push -forcecách cẩn thận hơn .
VonC


6
Như tôi nói chi tiết trong câu trả lời của riêng mình , git push --forcethực sự là một cách hợp lệ khác để đẩy mạnh và sẽ đẩy các nhánh cũng như git push origin master --forcevới mặc định của Git push.default config settings, mặc dù các nhánh cụ thể được đẩy khác nhau giữa các phiên bản Git trước 2.0 so với 2.0.

2
git push --forcehoạt động tốt trong những ngày này, FWIW ...
rogerdpack

git push --force-with-leasehoạt động thậm chí còn tốt hơn :), nó sẽ từ chối cập nhật một chi nhánh trừ khi đó là trạng thái mà bạn mong đợi. (xem developer.atlassian.com/blog/2015/04/force-with-lease )
spoorcc

Câu trả lời:


2309

Cứ làm đi:

git push origin <your_branch_name> --force

hoặc nếu bạn có một repo cụ thể:

git push https://git.... --force

Điều này sẽ xóa (các) cam kết trước đó của bạn và đẩy cam kết hiện tại của bạn.

Nó có thể không đúng, nhưng nếu bất cứ ai tình cờ thấy trang này, nghĩ rằng họ có thể muốn một giải pháp đơn giản ...

Cờ ngắn

Cũng lưu ý rằng đó -flà viết tắt của --force, vì vậy

git push origin <your_branch_name> -f

cũng sẽ làm việc


58
Bạn có thể sử dụng git push origin +masterthay thế, cho phép bạn đẩy nhiều refspec mà không buộc tất cả chúng.
nickgrim

5
Xin lưu ý rằng, nếu bạn vô tình làm git push --force, bạn có thể sẽ làm rối nhánh chủ của mình (tùy thuộc vào hành vi mặc định đẩy của bạn) .. Điều đó có thể hút .. một chút ..: D
Jeewes

9
@Jeewes bắt đầu với Git phiên bản 2.0, hành vi mặc địnhgit push --force về cơ bản là buộc đẩy chi nhánh hiện đang thanh toán sang bộ phận truy cập từ xa của nó, vì vậy nếu bạn đã kiểm tra chi nhánh chính thì nó giống hệt git push origin master --force. Sẽ khác nếu bạn đang sử dụng matchingcài đặt cho push.default, đây là mặc định cho các phiên bản Git trước 2.0. matchingđẩy tất cả các chi nhánh địa phương đến các chi nhánh từ xa có cùng tên, do đó, lực đẩy sau đó chắc chắn không phải là điều bạn muốn làm ...

@Jeewes Nhưng với Git 2.0, mặc định sẽ an toàn hơn hoặc ít nhất nó không nguy hiểm hơn git push origin master --force.

2
Push -f là tốt nhưng không được xem xét lại cho master vì hầu hết các kho lưu trữ của công ty đã bị vô hiệu hóa cho master. công merge -s oursviệc cho tôi
mihai

247

Và nếu push --forcekhông làm việc bạn có thể làm push --delete. Nhìn vào dòng thứ 2 trong trường hợp này:

git reset --hard HEAD~3  # reset current branch to 3 commits ago
git push origin master --delete  # do a very very bad bad thing
git push origin master  # regular push

Nhưng hãy cẩn thận...

Không bao giờ trở lại trong một lịch sử git công cộng!

Nói cách khác:

  • Đừng bao giờ forceđẩy vào một kho lưu trữ công cộng.
  • Đừng làm điều này hoặc bất cứ điều gì có thể phá vỡ của ai đó pull.
  • Đừng bao giờ resethoặc rewritelịch sử trong một repo ai đó có thể đã kéo.

Tất nhiên có những trường hợp ngoại lệ đặc biệt hiếm gặp ngay cả với quy tắc này, nhưng trong hầu hết các trường hợp, không cần thiết phải làm điều đó và nó sẽ tạo ra vấn đề cho mọi người khác.

Thay vào đó hãy hoàn nguyên.

luôn luôn cẩn thận với những gì bạn đẩy đến một repo công khai . Hoàn nguyên:

git revert -n HEAD~3..HEAD  # prepare a new commit reverting last 3 commits
git commit -m "sorry - revert last 3 commits because I was not careful"
git push origin master  # regular push

Trong thực tế, cả hai đầu nguồn gốc (từ hoàn nguyên và từ thiết lập lại ác ) sẽ chứa cùng một tệp.


chỉnh sửa để thêm thông tin cập nhật và nhiều đối số xung quanh push --force

Xem xét lực đẩy bằng cho thuê thay vì đẩy, nhưng vẫn thích hoàn nguyên

Một vấn đề khác push --forcecó thể mang lại là khi ai đó đẩy bất cứ điều gì trước khi bạn làm, nhưng sau khi bạn đã tải. Nếu bạn đẩy mạnh phiên bản nổi loạn của mình bây giờ, bạn sẽ thay thế công việc từ những người khác .

git push --force-with-leaseđược giới thiệu trong git 1.8.5 ( nhờ bình luận của @VonC về câu hỏi) cố gắng giải quyết vấn đề cụ thể này. Về cơ bản, nó sẽ mang lại lỗi và không đẩy nếu điều khiển từ xa được sửa đổi kể từ lần tìm nạp mới nhất của bạn.

Điều này là tốt nếu bạn thực sự chắc chắn push --forcelà cần thiết, nhưng vẫn muốn ngăn ngừa nhiều vấn đề hơn. Tôi muốn đi xa để nói rằng đó phải là push --forcehành vi mặc định . Nhưng nó vẫn không phải là một cái cớ để ép buộc a push. Những người tìm nạp trước cuộc nổi loạn của bạn vẫn sẽ gặp nhiều rắc rối, điều này có thể dễ dàng tránh được nếu bạn đã hoàn nguyên thay thế.

Và vì chúng ta đang nói về những git --pushtrường hợp ...

Tại sao bất cứ ai cũng muốn buộc đẩy?

@linquize đã mang đến một ví dụ lực đẩy tốt trên các bình luận: dữ liệu nhạy cảm . Bạn đã bị rò rỉ dữ liệu không nên đẩy. Nếu bạn đủ nhanh, bạn có thể "sửa"* nó bằng cách buộc một cú đẩy lên trên.

*Các dữ liệu vẫn sẽ được điều khiển từ xa , trừ khi bạn cũng làm một rác thu thập , hoặc làm sạch nó bằng cách nào đó . Ngoài ra còn có tiềm năng rõ ràng để nó được lan truyền bởi những người khác đã tải nó, nhưng bạn hiểu ý.


1
Vấn đề, @rogerdpack, không thể thực hiện được. Nó là. Nhưng nó có thể tổng hợp thành một thảm họa lớn. Càng nhiều người làm điều đó (lực đẩy) và bạn càng ít cập nhật (kéo) từ repo công khai, thảm họa càng lớn. Nó có thể phá hủy thế giới như bạn biết !!! 111 Ít nhất là thế giới bao gồm kho lưu trữ cụ thể đó.
cregox

3
Nếu bạn có dữ liệu nhạy cảm, hãy đẩy dữ liệu
nối tiếp

3
@Cawas: Tôi nghĩ rằng anh ta có nghĩa là nếu bạn đang cố xóa dữ liệu nhạy cảm khỏi kho lưu trữ, thì bạn muốn viết lại lịch sử. Nếu bạn hoàn nguyên, dữ liệu nhạy cảm vẫn còn đó trong cam kết trước đó. Điều đó nói rằng, nếu ai đó đã lấy từ kho lưu trữ, thì việc viết lại lịch sử sẽ không giúp bạn ngăn họ truy cập dữ liệu nhạy cảm - lúc đó đã quá muộn.
Stuart Golodetz

3
git push origin master --delete # do a very very bad bad thing git push origin master # regular pushđiều này thực sự đã giải quyết vấn đề của tôi một cách hoàn hảo (trên một repo chỉ có tôi và bạn tôi). có thể đó là sai đối với các repos công cộng nhưng đối với một tư nhân thì đây là một sự cứu rỗi.
Có thể Poyrazoğlu

1
điều này xảy ra tự động với một số người quản lý repo, còn gọi là tự động squash, v.v. buộc phải đẩy sau khi hoàn thành một nhánh tính năng để giảm các cam kết là phổ biến và được mong đợi.
FlavorScape

18

Trước hết, tôi sẽ không thực hiện bất kỳ thay đổi nào trực tiếp trong repo "chính". Nếu bạn thực sự muốn có một repo "chính", thì bạn chỉ nên đẩy nó, không bao giờ thay đổi trực tiếp.

Liên quan đến lỗi bạn đang gặp phải, bạn đã thử git pulltừ repo địa phương của bạn, và sau đó git pushđến repo chính? Những gì bạn hiện đang làm (nếu tôi hiểu rõ về nó) là buộc phải đẩy và sau đó mất các thay đổi của bạn trong repo "chính". Bạn nên hợp nhất các thay đổi cục bộ trước.


vâng tôi đã thử kéo nhưng tôi đang mất dữ liệu vì lần kéo đó. Tôi muốn thực hiện các repos chính của mình như là địa phương của tôi, mà không cần cập nhật trước từ chính.
Spyros

1
Trong trường hợp đó git push -f, nhưng sau đó nếu bạn thay đổi repo chính của mình một lần nữa, bạn phải quay lại repo cục bộ của mình và git pullđể nó được đồng bộ hóa với những thay đổi mới nhất. Sau đó, bạn có thể làm công việc của bạn, và đẩy một lần nữa. Nếu bạn làm theo quy trình "đẩy-kéo" này, bạn sẽ không gặp phải loại lỗi mà bạn đã phàn nàn.
ubik

yeah, tôi hiểu rằng đây là lỗi của tôi: / Tôi sẽ cố gắng đó và nhận trở lại trong một thời gian ngắn thanx
Spyros

1
đã cố gắng ép buộc, nhưng khi quay trở lại máy chủ chính để lưu các thay đổi, tôi bị dàn dựng lỗi thời. Vì vậy, khi tôi cam kết các kho lưu trữ không giống nhau. Và khi tôi cố gắng sử dụng git đẩy một lần nữa, tôi cũng gặp lỗi tương tự.
Spyros

17

Nếu tôi ở nhánh A địa phương và tôi muốn đẩy nhánh B cục bộ sang nhánh gốc CI có thể sử dụng cú pháp sau:

git push --force origin B:C

2
Tôi phát hiện ra rằng ngay cả tôi ở chi nhánh B địa phương, tôi vẫn cần phải làm git push --force origin B:C. Trong trường hợp của tôi, dường như git push --force origin Csẽ chỉ đẩy từ chủ địa phương sang chi nhánh C từ xa, bất kể tôi đang ở chi nhánh nào. git version 2.3.8 (Apple Git-58)
Weishi Zeng

12

sử dụng lệnh sau:

git push -f origin master

1
Có thể đưa ra một số giải thích thêm về lý do tại sao câu trả lời này thích hợp hơn những câu hỏi khác, và điều gì làm cho nó khác biệt.
Adam

oh, xin lỗi vì sự bất tiện này, tôi đã gặp vấn đề tương tự và lệnh này giải quyết nó, tôi nghĩ tôi nên chia sẻ nó.
mustafa Elsayed

12
Nó cũng giống như những người khác, bạn chỉ cần thay đổi vị trí của -fcờ ...
secraftiag

11

Tôi thực sự muốn giới thiệu:

  • chỉ đẩy đến repo chính

  • hãy chắc chắn rằng repo chính là một repo trần , để không bao giờ có bất kỳ vấn đề nào với cây làm việc repo chính không đồng bộ với .gitcơ sở của nó . Xem " Làm cách nào để đẩy kho lưu trữ git cục bộ sang máy tính khác? "

  • Nếu bạn phải sửa đổi trong repo chính (trần), sao chép nó (trên máy chủ chính), thực hiện sửa đổi của bạn và đẩy lùi nó

Nói cách khác, giữ một repo trần có thể truy cập cả từ máy chủ chính và máy tính cục bộ, để có một repo ngược dòng duy nhất từ ​​/ đến đó để kéo / kéo.


5

Đây là giải pháp của chúng tôi để thay thế chủ trên kho gitHub của công ty trong khi duy trì lịch sử.

push -fđể làm chủ kho lưu trữ của công ty thường bị vô hiệu hóa để duy trì lịch sử chi nhánh. Giải pháp này đã làm việc cho chúng tôi.

git fetch desiredOrigin
git checkout -b master desiredOrigin/master // get origin master

git checkout currentBranch  // move to target branch
git merge -s ours master  // merge using ours over master
// vim will open for the commit message
git checkout master  // move to master
git merge currentBranch  // merge resolved changes into master

đẩy chi nhánh của bạn đến desiredOrigin và tạo ra một PR


3

Tôi đã có cùng một câu hỏi nhưng cuối cùng đã tìm ra nó. Những gì bạn rất có thể cần làm là chạy hai lệnh git sau (thay thế hàm băm bằng số sửa đổi cam kết git):

git checkout <hash>
git push -f HEAD:master
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.