Gitブランチの最も近い親を見つける方法 質問する

Gitブランチの最も近い親を見つける方法 質問する

次のようなコミット ツリーを持つローカル リポジトリがあるとします。

master --> a
            \
             \
      develop c --> d
               \
                \
         feature f --> g --> h

masterこれは私の最新の安定したリリース コードであり、これはdevelop私の「次の」リリース コードでありは に向けて準備中の新機能featureです。develop

フックを使用して、コミットが HEADの直接の子孫でfeatureない限り、リモート リポジトリへのプッシュを拒否できるようにしたいと考えています。つまり、機能がオンになっているため、コミット ツリーは次のようになります。fdevelopgit rebased

master --> a
            \
             \
      develop c --> d
                     \
                      \
               feature f --> g --> h

それで、次のことが可能になります:

  • feature?の親ブランチを識別します。
  • 親ブランチ内のどのコミットfの子孫であるかを識別しますか?

そこから、親ブランチの HEAD が何であるかを確認し、f先行ブランチが親ブランチの HEAD と一致するかどうかを確認して、機能をリベースする必要があるかどうかを判断します。

ベストアンサー1

リモート リポジトリに開発ブランチのコピーがあると仮定すると(最初の説明ではローカル リポジトリにあると説明されていますが、リモートにも存在するようです)、必要なことは達成できるはずですが、アプローチは想定したものとは少し異なります。

Gitの履歴はダグコミット。ブランチ (および一般的な「ref」) は、継続的に拡大するコミット 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ただし、「 commit はcommit の子孫であるか3?」と尋ねている場合(および3が完全な SHA-1 コミット名であると想定)、およびラベルが存在するかどうか6に関係なく、答えは「はい」になります。barquux

したがって、「プッシュされたコミットは、 developブランチの現在の先端の子孫ですか?」などの質問をすることはできますが、「プッシュされたコミットの親ブランチは何ですか?」という質問を確実に行うことはできません。

あなたが望むことに近そうな、最も信頼できる質問は次のとおりです。

プッシュされたコミットのすべての祖先( developの現在の先端とその祖先を除く)のうち、 developの現在の先端を親として持つもの:

  • そのようなコミットが少なくとも 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を拒否するために使用できますが、およびも受け入れます(これらはマージを伴いますが、 developの先端はマージしません)。SH'JKNLP

と も拒否するにはLP質問を変更して尋ねます。

プッシュされたコミットのすべての祖先( developの現在の先端とその祖先を除く)について:

  • 2 つの親を持つコミットはありますか?
  • そうでない場合、少なくとも 1 つのそのようなコミットに、その (唯一の) 親であるdevelopmentの現在のヒントがありますか?
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

おすすめ記事