원격 저장소에 개발 브랜치 의 사본이 있다고 가정하면 (초기 설명에서 로컬 저장소에 설명하지만 원격에도 존재하는 것처럼 들린다) 원하는 생각을 얻을 수 있지만 접근 방식은 당신이 상상 한 것과는 조금 다릅니다.
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
라벨이 존재하거나하지 않습니다.
따라서 "푸시 된 커밋은 개발 브랜치 의 현재 팁의 후손 입니까?"와 같은 질문을 할 수 있지만 "푸시 된 커밋의 부모 분기는 무엇입니까?"라고 확실하게 요청할 수는 없습니다.
당신이 원하는 것에 가장 가까운 것으로 보이는 가장 신뢰할만한 질문은 다음과 같습니다.
모두를 위해 (현재의 팁을 제외한의 조상 커밋 밀어 개발 의 현재 끝이 있고, 그 조상) 개발을 부모로를 :
- 그러한 커밋이 하나 이상 존재합니까?
- 그러한 모든 커밋은 단일 부모 커밋입니까?
다음과 같이 구현할 수 있습니다.
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
, 당신은 질문을 변경 요청할 수 있습니다
푸시 된 커밋의 조상 (현재 개발 팁 및 조상 제외 ) :
- 두 부모와의 약속이 있습니까?
- 그렇지 않다면, 그러한 커밋 중 하나 이상이 현재 유일한 부모 를 개발 하고 있습니까?
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