Deploy: GitHub submodule sync 2026-07-27 17:37:38
This commit is contained in:
Submodule chatbotApi-chatbot2.0-agent updated: 6208e0bf12...4d8951ba8b
Submodule chatbotApp-chatbot2.0-agent updated: 37bb91bf97...a2af80ac38
Submodule exAiChatBot-chatbot2.0-agent updated: cdece6457f...8a82ebda62
+180
-54
@@ -1,30 +1,46 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
# GitHub upstream → monorepo submodule 최신 소스 반영 (pull only, push 없음)
|
# 4개 submodule: GitHub chatbot2.0-agent 동기화 → 로컬 변경 commit → push
|
||||||
#
|
#
|
||||||
# ./git_fetch_all.sh # 4개 submodule fetch + fast-forward
|
# ./git_fetch_all.sh # fetch/merge + commit + push
|
||||||
# ./git_fetch_all.sh --init # submodule 미초기화 시 clone 포함
|
# ./git_fetch_all.sh --init # submodule 미초기화 시 clone 포함
|
||||||
# ./git_fetch_all.sh --dry-run # 실행 없이 변경 예상만 출력
|
# ./git_fetch_all.sh --dry-run # 실행 없이 상태만 출력
|
||||||
|
# ./git_fetch_all.sh --no-push # commit까지, push 생략
|
||||||
|
# ./git_fetch_all.sh --no-commit # fetch/merge만 (commit·push 생략)
|
||||||
#
|
#
|
||||||
# 대상 (.gitmodules):
|
# 대상 (.gitmodules) — 모두 branch=chatbot2.0-agent (main 사용 안 함):
|
||||||
# chatbotApp-chatbot2.0-agent → KoreaExpressWayCorp/chatbotApp (chatbot2.0-agent)
|
# chatbotApi-chatbot2.0-agent
|
||||||
# chatbotApi-chatbot2.0-agent → KoreaExpressWayCorp/chatbotApi (chatbot2.0-agent)
|
# chatbotApp-chatbot2.0-agent
|
||||||
# exAiChatBot-chatbot2.0-agent → KoreaExpressWayCorp/exAiChatBot (chatbot2.0-agent)
|
# exAiChatBot-chatbot2.0-agent
|
||||||
# kakaoChatbotSkill-chatbot2.0-agent → KoreaExpressWayCorp/kakaoChatbotSkill (chatbot2.0-agent)
|
# kakaoChatbotSkill-chatbot2.0-agent
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
|
|
||||||
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
# bare repo 배포 시 상위에서 GIT_DIR 이 export 되면 submodule git 이 깨짐
|
# bare repo 배포 시 상위에서 GIT_DIR 이 export 되면 submodule git 이 깨짐
|
||||||
MONOREPO_GIT_DIR="${MONOREPO_GIT_DIR:-${GIT_DIR:-}}"
|
MONOREPO_GIT_DIR="${MONOREPO_GIT_DIR:-${GIT_DIR:-}}"
|
||||||
unset GIT_DIR GIT_WORK_TREE
|
unset GIT_DIR GIT_WORK_TREE
|
||||||
|
|
||||||
INIT=false
|
INIT=false
|
||||||
DRY_RUN=false
|
DRY_RUN=false
|
||||||
|
DO_COMMIT=true
|
||||||
|
DO_PUSH=true
|
||||||
|
TARGET_BRANCH="chatbot2.0-agent"
|
||||||
|
|
||||||
|
# 명시 대상 (순서 고정). .gitmodules 와 일치해야 함.
|
||||||
|
TARGET_PATHS=(
|
||||||
|
"chatbotApi-chatbot2.0-agent"
|
||||||
|
"chatbotApp-chatbot2.0-agent"
|
||||||
|
"exAiChatBot-chatbot2.0-agent"
|
||||||
|
"kakaoChatbotSkill-chatbot2.0-agent"
|
||||||
|
)
|
||||||
|
|
||||||
for arg in "$@"; do
|
for arg in "$@"; do
|
||||||
case "$arg" in
|
case "$arg" in
|
||||||
--init) INIT=true ;;
|
--init) INIT=true ;;
|
||||||
--dry-run) DRY_RUN=true ;;
|
--dry-run) DRY_RUN=true ;;
|
||||||
|
--no-commit) DO_COMMIT=false; DO_PUSH=false ;;
|
||||||
|
--no-push) DO_PUSH=false ;;
|
||||||
-h|--help)
|
-h|--help)
|
||||||
sed -n '2,14p' "$0"
|
sed -n '2,18p' "$0"
|
||||||
exit 0
|
exit 0
|
||||||
;;
|
;;
|
||||||
*)
|
*)
|
||||||
@@ -36,6 +52,7 @@ done
|
|||||||
|
|
||||||
log() { echo "[git_fetch_all] $*"; }
|
log() { echo "[git_fetch_all] $*"; }
|
||||||
warn() { echo "[git_fetch_all] ⚠️ $*" >&2; }
|
warn() { echo "[git_fetch_all] ⚠️ $*" >&2; }
|
||||||
|
ok() { echo "[git_fetch_all] ✅ $*"; }
|
||||||
|
|
||||||
cd "${ROOT_DIR}"
|
cd "${ROOT_DIR}"
|
||||||
|
|
||||||
@@ -44,20 +61,6 @@ if [[ ! -f .gitmodules ]]; then
|
|||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
SUBMODULE_PATHS=()
|
|
||||||
while IFS= read -r _path; do
|
|
||||||
[[ -n "${_path}" ]] && SUBMODULE_PATHS+=("${_path}")
|
|
||||||
done < <(git config -f .gitmodules --get-regexp '^submodule\..*\.path$' | awk '{print $2}')
|
|
||||||
|
|
||||||
if [[ ${#SUBMODULE_PATHS[@]} -eq 0 ]]; then
|
|
||||||
echo "ERROR: .gitmodules 에 submodule 경로 없음"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
if $INIT && ! $DRY_RUN; then
|
|
||||||
log "submodule init (direct clone)..."
|
|
||||||
fi
|
|
||||||
|
|
||||||
resolve_monorepo_git_dir() {
|
resolve_monorepo_git_dir() {
|
||||||
if [[ -n "${MONOREPO_GIT_DIR}" && -d "${MONOREPO_GIT_DIR}" ]]; then
|
if [[ -n "${MONOREPO_GIT_DIR}" && -d "${MONOREPO_GIT_DIR}" ]]; then
|
||||||
echo "${MONOREPO_GIT_DIR}"
|
echo "${MONOREPO_GIT_DIR}"
|
||||||
@@ -109,13 +112,56 @@ submodule_is_cloned() {
|
|||||||
[[ -e "${ROOT_DIR}/${path}/.git" ]]
|
[[ -e "${ROOT_DIR}/${path}/.git" ]]
|
||||||
}
|
}
|
||||||
|
|
||||||
fetch_one() {
|
repo_is_dirty() {
|
||||||
local path="$1"
|
! git diff --quiet || ! git diff --cached --quiet || [[ -n "$(git ls-files --others --exclude-standard)" ]]
|
||||||
local url branch old new dirty
|
}
|
||||||
|
|
||||||
url="$(git config -f .gitmodules "submodule.${path}.url")"
|
ensure_branch() {
|
||||||
branch="$(git config -f .gitmodules "submodule.${path}.branch" || echo main)"
|
local branch="$1"
|
||||||
branch="${branch:-main}"
|
local git_dir
|
||||||
|
# submodule 은 .git 이 파일일 수 있음 → rev-parse 사용
|
||||||
|
git_dir="$(git rev-parse --git-dir 2>/dev/null || echo .git)"
|
||||||
|
if [[ -d "${git_dir}/rebase-merge" || -d "${git_dir}/rebase-apply" ]]; then
|
||||||
|
warn "rebase 진행 중 — 수동 해결 후 재실행 (git rebase --continue / --abort)"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
if [[ -f "${git_dir}/MERGE_HEAD" ]]; then
|
||||||
|
warn "merge 진행 중 — 수동 해결 후 재실행"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
local cur
|
||||||
|
cur="$(git rev-parse --abbrev-ref HEAD 2>/dev/null || echo DETACHED)"
|
||||||
|
if [[ "${cur}" == "${branch}" ]]; then
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
if git show-ref --verify --quiet "refs/heads/${branch}"; then
|
||||||
|
git checkout "${branch}"
|
||||||
|
elif git show-ref --verify --quiet "refs/remotes/origin/${branch}"; then
|
||||||
|
git checkout -B "${branch}" "origin/${branch}"
|
||||||
|
else
|
||||||
|
git checkout -B "${branch}"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
sync_one() {
|
||||||
|
local path="$1"
|
||||||
|
local url branch old new stashed=0 ahead
|
||||||
|
|
||||||
|
url="$(git config -f .gitmodules "submodule.${path}.url" 2>/dev/null || true)"
|
||||||
|
if [[ -z "${url}" ]]; then
|
||||||
|
warn "${path} — .gitmodules 에 없음, 건너뜀"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 사용자 요구: main 금지, chatbot2.0-agent 고정
|
||||||
|
branch="$(git config -f .gitmodules "submodule.${path}.branch" || echo "${TARGET_BRANCH}")"
|
||||||
|
branch="${branch:-${TARGET_BRANCH}}"
|
||||||
|
if [[ "${branch}" != "${TARGET_BRANCH}" ]]; then
|
||||||
|
warn "${path} — .gitmodules branch=${branch} → ${TARGET_BRANCH} 로 강제"
|
||||||
|
branch="${TARGET_BRANCH}"
|
||||||
|
fi
|
||||||
|
|
||||||
log ">>> ${path}"
|
log ">>> ${path}"
|
||||||
log " url=${url} branch=${branch}"
|
log " url=${url} branch=${branch}"
|
||||||
@@ -135,52 +181,121 @@ fetch_one() {
|
|||||||
|
|
||||||
(
|
(
|
||||||
cd "${ROOT_DIR}/${path}"
|
cd "${ROOT_DIR}/${path}"
|
||||||
|
unset GIT_DIR GIT_WORK_TREE
|
||||||
if ! git diff --quiet || ! git diff --cached --quiet; then
|
|
||||||
dirty=yes
|
|
||||||
warn "${path} — 로컬 변경 있음 (fetch는 진행, fast-forward 실패 가능)"
|
|
||||||
else
|
|
||||||
dirty=no
|
|
||||||
fi
|
|
||||||
|
|
||||||
old="$(git rev-parse HEAD 2>/dev/null || echo none)"
|
old="$(git rev-parse HEAD 2>/dev/null || echo none)"
|
||||||
|
|
||||||
if $DRY_RUN; then
|
if $DRY_RUN; then
|
||||||
|
ensure_branch "${branch}" || true
|
||||||
git fetch origin "${branch}" 2>/dev/null || git fetch origin
|
git fetch origin "${branch}" 2>/dev/null || git fetch origin
|
||||||
new="$(git rev-parse "origin/${branch}" 2>/dev/null || echo unknown)"
|
new="$(git rev-parse "origin/${branch}" 2>/dev/null || echo unknown)"
|
||||||
if [[ "${old}" == "${new}" ]]; then
|
if [[ "${old}" == "${new}" ]]; then
|
||||||
log " [dry-run] 이미 최신: ${old:0:7}"
|
log " [dry-run] 원격 최신: ${old:0:7}"
|
||||||
else
|
else
|
||||||
log " [dry-run] ${old:0:7} → ${new:0:7}"
|
log " [dry-run] 원격 변경 ${old:0:7} → ${new:0:7}"
|
||||||
git log --oneline "${old}..origin/${branch}" 2>/dev/null | sed 's/^/ /' || true
|
git log --oneline "HEAD..origin/${branch}" 2>/dev/null | sed 's/^/ /' || true
|
||||||
|
fi
|
||||||
|
if repo_is_dirty; then
|
||||||
|
log " [dry-run] 로컬 미커밋 변경 있음 → commit/push 대상"
|
||||||
|
git status -sb | sed 's/^/ /'
|
||||||
|
else
|
||||||
|
log " [dry-run] 로컬 미커밋 변경 없음"
|
||||||
fi
|
fi
|
||||||
exit 0
|
exit 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# 1) 원격 fetch + 브랜치 고정
|
||||||
git fetch origin "${branch}"
|
git fetch origin "${branch}"
|
||||||
git checkout "${branch}" 2>/dev/null || git checkout -B "${branch}" "origin/${branch}"
|
ensure_branch "${branch}" || exit 1
|
||||||
|
git branch --set-upstream-to="origin/${branch}" "${branch}" 2>/dev/null || true
|
||||||
|
|
||||||
if git merge-base --is-ancestor HEAD "origin/${branch}" 2>/dev/null \
|
# 2) 로컬 미커밋 변경이 pull 을 막으면 stash
|
||||||
&& [[ "$(git rev-parse HEAD)" != "$(git rev-parse "origin/${branch}")" ]]; then
|
if repo_is_dirty; then
|
||||||
|
log " 로컬 변경 stash 후 원격 반영..."
|
||||||
|
git stash push -u -m "git_fetch_all auto-stash $(date '+%Y-%m-%d %H:%M:%S')" || true
|
||||||
|
stashed=1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 3) GitHub 변경사항 merge (ff → rebase → merge)
|
||||||
|
if [[ "$(git rev-parse HEAD)" != "$(git rev-parse "origin/${branch}")" ]]; then
|
||||||
|
log " 원격 변경 merge: origin/${branch}"
|
||||||
|
if git merge-base --is-ancestor HEAD "origin/${branch}" 2>/dev/null; then
|
||||||
git merge --ff-only "origin/${branch}"
|
git merge --ff-only "origin/${branch}"
|
||||||
elif [[ "$(git rev-parse HEAD)" != "$(git rev-parse "origin/${branch}")" ]]; then
|
else
|
||||||
warn "${path} — fast-forward 불가 (로컬 커밋/변경 존재). 수동 merge 필요"
|
if ! git pull --rebase origin "${branch}"; then
|
||||||
|
warn "${path} — rebase 실패, merge 로 재시도"
|
||||||
|
git rebase --abort 2>/dev/null || true
|
||||||
|
if ! git pull --no-rebase origin "${branch}"; then
|
||||||
|
warn "${path} — merge 충돌. 수동 해결 필요"
|
||||||
|
git status -sb | sed 's/^/ /'
|
||||||
|
if [[ "${stashed}" -eq 1 ]]; then
|
||||||
|
git stash pop || true
|
||||||
|
fi
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
ok "${path} 원격 반영 $(git log -1 --oneline)"
|
||||||
|
else
|
||||||
|
log " 원격과 동일 (fetch 완료)"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 4) stash 복원
|
||||||
|
if [[ "${stashed}" -eq 1 ]]; then
|
||||||
|
log " stash 복원..."
|
||||||
|
if ! git stash pop; then
|
||||||
|
warn "${path} — stash pop 충돌. 수동 해결 후 commit/push"
|
||||||
git status -sb | sed 's/^/ /'
|
git status -sb | sed 's/^/ /'
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 5) 로컬 수정사항 commit
|
||||||
|
if $DO_COMMIT && repo_is_dirty; then
|
||||||
|
log " 로컬 변경 commit..."
|
||||||
|
git add -A
|
||||||
|
if git diff --cached --quiet; then
|
||||||
|
log " staged 변경 없음 (ignore 된 파일만 있을 수 있음)"
|
||||||
|
else
|
||||||
|
git commit -m "$(cat <<EOF
|
||||||
|
sync: monorepo local updates ($(date '+%Y-%m-%d %H:%M'))
|
||||||
|
|
||||||
|
git_fetch_all.sh 로 chatbot2.0-agent 동기화 후 로컬 수정을 반영한다.
|
||||||
|
EOF
|
||||||
|
)"
|
||||||
|
ok "${path} commit $(git log -1 --oneline)"
|
||||||
|
fi
|
||||||
|
elif ! $DO_COMMIT && repo_is_dirty; then
|
||||||
|
log " [--no-commit] 미커밋 변경 유지"
|
||||||
|
git status -sb | sed 's/^/ /'
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 6) push (chatbot2.0-agent 만)
|
||||||
|
if $DO_PUSH; then
|
||||||
|
ahead="$(git rev-list --count "origin/${branch}..HEAD" 2>/dev/null || echo 0)"
|
||||||
|
if [[ "${ahead}" != "0" ]]; then
|
||||||
|
log " push origin ${branch} (ahead ${ahead})..."
|
||||||
|
if git push origin "${branch}"; then
|
||||||
|
ok "${path} push 완료"
|
||||||
|
else
|
||||||
|
warn "${path} — push 실패 (대용량 파일/권한 등). 로그 확인"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
log " push 생략 (원격과 동일)"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
log " [--no-push] push 생략"
|
||||||
|
fi
|
||||||
|
|
||||||
new="$(git rev-parse HEAD)"
|
new="$(git rev-parse HEAD)"
|
||||||
if [[ "${old}" == "${new}" ]]; then
|
log " HEAD ${old:0:7} → ${new:0:7} $(git log -1 --oneline)"
|
||||||
log " ✅ 최신 유지 $(git log -1 --oneline)"
|
|
||||||
else
|
|
||||||
log " ✅ 갱신 ${old:0:7} → ${new:0:7} $(git log -1 --oneline)"
|
|
||||||
fi
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
failures=0
|
failures=0
|
||||||
for path in "${SUBMODULE_PATHS[@]}"; do
|
for path in "${TARGET_PATHS[@]}"; do
|
||||||
if ! fetch_one "${path}"; then
|
if ! sync_one "${path}"; then
|
||||||
failures=$((failures + 1))
|
failures=$((failures + 1))
|
||||||
fi
|
fi
|
||||||
echo ""
|
echo ""
|
||||||
@@ -192,7 +307,12 @@ fi
|
|||||||
|
|
||||||
log "=========================================="
|
log "=========================================="
|
||||||
log "submodule 상태:"
|
log "submodule 상태:"
|
||||||
git submodule status || true
|
git submodule status 2>/dev/null || true
|
||||||
|
for path in "${TARGET_PATHS[@]}"; do
|
||||||
|
if submodule_is_cloned "${path}"; then
|
||||||
|
printf " %-36s %s\n" "${path}" "$(git -C "${ROOT_DIR}/${path}" log -1 --oneline 2>/dev/null || echo '?')"
|
||||||
|
fi
|
||||||
|
done
|
||||||
log "=========================================="
|
log "=========================================="
|
||||||
|
|
||||||
if [[ ${failures} -gt 0 ]]; then
|
if [[ ${failures} -gt 0 ]]; then
|
||||||
@@ -200,5 +320,11 @@ if [[ ${failures} -gt 0 ]]; then
|
|||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
log "완료 — GitHub → 로컬 반영 (push 없음)"
|
if $DRY_RUN; then
|
||||||
log "monorepo 커밋 갱신: git add .gitmodules *-chatbot2.0-agent && git status"
|
log "완료 — dry-run (변경 없음)"
|
||||||
|
elif $DO_PUSH; then
|
||||||
|
log "완료 — ${TARGET_BRANCH}: fetch/merge → commit → push"
|
||||||
|
else
|
||||||
|
log "완료 — ${TARGET_BRANCH}: fetch/merge$($DO_COMMIT && echo ' → commit' || true) (push 생략)"
|
||||||
|
fi
|
||||||
|
log "monorepo 포인터 갱신: git add *-chatbot2.0-agent && git status"
|
||||||
|
|||||||
Submodule kakaoChatbotSkill-chatbot2.0-agent updated: dad9107d81...fb83858448
Reference in New Issue
Block a user