一.Git簡介
Git是世界上最先進的分布式版本控制系統(tǒng),相對于SVN這樣的集中式版本控制系統(tǒng),Git不需要“中央服務(wù)器”,每一臺電腦都有一個完整的版本庫。因此,它的安全性要高很多。Git一般工作流程如下:
- 克隆 Git 遠(yuǎn)程資源庫作為工作目錄
- 在克隆的資源庫上添加或修改文件
- 如果其他人修改了,則需要相應(yīng)更新資源
- 在提交前查看修改
- 提交修改
- 修改完成后,若發(fā)現(xiàn)錯誤,撤回提交并再次修改并提交

Git支持Linux/Mac OS/Windows,可根據(jù)需求自行安裝。安裝后需要做如下配置:
- /etc/gitconfig 文件:系統(tǒng)中對所有用戶都普遍適用的配置。
- ~/.gitconfig 文件:用戶目錄下的配置文件只適用于該用戶。
- 當(dāng)前項目的 Git 目錄中的配置文件(也就是工作目錄中的 .git/config 文件):這里的配置僅僅針對當(dāng)前項目有效。
每一個級別的配置都會覆蓋上層的相同配置,所以 .git/config 里的配置會覆蓋 /etc/gitconfig 中的同名變量。根據(jù)需要,配置相應(yīng)的工作環(huán)境變量如用戶名、郵箱等。
二.版本管理

Git中的文件被分為兩種狀態(tài),一種是已跟蹤狀態(tài)(tracked),另一種是未跟蹤狀態(tài)(untracked)。只有處于已跟蹤狀態(tài)的文件才被納入GIT的版本控制,已跟蹤狀態(tài)的文件又分為未修改、已修改、暫存狀態(tài),如上圖所示。

