không thể đẩy sang nhánh sau khi rebase


131

Chúng tôi sử dụng git và có một nhánh chính và các nhánh nhà phát triển. Tôi cần thêm một tính năng mới và sau đó khởi động lại các xác nhận thành chủ, sau đó đẩy chủ lên máy chủ CI.

Vấn đề là nếu tôi có xung đột trong khi rebase, tôi không thể đẩy sang nhánh nhà phát triển từ xa (trên Github) sau khi rebase hoàn thành, cho đến khi tôi kéo nhánh từ xa của mình. Điều này gây ra các cam kết trùng lặp. Khi không có xung đột, hoạt động như mong đợi.

câu hỏi: sau khi rebase và giải quyết xung đột, làm cách nào để đồng bộ hóa các nhánh nhà phát triển cục bộ và từ xa mà không tạo các cam kết trùng lặp

Thiết lập:

// master branch is the main branch
git checkout master
git checkout -b myNewFeature

// I will work on this at work and at home
git push origin myNewFeature

// work work work on myNewFeature
// master branch has been updated and will conflict with myNewFeature
git pull --rebase origin master

// we have conflicts
// solve conflict
git rebase --continue

//repeat until rebase is complete
git push origin myNewFeature

//ERROR
error: failed to push some refs to 'git@github.com:ariklevy/dropLocker.git'
hint: Updates were rejected because the tip of your current branch is behind
hint: its remote counterpart. Merge the remote changes (e.g. 'git pull')
hint: before pushing again.
hint: See the 'Note about fast-forwards' in 'git push --help' for details.

// do what git says and pull
git pull origin myNewFeature

git push origin myNewFeature

// Now I have duplicate commits on the remote branch myNewFeature

BIÊN TẬP

Vì vậy, có vẻ như điều này sẽ phá vỡ quy trình làm việc:

developer1 làm việc trên myNewFeature developer2 hoạt động trên cả NewFeature của cả hai đều sử dụng master làm nhánh chính

developer2 hợp nhất myNewFeature của mình vào NewFeature

developer1 khởi động lại, giải quyết xung đột, sau đó buộc đẩy đến chi nhánh từ xa cho myNewFeature

Vài ngày sau, developer2, hợp nhất myNewFeature của anh ấy lại với NewFeature

Điều này sẽ khiến các nhà phát triển khác ghét nhà phát triển1?


không phải là một giải pháp mà chỉ là một ý nghĩ ai we? bạn có ở trong một nhóm không chỉ là bạn không? theynói (những người biết nhiều hơn tôi) rằng nếu bạn chia sẻ mã của mình thì bạn không nên sử dụng rebase. Tại sao bạn không làm git pullgit merge?
AdamT

xin lỗi, chúng tôi = nhóm phát triển
Matt

1
vì vậy, có lẽ không nên nổi loạn khi bạn đang chia sẻ mã. điều đó có thể khiến bạn phải làm những việc như những gì được liệt kê dưới đây ( forcesự thúc đẩy)
AdamT

oh xin lỗi, khi họ nói rewriting history, đó là mộtrebase
AdamT

Như anh ấy nói đó là một nhánh phát triển của riêng anh ấy nên không phải là vấn đề trừ khi có ai đó dự kiến ​​sẽ hợp nhất nó.
Learath2

Câu trả lời:


93

Trước tiên, bạn và những người bạn đang làm việc cần phải đồng ý liệu một nhánh chủ đề / phát triển là để phát triển chia sẻ hay chỉ là của riêng bạn. Các nhà phát triển khác biết không hợp nhất trên các nhánh phát triển của tôi bởi vì họ sẽ bị từ chối bất cứ lúc nào. Thông thường quy trình làm việc như sau:

o-----o-----o-----o-----o-----o       master
 \
   o-----o-----o                      devel0
                \
                  o-----o-----o       devel1

Sau đó, để luôn cập nhật với điều khiển từ xa, tôi sẽ làm như sau:

 git fetch origin
 git checkout master
 git merge --ff origin/master

Tôi làm điều này vì hai lý do. Đầu tiên bởi vì nó cho phép tôi xem nếu có thay đổi từ xa mà không cần phải chuyển từ chi nhánh phát triển của mình. Thứ hai, đó là một cơ chế an toàn để đảm bảo tôi không ghi đè lên bất kỳ thay đổi chưa được xác nhận / cam kết nào. Ngoài ra, nếu tôi không thể chuyển tiếp nhanh vào nhánh chính, điều đó có nghĩa là ai đó đã từ chối chủ nhân từ xa (mà họ cần phải bị đánh lạc hướng nghiêm trọng) hoặc tôi vô tình cam kết làm chủ và cần phải dọn sạch kết thúc của mình.

Sau đó, khi điều khiển từ xa có thay đổi và tôi đã nhanh chóng chuyển tiếp đến phần mới nhất tôi sẽ phản đối:

git checkout devel0
git rebase master
git push -f origin devel0

