### 倉庫的使用問題
很多時候我們需要構建復雜的項目,項目又可能依賴其它項目,同時還需要將其它倉庫作為子模塊的一些復雜情況。
下面我們就來說說實際中的一些復雜的情況。
比如釘釘項目那個,我們基于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.hmoore.net/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 發現并不包含之前添加的別名了,所以說明倉庫其實只是一個托管的平臺而已,本身并不包含源,只是克隆時下來默認加一個源而已。
**下面看看這種特殊倉庫,不倫不類的倉庫:**
* * * * *
這次提交怎么來的啊,明明前面有提交,原倉庫的提交,但是我第一次提交后這個提交就顯示沒有父提交了

并且也還是顯示這些文件是由本次提交創建的,而顯然不是我創建的。

不過也是的,畢竟我這次的第一次提交和之前原倉庫的提交沒什么關系,我是直接將別人的倉庫克隆古來,推送到了我的倉庫地址,這個倉庫是我的,但是還保留原來的提交記錄,這些提交記錄不是我的,而我的“第一次”,確實是基于別人的提交,但是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
- 代碼部署問題
- 開發流程
- 指定公鑰文件