Skip to content

背景:

最近有个项目是基于开源项目进行二次开发的,开源项目是前后端放在一起的,公司项目是将前端拆出来了,进行二次开发,但是经过一段时间,要同步线上的版本,由于项目结构已经变了,所以需要研究如何进行同步

实现方案

经过调研,决定使用git subtree 将子项目进行抽离

  1. 需要在当前项目创建一个远程分支 git remote add upstream <远程分支地址> 这里upstream 就是远程分支的名字,随便起,一般当前项目默认的远程分支是origin,为了避免重名就是用upstream

  2. 要落下所有这个分支的tag git fetch upstream --tags

  3. 使用git subtree 抽离子项目 git subtree split --prefix=子项目目录 -b 分支名称 tags/指定tag号

  4. 执行完上面的,分支已经检出来了,然后与当前本地项目分支合并会报错,由于不同源,所以要加参数,让两个无关的分支机型合并,使用 git merge --allow-unrelated-histories

说明:

其实同步线上的代码,不需要关系线上提交记录,只需要将指定tag版本更新下来就好了,所以保证只有一个提交节点最好,subtree有个指令是--squash可以忽略外部的提交记录,但是只能用在add和pull方法上, 例如 git subtree add --squash --prefix=子项目目录 <指定目录名> <远程分支地址> <指定tag号> 但是这个执行的效果就是在当前的目录下增加检出了一个子目录,这个目录的名字就是 指定目录名

参考 ai生成的同步脚本:

bash


#!/usr/bin/env bash
set -e

DIFY_REPO="https://github.com/langgenius/dify.git"
TEMP_DIR="dify-tmp"
SPLIT_BRANCH="dify-web-subtree"

# 自动删除本地临时分支
if git show-ref --verify --quiet refs/heads/${SPLIT_BRANCH}; then
  echo "[INFO] 删除已存在的本地分支 ${SPLIT_BRANCH} ..."
  git branch -D "${SPLIT_BRANCH}"
fi

# 自动清理临时目录
if [ -d "${TEMP_DIR}" ]; then
  echo "[INFO] 删除已存在的临时目录 ${TEMP_DIR} ..."
  git rm -rf "${TEMP_DIR}" || rm -rf "${TEMP_DIR}"
  git commit -m "chore: remove old temporary ${TEMP_DIR} directory" || true
fi

# 远程存在性检查
if git remote | grep -q '^dify$'; then
  echo "[INFO] 远程 'dify' 已存在,跳过添加"
else
  echo "[INFO] 添加远程 'dify' -> ${DIFY_REPO}"
  git remote add dify "${DIFY_REPO}"
fi

# 交互式读取版本号
read -rp "请输入要导入的 Dify 版本号(如 1.8.0): " VERSION
if [[ -z "$VERSION" ]]; then
  echo "[ERROR] 版本号不能为空,退出"
  exit 1
fi

# 只拉取指定 tag
echo "[INFO] 拉取 Dify 远程标签 ${VERSION} ..."
git fetch dify tag "${VERSION}"

# subtree add 整个 tag 到临时目录
echo "[INFO] 开始 subtree add ${VERSION} 到 ${TEMP_DIR} ..."
git subtree add --prefix="${TEMP_DIR}" dify "${VERSION}" --squash

# split 出 web 子目录到临时分支
echo "[INFO] 拆分 ${TEMP_DIR}/web 到临时分支 ${SPLIT_BRANCH} ..."
git subtree split --prefix="${TEMP_DIR}/web" --branch="${SPLIT_BRANCH}"

# 合并到根目录(不加 -X theirs,保留冲突标记)
echo "[INFO] 合并 ${SPLIT_BRANCH} 到当前分支根目录 ..."
if ! git merge --allow-unrelated-histories "${SPLIT_BRANCH}"; then
  echo "[WARN] 自动合并有冲突,请手动解决冲突后 git add、git commit!"
  exit 1
fi

# 清理临时目录与分支
echo "[INFO] 清理临时目录 ${TEMP_DIR} ..."
git rm -rf "${TEMP_DIR}" || rm -rf "${TEMP_DIR}"
git commit -m "chore: remove temporary ${TEMP_DIR} directory" || true

echo "[INFO] 删除临时分支 ${SPLIT_BRANCH} ..."
git branch -D "${SPLIT_BRANCH}"

echo "[SUCCESS] Dify ${VERSION} 的 web/ 目录已导入到项目根目录!"