Làm cách nào tôi có thể sử dụng git rebase mà không cần phải đẩy mạnh?


92

Trong nỗ lực đạt được niết bàn git, tôi đang dành cả ngày để học cách tận dụng rebase cho các tình huống mà tôi hiện đang hợp nhất.

Khi chạy qua những gì tôi coi là luồng git 101 (mà tôi trình bày bên dưới), tôi phải thực hiện push --forcekhi đẩy các thay đổi của mình trở lại nguồn gốc.

Tôi không phải là người duy nhất - tôi biết rằng đây là mặt đất có mái che (xem 1 , 2 , 3 , 4 , 5 ) và tôi hiểu các lý do kỹ thuật tại sao lực lượng là cần thiết. Vấn đề của tôi là điều này --- có rất nhiều (nhiều) mục blog ca ngợi rebase và cách nó đã thay đổi cuộc sống của họ (xem 1 , 2 , 3 , 4 để liệt kê một số), nhưng không ai trong số họ đề cập đó push --forcelà một phần của dòng chảy của chúng. Tuy nhiên, gần như mọi câu trả lời cho các câu hỏi stackoverflow hiện tại đều nói những câu như "vâng, nếu bạn định rebase, bạn phải sử dụng push --force".

Với số lượng và mức độ tin cậy của những người ủng hộ rebase, tôi phải tin rằng việc sử dụng 'push --force' không phải là một phần cố hữu của quy trình rebase và nếu ai đó thường xuyên phải thúc đẩy thì họ đang làm sai .

push --forcelà một điều tồi tệ .

Vì vậy, đây là dòng chảy của tôi. Bằng cách nào tôi có thể đạt được kết quả tương tự mà không cần đến sức mạnh?

Ví dụ đơn giản

Hai chi nhánh:

  • v1.0 - một nhánh phát hành, chỉ chứa các bản vá lỗi
  • master - mọi thứ cho bản phát hành lớn tiếp theo.

Tôi có một vài cam kết về bản vá và một vài cam kết cho bản phát hành tiếp theo.

trộn trước

Tôi muốn kết hợp các bản vá vào tổng thể của mình để chúng không bị mất cho bản phát hành tiếp theo. Tiền khai sáng, tôi chỉ đơn giản là:

git checkout master
git merge v1.0

Nhưng bây giờ tôi đang cố gắng

git checkout master
git rebase v1.0

Vì vậy, bây giờ tôi ở đây:

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

Thời gian cho:

git push

Không có con xúc xắc.

Câu trả lời:


43

Rebasing là một công cụ tuyệt vời, nhưng nó hoạt động tốt nhất khi bạn sử dụng nó để tạo các hợp nhất tua đi nhanh chóng cho các nhánh chủ đề vào chính. Ví dụ: bạn có thể căn cứ lại nhánh tiện ích bổ sung mới của mình so với nhánh phụ:

git checkout add-new-widget
git rebase -i master

trước khi thực hiện hợp nhất tua đi nhanh nhánh thành cái. Ví dụ:

git checkout master
git merge --ff-only add-new-widget

Lợi ích của việc này là lịch sử của bạn sẽ không có nhiều cam kết hợp nhất phức tạp hoặc xung đột hợp nhất, bởi vì tất cả các thay đổi của bạn sẽ được hoàn nguyên vào đầu tổng thể trước khi hợp nhất. Một lợi ích phụ là bạn đã giảm giá, nhưng bạn không cần phải sử dụng git push --forcevì bạn không làm tắc nghẽn lịch sử trên nhánh chính.

Đó chắc chắn không phải là trường hợp sử dụng duy nhất cho rebase hoặc quy trình làm việc duy nhất, nhưng đó là một trong những cách sử dụng hợp lý hơn cho nó mà tôi đã thấy. YMMV.


4
Cảm ơn CG, tôi nghĩ rằng "sử dụng nó để tạo ra các hợp nhất tua đi nhanh" là chìa khóa. Nó không áp dụng cho trường hợp của tôi ở trên khi tôi có hai nhánh sống - một nhánh phát triển và một nhánh phát hành, nhưng nó có vẻ áp dụng rất tốt cho các nhánh chủ đề tạm thời chỉ cần thiết cho một thời gian ngắn hạn, và sau đó có thể đã xóa khi chúng được hợp nhất. Cảm ơn một lần nữa.
Roy Truelove

