简体   繁体   English

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

[英]git move directory to another repository while keeping the history

First - apologies for asking this question.首先 - 很抱歉提出这个问题。 There are a lot of topics about it already.已经有很多关于它的话题。 But I'm not having much luck with them.但我对他们的运气并不好。 My lack of familiarity with git is not much help.我对 git 的不熟悉并没有多大帮助。

I'm moving a folder from one git repo to another (which already exists).我正在将一个文件夹从一个 git 存储库移动到另一个(已经存在)。 eg例如

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

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

In the end I want the repos to look like最后我希望回购看起来像

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

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

ie For a time dir-to-move will exist in both repos.即,有一段时间dir-to-move将存在于两个 repos 中。 But eventually I'll migrate the latest changes to repo-2 and remove dir-to-move from repo-1 .但最终我会将最新的更改迁移到repo-2并从repo-1中删除dir-to-move

My initial research made me believe that I needed to use filter-branch .我最初的研究让我相信我需要使用filter-branch eg例如

How to move files from one git repo to another preserving history using `git format-patch`and `git am` 如何使用 `git format-patch` 和 `git am` 将文件从一个 git 存储库移动到另一个保留历史的存储库

I've since learnt that subtree superseded that approach.从那以后,我了解到子树取代了这种方法。 However it's not doing what I expected.但是它没有按照我的预期进行。 I thought I'd be able to do something like我以为我可以做类似的事情

In repo-1 workspacerepo-1工作区

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

to filter the split branch down to only dir-to-move and it's history.拆分分支过滤为仅dir-to-move及其历史记录。 Then in repo-2 workspace然后在repo-2工作区

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

This does move the code across.这确实移动了代码。 It also, sort of, includes the history它也有点包括历史

eg例如

cd repo-2
git log

Shows commits from repo-1显示来自repo-1 的提交

but

cd repo-2
git log dir-to-move

Shows only an 'Add dir-to-move from commit....'仅显示“从提交中添加要移动的目录....”

ie The history is included but does not show up when checked for the specific files/directories.即包含历史记录,但在检查特定文件/目录时不会显示。

How can I do this properly?我怎样才能正确地做到这一点?

I can't help you with git subtree , but with filter-branch it's possible.我无法帮助您使用git subtree ,但是使用filter-branch是可能的。

First you need to create a common repository that will contain both source and destination branches.首先,您需要创建一个包含源分支和目标分支的公共存储库。 This can be done by adding a new "remote" beside "origin" and fetching from the new remote.这可以通过在“来源”旁边添加一个新的“远程”并从新的远程获取来完成。

Use filter-branch on the source branch to rm -rf all directories except dir-to-move .在源filter-branch上使用filter-branchrm -rfdir-to-move之外的所有目录。 After that you'll have a commit history that can be cleanly rebased or merged into the destination branch.之后,您将拥有一个可以干净地重新定位或合并到目标分支的提交历史记录。 I think the easiest way is to cherry-pick all non-empty commits from the source branch.我认为最简单的方法是从源分支中cherry-pick所有非空提交。 The list of these commits can be obtained by running git rev-list --reverse source-branch -- dir-to-move这些提交的列表可以通过运行git rev-list --reverse source-branch -- dir-to-move

Of course, if the history of dir-to-move is non-linear (already contains merge commits), then it won't be preserved by cherry-pick, so git merge can be used instead.当然,如果dir-to-move的历史是非线性的(已经包含了合并提交),那么cherry-pick 不会保留它,所以可以使用git merge代替。

Example create common repo:示例创建通用存储库:

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

Example filter branch示例过滤器分支

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

Example cherry-pick into destination master示例cherry-pick 到目标主机

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

FWIW, the following worked for me after a number of iterations. FWIW,经过多次迭代后,以下内容对我有用。

Clone both the repos to a temporary work area.将两个 repos 克隆到临时工作区。

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

Now switch to target repo and fetch everything from source.现在切换到目标 repo 并从源中获取所有内容。

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

Above steps assume that master branches are used for both source and targets.以上步骤假设主分支用于源和目标。 However, tags and branches were ignored.然而,标签和分支被忽略了。

My approach to move dir-to-move to repo 2 .我将dir-to-moverepo 2 Start by cloning the repo 1 in a new location and cd to the repo 1 folder.首先将repo 1克隆到新位置,然后 cd 到repo 1文件夹。 In my case I am moving the folder from repo 1 branch develop to repo 2 where develop is not existent yet.在我的情况下,我将文件夹从repo 1分支developrepo 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

Explanation for each line:每行说明:

  1. Cleans all commits not related to dir-to-move , removes all files outside that folder, moves all contents in the root folder repo 1 .清除与dir-to-move无关的所有提交,删除该文件夹外的所有文件,移动根文件夹repo 1中的所有内容。 From git docs :git 文档

Only look at the history which touches the given subdirectory.只查看触及给定子目录的历史记录。 The result will contain that directory (and only that) as its project root结果将包含该目录(并且仅包含该目录)作为其项目根目录

  1. You are still pointing to your origin repo 1 url您仍然指向您的 origin repo 1 url
  2. Replace the origin url for your current folder to point to repo 2替换当前文件夹的原始 url 以指向repo 2
  3. Check the URLs have been updated correctly检查 URL 是否已正确更新
  4. Push to repo 2 the (newly created, in this case) develop branch推送到repo 2 (新创建的,在这种情况下) develop分支

