Bắt đầu với git 1.9 / 2.0 Q1 2014, bạn sẽ không phải đánh dấu nguồn gốc nhánh trước của mình trước khi khôi phục nó trên nhánh ngược dòng được viết lại, như được mô tả trong câu trả lời của Aristotle Pagaltzis :
Xem commit 07d406b và commit d96855f :
Sau khi làm việc với topicnhánh được tạo bằng git checkout -b topic origin/master, lịch sử của nhánh theo dõi từ xa origin/mastercó thể đã được viết lại và xây dựng lại, dẫn đến lịch sử của hình dạng này:
o---B1
/
---o---o---B2--o---o---o---B (origin/master)
\
B3
\
Derived (topic)
nơi origin/mastersử dụng đến thời điểm tại các cam kết B3, B2, B1và bây giờ nó chỉ vào B, và bạn topicchi nhánh đã bắt đầu trên đầu trang của nó sao khi origin/masterđang ở B3.
Chế độ này sử dụng bản ghi lại của origin/masterđể tìm B3làm điểm rẽ nhánh, để topiccó thể khôi phục lại trên đầu bản cập nhậtorigin/master bằng cách:
$ fork_point=$(git merge-base --fork-point origin/master topic)
$ git rebase --onto origin/master $fork_point topic
Đó là lý do tại sao git merge-baselệnh có một tùy chọn mới:
--fork-point::
Tìm điểm mà tại đó một nhánh (hoặc bất kỳ lịch sử nào dẫn đến <commit>) được tách từ một nhánh khác (hoặc bất kỳ tham chiếu nào) <ref>.
Điều này không chỉ tìm kiếm tổ tiên chung của hai cam kết, mà còn tính đến bản tóm tắt của <ref>để xem liệu lịch sử dẫn đến phân <commit>nhánh từ một hậu thân trước đó của nhánh hay không<ref> .
Lệnh " git pull --rebase" tính toán điểm rẽ nhánh của nhánh đang được phục hồi bằng cách sử dụng các mục nhập reflog của basenhánh "" (thường là nhánh theo dõi từ xa) mà công việc của nhánh dựa vào, để đối phó với trường hợp "cơ sở" chi nhánh đã được quấn lại và xây dựng lại.
Ví dụ: nếu lịch sử trông giống như nơi:
- đầu hiện tại của
basenhánh "" đang ở B, nhưng lần tìm nạp trước đó đã quan sát thấy rằng đầu của nó đã từng như vậy B3và sau B2đó B1
trước khi đến cam kết hiện tại và
- nhánh được phục hồi trên đầu "cơ sở" mới nhất dựa trên cam kết
B3,
nó cố gắng tìm B3bằng cách đi qua đầu ra của " git rev-list --reflog base" (có nghĩa là B, B1, B2, B3) cho đến khi nó tìm thấy một cam kết rằng là tổ tiên của mũi hiện tại " Derived (topic)".
Trong nội bộ, chúng tôi có get_merge_bases_many()thể tính toán điều này bằng một lần thực hiện.
Chúng tôi muốn có một cơ sở hợp nhất giữa Derivedvà một cam kết hợp nhất hư cấu sẽ dẫn đến việc hợp nhất tất cả các mẹo lịch sử của " base (origin/master)".
Khi một cam kết như vậy tồn tại, chúng ta sẽ nhận được một kết quả duy nhất, kết quả này khớp chính xác với một trong các mục nhập reflog của " base".
Git 2.1 (Quý 3 năm 2014) sẽ thêm vào làm cho tính năng này trở nên mạnh mẽ hơn: xem cam kết 1e0dacd của John Giữ ( johnkeeping)
xử lý chính xác tình huống mà chúng tôi có cấu trúc liên kết sau:
C --- D --- E <- dev
/
B <- master@{1}
/
o --- B' --- C* --- D* <- master
Ở đâu:
B'là một phiên bản cố định của Bnó không giống với B;
C*và D*là bản vá giống hệt nhau Cvà Dtương ứng và xung đột về văn bản nếu áp dụng sai thứ tự;
Ephụ thuộc vào văn bản D.
Đúng kết quả của git rebase master devlà Bđược xác định là ngã ba-điểm devvà master, do đó C, D, Elà những cam kết mà cần phải được thực hiện lại vào master; nhưng Cvà Dlà bản vá giống hệt với C*và D*và vì vậy có thể bị loại bỏ, để kết quả cuối cùng là:
o --- B' --- C* --- D* --- E <- dev
Nếu điểm rẽ nhánh không được xác định, thì việc chọn Bmột nhánh có chứa B'dẫn đến xung đột và nếu các cam kết giống hệt bản vá không được xác định chính xác thì việc chọn Cvào một nhánh chứa D(hoặc tương đương D*) dẫn đến xung đột.
Các " --fork-point" phương thức " git rebase" thụt lùi khi lệnh được viết lại bằng C trở lại trong 2.20 thời đại, mà đã được sửa chữa với Git 2,27 (Q2 2020).
Xem cam kết f08132f ( 09/12/2019 ) của Junio C Hamano ( gitster) .
(Hợp nhất bởi Junio C Hamano - gitster- trong cam kết fb4175b , ngày 27 tháng 3 năm 2020)
rebase: --fork-pointsửa chữa hồi quy
Người ký hợp đồng: Alex Torok
[jc: sửa đổi bản sửa lỗi và sử dụng các bài kiểm tra của Alex]
Người ký hợp đồng: Junio C Hamano
" git rebase --fork-point master" được sử dụng để hoạt động OK, vì nó được gọi trong nội bộ " git merge-base --fork-point" biết cách xử lý tên đổi tên ngắn và chuyển nó thành tên đổi tên đầy đủ trước khi gọi get_fork_point()hàm cơ bản .
Điều này không còn đúng nữa sau khi lệnh được viết lại trong C, vì lệnh internall của nó được thực hiện trực tiếp để get_fork_point()không tạo ra một tham chiếu ngắn.
Di chuyển logic "dwim the refname refname to the full refname" được sử dụng trong "git merge-base" vào get_fork_point()hàm cơ bản để người gọi hàm khác trong quá trình triển khai "git rebase" hoạt động theo cách tương tự để khắc phục hồi quy này.