Git的簡單使用教程


Git的安裝

Linux下

直接sudoapt-get install git-core

Windows下

   直接下載安裝 https://git-for-windows.github.io/

安裝完成后,還需要最后一步設置,在命令行輸入:
$ git config –global user.name “Your Name”
$ git config –globaluser.email “email@example.com”
設置名稱和郵箱是為了在提交代碼的時候知道是誰提交的。

創建版本庫

   版本庫又名倉庫,可以簡單的理解為一個目錄,這個目錄里面所以的文件都可以被Git管理起來,每個文件的修改、刪除,Git都能跟蹤,以便任何時刻都可以追蹤歷史,或者在將來的某個時刻可以還原。
創建倉庫只需要在需要變成倉庫的目錄下輸入 gitinit
創建完后這個目錄下會出現 .git 的目錄,這個目錄是用來Git來跟蹤管理版本庫的。
如果要刪除這個倉庫只需要將這個目錄刪除掉。

在Linux下建立目錄並設置為Git倉庫的代碼:
mkdirlearngit
cdlearngit
gitinit
(顯示當前目錄) pwd

把文件添加到版本庫

注意:千萬不要使用Windows自帶的記事本編輯任何文本文件。原因是Microsoft開發記事本的團隊使用了一個非常弱智的行為來保存UTF-8編碼的文件,他們自作聰明地在每個文件開頭添加了0xefbbbf(十六進制)的字符。
建議使用notepad++代替。

將文件添加到倉庫:
第一步,用命令git add告訴Git,把文件添加到倉庫:
git add //git add readme.txt
第二步,用命令git commit告訴Git,把文件提交到倉庫:
git commit -m “wrote update info”
簡單解釋一下git commit命令,-m后面輸入的是本次提交的說明,可以輸入任意內容,當然最好是有意義的,這樣你就能從歷史記錄里方便地找到改動記錄。

為什么Git添加文件需要add,commit一共兩步呢?因為commit可以一次提交很多文件,所以你可以多次add不同的文件,比如:
$ git add file1.txt
$ git add file2.txt file3.txt
$ git commit -m “add 3files.”
$ git add . —>代表將所有文件進行添加

小結

初始化一個Git倉庫,使用git init命令。
添加文件到Git倉庫,分兩步:
l 第一步,使用命令git add ,注意,可反復多次使用,添加多個文件;
l 第二步,使用命令git commit,完成。

Git查看文件的更改

當我們將文件內容進行更改后可以用git status命令查看結果。
git status命令可以讓我們時刻掌握倉庫當前的狀態
我們可以使用git diff命令查看我們修改了什么。
git diff git diff顧名思義就是查看difference

小結

l 要隨時掌握工作區的狀態,使用gitstatus命令。
l 如果gitstatus告訴你有文件被修改過,用git diff可以查看修改內容。

版本退回

我們可以用git log命令查看修改歷史。
git log命令顯示從最近到最遠的提交日志,如果輸出信息太多可以加上
–pretty=oneline參數。
git log–pretty=oneline –>顯示信息為:版本號(commit id)和git commit -m提交時設置的提示說明。
首先,Git必須知道當前版本是哪個版本,在Git中,用HEAD表示當前版本,也就是最新提交的commit id為3628164…882e1e0,上一個版本就是HEAD^,上上一個版本就是HEAD^^,當然往上100個版本寫100個^比較容易數不過來,所以寫成HEAD~100。
我們使用 git reset命令來進行版本的回退。
git reset –hard HEAD^ —->返回上一個版本
也可以是 git reset –hard HEAD~1
(Windows系統下 git reset –hard HEAD^^ 才會返回上一個版本)
然后 stackoverflow 解釋:If you’re using Windows, you could do git log HEAD^^, I believe. – Name McChange Nov 4 ‘13 at 0:58 The ^ is an escape character in the Windows Command Line. Use ^^ instead of ^.
其他解釋:在windows的命令行中 git reset -hard HEAD^ 中 ^是一個特殊字符,使用時必須用雙引號引起來才能正確運行 git reset -hard HEAD”^” 或者 git reset -hard”HEAD^”
這樣一來最新的版本已經看不到了,但只要命令窗口還為關閉,只要能找到需要回到最新的版本號的commit id,於是就可以回到未來的某個版本。
git reset –hard 3628164 —–>在這里版本號不需要寫全 Git會自己匹配查找

但如果你命令窗口關閉了,或者到了第二天需要返回到曾經的最新版本,則必須要找到當時版本的commit id。在git中提供了一個gitreflog命令來記錄你的每一次命令。

