ThinkChat2.0新版上线,更智能更精彩,支持会话、画图、阅读、搜索等,送10W Token,即刻开启你的AI之旅 广告
### 仓库的使用问题 很多时候我们需要构建复杂的项目,项目又可能依赖其它项目,同时还需要将其它仓库作为子模块的一些复杂情况。 下面我们就来说说实际中的一些复杂的情况。 比如钉钉项目那个,我们基于think应用开发,同时基于thinkPHP框架,并且需要钉钉SDK。 **需求分析** - 我们项目组织结构基于think - 这个是个应用目录,不是最主要的核心框架,但是我们可能也想要与原仓库保持一些同步 - 我们会有基于自己应用的修改,并且有密码配置的隐私内容 - 我也希望为原项目贡献代码,但是可能意愿并不是很大,因为我们主要是基于此做自己的开发 - 我们不希望自己的这个项目仓库有原think的历史(提交记录),而是从自己的first commit开始 - 我们应用基于thinkPHP框架 - 我们希望框架能够与原仓库保持同步以获得安全性,但不排除会自己修改 - 我们希望能贡献代码 - 钉钉SDK(一开始我们将它放在public下单独测试用) - 我们想要与原仓库保持同步,但不排除会自己修改 - 我们会有基于自己应用的修改,并且有密码配置的隐私内容 - 我们希望能贡献代码 ### 讨论 >[danger] 这里有一个地方需要搞清楚的是,如果你对仓库需要修改,那么这个修改是你要为仓库做贡献的还是只是自己用的。这点需要搞清楚。 1 >[danger] 比如你发现仓库类库有点不完善地方你做修改后推送到自己fork的那个仓库,然后你会想对原仓库发起Pull requests来让别人拉取你的提交,别人同意后你就会出现在贡献者名单,这也是为开源项目贡献代码基础的流程。 2 >[danger] 你应该发现了一个规律,只要是想做贡献的那部分修改,你就推到你fork的那个仓库上去就可以了。换句话说,你fork的那个仓库上所有内容都是表示你要想要做的贡献,即使你没这样想,也只是认为你只是迟迟没有Pull requests而已,fork的意义就在于贡献代码。当然了,如果你真的不是这样想的,那么你可能是想基于别人的项目开发出自己的版本(不过fork来自己折腾,又不PR,自娱自乐,自立门户,这样不好吧),否则的话你最好不要fork。 3 >[danger] 或者你fork别人的项目后再创建一个你自己的开发分支,在上面进行开发也行(但其实分支的归属意义也是合并),所以这样没有意义,只要fork了,就说明你想为开源项目做贡献,如果不是这样,那你不是可能,而是一定用错了fork,说明你规划失误了。 ~~~ 而如果你只是需要对一些配置文件进行修改,你知道这些修改是没必要推送到你fork的仓库上去的(肯定没必要啊,你的配置又不是要做的贡献),并且你也不希望这些文件公开,那么最好的方式将这些文件是加入到.gitignore文件中去,这样修改就不会被跟踪,不会被提交,不过注意.gitignore这个文件本身也是不想成为贡献的哦,所以要忽略它本身。不过.gitignore的处理其实有时候还有点麻烦,参见[功能文件](http://www.kancloud.cn/xiak/github/216977),如果我们这样做的话,那么这些修改都只会在我们本地的工作区中,如果远程有新的提交pull时有冲突的需要我们手动的去解决下。 不要再理会这段话,之前写这段话的意思情况是,我们fork think仓库,然后在此fork的项目上开发应用,呵呵,我们会这样做的,fork有它自己的本分,我们开发跟它有什么关系,再说自己开发姓名中出现别人以前的提交记录,什么东西啊,乱七八糟的,所以呵呵了。 ~~~ >[info] **上面说得都是一般情况,我们可以借鉴参考,实际中可能有些不同。但记住fork的初心是为了PR,为了开源软件的不断发展。** * * * * * ### 引申思考 [Git@OSC 私有库已支持 Fork 和 Pull Requests](http://www.oschina.net/news/59065/gitosc-private-project-support-fork-and-pull-requests) 完全可以将别人的仓库代码克隆到本地后,再重新建个仓库推送到自己项目中。(这样的话会保留原项目的提交历史,并且现在进行“我的第一次提交(这个项目成了我的后的首次你提交)”就会出现下面的效果) >[danger] 这么来看的话,fork的作用其实就是关联项目,最终是为了PR、协作开发,因为如果你不通过fork而直接像上面那样将别人项目推到自己的仓库中基本和fork的仓库是一样的,只是你的项目就和原项目没有关联了,你就不能PR了。 fork还有一个用处,那就是可能暂时我们没有能力或者精力去贡献开源项目,但是我们也可以fork一份,有时开源项目更新过快,你不想尝试新的特性,想留在较为稳定的版本,那么你fork一份就相当于是为你自己保留一份,以后用的时候可以直接使用你这个fork的,这样在原项目不稳定时,你就可以放心的用这个了,等时机成熟,你在拉一个反方向的pull,来更新你fork的这个仓库,以保持更新,当然这取决于你。 * * * * * ### 深入讨论 看完了需求,经过讨论,……,别急,我们先不讨论怎么组织规划项目最好,先回顾一下一些基本的知识: - 如果需要贡献代码,那就fork,然后开发,最后Pull requests - 如果需要从first commit开始那就自己git init,这样才能甩掉别人的提交历史 - 如果需要同步那就pull - 如果是隐私的内容就不要推到公开的仓库上去 - 如果是商业项目不希望公开的最好创建私有仓库 那么现在关于钉钉这个项目的仓库规划问题就非常明了了: 1. think这个原始仓库我们不要,删除.git,开始初始化我们自己的仓库。 2. 与我们远端的项目仓库关联,first commit,推送。 > 如果以后think仓库有我们不想错过的更新怎么办呢? 很简单为我们的项目仓库添加一个upstream别名的远程仓库链接指向think仓库就可以了(think可以是任意公开仓库,也可能是你fork的那个,也可能是原仓库,关于用哪个其实看你自己了,如果你比较保守那么用你fork的,因为你不知道新的特性会不会对你的项目造成影响,而如果你比较激进,则大可不必担心这些问题,直接用原仓库吧,以保持和最新的同步,这同时代表更安全,但也可能存在潜在的风险),当你想要保持同步时直接pull upstream master 就可以了,如果有冲突的地方则需要我们去解决下。(想法很美好,然而这样会报错:“拒绝合并历史无关”,下面有会继续探讨,还有实验证明) thinkPHP框架我们手动git安装吧,用原仓库还是你fork的那个还是看你自己,如果你做了某些修改,pull有冲突时需要你去解决,不过不建议你修改,如果你修改了最好是Pull requests看一下能否得到认可,不然那就不好了,不要被孤立,一定不要这样做,尤其是在生产环境,不然很危险。(新手才会去随便改框架) * * * * * >[danger] 对于我目前来说,项目仓库其实可以分为四类: 1. 我们自己的应用仓库 2. 他人开源的项目仓库 3. 我fork的他人开源项目仓库 4. 我自己的开源项目仓库(和应用仓库相同,但是意义不同) 第一种比较特殊,我们只是把它当做版本管理的工具在使用了,通常来说它并不需要去和谁发生Pull requests。 后三种则是纯粹的开源项目,可能被其他应用项目所引用,也可能被其他开源项目所引用。就我们这个钉钉项目的话,明显属于第一种。 >[info] 也可以分为两大类,一类是我们自己的应用仓库,一类是开源的项目仓库(包括别人的也包括自己的,同时自己的又分为fork的和非fork的)。 >[danger] **再次重申一下fork的作用就是讲仓库/项目关联起来,它的意义是为了PR,为了开源软件的长久发展。** 对于第一种应用仓库来说,它的远程地址很多时候只是充当一个存储地址在使用了。我们可以放心地在这上面提交,因为它是我们自己的。 而对于后者开源仓库来说,我们则不能这么随意了。你每次push都表示有一定的意义。 比如我们修改thinkPHP框架,你是想贡献吗,那就push到你fork的仓库上去,然后再Pull requests,比如我们修改钉钉SDK你是想贡献吗,同上,如果不是,只是测试用,需要修改配置文件,如果你压根没想要参与贡献,那你就无需fork了。 **注意:对于非想要贡献的部分记得不要push到你fork的仓库上去。比如配置文件之类的,你可以将其添加到.gitignore去。** **问:**如果直接先克隆别人仓库,再添加远程别名,然后往自己github新建的仓库中提交会使什么后果? **答:**可以是可以,这个仓库就像是第四种类型,**但是有点特殊**,因为它还有之前原仓库的历史(不仅仅是提交历史,还有贡献记录等其它信息,这些在github上都可以看得出来,有洁癖的人真受不了这样的)。*(记住这种特殊的情况,下面我们还将会继续讨论到它)* **问:**如果再克隆这个特殊的仓库呢? **答:**git remote -v 发现并不包含之前添加的别名了,所以说明仓库其实只是一个托管的平台而已,本身并不包含源,只是克隆时下来默认加一个源而已。 **下面看看这种特殊仓库,不伦不类的仓库:** * * * * * 这次提交怎么来的啊,明明前面有提交,原仓库的提交,但是我第一次提交后这个提交就显示没有父提交了 ![](https://box.kancloud.cn/830ac966e7005e494e825b2a18fa9883_1016x119.png) 并且也还是显示这些文件是由本次提交创建的,而显然不是我创建的。 ![](https://box.kancloud.cn/21ee2bf9f6c18dce3bb1761e317f2965_1041x278.png) 不过也是的,毕竟我这次的第一次提交和之前原仓库的提交没什么关系,我是直接将别人的仓库克隆古来,推送到了我的仓库地址,这个仓库是我的,但是还保留原来的提交记录,这些提交记录不是我的,而我的“第一次”,确实是基于别人的提交,但是GitHub这里显示没有父提交,也说得通。 又试了,并没有出现这种奇怪的情况,提交是正常的,不过上面这个仓库的确是出现了这样的情况,哎,搞不清楚,反正别用这种恶心的东西就是的了。(可能是我们删除原.git目录后又初始化了仓库,然后又恢复了.git,哎,搞不清楚,总之不要再用这种恶心的东西就好了) * * * * * ## 扩展知识 **要贡献代码就fork别人的仓库** 要基于别人的仓库开发自己的应用,比如基于top-think/think,那么最好是克隆此仓库,然后删除它的.git,因为我们的应用并不想要它的这些提交记录,然后基于此初始化仓库,再提交,再push到我们的远程仓库。这样仓库就变成我们的了,**彻底的变成我们的了**,提交历史看上去也是从我们 first commit 开始的,没有别人的历史记录了,现在完完全全成了我们自己的仓库了。但这又有一个问题,如果top-think/think项目更新了,我们怎么保持跟进呢,其实有一个好办法,那就是: (莫被忽悠,下面代码是猜想) ~~~ git remote add think-origin https://github.com/top-think/think.git ~~~ 添加一个远程的仓库,然后想更新是拉取就可以了。 ~~~ git pull think-origin master ~~~ >[default] 这种方法其实是解决 [github上,我如果fork了别人的项目, 进行了改动。。 原版更新了。。 我要合并他的最新版使用rebase吗?](https://segmentfault.com/q/1010000002457936)这个问题的。 --- **呵呵,上面只是猜想,人家那样做是解决fork仓库与原仓库同步的问题,你以为呢?** 测试了,pull失败,这种办法还是只适用于fork别人的项目,**不适用于我们基于别人的项目创建自己的,还要与别人的保持对比,更新**。 既然要从自己开始那么就彻底,**既然断了(你都已经删了原.git,另起炉灶了),就不要在与原仓库有关系**,**如果想获得保持与原仓库同步,那么就请自己去关注原项目的进展,根据实际情况,自己在手动修改本项目吧,不要在跟原项目有关系了。** 其实:有人说这种情况也可以克隆top-think/think,然后建一个我们的分支app然后,我们应用在app分支开发,并将app分支推送到我们的远程仓库就可以了。**但是别忘了这样在app分支下git log中还是有原来仓库的提交历史的哦**(毕竟分支的起点在那里)。对于我们自己的应用来说,这可不是我们想要你的,**我们想要我们从自己的first commit开始自己的征途,再到星辰大海。** **下面来进行试验:** ~~~ $ git pull think-origin master warning: no common commits remote: Counting objects: 13208, done. remote: Compressing objects: 100% (13/13), done. remote: Total 13208 (delta 127), reused 126 (delta 126), pack-reused 13069 Receiving objects: 100% (13208/13208), 5.99 MiB | 22.00 KiB/s, done. Resolving deltas: 100% (7999/7999), done. From https://github.com/top-think/think * branch master -> FETCH_HEAD * [new branch] master -> think-origin/master fatal: refusing to merge unrelated histories ~~~ ~~~ git pull think-origin美元的主人 警告:没有共同提交 远程:计数对象:13208年,完成了。 远程:压缩对象:100%(13/13),完成。 远程:总数13208(三角洲127),再利用126(三角洲126),pack-reused 13069 接收对象:100%(13208/13208),5.99 MiB | 22.00简约/ s,完成。 解决增量:100%(7999/7999),完成。 从https://github.com/top-think/think *主- > FETCH_HEAD分支 *(分公司)的主人- > think-origin /主人 致命:拒绝联合国合并 ~~~ ~~~ $ git clone https://github.com/top-think/think.git Cloning into 'think'... remote: Counting objects: 13213, done. remote: Total 13213 (delta 0), reused 0 (delta 0), pack-reused 13213 Receiving objects: 100% (13213/13213), 6.11 MiB | 252.00 KiB/s, done. Resolving deltas: 100% (7918/7918), done. $cd think $rm -rf .git $git init Initialized empty Git repository in C:/Users/Administrator/Desktop/think/.git/ $git add . $git ci -am 'first commit' $git remote add think-origin https://github.com/top-think/think.git $ git pull think-origin master fatal: refusing to merge unrelated histories ~~~ **看来猜想是错的,这样还是两个无关的仓库啊,看来想基于think创建自己的应用仓库,并且还想与think保持同步,是不能的啊。没办法,既然脱离了就回不去了,只能自己关注think的进展,自己手动更新维护应用仓库吧。** **疑问?** git到底是怎么认为两个仓库无关的呢? 显然不是简单对比文件,因为克隆的也是和原仓库文件一样的,错误说明已经说的很清楚了:**“拒绝合并历史无关”**。**而如果是fork的仓库,或者是那种带别人历史的特殊仓库,就满足“历史相关”了(试验证明可以),这也再次说明了fork的仓库和那种直接将别人的项目克隆推到自己仓库的项目基本一样**,没有什么区别,**唯一的区别就是fork多了一个关联的属性**,不过这种特殊的仓库也显得**不伦不类**,有洁癖的人受不了这种。(必须强制地杜绝出现有这种不伦不类的情况,坚决抵制这种,好恶心。) 2016-12-20 01:35:43 ### 其他问题 coding速度比GitHub快些,我想同时将仓库推送到coding和GitHub上去怎么做呢?这很好办,[有没有办法同步 Coding 与 GitHub](https://segmentfault.com/q/1010000000172591)