我怎样才能将Git存储库结合到线性历史记录中? [英] How can I combine Git repositories into a linear history?

查看:111
本文介绍了我怎样才能将Git存储库结合到线性历史记录中?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有两个git仓库 R1 R2 ,其中包含两个句点的提交
产品的发展:1995-1997和1999-2013。
(我通过将现有的RCS和CVS存储库转换为Git来创建它们)。

$ p $ R1:
A --- B --- C --- D

R2:
K --- L --- M --- N

如何将两个存储库合并为一个包含
的项目线性历史记录的精确视图?

  A --- B --- C --- D --- K --- L --- M --- N 

请注意, R1 R2 文件已被添加,删除和重命名。



我尝试创建一个空的存储库,然后将它们的内容
合并到它。

  git remote add R1 /vol/R1.git 
git fetch R1

git remote add R2 /vol/R2.git
git fetch R2

git merge --strategy = recursive --strategy-option =他们的R1
git merge --strategy =递归--strategy-option =它们的R2

然而,这留下了最终版本中的文件 D
但不是修订 K
我可以制作合成提交以删除合并之间的额外文件,
,但这对我来说似乎不够雅观。
此外,通过这种方法,最终结果包含
没有真正发生的合并。

解决方案

使用git filter-branch



直接从 git-filter-branch 手册页:首先,创建一个新的仓库与原来的两个遥控器一样,就像你之前做的一样。我假设两者都使用分支名称master。

  git init回购
cd回购​​
git remote add R1 /vol/R1.git
git fetch R1
git remote add R2 /vol/R2.git
git fetch R2

接下来,将master(当前分支)指向R2的主字符。

  git reset --hard R2 / master 

现在我们可以将R1的主历史记录移植到开头。

  git filter-branch --parent-filter'seds_ ^ \ $ _- p R1 / master_'HEAD 

换句话说,我们插入一个在 D K 之间伪造父母提交,所以新的历史记录如下所示:

  A --- B --- C --- D --- K --- L --- M --- N 

K N K 的父指针改变,因此所有的SHA-1标识符都会改变。提交消息,作者,时间戳记等保持不变。

将两个以上的存储库与filter-branch合并在一起



如果你有两个以上的版本库,比如说R1(最早)到R5(最新版),只需重复 git reset git filter-branch 命令按照时间顺序排列。
$ b

PARENT_REPO = R1
为R2 R3 R4 R5中的CHILD_REPO; do
git reset --hard $ CHILD_REPO / master
git filter-branch --parent-filter'sed's_ ^ \ $ _- p'$ PARENT_REPO / master'''HEAD
PARENT_REPO = $ CHILD_REPO
完成



使用移植物



作为将 - parent-filter 选项用于 filter-branch 的替代方法,您可以使用移植机制。



考虑将 R2 / master 附加为(即,比 R1 / master 。像以前一样,首先将当前分支( master )指向 R2 / master 的顶端。

  git reset --hard R2 / master 

现在,不是运行 filter-branch 命令,而是在 .git / info / grafts 链接根目录(最旧)提交 > R2 / master K )添加到 R1 / master ( D )。 (如果 R2 / master 有多个根,下面只会链接其中之一。)



<$ p $ (git rev-list R2 / master | tail -n 1)
TIP_OF_R1 = $(git rev-parse R1 / master)
echo $ ROOT_OF_R2 $ TIP_OF_R1 >> .git / info / grafts

此时,您可以查看您的历史记录(例如, code> gitk )来查看它看起来是否正确。如果是这样,您可以通过以下方式进行更改:

  git filter-branch 



最后,您可以通过移除移植文件来清理所有内容。

  rm .git / info / grafts 

使用移植可能比使用 - parent-filter ,但它的优点是能够将两个以上的历史记录与单个过滤器分支。 (你可以用 - parent-filter 来做同样的事情,但是这个脚本会非常快速地变得非常难看)。它还有一个好处,可以让你在看到你的改变之前他们成为永久的;如果它看起来不好,只需删除移植文件即可中止。



将两个以上的存储库与移植文件合并在一起



要使用通过R5(最新)的R1(最旧)的移植方法,只需在移植文件中添加多行。 (您运行 echo 命令的顺序无关紧要。)

  git reset --hard R5 / master 

PARENT_REPO = R1
为R2中的CHILD_REPO R3 R3 R4 R5;做
ROOT_OF_CHILD = $(git rev-list $ CHILD_REPO / master | tail -n 1)
TIP_OF_PARENT = $(git rev-parse $ PARENT_REPO / master)
echo$ ROOT_OF_CHILD $ TIP_OF_PARENT>> .git / info / grafts
PARENT_REPO = $ CHILD_REPO
完成



git rebase?



其他人建议使用 git rebase R1 / master 来代替 git filter-branch 命令。这将采用空提交和 K 之间的差异,然后尝试将其应用于 D ,结果为:

  A --- B --- C --- D --- K'--- L'--- M '--- N'

