Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/git/24.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
git将目录移动到另一个存储库,同时保留历史记录_Git - Fatal编程技术网

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

git将目录移动到另一个存储库,同时保留历史记录,git,Git,首先,为提出这个问题道歉。关于它已经有很多话题了。但我和他们的运气不太好。我对git的不熟悉并没有多大帮助 我正在将一个文件夹从一个git repo移动到另一个(已经存在)。e、 g 最后,我希望回购协议看起来像 repo-1 ---- dir1 ---- dir2 ---- dir3 ---- dir-to-move ---- dir5 repo-2 ---- dir1 ---- dir2 ---- dir3 ---- dir-to-move i、 e.在一段时间内,两个回购协议中都将存在

首先,为提出这个问题道歉。关于它已经有很多话题了。但我和他们的运气不太好。我对git的不熟悉并没有多大帮助

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

最后,我希望回购协议看起来像

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

repo-2
---- dir1
---- dir2
---- dir3
---- dir-to-move
i、 e.在一段时间内,两个回购协议中都将存在待移动目录。但最终我会将最新的更改迁移到repo-2,并删除dir以从repo-1移动

我最初的研究让我相信我需要使用过滤器分支。e、 g

我知道子树取代了这种方法。然而,它并没有达到我的预期。我想我可以做一些类似的事情

在repo-1工作区中

git subtree split -P dir-to-move -b split
git remote add repo-1 repo-1-url.git
git subtree add --prefix dir-to-move split
将拆分的分支向下过滤为仅要移动的目录及其历史记录。 然后在repo-2工作区中

git subtree split -P dir-to-move -b split
git remote add repo-1 repo-1-url.git
git subtree add --prefix dir-to-move split
这确实会将代码移动到不同的位置。它还包括历史

e、 g

显示来自repo-1的提交

但是

仅显示“添加目录以从提交移动…”

i、 e.包含历史记录,但在检查特定文件/目录时不会显示


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

我无法帮助您使用
git子树
,但使用
过滤器分支
是可能的

首先,您需要创建一个包含源分支和目标分支的公共存储库。这可以通过在“源”旁边添加一个新的“远程”并从新远程获取来实现

使用源分支上的
filter branch
移动
rm-rf
dir以外的所有目录。在此之后,您将拥有一个提交历史记录,该历史记录可以清晰地重新设置基址或合并到目标分支中。我认为最简单的方法是从源分支中挑选所有非空提交。这些提交的列表可以通过运行
git rev list--reverse source branch--dir to move

当然,如果
dir to move
的历史记录是非线性的(已经包含合并提交),那么cherry pick将不会保留它,因此可以使用
git merge

创建普通回购的示例:

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"
示例cherry pick into destination master

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

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

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

我的移动方法
直接移动
repo 2
。首先在新位置克隆
repo 1
,然后将cd复制到
repo 1
文件夹中。就我而言,我正在将文件夹从
repo 1
分支
develope
移动到
repo 2
,其中
develope
尚不存在

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
每行说明:

  • 清除与要移动的目录无关的所有提交,删除该文件夹外的所有文件,移动根文件夹中的所有内容
    repo 1
    。发件人:
  • 只查看涉及给定子目录的历史记录。结果将包含该目录(并且仅包含该目录)作为其项目根目录

  • 您仍然指向您的源
    repo 1
    url
  • 将当前文件夹的源url替换为指向
    repo 2
  • 检查URL是否已正确更新
  • 推送到
    repo 2
    分支机构(本例中为新创建的分支机构)
    develope

  • 您现在可以克隆、提取或取回您的
    repo 2
    存储库。您将在
    repo-2
    文件夹下拥有要移动的
    dir的内容以及预期的相关历史记录。

    您甚至可以通过删除本地移动的
    dir以外的所有目录来提交
    repo-1
    (这样就无需使用
    fitler分支机构
    )然后拉至
    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
    或更高版本--允许不相关的历史记录
    选项

    建议的解决方案同时使用
    git过滤器分支
    正式推荐的版本。在我的帖子中找到一个完整的示例,其中包括有关windows用户安装的提示:

    看起来git无法遵循目录移动。如果指定某个文件而不是目录,它是否跟随其移动?似乎是唯一的解决方案。我在这里采用了这种方法,特别是,如果以前在repo-1中移动过
    dir to move
    的内容,则此解决方案将只截断这些文件在repo-1中
    dir to move
    位置中存在的历史记录。对于2021年或以后来到这里的任何人,请注意,在过去几年中,git约定已更改为使用
    main
    而不是
    master
    ,因此您可能需要将此答案代码中出现的
    master
    替换为
    main
    。我在windows+git bash上遇到过此方法的问题。我用实际的
    sed
    命令替换了
    usr\bin
    路径,但是我得到了
    Rewrite。。。mv:cannot stat
    my repo local path/.git rewrite/t/./index.new”:没有这样的文件或目录“Nice git voodoo”用于更正目标路径。在macOS上,我必须调整
    /usr/local/bin/sed-e“s/\t\”*/&dir才能移动\//“
    命令。不要使用
    /usr/local/bin/sed
    只需使用
    sed
    并将
    \t
    替换为带有
    ^
    +
    V
    选项卡的选项卡即可。我尝试过的
    ^+V
    选项卡是什么。然后在按住
    ^+V
    的同时,我按下
    选项卡
    ,然后它切换到一个新的不同选项卡。这种方法的问题是它不会移动所有远程分支和标记。它一次只移动一个分支,您可以对所有分支执行此操作
    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
    
    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