11

是的,我知道我应该从一开始就分叉该项目,但这就是我现在所处的情况。:)

我在本地计算机上有一个本地 Git 存储库,其中包含我的博客,该存储库有几个月的提交历史。最初,我只是从存储库 http://github.com/mojombo/mojombo.github.com下载文件,然后继续使用本地 Git 存储库,第一次提交看起来像是 mojombo 存储库中的最新文件。

我现在想分叉该项目并在其上重放我的本地 Git 存储库提交,所以看起来我从一开始就分叉了该项目,然后将其推回到我的 GitHub 上的 mojombo 存储库的分叉版本帐户:

http://github.com/program247365/mojombo.github.com

所以也许历史会是这样的:

mobjombo repository:         1---2---3----23
                                  \
my blog repository commits:       24---25---

我可以使用哪些 Git 命令来执行此操作?

我看过这个问题。我是否必须将 mojombo 的存储库作为远程项目添加到我的项目中,然后将其拉入、合并、解决冲突,然后推送到我在 GitHub 上的分叉项目?

4

3 回答 3

16

简而言之:

一种解决方案是使用嫁接连接历史,然后git filter-branch根据这些嫁接重写历史,然后可选地进行合并

请注意,在原始存储库( rebase解决方案)的新开发之上重放您的更改(您的提交)的解决方案是另一个可行的解决方案。


更长的版本:

假设您记得,或者您可以通过检查源代码和/或使用 git 命令找到您下载快照的存储库的修订版,并开始本地开发。让我们将此修订称为 START 或 A。

假设您本地断开连接的历史记录在原始存储库的克隆中。这意味着您的本地断开连接的开发与项目的完整历史记录在同一个存储库中。假设您的本地分支位于分支“master”中(为简单起见,只有一个分支)。

如果您没有使用本地断开连接的工作将项目提取到存储库中,您可以这样做:

$ git remote add origin git://github.com/mojombo/mojombo.github.com.git
$ git fetch origin

历史现在如下所示:

*---*---*---*---*---A---*---*---*---* <--- origin/master(远程跟踪分支)

                                     x---y---*---*---* <--- master(你的本地断开连接历史)

上图中名为 A 的提交是您作为快照下载并开始本地开发的 START 提交。

有两种可能性:您已将“A”的快照作为初始提交“x”提交,或者您所做的第一次提交是本地修改。

在第一种情况下(您提交了原始起始状态,例如“初始提交”或“导入”),您希望连接的历史看起来像这样:

*---*---*---*---*---A---*---*---*---* <--- origin/master(远程跟踪分支)
                                      \
                                        \-y---*---*---* <--- master(你的本地断开连接历史)

即你的第一个原始提交'y'让'A'作为父母。

在第二种情况下(您提交了更改),您希望连接的历史看起来像这样:

*---*---*---*---*---A---*---*---*---* <--- origin/master(远程跟踪分支)
                                      \
                                        \-x---y---*---*---* <--- master(你的本地断开连接历史)

即,您希望首先提交“x”以将“A”作为父级。

在这两种情况下,您都希望找到提交“A”的完整 SHA-1 标识符,以及提交“x”和“y”的完整 SHA-1 标识符。

您可以使用git rev-parse找到提交“A”的 SHA-1(假设您还不知道):

$ git rev-parse A     # or A^{commit}
437b1b20df4b356c9342dac8d38849f24ef44f27

(可能需要 '^{commit}' 后缀来确保您找到提交SHA-1,例如,如果您通过其标签知道“A”,例如“v0.99”,这很重要;在您的情况下,它是没有必要,因为有问题的存储库不使用标签)。

您可以使用git rev-list找到提交“x”和“y”的 SHA-1 (假设您的开发是在分支“master”上完成的):

$ git rev-list --topo-order master | tail -2
8bc9a0c769ac1df7820f2dbf8f7b7d64835e3c68
e83c5163316f89bfbde7d9ab23ca2e25604af290

(“ | tail -2”在这里是为了在生成的列表中找到最后两个提交;如果你没有它,你不需要使用它)。

注意: 在上面的所有示例中,完整的 SHA-1 都是示例,不应按原样使用!

让我们将您希望将“A”(或“START”)作为父级的提交命名为 FIRST(根据您的情况,它将是“x”或“y”,如上所述)。现在我们使用移植机制连接历史:

$ echo "<SHA-1 of FIRST> <SHA-1 of START>" > .git/info/grafts

然后你应该检查你现在是否已经正确连接(加入)历史,通过使用图形历史浏览器,如 gitk,或 QGit,或 GitX,你是在 MacOS X 上,甚至是“ git log --graph”,或“ git show-branch”,例如:

$ gitk master origin/master    # or --all

(此处 gitk 仅作为示例;如果您使用“ git show branch”,则并不总是可以使用 ' --all' 选项)。

最后,我们可能希望使这些更改永久化,因此从我们的存储库中获取的任何人也将具有关联的历史记录。我们可以使用git filter-branch来做到这一点:

$ git filter-branch master

您将在“refs/original/master”中拥有原始(断开连接的)历史记录。

现在您可以删除移植文件:

$ rm .git/info/grafts

现在您将能够合并原始存储库的新开发:

$ git merge origin/master

设置每个分支的配置,以便在分支'master'上拉(合并)原始(al)存储库中的更改时只需执行“git pull”就足够了,留给读者练习......: - )


注意: rebase 解决方案将导致以下历史记录(假设我们有第一次提交是简单导入的情况):

*---*---*---*---*---A---*---*---*---* <--- origin/master(远程跟踪分支)
                                                                     \
                                                                       \-y'---*'---*'---*' <--- master(你的本地断开连接历史)

(其中y'意味着提交y被修改:它应该是相同的变更集,但它与提交不同)。

于 2009-09-22T08:09:58.097 回答
6

当我尝试git pull时,它给了我以下错误:

$ git pull grid master:master
! [rejected]        master     -> master  (non fast forward)

在我的特殊情况下,这似乎git rebase是我要走的路,如下面的步骤所示:

#Clone my forked project from github
git clone git@github.com:program247365/mojombo.github.com.git 

#Add my repo as a remote repo, with the alias 'grid'
git remote add grid "path/to/remote/gitrep/with/all/history/unrelated/to/mojombo/" 

#Rebase my commits on top of mojombo's
git rebase master grid/master

#Switch to the local master branch 
git checkout master

#Call up my mergetool via git, to start rectifying the conflicts that emerge between my repo, and mojombo's
git mergetool

#Push my rebased/combined repo back to Github.com
git push github
于 2009-09-22T04:13:14.423 回答
4

这里有一个关于你能做什么的想法。这与您在问题底部总结的想法相反。

  1. Fork mojombo 在 GitHub 中的存储库。
  2. 克隆您的分叉副本。
  3. 合并现有(原始)存储库中的更改。
  4. 删除您的原始存储库(如果需要,但您不再需要它)。

所以基本上,在 GitHub 上 fork 之后,您可能会使用以下命令序列:

$ git clone git://github.com/$YOUR_USERNAME/$YOUR_PROJECT.git  # Clone your GitHub fork (#2 from above)
$ git pull /path/to/your/original/repo master:master           # Clone your original repo's master branch into your new repo (cloned from GitHub)
$ rm -rf /path/to/your/original/repo                           # Might as well delete the original -- you don't need it anymore, since all your history is in your new repo

总之,此方法将合并您在旧存储库中所做的所有更改(从而保留您的开发历史),同时还提取 mojombo 的历史,允许您跟上 mojombo 的更改/轻松地将更改贡献回他的回购,如果适用的话。

于 2009-09-21T22:48:38.953 回答