Làm việc trên một chi nhánh với sự phụ thuộc vào một chi nhánh khác đang được xem xét


65

Làm thế nào để git giúp đối phó với kịch bản dưới đây:

Tôi có một nhiệm vụ được chia thành 2 phần: nhiệm vụ phụ trợ và nhiệm vụ frontend. Tôi thực hiện một yêu cầu kéo để hợp nhất các thay đổi phụ trợ và chờ đợi nó được hợp nhất (và phản hồi địa chỉ). Trong khi chờ đợi, tôi thực sự không thể làm việc với các thay đổi ở lối vào vì nó phụ thuộc vào các thay đổi phụ trợ và những thay đổi này chưa có sẵn trên nhánh chính.

Cách tốt nhất để kéo các thay đổi vào nhánh thay đổi từ nhánh thay đổi phụ trợ trong khi nó vẫn đang được xem xét là gì?


14
Thông thường, các giao diện của dự án back end nên được xác định rõ ràng. Vì vậy, khi bắt đầu triển khai giao diện người dùng của bạn, điều đó không làm phiền bạn, nếu logic phía sau vẫn được xem xét, vì bạn có thể sử dụng giả lập.
Herr Derb

17
@HerrDerb Ôi đứa trẻ mùa hè ngọt ngào ...
vườn

4
Tại sao bạn không thể viết nó chống lại mã phụ trợ chưa được xem xét của bạn?
dùng253751

Đội của bạn có một số loại kỹ thuật đã thỏa thuận để xử lý tình huống này không? Nếu không, có lẽ bạn nên đồng ý về một cái gì đó như thế này, vì đó là một tình huống khá phổ biến.
Radu Murzea

Chẳng có ai. Đó là lý do tại sao tôi hỏi câu hỏi này. Tôi đã nhận được đề nghị rất tốt. Tôi sẽ thử các đề xuất và xem cách họ làm việc cho tôi.
sul4bh

Câu trả lời:


42

Tôi có vấn đề này quá đôi khi. Git rất linh hoạt. Đây là một cách bạn có thể làm điều đó.

Chi nhánh đầu tiên của bạn featureAlà lên để xem xét.

Chi nhánh thứ hai của bạn featureBđang được phát triển và phụ thuộc vào mã trong featureAchi nhánh.

Hợp nhất các featureAchi nhánh vào featureBchi nhánh.

Nếu bạn thực hiện thay đổi cho featureAchi nhánh thì bạn nên hợp nhất featureAchi nhánh vào featureBchi nhánh một lần nữa để kết hợp các thay đổi.

Bạn cũng nên đảm bảo hợp nhất featureAvào thân chính trước, nếu không, khi bạn hợp nhất featureBvào thân chính, bạn sẽ vô tình cũng hợp nhất featureA. Sau khi featureAđược hợp nhất vào thân chính, bạn có thể thoát khỏi featureAnhánh vì featureBchỉ phụ thuộc vào thân chính bây giờ.

Tôi thích nó khi các nhánh tính năng của tôi không phụ thuộc vào nhau nhưng đôi khi chúng làm được và bạn phải lăn lộn với nó.


Điều này thật ý nghĩa. Điều này cho phép hoàn tác việc sáp nhập featureAvào featureBnếu cần thiết?
sul4bh

8
Không có thao tác hoàn tác nào nhưng như @ 9000 đề cập, bạn có thể tạo một chi nhánh mới và anh đào chọn những cam kết bạn muốn từ featureAđó nếu bạn phải bắt đầu lại từ đầu. Thật tốt khi nghĩ về các chi nhánh Git là dùng một lần. Chúng rẻ và dễ dàng, bạn luôn có thể tạo một chi nhánh mới. Bạn thậm chí có thể tạo một nhánh thử nghiệm khỏi nhánh của mình featureBnếu bạn muốn chơi xung quanh với thứ gì đó mà bạn không chắc chắn, và sau đó loại bỏ nó nếu nó không hoạt động, hoặc hợp nhất nó trở lại featureBnhánh của bạn nếu nó làm được.
Matt

