Git 2.18 (quý 2 năm 2018) sẽ cải thiện đáng kể --preserve-merge
tùy chọn bằng cách thêm tùy chọn mới.
" git rebase
" Đã học " --rebase-merges
" để ghép toàn bộ cấu trúc liên kết của đồ thị cam kết ở nơi khác .
(Lưu ý: Git 2.22, Q2 2019, thực sự không dùng nữa --preserve-merge
và Git 2.25, Q1 2020, ngừng quảng cáo nó trong git rebase --help
đầu ra "" )
Xem cam kết 25cff9f , cam kết 7543f6f , cam kết 1131ec9 , cam kết 7ccdf65 , cam kết 537e7d6 , cam kết a9be29c , cam kết 8f6aed7 , cam kết 1644c73 , cam kết d1e8b01 , cam kết 4c68e7d , cam kết 9055e40 , cam kết cb5206e , cam kết a01c2a5 , cam kết 2f6b1d1 , cam kết bf5c057 (ngày 25 tháng 4 năm 2018) của tác giả Julian Schindelin ( dscho
) .
Xem cam kết f431d73 (25 tháng 4 năm 2018) của Stefan Beller ( stefanbeller
) .
Xem cam kết 2429335 (25 tháng 4 năm 2018) của Phillip Wood ( phillipwood
) .
(Được hợp nhất bởi Junio C Hamano - gitster
- trong cam kết 2c18e6a , ngày 23 tháng 5 năm 2018)
pull
: chấp nhận --rebase-merges
để tạo lại cấu trúc liên kết chi nhánh
Tương tự như preserve
chế độ chỉ đơn giản là truyền --preserve-merges
tùy chọn cho rebase
lệnh, merges
chế độ chỉ đơn giản là chuyển
--rebase-merges
tùy chọn.
Điều này sẽ cho phép người dùng thuận tiện khởi động lại các cấu trúc liên kết cam kết không tầm thường khi kéo các xác nhận mới, mà không làm phẳng chúng.
git rebase
trang man bây giờ có một phần đầy đủ dành riêng cho lịch sử nổi loạn với sự hợp nhất .
Trích xuất:
Có nhiều lý do chính đáng tại sao nhà phát triển có thể muốn tạo lại các cam kết hợp nhất: để giữ cấu trúc nhánh (hoặc "cấu trúc liên kết cam kết") khi làm việc trên nhiều nhánh liên quan đến nhau.
Trong ví dụ sau, nhà phát triển làm việc trên nhánh chủ đề tái cấu trúc các nút được xác định và trên nhánh chủ đề khác sử dụng phép tái cấu trúc đó để thực hiện nút "Báo cáo lỗi".
Đầu ra của git log --graph --format=%s -5
có thể trông như thế này:
* Merge branch 'report-a-bug'
|\
| * Add the feedback button
* | Merge branch 'refactor-button'
|\ \
| |/
| * Use the Button class for all buttons
| * Extract a generic Button class from the DownloadButton one
Nhà phát triển có thể muốn khởi động lại các cam kết đó thành mới hơn master
trong khi vẫn giữ cấu trúc liên kết nhánh, ví dụ như khi nhánh chủ đề đầu tiên được dự kiến sẽ được tích hợp vào master
sớm hơn nhiều so với thứ hai, để giải quyết xung đột hợp nhất với các thay đổi đối với
DownloadButton
lớp đã tạo nó vào master
.
Rebase này có thể được thực hiện bằng cách sử dụng --rebase-merges
tùy chọn.
Xem cam kết 1644c73 cho một ví dụ nhỏ:
rebase-helper
--make-script
: giới thiệu một lá cờ để hợp nhất rebase
Trình sắp xếp thứ tự chỉ học các lệnh mới nhằm tái tạo cấu trúc nhánh ( tương tự về tinh thần --preserve-merges
, nhưng với thiết kế ít bị phá vỡ hơn ).
Hãy cho phép rebase--helper
tạo danh sách việc cần làm bằng cách sử dụng các lệnh này, được kích hoạt bởi --rebase-merges
tùy chọn mới .
Đối với một cấu trúc liên kết cam kết như thế này (trong đó CHÍNH chỉ đến C):
- A - B - C (HEAD)
\ /
D
danh sách việc cần làm sẽ như thế này:
# branch D
pick 0123 A
label branch-point
pick 1234 D
label D
reset branch-point
pick 2345 B
merge -C 3456 D # C
Sự khác biệt với là --preserve-merge
gì?
Cam kết 8f6aed7 giải thích:
Ngày xửa ngày xưa, nhà phát triển ở đây nghĩ rằng: sẽ không hay nếu nói, các bản vá Git cho Windows trên lõi Git có thể được biểu diễn dưới dạng một nhánh dày và được đặt lại trên đỉnh Git để duy trì một bộ vá có thể chọn anh đào?
Nỗ lực ban đầu để trả lời điều này là : git rebase --preserve-merges
.
Tuy nhiên, thí nghiệm đó không bao giờ được dự định là một tùy chọn tương tác và nó chỉ được hỗ trợ git rebase --interactive
bởi vì việc triển khai lệnh đó trông rất, rất quen thuộc: nó được thiết kế bởi cùng một người đã thiết kế --preserve-merges
: thật sự của bạn.
Và bởi "của bạn thật sự", tác giả đề cập đến chính mình: Johannes Schindelin ( dscho
) , người là lý do chính (với một vài anh hùng khác - Hannes, Steffen, Sebastian, ...) rằng chúng tôi có Git For Windows (mặc dù trở lại trong ngày - 2009 - điều đó không dễ dàng ).
Anh ấy làm việc tại Microsoft từ tháng 9 năm 2015 , điều này hợp lý khi xem xét Microsoft hiện đang sử dụng rất nhiều Git và cần các dịch vụ của anh ấy. Xu hướng
đó thực sự bắt đầu vào năm 2013, với TFS . Kể từ đó, Microsoft quản lý kho Git lớn nhất hành tinh ! Và, kể từ tháng 10 năm 2018, Microsoft đã mua lại GitHub .
Bạn có thể thấy Johannes phát biểu trong video này cho Git Merge 2018 vào tháng 4 năm 2018.
Một thời gian sau, một số nhà phát triển khác (tôi đang nhìn bạn, Andreas! ;-)) đã quyết định rằng sẽ là một ý tưởng tốt khi cho phép --preserve-merges
kết hợp với --interactive
(với sự cẩn thận!) Và người duy trì Git (tốt, người duy trì Git tạm thời trong thời gian Junio vắng mặt, điều đó đã được đồng ý, và đó là khi sự quyến rũ của --preserve-merges
thiết kế bắt đầu tan rã khá nhanh chóng và vô duyên.
Ở đây Jonathan đang nói về Andreas Schwab từ Suse.
Bạn có thể thấy một số cuộc thảo luận của họ trở lại vào năm 2012 .
Nguyên nhân? Trong --preserve-merges
chế độ, cha mẹ của một cam kết hợp nhất (hoặc cho vấn đề đó, của bất kỳ cam kết nào ) không được nêu rõ ràng, nhưng được
ngụ ý bởi tên cam kết được truyền cho pick
lệnh .
Điều này làm cho nó không thể, ví dụ, để sắp xếp lại các cam kết .
Không đề cập đến việc di chuyển các cam kết giữa các nhánh hoặc, thần cấm, để chia các nhánh chủ đề thành hai.
Than ôi, những thiếu sót này cũng ngăn cản chế độ đó (với mục đích ban đầu là phục vụ nhu cầu của Git cho Windows, với hy vọng bổ sung rằng nó cũng có thể hữu ích cho những người khác) để phục vụ nhu cầu của Git cho Windows.
Năm năm sau, khi nó trở nên thực sự không thể có được một loạt các bản vá lỗi lớn, khó sử dụng của các bản vá liên quan một phần, không liên quan một phần trong Git cho Windows, đôi khi đã bị từ chối bởi các thẻ Git cốt lõi (gây ra sự phẫn nộ không đáng có của nhà phát triển của git-remote-hg
loạt game xấu số
mà cách tiếp cận cạnh tranh của Git đối với Windows, chỉ bị bỏ rơi mà không có người bảo trì sau đó) thực sự không thể thực hiện được, " kéo cắt vườn Git " đã ra : một kịch bản, ủng hộ heo trên đỉnh của cuộc nổi loạn tương tác, đầu tiên sẽ xác định cấu trúc liên kết nhánh của các bản vá được khởi tạo lại, tạo một danh sách giả cần làm để chỉnh sửa thêm, chuyển đổi kết quả thành một danh sách việc cần làm thực sự (sử dụng rất nhiềuexec
lệnh "thực hiện" các lệnh danh sách việc cần làm bị thiếu) và cuối cùng tạo lại chuỗi bản vá trên đầu trang của cam kết cơ sở mới.
(Kịch bản kéo cắt vườn Git được tham chiếu trong bản vá này trong cam kết 9055e40 )
Đó là vào năm 2013.
Và phải mất khoảng ba tuần để đưa ra thiết kế và thực hiện nó như một kịch bản ngoài luồng. Không cần phải nói, việc thực hiện cần một vài năm để ổn định, tất cả trong khi bản thân thiết kế đã chứng minh âm thanh của nó.
Với bản vá này, sự tốt đẹp của kéo cắt vườn Git git
rebase -i
tự nó đến .
Vượt qua --rebase-merges
tùy chọn sẽ tạo ra một danh sách việc cần làm có thể hiểu được một cách dễ dàng và rõ ràng làm thế nào để sắp xếp lại các cam kết .
Các nhánh mới có thể được giới thiệu bằng cách chèn label
lệnh và gọi merge <label>
.
Và một khi chế độ này sẽ trở nên ổn định và được chấp nhận rộng rãi, chúng ta có thể loại bỏ lỗi thiết kế đó--preserve-merges
.
Git 2.19 (Q3 2018) cải thiện --rebase-merges
tùy chọn mới bằng cách làm cho nó hoạt động với --exec
.
Các " --exec
" tùy chọn " git rebase --rebase-merges
" đặt các lệnh exec tại địa điểm sai, đã được sửa chữa.
Xem cam kết 1ace63b (ngày 09 tháng 8 năm 2018) và cam kết f0880f7 (ngày 06 tháng 8 năm 2018) của tác giả Julian Schindelin ( dscho
) .
(Được hợp nhất bởi Junio C Hamano - gitster
- trong cam kết 750eb11 , ngày 20 tháng 8 năm 2018)
rebase --exec
: làm cho nó hoạt động với --rebase-merges
Ý tưởng --exec
là nối thêm một exec
cuộc gọi sau mỗi cuộc gọi pick
.
Kể từ khi giới thiệu fixup!
/ s quash!
cam kết, ý tưởng này đã được mở rộng để áp dụng cho "pick, có thể theo sau là chuỗi sửa lỗi / squash", tức là một exec sẽ không được chèn giữa a pick
và bất kỳ dòng fixup
hoặc tương ứng nào của nó
squash
.
Việc triển khai hiện tại sử dụng một mánh khóe bẩn thỉu để đạt được điều đó: nó giả định rằng chỉ có các lệnh pick / fixup / squash, sau đó
chèn các exec
dòng trước bất kỳ pick
ngoại trừ đầu tiên và nối thêm một lệnh cuối cùng.
Với danh sách todo tạo ra bởi git rebase --rebase-merges
, đây đơn giản chương trình thực hiện vấn đề của nó: nó tạo ra chính xác những điều sai khi có label
, reset
và merge
lệnh.
Hãy thay đổi cách thực hiện để thực hiện chính xác những gì chúng ta muốn: tìm kiếm các
pick
dòng, bỏ qua bất kỳ chuỗi sửa lỗi / squash nào, sau đó chèn exec
dòng . Lót, rửa sạch, lặp lại.
Lưu ý: chúng tôi chịu khó chèn trước các dòng bình luận bất cứ khi nào có thể, vì các cam kết trống được thể hiện bằng các dòng chọn nhận xét (và chúng tôi muốn chèn một dòng exec của pick trước trước một dòng như vậy, không phải sau đó).
Trong khi ở đó, cũng thêm exec
các dòng sau merge
các lệnh, bởi vì chúng giống nhau về tinh thần với pick
các lệnh: chúng thêm các xác nhận mới.
Git 2.22 (Q2 2019) sửa lỗi sử dụng refs / viết lại / phân cấp để lưu trữ trạng thái trung gian rebase, vốn đã tạo ra hệ thống phân cấp cho mỗi worktree.
Xem cam kết b9317d5 , cam kết 90d31ff , cam kết 09e6564 (07 tháng 3 năm 2019) của Nguyễn Thái Ngọc Duy ( pclouds
) .
(Được hợp nhất bởi Junio C Hamano - gitster
- trong cam kết 917f2cd , ngày 09 tháng 4 năm 2019)
Hãy chắc chắn rằng refs / viết lại / là trên mỗi worktree
a9be29c (sequencer: tạo các ref được tạo bởi label
lệnh worktree-local, 2018-04-25, Git 2.19) thêm vào refs/rewritten/
dưới dạng không gian tham chiếu trên mỗi worktree.
Thật không may (xấu của tôi) có một vài nơi cần cập nhật để đảm bảo rằng đó thực sự là một công việc.
- add_per_worktree_entries_to_dir()
được cập nhật để đảm bảo danh sách giới thiệu nhìn vào per-worktree refs/rewritten/
thay vì per-repo.
common_list[]
được cập nhật để git_path()
trả về vị trí chính xác. Điều này bao gồm " rev-parse --git-path
".
Mớ hỗn độn này được tạo ra bởi tôi.
Tôi bắt đầu cố gắng khắc phục nó bằng việc giới thiệu refs/worktree,
nơi tất cả các ref sẽ là per-worktree mà không cần các phương pháp điều trị đặc biệt.
Refs không may / viết lại đã đến trước refs / worktree vì vậy đây là tất cả những gì chúng ta có thể làm.
Với Git 2.24 (Q4 2019), " git rebase --rebase-merges
" đã học cách điều khiển các chiến lược hợp nhất khác nhau và chuyển các tùy chọn cụ thể cho chiến lược cho chúng.
Xem cam kết 476998d (04 tháng 9 năm 2019) của Elijah Newren ( newren
) .
Xem cam kết e1fac53 , cam kết a63f990 , cam kết 5dcdd74 , cam kết e145d99 , cam kết 4e6023b , cam kết f67336d , cam kết a9c7107 , cam kết b8c6f24 , cam kết d51b771 , cam kết c248d32 , cam kết 8c1e240 , cam kết 5efed0e , cam kết 68b54f6 , cam kết 2e7bbac , cam kết 6180b20 , cam kết d5b581f (31 Tháng 7 năm 2019) bởiJulian Schindelin ( dscho
) .
(Được hợp nhất bởi Junio C Hamano - gitster
- trong cam kết 917a319 , ngày 18 tháng 9 năm 2019)
Với Git 2.25 (Q1 2020), logic được sử dụng để phân biệt các giới thiệu toàn cầu của kho lưu trữ cục bộ và kho lưu trữ được cố định, để tạo điều kiện thuận lợi cho việc hợp nhất bảo toàn.
Xem cam kết f45f88b , cam kết c72fc40 , cam kết 8a64881 , cam kết 7cb8c92 , cam kết e536b1f (ngày 21 tháng 10 năm 2019) bởi SZEDER Gábor ( szeder
) .
(Được hợp nhất bởi Junio C Hamano - gitster
- trong cam kết db806d7 , ngày 10 tháng 11 năm 2019)
path.c
: không gọi match
hàm không có giá trị trongtrie_find()
Đã ký tắt: SZEDER Gábor
'Nhật ký / refs' không phải là đường dẫn dành riêng cho cây hoạt động, nhưng vì cam kết b9317d55a3 (Đảm bảo refs / viết lại / là per-worktree, 2019-03-07, v2.22.0-rc0) ' git rev-parse --git-path
' đã trở lại đường dẫn không có thật nếu có dấu ' /
':
$ git -C WT/ rev-parse --git-path logs/refs --git-path logs/refs/
/home/szeder/src/git/.git/logs/refs
/home/szeder/src/git/.git/worktrees/WT/logs/refs/
Chúng tôi sử dụng trie
cấu trúc dữ liệu để quyết định một cách hiệu quả liệu một đường dẫn thuộc về thư mục chung hay là làm việc cụ thể theo cây.
Khi nó xảy ra, b9317d55a3 đã kích hoạt một lỗi cũ như trie
bản thân việc triển khai, được thêm vào 4e09cf2acf (" path
: tối ưu hóa kiểm tra thư mục chung", 2015-08-31, Git v2.7.0-rc0 - hợp nhất được liệt kê trong lô # 2 ).
Theo nhận xét mô tả trie_find()
, nó chỉ nên gọi hàm so khớp đã cho là 'fn' cho tiền tố kết thúc "/ -or- \ 0 của khóa mà bộ ba chứa giá trị".
Điều này không đúng: có ba nơi trie_find () gọi hàm so khớp, nhưng một trong số đó thiếu kiểm tra sự tồn tại của giá trị.
b9317d55a3 đã thêm hai khóa mới vào trie
:
- '
logs/refs/rewritten
' và
- '
logs/refs/worktree
', bên cạnh đã tồn tại ' logs/refs/bisect
'.
Điều này dẫn đến một trie
nút có đường dẫn ' logs/refs/
', không tồn tại trước đó và không có giá trị kèm theo.
Một truy vấn cho ' logs/refs/
' tìm thấy nút này và sau đó nhấn vào một điểm gọi của match
hàm không kiểm tra sự tồn tại của giá trị và do đó gọi match
hàm với NULL
giá trị.
Khi match
hàm check_common()
được gọi với một NULL
giá trị, nó trả về 0, cho biết đường dẫn được truy vấn không thuộc về thư mục chung, cuối cùng dẫn đến đường dẫn không có thật được hiển thị ở trên.
Thêm điều kiện còn thiếu để trie_find()
nó sẽ không bao giờ gọi hàm so khớp với giá trị không tồn tại.
check_common()
sau đó sẽ không còn phải kiểm tra xem nó có giá trị không phải là NULL hay không, vì vậy hãy loại bỏ điều kiện đó.
Tôi tin rằng không có con đường nào khác có thể gây ra đầu ra không có thật tương tự.
AFAICT chỉ có khóa khác dẫn đến chức năng khớp được gọi với NULL
giá trị là ' co
' (vì các phím ' common
' và ' config
').
Tuy nhiên, vì chúng không nằm trong một thư mục thuộc về thư mục chung, nên sẽ có đường dẫn cụ thể cho cây làm việc.
git --rebase-merges
cuối cùng sẽ thay thế cái cũgit --preserve-merges
. Xem câu trả lời của tôi dưới đây