Git中的工作區(qū)域又分為三個:工作區(qū)、暫存區(qū)、版本庫(倉庫)
- 工作區(qū)
就是在電腦中能看到的目錄 - 暫存區(qū)
stage或者index,存放在.git目錄下的index文件中 - 版本庫
工作區(qū)有一個隱藏的目錄.git,即git的版本庫,又名倉庫(repository)。簡單理解成一個目錄,是Git用來跟蹤和管理版本庫的。工作區(qū)所有文件都可以被Git管理起來,每個文件的修改、刪除,Git都能跟蹤,以便任何時刻都可以追蹤歷史,或者在將來某個時刻可以“還原”。
創(chuàng)建倉庫
步驟1:創(chuàng)建一個空目錄,如“mkdir git;cd git”
步驟2: git init
創(chuàng)建完成后,在當(dāng)前目錄下生成一個隱藏目錄.git添加文件
步驟1:創(chuàng)建文件readme.txt
步驟2:git add readme.txt,將文件寫入暫存區(qū)
步驟3:git commit -m "wrote a readme file",將暫存區(qū)所有添加到倉庫中。(-m 為本次提交說明)查看狀態(tài)
步驟1:git status,獲取倉庫當(dāng)前的狀態(tài)
步驟2:git diff,查看文件修改的內(nèi)容版本回退
Git每一次的commit提交為“保存一個快照”,一旦把文件改亂了,或者誤刪了文件,還可以從其中的一個commit恢復(fù)。
步驟1:git log,顯示從最近到最遠(yuǎn)的提交日志
步驟2:git reset --hard HEAD^,回退到上一個版本
注:在Git中,用HEAD表示當(dāng)前版本,也就是最新的提交,上一個版本就是HEAD^,依次類推;也可用git log顯示出來的commit id來標(biāo)識版本回退(--hard撤銷工作區(qū)域與暫存區(qū)的修改)
步驟3:要重返未來,用git reflog查看命令歷史,以便確定要回到未來的哪個版本修改文件
工作區(qū)中新建的文件,git status查看時為“Untracked files”狀態(tài),當(dāng)提交到版本庫并修改后,
步驟1:git status,狀態(tài)為“Changes not staged for commit”
步驟2:git add再git commit
注:git commit只會把提交到暫存區(qū)的修改,加入到commit中
步驟3:如果我們提交過后發(fā)現(xiàn)有個文件改錯了,或者只是想修改提交說明,這時可以對相應(yīng)文件做出修改,將修改過的文件通過"git add"添加到暫存區(qū),然后執(zhí)行g(shù)it commit --amend,覆蓋上一次提交-
撤銷修改
步驟1:git checkout -- file,可以丟棄工作區(qū)的修改(注意“--”非常重要,否則表示切換分支)。存在下面幾種情況:- 修改后沒有存入暫存區(qū),可以直接回到和版本庫一樣
- 已經(jīng)添加到暫存區(qū),但未修改,用命令git reset HEAD <file>(即取消暫存),就回到前面1場景
- 已經(jīng)添加到暫存區(qū),又做了修改,撤銷修改就回到了添加到暫存區(qū)后的狀態(tài)
- 若修改已經(jīng)提交到了版本庫,則參考前面“版本回退”
-
刪除文件
步驟1:使用rm 刪除工作區(qū)的文件
步驟2:有兩種情況- 情況一:從版本庫中刪除,即git rm然后提交git commit
- 情況二:刪除錯了,git checkout -- test.txt將文件恢復(fù)到當(dāng)前版本(注意不要忘了"--")
三.遠(yuǎn)程倉庫
可以自己搭建Git服務(wù)器作為遠(yuǎn)程倉庫,也可以使用已有的代碼托管服務(wù)網(wǎng)站,如GitHub、碼云等。
-
GitHub
1.1 配置環(huán)境
步驟1:ssh-keygen -t rsa -C "youremail@example.com"生成公私鑰(在用戶主目錄下 "cd ~");生成的公私鑰主要用于加密通信內(nèi)容以及身份校驗,私鑰自己保留,公鑰提供給GitHub
步驟2:登陸GitHub,打開“Account settings”,“SSH Keys”頁面:點“Add SSH Key”,填上任意Title,在Key文本框里粘貼id_rsa.pub文件的內(nèi)容
1.2 添加遠(yuǎn)程倉庫
- 步驟1:登陸GitHub,在右上角找到“Create a new repo”按鈕,創(chuàng)建一個新的空的倉庫;然后,可以從這個倉庫在本地克隆出新的倉庫,也可以把一個已有的本地倉庫與之關(guān)聯(lián)
- 步驟2:在本地的倉庫下運行g(shù)it remote add origin git@github.com:xxx.git;其中origin是遠(yuǎn)程庫的名字,git@github.com:xxx.git是步驟1創(chuàng)建的遠(yuǎn)程倉庫;使得本地倉庫與遠(yuǎn)程倉庫關(guān)聯(lián)
- 步驟3:git push -u origin master,將本地庫的所有內(nèi)容推送到遠(yuǎn)程庫上(-u主要是第一次推送,指定origin為默認(rèn)主機,后續(xù)推送時則不需要)
1.3 從遠(yuǎn)程庫克隆
- 步驟1:類似于1.2中的步驟1,在GitHub網(wǎng)站上創(chuàng)建遠(yuǎn)程倉庫,如名字叫g(shù)itskills
- 步驟2:從遠(yuǎn)程庫克隆,git clone git@github.com:xxx/gitskills.git,這樣就在本地目錄下克隆了一份遠(yuǎn)程庫。Git支持多種協(xié)議,如默認(rèn)的ssh(git://),以及http、https等
1.4 使用GitHub參與開源項目
- 在GitHub上,可以Fork任意開源倉庫;
- 自己擁有Fork后的倉庫的讀寫權(quán)限,然后在本地克隆一個Fork后的倉庫;
- 可以推送pull request給官方倉庫來貢獻代碼
2.自己搭建Git服務(wù)器
- 步驟1:安裝Git,sudo apt-get install git
- 步驟2:創(chuàng)建用戶,sudo adduser git
- 步驟3:創(chuàng)建證書登錄,收集需要登錄的用戶的公鑰,把用戶公鑰導(dǎo)入到/home/git/.ssh/authorized_keys文件中
- 步驟4: 初始化Git倉庫,sudo git init --bare sample.git;修改用戶sudo chown -R git:git sample.git防止其他用戶修改
- 步驟5:禁用shell登錄,通過編輯/etc/passwd文件完成
- 步驟6:本地倉庫克隆git clone git@server:/srv/sample.git
3.碼云
四.分支管理

- 創(chuàng)建和合并分支
在Git里,默認(rèn)為主分支即master,而HEAD指向當(dāng)前的分支。一開始master指向最新的提交,而HEAD指向master;當(dāng)創(chuàng)建并切換到分支dev后,dev指向與master相同的提交,并且HEAD指向dev。當(dāng)在新的分支dev上提交時,dev指針向前移動,master不變。
- git checkout -b dev,創(chuàng)建并切換到分支dev
- git branch,查看分支
- git branch <name>,創(chuàng)建分支
- git checkout <name>,切換分支
- git merge <name>,合并某分支到當(dāng)前分支
- git branch -d <name>,刪除分支
-
解決沖突
當(dāng)把feature1分支的修改自動合入master分支時,可能會產(chǎn)生沖突。Git會在文件中使用<<<<<<<,=======,>>>>>>>標(biāo)記出不同分支的內(nèi)容,我們手工修改后再提交。
-
分支管理策略
- master分支主要用來發(fā)布版本,比較穩(wěn)定
- 團隊在dev分支上工作,dev分支是不穩(wěn)定的,等到某個版本穩(wěn)定時,再合入master分支
- 個人在自己的分支下開發(fā)工作,如michael、bob等,再不斷的往dev分支上合入代碼
-
Bug分支
當(dāng)你在dev分支上的開發(fā)進行到一半時,需要在master分支上去修復(fù)一個緊急的Bug。第一步就需要先切換到master 分支。但當(dāng)你執(zhí)行 $ git checkout master 命令的時候,會提示出錯,需要將當(dāng)前的分支修改提交后才能切換。怎么辦?- 步驟1:git stash,將當(dāng)前工作現(xiàn)場儲藏起來
- 步驟2:git checkout master,切換到主分支并創(chuàng)建bug分支來修復(fù)問題
- 步驟3:修復(fù)完成后,切回主分支并合并修改,然后刪除bug分支
- 步驟4:切換至dev分支,git checkout dev,并執(zhí)行g(shù)it stash list查看,git stash pop恢復(fù)現(xiàn)場并刪除儲藏(或者git stash apply stash@{0}恢復(fù),但是恢復(fù)后,stash內(nèi)容并不刪除,用git stash drop來刪除)
多人協(xié)作
- 克隆遠(yuǎn)程庫,同時執(zhí)行g(shù)it checkout -b dev origin/dev,創(chuàng)建遠(yuǎn)程庫的dev分支到本地
- 試圖用git push origin <branch-name>推送自己的修改;
- 若推送失敗,則因為遠(yuǎn)程分支比你的本地更新,需要先用git pull試圖合并;git pull --rebase origin master,rebase是通過將local commit一個一個地在更新后的master分支上運行;git add <conflicted-files>;git rebase --continue
- 如果合并有沖突,則解決沖突,并在本地提交;
- 沒有沖突或者解決掉沖突后,再用git push origin <branch-name>推送就能成功
- 如果git pull提示no tracking information,則說明本地分支和遠(yuǎn)程分支的連接關(guān)系沒有創(chuàng)建,用命令git branch --set-upstream-to <branch-name> origin/<branch-name>。
關(guān)于Git的工作流請參考:深入理解學(xué)習(xí)Git工作流
-
Rebase
rebase的目的是把本地未push的分叉提交歷史整理成直線,使得我們在查看歷史提交的變化時更容易,因為分叉的提交需要三方對比。- 步驟: git rebase
有兩種方法將一個分支的改動合并進另一個分支,一個就是前面所說的分支合并,另一個就是分支衍合,這兩種方式有什么區(qū)別呢?
分支合并(merge)是將兩個分支的改動合并到一起,并生成一個新的提交,提交歷史是按時間排序的,即我們實際提交的順序,通過git log --graph或一些圖形化工具,可能很明顯地看到分支的合并歷史,如果分支比較多就很混亂,而且如果以功能點新建分支,等功能點完成后合回主線,由于merge后提交是按提交時間排序的,提交歷史就比較亂,各個功能點的提交混雜在一起。
分支合并
而分支衍合(rebase)是找到兩個分支的共同祖先提交,將要被rebase進來的分支的提交依次在要被rebase到的分支上重演一遍,即回到兩個分支的共同祖先,將branch(假如叫experiment)的每次提交的差異保存到臨時文件里,然后切換到要衍合入的分支(假如是master),依次應(yīng)用補丁文件。experiment上有幾次提交,在master就生成幾次新的提交,而且是連在一起的,這樣合進主線后每個功能點的提交就都在一起,而且提交歷史是線性的
分支衍合
git rebase -i HEAD ~ 2,HEAD~2表示倒數(shù)第三個提交,這條命令要指定要重排的最舊的提交的父提交。
- cherry-pick
當(dāng)與別人和作開發(fā)時,會向別人貢獻代碼或者接收別人貢獻的代碼,有時候可能不想完全Merge別人貢獻的代碼,只想要其中的某一個提交,這時就可以使用cherry-pick了。就一個命令
git cherry-pick <commit-id>
一般通過在gerrit中粘貼相應(yīng)的命令,直接在提交的目錄下執(zhí)行這個命令
五.標(biāo)簽管理
tag是一個容易讓人記住的有意義的名字,與某個commit綁定在一起
- 切換到需要打標(biāo)簽的分支是,執(zhí)行g(shù)it tag <tagname>
- 查看所有的標(biāo)簽,git tag
- 歷史提交打標(biāo)簽,git tag <tagname> commit_id
- 查看標(biāo)簽信息,git show <tagname>
- 刪除標(biāo)簽,git tag -d <tagname>
- 推送某個標(biāo)簽到遠(yuǎn)程,使用命令git push origin <tagname>
- 一次性推送全部尚未推送到遠(yuǎn)程的本地標(biāo)簽git push origin --tags
六.其它
-
忽略特殊文件
Git工作區(qū)的根目錄下創(chuàng)建一個.gitignore文件,把要忽略的文件名填進去,Git就會自動忽略這些文件。忽略文件的是:- 忽略操作系統(tǒng)自動生成的文件,如縮略圖等;
- 忽略編譯生成的中間文件、可執(zhí)行文件等,如.class .o文件;
- 忽略私有的帶有敏感信息的配置文件
忽略的規(guī)則是:
- 所有以#開頭的行會被忽略
- 可以使用glob模式匹配
- 匹配模式后跟反斜杠(/)表示要忽略的是目錄
- 如果不要忽略某模式的文件在模式前加"!"
Git跟蹤限制
目前的版本控制系統(tǒng)只能跟蹤文本文件如網(wǎng)頁、txt、程序源代碼等,視頻圖片等二進制文件,Git無法知道具體改動細(xì)節(jié)
參考:
Git手冊
https://www.liaoxuefeng.com/wiki/0013739516305929606dd18361248578c67b8067c8c017b000/00137402760310626208b4f695940a49e5348b689d095fc000
http://www.runoob.com/git/git-remote-repo.html