这很可能会导致合并冲突,甚至可能导致虚假如果文件在 D K K'中创建文件C $ C>。唯一的情况是,如果 D K 的树相同。



(另一个细微区别是, git rebase 会改变 K'的提交者信息 N',而 git filter-branch 不会。)


I have two git repositories R1 and R2, which contain commits from two periods of a product's development: 1995-1997 and 1999-2013. (I created them by converting existing RCS and CVS repositories into Git.)

R1:
A---B---C---D

R2:
K---L---M---N

How can I combine the two repositories into a single one that contains an accurate view of the project's linear history?

A---B---C---D---K---L---M---N

Note that between R1 and R2 files have been added, deleted, and renamed.

I tried creating an empty repository and then merging their contents onto it.

git remote add R1 /vol/R1.git
git fetch R1

git remote add R2 /vol/R2.git
git fetch R2

git merge --strategy=recursive --strategy-option=theirs R1
git merge --strategy=recursive --strategy-option=theirs R2

However, this leaves in the end files that were in revision D, but not in revision K. I could craft a synthetic commit to remove the extra files between the merges, but this seems inelegant to me. Furthermore, through this approach the end-result contains merges that didn't actually occur.

解决方案

Using git filter-branch

Using the trick straight from the git-filter-branch man page:

First, create a new repository with the two original ones as remotes, just as you did before. I am assuming that both use the branch name "master".

git init repo
cd repo
git remote add R1 /vol/R1.git
git fetch R1
git remote add R2 /vol/R2.git
git fetch R2

Next, point "master" (the current branch) to the tip of R2's "master".

git reset --hard R2/master

Now we can graft the history of R1's "master" to the beginning.

git filter-branch --parent-filter 'sed "s_^\$_-p R1/master_"' HEAD

In other words, we are inserting a fake parent commit between D and K so the new history looks like:

A---B---C---D---K---L---M---N

The only change to K through N is that K's parent pointer changes, and thus all of the SHA-1 identifiers change. The commit message, author, timestamp, etc., stay the same.

Merging more than two repositories together with filter-branch

If you have more than two repositories to do, say R1 (oldest) through R5 (newest), just repeat the git reset and git filter-branch commands in chronological order.

PARENT_REPO=R1
for CHILD_REPO in R2 R3 R4 R5; do
    git reset --hard $CHILD_REPO/master
    git filter-branch --parent-filter 'sed "s_^\$_-p '$PARENT_REPO/master'"' HEAD
    PARENT_REPO=$CHILD_REPO
done

Using grafts

As an alternative to using the --parent-filter option to filter-branch, you may instead use the grafts mechanism.

Consider the original situation of appending R2/master as a child of (that is, newer than) R1/master. As before, start by pointing the current branch (master) to the tip of R2/master.

git reset --hard R2/master

Now, instead of running the filter-branch command, create a "graft" (fake parent) in .git/info/grafts that links the "root" (oldest) commit of R2/master (K) to the tip (newest) commit in R1/master (D). (If there are multiple roots of R2/master, the following will only link one of them.)

ROOT_OF_R2=$(git rev-list R2/master | tail -n 1)
TIP_OF_R1=$(git rev-parse R1/master)
echo $ROOT_OF_R2 $TIP_OF_R1 >> .git/info/grafts

At this point, you can look at your history (say, through gitk) to see if it looks right. If so, you can make the changes permanent via:

git filter-branch

Finally, you can clean everything up by removing the graft file.

rm .git/info/grafts

Using grafts is likely more work than using --parent-filter, but it does have the advantage of being able to graft together more than two histories with a single filter-branch. (You could do the same with --parent-filter, but the script would become very ugly very fast.) It also has the advantage of allowing you to see your changes before they become permanent; if it looks bad, just delete the graft file to abort.

Merging more than two repositories together with grafts

To use the graft method with R1 (oldest) through R5 (newest), just add multiple lines to the graft file. (The order in which you run the echo commands does not matter.)

git reset --hard R5/master

PARENT_REPO=R1
for CHILD_REPO in R2 R3 R4 R5; do
    ROOT_OF_CHILD=$(git rev-list $CHILD_REPO/master | tail -n 1)
    TIP_OF_PARENT=$(git rev-parse $PARENT_REPO/master)
    echo "$ROOT_OF_CHILD" "$TIP_OF_PARENT" >> .git/info/grafts
    PARENT_REPO=$CHILD_REPO
done

What about git rebase?

Several others have suggested using git rebase R1/master instead of the git filter-branch command above. This will take the diff between the empty commit and K and then try to apply it to D, resulting in:

A---B---C---D---K'---L'---M'---N'

This will most likely cause a merge conflict, and may even result in spurious files being created in K' if a file was deleted between D and K. The only case in which this will work is if the trees of D and K are identical.

(Another slight difference is that git rebase alters the committer information for K' through N', whereas git filter-branch does not.)

这篇关于我怎样才能将Git存储库结合到线性历史记录中?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