リモートリポジトリに開発ブランチのコピーがあると仮定すると(最初の説明ではローカルリポジトリに記述されていますが、リモートにも存在するようです)、私が望むことを実現できるはずですが、アプローチあなたが想像していたものとは少し異なります。
Gitの履歴は、コミットのDAGに基づいています。ブランチ(および一般に「参照」)は、継続的に成長するコミットDAGの特定のコミットを指す一時的なラベルにすぎません。そのため、ブランチ間の関係は時間とともに変化する可能性がありますが、コミット間の関係は変化しません。
---o---1 foo
\
2---3---o bar
\
4
\
5---6 baz
baz
(の古いバージョン)に基づいているように見えbar
ますか?しかし、削除するとbar
どうなるでしょうか。
---o---1 foo
\
2---3
\
4
\
5---6 baz
今でbaz
はに基づいてfoo
いるように見えます。しかし、の祖先はbaz
変更されず、ラベル(および結果のぶら下がりコミット)を削除しただけです。そして、新しいラベルをに追加するとどうなり4
ますか?
---o---1 foo
\
2---3
\
4 quux
\
5---6 baz
今でbaz
はに基づいてquux
いるように見えます。それでも、祖先は変更されず、ラベルのみが変更されました。
しかし、「コミットはコミット6
の子孫3
ですか?」(3
および6
が完全なSHA-1コミット名であると想定)、bar
およびquux
ラベルが存在するかどうかに関係なく、答えは「はい」になります。
したがって、「プッシュされたコミットは開発ブランチの現在の先端の子孫ですか?」のような質問をすることができますが、「プッシュされたコミットの親ブランチは何ですか?」
あなたが望むものに近づくように思われる最も信頼できる質問は:
プッシュされたコミットのすべての祖先(開発の現在のヒントとその祖先を除く)について、現在の開発のヒントを親として持っています。
- そのようなコミットが少なくとも1つ存在しますか?
- そのようなコミットはすべて単一親コミットですか?
これは次のように実装できます。
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
これは、制限したいものの一部をカバーしますが、すべてではありません。
参考までに、ここに拡張された例の履歴を示します。
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
上記のコードは拒絶するために使用することができH
かつS
受け入れながらH'
、J
、K
、またはN
、それはまた、受け入れるだろうL
とP
(彼らはマージを伴うが、彼らはの先端マージしていない開発を)。
また、拒否することL
とP
、あなたが質問を変更して求めることができます
プッシュされたコミットのすべての祖先(開発の現在のヒントとその祖先を除く):
- 2人の親とのコミットはありますか?
- そうでない場合、少なくとも1つのそのようなコミットには、その(唯一の)親を開発するという現在のヒントがありますか?
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