Git是一個開源的分佈式版本控制系統,用以有效、高速的處理從很小到很是大的項目版本管理。Git 是 Linus Torvalds 爲了幫助管理 Linux 內核開發而開發的一個開放源碼的版本控制軟件。
Torvalds 開始着手開發 Git 是爲了做爲一種過渡方案來替代 BitKeeper,後者以前一直是 Linux 內核開發人員在全球使用的主要源代碼工具。開放源碼社區中的有些人以爲 BitKeeper 的許可證並不適合開放源碼社區的工做,所以 Torvalds 決定着手研究許可證更爲靈活的版本控制系統。儘管最初 Git 的開發是爲了輔助 Linux 內核開發的過程,可是咱們已經發如今不少其餘自由軟件項目中也使用了 Git。html
版本管理:前端
在開發中,這是剛需,必須容許能夠很容易對產品的版本進行任意回滾,版本控制工具實現這個功能的原理簡單來說,就是你每修改一次代碼,它就幫你作一次快照。node
協做開發:python
一個複雜點的軟件,每每不是一個開發人員能夠搞定的,IT公司爲加快產品開發速度,會招聘一堆跟你同樣的開發人員開發這個產品,拿QQ來舉例,如今假設3我的一塊兒開發QQ,A開發聯繫人功能,B開發發文 字、圖片、語音通信功能,C開發視頻通話功能, B和C的功能都是要基於通信錄的,你說簡單,直接把A開發的代碼copy過來,在它的基礎上開發就行了,能夠,可是你在他的代碼基礎上開發了2周後,這期間A沒閒 着,對通信錄代碼做了更新,此時怎麼辦?你和他的代碼不一致了,此時咱們知道,你確定要再把A的新代碼拿過來替換掉你手上的舊通信錄功能代碼, 如今人少,3我的之間溝通很簡單,但想一想,若是團隊變成30 我的呢?來回這樣copy代碼,很快就亂了,因此此時急需一個工具,能確保一直存儲最新的代碼庫,全部人的代碼應該和最新的代碼庫保持一致。git
Linus在1991年建立了開源的Linux,今後,Linux系統不斷髮展,已經成爲最大的服務器系統軟件了。Linus雖然建立了Linux,但Linux的壯大是靠全世界熱心的志願者參與的,這麼多人在世界各地爲Linux編寫代碼,那Linux的代碼是如何管理的呢?github
事實是,在2002年之前,世界各地的志願者把源代碼文件經過diff的方式發給Linus,而後由Linus本人經過手工方式合併代碼!你也許會想,爲何Linus不把Linux代碼放到版本控制系統裏呢?不是有CVS、SVN這些免費的版本控制系統嗎?由於Linus堅決地反對CVS和SVN,這些集中式的版本控制系統不但速度慢,並且必須聯網才能使用。有一些商用的版本控制系統,雖然比CVS、SVN好用,但那是付費的,和Linux的開源精神不符。數據庫
不過,到了2002年,Linux系統已經發展了十年了,代碼庫之大讓Linus很難繼續經過手工方式管理了,社區的弟兄們也對這種方式表達了強烈不滿,因而Linus選擇了一個商業的版本控制系BitKeeper,BitKeeper的老闆BitMover公司出於人道主義精神,受權Linux社區無償使用這個版本控制系統。安定團結的大好局面在2005年就被打破了,緣由是Linux社區彙集,難免沾染了一些梁山好漢的江湖習氣。開發Samba的Andrew試圖破解BitKeeper的協議(這麼幹的其實也不僅他一個),被BitMover公司發現了(監控工做作得不錯!),因而BitMover公司怒了,要收回Linux社區的無償使用權。Linus能夠向BitMover公司道個歉,保證之後嚴格管教弟兄們,嗯,這是不可能的。實際狀況是這樣的:Linus花了兩週時間本身用C寫了一個分佈式版本控制系統,這就是Git!一個月以內,Linux系統的源碼已經由Git管理了!牛是怎麼定義的呢?你們能夠體會一下。bootstrap
Git迅速成爲最流行的分佈式版本控制系統,尤爲是2008年,GitHub網站上線了(github是一個基於git的代碼託管平臺,付費用戶能夠建私人倉庫,咱們通常的免費用戶只能使用公共倉庫,也就是代碼要公開。),它爲開源項目免費提供Git存儲,無數開源項目開始遷移至GitHub,包括jQuery,PHP,Ruby等等。vim
歷史就是這麼偶然,若是不是當年BitMover公司威脅Linux社區,可能如今咱們就沒有免費而超級好用的Git了。windows
今天,GitHub已經是:
Git能夠在Linux、Unix、Mac和Windows這幾大平臺上正常運行了。
Linux上安裝Git:sudo
apt-get
install
git
Window上安裝Git:
一、在Git官網下載windows版的git,可是官網幾乎很難進去。SO,我在網盤存了Windows-Git-2.17。
連接:https://pan.baidu.com/s/14y7F7t9gKaZyG2Q_SHGH6A
提取碼:2ds0
二、安裝教程
https://jingyan.baidu.com/article/afd8f4dea2ff0b34e286e984.html
版本倉庫能夠簡單理解成一個目錄,這個目錄裏面的全部文件均可以被Git管理起來,每一個文件的修改、刪除,Git都能跟蹤,以便任什麼時候刻均可以追蹤歷史,或者在未來某個時刻能夠「還原」。
一、建立版本庫
$ mkdir git_test $ cd git_test/ $ git init Initialized empty Git repository in /Users/luban/git_test/.git/
.git
的目錄是Git來跟蹤管理版本庫的,沒事千萬不要手動修改這個目錄裏面的文件,否則改亂了,就把Git倉庫給破壞了。
若是你沒有看到.git
目錄,那是由於這個目錄默認是隱藏的,用ls -ah
命令就能夠看見。
二、把文件添加到版本庫
版本控制系統,其實只能跟蹤文本文件的改動,好比TXT文件,網頁,全部的程序代碼等等,Git也不例外。版本控制系統能夠告訴你每次的改動,好比在第7行加了一個單詞「Linux」,在第8行刪了一個單詞「Windows」。而圖片、視頻這些二進制文件,雖然也能由版本控制系統管理,但無法跟蹤文件的變化,只能把二進制文件每次改動串起來,也就是隻知道圖片從100KB改爲了120KB,但到底改了啥,版本控制系統不知道,也無法知道。
不幸的是,Microsoft的Word格式是二進制格式,所以,版本控制系統是無法跟蹤Word文件的改動的。若是要真正使用版本控制系統,就要以純文本方式編寫文件。由於文本是有編碼的,建議使用標準的UTF-8編碼,全部語言使用同一種編碼,既沒有衝突,又被全部平臺所支持。
先編寫一個文件:
$ vim first_git_file.txt
第一次使用git哈哈
注意:文件要放到git_test目錄下(子目錄也行),由於這是一個Git倉庫,放到其餘地方Git再厲害也找不到這個文件。
把一個文件放到Git倉庫只須要兩步:
一、把文件添加到倉庫(在git_test目錄下)
$ git add first_git_file.txt
執行上面的命令,沒有error說明添加成功。
二、把文件提交到倉庫
$ git commit -m "commit my first git file" [master (root-commit) 621e6e4] commit my first git file Committer: Your name and email address were configured automatically based on your username and hostname. Please check that they are accurate. You can suppress this message by setting them explicitly. Run the following command and follow the instructions in your editor to edit your configuration file: git config --global --edit After doing this, you may fix the identity used for this commit with: git commit --amend --reset-author 1 file changed, 2 insertions(+) create mode 100644 first_git_file.txt
中間紅色部分的意思是,你在往git庫裏提交代碼時,你須要告訴git你是誰,這樣git就會紀錄下來是誰改的代碼,其實就是爲了往後查詢方便,你只須要提供一個名字和郵件地址就能夠,
$ git config --global user.email "test@example.com" $ git config --global user.name "test"
$git commit -m "commit my first git file"
git commit
命令,-m
後面輸入的是本次提交的說明,能夠輸入任意內容,固然最好是有意義的,這樣你就能從歷史記錄裏方便地找到改動記錄。
爲何Git添加文件須要add
,commit
一共兩步呢?由於commit
能夠一次提交不少文件,因此你能夠屢次add
不一樣的文件,好比:
$ git add file1.txt $ git add file2.txt file3.txt $ git commit -m "add 3 files."
添加當前目錄到倉庫:git add .
查看當前倉庫狀態:git status
查看日誌:git log
一、修改並提交代碼
咱們已經成功地添加並提交了一個first_git_file.txt文件,如今,是時候繼續工做了,因而,咱們繼續修改first_git_file.txt文件,改爲以下內容:
第一次使用git,哈哈
11111111111111111
如今,運行git status
命令看看結果:
$ git status On branch master Changes not staged for commit: (use "git add <file>..." to update what will be committed) (use "git checkout -- <file>..." to discard changes in working directory) modified: first_git_file.txt no changes added to commit (use "git add" and/or "git commit -a")
雖然Git告訴咱們first_git_file.txt被修改了,但若是能看看具體修改了什麼內容,天然是很好的。好比你外出兩週從國外回來,第一天上班時,已經記不清上次怎麼修改的first_git_file.txt,
因此,須要用git diff
這個命令看看:
輸出中+號綠色顯示的就是修改或新增的內容,-號紅色顯示的就是去掉或被修改的內容
知道了對first_git_file.txt 做了什麼修改後,再把它提交到倉庫就放心多了,提交修改和提交新文件是同樣的兩步,第一步是git add
:
提交後,咱們再用git status
命令看看倉庫的當前狀態:
Git告訴咱們當前沒有須要提交的修改,並且,工做目錄是乾淨(working directory clean)的。
代碼回滾
再一次修改first_git_file.txtt文件以下:
第一次使用git,哈哈 11111111111111111,hello python! 22222222222222222
而後嘗試提交:
像這樣,不斷對文件進行修改,而後不斷提交修改到版本庫裏,就比如玩RPG遊戲時,每經過一關就會自動把遊戲狀態存檔,若是某一關沒過去,你還能夠選擇讀取前一關的狀態。有些時候,在打Boss以前,你會手動存檔,以便萬一打Boss失敗了,能夠讀取最新的存檔從新開始。Git也是同樣,每當你以爲文件修改到必定程度的時候,就能夠「保存一個快照」,這個快照在Git中被稱爲commit
。一旦你把文件改亂了,或者誤刪了文件,還能夠從最近的一個commit
恢復,而後繼續工做,而不是把幾個月的工做成果所有丟失。
如今,回顧一下first_git_file.txt文件一共有幾個版本被提交到Git倉庫裏了:
版本1:
第一次使用git哈哈
版本2:
第一次使用git,哈哈
11111111111111111
版本3:
第一次使用git,哈哈 11111111111111111,hello python! 22222222222222222
在實際工做中,咱們腦子裏怎麼可能記得一個幾千行的文件每次都改了什麼內容,否則要版本控制系統幹什麼。
版本控制系統確定有某個命令能夠告訴咱們歷史記錄,在Git中,咱們用git log
命令查看:
git log
命令顯示從最近到最遠的提交日誌,咱們能夠看到3次提交,最近的一次是second change,上一次是first change,最先的一次是commit my first git file
。
若是嫌輸出信息太多,看得眼花繚亂的,能夠試試加上--pretty=oneline
參數:
友情提示的是,你看到的一大串相似的5175f849175073e17fa6f28eee4a3b6d41a3a822是commit id
(版本號),和SVN不同,Git的commit id
不是1,2,3……遞增的數字,而是一個SHA1計算出來的一個很是大的數字,用十六進制表示,並且每一個人的commit id
確定不同,以本身的爲準。爲何commit id
須要用這麼一大串數字表示呢?由於Git是分佈式的版本控制系統,後面咱們還要研究多人在同一個版本庫裏工做,若是你們都用1,2,3……做爲版本號,那確定就衝突了。
回滾回滾回滾
好了,如今咱們啓動時光穿梭機,準備把first_git_file.txt回退到上一個版本,也就是「first change」的那個版本,怎麼作呢?
首先,Git必須知道當前版本是哪一個版本,在Git中,用HEAD
表示當前版本,也就是最新的提交c71fa92ffa180708f9169ba90673dc05219d5ab9(注意個人提交ID和你的確定不同),上一個版本就是HEAD^
,上上一個版本就是HEAD^^
,固然往上100個版本寫100個^
比較容易數不過來,因此寫成HEAD~100
。
如今,咱們要把當前版本「second change」回退到上一個版本「first change」,就能夠使用git reset
命令:
此時再看你的文件內容,果真就退回去了
此時還能夠繼續再往前回退一個版本,不過且慢,然咱們用git log
再看看如今版本庫的狀態:
最新的那個版本second change 已經看不到了!比如你從21世紀坐時光穿梭機來到了18世紀,想再回去已經回不去了,怎麼辦?
辦法其實仍是有的,只要上面的命令行窗口尚未被關掉,你就能夠順着往上找啊找啊,找到那個second change的commit id
是c71fa92ffa180708f9169ba90673dc05219d5ab9
因而就能夠指定回到將來的某個版本:
胖子,沒錯,仍是我胡漢三!
Git的版本回退速度很是快,由於Git在內部有個指向當前版本的HEAD
指針,當你回退版本的時候,Git僅僅是把HEAD從指向second change
如今假設,你回退到了first change版本,關掉了電腦,次日早上就後悔了,想恢復到新版本second change怎麼辦?找不到新版本的commit id怎麼辦?畢竟咱們並不是聖賢。
在Git中,老是有後悔藥能夠吃的。當你用$ git reset --hard HEAD^回退到first change版本時,再想恢復到最新second change的版本,就必須找到second change的commit id。
救命稻草------Git提供了一個命令git reflog用來記錄你的每一次命令:
如今,你又能夠乘坐時光機回到將來了。
Git和其餘版本控制系統如SVN的一個不一樣之處就是有暫存區的概念。
工做區(Working Directory)
就是你在電腦裏能看到的目錄,好比個人git_test文件夾就是一個工做區:
$ ls git_test/
first_git_file.txt
版本庫(Repository)
工做區有一個隱藏目錄.git
,這個不算工做區,而是Git的版本庫。
Git的版本庫裏存了不少東西,其中最重要的就是稱爲stage(或者叫index)的暫存區,還有Git爲咱們自動建立的第一個分支master
,以及指向master
的一個指針叫HEAD
。
分支和HEAD
的概念用後面的示例引出。
前面咱們把文件往Git版本庫裏添加的時候,是分兩步執行的:
第一步是用git add
把文件添加進去,實際上就是把文件修改添加到暫存區;
第二步是用git commit
提交更改,實際上就是把暫存區的全部內容提交到當前分支。
由於咱們建立Git版本庫時,Git自動爲咱們建立了惟一一個master
分支,因此,如今,git commit
就是往master
分支上提交更改。
簡單理解爲,須要提交的修改文件統統放到暫存區,而後,一次性提交暫存區的全部修改文件。
咱們再次修改first_git_file.txt,而且新建一個readme.md,隨便寫點解釋語句(針對本次修改)
先用git status
查看一下狀態:
Git很是清楚地告訴咱們,first_git_file.txt
被修改了,而readme.md
還歷來沒有被添加過,因此它的狀態是Untracked
。
如今,使用命令git add .
,再用git status
再查看一下:
如今暫存區的狀態就變成以下圖所示:
因此,git add
命令實際上就是把要提交的全部修改放到暫存區(Stage),而後,執行git commit
就能夠一次性把暫存區的全部修改提交到分支。
一旦提交後,若是你又沒有對工做區作任何修改,那麼工做區就是「乾淨」的:
如今的版本庫變成了這樣,暫存區沒有東西
暫存區是Git很是重要的概念,弄明白了暫存區,就弄明白了Git的不少操做到底幹了什麼。
假設本身在readme.md寫了不合適的語句:
在你準備提交前,你猛然發現了「魯班大師智障二百五!」可能會讓你丟掉這個月的獎金!
既然錯誤發現得很及時,就能夠很容易地糾正它。你能夠刪掉最後一行,手動把文件恢復到上一個版本的狀態。
但若是用git status
查看一下:
你能夠發現,Git會告訴你,git checkout -- file
能夠丟棄工做區的修改:
你剛纔添加的話就被撤銷了,命令git checkout -- readme.md
意思就是,把readme.md
文件在工做區的修改所有撤銷,這裏有兩種狀況:
第一種是readme.md
自修改後尚未被放到暫存區,如今,撤銷修改就回到和版本庫如出一轍的狀態;
第二種是readme.md
已經添加到暫存區後,又做了修改,如今,撤銷修改就回到添加到暫存區後的狀態。
總之,就是讓這個文件回到最近一次git commit
或git add
時的狀態。
git checkout -- file
命令中的--
很重要,沒有--
,就變成了「切換到另外一個分支」的命令。
假設咱們遇到第二種狀況:在readme.md中寫了髒話,而且添加到了暫存區該怎樣解決呢?
慶幸的是在沒提交以前,咱們發現了它。Git一樣告訴咱們,用命令git reset HEAD file
能夠把暫存區的修改撤銷掉(unstage),從新放回工做區:
如今,咱們將readme.md的修改撤回到了工做區:
如今只需按照第一種在工做區的狀況對待便可。
step1:git checkout -- readme.md
step2: git status
step3: cat readme.md
世界終於清淨了!哈哈哈
在Git中,刪除也是一個修改操做,先添加一個新文件test.txt到Git而且提交:
通常狀況下,你一般直接在文件管理器中把沒用的文件刪了,或者用rm
命令刪了
這個時候,Git知道你刪除了文件,所以,工做區和版本庫就不一致了,git status
命令會馬上告訴你哪些文件被刪除了:
如今咱們有兩個選擇,一是確實要從版本庫中刪除該文件,那就用命令git rm
刪掉,而且git commit
:
如今,文件就從版本庫中被刪除了。
另外一種狀況是刪錯了,由於版本庫裏還有呢,因此能夠很輕鬆地把誤刪的文件恢復到最新版本:
git checkout --
test
.txt
git checkout
實際上是用版本庫裏的版本替換工做區的版本,不管工做區是修改仍是刪除,均可以「一鍵還原」。
可是版本庫裏的文件被刪就完全沒了。
一個神奇的網站--GitHub,這個網站就是提供Git倉庫託管服務的。因此,只要註冊一個GitHub帳號,就能夠免費得到Git遠程倉庫。
在繼續閱讀後續內容前,請自行註冊GitHub帳號。因爲你的本地Git倉庫和GitHub倉庫之間的傳輸是經過SSH加密的,因此,須要一點設置:
第1步:建立SSH Key。
在用戶主目錄下,看看有沒有.ssh目錄,若是有,再看看這個目錄下有沒有id_rsa
和id_rsa.pub
這兩個文件,若是已經有了,可直接跳到下一步。若是沒有,打開Shell(Windows下打開Git Bash),建立SSH Key:
$ ssh-keygen -t rsa -C "youremail@example.com"
你須要把郵件地址換成你本身的郵件地址,而後一路回車,使用默認值便可,因爲這個Key也不是用於軍事目的,因此也無需設置密碼。
若是一切順利的話,能夠在用戶主目錄裏找到.ssh
目錄,裏面有id_rsa
和id_rsa.pub
兩個文件,這兩個就是SSH Key的祕鑰對,id_rsa
是私鑰,不能泄露出去,id_rsa.pub
是公鑰,能夠放心地告訴任何人。
第2步:登錄GitHub,打開「Account settings」,「SSH Keys」頁面:
而後,點「Add SSH Key」,填上任意Title,在Key文本框裏粘貼id_rsa.pub
文件的內容:
點「Add Key」,你就應該看到已經添加的Key。
爲何GitHub須要SSH Key呢?由於GitHub須要識別出你推送的提交確實是你推送的,而不是別人冒充的,而Git支持SSH協議,因此,GitHub只要知道了你的公鑰,就能夠確認只有你本身才能推送。
固然,GitHub容許你添加多個Key。假定你有若干電腦,你一下子在公司提交,一下子在家裏提交,只要把每臺電腦的Key都添加到GitHub,就能夠在每臺電腦上往GitHub推送了。
友情提示,在GitHub上免費託管的Git倉庫,任何人均可以看到喔(但只有你本身才能改)。因此,不要把敏感信息放進去。
若是你不想讓別人看到Git庫,有兩個辦法,一個是交點保護費,讓GitHub把公開的倉庫變成私有的,這樣別人就看不見了(不可讀更不可寫)。另外一個辦法是本身動手,搭一個Git服務器,由於是你本身的Git服務器,因此別人也是看不見的。
11.1 建立遠程倉庫
在本地建立了一個Git倉庫後,又想在GitHub建立一個Git倉庫,而且讓這兩個倉庫進行遠程同步,這樣,GitHub上的倉庫既能夠做爲備份,又可讓其餘人經過該倉庫來協做,真是一舉多得。
首先,登錄GitHub,而後,在右上角找到「New repository」按鈕,建立一個新的倉庫:
目前,在GitHub上的這個Gittest倉庫仍是空的,GitHub告訴咱們,能夠從這個倉庫克隆出新的倉庫,也能夠把一個已有的本地倉庫與之關聯,而後,把本地倉庫的內容推送到GitHub倉庫。
如今,咱們根據GitHub的提示,在本地已有的git_test倉庫下運行命令:
注意,把上面的Yun-Wangjun替換成你本身的GitHub帳戶名,不然,你在本地關聯的就是個人遠程庫,關聯沒有問題,可是你之後推送是推不上去的,
由於你的SSH Key公鑰不在個人帳戶列表中。添加後,遠程庫的名字就是origin
,這是Git默認的叫法,也能夠改爲別的,可是origin
這個名字一看就知道是遠程庫。
把本地庫的內容推送到遠程,用git push
命令,其實是把當前分支master
推送到遠程。此時刷新遠程倉庫頁面, 就看到了你剛從本地推上來的代碼了。
從如今起,只要本地做了提交,就能夠經過命令:
$ git push origin master
建立一個hello.py文件,同時上傳到遠程
而後刷新下遠程倉庫頁面,就看到你的新建立的文件了。
首先,登錄GitHub,建立一個新的倉庫,名字叫remote_to_local
:
如今,遠程庫已經準備好了,下一步是用命令git clone
克隆一個本地庫:
在本地找一個你想存放這個遠程倉庫的目錄,而後在本地命令行用git clone 命令來克隆這個遠程庫。
若是有多我的協做開發,那麼每一個人各自從遠程克隆一份就能夠了。GitHub給出的地址不止一個,還能夠用 https://github.com/Yun-Wangjun/remote_to_local.git這樣的地址。實際上,Git支持多種協議,默認的git://
使用ssh,但也能夠使用https
等其餘協議。使用https
除了速度慢之外,還有個最大的麻煩是每次推送都必須輸入口令。
分支就是科幻電影裏面的平行宇宙,當你正在電腦前努力學習Git的時候,另外一個你正在另外一個平行宇宙裏努力學習SVN。
若是兩個平行宇宙互不干擾,那對如今的你也沒啥影響。不過,在某個時間點,兩個平行宇宙合併了,結果,你既學會了Git又學會了SVN!
好比:2我的開發一個購物商城,你負責前端,另外一個負責後端。你開發一個新功能,可是須要兩週才能完成,第一週你寫了50%的代碼,若是馬上提交,因爲代碼還沒寫完,不完整的代碼庫會致使別人不能幹活了。若是等代碼所有寫完再一次提交,又存在丟失天天進度的巨大風險。你建立了一個屬於你本身的分支,別人看不到,還繼續在原來的分支上正常工做,而你在本身的分支上幹活,
想提交就提交,直到開發完畢後,再一次性合併到原來的分支上,這樣,既安全,又不影響別人工做。
其餘版本控制系統如SVN等都有分支管理,可是用過以後你會發現,這些版本控制系統建立和切換分支比蝸牛還慢,
但Git的分支是不同凡響的,不管建立、切換和刪除分支,Git在1秒鐘以內就能完成!不管你的版本庫是1個文件仍是1萬個文件。
12.1建立與合併分支
在版本回退部分時,每次提交,Git都把它們串成一條時間線,這條時間線就是一個分支。截止到目前,只有一條時間線,在Git裏,這個分支叫主分支,即master
分支。HEAD
嚴格來講不是指向提交,而是指向master
,master
纔是指向提交的,因此,HEAD
指向的就是當前分支。
一開始的時候,master
分支是一條線,Git用master
指向最新的提交,再用HEAD
指向master
,就能肯定當前分支,以及當前分支的提交點:
每次提交,master
分支都會向前移動一步,這樣,隨着你不斷提交,master
分支的線也愈來愈長, 當咱們建立新的分支,
例如dev
時,Git新建了一個指針叫dev
,指向master
相同的提交,再把HEAD
指向dev
,就表示當前分支在dev
上:
$ git checkout -b dev Switched to a new branch 'dev'
#注意:命令加上參數表示建立並切換,至關於如下兩條命令:
命令會列出全部分支,當前分支前面會標一個號。
#切換分支:git checkout branch_name
git checkout-bgit branch devgit checkout dev#git branch*
咱們能夠在dev
分支上正常提交,好比對readme.txt作個修改,加上一行,而後提交:
如今,dev
分支的工做完成,咱們就能夠切換回master
分支:切換回master
分支後,再查看一個readme.txt文件,剛纔添加的內容不見了!由於那個提交是在dev
分支上,而master
分支此刻的提交點並無變:
如今就能夠把dev
合併到master
上。Git怎麼合併呢?最簡單的方法,就是直接把master
指向dev
的當前提交,就完成了合併:
注意到上面的Fast-forward
信息,Git告訴咱們,此次合併是「快進模式」,也就是直接把master
指向dev
的當前提交,因此合併速度很是快。
因此Git合併分支也很快!就改改指針,工做區內容也不變!
合併完分支後,甚至能夠刪除dev
分支。刪除dev
分支就是把dev
指針給刪掉,刪掉後,咱們就剩下了一條master
分支:
由於建立、合併和刪除分支很是快,因此Git鼓勵你使用分支完成某個任務,合併後再刪掉分支,這和直接在master
分支上工做效果是同樣的,但過程更安全。
12.2解決衝突
合併分支每每也不是一路順風的。準備新的feature_1
分支,繼續咱們的新分支開發:
修改readme.txt最後一行,改成:
在feature_1
分支上提交:
切換到master
分支:
Git還會自動提示咱們當前master
分支比遠程的master
分支要超前1個提交。
在master
分支上把readme.txt文件的最後一行修改並提交:
如今,master
分支和feature_1
分支各自都分別有新的提交,變成了這樣:
這種狀況下,Git沒法執行「快速合併」,只能試圖把各自的修改合併起來,但這種合併就可能會有衝突:
git告訴咱們:
自動合併README.md
CONFLICT(內容):在README.md中合併衝突
自動合併失敗; 修復衝突,而後提交結果。
readme.txt文件存在衝突, 必須手動解決衝突後再提交。git status
也能夠告訴咱們衝突的文件:
git告訴咱們:
在分支master 你的分支在2次提交以前領先於'origin / master'。 (使用「git push」發佈您的本地提交) 你有未合併的路徑。 (修復衝突並運行「git commit」) (使用「git merge --abort」停止合併) 未合併的路徑: (使用「git add <file> ...」來標記分辨率) 二者都修改過:README.md 沒有更改添加到提交(使用「git add」和/或「git commit -a」)
咱們能夠直接查看readme.txt的內容:
Git用<<<<<<<
,=======
,>>>>>>>
標記出不一樣分支的內容,咱們修改以下後保存,提交:
如今,master
分支和feature1
分支變成了下圖所示:
用帶參數的git log
也能夠看到分支的合併狀況:
首先,master
分支應該是很是穩定的,也就是僅用來發布新版本,平時不能在上面開發;
那在哪幹活呢?幹活都在dev
分支上,也就是說,dev
分支是不穩定的,到某個時候,好比1.0版本發佈時,再把dev
分支合併到master
上,在master
分支發佈1.0版本;
你和你的小夥伴們每一個人都在dev
分支上幹活,每一個人都有本身的分支,時不時地往dev
分支上合併就能夠了。
因此,團隊合做的分支看起來就像這樣:
軟件開發中,bug就像屢見不鮮同樣。有了bug就須要修復,在Git中,因爲分支是如此的強大,因此,每一個bug均可以經過一個新的臨時分支來修復,修復後,合併分支,而後將臨時分支刪除。
當你接到一個修復一個代號101的bug的任務時,很天然地,你想建立一個分支issue-101
來修復它,可是,等等,當前正在dev
上進行的工做尚未提交:
$ git status # On branch dev # Changes to be committed: # (use "git reset HEAD <file>..." to unstage) # # new file: hello.py # # Changes not staged for commit: # (use "git add <file>..." to update what will be committed) # (use "git checkout -- <file>..." to discard changes in working directory) # # modified: readme.txt #
並非你不想提交,而是工做只進行到一半,還無法提交,預計完成還需1天時間。可是,必須在兩個小時內修復該bug,怎麼辦?
幸虧,Git還提供了一個stash
功能,能夠把當前工做現場「儲藏」起來,等之後恢復現場後繼續工做:
$ git stash Saved working directory and index state WIP on dev: 6224937 add merge HEAD is now at 6224937 add merge
如今,用git status
查看工做區,就是乾淨的(除非有沒有被Git管理的文件),所以能夠放心地建立分支來修復bug。
首先肯定要在哪一個分支上修復bug,假定須要在master
分支上修復,就從master
建立臨時分支:
$ git checkout master Switched to branch 'master' Your branch is ahead of 'origin/master' by 6 commits. $ git checkout -b issue-101 Switched to a new branch 'issue-101'
如今修復bug,須要把「Git is free software ...」改成「Git is a free software ...」,而後提交:
$ git add readme.txt $ git commit -m "fix bug 101" [issue-101 cc17032] fix bug 101 1 file changed, 1 insertion(+), 1 deletion(-)
修復完成後,切換到master
分支,並完成合並,最後刪除issue-101
分支:
$ git checkout master Switched to branch 'master' Your branch is ahead of 'origin/master' by 2 commits. $ git merge --no-ff -m "merged bug fix 101" issue-101 Merge made by the 'recursive' strategy. readme.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) $ git branch -d issue-101 Deleted branch issue-101 (was cc17032).
原計劃兩個小時的bug修復只花了5分鐘!如今,是時候接着回到dev
分支幹活了!
$ git checkout dev Switched to branch 'dev' $ git status # On branch dev nothing to commit (working directory clean)
工做區是乾淨的,剛纔的工做現場存到哪去了?用git stash list
命令看看:
$ git stash list
stash@{0}: WIP on dev: 6224937 add merge
工做現場還在,Git把stash內容存在某個地方了,可是須要恢復一下,有兩個辦法:
一是用git stash apply
恢復,可是恢復後,stash內容並不刪除,你須要用git stash drop
來刪除;
另外一種方式是用git stash pop
,恢復的同時把stash內容也刪了
$ git stash pop # On branch dev # Changes to be committed: # (use "git reset HEAD <file>..." to unstage) # # new file: hello.py # # Changes not staged for commit: # (use "git add <file>..." to update what will be committed) # (use "git checkout -- <file>..." to discard changes in working directory) # # modified: readme.txt # Dropped refs/stash@{0} (f624f8e5f082f2df2bed8a4e09c12fd2943bdd40)
再用git stash list
查看,就看不到任何stash內容了:
$ git stash list
你能夠屢次stash,恢復的時候,先用git stash list
查看,而後恢復指定的stash,用命令:
$ git stash apply stash@{0}
當你從遠程倉庫克隆時,實際上Git自動把本地的master
分支和遠程的master
分支對應起來了,而且,遠程倉庫的默認名稱是origin
。
要查看遠程庫的信息,用git remote
:
或者,用git remote -v
顯示更詳細的信息:
上面顯示了能夠抓取和推送的origin
的地址。若是沒有推送權限,就看不到push的地址
13.1推送分支
推送分支,就是把該分支上的全部本地提交推送到遠程庫。推送時,要指定本地分支,這樣,Git就會把該分支推送到遠程庫對應的遠程分支上:
$ git push origin master
若是要推送其餘分支,好比dev
,就改爲:
$ git push origin dev
可是,並非必定要把本地分支往遠程推送,那麼,哪些分支須要推送,哪些不須要呢?
master分支是主分支,所以要時刻與遠程同步;
dev分支是開發分支,團隊全部成員都須要在上面工做,因此也須要與遠程同步;
bug分支只用於在本地修復bug,就不必推到遠程了,除非老闆要看看你每週到底修復了幾個bug;
feature分支是否推到遠程,取決於你是否和你的小夥伴合做在上面開發。
總之,就是在Git中,分支徹底能夠在本地本身藏着玩,是否推送,由本身而定!
多人協做時,你們都會往master
和dev
分支上推送各自的修改。
如今,模擬一個你的小夥伴,能夠在另外一臺電腦(注意要把SSH Key添加到GitHub)或者同一臺電腦的另外一個目錄下克隆:
默認狀況下,你的小夥伴只能看到本地的master
分支。不信能夠用git branch
命令看看:
如今,你的小夥伴要在dev
分支上開發,就必須建立遠程origin
的dev
分支到本地,因而他用這個命令建立本地dev
分支並在dev
上繼續修改:
你的小夥伴已經向origin/dev分支推送了他的提交,而碰巧你也對一樣的文件做了修改,並試圖推送:
推送失敗,由於你的小夥伴的最新提交和你試圖推送的提交有衝突,解決辦法也很簡單,Git已經提示咱們,
先用git pull
把最新的提交從origin/dev
抓下來,而後,在本地合併,解決衝突,再推
git pull
也失敗了,緣由是沒有指定本地dev
分支與遠程origin/dev
分支的連接,根據提示,設置dev
和origin/dev
的連接:
再pull:
這回git pull
成功,可是合併有衝突,須要手動解決,解決的方法和分支管理中的解決衝突徹底同樣。解決後,提交,再push:
所以,多人協做的工做模式一般是這樣:
首先,能夠試圖用git push origin branch-name
推送本身的修改;
若是推送失敗,則由於遠程分支比你的本地更新,須要先用git pull
試圖合併;
若是合併有衝突,則解決衝突,並在本地提交;
沒有衝突或者解決掉衝突後,再用git push origin branch-name
推送就能成功!
若是git pull
提示「no tracking information」,則說明本地分支和遠程分支的連接關係沒有建立,用命令git branch --set-upstream branch-name origin/branch-name
。
這就是多人協做的工做模式,一旦熟悉了,就很是簡單。
咱們一直用GitHub做爲免費的遠程倉庫,若是是我的的開源項目,放到GitHub上是徹底沒有問題的。其實GitHub仍是一個開源協做社區,經過GitHub,既可讓別人參與你的開源項目,也能夠參與別人的開源項目。
在GitHub上,利用Git極其強大的克隆和分支功能,IT人員真正能夠第一次自由參與各類開源項目了。
如何參與一個開源項目呢?好比人氣極高的bootstrap項目,這是一個很是強大的CSS框架,你能夠訪問它的項目主頁https://github.com/twbs/bootstrap,點「Fork」就在本身的帳號下克隆了一個bootstrap倉庫,而後,從本身的帳號下clone:
必定要從本身的帳號下clone倉庫,這樣你才能推送修改。若是從bootstrap的做者的倉庫地址克隆
,由於沒有權限,你將不能推送修改。
Bootstrap的官方倉庫twbs/bootstrap
、你在GitHub上克隆的倉庫my/bootstrap
,以及你本身克隆到本地電腦的倉庫,他們的關係就像下圖顯示的那樣:
若是你想修復bootstrap的一個bug,或者新增一個功能,馬上就能夠開始幹活,幹完後,往本身的倉庫推送。
若是你但願bootstrap的官方庫能接受你的修改,你就能夠在GitHub上發起一個pull request。固然,對方是否接受你的pull request就不必定了。
若是你沒能力修改bootstrap,但又想要試一把pull request,那就Fork一下個人倉庫 ,建立一個your-github-id.txt
的文本文件,寫點本身學習Git的心得,而後推送一個pull request給我,我會視心情而定是否接受。
小結
在GitHub上,能夠任意Fork開源倉庫;
本身擁有Fork後的倉庫的讀寫權限;
能夠推送pull request給官方倉庫來貢獻代碼。
有些時候,你必須把某些文件放到Git工做目錄中,但又不能提交它們,好比保存了數據庫密碼的配置文件啦,等等,每次git status
都會顯示Untracked files ...
,有強迫症的童鞋內心確定不爽。
好在Git考慮到了你們的感覺,這個問題解決起來也很簡單,在Git工做區的根目錄下建立一個特殊的.gitignore
文件,而後把要忽略的文件名填進去,Git就會自動忽略這些文件。
不須要從頭寫.gitignore
文件,GitHub已經爲咱們準備了各類配置文件,只須要組合一下就能夠使用了。全部配置文件能夠直接在線瀏覽:https://github.com/github/gitignore
忽略文件的原則是:
.class
文件;舉個例子:
假設你在Windows下進行Python開發,Windows會自動在有圖片的目錄下生成隱藏的縮略圖文件,若是有自定義目錄,目錄下就會有Desktop.ini
文件,所以你須要忽略Windows自動生成的垃圾文件:
# Windows: Thumbs.db ehthumbs.db Desktop.ini
而後,繼續忽略Python編譯產生的.pyc
、.pyo
、dist
等文件或目錄:
# Python: *.py[cod] *.so *.egg *.egg-info dist build
加上你本身定義的文件,最終獲得一個完整的.gitignore
文件,內容以下:
# Windows: Thumbs.db ehthumbs.db Desktop.ini # Python: *.py[cod] *.so *.egg *.egg-info dist build # My configurations: db.ini deploy_key_rsa
最後一步就是把.gitignore
也提交到Git,就完成了!固然檢驗.gitignore
的標準是git status
命令是否是說working directory clean
。
使用Windows的童鞋注意了,若是你在資源管理器裏新建一個.gitignore
文件,它會很是弱智地提示你必須輸入文件名,可是在文本編輯器裏「保存」或者「另存爲」就能夠把文件保存爲.gitignore
了。
有些時候,你想添加一個文件到Git,但發現添加不了,緣由是這個文件被.gitignore
忽略了:
$ git add App.class The following paths are ignored by one of your .gitignore files: App.class Use -f if you really want to add them.
若是你確實想添加該文件,能夠用-f
強制添加到Git:
$ git add -f App.class
或者你發現,多是.gitignore寫得有問題,須要找出來到底哪一個規則寫錯了,能夠用git check-ignore命令檢查:
$ git check-ignore -v App.class .gitignore:3:*.class App.class
Git會告訴咱們,.gitignore
的第3行規則忽略了該文件,因而咱們就能夠知道應該修訂哪一個規則。
小結
忽略某些文件時,須要編寫.gitignore
;
.gitignore
文件自己要放到版本庫裏,而且能夠對.gitignore
作版本管理!