[英]Will GitHub allow a merge or rebase of a “branch of another branch”?
[英]Don't allow branch to merge to another branch
我有一個分支,我想允許它從另一個分支合並。 但是我不允許它合並到另一個分支(例如Dev,master)。
感謝幫助
您將發現執行此操作的簡便方法。 我可以大致告訴您您需要做什么; 但是您必須克服一些重要的障礙,而對於那些您一個人來說,因為我沒有浪費足夠的時間來充分發展我認為是個糟糕主意的想法。
唯一可能的解決方案是設置git hook。 您可以在原始存儲庫上放置一個預接收鈎子,這樣,如果有人嘗試執行包含您不喜歡的合並的推送,則可以拒絕該推送。 (面臨的挑戰是確定您不喜歡的合並;我會再說一遍。)
當然,當有人推動時,他們可能需要重做很多工作。 因此,您的開發人員知道他們不能推送違反您的規則的引用,因此他們可能希望安裝與預提交掛鈎相同的腳本以避免錯誤。 (假設他們不只是認為不值得在具有這種約束的項目上工作。)
棘手的部分是如何檢測要執行的合並類型。 您的腳本將必須分析任何新的合並,以查看第一和第二父級。 因此,您可能首先說,如果合並的第二個(或后續)父級等於master
,則拒絕推送。 所以如果你有
x -- x -- A <--(master)
\
x -- x -- B <--(dev)
有人不能簡單地說
git checkout dev
git merge master
git push
因為您的腳本看到新合並提交的第二個孩子是A
,即master
。 所以他們不能推
x ----- x ---- A <--(master)
\ \
x -- x -- B -- M <--(dev)
但是在那種情況下,您可能也不想讓他們推動
x ----- x ---- A -- C <--(master)
\ \
x -- x -- B -- M <--(dev)
如果這只鈎子看着master
,他們可以說
git checkout master
# stage some changes, or make the following commit with the allow-empty flag
git commit
git push
git checkout dev
git merge master^
git push
開發人員必須竭盡全力將master合並到dev,但是仍然可以做到。 而且由於您顯然希望將此規則作為一條規則,這意味着即使您沒有看到,開發人員也可以看到這些合並的價值,因此可以預期您將需要更嚴格地執行該規則。 因此,您的腳本實際上需要查找可以從 master
到達其第二(或后續)父級的任何合並。
因此,您可以使用git rev-list
來構建無法合並的修訂列表,並檢查每個新的合並,以查找第二個(或后續)父級包含在該列表中。
但這可能會帶來一些意想不到的后果。 如果有的話
x -- x -- x -- M -- x <--(master)
\ \ /
\ x --- A <--(hotfix)
\
x -- x -- B <--(dev)
您可能應該允許將該修補程序合並到dev中,但是在此圖中,可以從master
該修補程序。 (您可能需要先合並此修補程序才能進行dev
, 然后再進行master
,但充其量是與人們可能做的事情相反的另一個任意約束。)
因此,也許當您使用rev-list
構建禁止合並目標的列表時,您會為其指定first-parent
參數。 這開始變得很難推理,因此目前尚不清楚它是否可以防彈,但我想它正在接近。
除了下一件事,如果有人使用reset
來移動master
ref,那么在推送時您不能說出他們正在合並的內容實際上是來自master
分支怎么辦? 您要禁止所有強制執行操作嗎? (公平地說,應該謹慎使用推力。這一限制可能迫使開發人員考慮按常規使用它的工作流程,這是一個不好的主意。但是完全消除強制推力可能效果不佳。 )
哦,您的存儲庫越大( master
的歷史越深),您的鈎子將變得越來越耗費資源(減慢push
操作)。 我想你可以設置提交的最大數量的master
來看待,這樣的假設沒有人會回去太遠尋找歷史的允許段從合並master
。 但這是腳本的另一種復雜性,可能會導致其變得過時。
所有這些的重點是,您可以花費大量的精力來控制您的開發人員,也可以設置人們一致認可的團隊實踐,因為他們是優秀的開發人員。
您可以通過將此答案調整為本地的pre-push
掛鈎來接近解決方案(在這種情況下,所有開發人員都需要安裝掛鈎,因此您也可以考慮編寫一個腳本,使您可以將掛鈎保留在存儲庫中)使它更容易為你的開發者安裝), 或者您也可以重新配制溶液倒入pre-receive
的起源掛鈎,更多的嚴格執行。
這個想法是使用標記來標識一個長期的“不良”提交(標記“不良”分支上的第一次提交),該提交永遠都不應被合並到您的干凈分支中,然后該鈎子查看git merge-base
您要推送的ref和“壞”標簽之間的git merge-base
,如果它們一致,則拒絕推送。
這是我對該答案的改編,可用作pre-push
鈎。 它包括一些邏輯,該邏輯允許應包含錯誤提交的分支被推送,並且不打擾檢查推送標簽和其他非分支引用。
#!/bin/bash
#
# This prevents a push to the named remote if the push has any "forbidden"
# commits (indicated by a tag matching the forbidden_pat variable) as any
# ancestors. It prevents a known-bad branch from having its history
# intermingled with other branches.
#
# Adapted from http://stackoverflow.com/a/13384768
# which remote should we protect?
protected_remote="origin"
# which branch should allow forbidden commits?
skip_branch_regex='^test[1-3]$'
# what do our forbidden tags look like?
forbidden_pat="forbidden/*"
# only check if this is the remote we care about
if [ "$1" != "$protected_remote" ]; then
exit 0
fi
# we might be trying to push multiple branches (e.g. push.default = matching).
# See http://git-scm.com/docs/githooks#_pre_push for the format
while read line
do
words=($line)
branch="${words[0]##refs/heads/}"
ref="${words[1]}"
# don't proceed if this is not a branch (IOW, if our substitution didn't
# change anything; we only want to check pushing branch pointers, not tags or
# other refs
if [ "$branch" = "${words[0]}" ]; then
continue
fi
# don't proceed if we're trying to push a branch that can receive the bad
# commit
if [[ "$branch" =~ $skip_branch_regex ]]; then
continue
fi
# check each forbidden tag to see if it's an ancestor of the ref we're
# trying to push; reject if it is.
for forbidden in $(git tag -l "$forbidden_pat"); do
if [ $(git merge-base "$forbidden" "$ref") = $(git rev-parse "$forbidden") ]; then
echo "Push to $branch contains BAD commit $forbidden." >&2
exit 1
fi
done
done
exit 0
在多開發人員環境中,這已經可以令人滿意地工作了。
綜上所述 ,我同意Mark Adelsberger的回答,即這不是要以編程方式解決的問題,而是應該以其他方式(培訓,自動化測試,簡化的分支工作流程等)解決的問題。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.