(Điều này bắt đầu như một câu trả lời cho một câu hỏi trùng lặp. Tôi đã thực hiện một chút chỉnh sửa ánh sáng để làm sạch nó.)
Tất cả các mũi tên bên trong của Git là một chiều, chỉ về phía sau. Do đó, không có cú pháp thuận tiện ngắn để di chuyển về phía trước: điều đó là không thể.
Đó là khả năng "động thái chống lại các mũi tên", nhưng cách để làm điều đó là ngạc nhiên nếu bạn chưa nhìn thấy nó trước đây, và sau đó hiển nhiên sau đó. Hãy nói rằng chúng ta có:
A <-B <-C <-D <-E <-- last
^
|
\--------- middle
Sử dụng middle~2
theo mũi tên hai lần từ C
trở lại A
. Vậy làm thế nào để chúng ta di chuyển từ C
đến D
? Câu trả lời là: chúng tôi bắt đầu E
, sử dụng tên last
và làm việc ngược lại cho đến khi chúng tôi đến middle
, ghi lại các điểm chúng tôi ghé thăm trên đường đi . Sau đó, chúng tôi chỉ cần di chuyển xa như chúng tôi muốn theo hướng last
: di chuyển một bước tới D
, hoặc hai đếnE
.
Điều này đặc biệt quan trọng khi chúng ta có các chi nhánh:
D--E <-- feature1
/
...--B--C <-- master
\
F--G <-- feature2
Cam kết nào là một bước sau C
? Không có câu trả lời đúng cho đến khi bạn thêm vào câu hỏi: theo hướng của tính năng ___ (điền vào chỗ trống).
Để liệt kê các cam kết giữa C
(không bao gồm C
) chính nó và, giả sử G
, chúng tôi sử dụng:
git rev-list --topo-order --ancestry-path master..feature2
Điều --topo-order
chắc chắn rằng ngay cả khi có sự phân nhánh và hợp nhất phức tạp, các cam kết được đưa ra theo thứ tự cấu trúc liên kết. Điều này chỉ được yêu cầu nếu chuỗi không tuyến tính. Các --ancestry-path
phương tiện hạn chế rằng khi chúng tôi làm việc ngược từ feature2
, chúng tôi chỉ danh sách cam kết có cam kết C
là một trong những tổ tiên của mình. Đó là, nếu đồ thị xếp hạng hay phần có liên quan của nó thì dù sao thì thực tế thì trông giống như thế này:
A--B--C <-- master
\ \
\ F--G--J <-- feature2
\ /
H-------I <-- feature3
một yêu cầu đơn giản của mẫu feature2..master
liệt kê các cam kết J
, G
và I
, F
và H
theo một số thứ tự. Với --ancestry-path
chúng tôi loại ra H
và I
: họ không phải là hậu duệ của C
, chỉ của A
. Với --topo-order
chúng tôi đảm bảo rằng thứ tự liệt kê thực tế là J
, sau đó G
, sau đóF
.
Các git rev-list
lệnh tràn các ID băm ra trên đầu ra tiêu chuẩn của nó, mỗi dòng một. Để tiến lên một bước theo hướng feature2
, sau đó, chúng tôi chỉ muốn cuối cùng dòng .
Có thể (và hấp dẫn và có thể hữu ích) để thêm vào --reverse
để git rev-list
in các cam kết theo thứ tự đảo ngược sau khi tạo chúng. Điều này không hoạt động, nhưng nếu bạn sử dụng nó trong một đường ống như thế này:
git rev-list --topo-order --ancestry-path --reverse <id1>...<id2> | head -1
để chỉ nhận "cam kết tiếp theo theo hướng id2" và có một danh sách các cam kết rất dài, git rev-list
lệnh có thể nhận được một đường ống bị hỏng khi nó cố gắng ghi vào head
đó đã ngừng đọc đầu vào và thoát. Do lỗi đường ống thường bị bỏ qua bởi vỏ, điều này chủ yếu hoạt động. Chỉ cần đảm bảo rằng chúng bị bỏ qua trong việc sử dụng của bạn .
Nó cũng hấp dẫn để thêm -n 1
vào git rev-list
lệnh, cùng với --reverse
. Đừng làm thế! Điều đó làm cho git rev-list
dừng lại sau khi đi một bước trở lại , và sau đó đảo ngược danh sách (một mục) các cam kết được truy cập. Vì vậy, điều này chỉ sản xuất <id2>
mỗi lần.
Lưu ý bên quan trọng
Lưu ý rằng với các mảnh đồ thị "kim cương" hoặc "vòng benzen":
I--J
/ \
...--H M--... <-- last
\ /
K--L
di chuyển một cam kết "chuyển tiếp" từ H
đối last
sẽ giúp bạn có một trong hai I
hoặc K
. Không có gì bạn có thể làm về điều đó: cả hai cam kết là một bước tiến! Nếu sau đó bạn bắt đầu từ cam kết kết quả và đi thêm một bước nữa, thì bây giờ bạn đã cam kết với bất kỳ con đường nào bạn đã bắt đầu.
Cách chữa trị cho điều này là tránh di chuyển từng bước một và bị khóa vào các chuỗi phụ thuộc vào đường dẫn. Thay vào đó, nếu bạn có kế hoạch đến thăm toàn bộ chuỗi đường dẫn tổ tiên, trước khi làm bất cứ điều gì khác , hãy tạo một danh sách đầy đủ tất cả các cam kết trong chuỗi:
git rev-list --topo-order --reverse --ancestry-path A..B > /tmp/list-of-commits
Sau đó, truy cập từng cam kết trong danh sách này, từng lần một và bạn sẽ nhận được toàn bộ chuỗi. Điều --topo-order
này sẽ đảm bảo bạn đạt được - I
và - J
theo thứ tự đó, và - K
và L
theo thứ tự đó (mặc dù không có cách nào dễ dàng để dự đoán liệu bạn sẽ thực hiện cặp IJ trước hay sau cặp KL).