只使用本地存储库历史logging的子集创buildGitHub存储库

背景:我正在接近开放采购我已经工作了两年多的个人研究代码 。 它开始作为一个SVN存储库的生活,但我大约一年前转移到Git,我想分享GitHub上的代码。 但是,这些年来积累了很多的东西,我宁愿让公众的版本在现在的状态下开始。 不过,我仍然想为此作出贡献,并纳入其他人的潜在贡献。

问题是:有没有办法“分叉”一个git仓库,以便叉子上没有历史logging(它位于GitHub上),但是我的本地仓库仍然有完整的历史logging,我可以把/推到GitHub上?

我没有任何关于大型软件仓库pipe理的经验,所以非常感谢。

您可以在Git中轻松创build新的历史logging。 假设你想让你的master分支成为你将要推送给GitHub的分支,并且你的完整历史将被存储在old-master 。 你可以移动你的master分支到old-master ,然后启动一个新的分支没有历史使用git checkout --orphan

 git branch -m master old-master git checkout --orphan master git commit -m "Import clean version of my code" 

现在你有一个没有历史的新的master分支,你可以推送到GitHub。 但是,正如你所说,你希望能够看到你的本地存储库中的所有旧的历史logging; 并可能希望它不被断开连接。

你可以使用git replace来做到这一点。 replaceref是Git查看给定提交时指定备用提交的一种方式。 因此,在查看历史logging时,可以让Git查看旧分支的最后一个提交,而不是新分支的第一个提交。 为了做到这一点,你需要从旧的回购引入断开的历史。

 git replace master old-master 

现在你有了新的分支,你可以在其中看到你所有的历史,但是实际的提交对象与旧的历史logging是断开的,所以你可以把新的提交推送到GitHub而不需要提交旧的提交。 推你的master分支GitHub,只有新的提交将GitHub。 但是看看gitkgit log中的历史git log ,你会看到完整的历史logging。

 git push github master:master gitk --all 

陷阱

如果你曾经在旧的提交中build立任何新的分支,你将必须小心保持历史分开; 否则,在这些分支上的新提交实际上会有旧的提交,所以如果你把它提交给GitHub的话,你会把整个历史一起拉下来。 只要你保留所有基于你的新master新的提交,你会没事的。

如果你曾经运行过git push --tags github ,那么你的所有标签(包括旧标签)都会被推送,这将会导致你的所有旧的历史logging被一并拉走。 你可以通过删除所有的旧标签( git tag -d $(git tag -l) )来处理这个问题,或者从不使用git push --tags而只是手动推送标签,或者使用如下所述的两个存储库。

这两个问题的基本问题是,如果你推任何连接到任何旧历史的ref(除了通过被replace的提交),你将会推高所有的旧历史。 可能避免这种情况的最好办法是使用两个存储库,一个只包含新的提交,一个包含新旧历史的存储库,以便查看完整的历史logging。 你做所有的工作,你的承诺,你从GitHub的推动和拉动,只有新的提交回购; 这样,你不可能不小心推动你的旧提交。 然后,当您需要查看整个事件时,您将所有新的提交拖入具有完整历史logging的回购。 您可以从GitHub或您的其他本地回购,以较方便的方式。 这将是你的档案,但为了避免意外地发布你的旧历史,你永远不会推它到GitHub。 以下是您可以设置的方法:

 〜$ mkdir newrepo
 〜$ cd newrepo
 newrepo $ git init
 newrepo $ git pull〜/ oldrepo master
 #现在newrepo只是新的历史; 我们可以设置oldrepo从它拉
 newrepo $ cd〜/ oldrepo
 oldrepo $ git remote add newrepo〜/ newrepo
 oldrepo $ git远程更新
 oldrepo $ git branch --set-upstream master newrepo / master
 #...在newrepo中工作,提交,推送到GitHub等
 #现在,如果我们想看看oldrepo的完整历史:
 oldrepo $ git pull

如果你使用1.7.2以上的Git

你没有git checkout --orphan ,所以你必须通过从当前版本库的当前版本创build一个新的版本库,然后拉入旧的断开连接的历史logging来手工完成。 你可以这样做,例如:

 oldrepo $ mkdir〜/ newrepo
 oldrepo $ cp $(git ls-files)〜/ newrepo
 oldrepo $ cd〜/ newrepo
 newrepo $ git init
 newrepo $ git add。
 newrepo $ git commit -m“导入我的代码的干净的版本”
 newrepo $ git fetch〜/ oldrepo master:old-master

如果你在Git 1.6.5以上

在1.6.5中添加了git replace和replace ref,所以你必须使用一个较老的,不太灵活的机制,称为嫁接(grafts) ,它允许你为给定的提交指定备用父节点。 而不是git replace命令,运行:

 echo $(git rev-parse master) $(git rev-parse old-master) >> .git/info/grafts 

这将使得它在本地看起来好像master提交具有old-master提交作为它的父代,所以你会看到比git replace更多的提交。

上面Brian的回答似乎是完整的,知识丰富,但有点复杂。

easy(ier)解决scheme将保留两个存储库。

您正在使用的私人github存储库。 你将所有的历史logging都推送到这个存储库。

第二个存储库是一个公共的github存储库,只有当你想向公众发布一个新的版本时才会发布到这个存储库。 您通过使用简单的diff +补丁发布到它,然后提交+推。

一个非常简单而有趣的做法如下 –

假设你在REPO-A提交C1到C10,其中C1是最初的提交,而C10是最新的HEAD。 你想创build一个新的REPO-B,这样它就提交了C4到C8(一个子集)。

注意:使用这个方法会改变提交SHA(例如:在这个例子中是C4'到C8'),但是每个提交保持的改变将保持不变,现在你的第一次提交将以你之前提交的所有改变开始,直到那个点结合。

该怎么办?


recursion地将所有内容复制到本地机器上

 cp -R REPO-A REPO-B 

可以select从您的REPO-B中删除所有遥控器,因为大多数情况下您可能想将其作为单独的存储库使用。

 cd REPO-B git remote -v git remote remove REMOTE_NAME 

强制将分支指针移动到子集的后端。 对于C8到C8的C8。 但很可能你需要子集直到HEAD(例如:从C4到C10或C6到C10),在这种情况下,不需要下面的步骤。

 git checkout -b temp git branch -f master C8 git checkout master git branch -D temp 

在文件.git/info/grafts目录中input子集的前一个末尾的提交SHA。 在这种情况下,它是提交C4的SHA。

 git rev-parse --verify C4 >> .git/info/grafts 

做一个没有任何参数的git分支过滤

 git filter-branch 

或者这不起作用

 git filter-branch --all 

现在,您可以将其推送到单独的/新的远程,如果你想

 git remote add origin NEWREMOTE git push -u origin master 

怎么运行的?


这个链接告诉你它是如何真正起作用的 – http://git.661346.n2.nabble.com/how-to-delete-the-entire-history-before-a-certain-commit-td5000540.html

你可以在git-filter-branch(1)手册页,gitrepository-layout(5)git repository布局描述和gitglossary(7)git词汇表中阅读关于移植的信息。

简而言之,.git / info / grafts中的每一行都由sha1对象的id组成,后面是空格分隔的有效(嫁接)父对象列表。 因此,例如在提交a3eb250f996bf5e之后,要删除历史logging,您需要在.git / info / grafts文件中放置仅包含此SHA-1的行,例如:

$ git rev-parse –verify a3eb250f996bf5e >> .git / info / grafts