9
Việc hợp nhất sẽ tạo ra một mớ hỗn độn sẽ rất khó (không phải là không thể) để khôi phục lại. Tôi sẽ chọn cherry-pick hoặc rebase (nghĩa là: cherry-pick mọi thứ trong FeatureA ở cơ sở của FeatureB). Xem câu trả lời của 9000.
Pierre.Sassoulas

1
Điều này tạo ra một lịch sử phức tạp sẽ là vấn đề trong nhiều năm tới bất cứ khi nào ai đó muốn hiểu mã nào đã được thay đổi cho FeatureA và FeatureB
Ian

2
nếu featureA được cập nhật, featureB nên được rebased không sáp nhập
Lyndon Trắng

40

Giữ, bỏ qua sáp nhập

Đối với phương pháp này, bạn không muốn hợp nhất feature_athành feature_bnhiều lần.

Rebasing đã được đề cập trong các câu trả lời khác, nhưng chỉ để nổi loạn mọi thứ trên master. Những gì bạn muốn làm trong trường hợp của bạn là:

  • Bắt đầu feature_btừ feature_a, tức là:

    git checkout feature_a
    git checkout -b feature_b
    
  • Bất cứ khi nào feature_athay đổi trong khi nó đang chờ đợi để được sáp nhập vào master, bạn rebase feature_b vào nó:

    ... commit something onto feature_a ...
    git checkout feature_b
    git rebase feature_a
    
  • Cuối cùng, ngay sau khi feature_ađược sáp nhập vào master, bạn chỉ cần lấy cái mới mastervà khởi động feature_alại nó lần cuối:

    git checkout master
    git pull origin master
    git checkout feature_b
    git rebase --onto master feature_a feature_b
    

    Cuộc nổi loạn cuối cùng này sẽ ghép tất cả các cam kết đang lơ lửng từ feature_acam kết (hiện không liên quan vì nó đã được sáp nhập vào master) ngay trên master. feature_bBây giờ của bạn là một chi nhánh đơn giản, tiêu chuẩn đi ngay từ master.

EDIT: lấy cảm hứng từ các bình luận, một chút ngẩng cao đầu: nếu bạn cần thực hiện một số thay đổi có ảnh hưởng đến cả hai tính năng, thì hãy chắc chắn đưa nó vào feature_a(và sau đó rebase như được hiển thị). Đừng không làm cho nó trong hai cam kết khác nhau trong cả hai ngành, thậm chí nếu có thể hấp dẫn; như feature_alà một phần của lịch sử feature_b, việc có một thay đổi duy nhất trong hai cam kết khác nhau sẽ sai về mặt ngữ nghĩa và có thể dẫn đến xung đột hoặc "hồi sinh" mã không mong muốn, sau đó.


2
Với việc nổi loạn feature_anhiều lần, sau đó bạn có thể gặp vấn đề, khi feature_ađó chính nó đã bị nổi loạn trong thời gian đó. Kết quả của việc chạy, git checkout feature_b; git rebase feature_abạn có thể nhận được xung đột hoặc một số xác nhận hài hước có chứa các cam kết hoàn nguyên các thay đổi mới của feature_a. Điều này thường có thể giải quyết được bằng cách sử dụng --interactivevà bỏ qua các cam kết được lấy từ phiên bản cũ của chi nhánh khác (tôi đã phải làm điều này nhiều lần gần đây).
maaartinus

@maaartinus, cảm ơn vì đã đề phòng, tôi đã không gặp phải những vấn đề như vậy. Cũng rebasenhư nhiều bước riêng lẻ hơn đơn giản merge, chắc chắn có cơ hội cao hơn để tạo ra xung đột; mặt khác mergesẽ chỉ là sai về mặt ngữ nghĩa để làm trong trường hợp này.
AnoE

Tôi đoán, mergesẽ có những vấn đề tương tự hoặc tồi tệ hơn (một cuộc xung đột không tệ như nhận được một thay đổi không mong muốn). Tôi xem một nhánh là chuỗi các thay đổi mong muốn có trước nhiều thay đổi không liên quan (về mặt logic thuộc về một nhánh khác). Khi liên tục nổi loạn với cùng một nhánh, tôi luôn loại bỏ các thay đổi không liên quan vì tôi biết dù sao chúng cũng sẽ xuất hiện (có thể trong một hình dạng cập nhật) và nó hoạt động tốt.
maaartinus

1
@maaartinus, tôi đã thêm một phụ lục nhỏ về điều này (để liên tục thực hiện các thay đổi cần đi vào cả hai nhánh chỉ trong nhánh cơ sở, không phải trong hai cam kết khác nhau).
AnoE

Kỹ thuật đẹp. Đó là cách tôi luôn luôn làm điều đó. git rebase --ontoFTW: D
Radu Murzea

29

Bạn đã có một nhánh mà mỗi nhánh tính năng của bạn phụ thuộc và liên tục thay đổi. Nó được gọi là master.

Cách điển hình để một nhánh tính năng giữ đồng bộ với masternó là ở trên đỉnh của nó. Khi masterthay đổi, bạn thường git fetch origin master:master && git rebase mastertrong thư mục làm việc của chi nhánh.

Bạn có thể làm điều tương tự với một nhánh tính năng khác: tiếp tục tìm nạp nó và nổi loạn lên trên nó.

Nếu, vì một số lý do, bạn sẽ cần chuyển các thay đổi của mình sang một chi nhánh khác, bạn có thể chọn các cam kết của mình , không bao giờ trộn lẫn với các cam kết của chi nhánh khác.


Nhưng tôi nghĩ kịch bản là tính năng b cần mã có trong tính năng-a, việc phân nhánh từ chủ sẽ không hữu ích lắm. Tôi nên bắt đầu từ đâu? Tôi có nên phân nhánh từ tính năng-a và giữ cho các đồng bộ hóa cho đến khi tính năng-a được tái hòa nhập với chủ, sau đó chuyển từ chủ sang tính năng-b?
Thời tiết

@ Thẩm mỹ: tất nhiên bạn có thể dựa feature-bvào feature-a, và thực hiện một cuộc nổi loạn hết lần này đến lần khác feature-a. Đây là một cách điển hình để thực hiện một thay đổi lớn có thể quan sát được: chia nó thành part-A(dựa trên master), part-B(dựa trên part-A) và nhiều hơn nữa nếu cần. Sau đó thực hiện một yêu cầu kéo cho từng phần và người đánh giá có thời gian dễ dàng hơn để xem các phần nhỏ hơn, được nhóm hợp lý.
9000

sẽ có vấn đề gì nếu tôi phản đối part-b với part-a so với part-b với master về mặt PR? Tôi chỉ muốn đảm bảo những thay đổi của mình không hiển thị phần thay đổi như những thay đổi trong phần b. Ngoài ra, nếu tôi hợp nhất với rebase, điều đó sẽ ảnh hưởng đến PR part-b như thế nào? Mỗi khi tôi nghĩ rằng tôi hiểu được các hiệu ứng, tôi nhận được một số kết quả khác nhau lol
Trang web

5

Trong trường hợp này, tác vụ frontend có sự phụ thuộc quan trọng vào mã phụ trợ và bạn muốn bắt đầu công việc trên frontend trước khi phần cuối được hoàn thành và được chấp nhận trên master, tôi chỉ cần bắt đầu tác vụ frontend như một nhánh tính năng xuất phát từ nhánh phụ trợ, thay vì phân nhánh frontend trên master.

Một nhánh tính năng sống đủ lâu cần phải hợp nhất trong các thay đổi từ chính thỉnh thoảng (để đảm bảo bạn điều hòa mọi xung đột hợp nhất hoặc ngữ nghĩa như một phần của dev hoạt động trên nhánh tính năng, thay vì là một phần của "đánh giá, qa, hợp nhất- quy trình "làm chủ". Vì vậy, bạn làm điều đó trên nhánh trước của bạn và khi công việc phụ trợ đã được chấp nhận để làm chủ, bạn sẽ nhận được bất kỳ thay đổi nhỏ nào được thực hiện cho phụ trợ như một phần của đánh giá / chấp nhận tự động, theo cùng một lộ trình bạn nhận bất kỳ thay đổi mã khác trên chủ.

Nếu hóa ra nhánh phụ trợ cần nhiều công việc hơn và nó tiếp tục thay đổi trong một khoảng thời gian trước khi được hợp nhất thành chủ (giả sử nếu có vấn đề lớn được tìm thấy trong quá trình xem xét), thì bạn có thể muốn thực hiện sáp nhập định kỳ trực tiếp từ nhánh phụ trợ vào nhánh frontend (vì vậy bạn không tiếp tục dựa vào tất cả các công việc frontend của mình trên mã phụ trợ lỗi thời). Điều này thật dễ dàng nếu bạn là nhà phát triển duy nhất thực hiện cả hai tính năng (vì bạn biết nếu bản thân bạn thực hiện bất kỳ thay đổi lớn nào), nhưng ngay cả khi cả hai tính năng này đều được xử lý song song bởi các nhà phát triển khác nhau thì vẫn ổn; bạn chỉ cần duy trì liên lạc (dù sao bạn cũng cần phải thực hiện các nhiệm vụ song song khi người này có sự phụ thuộc quan trọng vào người khác).

Nếu nó chỉ ra rằng toàn bộ nhánh phụ trợ cần phải bị hủy bỏ và sẽ không bao giờ được hợp nhất (có vẻ như đây sẽ là một vấn đề lớn hiếm khi xảy ra), thì bạn có thể chọn cam kết của mình cho một chi nhánh mới sắp ra chủ không có công việc phụ trợ hoặc bạn áp dụng các cam kết ngược sẽ loại bỏ tất cả mã phụ trợ cho nhánh frontend. Nhưng như tôi có thể thấy, sẽ có nhiều khả năng tạm dừng công việc frontend cho đến khi bạn tìm ra điều gì sẽ thay thế phần phụ trợ mà bạn đang ném ra, và sau đó quyết định làm gì.


2

Tôi không thấy vấn đề ở đây.

Bạn đã có điều này mỗi lần với masterchi nhánh của mình , nó luôn thay đổi trong khi các tính năng được phát triển và sau đó được hợp nhất.

Vì vậy, trong ví dụ cụ thể của bạn, trước tiên bạn tạo feature_xxx_backendchi nhánh và phát triển các thay đổi phụ trợ. Khi điều này được thực hiện, chi nhánh sẽ được xem xét và sẽ được hợp nhất vào masterkhi hoàn thành đánh giá.

Vì vậy, chỉ cần bắt đầu một chi nhánh khác feature_yyy_frontend,. Bạn có thể sẽ muốn phân nhánh trực tiếp từ đó feature_xxx_backend, để bạn có những thay đổi đó trong tài khoản của bạn. sau đó chỉ cần phát triển tính năng frontend như chi nhánh master.

Khi feature_xxx_backendchi nhánh thay đổi, ví dụ vì có những thứ xuất hiện trong quá trình xem xét cần phải được quảng cáo, chỉ cần thực hiện những thay đổi này và hợp nhất chúng vào feature_yyy_frontendchi nhánh. Sau đó tiếp tục trên nhánh frontend.

Khi đánh giá của nhánh phụ trợ được hoàn thành, nó sẽ được hợp nhất vào master. Tại thời điểm này, nó sẽ là khôn ngoan để rebase các feature_yyy_frontendchi nhánh lên master, vì vậy mà các nhà phê bình chỉ cần xem lại mới thay đổi mà chi nhánh này góp phần vào việc master, và không cần phải xem lại lần nữa những thay đổi được thực hiện cho các phụ trợ (đã được phê duyệt ).

Điều này cũng có thể được thực hiện khi bạn có hai, ba hoặc nhiều nhánh phụ thuộc. Nếu bạn có hai nhánh tính năng mà bạn phụ thuộc, đơn giản hãy tạo một nhánh dẫn xuất có cả hai tính năng được hợp nhất. Chi nhánh từ đó, phát triển tính năng thứ ba, hợp nhất cả hai nhánh tính năng trên đường đi khi mỗi nhánh đó thay đổi. Khi cả hai tính năng được thực hiện và được hợp nhất vào nhánh dẫn xuất, hãy khởi động lại vào đó hoặc nếu chúng được hợp nhất thành chủ, hãy khởi động lại thành chủ.

Rebasing (như được đề xuất ở trên) thực sự mạnh mẽ và giúp giữ một bản ghi rõ ràng về các thay đổi, giúp việc đánh giá dễ dàng hơn nhiều.


2

Như Polygnome đã đề cập, bạn thực sự có thể hợp nhất nhánh frontend của bạn với nhánh phụ trợ thay vì các bậc thầy. Ngay cả với thiết lập chi nhánh hiện tại bạn có bây giờ, bạn chỉ cần làm:

git checkout frontend
git merge backend

hoặc đơn giản

git merge backend frontend

Hãy ghi nhớ rằng nếu thay đổi phụ trợ không được chấp nhận và cần thêm công việc, bạn sẽ phải hợp nhất các cập nhật từ phụ trợ vào giao diện để tránh xung đột. Khi các thay đổi được chấp nhận vào bản gốc, bạn có thể khởi động lại giao diện của mình trên bản gốc để thoát khỏi các cam kết hợp nhất phụ trợ.

Về mặt kỹ thuật, bạn cũng có thể làm mọi thứ với rebase, nhưng điều đó sẽ làm rối tung lịch sử cam kết của chi nhánh frontend của bạn. Tôi đến từ đâu, đây được coi là thực hành xấu. YMMV


"Thật kỳ lạ khi không ai đề cập rằng bạn thực sự có thể hợp nhất nhánh frontend của bạn với nhánh phụ trợ của bạn thay vì các bậc thầy:" Điều này đã được đề cập, ví dụ như trong câu trả lời của riêng tôi.
Polygnome

Giao diện @Polygnome không phải phân nhánh trực tiếp từ phụ trợ. Cả hai đều có thể được phân nhánh từ chủ, nhưng bạn vẫn có thể hợp nhất chúng. Vì vậy, câu trả lời của bạn không đề cập đến điều đó thực sự.
Joris Meys

Trên thực tế, câu trả lời của tôi không đề nghị bạn phân nhánh trực tiếp từ phụ trợ, nó chỉ sai mà đó có thể là con đường phải đi (vì bạn hợp nhất những thay đổi đó vào nhánh frontend).
Polygnome

@Polygnome thì tôi hiểu nhầm câu trả lời của bạn. Cập nhật đặc biệt cho bạn :-)
Joris Meys

Tôi không biết ai đã đánh giá thấp điều này, nhưng xin vui lòng cho tôi biết tôi sai ở đâu, vì vậy tôi cũng có thể học được điều gì đó.
Joris Meys

1

Hầu hết các câu trả lời ở đây mô tả chính xác quá trình hợp nhất các thay đổi từ nhánh thứ hai sang nhánh thứ nhất, nhưng chúng không giải quyết làm thế nào để giảm thiểu số lượng xung đột mà bạn có thể cần giải quyết.

Bất cứ khi nào bạn có hai bộ thay đổi lớn mà bạn muốn xem xét riêng lẻ (như featureAfeatureB), hãy tạo một PR không có nghĩa là được hợp nhất, nhưng để thu thập phản hồi sớm về PoC của featureA.

Mọi người sẽ có thể xem xét nó một cách nhanh chóng (đó chỉ là PoC) và mục tiêu là xác nhận thiết kế hoặc phương pháp tiếp cận chung.

Sau đó, bạn có thể tiếp tục làm việc trên tính năng A, tạo yêu cầu kéo cho nó và chi nhánh và làm việc trên tính năng B.

Sự khác biệt lớn là bây giờ bạn có thể mong đợi featureAkhông thay đổi hoàn toàn: thiết kế và phương pháp đã được xác nhận. Việc xem xét mã và các thay đổi bắt buộc có thể tinh tế và cục bộ hơn là "woops, bạn cần một cách tiếp cận khác". Điều này sẽ giảm thiểu số lượng công việc bạn cần làm để sau này hợp nhất featureBtrên featureAmã của, bất kể phương thức bạn đã chọn.

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.