nau*_*101 103 git git-submodules
通常情况下,您正在编写某种类型的项目,过了一段时间后,很明显项目的某些组件实际上可用作独立组件(可能是库).如果您从早期开始就有这个想法,那么大部分代码都存在于自己的文件夹中.
有没有办法将git项目的子目录之一转换为子模块?理想情况下会发生这样的情况,即该目录中的所有代码都从父项目中删除,并且子模块项目被添加到其中,具有所有适当的历史记录,并且所有父项目提交都指向正确的子模块提交.
kni*_*ttl 78
要将子目录隔离到其自己的存储库,请使用filter-branch
原始存储库的克隆:
git clone <your_project> <your_submodule>
cd <your_submodule>
git filter-branch --subdirectory-filter 'path/to/your/submodule' --prune-empty -- --all
Run Code Online (Sandbox Code Playgroud)
它只不过是删除原始目录并将子模块添加到父项目中.
zed*_*ght 17
首先将dir更改为将成为子模块的文件夹.然后:
git init
git remote add origin repourl
git add .
git commit -am'first commit in submodule'
git push -u origin master
cd ..
rm -rf folder wich will be a submodule
git commit -am'deleting folder'
git submodule add repourl folder wich will be a submodule
git commit -am'adding submodule'
Run Code Online (Sandbox Code Playgroud)
ood*_*vid 10
我知道这是一个旧线程,但这里的答案压缩了其他分支中的任何相关提交.
克隆并保留所有额外分支和提交的简单方法:
1 - 确保你有这个git别名
git config --global alias.clone-branches '! git branch -a | sed -n "/\/HEAD /d; /\/master$/d; /remotes/p;" | xargs -L1 git checkout -t'
Run Code Online (Sandbox Code Playgroud)
2 - 克隆遥控器,拉动所有分支,更改遥控器,过滤目录,按下
git clone git@github.com:user/existing-repo.git new-repo
cd new-repo
git clone-branches
git remote rm origin
git remote add origin git@github.com:user/new-repo.git
git remote -v
git filter-branch --subdirectory-filter my_directory/ -- --all
git push --all
git push --tags
Run Code Online (Sandbox Code Playgroud)
官方 git 项目现在推荐使用git-filter-repo
# install git-filter-repo, see [1] for install via pip, or other OS's.
sudo apt-get install git-filter-repo
# copy your repo; everything EXCEPT the subdir will be deleted, and the subdir will become root.
# --no-local is required to prevent git from hard linking to files in the original, and is checked by `filter-branch`
git clone working-dir/.git working-dir-copy --no-local
cd working-dir-copy
# extract the desired subdirectory and its history.
git filter-repo --subdirectory-filter foodir
# foodir is now its own directory. Push it to github/gitlab etc
git remote add origin user@hosting/project.git
git push -u origin --all
git push -u origin --tags
Run Code Online (Sandbox Code Playgroud)
也感谢这个要点。
编辑:对于 LFS 用户(穷人),git clone 不会拉取图像的整个 lfs 历史记录,这会导致 git push 失败。
// Original branch needs to get history of all images
git lfs fetch --all
// clone needs to copy the history
git lfs install --skip-smudge
git lfs pull working-dir --all
Run Code Online (Sandbox Code Playgroud)
https://github.com/newren/git-filter-repo/blob/main/INSTALL.md
假设我们有一个名为 的存储库repo-old
,其中包含一个子目录, sub
我们希望将其转换为具有自己的 repo 的子模块repo-sub
。
进一步的目的是,原始存储库repo-old
应转换为修改后的存储库repo-new
,其中接触先前存在的子目录的所有提交sub
现在应指向我们提取的子模块 repo 的相应提交repo-sub
。
可以通过git filter-branch
两步过程来实现这一目标:
repo-old
从到 的子目录提取(已在接受的答案repo-sub
中提到)repo-old
子目录从到 的替换repo-new
(使用正确的提交映射)备注:我知道这个问题很旧,并且已经提到过,它git filter-branch
已被弃用并且可能很危险。但另一方面,它可能会帮助其他人拥有易于在转换后验证的个人存储库。所以要注意!请告诉我是否有任何其他工具可以做同样的事情而不被弃用并且可以安全使用!
我将在下面解释如何使用 git 版本 2.26.2 在 Linux 上实现这两个步骤。旧版本可能在某种程度上可以工作,但这需要测试。
为了简单起见,我将仅限于原始存储库中只有一个master
分支和一个远程的情况。另请注意,我依赖于带有前缀的临时 git 标签,这些前缀将在此过程中被删除。因此,如果已经有类似命名的标签,您可能需要调整下面的前缀。最后请注意,我还没有对此进行广泛的测试,并且可能存在配方失败的极端情况。因此,请在继续之前备份所有内容!origin
repo-old
temp_
以下 bash 片段可以连接成一个大脚本,然后应在存储库所在的同一文件夹中执行该脚本repo-org
。不建议将所有内容直接复制并粘贴到命令窗口中(即使我已经成功测试了这一点)!
# Root directory where repo-org lives
# and a temporary location for git filter-branch
root="$PWD"
temp='/dev/shm/tmp'
# The old repository and the subdirectory we'd like to extract
repo_old="$root/repo-old"
repo_old_directory='sub'
# The new submodule repository, its url
# and a hash map folder which will be populated
# and later used in the filter script below
repo_sub="$root/repo-sub"
repo_sub_url='https://github.com/somewhere/repo-sub.git'
repo_sub_hashmap="$root/repo-sub.map"
# The new modified repository, its url
# and a filter script which is created as heredoc below
repo_new="$root/repo-new"
repo_new_url='https://github.com/somewhere/repo-new.git'
repo_new_filter="$root/repo-new.sh"
Run Code Online (Sandbox Code Playgroud)
# The index filter script which converts our subdirectory into a submodule
cat << EOF > "$repo_new_filter"
#!/bin/bash
# Submodule hash map function
sub ()
{
local old_commit=\$(git rev-list -1 \$1 -- '$repo_old_directory')
if [ ! -z "\$old_commit" ]
then
echo \$(cat "$repo_sub_hashmap/\$old_commit")
fi
}
# Submodule config
SUB_COMMIT=\$(sub \$GIT_COMMIT)
SUB_DIR='$repo_old_directory'
SUB_URL='$repo_sub_url'
# Submodule replacement
if [ ! -z "\$SUB_COMMIT" ]
then
touch '.gitmodules'
git config --file='.gitmodules' "submodule.\$SUB_DIR.path" "\$SUB_DIR"
git config --file='.gitmodules' "submodule.\$SUB_DIR.url" "\$SUB_URL"
git config --file='.gitmodules' "submodule.\$SUB_DIR.branch" 'master'
git add '.gitmodules'
git rm --cached -qrf "\$SUB_DIR"
git update-index --add --cacheinfo 160000 \$SUB_COMMIT "\$SUB_DIR"
fi
EOF
chmod +x "$repo_new_filter"
Run Code Online (Sandbox Code Playgroud)
cd "$root"
# Create a new clone for our new submodule repo
git clone "$repo_old" "$repo_sub"
# Enter the new submodule repo
cd "$repo_sub"
# Remove the old origin remote
git remote remove origin
# Loop over all commits and create temporary tags
for commit in $(git rev-list --all)
do
git tag "temp_$commit" $commit
done
# Extract the subdirectory and slice commits
mkdir -p "$temp"
git filter-branch --subdirectory-filter "$repo_old_directory" \
--tag-name-filter 'cat' \
--prune-empty --force -d "$temp" -- --all
# Populate hash map folder from our previously created tag names
mkdir -p "$repo_sub_hashmap"
for tag in $(git tag | grep "^temp_")
do
old_commit=${tag#'temp_'}
sub_commit=$(git rev-list -1 $tag)
echo $sub_commit > "$repo_sub_hashmap/$old_commit"
done
git tag | grep "^temp_" | xargs -d '\n' git tag -d 2>&1 > /dev/null
# Add the new url for this repository (and e.g. push)
git remote add origin "$repo_sub_url"
# git push -u origin master
Run Code Online (Sandbox Code Playgroud)
cd "$root"
# Create a clone for our modified repo
git clone "$repo_old" "$repo_new"
# Enter the new modified repo
cd "$repo_new"
# Remove the old origin remote
git remote remove origin
# Replace the subdirectory and map all sliced submodule commits using
# the filter script from above
mkdir -p "$temp"
git filter-branch --index-filter "$repo_new_filter" \
--tag-name-filter 'cat' --force -d "$temp" -- --all
# Add the new url for this repository (and e.g. push)
git remote add origin "$repo_new_url"
# git push -u origin master
# Cleanup (commented for safety reasons)
# rm -rf "$repo_sub_hashmap"
# rm -f "$repo_new_filter"
Run Code Online (Sandbox Code Playgroud)
备注:如果新创建的存储库在此repo-new
期间挂起,git submodule update --init
则尝试递归地重新克隆存储库一次:
cd "$root"
# Clone the new modified repo recursively
git clone --recursive "$repo_new" "$repo_new-tmp"
# Now use the newly cloned one
mv "$repo_new" "$repo_new-bak"
mv "$repo_new-tmp" "$repo_new"
# Cleanup (commented for safety reasons)
# rm -rf "$repo_new-bak"
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
18208 次 |
最近记录: |