小結

l HEAD指向的版本就是當前版本,因此,Git允許我們在版本的歷史之間穿梭,使用命令git reset –hard commit_id。
l 穿梭前,用git log可以查看提交歷史,以便確定要回退到哪個版本。
l 要重返未來,用git reflog查看命令歷史,以便確定要回到未來的哪個版本。

Git的工作區和暫存區

工作區(WorkingDirectory)

   就是本地電腦可以看到的目錄

版本庫(Repository)

這里寫圖片描述
工作區中有一個隱藏的目錄 .git,這個不算工作區,而是Git的版本庫。
Git的版本庫中存放了很多東西,其中最重要的就是成為stage(或者叫index)的暫存區,還有Git為我們自動創建的第一個分支master,以及指向master的一個指針叫HEAD。
文件往Git版本庫中添加的時候,是分兩步執行的:
第一步是: git add把文件添加進去,實際上就是把文件修改添加到暫存區。
第二步是: git commit提交更改,實際上就是把暫存區的所有內容提交到當前分支。
因為我們創建Git版本庫時,Git自動為我們創建了唯一一個master分支,所以 git commit就是往master分支上提交修改。

管理修改

Git跟蹤並管理的是修改,而非文件。
第一次修改 -> git add -> 第二次修改 -> git commit
由於Git管理的是修改,當你使用git add命令后,在工作區的第一次修改會被放入暫存區,但是第二次修改的並沒有放在暫存區,所以git commit提交的是第一次修改的版本。
提交后,用git diff HEAD – 命令可以查看工作區和版本庫里面最新版本的區別。

撤銷修改

   Git中使用 git checkout -- < filename> 丟掉工作區的所有修改。

命令git checkout – 的意思是,把文件在工作區的所有修改撤銷,這里有兩種情況:
一種是:文件自修改后還沒有被放到暫存區,現在,撤銷修改就回到和版本庫一模一樣的狀態;
一種是:文件已經添加到暫存區后,又作了修改,現在撤銷修改就回到添加到暫存區后的狀態。
總之,就是讓這個文件回到最近的一次 git commit 或 git add 時的狀態。

   Git中使用gitreset HEAD <filename>命令可以將暫存區的修改撤銷,重新放回工作區。
git reset 命令既可以回退版本,也可以將暫存區的修改退回到工作區。當我們用HEAD時,表示最新版。

小結

場景一:當你亂改了工作區的某個文件的內容,想直接丟棄工作區的時,用命令gitcheckout –
場景二:當你不但亂改了工作區的某個文件的內容,還添加到了暫存區,想丟棄修改,分兩步,首先使用命令gitreset HEAD ,就回到了場景一,第二部按場景一操作。
場景三:已經提交了不合適的修改到了版本庫時,想要撤回本次提交,可以采用版本回退(git reset –hard HEAD^)回退到上一個版本,不過前提是沒有推送到遠程庫。

刪除文件

   一般情況下,通常可以直接將在文件管理器中把沒用的文件刪除了,或者使用rm命令刪掉:rm<filename>
如果確實要將文件從版本庫中刪除,那就使用命令git rm刪掉,並且git commit.
如果刪錯了,因為版本庫中還有這個文件,所以可以使用命令 git checkout -- <filename>將誤刪的文件恢復到最新版本。

遠程倉庫

   Git是一個分布式版本控制系統,同一個Git倉庫,可以分布在不同的機器上。最早,只有一台機器有一個原始版本庫,此后,別的機器可以“克隆”這個原始版本庫,而且每台機器的版本庫其實都是一樣的,並沒有主次之分。
然而,現階段還沒有必要自己搭建Git服務器,可以直接使用GitHub來作為Git服務器倉庫。
由於本地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"

你需要把郵件地址換成你自己的郵件地址(其實就是公鑰的名字),然后一路回車,使用默認值即可。也可以直接ssh-keygen
之后在用戶目錄下就可以找到 .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。
替換密鑰時需要將原來的.ssh文件夾刪掉並重新生成即可。

添加遠程庫

目標:在GitHub新建一個Git倉庫,讓兩個倉庫進行遠程同步。

   首先在GitHub上新建一個Git倉庫。然后在本地的Git倉庫運行:
gitremote add origin git@github.com:<GitHub用戶名>/<新建的GitHub倉庫名.git>

