git将目录移动到另一个存储库,同时保留历史记录

时间:2017-01-23 17:19:11

标签: git

首先 - 向这个问题道歉。关于它的话题已经很多了。但我对他们没有太多运气。我对git缺乏熟悉并没有多大帮助。

我正在将一个文件夹从一个git repo移动到另一个(已经存在)。 e.g。

repo-1
---- dir1
---- dir2
---- dir3
---- dir-to-move
---- dir5

repo-2
---- dir1
---- dir2
---- dir3

最后我希望回购看起来像

repo-1
---- dir1
---- dir2
---- dir3
---- dir-to-move
---- dir5

repo-2
---- dir1
---- dir2
---- dir3
---- dir-to-move

即。一段时间内,两个仓库中都会存在 dir-to-move 。但最终我会将最新的更改迁移到 repo-2 并从 repo-1 中删除 dir-to-move

我的初步研究让我相信我需要使用 filter-branch 。 e.g。

How to move files from one git repo to another preserving history using `git format-patch`and `git am`

我已经知道子树取代了这种方法。然而,它并没有达到我的预期。我以为我能够做类似

的事情

repo-1 工作空间

git subtree split -P dir-to-move -b split

拆分分支过滤到 dir-to-move 及其历史记录。 然后在 repo-2 工作区

git remote add repo-1 repo-1-url.git
git subtree add --prefix dir-to-move split

这会移动代码。它也有,包括历史

e.g。

cd repo-2
git log

显示来自 repo-1

的提交

cd repo-2
git log dir-to-move

仅显示“从提交添加目标移动...”

即。包含历史记录但在检查特定文件/目录时不会显示。

我该如何正确地做到这一点?

6 个答案:

答案 0 :(得分:7)

FWIW,经过多次迭代后,以下内容对我有用。

将两个仓库克隆到临时工作区。

git clone <repourl>/repo-1.git 
git clone <repourl>/repo-2.git
cd repo-1
git remote rm origin # delete link to original repository to avoid any accidental remote changes
git filter-branch --subdirectory-filter dir-to-move -- --all  # dir-to-move is being moved to another repo.  This command goes through history and files, removing anything that is not in the folder.  The content of this folder will be moved to root of the repo as a result. 
# This folder has to be moved to another folder in the target repo.  So, move everything to another folder.
git filter-branch -f --index-filter \
'git ls-files -s | /usr/local/bin/sed -e "s/\t\"*/&dir-to-move\//" |
    GIT_INDEX_FILE=$GIT_INDEX_FILE.new \
        git update-index --index-info &&
 mv "$GIT_INDEX_FILE.new" "$GIT_INDEX_FILE"' HEAD
# Above command will go through history and rewrite the history by adding dir-to-move/ to each files.  As a result, all files will be moved to a subfolder /dir-to-move.  Make sure to use gnu-sed as OSX sed doesn't handle some extensions correctly.  For eg. \t

现在切换到目标仓库并从源头获取所有内容。

git clone repo-2
git remote add master ../repo-1/
git pull master master --allow-unrelated-histories
git push  # push everything to remote 

以上步骤假设主分支用于源和目标。但是,标签和分支被忽略了。

答案 1 :(得分:5)

我无法帮助您git subtree,但filter-branch可能会帮助您。

首先,您需要创建一个包含源和目标分支的公共存储库。这可以通过在“origin”旁边添加一个新的“remote”并从新的遥控器中获取来完成。

在源分支上使用filter-branchrm -rfdir-to-move以外的所有目录。之后,您将拥有一个可以干净地重新定位或合并到目标分支的提交历史记录。我认为最简单的方法是cherry-pick来自源分支的所有非空提交。可以通过运行git rev-list --reverse source-branch -- dir-to-move

来获取这些提交的列表

当然,如果dir-to-move的历史是非线性的(已经包含合并提交),那么它不会被cherry-pick保留,因此可以使用git merge代替。 / p>

示例create common repo:

cd repo-2
git remote add source ../repo-1
git fetch source

示例过滤器分支

cd repo-2
git checkout -b source-master source/master
CMD="rm -rf dir1 dir2 dir3 dir5"
git filter-branch --tree-filter "$CMD"

示例樱桃挑选到目的地主人

cd repo-2
git checkout master
git cherry-pick `git rev-list --reverse source-master -- dir-to-move`

答案 2 :(得分:1)

我将dir-to-move移至repo 2的方法。首先将repo 1克隆到新位置,然后将其CD克隆到repo 1文件夹中。在我的情况下,我要将文件夹从repo 1分支develop移到repo 2尚不存在的develop

git filter-branch --subdirectory-filter dir-to-move -- --all     #line 1
git remote -v                                                    #line 2
git remote set-url origin repo_2_remote_url                      #line 3
git remote -v                                                    #line 4
git push origin develop                                          #line 5

每行的说明:

  1. 清除所有与dir-to-move不相关的提交,删除该文件夹之外的所有文件,将所有内容移至根文件夹repo 1中。来自git docs
  

仅查看涉及给定子目录的历史记录。结果将包含该目录(并且仅包含该目录)作为其项目根目录

  1. 您仍然指向您的来源repo 1网址
  2. 替换当前文件夹的原始网址,使其指向repo 2
  3. 检查URL是否已正确更新
  4. repo 2分支(在这种情况下,是新创建的)develop推送到

您现在可以克隆或提取或获取repo 2存储库。您将在repo 2文件夹下拥有dir-to-move的内容以及相关的历史记录。

答案 3 :(得分:0)

您甚至可以通过以下方式对F(x) = str2sym('F(x+dx)') F(x) = F(dx + x) >> diff(F,x,3) ans(x) = D(D(D(F)))(dx + x) 进行提交:删除本地repo-1以外的所有目录(通过这种方式,无需使用dir-to-move),然后拉到fitler-branch

repo-2

注意:使用git clone https://path/to/repo-1 cd repo-1 rm dir1 dir2 dir3 dir5 -rf git commit -m "Removed unwanted directory for repo-2 cd ../ git clone https://path/to/repo-2 cd repo-2 git remote add repo-1-src ../repo-1 git pull repo-1-src master --allow-unrelated-histories 选项,请确保git版本为2.9或更高版本

答案 4 :(得分:0)

与此同时,推荐的解决方案是使用git filter-branch官方推荐的git-filter-repo。在我的文章https://stackoverflow.com/a/65265319/298288

中找到完整的示例,其中包含有关Windows用户安装的提示。

答案 5 :(得分:0)

这确实可以使用 git subtree

在 repo-1 中创建一个子树:

git subtree split -P dir-to-move -b <split>

split 分支现在将只包含 dir-to-move 目录。 您现在需要将 repo-1 中的分支拉入 repo-2 中的分支。

如果 repo-2 恰好是一个新的存储库(例如,就在 git init 之后),事情就像检查一个没有历史记录的分支并从 repo-1 中拉取一样简单。

cd repo-2
git checkout <branch>
git pull <path-to-repo-1.git> <split>

但是,如果 repo-2 是已经提交的现有存储库(如本问题中的情况),您需要从 repo-2 中的孤立分支合并:

cd repo-2
git checkout --orphan <temp>                    # Create a branch with no history
git pull <path-to-rpeo-1.git> <split>           # Pull the commits from the subtree
git checkout <branch>                           # Go back to the original branch
git merge --allow-unrelated-histories <temp>    # Merge the unrelated commits back
git branch -d <temp>                            # Delete the temporary branch