Các nhà phát triển khác sau đó biết rằng họ sẽ cần loại bỏ các nhánh phát triển mới nhất của họ:

git fetch <remote>
git checkout devel1
git rebase <remote>/devel0

Điều này dẫn đến lịch sử sạch hơn nhiều:

o-----o                                 master
       \
         o-----o-----o                  devel0
                      \
                        o-----o-----o   devel1

Đừng hợp nhất cam kết qua lại theo ý thích của bạn. Nó không chỉ tạo ra các cam kết trùng lặp và làm cho lịch sử không thể theo dõi, việc tìm hồi quy từ một thay đổi cụ thể trở nên gần như không thể (đó là lý do tại sao bạn sử dụng kiểm soát phiên bản ở nơi đầu tiên, phải không?). Vấn đề bạn gặp phải là kết quả của việc làm này.

Ngoài ra, có vẻ như các nhà phát triển khác có thể đang thực hiện các cam kết với các nhánh phát triển của bạn. Bạn có thể xác nhận điều này?

Thời gian duy nhất để hợp nhất là khi nhánh chủ đề của bạn đã sẵn sàng để được chấp nhận master.

Còn một chú ý đáng nói. Nếu nhiều nhà phát triển đang cam kết vào cùng một kho lưu trữ, tất cả bạn nên xem xét việc có các nhánh được đặt tên để phân biệt giữa các nhánh phát triển. Ví dụ:

git branch 'my-name/devel-branch'

Vì vậy, tất cả các nhánh chủ đề của nhà phát triển nằm trong tập hợp lồng riêng của họ.


1
"Ngoài ra, có vẻ như các nhà phát triển khác có thể cam kết với các nhánh phát triển của bạn. Bạn có thể xác nhận điều này không?" CÓ, họ là ...
Matt

Bạn cũng đã đưa đến sự chú ý của tôi một vấn đề khác. Làm việc giữa văn phòng và nhà. Tôi hợp nhất ở cả hai nơi và vào cuối ngày tôi đẩy để tôi có thể nhận từ nơi tôi rời đi. Sau đó, khi đến lúc phải nổi loạn, tất cả những cam kết đó tạo ra sự nhầm lẫn. Tôi cần coi các nhánh của mình là một nhánh và rebase
Matt

@Matt Vâng, hai vấn đề đó sẽ thực sự làm hỏng quy trình làm việc của bạn. Đầu tiên, tôi sẽ liên lạc với các nhà phát triển khác mà chỉ chủ sở hữu mới có thể cam kết với một nhánh được đặt tên (ví dụ: 'matt / devel'). IMHO, không có hai nhà phát triển nên cam kết với cùng một chi nhánh. Chỉ tạo ra sự nhầm lẫn. Để sau này, việc nổi loạn và đẩy lực lượng phải giữ cho hai địa điểm được cập nhật.
Trevor Norris

Câu trả lời chính xác. Tôi có một câu hỏi phụ, tại sao bạn sử dụng --forcecờ khi bạn làm git push -f origin devel0?
Nobita

2
@Nobita Khi git pushkhông thể chuyển tiếp nhanh (tức là lịch sử sha không khớp), bạn phải buộc đẩy để ghi đè lên lịch sử trước đó với lịch sử mới được tạo từ git rebase.
Trevor Norris

50

Bạn cần phải đẩy lực đẩy khi bạn đã di chuyển các cam kết xuống phía dưới dòng git đang mong đợi bạn thêm các cam kết vào đầu nhánh. git push -f origin myNewFeaturesẽ khắc phục vấn đề của bạn.

Mẹo: Trên đây là cách sử dụng hợp pháp lực đẩy. Không bao giờ viết lại lịch sử trên một kho lưu trữ truy cập công khai hoặc nhiều người sẽ ghét bạn.


1
Tôi thấy đây là cách tối ưu nhất để duy trì quy trình làm việc.
Syed Priom

1
Cảm ơn bạn đời. Tôi đã sử dụng lệnh này để buộc chi nhánh địa phương bị từ chối của tôi đến cùng một chi nhánh từ xa.
wei

11
sử dụng git push --force-with-leasesẽ an toàn hơn nhiều so với sử dụnggit push --force

git push --force-with-lease origin HEAD- giả sử chi nhánh mục tiêu của bạn đã được kiểm tra
Lucaci Sergiu

31

Điều chính cần ghi nhớ ở đây là những gì pull và rebase đang làm đằng sau hậu trường.

Một kéo về cơ bản sẽ làm hai việc: tìm nạp và hợp nhất. Khi bạn bao gồm --rebase, nó sẽ thực hiện rebase thay vì hợp nhất.

Một rebase khá giống như dập tắt tất cả các thay đổi cục bộ của bạn kể từ khi bạn phân nhánh, chuyển nhanh chi nhánh của bạn đến cam kết mới nhất trên mục tiêu và hủy bỏ các thay đổi của bạn theo thứ tự trên cùng.

