git filter repo 能否从许多按日期交织提交的 repos 中创建一个 monorepo?

Can git filter repo create a monorepo from many repos interweaving commits by date?

使用 git-filter-repo 是否可以将 N 个存储库组合成一个单一存储库,重新编写提交,以便提交交织,或者 "zippered" 按日期更新? 目前,我仅使用 2 个回购协议对此进行测试,每个回购协议都有自己的子目录。操作后,每个 repo 的提交彼此 "top" 而不是交织在一起。我真正想要的是能够通过编写的数据获得完全线性的历史记录,而无需添加合并提交。


rm -rf ___x
mkdir ___x
cd ___x

echo "creating the monorepo"
git init
touch "README.md"
git add .
git commit -am "Hello World!"

declare -A data
data=( 
    ["foo"]="https://github.com/bcanzanella/foo.git"
    ["bar"]="https://github.com/bcanzanella/bar.git"
)

for d in "${!data[@]}"; 
do  {
    REPO_NAME=$d
    REPO_REMOTE=${data[$d]}

    # since we can use a foo/bar as the repo identifier, replace the / with a -
    REPO_DIR_TMP="$(mktemp -d -t "${REPO_NAME/\//-}.XXXX")"

    echo "REPO REMOTE: $REPO_REMOTE"
    echo "REPO NAME: $REPO_NAME"
    echo "REPO TMP DIR: $REPO_DIR_TMP"
    echo ""

    echo "Cloning..."
    git clone "$REPO_REMOTE" "$REPO_DIR_TMP"

    echo "filtering into ..."
    cd $REPO_DIR_TMP && git-filter-repo --to-subdirectory-filter "$REPO_NAME"
    # cat .git/filter-repo/commit-map

    ## merge the rewritten repo
    git remote add "$REPO_NAME" "$REPO_DIR_TMP"

    echo "fetching..."
    git fetch "$REPO_NAME"

    echo "merging..."
    git merge --allow-unrelated-histories "$REPO_NAME/master" --no-edit

    ## delete the rewritten repo
    echo "Removing temp dir $REPO_DIR_TMP..."
    rm -rf "$REPO_DIR_TMP"

    echo "Removing remote $REPO_NAME..."
    # git remote rm "$REPO_NAME"

    echo "$REPO_NAME done!"
} 
done

强调 eftshift0 的评论:变基和重写历史可能导致提交以看似荒谬的时间顺序排序。

如果您知道所有提交都是有序的(例如:父提交的提交日期始终比其子提交的提交日期 "older"),您可以生成git rebase -i 脚本中的正确提交列表。


[edit] 考虑之后,这对于您的用例可能就足够了:

使用 --date-order 查看您的回购历史:

git log --graph --oneline --date-order

如果提交序列符合您的预期,您可以使用 git log 生成 rebase -i 序列脚本:

# --reverse   : 'rebase -i' asks for entries starting from the oldest
# --no-merges : do not mention the "merge" commits
# sed -e 's/^/pick /' : use any way you see fit to prefix each line with 'pick '
#        (another valid way is to copy paste the list of commits in an editor,
#         and add 'pick ' to each line ...)
git log --reverse --no-merges --oneline --date-order |\
  sed -e 's/^/pick /' > /tmp/rebase-apply.txt

然后 rebase 你的 repo 的完整历史:

git rebase -i --root

在编辑器中,copy/paste 您使用第一个命令创建的脚本, 保存并关闭。

希望您能得到一个无冲突的统一历史。