這里面 origin是遠程庫的名稱,是Git的默認叫法,也可以進行修改。
下一步,就可以把本地庫的所以內容推送到遠程庫上:
gitpush -u origin master
把本地庫的內容推送到遠程,使用git push命令,實際上是把當前分支master推送到遠程。
由於遠程庫是空的,我們第一次推送master分支時,加上了-u參數,Git不但會把本地的master分支內容推送的遠程新的master分支,還會把本地的master分支和遠程的master分支關聯起來,在以后的推送或者拉取時就可以簡化命令。
從現在起,只要本地做了提交,就可以通過命令:git pushorigin master 把本地的master分支的最新修改推送到GitHub。

小結

要關聯一個遠程庫使用命令gitremote add origin git@server-name:path/repo-name.git
關聯后使用命令 git push -u origin master 第一次推送master分支的所有內容。
此后每次版本更新只需要使用命令 git push origin master 推送最新的修改。

從遠程庫克隆

上次我們講了先有本地庫,后有遠程庫的時候,如何關聯遠程庫。現在,我們從零開始,先創建遠程庫,然后,從遠程庫克隆。
首先,登陸GitHub,創建一個新的倉庫,名字叫gitskills
然后選擇Initialize this repositorywith a README,這樣GitHub會自動為我們創建一個README.md文件。
現在我們使用命令遠程克隆一個本地庫:
git clone git@github.com:

小結

要克隆一個倉庫,首先必須知道倉庫的地址,然后使用git clone命令克隆。
Git支持多種協議,包括https,但通過ssh支持的原生git協議速度最快。

分支管理

分支在實際中有什么用呢?假設你准備開發一個新功能,但是需要兩周才能完成,第一周你寫了50%的代碼,如果立刻提交,由於代碼還沒寫完,不完整的代碼庫會導致別人不能使用。如果等代碼全部寫完再一次提交,又存在丟失每天進度的巨大風險。現在有了分支,就不用怕了。你創建了一個屬於你自己的分支,別人看不到,還繼續在原來的分支上正常工作,而你在自己的分支上干活,想提交就提交,直到開發完畢后,再一次性合並到原來的分支上,這樣,既安全,又不影響別人工作。

創建與合並分支

   在版本回退里,你已經知道,每次提交,Git都把它們串成一條時間線,這條時間線就是一個分支。截止到目前,只有一條時間線,在Git里,這個分支叫主分支,即master分支。HEAD嚴格來說不是指向提交,而是指向master,master才是指向提交的,所以,HEAD指向的就是當前分支。

一開始的時候,master分支是一條線,Git用master指向最新的提交,再用HEAD指向master,就能確定當前分支,以及當前分支的提交點:
這里寫圖片描述
每次提交,master分支都會向前移動一步,這樣,隨着你不斷提交,master分支的線也越來越長。
當我們創建新的分支,例如dev時,Git新建了一個指針叫dev,指向master相同的提交,再把HEAD指向dev,就表示當前分支在dev上:
這里寫圖片描述
Git創建一個分支很快,因為除了增加一個dev指針,改改HEAD的指向,工作區的文件都沒有任何變化。
不過,從現在開始,對工作區的修改和提交就是針對dev分支了,比如新提交一次后,dev指針往前移動一步,而master指針不變。
這里寫圖片描述
假如我們在dev上的工作完成了,就可以把dev合並到master上。Git怎么合並呢?最簡單的方法,就是直接把master指向dev的當前提交,就完成了合並。
這里寫圖片描述
所以Git合並分支也很快,只是改改指針,工作區內容也不變。
合並完分支后,甚至可以刪除dev分支。刪除dev分支就是把dev指針給刪掉,刪掉后,我們就剩下了一條master分支:
這里寫圖片描述
實戰:
首先我們創建 dev 分支,然后切換到 dev 分支。
gitcheckout -b dev
git checkout命令加上-b參數表示創建並切換,相當於以下兩條命令:
git branch dev
gitcheckout dev
然后,用git branch命令查看當前分支:
git branch
git branch命令會列出所有分支,當前分支前面會標一個*號。
然后我們就可以在dev分支上正常提交。等到,dev分支工作完成時,我們就可以切回master分支。
gitcheckout master
切換回master分支后,再查看之前在dev分支提交的文件,會發現才添加的內容還沒有出現,那時因為那個提交是在dev分支上,而master分支此刻的提交點並沒有變。
所以現在,我們要把dev分支的工作成果合並到master分支上:
這里寫圖片描述
git merge dev
git merge命令用於合並指定分支到當前分支。合並后,再查看文件內容,就可以看到,和dev分支的最新提交是完全一樣的。
合並完成后,我們就可以刪除dev分支了:
git branch -d dev
刪除后,查看branch,就只剩下master分支了:
git branch

