### 仓库的使用问题
很多时候我们需要构建复杂的项目,项目又可能依赖其它项目,同时还需要将其它仓库作为子模块的一些复杂情况。
下面我们就来说说实际中的一些复杂的情况。
比如钉钉项目那个,我们基于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)
- 说明
- git配置
- git与github的关系
- 基础概念
- git命令
- git init
- git status
- git diff
- git log
- git reflog
- git add
- git commit
- git reset
- git checkout
- git rm
- git stash
- git remote
- git push
- git clone
- git branch
- git fetch
- git merge
- git rebase
- git pull
- git tag
- 建立版本库
- 分支合并
- 远程库别名
- Pull requests
- 扩展知识
- 功能文件
- 差异看法
- 注意细节
- github移动端
- git工作系统理解
- 仓库嵌套问题
- 仓库的使用问题
- 常用命令
- 学习资料
- 学习总结
- 示例文件
- README.md
- CONTRIBUTING.md
- .gitignore
- coding
- 大小写问题
- 如何贡献
- 使用账号密码clone
- git目录分析
- HEAD
- 代码部署问题
- 开发流程
- 指定公钥文件