Giả sử rằng kho lưu trữ từ xa có một bản sao của nhánh phát triển (mô tả ban đầu của bạn mô tả nó trong một kho lưu trữ cục bộ, nhưng có vẻ như nó cũng tồn tại trong điều khiển từ xa), bạn sẽ có thể đạt được những gì tôi nghĩ bạn muốn, nhưng cách tiếp cận là một chút khác biệt với những gì bạn đã hình dung.
Lịch sử của Git dựa trên DAG cam kết. Các chi nhánh (và các lượt giới thiệu khác nói chung) chỉ là các nhãn tạm thời chỉ ra các cam kết cụ thể trong DAG cam kết tăng trưởng liên tục. Như vậy, mối quan hệ giữa các nhánh có thể thay đổi theo thời gian, nhưng mối quan hệ giữa các cam kết thì không.
---o---1 foo
\
2---3---o bar
\
4
\
5---6 baz
Có vẻ như baz
là dựa trên (một phiên bản cũ) bar
? Nhưng nếu chúng ta xóa bar
thì sao?
---o---1 foo
\
2---3
\
4
\
5---6 baz
Bây giờ có vẻ như baz
là dựa trên foo
. Nhưng tổ tiên của baz
không thay đổi, chúng tôi chỉ xóa một nhãn (và kết quả là cam kết lơ lửng). Và nếu chúng ta thêm một nhãn mới tại 4
?
---o---1 foo
\
2---3
\
4 quux
\
5---6 baz
Bây giờ có vẻ như baz
là dựa trên quux
. Tuy nhiên, tổ tiên không thay đổi, chỉ có nhãn thay đổi.
Tuy nhiên, nếu chúng tôi hỏi rằng Cam có phải 6
là hậu duệ của cam kết 3
không? (giả sử 3
và 6
có đầy đủ tên cam kết SHA-1), thì câu trả lời sẽ là có đúng, có hay không bar
và có quux
nhãn hay không.
Vì vậy, bạn có thể đặt câu hỏi như là cam kết được đẩy ra là hậu duệ của đầu phát triển hiện tại của chi nhánh phát triển ? Nhưng, bạn không thể tin cậy hỏi rằng nhánh cha mẹ của cam kết bị đẩy là gì?
Một câu hỏi chủ yếu đáng tin cậy dường như gần với những gì bạn muốn là:
Đối với tất cả các tổ tiên của cam kết được đẩy (không bao gồm mẹo phát triển hiện tại và tổ tiên của nó), có mẹo phát triển hiện tại với tư cách là cha mẹ:
- có ít nhất một cam kết như vậy tồn tại?
- tất cả các cam kết như vậy cam kết cha mẹ đơn?
Mà có thể được thực hiện như:
pushedrev=...
basename=develop
if ! baserev="$(git rev-parse --verify refs/heads/"$basename" 2>/dev/null)"; then
echo "'$basename' is missing, call for help!"
exit 1
fi
parents_of_children_of_base="$(
git rev-list --pretty=tformat:%P "$pushedrev" --not "$baserev" |
grep -F "$baserev"
)"
case ",$parents_of_children_of_base" in
,) echo "must descend from tip of '$basename'"
exit 1 ;;
,*\ *) echo "must not merge tip of '$basename' (rebase instead)"
exit 1 ;;
,*) exit 0 ;;
esac
Điều này sẽ bao gồm một số những gì bạn muốn hạn chế, nhưng có thể không phải là tất cả.
Để tham khảo, đây là một lịch sử ví dụ mở rộng:
A master
\
\ o-----J
\ / \
\ | o---K---L
\ |/
C--------------D develop
\ |\
F---G---H | F'--G'--H'
| |\
| | o---o---o---N
\ \ \ \
\ \ o---o---P
\ \
R---S
Đoạn mã trên có thể được sử dụng để từ chối H
và S
khi chấp nhận H'
, J
, K
, hoặc N
, nhưng nó sẽ cũng chấp nhận L
và P
(họ liên quan đến sáp nhập, nhưng họ không hợp nhất là đỉnh của phát triển ).
Để từ chối L
và P
, bạn có thể thay đổi câu hỏi và hỏi
Đối với tất cả các tổ tiên của cam kết đẩy (không bao gồm mẹo phát triển hiện tại và tổ tiên của nó):
- Có bất kỳ cam kết với hai cha mẹ?
- nếu không, ít nhất một cam kết như vậy có mẹo phát triển (chỉ) cha mẹ hiện tại của nó không?
pushedrev=...
basename=develop
if ! baserev="$(git rev-parse --verify refs/heads/"$basename" 2>/dev/null)"; then
echo "'$basename' is missing, call for help!"
exit 1
fi
parents_of_commits_beyond_base="$(
git rev-list --pretty=tformat:%P "$pushedrev" --not "$baserev" |
grep -v '^commit '
)"
case "$parents_of_commits_beyond_base" in
*\ *) echo "must not push merge commits (rebase instead)"
exit 1 ;;
*"$baserev"*) exit 0 ;;
*) echo "must descend from tip of '$basename'"
exit 1 ;;
esac