小結

Git鼓勵大量使用分支:
查看分支:git branch
創建分支:git branch
切換分支:git checkout
創建+切換分支:git checkout -b
合並某分支到當前分支:git merge
刪除分支:git branch -d

解決沖突

准備新的feature1分支,繼續我們的新分支開發:
$ gitcheckout -b feature1
Switched to a new branch’feature1’
修改readme.txt最后一行,改為:
Creating a new branch isquick AND simple.
在feature1分支上提交:
$ git add readme.txt
$ git commit -m “AND simple”
[feature1 75a857c] 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.
Git還會自動提示我們當前master分支比遠程的master分支要超前1個提交。
在master分支上把readme.txt文件的最后一行改為:
Creating a new branch is quick & simple.
提交:
$ gitadd readme.txt
$ gitcommit -m “& simple”
[master 400b400] & simple
1 file changed, 1 insertion(+), 1 deletion(-)
現在,master分支和feature1分支各自都分別有新的提交,變成了這樣:
這里寫圖片描述
這種情況下,Git無法執行“快速合並”,只能試圖把各自的修改合並起來,但這種合並就可能會有沖突,我們試試看:
$ git merge feature1
Auto-merging readme.txt
CONFLICT (content): Mergeconflict in readme.txt
Automatic merge failed; fixconflicts and then commit the result.
果然沖突了!Git告訴我們,readme.txt文件存在沖突,必須手動解決沖突后再提交。git status也可以告訴我們沖突的文件:
$ git status
On branch master
no changes added to commit (use “gitadd” and/or “git commit -a”)
我們可以直接查看readme.txt的內容:
Git is a distributed versioncontrol system.
Git is free softwaredistributed under the GPL.
Git has a mutable indexcalled stage.
Git tracks changes of files.
<<<<<<< HEAD
Creating a new branch isquick & simple.
Creating a new branch isquick AND simple.
>>>>>> feature1
Git用<<<<<<<,=======,>>>>>>>標記出不同分支的內容,我們修改如下后保存:
Creating a new branch is quick and simple.
再提交:
$ git add readme.txt
$ git commit -m “conflict fixed”
現在,master分支和feature1分支變成了下圖所示:
用帶參數的git log也可以看到分支的合並情況:
$ git log –graph –pretty=oneline–abbrev-commit
* 59bc1cb conflict fixed
|\
| *75a857c AND simple
* |400b400 & simple
|/
*fec145a branch test

最后,刪除feature1分支:
$ git branch -d feature1
工作完成。

小結

當Git無法自動合並分支時,就必須首先解決沖突。解決沖突后,再提交,合並完成。
用git log –graph命令可以看到分支合並圖。

分支管理策略

   通常合並分支的時,Git一般會Fast forward模式,但這種模式下,刪除分支后,會丟掉分支信息。如果強制禁用Fast forward模式,Git就會在merge時生成一個新的commit,這樣,從分支的歷史就可以看出分支的信息。
下面我們使用--no-ff方式的git merge:

首先,仍然創建並切換dev分支:
git checkout -b dev
修改readme.txt文件,並提交一個新的commit:
git add readme.txt
git commit -m “addmerge”
現在,我們切換回master:
git checkout master
准備合並dev分支,請注意–no-ff參數,表示禁用Fast forward:
git merge –no-ff -m”merge with no-ff” dev
因為本次合並要創建一個新的commit,所以加上-m參數,把commit描述寫進去。合並后,我們用git log看看分支歷史:
git log –graph–pretty=oneline –abbrev-commit
可以看到,不使用Fast forward模式,merge后就像這樣:

分支策略

在實際開發中,我們應該按照幾個基本原則進行分支管理:首先,master分支應該是非常穩定的,也就是僅用來發布新版本,平時不能在上面干活;dev分支是不穩定的,到某個時候,比如1.0版本發布時,再把dev分支合並到master上,在master分支發布1.0版本;你和你的小伙伴們每個人都在dev分支上干活,每個人都有自己的分支,時不時地往dev分支上合並就可以了。所以,團隊合作的分支看起來就像這樣:

小結

Git分支十分強大,在團隊開發中應該充分應用。合並分支時,加上–no-ff參數就可以用普通模式合並,合並后的歷史有分支,能看出來曾經做過合並,而fast forward合並就看不出來曾經做過合並。

Bug分支

   在Git中,由於分支是如此的強大,所以,每個bug都可以通過一個新的臨時分支來修復,修復后,合並分支,然后將臨時分支刪除。