You can now clone or pull or fetch your repo 2 repository.您现在可以克隆、拉取或获取您的repo 2存储库。 You will have under repo 2 folder the contents of dir-to-move along with relevant history as expected.您将在repo 2文件夹下拥有dir-to-move的内容以及预期的相关历史记录。

Another solution is to use git-filter-repo which git filter-branch officially recommends .另一种解决方案是使用git-filter-repo ,这是git filter-branch 官方推荐的

Find a full example including hints about the installation for windows users at my answer on how to push commits affecting a given path to a new origin?在我的关于如何将影响给定路径的提交推送到新源​​的回答中找到一个完整的示例,包括有关 Windows 用户安装的提示

git: Move folder from one repository to another while keeping history git:将文件夹从一个存储库移动到另一个存储库,同时保留历史记录

cd target-repo
git remote add source ../source-repo
git fetch source
git checkout -b source source/master

# filter out history of a single folder
git filter-branch --subdirectory-filter ./dir -- --all

# put the folder history on top of your target repo history
git rebase master

You can even make a commit on repo-1 by deleting all directory other than dir-to-move locally (by this way no need to use fitler-branch ) and then pull to repo-2 .你甚至可以提交关于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

Note : Make sure git version is 2.9 or more for using --allow-unrelated-histories option注意:确保git版本为2.9或更高版本以使用--allow-unrelated-histories选项

This is indeed possible using git subtree .这确实可以使用git subtree

In repo-1 create a subtree:在 repo-1 中创建一个子树:

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

The split branch will now only contain the dir-to-move directory. split分支现在将只包含dir-to-move目录。 You now need to pull the branch from repo-1 into a branch in repo-2.您现在需要将分支从 repo-1 拉入 repo-2 中的分支。

In case repo-2 happens to be a new repository (eg just after git init ) Things are as easy as checking out a branch with no history and pulling from repo-1.如果 repo-2 恰好是一个新的存储库(例如,就在git init ),事情就像检查一个没有历史记录的分支并从 repo-1 中拉取一样简单。

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

However if repo-2 is an existing repo where commits have already been made (as is the case in this question), you need to merge from an orphan branch in repo-2:但是,如果 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

dumb solution manual solution if all other fails:如果所有其他都失败,则愚蠢的解决方案手动解决方案:

  1. Download all files from first repo从第一个 repo 下载所有文件
  2. Create a new repo创建一个新的仓库
  3. Clone the second repo to disk.将第二个 repo 克隆到磁盘。
  4. Unpack the first repo files you want to keep (new structure)解压要保留的第一个 repo 文件(新结构)
  5. Push the changes to second repo.将更改推送到第二个 repo。
  6. Verify that you have what you want确认你有你想要的
  7. Delete the files/folders from first repo that you dont want.从您不想要的第一个存储库中删除文件/文件夹。

You loose traceability of course...你当然失去了可追溯性......

My favorite solution, which I've been using for years, is http://blog.neutrino.es/2012/git-copy-a-file-or-directory-from-another-repository-preserving-history/ .我最喜欢的解决方案是http://blog.neutrino.es/2012/git-copy-a-file-or-directory-from-another-repository-preserving-history/ However, it seems to be falling off google search, so I worry it might vanish some day, so I'm reproducing it here:然而,它似乎正在从谷歌搜索中消失,所以我担心它有一天会消失,所以我在这里复制它:

mkdir /tmp/mergepatchs
cd ~/repo/org
export reposrc=myfile.c #or mydir
git format-patch -o /tmp/mergepatchs $(git log $reposrc|grep ^commit|tail -1|awk '{print $2}')^..HEAD $reposrc
cd ~/repo/dest
git am /tmp/mergepatchs/*.patch

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 将git存储库作为子文件夹移动到另一个存储库,同时保留历史记录 - Move a git repository to another repository as a subfolder while keeping history 将目录移动到另一个git存储库,同时保留相关历史记录 - Moving a directory to another git repository while retaining relevant history 将Git存储库移动到另一个目录 - Move a Git repository to another directory 将文件夹移动到另一个git存储库并保留历史记录 - Move folder to another git repository and keep the history 将文件移动到另一个具有历史记录的 Git 存储库 - Move file to another Git repository with history git将存储库作为目录移动到另一个存储库 - git move repository to another repository as a directory 如何将 git 存储库移动到另一个目录并使该目录成为 git 存储库? - How to move a git repository into another directory and make that directory a git repository? 将Git存储库合并到另一个保留所有历史记录的存储库中 - Merge a Git repository into another one keeping all the history 是否可以将一堆文件从一个git存储库移动到另一个git存储库,同时保留(大多数)历史记录? - Is it possible to move a bunch of files from one git repository to another while preserving (most) history? 如何在保留历史记录的同时将文件从一个git存储库移动到另一个存储库 - How to move a file from one git repository to another while preserving history
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM