玩轉(zhuǎn)Git

其實使用git已經(jīng)有兩年多時間了谴垫,但是對Git的概念一直懵懵懂懂富弦,平時常用的命令就那么幾個而线,而且大部分的時候都是直接使用GitHub DeskTop客戶端操作了锋华。一直想要從頭到尾梳理一下Git嗡官,網(wǎng)上廖雪峰的Git教程是很不錯的,樓主就參照他的教程按照自己的梳理及操作毯焕,再來一遍衍腥。就啰嗦這么多,直接開始吧纳猫。

1 Git簡介

Git是目前世界上最先進(jìn)的分布式版本控制系統(tǒng)婆咸,說到這里我們必須比較一下分布式和集中式版本控制系統(tǒng)的區(qū)別。

  • 集中式版本控制系統(tǒng)芜辕,版本庫是集中存放在中央服務(wù)器的尚骄,而干活的時候,用的都是自己的電腦侵续,所以要先從中央服務(wù)器取得最新的版本乖仇,然后開始干活憾儒,干完活了,再把自己的活推送給中央服務(wù)器乃沙。它最大的毛病集就是必須聯(lián)網(wǎng)才能工作起趾。
  • 分布式版本控制系統(tǒng)根本沒有“中央服務(wù)器”,每個人的電腦上都是一個完整的版本庫警儒,這樣工作的時候训裆,就不需要聯(lián)網(wǎng)了,因為版本庫就在你自己的電腦上蜀铲。既然每個人電腦上都有一個完整的版本庫边琉,那多個人如何協(xié)作呢?比方說你在自己電腦上改了文件A记劝,你的同事也在他的電腦上改了文件A变姨,這時,你們倆之間只需把各自的修改推送給對方厌丑,就可以互相看到對方的修改了定欧。實際使用中分布式版本控制系統(tǒng)通常也有一臺充當(dāng)“中央服務(wù)器”的電腦,但這個服務(wù)器的作用僅僅是用來方便“交換”大家的修改怒竿,沒有它大家也一樣干活砍鸠,只是交換修改不方便而已。

2 Git本地庫與遠(yuǎn)程庫

2.1 創(chuàng)建本地版本庫

版本庫又名倉庫耕驰,英文名repository爷辱,你可以簡單理解成一個目錄,這個目錄里面的所有文件都可以被Git管理起來朦肘,每個文件的修改饭弓、刪除,Git都能跟蹤媒抠,以便任何時刻都可以追蹤歷史示启,或者在將來某個時刻可以“還原”。

創(chuàng)建一個版本庫非常簡單领舰,首先夫嗓,選擇一個合適的地方,創(chuàng)建一個空目錄:

fh:Desktop fenghuoMac$ mkdir learngit
fh:Desktop fenghuoMac$ cd learngit/
fh:learngit fenghuoMac$ pwd
/Users/fenghuoMac/Desktop/learngit

第二步冲秽,通過git init命令把這個目錄變成Git可以管理的倉庫:

fh:learngit fenghuoMac$ git init
Initialized empty Git repository in /Users/fenghuoMac/Desktop/learngit/.git/

倉庫創(chuàng)建好后舍咖,當(dāng)前目錄下會多一個.git目錄,這個目錄是Git來跟蹤管理版本庫的锉桑,沒事千萬不要手動修改這個目錄里面的文件排霉,不然改亂了,就把Git倉庫給破壞了民轴。這個目錄一般是隱藏的攻柠,使用ls -ah可以看到球订。

fh:learngit fenghuoMac$ ls -ah
.   ..  .git

2.2 創(chuàng)建遠(yuǎn)程版本庫

現(xiàn)在已經(jīng)在本地創(chuàng)建了一個Git倉庫后,又想在GitHub創(chuàng)建一個Git倉庫瑰钮,并且讓這兩個倉庫進(jìn)行遠(yuǎn)程同步冒滩。
登錄GitHub,New repository ->輸入Repository Name:learngit浪谴,其他的就按默認(rèn)的來 ->create Repository


image.png

根據(jù)github的提示开睡,可以從這個倉庫克隆出新的倉庫,也可以把一個已有的本地倉庫與之關(guān)聯(lián)苟耻,然后篇恒,把本地倉庫的內(nèi)容推送到GitHub倉庫。


image.png

2.3 本地倉庫與遠(yuǎn)程倉庫關(guān)聯(lián)

2.3.1 先創(chuàng)建本地倉庫凶杖,再關(guān)聯(lián)原地倉庫

樓主一般都是先在本地創(chuàng)建一個本地倉庫胁艰,參看2.1節(jié)創(chuàng)建本地git倉庫,然后在github創(chuàng)建一個遠(yuǎn)程庫learngit智蝠,然后調(diào)用以下命令將本地庫與遠(yuǎn)程倉庫關(guān)聯(lián)起來:

git remote add origin https://github.com/Lisajoy512/learn.git
git push -u origin master

第一次推送master分支時腾么,加上了-u參數(shù),Git不但會把本地的master分支內(nèi)容推送的遠(yuǎn)程新的master分支寻咒,還會把本地的master分支和遠(yuǎn)程的master分支關(guān)聯(lián)起來哮翘,在以后的推送或者拉取時就可以簡化命令颈嚼。
在此過程中毛秘,執(zhí)行g(shù)it push -u origin master可能會出現(xiàn)以下錯誤,錯誤原因在于空目錄不可以提交阻课,因此一般需要在本地倉庫提交一兩個文件才可以執(zhí)行成功叫挟。

error:src refspec master does not match any

2.3.2 先創(chuàng)建遠(yuǎn)程庫,然后clone到本地庫

注意在github上創(chuàng)建時限煞,勾選上initialize this repository with a README選項抹恳。


image.png

執(zhí)行clone命令,將遠(yuǎn)程庫clone到本地

fh:Desktop fenghuoMac$ git clone https://github.com/Lisajoy512/learngit
Cloning into 'learngit'...
remote: Counting objects: 3, done.
remote: Total 3 (delta 0), reused 0 (delta 0), pack-reused 0
Unpacking objects: 100% (3/3), done.
fh:Desktop fenghuoMac$ cd learngit/
fh:learngit fenghuoMac$ ls -au
.       ..      .git        README.md

3 工作區(qū)與暫存區(qū)

3.1 工作區(qū) working directory

工作區(qū)就是你在電腦里能看到的目錄署驻,learngit文件夾就是一個工作區(qū):


image.png

3.2 版本庫

工作區(qū)有一個隱藏目錄.git奋献,這個不算工作區(qū),而是Git的版本庫旺上。

Git的版本庫里存了很多東西瓶蚂,其中最重要的就是稱為stage(或者叫index)的暫存區(qū),還有Git為我們自動創(chuàng)建的第一個分支master宣吱,以及指向master的一個指針叫HEAD窃这。

git-repo

我們把文件往Git版本庫里添加的時候,是分兩步執(zhí)行的:
第一步是用git add把文件添加進(jìn)去征候,實際上就是把文件修改添加到暫存區(qū)杭攻;
第二步是用git commit提交更改祟敛,實際上就是把暫存區(qū)的所有內(nèi)容提交到當(dāng)前分支。

因為我們創(chuàng)建Git版本庫時兆解,Git自動為我們創(chuàng)建了唯一一個master分支馆铁,所以,現(xiàn)在痪宰,git commit就是往master分支上提交更改叼架。
你可以簡單理解為,需要提交的文件修改通通放到暫存區(qū)衣撬,然后乖订,一次性提交暫存區(qū)的所有修改。

4 文件提交

4.1 提交文件git add具练、git commit

fh:learngit fenghuoMac$ git add .
fh:learngit fenghuoMac$ git commit -m "first commit"
[master dc39153] first commit
 1 file changed, 2 insertions(+), 1 deletion(-)

fh:learngit fenghuoMac$ git add .
fh:learngit fenghuoMac$ git commit -m "second commit"
[master cc8b902] second commit
 1 file changed, 2 insertions(+), 1 deletion(-)

4.2查看倉庫狀態(tài) git status

我現(xiàn)在learngit目錄下增加一個test.txt的空文件乍构,然后修改一下README.md。此時使用git status查看下倉庫的狀態(tài)扛点。此時我們可以看到“Changes not staged for commit:modified:README.md”哥遮,“Untracked files:test.txt”

git status
On branch master
Your branch is ahead of 'origin/master' by 2 commits.
  (use "git push" to publish your local commits)
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.md

Untracked files:
  (use "git add <file>..." to include in what will be committed)

    test.txt

no changes added to commit (use "git add" and/or "git commit -a")

現(xiàn)在我們使用“git add .”提交所有的文件,然后再用git status查看倉庫狀態(tài):

fh:learngit fenghuoMac$ git add .
fh:learngit fenghuoMac$ git status
On branch master
Your branch is ahead of 'origin/master' by 2 commits.
  (use "git push" to publish your local commits)
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

    modified:   README.md
    new file:   test.txt

現(xiàn)在陵究,暫存區(qū)的狀態(tài)就變成這樣了:

所以眠饮,git add命令實際上就是把要提交的所有修改放到暫存區(qū)(Stage),然后铜邮,執(zhí)行git commit就可以一次性把暫存區(qū)的所有修改提交到分支∫钦伲現(xiàn)在我們隊修改進(jìn)行commit提交:

fh:learngit fenghuoMac$ git commit -m "third commit"
[master 7e59f25] third commit
 2 files changed, 2 insertions(+), 1 deletion(-)
 create mode 100644 test.txt
fh:learngit fenghuoMac$ git status
On branch master
Your branch is ahead of 'origin/master' by 3 commits.
  (use "git push" to publish your local commits)
nothing to commit, working tree clean

現(xiàn)在版本庫變成了這樣,暫存區(qū)就沒有任何內(nèi)容了:

git-stage-after-commit

接下來我們還要用實踐來證明一點松蒜,git commit只是把暫存區(qū)的文件提交到分支扔茅。我們先對README.md進(jìn)行修改,然后執(zhí)行git add秸苗,然后修改test.txt文件召娜,然后執(zhí)行git commit,最后執(zhí)行git status來查看倉庫狀態(tài)惊楼。我們會發(fā)現(xiàn)text.txt的修改并沒有被提交玖瘸。

fh:learngit fenghuoMac$ git add .
fh:learngit fenghuoMac$ git commit -m "forth commit"
[master 977ad71] forth commit
 1 file changed, 2 insertions(+), 1 deletion(-)
fh:learngit fenghuoMac$ git status
On branch master
Your branch is ahead of 'origin/master' by 4 commits.
  (use "git push" to publish your local commits)
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:   test.txt

no changes added to commit (use "git add" and/or "git commit -a")

4.3 查看工作區(qū)與版本庫的區(qū)別 git diff

使用git diff命令查看,可以看出test.txt確實沒有被提交到版本庫檀咙。

fh:learngit fenghuoMac$ git diff
diff --git a/test.txt b/test.txt
index e69de29..e3a9368 100644
--- a/test.txt
+++ b/test.txt
@@ -0,0 +1 @@
+#1

fh:learngit fenghuoMac$ git diff HEAD -- test.txt
diff --git a/test.txt b/test.txt
index e69de29..e3a9368 100644
--- a/test.txt
+++ b/test.txt
@@ -0,0 +1 @@
+#1

4.4 回顧提交歷史git log

git log命令顯示從最近到最遠(yuǎn)的提交日志雅倒。如果嫌輸出信息過多,可以增加--pretty=oneline參數(shù)攀芯,其中cc8b9024a4f3789aacfdbc423ac64078d607b1a1類似的長串就是我們提交的commit id了屯断,與SVN以遞增的數(shù)字為commit id不同。

fh:learngit fenghuoMac$ git log
commit cc8b9024a4f3789aacfdbc423ac64078d607b1a1 (HEAD -> master)
Author: xxx
Date:   Mon Jan 15 15:31:40 2018 +0800

    second commit

commit dc39153d554fb880d37dc3a0eabb63aa0948b757
Author: xxx
Date:   Mon Jan 15 15:31:04 2018 +0800

    first commit

commit 43167cfad41603614ddc796032fa626aa44bbc44 (origin/master, origin/HEAD)
Author: xxx
Date:   Mon Jan 15 15:20:41 2018 +0800

    Initial commit
fh:learngit fenghuoMac$ 
fh:learngit fenghuoMac$ git log --pretty=oneline
cc8b9024a4f3789aacfdbc423ac64078d607b1a1 (HEAD -> master) second commit
dc39153d554fb880d37dc3a0eabb63aa0948b757 first commit
43167cfad41603614ddc796032fa626aa44bbc44 (origin/master, origin/HEAD) Initial commit

4.5 git reflog

那如果已經(jīng)關(guān)閉了命令行,無從知道“second commit”的commit id怎么辦殖演。放心氧秘,Git提供了一個命令git reflog用來記錄你的每一次命令∨烤茫可以從命令的歷史中得知head現(xiàn)在指向了哪個commit id丸相。

fh:learngit fenghuoMac$ git reflog
cc8b902 (HEAD -> master) HEAD@{0}: reset: moving to cc8b9024a4f3789aacfdbc423ac64078d607b1a1
dc39153 HEAD@{1}: reset: moving to head^
cc8b902 (HEAD -> master) HEAD@{2}: commit: second commit
dc39153 HEAD@{3}: commit: first commit
43167cf (origin/master, origin/HEAD) HEAD@{4}: clone: from https://github.com/Lisajoy512/learngit

5 分支管理

5.1 分支管理常用命令

查看本地分支:$ git branch
查看遠(yuǎn)程分支:$ git branch -r
創(chuàng)建本地分支:$ git branch [name] ----注意新分支創(chuàng)建后不會自動切換為當(dāng)前分支
切換分支:$ git checkout [name]
創(chuàng)建新分支并立即切換到新分支:$ git checkout -b [name]
刪除分支:$ git branch -d [name] ---- -d選項只能刪除已經(jīng)參與了合并的分支,對于未有合并的分支是無法刪除的彼棍。如果想強(qiáng)制刪除一個分支灭忠,可以使用-D選項
合并分支:$ git merge [name] ----將名稱為[name]的分支與當(dāng)前分支合并
創(chuàng)建遠(yuǎn)程分支(本地分支push到遠(yuǎn)程):$ git push origin [name]
刪除遠(yuǎn)程分支:$ git push origin :heads/[name] 或 $ gitpush origin :[name]

檢出倉庫: $ git clone git://github.com/jquery/jquery.git
查看遠(yuǎn)程倉庫:$ git remote -v
添加遠(yuǎn)程倉庫:$ git remote add [name] [url]
刪除遠(yuǎn)程倉庫:$ git remote rm [name]
修改遠(yuǎn)程倉庫:$ git remote set-url --push [name] [newUrl]
拉取遠(yuǎn)程倉庫:$ git pull [remoteName] [localBranchName]
推送遠(yuǎn)程倉庫:$ git push [remoteName] [localBranchName]

如果想把本地的某個分支test提交到遠(yuǎn)程倉庫,并作為遠(yuǎn)程倉庫的master分支座硕,或者作為另外一個名叫test的分支弛作,如下:

$git push origin test:master         // 提交本地test分支作為遠(yuǎn)程的master分支
$git push origin test:test              // 提交本地test分支作為遠(yuǎn)程的test分支

5.2 分支策略

在分支管理策略里,我們常用到的有三種分支:master分支华匾、dev分支映琳、bug分支。
master分支:master主分支應(yīng)該是非常穩(wěn)定的蜘拉,也就是用來發(fā)布新版本萨西,一般情況下不允許在上面干活⌒裥瘢可以在要發(fā)布谎脯,或者說dev分支代碼穩(wěn)定后可以合并到主分支master上來。
dev分支:每個開發(fā)可各自擁有自己的dev分支持寄,平時各自的開發(fā)工作都在dev分支上進(jìn)行源梭。
bug分支:為了修復(fù)bug臨時拉出來的分支。
現(xiàn)在我們著重講一下bug分支际看。假設(shè)現(xiàn)在有一個場景咸产,在dev分支開發(fā)中時接到一個修復(fù)bug的任務(wù)矢否。但是在dev分支上的任務(wù)開發(fā)到一半仲闽,目前還無法提交,此時可以采用保留現(xiàn)場功能僵朗。
比如我們修改一下README.md赖欣,然后git status查看倉庫狀態(tài)會有一條modified提示,然后git stash保留工作現(xiàn)場验庙,最后使用git status查看工作區(qū)就是clean的了顶吮。

fh:learngit fenghuoMac$ git status
On branch master
Your branch is up-to-date with 'origin/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:   README.md

no changes added to commit (use "git add" and/or "git commit -a")
fh:learngit fenghuoMac$ git stash
Saved working directory and index state WIP on master: 4fbda2f sixth commit
fh:learngit fenghuoMac$ git status
On branch master
Your branch is up-to-date with 'origin/master'.
nothing to commit, working tree clean

修改完bug后將代碼合并到master分支后,我們現(xiàn)在要重新切回dev分支繼續(xù)干活粪薛,git stash list查看工作現(xiàn)場悴了,git stash apply恢復(fù)現(xiàn)場。

fh:learngit fenghuoMac$ git checkout wye
Switched to branch 'wye'
fh:learngit fenghuoMac$ git stash list
stash@{0}: WIP on master: 4fbda2f sixth commit
fh:learngit fenghuoMac$ 
Auto-merging README.md
CONFLICT (content): Merge conflict in README.md
fh:learngit fenghuoMac$ git stash list
stash@{0}: WIP on master: 4fbda2f sixth commit

關(guān)于git stash不講太多,還有兩個相關(guān)的命令在這里也捎帶列一下:
git stash drop:git stash apply恢復(fù)湃交,恢復(fù)后熟空,stash內(nèi)容并不刪除,你需要使用git stash drop命令來刪除搞莺。
git stash pop:恢復(fù)的同時把stash內(nèi)容也刪除了息罗。

5.3 分支合并

一開始的時候,master分支是一條線才沧,Git用master指向最新的提交迈喉,再用HEAD指向master,就能確定當(dāng)前分支温圆,以及當(dāng)前分支的提交點:

git-br-initial

每次提交挨摸,master分支都會向前移動一步,這樣岁歉,隨著你不斷提交油坝,master分支的線也越來越長。
當(dāng)我們創(chuàng)建新的分支刨裆,例如dev時澈圈,Git新建了一個指針叫dev,指向master相同的提交帆啃,再把HEAD指向dev瞬女,就表示當(dāng)前分支在dev上:

git-br-create

你看,Git創(chuàng)建一個分支很快努潘,因為除了增加一個dev指針遥缕,改改HEAD的指向,工作區(qū)的文件都沒有任何變化尊勿!

不過靶剑,從現(xiàn)在開始,對工作區(qū)的修改和提交就是針對dev分支了压怠,比如新提交一次后眠冈,dev指針往前移動一步,而master指針不變:

git-br-dev-fd

5.3.1 git merge

5.3.1.1 Fast-forward模式

假如我們在dev上的工作完成了菌瘫,就可以把dev合并到master上蜗顽。Git怎么合并呢?最簡單的方法雨让,就是直接把master指向dev的當(dāng)前提交雇盖,就完成了合并。
這種最簡單的合并方式我們稱為Fast forward模式栖忠,在命令行里可以看到git給我們的“Fast-forward”的提示:

fh:learngit fenghuoMac$ git merge wye
Updating 3ff16c8..75941ab
Fast-forward
 README.md | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)
git-br-ff-merge

5.3.1.2 --no-ff模式

使用Fast forward模式崔挖,刪除分支后贸街,會丟掉分支信息。
如果要強(qiáng)制禁用Fast forward模式狸相,Git就會在merge時生成一個新的commit匾浪,這樣,從分支歷史上就可以看出分支信息卷哩。

fh:learngit fenghuoMac$ git merge --no-ff wye
Merge made by the 'recursive' strategy.
 README.md | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

不使用Fast forward模式蛋辈,merge后就像這樣:

git-no-ff-mode

5.3.2 git rebase

merge和rebase命令都是合并目標(biāo)分支到當(dāng)前分支的,但區(qū)別是rebase命令執(zhí)行后将谊,實際上是將分支點從C移到了G冷溶,這樣分支也就具有了從C到G的功能

image

6 文件撤銷

6.1 撤銷工作區(qū)的修改git checkout -- file

我們現(xiàn)在編輯一下README.md,然后使用git status查看下倉庫狀態(tài)尊浓,然后git checkout -- README.md撤銷修改逞频,最后再使用git status查看一下狀態(tài),會發(fā)現(xiàn)README.md已經(jīng)還原到修改之前了栋齿。

fh:learngit fenghuoMac$ git status
On branch master
Your branch is ahead of 'origin/master' by 4 commits.
  (use "git push" to publish your local commits)
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.md

no changes added to commit (use "git add" and/or "git commit -a")
fh:learngit fenghuoMac$ git checkout -- README.md
fh:learngit fenghuoMac$ git status
On branch master
Your branch is ahead of 'origin/master' by 4 commits.
  (use "git push" to publish your local commits)
nothing to commit, working tree clean

現(xiàn)在我們調(diào)整下步驟苗胀,我們現(xiàn)在編輯一下README.md(現(xiàn)在文件的最后一行內(nèi)容是#5),然后git add提交到暫存區(qū)瓦堵,然后使用git status查看下倉庫狀態(tài)基协,然后git checkout -- README.md撤銷修改,最后再使用cat查看一下文件內(nèi)容:

fh:learngit fenghuoMac$ git add .
fh:learngit fenghuoMac$ git status
On branch master
Your branch is ahead of 'origin/master' by 4 commits.
  (use "git push" to publish your local commits)
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

    modified:   README.md

fh:learngit fenghuoMac$ cat README.md
# learngit
#1 
#2
#3
#4
#5

現(xiàn)在我們繼續(xù)編輯修改README.md(現(xiàn)在文件內(nèi)容最后一行是#6)菇用,然后git checkout -- README.md撤銷修改澜驮,最后再使用cat查看一下文件內(nèi)容:

fh:learngit fenghuoMac$ cat README.md
# learngit
#1 
#2
#3
#4
#5
#6

fh:learngit fenghuoMac$ git checkout -- README.md
fh:learngit fenghuoMac$ cat README.md
# learngit
#1 
#2
#3
#4
#5

命令git checkout -- README.md意思就是,把readme.txt文件在工作區(qū)的修改全部撤銷惋鸥,這里有兩種情況:

  • 一種是readme.txt自修改后還沒有被放到暫存區(qū)杂穷,現(xiàn)在,撤銷修改就回到和版本庫一模一樣的狀態(tài)卦绣;
  • 一種是readme.txt已經(jīng)添加到暫存區(qū)后耐量,又作了修改,現(xiàn)在滤港,撤銷修改就回到添加到暫存區(qū)后的狀態(tài)廊蜒。
    總之,就是讓這個文件回到最近一次git commit或git add時的狀態(tài)蜗搔。git checkout -- file命令中的--很重要劲藐,沒有--八堡,就變成了切換分支的命令了樟凄。

6.2 撤銷暫存區(qū)的修改 git reset

現(xiàn)在我們修改README.md,且將其add到暫存區(qū)兄渺,但是我們想撤銷README.md的修改返回到工作區(qū)怎么操作呢缝龄?在add之后我們可以使用git reset HEAD README.md命令把暫存區(qū)的修改撤銷掉(unstage),重新放回工作區(qū)。這里的HEAD表示的便是最新的版本叔壤,HEAD你也可以自己替換為其他的commit ID表示要回退到哪一次版本瞎饲。

fh:learngit fenghuoMac$ git add .
fh:learngit fenghuoMac$ git status
On branch master
Your branch is ahead of 'origin/master' by 5 commits.
  (use "git push" to publish your local commits)
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

    modified:   README.md

fh:learngit fenghuoMac$ git reset HEAD README.md
Unstaged changes after reset:
M   README.md
fh:learngit fenghuoMac$ git status
On branch master
Your branch is ahead of 'origin/master' by 5 commits.
  (use "git push" to publish your local commits)
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.md

no changes added to commit (use "git add" and/or "git commit -a")

6.3 刪除文件 git rm

我們想要刪除test.txt,可能我們會直接執(zhí)行rm test.txt(此時表示只是在工作區(qū)刪除)命令炼绘,然后執(zhí)行git add test.txt嗅战,最后執(zhí)行git commit -m "delete test.txt",才能真正將刪除提交到版本庫俺亮。
git提供了git rm命令驮捍,執(zhí)行git rm test.txt相當(dāng)于先在工作區(qū)刪除然后提交到暫存區(qū)。最后執(zhí)行最后執(zhí)行git commit -m "delete test.txt"將刪除真正提交到版本庫脚曾。
在研讀廖雪峰老師的使用git checkout -- test.txt撤回刪除時我實踐時遇到了這樣的問題

fh:learngit fenghuoMac$ git rm test.txt
rm 'test.txt'
fh:learngit fenghuoMac$ git status
On branch master
Your branch is ahead of 'origin/master' by 6 commits.
  (use "git push" to publish your local commits)
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

    deleted:    test.txt

fh:learngit fenghuoMac$ git checkout -- test.txt
error: pathspec 'test.txt' did not match any file(s) known to git.

注意這里的報錯原因是:工作區(qū)(已刪除test.txt)與add后的緩存區(qū)(git add test.txt 所以也刪除了test.txt)比較了文件,都是沒有test.txt文件,沒有差異,提示沒有匹配到文件(英文錯誤提示)东且。此時必須用git checkout HEAD test.txt或者git reset命令來恢復(fù)誤刪的文件了。

而如果單純使用rm命令刪除了test.txt文件本讥,則可以使用git checkout -- test.txt恢復(fù)珊泳。git checkout其實是用版本庫里的版本替換工作區(qū)的版本。

fh:learngit fenghuoMac$ rm test.txt
fh:learngit fenghuoMac$ git checkout -- test.txt

7 版本回退

7.1 git reset

根據(jù)6.2節(jié)我們知道git reset命令可以暫存區(qū)的修改回退到工作區(qū)拷沸,現(xiàn)在我們要講的是回退版本色查。
在Git中,用HEAD表示當(dāng)前版本撞芍,也就是最新的提交cc8b9024a4f3789aacfdbc423ac64078d607b1a1综慎,上一個版本就是HEAD^ ,上上一個版本就是HEAD^^ 勤庐,當(dāng)然往上100個版本寫100個^比較容易數(shù)不過來示惊,所以寫成HEAD~100。
回退到過去某個版本
比如我要回退到上一個版本:

fh:learngit fenghuoMac$ git reset --hard head^
HEAD is now at dc39153 first commit
fh:learngit fenghuoMac$ git log --pretty=oneline
dc39153d554fb880d37dc3a0eabb63aa0948b757 (HEAD -> master) first commit
43167cfad41603614ddc796032fa626aa44bbc44 (origin/master, origin/HEAD) Initial commit

回退到某個未來的版本
比如我們已回退到“first commit”的版本愉镰,但現(xiàn)在后悔了想回到“second commit”版本米罚,只要命令行窗口沒關(guān)閉我們知道“second commit”的commit id(一般寫commit id頭幾位便可以,git會自動尋找)便可以回退:

fh:learngit fenghuoMac$ git reset --hard cc8b9024a4f3789aacfdbc423ac64078d607b1a1
HEAD is now at cc8b902 second commit
fh:learngit fenghuoMac$ git log --pretty=oneline
cc8b9024a4f3789aacfdbc423ac64078d607b1a1 (HEAD -> master) second commit
dc39153d554fb880d37dc3a0eabb63aa0948b757 first commit
43167cfad41603614ddc796032fa626aa44bbc44 (origin/master, origin/HEAD) Initial commit

git里面回退是非常高效的丈探,因為Git在內(nèi)部有個指向當(dāng)前版本的HEAD指針录择,當(dāng)你回退版本的時候,Git僅僅是把HEAD指向你要回退的那個版本了碗降。
reset參數(shù)詳解:
--soft – 緩存區(qū)和工作目錄都不會被改變
--mixed – 默認(rèn)選項隘竭。緩存區(qū)和你指定的提交同步,但工作目錄不受影響
--hard – 緩存區(qū)和工作目錄都同步到你指定的提交

這些標(biāo)記往往和HEAD作為參數(shù)一起使用讼渊。比如:
git reset --mixed HEAD 將你當(dāng)前的改動從緩存區(qū)中移除动看,但是這些改動還留在工作目錄中。
另一方面爪幻,如果你想完全舍棄你沒有提交的改動菱皆,你可以使用git reset --hard HEAD须误。這是git reset最常用的兩種用法。

7.2 git revert

Revert撤銷一個提交的同時會創(chuàng)建一個新的提交仇轻。這是一個安全的方法京痢,因為它不會重寫提交歷史。比如篷店,下面的命令會找出倒數(shù)第二個提交祭椰,然后創(chuàng)建一個新的提交來撤銷這些更改,然后把這個提交加入項目中疲陕。

相比git reset吭产,它不會改變現(xiàn)在的提交歷史。因此鸭轮,git revert可以用在公共分支上臣淤,git reset應(yīng)該用在私有分支上。
你也可以把git revert當(dāng)作撤銷已經(jīng)提交的更改窃爷,而git reset HEAD用來撤銷沒有提交的更改邑蒋。
然后我們可以通過git revert --abort來取消這次revert。

就像git checkout 一樣按厘,git revert 也有可能會重寫文件医吊。所以,Git會在你執(zhí)行revert之前要求你提交或者緩存你工作目錄中的更改逮京。

8 標(biāo)簽管理

git中的標(biāo)簽相關(guān)的功能非常簡單卿堂,這里就不贅述了。常用命令有:
查看版本:$ git tag
創(chuàng)建版本:$ git tag [name]
刪除版本:$ git tag -d [name]
查看遠(yuǎn)程版本:$ git tag -r
創(chuàng)建遠(yuǎn)程版本(本地版本push到遠(yuǎn)程):$ git push origin [name]
刪除遠(yuǎn)程版本:$ git push origin :refs/tags/[name]
合并遠(yuǎn)程倉庫的tag到本地:$ git pull origin --tags
上傳本地tag到遠(yuǎn)程倉庫:$ git push origin --tags
創(chuàng)建帶注釋的tag:$ git tag -a [name] -m 'yourMessage'
列舉一個工作可能遇到的小意外懒棉,假如本應(yīng)在上周五打tag時忘記了草描,現(xiàn)在已經(jīng)是下周一了,怎么辦策严?很簡單穗慕,找到上周五提交的commit id,然后在這次的commit id上打tag妻导。

git tag v0.9 6224937

9 忽略文件

有些時候逛绵,你必須把某些文件放到Git工作目錄中,但又不能提交它們倔韭,比如保存了數(shù)據(jù)庫密碼的配置文件啦术浪,等等,每次git status都會顯示Untracked files ...寿酌,有強(qiáng)迫癥的童鞋心里肯定不爽胰苏。
這個問題解決起來也很簡單,在Git工作區(qū)的根目錄下創(chuàng)建一個特殊的.gitignore文件份名,然后把要忽略的文件名填進(jìn)去碟联,Git就會自動忽略這些文件妓美。
忽略文件這個比較簡單僵腺,就提示一下樓主遇到的坑鲤孵,比如我在.gitignore里添加了README.md文件,然后修改README.md文件再add發(fā)現(xiàn)依然可以提交辰如,這種情況是因為新建的文件在git中會有緩存普监,如果某些文件已經(jīng)被納入了版本管理中,就算是在.gitignore中已經(jīng)聲明了忽略路徑也是不起作用的琉兜,這時候我們就應(yīng)該先把本地緩存刪除凯正,然后再進(jìn)行g(shù)it的push,這樣就不會出現(xiàn)忽略的文件了豌蟋。git清除本地緩存命令如下:

git rm -r --cached .
git add .
git commit -m 'update .gitignore'

10 參考文章:

廖雪峰的Git教程
Git簡介及常用命令
Git使用詳細(xì)教程
代碼回滾:git reset廊散、git checkout和git revert區(qū)別和聯(lián)系
Git的奇技淫巧??
Learn Git Branching

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市梧疲,隨后出現(xiàn)的幾起案子允睹,更是在濱河造成了極大的恐慌,老刑警劉巖幌氮,帶你破解...
    沈念sama閱讀 212,542評論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件缭受,死亡現(xiàn)場離奇詭異,居然都是意外死亡该互,警方通過查閱死者的電腦和手機(jī)米者,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,596評論 3 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來宇智,“玉大人蔓搞,你說我怎么就攤上這事∷骈伲” “怎么了败明?”我有些...
    開封第一講書人閱讀 158,021評論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長太防。 經(jīng)常有香客問我妻顶,道長,這世上最難降的妖魔是什么蜒车? 我笑而不...
    開封第一講書人閱讀 56,682評論 1 284
  • 正文 為了忘掉前任讳嘱,我火速辦了婚禮,結(jié)果婚禮上酿愧,老公的妹妹穿的比我還像新娘沥潭。我一直安慰自己,他們只是感情好嬉挡,可當(dāng)我...
    茶點故事閱讀 65,792評論 6 386
  • 文/花漫 我一把揭開白布钝鸽。 她就那樣靜靜地躺著汇恤,像睡著了一般。 火紅的嫁衣襯著肌膚如雪拔恰。 梳的紋絲不亂的頭發(fā)上因谎,一...
    開封第一講書人閱讀 49,985評論 1 291
  • 那天,我揣著相機(jī)與錄音颜懊,去河邊找鬼财岔。 笑死,一個胖子當(dāng)著我的面吹牛河爹,可吹牛的內(nèi)容都是我干的匠璧。 我是一名探鬼主播,決...
    沈念sama閱讀 39,107評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼咸这,長吁一口氣:“原來是場噩夢啊……” “哼夷恍!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起媳维,我...
    開封第一講書人閱讀 37,845評論 0 268
  • 序言:老撾萬榮一對情侶失蹤酿雪,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后侨艾,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體执虹,經(jīng)...
    沈念sama閱讀 44,299評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,612評論 2 327
  • 正文 我和宋清朗相戀三年唠梨,在試婚紗的時候發(fā)現(xiàn)自己被綠了袋励。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,747評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡当叭,死狀恐怖茬故,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情蚁鳖,我是刑警寧澤磺芭,帶...
    沈念sama閱讀 34,441評論 4 333
  • 正文 年R本政府宣布,位于F島的核電站醉箕,受9級特大地震影響钾腺,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜讥裤,卻給世界環(huán)境...
    茶點故事閱讀 40,072評論 3 317
  • 文/蒙蒙 一放棒、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧己英,春花似錦间螟、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,828評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽荣瑟。三九已至,卻和暖如春摩泪,著一層夾襖步出監(jiān)牢的瞬間笆焰,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,069評論 1 267
  • 我被黑心中介騙來泰國打工加勤, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留仙辟,地道東北人同波。 一個月前我還...
    沈念sama閱讀 46,545評論 2 362
  • 正文 我出身青樓鳄梅,卻偏偏與公主長得像,于是被迫代替她去往敵國和親未檩。 傳聞我的和親對象是個殘疾皇子戴尸,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,658評論 2 350