Git提供了一個stash功能,可以把當前工作現場存儲起來,等以后恢復現場后繼續工作: git stash

首先確定要在哪個分支上修復bug,假定需要在master分支上修復,就從master創建臨時分支:
git checkout master
git checkout -b issue-101
現在修復bug,然后提交:
git add readme.txt
git commit -m “fix bug101”
修復完成后,切換到master分支,並完成合並,最后刪除issue-101分支:
git checkout master
git merge –no-ff -m”merged bug fix 101” issue-101
git branch -d issue-101
接着回到dev分支
git checkout dev
git status
工作區是干凈的,用git stash list命令查看剛才的工作現場存到哪了。
git stash list
工作現場還在,Git把stash內容存在某個地方了,但是需要恢復一下,有兩個辦法:
一是用git stash apply恢復,但是恢復后,stash內容並不刪除,你需要用git stash drop來刪除;
另一種方式是用git stash pop,恢復的同時把stash內容也刪了:
git stash pop
再用git stash list查看,就看不到任何stash內容了:
git stash list
你可以多次stash,恢復的時候,先用git stash list查看,然后恢復指定的stash,用命令:
git stash apply stash@{0}

小結

修復bug時,我們會通過創建新的bug分支進行修復,然后合並,最后刪除;當手頭工作沒有完成時,先把工作現場git stash一下,然后去修復bug,修復后,再git stash pop,回到工作現場。

Feature分支

   添加一個新功能時,為了不把主分支搞亂了,所以最好建一個feature分支,在上面開發,完成后合並,最后,刪除該feature分支。

git checkout -b feature-new —創建了一個名字是feature-new的分支
開發完畢后:
git add new.py
git status
git commit -m “add feature new”
切回dev,准備合並:
git checkout dev
將feature分支和bug分支合並,然后刪除。
但如果,由於一些原因,新功能被取消,所以這個分支必須就地銷毀。
git branch -d feature-new 但由於分支還沒有合並,所以這樣銷毀會失敗,如果強行刪除,需要使用命令gitbranch -D feature-new

小結

開發一個新feature,最好新建一個分支。如果要丟棄一個沒有被合並的分支,可以通過git branch -D 強行刪除。

多人協作

   當你從遠程倉庫克隆時,實際上Git自動的把本地的master分支和遠程的master對應起來了,並且,遠程倉庫的默認名稱是origin。
要查看遠程庫的信息,用git remote,或者使用git remote -v顯示更詳細的信息。git remote -v顯示了抓取和推送的origin的地址。如果沒有推送權限,就看不到push的地址。

推送分支

推送分支,就是把該分支推送到遠程庫。推送時要指定本地分支,這樣,Git就會把該分支推送到遠程庫對應的遠程分支上。
git push origin master
如果要推送其他分支,如dev就要改成 git push origin dev
但是,並不一定要把本地分支往遠程分支推送。
master分支是主分支,因此要時刻與遠程同步;
dev分支是開發分支,團隊所有成員都要在上面工作,所以也需要與遠程同步。
bug分支只用於在本地修復bug,所以就沒必要推到遠程了。
feature是否推送到遠程,取決於你是否要和小伙伴合作在上面開發。
總之,就是在Git中,分支完全可以在本地自己藏着玩,是否推送,視心情而定!

抓取分支

   多人協作時,大家都會往master和dev分支上推送各自的修改。
但現在一個小伙伴從遠程clone時,默認情況下只能看到你本地的master分支。現在,你的小伙伴要在dev分支上開發,就必須創建遠程origin和dev分支到本地,於是用

git checkout -b dev origin/dev
現在,他就可以在dev上繼續修改,然后時不時把dev分支push到遠程。

git clone git@github.com:tomatoyan/learngit.git
git config user.name “Bob”
git config user.email “bob@example.com”
git branch
git checkout -b dev origin/dev

git add hello.py
git commit -m “add hello info”
git push origin dev

如果你的小伙伴已經向origin/dev分支推送了他的提交,而碰巧你也對同樣的文件作了修改,並試圖推送:
$ git add hello.py
$ git commit -m “add coding: utf-8”
[dev bd6ae48] add coding: utf-8
1 filechanged, 1 insertion(+)
$ git push origin dev
To git@github.com:michaelliao/learngit.git
![rejected] dev -> dev(non-fast-forward)
error: failed to push some refs to ‘git@github.com:michaelliao/learngit.git’
hint: Updates were rejected because the tip ofyour current branch is behind
hint: its remote counterpart. Merge the remotechanges (e.g. ‘git pull’)
hint: before pushing again.
hint: See the ‘Note about fast-forwards’ in’git push –help’ for details.
推送失敗,因為你的小伙伴的最新提交和你試圖推送的提交有沖突,Git已經提示我們,先用git pull把最新的提交origin/dev抓下來,然后,在本地倉庫,解決沖突,再推送。
$ git pull
remote: Counting objects: 5, done.
remote: Compressing objects: 100% (2/2), done.
remote: Total 3 (delta 0), reused 3 (delta 0)
Unpacking objects: 100% (3/3), done.
From github.com:michaelliao/learngit
fc38031..291bea8 dev -> origin/dev
There is no tracking information for thecurrent branch.
Please specify which branch you want to mergewith.
See git-pull(1) for details
gitpull
If you wish to set tracking information forthis branch you can do so with:
gitbranch –set-upstream dev origin/
git pull也失敗了,原因是沒有指定本地dev分支與遠程origin/dev分支的鏈接,根據提示,設置dev和origin/dev的鏈接。
$ git branch –set-upstream dev origin/dev
Branch dev set up to track remote branch dev from origin.
再pull:
$ git pull
Auto-merging hello.py
CONFLICT (content): Merge conflict in hello.py
Automatic merge failed; fix conflicts and then commit the result.
這回git pull成功,但是合並有沖突,需要手動解決,解決的方法和分支管理中的解決沖突完全一樣。解決后,提交,再push:
$ git commit -m “merge & fix hello.py”
[dev adca45d] merge & fix hello.py
$ git push origin dev
Counting objects: 10, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (5/5), done.
Writing objects: 100% (6/6), 747 bytes, done.
Total 6 (delta 0), reused 0 (delta 0)
To git@github.com:michaelliao/learngit.git
291bea8..adca45d dev -> dev
因此,多人協作的工作模式是這樣:
1、 首先,可以試圖用git push origin 推送自己的修改;
2、 如果推送失敗,則因為遠程分支比你的本地更新,需要先用git pull試圖合並;
3、 如果合並有沖突,則解決沖突,並在本地提交;
4、 沒有沖突或者解決掉沖突后,再用git push origin branch-name推送就能成功。
如果git pull提示“no tracking information”,則說明本地分支和遠程分支的鏈接關系沒有創建,用命令git branch –set-upstreambranch-name origin/branch-name。

小結

   查看遠程庫信息,使用git remote -v;
本地新建的分支如果不推送到遠程,對其他人就是不可見的;
從本地推送分支,使用git push origin <branch-name >,如果推送失敗,先用git pull抓取遠程的新提交;
在本地創建和遠程分支對應的分支,使用git checkout -b <branch-name > origin/<branch name>,本地和遠程分支的名稱最好一致。
建立本地分支和遠程分支的聯系,使用git branch –set-upstream <branch-name > origin/< branch-name >
從遠程抓取分支,使用git pull,如果有沖突,要先處理沖突。

查看歷史分支流程提交信息 git log –graph –pretty=oneline –abbrev-commit

標簽管理

發布一個版本時,我們通常先在版本庫中打一個標簽(tag),這樣,就唯一確定了打標簽時刻的版本。將來無論什么時候,取某個標簽的版本,就是把那個打標簽的時刻的歷史版本取出來。所以,標簽也是版本庫的一個快照。
Git的標簽雖然是版本庫的快照,但其實它就是指向某個commit的指針,所以,創建和刪除標簽都是瞬間完成的。
Git有commit,為什么還要引入tag?
“請把上周一的那個版本打包發布,commit號是6a5819e…”
“一串亂七八糟的數字不好找!”
如果換一個辦法:
“請把上周一的那個版本打包發布,版本號是v1.2”
“好的,按照tag v1.2查找commit就行!”
所以,tag就是一個讓人容易記住的有意義的名字,它跟某個commit綁在一起。

創建標簽

   在Git中打標簽很簡單,首先,切換到需要打標簽的分支上。
git tag <name>就可以打一個新標簽:git tagv1.0
然后可以用命令git tag查看所有的標簽。

