我有一个独特的需求,我正在寻找解决方案......我确实在网上查看了很多其他解决方案,但没有找到符合我期望的解决方案......
有两个存储库 - X 和 Y(下图)。我想永远删除 Repo X。但是有一个文件夹,比如说 A,我也想把它和所有 Git 提交历史一起带到第二个仓库(Y)中......篡改历史是可以的,我希望仓库 Y 的历史声称文件夹 A 存在于从一开始的 repo Y 和对该文件夹 A 的所有更改都是在它在 repo Y 中时进行的。我不希望 repo Y 的历史显示文件夹 A 是在从另一个分支/ repo merge 之后出现的。我也不想 rebase ,因为文件夹 A 的所有提交(~1000)将被转储到 Repo Y 的现有提交之上。
***** Original Commits on the timeline for Repo X and Repo Y *****
Repo Y: -------Cx--------Cy--------Cz----------
Repo X: -----------Ca----------Cb------Cc------ (only commits that touch Folder A)
我找到了一个命令来过滤分支并重写 repo X 的提交,这样根据 git 只有文件夹 A 的内容存在。git filter-branch --subdirectory-filter ./A -- --all
然后使用以下脚本将“文件夹 A”的所有内容移动到 Repo X 中名为“A”的文件夹中# https://gist.github.com/xkr47/f766f4082112c086af63ef8d378c4304
# placed the script above in PATH and executed the following command at Repo X
git filter-mv 's!^!A/!'
所以现在我有了 repo Y,这是我需要将文件夹 A 从 repo X 移动到的 repo,其中包含所有 Git 提交历史......我也有修改后的 repo X,其中唯一的内容是文件夹 A
请注意,不存在提交冲突的可能性,因为 repo X 上的所有提交都对文件夹 (A) 进行,而 repo Y 中根本不存在该文件夹
现在,我将能够将本地 Repo X 标记为我的 Repo Y 的远程,并且可以 merge 或 rebase
# repo X lives in the same directory as repo Y
# commands run inside repo Y
git remote add repoX ../X
git pull repoX <branch> --allow-unrelated-histories
# or
git pull repoX <branch> --rebase
merge ***** MERGE's output *****
Repo Y: -------Cx--------Cy-------Cz-----(MERGE)----
/
/
-----Ca---------Cb------Cc (Folder A commits)
提交的时间线将保持不变,但在两者 merge 之前将处于不同的轨道上,并且我将无法在 merge 提交之前的任何时候看到两个存储库中的内容,因为它们将位于单独的提交行上(我想要文件夹 A,以及它经历的所有更改,在 repo Y 和它的提交行)
(……这样我就可以回到 Repo Y 中的任何一点,并根据提交时间一起查看 Repo Y 和文件夹 A 的演变)
REBASE
***** REBASE's output *****
Repo Y: -------Cx--------Cy--------Cz------Ca-----Cb-----Cc----
但是我不希望 Repo X 的提交是在 Repo Y 的最新提交之后......在我的用例中,Repo X 将有大约 1000 次提交,并且一次重新调整它们会破坏 Repo Y 的提交时间表。我希望它们根据提交发生的时间在 Repo Y 的提交中融合
预期
***** Expected Output *****
Repo Y: -------Cx--Ca----Cy----Cb--Cz--Cc------ (Repo Y commits fused with commits from repo X - only adds a folder (A) to repo Y)
我知道干涉 Git Histories 不是一件好事。但是对于我的用例,这可能是我能做的最好的事情……
最佳答案
线性历史场景
如果您的“Repo Y”是单分支和线性的(没有 merge ;但是可以使用简单的 git rebase
将 merge 线性化),那么我能想到的一种可能的解决方案是将生成的 rebase 序列替换为包含融合提交的 rebase 序列依次。
master
如果出现问题,分支提交:git checkout master
git tag old-master-before-fuse
git remote add X ...path-to-your-Repo-X...
git fetch X
git rev-list --format='%at %ct %H' refs/heads/master refs/remotes/X/master \ # produce a table of all commits from both repositories (fields: author timestamp, committer timestamp, commit hash)
| grep -P '^\d+' \ # don't know to remove the "commit XXXX" lines from the output above otherway
| sort -k1 -n \ # sort by the author timestamp
| cut -d' ' -f3 \ # take hashes only
| while read LINE; do # prepare each hash for the interactive rebase sequencing
echo "pick $LINE"
done \
> .git-rebase-todo # save it to a temporary file to be used later
git rebase -i --root
一旦你的编辑器出现,用一个“break”删除所有“pick”命令,然后退出编辑器。 Git 将在此处停止( git rebase --continue
没有进一步的步骤将使 master
分支空白)。.git-rebase-todo
替换当前的待办事项序列并继续 rebase :cp .git-rebase-todo .git/rebase-merge/git-rebase-todo
git rebase --continue
这将使 master
包含融合提交历史的分支。git tag -d old-master-before-fuse
)和远程链接( git remote remove X
)。 以下是我用于测试的存储库的转储:
“ repo X”
blob
mark :1
data 0
reset refs/heads/master
commit refs/heads/master
mark :2
author - <-> 1577886449 +0200
committer - <-> 1606398449 +0200
data 3
Cx
M 100644 :1 Cx
commit refs/heads/master
mark :3
author - <-> 1580564850 +0200
committer - <-> 1606398450 +0200
data 3
Cy
from :2
M 100644 :1 Cy
commit refs/heads/master
mark :4
author - <-> 1583070451 +0200
committer - <-> 1606398451 +0200
data 3
Cz
from :3
M 100644 :1 Cz
“ repo Y”blob
mark :1
data 0
reset refs/heads/master
commit refs/heads/master
mark :2
author - <-> 1577972852 +0200
committer - <-> 1606398452 +0200
data 3
Ca
M 100644 :1 Ca
commit refs/heads/master
mark :3
author - <-> 1580651253 +0200
committer - <-> 1606398453 +0200
data 3
Cb
from :2
M 100644 :1 Cb
commit refs/heads/master
mark :4
author - <-> 1583156854 +0200
committer - <-> 1606398454 +0200
data 3
Cc
from :3
M 100644 :1 Cc
可以使用 git fast-import
恢复转储。 .使用这两个示例存储库,熔断器例程将生成以下
git log --oneline
结果:7efcbbd (HEAD -> master) Cc
6cc905d Cz
a20f00e Cb
6650162 Cy
e8e9bf1 Ca
40678ea Cx
关于git - 如何将来自两个分支/存储库的提交/更改融合到同一提交时间线中?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65015989/