(Điều này giải thích lý do tại sao bạn có thể nhận được nhiều lời nhắc giải quyết xung đột khi thực hiện rebase so với một giải quyết xung đột mà bạn có thể nhận được bằng cách hợp nhất. Bạn có cơ hội giải quyết xung đột trên MACHI cam kết đang bị từ chối để bảo vệ các cam kết của bạn. )

Bạn không bao giờ muốn đẩy các thay đổi được khởi động lại cho các chi nhánh từ xa vì đây là viết lại lịch sử. Thông thường, không bao giờ là một chút mạnh mẽ vì hầu như luôn có ngoại lệ. Ví dụ, trường hợp bạn cần duy trì một phiên bản từ xa của kho lưu trữ cục bộ để hoạt động trên một môi trường cụ thể.

Điều này sẽ yêu cầu bạn đẩy các thay đổi được khởi động lại vào các thời điểm bằng cách sử dụng vũ lực:

git push -f origin newfeature

Hoặc trong một số trường hợp, quản trị viên của bạn có thể đã xóa khả năng bắt buộc để bạn phải xóa và tạo lại:

git push origin :newfeature
git push origin newfeature

Trong cả hai trường hợp, bạn phải hoàn toàn chắc chắn rằng bạn biết những gì bạn đang làm nếu người khác đang cộng tác với bạn trên chi nhánh từ xa của bạn. Điều này có thể có nghĩa là ban đầu bạn làm việc với nhau bằng cách hợp nhất và chuyển đổi chúng thành định dạng cam kết dễ quản lý hơn ngay trước khi thành thạo và xóa chi nhánh làm việc của bạn.

Hãy nhớ rằng bạn hầu như luôn có thể dự phòng trên GC của git bằng cách tận dụng:

git reflog

Đây là một trình bảo vệ cuộc sống HUGE vì bạn có thể thiết lập lại trạng thái ổn định hơn nếu bạn bị lạc trong tất cả các quản lý xung đột / xung đột.


Tùy chọn xóa và tạo lại ở trên đã làm việc tốt cho tôi. Không cho phép trên repo của tôi!
Simon Holmes

2

Bạn cần thực hiện một động tác đẩy, tức là git push -f origin myNewFeature

Ồ, và tốt hơn hết là bạn nên chắc chắn rằng mọi người không dựa trên bất cứ điều gì trên nhánh nhà phát triển của bạn - thông thường bạn không cần phải xuất bản các chi nhánh nơi bạn đang viết lại lịch sử (hoặc không viết lại lịch sử một khi đã xuất bản). Một cách sẽ là sử dụng một tên chi nhánh như thế wip/myNewFeaturevà sau đó đề cập rằng wipcác chi nhánh sẽ được chuyển sang làm chủ theo thời gian.


sử dụng git push --force-with-leasesẽ an toàn hơn nhiều so với sử dụnggit push --force

@MrCholo Mọi người sẽ không bắt đầu sử dụng điều này cho đến khi git thêm một tùy chọn ngắn cho nó giống như -fmột cú đẩy cưỡng bức thông thường :)
ThiefMaster

ha yeah, tôi đã sử dụng nó trong một kịch bản tự động tho

2

Câu trả lời chung đã được đưa ra - để sử dụng git push -f origin myNewFeaturekhi đẩy các thay đổi bị từ chối - là một khởi đầu tốt. Tôi đang viết câu trả lời này để giải quyết việc chỉnh sửa về việc liệu nó có phá vỡ quy trình làm việc của bạn không.

Nếu chúng ta giả định rằng bạn sẽ được sử dụng git pull --rebase ...(hoặc một số biến thể trên đó) tiếp theo là một lực đẩy để các chi nhánh từ xa, thì điều đó phá vỡ các quy trình làm việc trong ví dụ của bạn được developer2 được sáp nhập myNewFeaturevào hisNewFeature. Thật có ý nghĩa khi có thể khởi động lại nhánh tính năng của riêng bạn miễn là không có ai khác làm việc trên nhánh đó, vì vậy bạn cần các quy tắc để phân định lãnh thổ chi nhánh.

Bạn có thể giải quyết vấn đề này bằng cách a) thiết lập một quy tắc mà bạn chỉ hợp nhất từ masterhoặc b) tạo ra một developnhánh tập thể , dựa vào đó bạn dựa vào myNewFeaturenhánh của riêng mình và thiết lập một quy tắc mà bạn chỉ hợp nhất từ ​​đó develop. mastersau đó sẽ chỉ được dành riêng cho các mốc hoặc bản phát hành (hoặc tuy nhiên bạn muốn thiết lập tính năng đó) và developsẽ là nơi bạn đẩy từng tính năng khi nó sẵn sàng được tích hợp vào các nhánh tính năng khác.

Tôi tin rằng đây có thể được coi là một phiên bản đơn giản hóa của quy trình Gitflow.


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.