1
Tôi hiểu điều này, nhưng câu hỏi ban đầu vẫn còn. Tôi nghĩ câu trả lời thực tế là một trong những do @Fabien Quatravaux
IsmailS

4
Chà, bạn vẫn sẽ phải đẩy nhánh 1.0, phải không? Ít nhất, đó là cách mọi thứ có xu hướng xảy ra với tôi mọi lúc. Phương pháp Fabiens sẽ ngăn điều đó xảy ra.
joerx

23

@CodeGnome nói đúng. Bạn không nên rebase master trên nhánh v1.0 mà là nhánh v1.0 trên master, điều đó sẽ tạo nên sự khác biệt.

git checkout -b integrate_patches v1.0
git rebase master
git checkout master
git merge integrate_patches

Tạo một nhánh mới trỏ đến v1.0, di chuyển nhánh mới đó lên trên cái chính và sau đó tích hợp phiên bản mới của các bản vá lỗi V1.0 vào nhánh chính. Bạn sẽ kết thúc với một cái gì đó như:

o [master] [integrate_patches] Another patch on v1.0
o A patch on v1.0
o Another change for the next major release
o Working on the next major release
|  o [v1.0] Another path on v1.0
|  o A patch on v1.0
| /
o Time for the release

Cách sử dụng rebase này được khuyến nghị bởi tài liệu git chính thức .

Tôi nghĩ rằng bạn đã đúng về việc git push --force: bạn chỉ nên sử dụng nó nếu bạn đã phạm sai lầm và đẩy một cái gì đó bạn không muốn.


Tôi nghĩ đây là câu trả lời tốt nhất cho vấn đề cụ thể trong OP. Bạn tạo một nhánh hợp nhất tạm thời và căn cứ lại nhánh đó, sau đó hợp nhất để làm chủ và đẩy về gốc. Nhánh tạm thời không phải được đẩy đến điểm gốc. Lời khuyên bổ sung duy nhất tôi sẽ đưa ra là có một chi nhánh phát triển hoặc qa nơi mã được hợp nhất / khôi phục có thể đủ điều kiện. Sau khi đủ điều kiện, mã này sau đó sẽ được hợp nhất ff-only thành master. Điều này cho phép dễ dàng sửa lỗi nếu quá trình xác nhận của bạn mất quá nhiều thời gian. Về cơ bản đây là quy trình "git flow".
Javid Jamae

Cảm ơn Fabien, câu trả lời tuyệt vời. Đối với những người thân của chúng ta rằng chỉ muốn tích hợp các thay đổi vào mastervà không ngại việc sáp nhập các chi nhánh tính năng riêng của mình, điều này có thể được thực hiện với:git checkout my-branch; git rebase master; git checkout master; git merge my-branch
Siavas

17

Bạn phải thúc đẩy nếu bạn rebase bạn đã xuất bản các thay đổi của mình, phải không?

Tôi sử dụng rebase rất nhiều, nhưng tôi hoặc xuất bản lên một cái gì đó riêng tư mà lực đẩy không quan trọng (ví dụ: bản sao của riêng tôi trên GitHub, như một phần của yêu cầu kéo) hoặc tôi rebase trước khi đẩy lần đầu tiên.

Đây là trọng tâm của quy trình làm việc mà bạn sử dụng rebase, nhưng đừng ép quá nhiều: không xuất bản mọi thứ cho đến khi chúng sẵn sàng, không rebase sau khi bạn đẩy.


Cảm ơn Dan. Bạn có thể cho tôi biết làm thế nào những điều trên sẽ đạt được sau đó? Đây không phải là một kịch bản mà rebase áp dụng?
Roy Truelove

2
Nếu bạn tách biệt tất cả công việc của mình thành các nhánh chủ đề, thì điều đó sẽ tạo ra một kịch bản tốt để phục hồi. Bạn rebasemới kéo các thay đổi vào nhánh chủ đề của mình, nhưng khi bạn đã hoàn thành các thay đổi của nhánh đó, bạn sẽ mergeđưa nhánh đó trở lại nhánh phát triển chính.
redhotvengeance

1
Vấn đề là bạn đã xuất bản nhánh - vì vậy bạn cần phải đẩy mạnh vào kho lưu trữ. Bạn cần từ bỏ một trong hai cách: xuất bản theo cách bạn làm, hoặc giảm giá. Lấy làm tiếc.
Daniel Pittman

Có vẻ như việc phục hồi không hoạt động cho trường hợp này. v1.0 không phải là một nhánh chủ đề, nó là một nhánh phát hành, vì vậy nó sẽ không bao giờ chết và phải được xuất bản.
Roy Truelove

