- 原文地址:Learn git concepts, not commands
- 原文做者:Nico Riedmann
- 譯文出自:掘金翻譯計劃
- 本文永久連接:github.com/xitu/gold-m…
- 譯者:Mirosalva
- 校對者:shixi-li,Moonliujk
用交互式的教程教你 Git 的原理,而非羅列經常使用命令。html
因此,你想正確地使用 Git 嗎?前端
但你確定不想僅僅學一些操做命令,你還想要理解其背後的原理,對吧?android
那麼本文就是爲你量身定作的!ios
讓咱們快點開動吧!git
本文的落筆點基於 Rachel M. Carmena 撰寫的 如何教授 Git 一文中說起的常規概念。github
網上有不少重方法輕原理的 Git 教程,但我仍是挖掘到了兼得兩者的寶貴資源(也是本教程的靈感源泉),那就是 git Book 和 Reference page。後端
所以,若是你讀完了本文還意猶未盡,就快點擊上面兩個連接一探究竟吧!我真心但願本教程中介紹的概念,能幫你理解另外兩篇文章中詳解的其餘 Git 功能bash
建議按照順序閱讀本系列文章:app
咱們全部人通常都會工做在分支上,咱們須要討論下如何經過合併來從一個分支上獲取變動到另外一個分支上。編輯器
咱們剛在 change_alice
分支上修改了 Alice.txt
,我想說咱們對所作的改變感到滿意。
若是你接着執行 git checkout master
命令,那麼咱們在其餘分支上建立的 提交
沒法在此看到爲了將變動弄到 master 分支,咱們須要 合併
change_alice
分支到 master 分支上。
注意:你老是將某個分支 合併
到當前分支。
既然咱們已經執行了 checked out
來切換到 master 分支,如今咱們能夠執行 git merge change_alice
合併命令。
因爲 Alice.txt
並無其餘衝突變動,咱們在 master 分支未作修改,所以合併將在所謂的快進合併中進行。
在下面的圖表中,咱們能夠看到,這僅僅意味着:master 的指針會被簡單地前進到 change_alice 分支存在的位置。
第一張圖顯示了咱們執行 合併
前的狀態,master 指針仍處於它以前的提交位置,同時另外一個分支上咱們又作了一次提交。
第二張圖顯示了在咱們 合併
以後發生了什麼變化。
讓咱們試一些更復雜的。
在 master 分支的 Bob.txt
文件新行中添加一些文字,而後提交它。
接着執行 git checkout change_alice
命令,改變 Alice.txt
文件並提交。
在下圖中,你能夠看到咱們的提交歷史如今的樣子。master 和 change_alice
分支都源於同一個提交,但那以後它們發生了分歧 ,每一個分支都有本身額外的提交。
若是你如今使用命令 git merge change_alice
來執行一個快進合併是不可能的了。取代它的是,你最愛的文本編輯器將會打開,而且容許你修改 合併提交
操做的提交信息,git 即將執行這個提交從而將兩個分支從新保持一致。你如今使用默認提交信息就行。下圖顯示了咱們在執行 合併
後的 git 歷史狀態。
新的提交將咱們在 change_alice
分支上的修改引入到 master 分支。
正如你以前記得那樣,git 中的修訂不只僅是文件的快照,還包含了它們來自何處的一些信息。每次 提交
都包含一個或多個父級提交信息。咱們的新 合併
提交包含了 master 分支的最後提交,以及咱們在另外一個分支上的提交來做爲此次合併的父級提交。
目前爲止,咱們的修改都沒有相互干擾。
讓咱們介紹一種衝突,而後解決它。
建立一個新分支,而後將它 檢出
。你知道如何操做,不過或許可使用 git checkout -b
命令爲你減小麻煩。
我把它命名爲 bobby_branch
。
在這個分支上,咱們會修改 Bob.txt
文件。
第一行應該仍然是 Hi!! I'm Bob. I'm new here.
,把它修改爲 Hi!! I'm Bobby. I'm new here.
。
暫存文件以後,在你再次 檢出
master 分支以前,提交
你的修改。在 master 分支咱們將同一行修改成 Hi!! I'm Bob. I've been here for a while now.
,接着 提交
該修改。
如今是將新分支 合併
到 master 的時候了。
若是你嘗試這麼作,你將會看到以下的結果:
Auto-merging Bob.txt
CONFLICT (content): Merge conflict in Bob.txt
Automatic merge failed; fix conflicts and then commit the result.
複製代碼
兩個分支都修改了同一行,此時 git 工具沒法本身徹底處理這種狀況。
若是你運行 git status
命令,你會獲取到用來指導接下來如何繼續的全部常見幫助命令。
首先咱們必須手動解決衝突。
對於像這個簡單衝突來講,你最喜好的文本編輯器就夠用了。而對於合併含有不少變化的多個文件來講,使用更強大的工具會讓你輕鬆很多,我建議選用包含版本控制工具,具備友好合並界面的你最喜好的 IDE。
若是你打開 Bob.txt
文件,你會看到一些相似下面的內容(我已經截斷了以前可能放在第二行的其餘內容):
<<<<<<< HEAD
Hi! I'm Bob. I've been here for a while now.
=======
Hi! I'm Bobby. I'm new here.
>>>>>>> bobby_branch
[...你在第 2 行傳入的隨便什麼內容]
複製代碼
在上面你能夠看到當前 HEAD 上 Bob.txt
發生的變化,在下面你能夠看到咱們正嘗試合併進來的分支所作的更改。
爲了手工解決衝突,你只須要確保文件最終保留一些合理內容,而不包含 git 引入文件的特殊行。
因此繼續修改文件爲下面這種內容:
Hi! I'm Bobby. I've been here for a while now.
[...]
複製代碼
從這裏開始,咱們即將要作的事是適用於任何變動。
在咱們執行 add Bob.txt
添加文件後,暫存這些變動,而後執行 提交
。
咱們已經瞭解爲解決衝突所作的變動提交,就是合併過程當中一直都有的合併提交。
實際上你應該意識到在解決衝突的過程當中,若是你不想繼續 合併
進程,你能夠經過運行 git merge --abort
命令直接 停止
它。
Git 有另一種純淨方式來集成兩個分支的變化,叫作 變基
。
咱們始終記得一個分支老是基於另一個分支。當你建立它時,從某處開始分叉。
在咱們簡單的合併樣例中,咱們從 master 分支的某次提交建立了一個分支,而後提交了在 master 和 change_alice
分別提交了一些變動。
當一個分支相對於它所基於的分支產生了改變,若是你想要把最新的變動整合到你當前的分支,變基
提供了一種比 合併
更加純淨的處理方式。
正如你所看到的,一次 合併
引入了一個合併提交,這個過程當中兩邊的歷史記錄獲得整合。
很容易看得出,變基僅僅改變了你的分支所依賴的歷史記錄點(建立分支所基於的某次提交)。
爲了嘗試這一點,咱們首先將 master 分支再次檢出,而後基於它來建立/檢出一個新分支。
我稱本身的新分支爲 add_patrick
,而後我添加了一個新文件 Patrick.txt
,而後以信息 「Add Patrick」 提交了該文件。
在你爲該分支添加了一條提交後,返回 master 分支,作一點修改而後提交它。我作的修改是爲 Alice.txt
文件多加了一些文本。
就像咱們合併樣例中那樣,兩個分支有公共祖先,然而歷史是不一樣的,你能夠從下圖中看出:
如今讓咱們再執行 checkout add_patrick
命令,而後把 master 上作的修改獲取到咱們正在操做的分支上!
當咱們執行 git rebase master
命令,咱們讓 add_patrick
分支從新以當前狀態的 master 分支作了基準。
上面這條命令爲咱們提供了目前操做的友好提示:
First, rewinding head to replay your work on top of it...
Applying: Add Patrick
複製代碼
咱們知道 HEAD 是咱們所在的工做環境中當前提交的指針。
在變基操做執行以前,它的指向與 add_patrick
分支一致。發生了變基,它會首先移回到兩個分支的公共祖先,而後移動到咱們想要定爲基點的那個分支的當前頂點。
因此 HEAD 移動到 0cfc1d2 此次提交,而後到 7639f4b 此次提交,它是位於 master 分支的頂點。
而後變基操做會將咱們在 add_patrick
分支上作的每個提交都應用到那個頂點上。
爲了更精確瞭解 git 把 HEAD 指針移回到分支的公共祖先過程當中作了什麼,能夠把你在被操做的分支上每次提交都存儲一部分(修改的 差別點
、提交信息、做者等等。)。
在上面操做以後,你正在變基的分支須要 檢出
最新的提交,而後把存下的全部變化以一條新提交應用到前面的提交之上。
因此在咱們原先簡單的視圖中,咱們認爲在 變基
以後,0cfc1d2 此次提交再也不指向它歷史中原公共祖先,而是指向 master 分支的頂部。
事實上,0cfc1d2 此次提交消失了,而且 add_patrick
分支以一個新提交 0ccaba8 爲開始,它以 master 分支的最新提交做爲公共祖先。
咱們讓它看起來就像,add_patrick
分支是以當前 master 分支爲基點,而不是分支的較舊版本,不過咱們這樣作至關於重寫了該分支的歷史。
在本教程的末尾,咱們會多學習一些重寫歷史以及何時適宜和不適宜這麼作。
當你本身的工做分支是基於一個共享分支時,例如 master 分支,變基
是一種至關強大的工具。
使用變基操做,能夠確保你能常常整合別人提交到 master 分支的變動和推送,而且保證一條幹淨線性的歷史,在你的工做文本須要引入到共享分支時,這種歷史能夠作 快進合併
。
相對於包含合併提交的凌亂歷史,保持歷史的線性也可使提交日誌更加有用(試一下 git log --graph
,或者看一下 GitHub 或 GitLab 的分支視圖)。
就像 合併
過程當中,若是遇到兩次提交修改了一個文件中一樣位置的內容塊,你可能會遇到衝突。
然而當你在 變基
過程當中遇到衝突,你無需在額外的合併提交中解決它,卻能夠在當前正在執行的提交中解決它。
一樣地,將你的修改直接以原始分支的當前狀態爲基準。
事實上,你在 變基
過程當中的解決衝突操做很是相似你在 合併
中的操做,因此若是你不太肯定如何操做的話,能夠回過頭查看那個小節。
惟一的區別在於,因爲你沒有引入合併提交,因此不須要你提交衝突解決結果。只需添加變動到暫存環境,而後執行 git rebase --continue
命令。衝突將會在剛剛執行的提交中獲得解決。
當合並時,你一直均可以中止和丟棄目前你作的全部內容,經過執行 git rebase --abort
命令。
目前爲止,咱們已經學習瞭如何生成和共享內容變動。
若是你是獨自工做,這些已經夠用了。可是一般咱們是多人共同處理一項工做,而且咱們想要從遠程倉庫以某種方式獲取他們的變動到咱們本身的工做環境中。
因爲已通過了一段時間,讓咱們看一下 git 的組件:
就像你的工做環境,每一個工做在同一份源代碼的人都有他們本身的工做環境。
全部這些工做環境都有它們本身的進行中和暫存的變動,這些會在某個節點被 提交
到本地倉庫,最終 推送
到遠程倉庫。
咱們的例子中,咱們會使用 GitHub 提供的在線工具,來模擬在咱們工做時其餘人對遠程倉庫生成的變動。
查看你在 github.com 網上對這個倉庫的 fork 分支,打開 Alice.txt
文件。
找到編輯按鈕,經過網站來生成和提交一個變動。
在這個倉庫中,我已經在一個叫作 fetching_changes_sample
的分支上爲 Alice.txt
文件添加了一個遠程倉庫變動,可是在你的該倉庫版本,你固然能夠直接改變 master
分支上這個文件。
咱們還記得,當你執行 git push
命令時,會將本地倉庫的變動同步到遠程倉庫。
爲了獲取遠程倉庫中的變動到本地倉庫,你可使用 git fetch
命令。
這個操做獲取到遠程的任何變動到你的本地倉庫,包含提交和分支。
這點要注意,變動尚未被整合到本地分支,更不用說工做空間和暫存區域。
若是你如今執行 git status
命令,你會看到 git 命令的另外一個很棒的例子,告訴你如今正發生什麼:
git status
On branch fetching_changes_sample
Your branch is behind 'origin/fetching_changes_sample' by 1 commit, and can be fast-forwarded.
(use "git pull" to update your local branch)
複製代碼
因爲咱們沒有工做中和暫存的變動,咱們如今能夠執行 git pull
命令來從倉庫中拉取全部變動到咱們的工做空間。
拉取會隱式地
獲取
遠程倉庫,但有時候單獨執行獲取
是個好選擇。 例如,當你想要同步任何新的遠程分支,或者你想在像origin/master
這種分支上執行git rebase
以前,須要確保你的本地倉庫是最新的。
在咱們 拉取
以前,讓咱們本地修改一個文件來看會發生什麼。
讓咱們在工做空間再次修改 Alice.txt
文件!
若是你如今嘗試作一次 git pull
,你會看到以下錯誤:
git pull
Updating df3ad1d..418e6f0
error: Your local changes to the following files would be overwritten by merge:
Alice.txt
Please commit your changes or stash them before you merge.
Aborting
複製代碼
你沒法 拉取
任何變動,由於工做空間中有些文件被修改,同時你正在拉取進來的提交也有這些文件的變化。
這種狀況的一種解決方法是,爲了獲取你比較信任的某個點上的變動,在你最終提交它們以前,能夠把本地變動 添加
到暫存空間。可是在你最終提交它們以前,而這是學習另外一個很棒工具的一個好時機。
在任什麼時候刻若是你有一些本地變動,還不想放進一個提交中,或者想存在某個地方來以其餘某種角度來解決一個問題,你能夠將這些變動 儲藏
起來。
一次 git stash
基本上是一個變動的堆棧,這裏面你能夠存儲對工做空間的任何變動。
最經常使用的命令是:git stash
,它將對工做空間的任何修改儲藏起來。還有 git stash pop
命令,它拿到儲藏起來的最近修改,並將其再次應用到工做空間。
就如堆棧命令的命名,git stash pop
命令在應用變動以前,將最近存儲的變動移除。
若是你想保留儲藏的變動,你可使用 git stash apply
命令,這種方式不會在應用變動以前從儲藏中移除它們。
爲了檢查你當前的 儲藏
,你可使用 git stash list
命令來列出各個單獨的條目,還可使用 git stash show
命令來顯示 儲藏
中最近條目的變動。
另外一個好用的命令是
git stash branch {BRANCH NAME}
,它從當前的 HEAD 開始建立一個分支,此時你儲藏了變動,並把它們應用到了新建分支中。
如今咱們瞭解了 git stash
命令,讓咱們執行它,用來從工做空間中移除咱們對 Alice.txt
文件作的本地變動,這樣咱們就能夠繼續上面的操做,執行 git pull
命令來拉取咱們在網站上作的遠程變動。
在那以後,讓咱們執行 git stash pop
命令來取回本地變動。
由於咱們 拉取
的提交和 儲藏
的變動都修改了 Alice.txt
文件,因此你須要解決衝突,就像在 合併
或 變基
中你作的那樣。 完成 添加
後,提交這個變動。
如今咱們已經理解如何 獲取
和 拉取
遠程變動到咱們的工做環境,正是製造一些衝突的時候!
不要推送那個修改 Alice.txt
文件的提交,回到你位於 github.com 的遠程倉庫
這裏咱們又要修改 Alice.txt
文件並提交它。
如今實際上在咱們的本地和遠程倉庫之間存在兩處衝突。
不要忘了運行 git fetch
命令來查看遠程的變動,而不是當即 拉取
它。
若是你如今運行 git status
命令,你會看到兩個分支各有一個與對方不一樣的提交。
git status
On branch fetching_changes_sample
Your branch and 'origin/fetching_changes_sample' have diverged,
and have 1 and 1 different commits each, respectively.
(use "git pull" to merge the remote branch into yours)
複製代碼
另外,咱們已經在上面不一樣提交中修改了同一個文件,爲了介紹 合併
中的衝突這個概念,因此咱們須要解決它。
當你執行 git pull
命令時,而本地和遠程倉庫之間存在着差別,就會發生與 合併
兩個分支過程時一樣的事情。
額外的,你能夠認爲遠程倉庫和本地倉庫分支之間的關係是一種從一個分支上建立另外一個分支的特殊狀況。
本地分支是基於你從遠程倉庫最近一次獲取的分支狀態的。
若是以這種方式思考,這兩種選項來獲取遠程倉庫變化就頗有道理:
當你執行 git pull
命令,本地和遠程倉庫的版本就會 合併
。就像 合併
不一樣分支同樣,這會引入一個合併提交。
由於任何本地分支都基於它們各自的遠程版本,咱們也能夠對它執行 變基
,這樣作的話咱們在本地作的任何變動,都表現爲基於遠程倉庫中的最新可用版本。
爲了這麼作,咱們可使用 git pull --rebase
命令(或者簡寫git pull -r
)。
在變基這小節中已經詳細介紹了,保持一個乾淨線性的歷史提交記錄是有好處的,因此我才強烈建議當你須要執行 git pull
命令時,不妨使用 git pull -r
替代。
你也能夠告訴 git 使用
變基
來代替合併
,做爲你執行git pull
命令時的默認策略,經過一個像這樣git config --global pull.rebase true
的命令來設置pull.rebase
標識。
在我介紹前面幾個段落以後,若是你尚未執行過 git pull
命令的話,讓我如今一塊兒執行 git pull -r
來獲取遠程變動吧,讓它顯得就像咱們的新提交位於那些遠程變動以後。
固然就像一個正常的 變基
(或者 合併
)操做,你須要解決咱們引入的衝突,以便 git pull
命令能夠完成。
歡迎繼續閱讀本系列其餘文章:
若是發現譯文存在錯誤或其餘須要改進的地方,歡迎到 掘金翻譯計劃 對譯文進行修改並 PR,也可得到相應獎勵積分。文章開頭的 本文永久連接 即爲本文在 GitHub 上的 MarkDown 連接。
掘金翻譯計劃 是一個翻譯優質互聯網技術文章的社區,文章來源爲 掘金 上的英文分享文章。內容覆蓋 Android、iOS、前端、後端、區塊鏈、產品、設計、人工智能等領域,想要查看更多優質譯文請持續關注 掘金翻譯計劃、官方微博、知乎專欄。