默認的標簽是打在最新提交的commit上的,有時候,如果忘了打標簽,方法是找到歷史提交commit id,然后打上就好了。
git log –pretty=oneline–abbrev-commit
要對add merge的這次提交加標簽,它對應的commit id是6224937,則敲入
git tag v1.0 6224937
這里的標簽不是按照時間順序列出,而是按照字母排序的。可以用git show查看標簽信息。
還可以創建帶有說明的標簽,用-a指定標簽名,-m指定說明文字。
git tag -a -m <”說明文字”>
還可以通過-s用私鑰簽名一個標簽:
git tag -s -m <”說明文字”>
簽名采用PGP簽名,因此,必須首先安裝gpg(GnuPG),如果沒有找到gpg,或者沒有gpg密鑰對,就會報錯。
用命令git show 可以看到PGP簽名信息:

小結

   命令git tag <name>用於新建一個標簽,默認為HEAD,也可以指定一個commit id

git tag -a -m <“說明文字”>可以指定標簽信息
git tag -s -m <“說明文字”>可以用PGP簽名標簽
命令git tag可以查看所有標簽

操作標簽

標簽的刪除:git tag -d v0.1
git tag -d
推送標簽去遠程
git push origin
或者一次性推送全部尚未推送到遠程的本地標簽:
git push origin –tags
但如果標簽推送到了遠程,要刪除就麻煩一點了,先從本地刪除:
git tag -d
然后,再從遠程刪除。刪除命令也是push,格式如下:
git push origin:refs/tags/

小結

l 命令git push origin 可以推送一個本地標簽;
l 命令git push origin –tags 可以推送全部未推送過的本地標簽;
l 命令git tag -d 可以刪除一個本地標簽;
l 命令git push origin :refs/tags/ 可以刪除一個遠程標簽。

使用GitHub

   如何參與GitHub上的開源項目。

git clone git@github.com:michaelliao/boostrap.git
一定要從自己的帳號下clone倉庫,這樣才能推送修改。如果從boostrap的作者的倉庫地址git@github.com:twbs/boostrap.git克隆,因為沒有權限,你將不能修改推送。
如果你想修復boostrap的一個bug,或者新增一個功能,立刻就可以開始干活,干完后就可以往自己的倉庫推送。
如果你希望boostrap的官方庫能接受你的修改,你就可以在GitHub上發起一個pull request。當然,對方是否接受你的pull request就不一定了。
小結

l 在GitHub上,可以任意Fork開源倉庫;
l 自己擁有Fork后的倉庫的讀寫權限;
l 可以推送pull request給官方倉庫來貢獻代碼。

自定義Git

我們可以配置user.name和user.email。
我們可以讓Git顯示顏色
git config –globalcolor.ui true
這樣Git會適當地顯示不同的顏色。
忽略特殊文件

   在Git工作區的根目錄下創建一個特殊的 .gitignore文件,然后把要忽略的文件名添加進去,Git就會自動忽略這些文件。不要從頭寫 .gitignore文件,GitHub已經准備為我們准備了各種配置文件,只需要組合一下就可以使用了。所有配置文件可以直接在線瀏覽:https://github.com/github/gitignore

忽略文件的原則是:
1.忽略操作系統自動生成的文件,比如縮略圖等;
2.忽略編譯生成的中間文件、可執行文件等,也就是如果一個文件是通過另一個文件自動生成的,那自動生成的文件就沒必要放進版本庫,比如Java編譯產生的.class文件;
3.忽略你自己的帶有敏感信息的配置文件,比如存放口令的配置文件。
最后一步就是把 .gitignore也提交到Git。
當然檢驗.gitignore的標准是git status命令是不是說working directory clean。
使用Windows時,如果你在資源管理器里新建一個.gitignore文件,它會非常弱智地提示你必須輸入文件名,但是在文本編輯器里“保存”或者“另存為”就可以把文件保存為.gitignore了。有些時候,你想添加一個文件到Git,但發現添加不了,原因是這個文件被.gitignore忽略了:
$ git add App.class
The following paths areignored by one of your .gitignore files:
App.class
Use -f if you really want toadd them.
如果你確實想添加該文件,可以用-f強制添加到Git:
$ git add -f App.class
或者你發現,可能是.gitignore寫得有問題,需要找出來到底哪個規則寫錯了,可以用gitcheck-ignore命令檢查:
$ git check-ignore -v App.class
.gitignore:3:*.class App.class
Git會告訴我們,.gitignore的第3行規則忽略了該文件,於是我們就可以知道應該修訂哪個規則。

小結

l 忽略那些文件,需要編寫 .gitignore;
l .gitignore文件本身要放到版本庫里,並且可以對 .gitignore做版本管理。

配置別名

