Git kéo sau khi cập nhật bắt buộc


332

Tôi chỉ bóp chết một số cam kết git rebasevà làm một git push --force(đó là xấu xa, tôi biết).

Bây giờ các kỹ sư phần mềm khác có một lịch sử khác và khi họ làm một git pull, Git sẽ hợp nhất. Có cách nào để khắc phục điều này, ngoại trừ làm một rm my-repo; git clone git@example.org:my-repo.git?

Tôi cần một cái gì đó giống như ngược lại git push --force, nhưng git pull --forcekhông cho kết quả như mong muốn.


16
họ có thể xóa chi nhánh của mình và tạo lại nó, mà không phải xóa toàn bộ repo:git checkout master && git branch -D test && git checkout -b test origin/test
Florian Klein


Câu trả lời:


508

Để nhận các cam kết mới

git fetch

Cài lại

Bạn có thể đặt lại cam kết cho một chi nhánh địa phương bằng cách sử dụng git reset.

Để thay đổi cam kết của một chi nhánh địa phương:

git reset origin/master --hard

Hãy cẩn thận, vì tài liệu đưa ra:

Đặt lại chỉ mục và cây làm việc. Mọi thay đổi đối với các tệp được theo dõi trong cây làm việc kể từ khi <commit> bị loại bỏ.

Nếu bạn thực sự muốn giữ bất kỳ thay đổi nào bạn có tại địa phương - --softthay vào đó hãy thực hiện đặt lại. Sẽ cập nhật lịch sử cam kết cho chi nhánh, nhưng không thay đổi bất kỳ tệp nào trong thư mục làm việc (và sau đó bạn có thể cam kết chúng).

Nổi loạn

Bạn có thể phát lại các cam kết cục bộ của mình trên bất kỳ cam kết / chi nhánh nào khác bằng cách sử dụng git rebase:

git rebase -i origin/master

Điều này sẽ gọi rebase trong chế độ tương tác, nơi bạn có thể chọn cách áp dụng từng cam kết riêng lẻ không có trong lịch sử mà bạn đang bắt đầu.

Nếu các xác nhận bạn đã xóa (với git push -f) đã được đưa vào lịch sử địa phương, chúng sẽ được liệt kê dưới dạng các cam kết sẽ được áp dụng lại - chúng sẽ cần được xóa như một phần của cuộc nổi loạn hoặc đơn giản là chúng sẽ được đưa vào lịch sử cho chi nhánh - và xuất hiện trở lại trong lịch sử từ xa trong lần đẩy tiếp theo.

Sử dụng trợ giúp git command --helpđể biết thêm chi tiết và ví dụ về bất kỳ lệnh nào ở trên (hoặc khác).


2
@iblue chọn giữa việc mất tất cả các thay đổi, xóa lịch sử cam kết nhưng vẫn giữ các thay đổi tệp hoặc cố gắng áp dụng từng cam kết trên đỉnh đầu mới. Tùy chọn đơn giản nhất có lẽ là thiết lập lại mềm.
AD7six

1
@iblue Khi đồng nghiệp của bạn sử dụng 'git rablesse origin / master', và trong khi đó, họ đã có một số cam kết trước đó, git sẽ viết cam kết của bạn vào phía sau cam kết của họ.
Tim

6
Có thể đáng nói đến nếu điều này dành cho một chi nhánh khác:git reset origin/otherbranch --hard
bmaupin

Vì vậy, để làm rõ, đây là một trong hai : Lựa chọn 1: reset --hard, hoặc Phương án 2: reset --soft+ rebase, phải không?
PlasmaBinturong

2
@PlasmaBinturong Số git reset --soft origin/mastersẽ thay đổi lịch sử cam kết để phù hợp với sự khác biệt từ xa và giai đoạn với điều khiển từ xa được cam kết . Sẽ không cần phải phản ứng lại trong kịch bản đó (và bạn sẽ bị ngăn không được thực hiện vì những thay đổi không được cam kết) vì không có sự khác biệt trong lịch sử cam kết. Hai tùy chọn được đặt lại hoặc rebase - không phải là sự kết hợp của cả hai. Vui lòng đặt câu hỏi nếu kịch bản của bạn khác với kịch bản tôi đã trả lời ở đây.
AD7six

16

Điều này sẽ không sửa các nhánh đã có mã mà bạn không muốn trong đó (xem bên dưới để biết cách thực hiện), nhưng nếu họ đã rút một số nhánh và bây giờ muốn nó sạch (và không "đi trước" nguồn gốc / một số chi nhánh) sau đó bạn chỉ cần:

git checkout some-branch   # where some-branch can be replaced by any other branch
git branch base-branch -D  # where base-branch is the one with the squashed commits
git checkout -b base-branch origin/base-branch  # recreating branch with correct commits

Lưu ý: Bạn có thể kết hợp tất cả những thứ này bằng cách đặt && giữa chúng

Note2: Florian đã đề cập đến điều này trong một bình luận, nhưng ai đọc bình luận khi tìm câu trả lời?

Lưu ý 3: Nếu bạn có các nhánh bị ô nhiễm, bạn có thể tạo các nhánh mới dựa trên "nhánh câm" mới và chỉ cần chọn cam kết.

Ví dụ:

git checkout feature-old  # some branch with the extra commits
git log                   # gives commits (write down the id of the ones you want)
git checkout base-branch  # after you have already cleaned your local copy of it as above
git checkout -b feature-new # make a new branch for your feature
git cherry-pick asdfasd   # where asdfasd is one of the commit ids you want
# repeat previous step for each commit id
git branch feature-old -D # delete the old branch

Bây giờ tính năng mới là chi nhánh của bạn mà không có các cam kết bổ sung (có thể xấu)!


Đây là những gì tôi thực sự muốn. Ai đó đã từ chối chi nhánh chính (vì chúa biết lý do gì) nhưng tôi không có thay đổi cục bộ nào trên đó mà tôi muốn cam kết hoặc bất cứ điều gì. Vì vậy, tất cả những gì tôi phải làm là xóa chi nhánh chính địa phương (cảm thấy thực sự kỳ lạ) và kiểm tra lại. Cảm ơn!
Danilo Carvalho

@ peter-mortensen Chỉnh sửa phải đáng kể theo stackoverflow.com/help/editing
Tom Prats

cho bước cuối cùng, bạn cũng có thể sử dụng git checkout -b base-branch origin/base-branchvớigit checkout --track origin/base-branch
bluesmonk

1

Kéo với rebase

Một kéo thông thường là tìm nạp + hợp nhất, nhưng những gì bạn muốn là tìm nạp + rebase. Đây là một tùy chọn với pulllệnh:

git pull --rebase

Tôi sử dụng tất cả thời gian này để nhận mã mới nhất từ ​​chủ vào nhánh tính năng của mình mà không có tất cả các cam kết hợp nhất trong lịch sử.
herman
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.