git learn
因?yàn)镚it是分布式版本控制系統(tǒng),所以,每個(gè)機(jī)器都必須自報(bào)家門:你的名字和Email地址。你也許會(huì)擔(dān)心,如果有人故意冒充別人怎么辦?這個(gè)不必?fù)?dān)心,首先我們相信大家都是善良無(wú)知的群眾,其次,真的有冒充的也是有辦法可查的。
注意git config命令的--global參數(shù),用了這個(gè)參數(shù),表示你這臺(tái)機(jī)器上所有的Git倉(cāng)庫(kù)都會(huì)使用這個(gè)配置,當(dāng)然也可以對(duì)某個(gè)倉(cāng)庫(kù)指定不同的用戶名和Email地址。
?
?
什么是版本庫(kù)呢?版本庫(kù)又名倉(cāng)庫(kù),英文名repository,你可以簡(jiǎn)單理解成一個(gè)目錄,這個(gè)目錄里面的所有文件都可以被Git管理起來(lái),每個(gè)文件的修改、刪除,Git都能跟蹤,以便任何時(shí)刻都可以追蹤歷史,或者在將來(lái)某個(gè)時(shí)刻可以“還原”。
所以,創(chuàng)建一個(gè)版本庫(kù)非常簡(jiǎn)單,首先,選擇一個(gè)合適的地方,創(chuàng)建一個(gè)空目錄:
$ mkdir learngit $ cd learngit $ pwd /Users/michael/learngitpwd命令用于顯示當(dāng)前目錄。在我的Mac上,這個(gè)倉(cāng)庫(kù)位于/Users/michael/learngit。
如果你使用Windows系統(tǒng),為了避免遇到各種莫名其妙的問題,請(qǐng)確保目錄名(包括父目錄)不包含中文。
第二步,通過git init命令把這個(gè)目錄變成Git可以管理的倉(cāng)庫(kù):
$ git init Initialized empty Git repository in /Users/michael/learngit/.git/瞬間Git就把倉(cāng)庫(kù)建好了,而且告訴你是一個(gè)空的倉(cāng)庫(kù)(empty Git repository),細(xì)心的讀者可以發(fā)現(xiàn)當(dāng)前目錄下多了一個(gè).git的目錄,這個(gè)目錄是Git來(lái)跟蹤管理版本庫(kù)的,沒事千萬(wàn)不要手動(dòng)修改這個(gè)目錄里面的文件,不然改亂了,就把Git倉(cāng)庫(kù)給破壞了。
如果你沒有看到.git目錄,那是因?yàn)檫@個(gè)目錄默認(rèn)是隱藏的,用ls -ah命令就可以看見。
?
git? diff 查看修改
在實(shí)際工作中,我們腦子里怎么可能記得一個(gè)幾千行的文件每次都改了什么內(nèi)容,不然要版本控制系統(tǒng)干什么。版本控制系統(tǒng)肯定有某個(gè)命令可以告訴我們歷史記錄,在Git中,我們用git log命令查看:
$ git log commit 1094adb7b9b3807259d8cb349e7df1d4d6477073 (HEAD -> master) Author: Michael Liao <askxuefeng@gmail.com> Date: Fri May 18 21:06:15 2018 +0800append GPLcommit e475afc93c209a690c39c13a46716e8fa000c366 Author: Michael Liao <askxuefeng@gmail.com> Date: Fri May 18 21:03:36 2018 +0800add distributedcommit eaadf4e385e865d25c48e7ca9c8395c3f7dfaef0 Author: Michael Liao <askxuefeng@gmail.com> Date: Fri May 18 20:59:18 2018 +0800 wrote a readme filegit log命令顯示從最近到最遠(yuǎn)的提交日志,我們可以看到3次提交,最近的一次是append GPL,上一次是add distributed,最早的一次是wrote a readme file。
如果嫌輸出信息太多,看得眼花繚亂的,可以試試加上--pretty=oneline參數(shù):
$ git log --pretty=oneline 1094adb7b9b3807259d8cb349e7df1d4d6477073 (HEAD -> master) append GPL e475afc93c209a690c39c13a46716e8fa000c366 add distributed eaadf4e385e865d25c48e7ca9c8395c3f7dfaef0 wrote a readme file在Git中,總是有后悔藥可以吃的。當(dāng)你用$ git reset --hard HEAD^回退到add distributed版本時(shí),再想恢復(fù)到append GPL,就必須找到append GPL的commit id。Git提供了一個(gè)命令git reflog用來(lái)記錄你的每一次命令:
?
?
要關(guān)聯(lián)一個(gè)遠(yuǎn)程庫(kù),使用命令git remote add origin git@server-name:path/repo-name.git;
關(guān)聯(lián)后,使用命令git push -u origin master第一次推送master分支的所有內(nèi)容;
此后,每次本地提交后,只要有必要,就可以使用命令git push origin master推送最新修改;
分布式版本系統(tǒng)的最大好處之一是在本地工作完全不需要考慮遠(yuǎn)程庫(kù)的存在,也就是有沒有聯(lián)網(wǎng)都可以正常工作,而SVN在沒有聯(lián)網(wǎng)的時(shí)候是拒絕干活的!當(dāng)有網(wǎng)絡(luò)的時(shí)候,再把本地提交推送一下就完成了同步,真是太方便了!
?
創(chuàng)建與合并分支
閱讀: 999264在版本回退里,你已經(jīng)知道,每次提交,Git都把它們串成一條時(shí)間線,這條時(shí)間線就是一個(gè)分支。截止到目前,只有一條時(shí)間線,在Git里,這個(gè)分支叫主分支,即master分支。HEAD嚴(yán)格來(lái)說(shuō)不是指向提交,而是指向master,master才是指向提交的,所以,HEAD指向的就是當(dāng)前分支。
一開始的時(shí)候,master分支是一條線,Git用master指向最新的提交,再用HEAD指向master,就能確定當(dāng)前分支,以及當(dāng)前分支的提交點(diǎn):
每次提交,master分支都會(huì)向前移動(dòng)一步,這樣,隨著你不斷提交,master分支的線也越來(lái)越長(zhǎng):
當(dāng)我們創(chuàng)建新的分支,例如dev時(shí),Git新建了一個(gè)指針叫dev,指向master相同的提交,再把HEAD指向dev,就表示當(dāng)前分支在dev上:
你看,Git創(chuàng)建一個(gè)分支很快,因?yàn)槌嗽黾右粋€(gè)dev指針,改改HEAD的指向,工作區(qū)的文件都沒有任何變化!
不過,從現(xiàn)在開始,對(duì)工作區(qū)的修改和提交就是針對(duì)dev分支了,比如新提交一次后,dev指針往前移動(dòng)一步,而master指針不變:
假如我們?cè)赿ev上的工作完成了,就可以把dev合并到master上。Git怎么合并呢?最簡(jiǎn)單的方法,就是直接把master指向dev的當(dāng)前提交,就完成了合并:
所以Git合并分支也很快!就改改指針,工作區(qū)內(nèi)容也不變!
合并完分支后,甚至可以刪除dev分支。刪除dev分支就是把dev指針給刪掉,刪掉后,我們就剩下了一條master分支:
真是太神奇了,你看得出來(lái)有些提交是通過分支完成的嗎?
下面開始實(shí)戰(zhàn)。
首先,我們創(chuàng)建dev分支,然后切換到dev分支:
$ git checkout -b dev Switched to a new branch 'dev'git checkout命令加上-b參數(shù)表示創(chuàng)建并切換,相當(dāng)于以下兩條命令:
$ git branch dev $ git checkout dev Switched to branch 'dev'然后,用git branch命令查看當(dāng)前分支:
$ git branch * devmastergit branch命令會(huì)列出所有分支,當(dāng)前分支前面會(huì)標(biāo)一個(gè)*號(hào)。
然后,我們就可以在dev分支上正常提交,比如對(duì)readme.txt做個(gè)修改,加上一行:
Creating a new branch is quick.然后提交:
$ git add readme.txt $ git commit -m "branch test" [dev b17d20e] branch test1 file changed, 1 insertion(+)現(xiàn)在,dev分支的工作完成,我們就可以切換回master分支:
$ git checkout master Switched to branch 'master'切換回master分支后,再查看一個(gè)readme.txt文件,剛才添加的內(nèi)容不見了!因?yàn)槟莻€(gè)提交是在dev分支上,而master分支此刻的提交點(diǎn)并沒有變:
現(xiàn)在,我們把dev分支的工作成果合并到master分支上:
$ git merge dev Updating d46f35e..b17d20e Fast-forwardreadme.txt | 1 +1 file changed, 1 insertion(+)git merge命令用于合并指定分支到當(dāng)前分支。合并后,再查看readme.txt的內(nèi)容,就可以看到,和dev分支的最新提交是完全一樣的。
注意到上面的Fast-forward信息,Git告訴我們,這次合并是“快進(jìn)模式”,也就是直接把master指向dev的當(dāng)前提交,所以合并速度非常快。
當(dāng)然,也不是每次合并都能Fast-forward,我們后面會(huì)講其他方式的合并。
合并完成后,就可以放心地刪除dev分支了:
$ git branch -d dev Deleted branch dev (was b17d20e).刪除后,查看branch,就只剩下master分支了:
$ git branch * master因?yàn)閯?chuàng)建、合并和刪除分支非常快,所以Git鼓勵(lì)你使用分支完成某個(gè)任務(wù),合并后再刪掉分支,這和直接在master分支上工作效果是一樣的,但過程更安全。
?
創(chuàng)建與合并分支
閱讀: 999264在版本回退里,你已經(jīng)知道,每次提交,Git都把它們串成一條時(shí)間線,這條時(shí)間線就是一個(gè)分支。截止到目前,只有一條時(shí)間線,在Git里,這個(gè)分支叫主分支,即master分支。HEAD嚴(yán)格來(lái)說(shuō)不是指向提交,而是指向master,master才是指向提交的,所以,HEAD指向的就是當(dāng)前分支。
一開始的時(shí)候,master分支是一條線,Git用master指向最新的提交,再用HEAD指向master,就能確定當(dāng)前分支,以及當(dāng)前分支的提交點(diǎn):
每次提交,master分支都會(huì)向前移動(dòng)一步,這樣,隨著你不斷提交,master分支的線也越來(lái)越長(zhǎng):
當(dāng)我們創(chuàng)建新的分支,例如dev時(shí),Git新建了一個(gè)指針叫dev,指向master相同的提交,再把HEAD指向dev,就表示當(dāng)前分支在dev上:
你看,Git創(chuàng)建一個(gè)分支很快,因?yàn)槌嗽黾右粋€(gè)dev指針,改改HEAD的指向,工作區(qū)的文件都沒有任何變化!
不過,從現(xiàn)在開始,對(duì)工作區(qū)的修改和提交就是針對(duì)dev分支了,比如新提交一次后,dev指針往前移動(dòng)一步,而master指針不變:
假如我們?cè)赿ev上的工作完成了,就可以把dev合并到master上。Git怎么合并呢?最簡(jiǎn)單的方法,就是直接把master指向dev的當(dāng)前提交,就完成了合并:
所以Git合并分支也很快!就改改指針,工作區(qū)內(nèi)容也不變!
合并完分支后,甚至可以刪除dev分支。刪除dev分支就是把dev指針給刪掉,刪掉后,我們就剩下了一條master分支:
真是太神奇了,你看得出來(lái)有些提交是通過分支完成的嗎?
下面開始實(shí)戰(zhàn)。
首先,我們創(chuàng)建dev分支,然后切換到dev分支:
$ git checkout -b dev Switched to a new branch 'dev'git checkout命令加上-b參數(shù)表示創(chuàng)建并切換,相當(dāng)于以下兩條命令:
$ git branch dev $ git checkout dev Switched to branch 'dev'然后,用git branch命令查看當(dāng)前分支:
$ git branch * devmastergit branch命令會(huì)列出所有分支,當(dāng)前分支前面會(huì)標(biāo)一個(gè)*號(hào)。
然后,我們就可以在dev分支上正常提交,比如對(duì)readme.txt做個(gè)修改,加上一行:
Creating a new branch is quick.然后提交:
$ git add readme.txt $ git commit -m "branch test" [dev b17d20e] branch test1 file changed, 1 insertion(+)現(xiàn)在,dev分支的工作完成,我們就可以切換回master分支:
$ git checkout master Switched to branch 'master'切換回master分支后,再查看一個(gè)readme.txt文件,剛才添加的內(nèi)容不見了!因?yàn)槟莻€(gè)提交是在dev分支上,而master分支此刻的提交點(diǎn)并沒有變:
現(xiàn)在,我們把dev分支的工作成果合并到master分支上:
$ git merge dev Updating d46f35e..b17d20e Fast-forwardreadme.txt | 1 +1 file changed, 1 insertion(+)git merge命令用于合并指定分支到當(dāng)前分支。合并后,再查看readme.txt的內(nèi)容,就可以看到,和dev分支的最新提交是完全一樣的。
注意到上面的Fast-forward信息,Git告訴我們,這次合并是“快進(jìn)模式”,也就是直接把master指向dev的當(dāng)前提交,所以合并速度非常快。
當(dāng)然,也不是每次合并都能Fast-forward,我們后面會(huì)講其他方式的合并。
合并完成后,就可以放心地刪除dev分支了:
$ git branch -d dev Deleted branch dev (was b17d20e).刪除后,查看branch,就只剩下master分支了:
$ git branch * master因?yàn)閯?chuàng)建、合并和刪除分支非常快,所以Git鼓勵(lì)你使用分支完成某個(gè)任務(wù),合并后再刪掉分支,這和直接在master分支上工作效果是一樣的,但過程更安全。
小結(jié)
Git鼓勵(lì)大量使用分支:
查看分支:git branch
創(chuàng)建分支:git branch <name>
切換分支:git checkout <name>
創(chuàng)建+切換分支:git checkout -b <name>
合并某分支到當(dāng)前分支:git merge <name>
刪除分支:git branch -d <name>
解決沖突
閱讀: 598660人生不如意之事十之八九,合并分支往往也不是一帆風(fēng)順的。
準(zhǔn)備新的feature1分支,繼續(xù)我們的新分支開發(fā):
$ git checkout -b feature1 Switched to a new branch 'feature1'修改readme.txt最后一行,改為:
Creating a new branch is quick AND simple.在feature1分支上提交:
$ git add readme.txt$ git commit -m "AND simple" [feature1 14096d0] AND simple 1 file changed, 1 insertion(+), 1 deletion(-)切換到master分支:
$ git checkout master Switched to branch 'master' Your branch is ahead of 'origin/master' by 1 commit.(use "git push" to publish your local commits)Git還會(huì)自動(dòng)提示我們當(dāng)前master分支比遠(yuǎn)程的master分支要超前1個(gè)提交。
在master分支上把readme.txt文件的最后一行改為:
Creating a new branch is quick & simple.提交:
$ git add readme.txt $ git commit -m "& simple" [master 5dc6824] & simple1 file changed, 1 insertion(+), 1 deletion(-)現(xiàn)在,master分支和feature1分支各自都分別有新的提交,變成了這樣:
這種情況下,Git無(wú)法執(zhí)行“快速合并”,只能試圖把各自的修改合并起來(lái),但這種合并就可能會(huì)有沖突,我們?cè)囋嚳?#xff1a;
$ git merge feature1 Auto-merging readme.txt CONFLICT (content): Merge conflict in readme.txt Automatic merge failed; fix conflicts and then commit the result.果然沖突了!Git告訴我們,readme.txt文件存在沖突,必須手動(dòng)解決沖突后再提交。git status也可以告訴我們沖突的文件:
$ git status On branch master Your branch is ahead of 'origin/master' by 2 commits.(use "git push" to publish your local commits)You have unmerged paths.(fix conflicts and run "git commit") (use "git merge --abort" to abort the merge) Unmerged paths: (use "git add <file>..." to mark resolution) both modified: readme.txt no changes added to commit (use "git add" and/or "git commit -a")我們可以直接查看readme.txt的內(nèi)容:
Git is a distributed version control system. Git is free software distributed under the GPL. Git has a mutable index called stage. Git tracks changes of files. <<<<<<< HEAD Creating a new branch is quick & simple. ======= Creating a new branch is quick AND simple. >>>>>>> feature1Git用<<<<<<<,=======,>>>>>>>標(biāo)記出不同分支的內(nèi)容,我們修改如下后保存:
Creating a new branch is quick and simple.再提交:
$ git add readme.txt $ git commit -m "conflict fixed" [master cf810e4] conflict fixed現(xiàn)在,master分支和feature1分支變成了下圖所示:
用帶參數(shù)的git log也可以看到分支的合并情況:
$ git log --graph --pretty=oneline --abbrev-commit * cf810e4 (HEAD -> master) conflict fixed |\ | * 14096d0 (feature1) AND simple * | 5dc6824 & simple |/ * b17d20e branch test * d46f35e (origin/master) remove test.txt * b84166e add test.txt * 519219b git tracks changes * e43a48b understand how stage works * 1094adb append GPL * e475afc add distributed * eaadf4e wrote a readme file最后,刪除feature1分支:
$ git branch -d feature1 Deleted branch feature1 (was 14096d0).總結(jié)
- 上一篇: hbuild html5打包apk,使用
- 下一篇: [react] React Fiber它