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 topic
nhá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/master
có 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/master
sử dụng đến thời điểm tại các cam kết B3
, B2
, B1
và bây giờ nó chỉ vào B
, và bạn topic
chi 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 B3
làm điểm rẽ nhánh, để topic
có 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-base
lệ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 base
nhá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
base
nhá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 B3
và 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 B3
bằ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 Derived
và 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 B
nó không giống với B
;
C*
và D*
là bản vá giống hệt nhau C
và D
tương ứng và xung đột về văn bản nếu áp dụng sai thứ tự;
E
phụ thuộc vào văn bản D
.
Đúng kết quả của git rebase master dev
là B
được xác định là ngã ba-điểm dev
và master
, do đó C
, D
, E
là những cam kết mà cần phải được thực hiện lại vào master
; nhưng C
và D
là 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 B
mộ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 C
và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-point
sử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.