我們可以對命令配置成別名
比如可以用git st就表示git status
我們只需敲一行命令,告訴Git,以后st就表示 status
git config –globalalias.st status
當然還有別的命令可以簡寫,很多人都用co表示checkout,ci表示commit,br表示branch:
$ git config –globalalias.co checkout
$ git config –globalalias.ci commit
$ git config –globalalias.br branch
–global參數是全局參數,也就是這些命令在這台電腦的所有Git倉庫下都有用。

配置文件

配置Git時,加上 –global 是針對當前用戶起作用的,如果不加,那只針對當前的倉庫起作用。
每個倉庫的Git配置文件都放在 .git/config文件中:
$ cat .git/config
[core]
repositoryformatversion = 0
filemode = true
bare = false
logallrefupdates = true
ignorecase = true
precomposeunicode = true
[remote “origin”]
url = git@github.com:tomato/learngit.git
fetch = +refs/heads/:refs/remotes/origin/
[branch “master”]
remote = origin
merge = refs/heads/master
[alias]
last = log -1
別名就在[alias]后面,要刪除別名,直接把對應的行刪掉即可。
而當前用戶的Git配置文件放在用戶主目錄下的一個隱藏文件.gitconfig中:
$ cat .gitconfig
[alias]
co = checkout
ci = commit
br = branch
st = status
[user]
name = Your Name
email = your@email.com
配置別名也可以直接修改這個文件,如果改錯了,可以刪掉文件重新通過命令配置。

搭建Git服務器

   搭建Git服務器需要准備一台運行Linux的機器,強烈推薦用Ubuntu或Debian,這樣,通過幾條簡單的apt命令就可以完成安裝。
假設你已經有sudo權限的用戶賬號,下面,正式開始安裝。

第一步,安裝git:
sudo apt-get install git
第二步,創建一個git用戶,來運行git服務:
sudo adduser git
第三步,創建證書登錄:
收集所有需要登錄的用戶的公鑰,就是他們自己的id_rsa.pub文件,把所有公鑰導入到/home/git/.ssh/authorized_keys文件里,一行一個。
第四步,初始化Git倉庫:
先選定一個目錄作為一個Git倉庫,假定是 /srv/sample.git ,在 /srv 目錄下輸入命令:
sudo git init–bare sample.git
Git就會創建一個裸倉庫,裸倉庫沒有工作區,因為服務器上的Git倉庫純粹是為了共享,所以不讓用戶直接登錄到服務器上去改工作區,並且服務器上的Git倉庫通常都以.git結尾。然后,把owner改為git:
sudo chown -R git:gitsample.git
第五步,禁用shell登錄,出於安全考慮,第二件創建的git用戶不允許登錄shell,這可以通過編輯 /etc/passwd 文件完成。找到類似下面的一行:
git:x:1001:1001:,,,:/home/git:/bin/bash
改為:
git:x:1001:1001:,,,:/home/git:/usr/bin/git-shell
這樣,git用戶可以通過ssh使用git,但無法登錄shell,因為我們為git用戶指定的git-shell每一次登陸就自動退出。
第六步,克隆遠程倉庫。現在可以通過git clone命令克隆遠程倉庫,在各自的電腦上運行。
gitclone git@server:/srv/sample.git
剩下的便是推送了。

管理公鑰

   如果團隊很小,把每個人的公鑰收集起來放到服務器的/home/git/.ssh/authorized_keys文件里就是可行的。如果團隊有幾百號人,就沒法這么玩了,這時,可以用Gitosis來管理公鑰。這里我們不介紹怎么玩Gitosis了,幾百號人的團隊基本都在500強了,相信找個高水平的Linux管理員問題不大。

管理權限

   有很多不但視源代碼如生命,而且視員工為竊賊的公司,會在版本控制系統里設置一套完善的權限控制,每個人是否有讀寫權限會精確到每個分支甚至每個目錄下。因為Git是為Linux源代碼托管而開發的,所以Git也繼承了開源社區的精神,不支持權限控制。不過,因為Git支持鈎子(hook),所以,可以在服務器端編寫一系列腳本來控制提交等操作,達到權限控制的目的。Gitolite就是這個工具。這里我們也不介紹Gitolite了,不要把有限的生命浪費到權限斗爭中。

小結

搭建Git服務器非常簡單,通常10分鍾即可完成;要方便管理公鑰,用Gitosis;要像SVN那樣變態地控制權限,用Gitolite。

參考文獻:

http://www.liaoxuefeng.com/wiki/0013739516305929606dd18361248578c67b8067c8c017b000
https://git-scm.com/book/en/v2
https://git-scm.com/book/zh/v2


注意!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。



 
粤ICP备14056181号  © 2014-2021 ITdaan.com