5

Tôi nghĩ rằng có một trường hợp sử dụng tốt cho mô hình rebase-then-force-push này không phải là kết quả của một sự thúc đẩy nhầm lẫn: tự bạn làm việc trên một nhánh tính năng từ nhiều vị trí (máy tính). Tôi làm việc này thường xuyên, vì đôi khi tôi làm việc tại văn phòng trên máy tính để bàn và đôi khi ở nhà / trang web của khách hàng trên máy tính xách tay của mình. Đôi khi tôi cần rebase để theo kịp với nhánh chính và / hoặc để làm cho các hợp nhất sạch hơn, nhưng tôi cũng cần phải đẩy mạnh khi tôi rời một máy để bắt đầu làm việc trên máy khác (nơi tôi chỉ kéo). Hoạt động như một cái duyên, miễn là tôi là người duy nhất làm việc trên chi nhánh.


2
Tôi có cùng quy trình làm việc này (làm việc từ nhiều máy tính / vị trí). Vì vậy, giả sử bạn đang làm việc trên một nhánh chủ đề có tên là 'mytopic'. Miễn là bạn luôn căn cứ lại một nhánh ném cục bộ (chỉ đơn thuần là một nhánh của mytopic) vào "master" và sau đó hợp nhất nó lại thành mytopic, thì bạn sẽ không bao giờ phải ép push. OP có một kịch bản hơi khác, vì vậy trong trường hợp như vậy, một lực đẩy có thể là cần thiết. Tuy nhiên, tôi nghĩ rằng OP đang phục hồi sai cách - nếu anh ấy làm điều đó như tôi đã mô tả thì không cần thiết phải đẩy mạnh.
bwv549

3

Đây là những gì tôi sử dụng (giả sử tên chi nhánh của bạn là foobar ):

git checkout master              # switch to master
git rebase   foobar              # rebase with branch
git merge -s ours origin/master  # do a basic merge -- but this should be empty
git push origin master           # aaand this should work

2
Bậc thầy phục hồi trông kỳ lạ.
Emil Vikström

2
gitkhông phải là không có cá tính
redolent

1
git merge -s ours origin/<branch>là những gì đã sửa nó cho chúng tôi
Tối đa

0

tl; dr hợp nhất với các nhánh chia sẻ, rebase với các nhánh riêng lẻ. --force-with-leaselà một sự thay thế an toàn hơn cho vũ lực và sẽ giúp bạn đạt được niết bàn đã nói mà không có bản chất hủy diệt của vũ lực.

Một nguyên tắc chung mà tôi đã thấy làm việc cho các quy trình làm việc của các nhóm khác nhau là sử dụng mergecho các nhánh chia sẻ (tức là làm chủ hoặc phát triển) và sử dụng rebasekhi làm việc trên nhánh tính năng của riêng bạn. Đây là vòng đời điển hình của một nhánh tính năng

git checkout master
git checkout -b new-feature
git commit -am "commit new work"
git push -u origin new-feature
# have code reviewed, run CI, etc.,
# meanwhile master has new commits
git checkout master
git pull
git rebase -i master # -i for interactive rebase allows you to squash intermediate commits
git push --force-with-lease
git merge master

Một phiên bản tiếng Anh đơn giản của những gì chúng tôi đã làm ở đây:

  1. Đã tạo một nhánh mới ngoài tổng thể
  2. Hoàn thành công việc trên nhánh và được đẩy sang điều khiển từ xa
  3. từ bỏ chủ nhân
  4. Đẩy công việc sang điều khiển từ xa với force-with-lease
  5. hợp nhất thành cái chính với một nhật ký git rất rõ ràng, giảm sự lộn xộn từ nhiều lần hợp nhất từ ​​nhánh chia sẻ của chúng tôi để nhánh của chúng tôi "bắt kịp" với cái chính mới nhất (nhánh chia sẻ)

Bước thứ 4 THỰC SỰ rất quan trọng và là một trong những lý do chính khiến tôi bắt đầu ủng hộ việc sử dụng rebase. force-with-leasekiểm tra điều khiển từ xa để xem có bất kỳ cam kết mới nào đã được thêm vào hay không. Nếu của bạn git pushđã được chứng minh là phá hoại, nó sẽ không thúc đẩy!

Tôi hy vọng điều này giúp ai đó tự tin hơn để sử dụng rebase.

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.