天天看點

Git學習筆記

Git學習筆記

​​ Remote:遠端倉庫 Repository:本地倉庫

​​ Workspace: 工作區 Index: 暫存區

安裝Git

Windows

​ 在官網

下載下傳安裝程式

, 然後按預設選項安裝即可。

Git學習筆記

​ 安裝完成後,在開始菜單裡找到“Git”->“Git Bash”,蹦出一個類似指令行視窗的東西,就說明Git安裝成功!

Git學習筆記

Linux

​ 系統版本:CentOS 7.3,x86_64 , root使用者

Git學習筆記

​ 檢視系統是否已安裝git :

git --version

, 如果提示

bash: /usr/bin/git: No such file or directory

,則說明系統中還沒有安裝git; 如果顯示了git 版本号,則證明系統中已經安裝了git。

​ Redhat系的Linux發行版,安裝git最便捷的方法是直接使用yum 安裝:

yum install git

, 但是經過測試,CentOS 7.3 通過yum 安裝的Git 版本預設為v1.8.3 , 而目前git最新版本為v2.16.0,低版本的git存在安全漏洞,是以不建議使用yum安裝,推薦使用源碼安裝git.

  1. 解除安裝已經安裝的低版本的git:

    yum remove git

  2. 安裝git依賴包
sudo yum groupinstall "Development Tools" 
sudo yum install -y curl-devel expat-devel gettext-devel openssl-devel perl-CPAN perl-devel zlib-devel
           
  1. 依賴包安裝完成後,需要找出并 下載下傳最新版本的git ,,位于清單頂部的是最新版本,注意不要選擇帶有-rc的版本,因為它代表了一個候選釋出版本。
    Git學習筆記
    選擇最新的版本 ,使用wget下載下傳:
wget https://github.com/git/git/archive/v2.15.1.tar.gz
           
  1. 安裝git
#解壓
tar -zxvf git.tar.gz 
#編譯
cd git*   #進入git解壓目錄
make configure
./configure   --prefix=/usr/local/
make prefix=/usr/local/ all
make install
           
  1. 檢視版本

    git --version

    , 如果顯示的git版本還是v1.8或提示找不到git目錄,執行指令:

    cp /usr/local/bin/git* /usr/bin/

    ,就可以了。
    Git學習筆記

設定Git

​ 設定你的一些個人資訊,如你送出的姓名和電子郵件:

$ git config --global user.name 'shijianzhihu'
$ git config --global user.email '[email protected]'

#檢視所有已配置的全局資訊
$ git config --list 
           

Git 常用指令

以下所有的指令說明都基于Git v2.13.0,不同版本的Git ,指令可能會有所差別!

$ git --version #檢視git 版本

$ git [command] --help #檢視command使用者手冊

git clone

git clone

用來從從遠端主機克隆一個版本庫,文法為:

git clone <版本庫位址>

,該指令會在本地主機生成一個與遠端主機版本庫同名的目錄,如果要指定不同的目錄名,可以将目錄名作為

git clone

指令的第二個參數:

git clone <版本庫的網址> <本地目錄名>

git remote

Git要求每個遠端主機都必須指定一個主機名。

git remote

指令就用于管理主機名.

#檢視所有遠端主機名
$ git remote
origin

#檢視遠端主機位址
$ git remote -v
origin  https://github.com/naver/ngrinder.git (fetch)
origin  https://github.com/naver/ngrinder.git (push)
           

git fetch

一旦遠端主機的版本庫有了更新,需要将這些更新取回本地,這時就要用到

git fetch

指令.

#将遠端主機的所有分支的更新取回本地
$ git fetch <遠端主機名>
如:git fetch origin

#取回指定分支的更新
$ git fetch <遠端主機名> <分支名>
如:git fetch origin dev
           

git branch

git branch

用來顯示、建立或删除分支。

OPTIONS

# 不帶參數時,會列出所有本地分支,并且在目前分支前加"*";
$ git branch
  dev
  master
* test

<newBranch>
#建立本地分支,但不會自動切換到該分支
$ git branch bug-fixed

<-r, --remotes>
#列出所有遠端分支
$ git branch -r
  origin/bug-fixed
  origin/b2b
  origin/beta
  origin/collections
  origin/chart

<-a --all>
#列出所有本地分支和遠端分支
$ git branch -a

<-m ,--move | -M>
#移動/重命名一個分支和相應的曆史資訊
#<-M>:強制move/rename
$ git branch -m bug-fixed bug-fixed2

<-d, --delete | -D>
#删除本地分支,不能删除目前checkout的分支;
#如果要删除的分支有未合并的内容,則會報錯:'the branch  XXX is not fully merged',解決辦法:使用'-D' 強制删除;
$ git branch -D 'bug-fixed'

#補充:利用shell管道指令實作批量删除分支
$ git branch | grep 'branchName' | xargs branch -D

<--set-upstream-to origin/branchname localBranchname>
注意,<–set-upstream-to> 在已經替代了 <–set-upstream>,二者跟随的參數需要對調一下位置;
#設定本地分支與遠端分支關聯,如果沒有關聯的情況下,git pull 會提示如下資訊:
$ git push origin test
$ git pull
There is no tracking information for the current branch.
Please specify which branch you want to merge with.
See git-pull(1) for details.

    git pull <remote> <branch>

If you wish to set tracking information for this branch you can do so with:

    git branch --set-upstream-to=origin/<branch> test
    
設定遠端關聯分支的方法,如下
$ git branch --set-upstream-to origin/test test
Branch test set up to track remote branch test from origin.
$ git pull
Already up-to-date.

<-v, --verbose | -vv>
#<-v>:檢視本地分支最後的修改資訊,目前分支名稱前會帶有'*'
$ git branch -av
  bug-fixed3 fdcbdf7 add bug -fixed2
  dev        1599863 test
* master     9faecaf [ahead 1] update test.txt  #[ahead 1]表示本地分支比遠端分支領先一個commit
  test       1599863 test
  remotes/origin/HEAD       -> origin/master
  remotes/origin/bug-fixed3 fdcbdf7 add bug -fixed2


#<-vv>:在git branch -v的基礎上,顯示本地分支的遠端關聯分支(upstream branch);
#檢視遠端關聯分支,可以使用git config --list指令
$ git branch -vv
  bug-fixed3 fdcbdf7 add bug -fixed2
  dev        1599863 test
* master     9faecaf [origin/master: ahead 1] update test.txt 
  test       1599863 test
           

git checkout

git checkout

用來切換分支或恢複工作樹檔案。

<branch>
#切換目前分支到本地已有分支
$ git checkout dev
Switched to branch 'dev'

#建立本地分支,并切換到該分支
$ git checkout -b five
Switched to a new branch 'five'

#建立本地分支,并切換到該分支,而且關聯遠端分支
$ git checkout -b six --track origin/dev
Switched to a new branch 'six'
Branch six set up to track remote branch dev from origin.

第三條指令相當于以下指令的合集:
$ git branch 
$ git checkout six
$ git branch --set-upstream-to origin/dev six

<-- fileNmae> #'--' 和'fileName'之間有空格!
#将指定檔案在工作區的修改撤銷到最近一次git add 或git commit時的内容(隻對tracked file有效)
比如下面的兩個例子:
$ cat test.txt
one
$ git add . -v
add 'test.txt'
$ git commit -m 'update test.txt'
[test a2d987d] update test.txt
 1 file changed, 1 insertion(+)
$ vim test.txt
$ cat test.txt
one
two
$ git checkout -- test.txt #注意空格,否則報錯
$ cat test.txt
one
$ git status 
nothing to commit, working tree clean
****************************************
$ cat test.txt
one
two
$ vim test.txt
$ cat test.txt
one
two
three
$ vim test.txt
$ cat test.txt
one
two
three
four
$ git checkout -- test.txt
$ cat test.txt
one
two

補充:
$ git checkout -- stu.txt test.txt
$ git checkout -- *
$ git checkout -- *.txt

# git checkout -- 不加檔案名來檢視目前工作區修改了哪些檔案
$ git checkout --
M       blog.txt
D       start.txt
Your branch is up-to-date with 'origin/sprider'.

# 取檔案在commit_id時的版本
$ git checkout 1599863 fileName
           

git status

git status

用來顯示工作樹狀态, git會非常友好的提示使用者下一步的操作,請看下面的例子:

$ git status
On branch test
Your branch is up-to-date with 'origin/test'.
Untracked files:
  (use "git add <file>..." to include in what will be committed)

        blog.txt

nothing added to commit but untracked files present (use "git add" to track)

$ git add blog.txt

$ git status
#
On branch test
Your branch is up-to-date with 'origin/test'.
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

        new file:   blog.txt

$ git commit -m 'add blog.txt'
$ git status
On branch test
Your branch is ahead of 'origin/test' by 1 commit.
  (use "git push" to publish your local commits)
nothing to commit, working tree clean
           

git add

git add

指令主要用于把我們要送出的檔案的資訊添加到索引庫(Index)中。當我們使用

git commit

時,git将依據索引庫中的内容來進行檔案的送出。

git add

指令可以在commit之前多次執行。

Git學習筆記

git add file

COMMON OPTIONS

<pathspec>
#可以使用'*'模糊比對路徑
$ git add *.c
# 路徑可以到目錄層級
$ git add test/

<-v,--verbose>
#顯示本次added的檔案名
$ git add -v file3.txt
add 'file3.txt'
$ git add -v study/
add 'study/study.txt'

<-f, --force>
#允許添加被忽略的檔案
#關于git忽略檔案的介紹,見下一小節
$ git add -f commonVars.pyc

<-u, --update>
#add被修改(modified)和被删除(deleted)檔案,不包含新檔案(new,untracked file)
$ git add -uv

<-A, --all>
#add所有變化,包括被修改(modified)、被删除(deleted)檔案和包括新檔案(new)
$ git add -Afv
           

git add -A | git add -u |git add .

  • git add

    .:他會監控工作區的狀态樹,使用它會把工作時的所有變化送出到暫存區,包括modified、new和deleted ;
  • git add -u

    :他僅監控已經被add的檔案(即tracked file),他會将被修改的檔案送出到暫存區。add -u 不會送出new(untracked file);
  • git add -A

    :等同于 git add .;

    注意,在Git v1.x.x版本,git add . 不能添加deleted檔案

git 特殊檔案

有些時候,我們必須或被必須把某些檔案放到Git的工作目錄中,但是又不能送出它們。這就導緻每次

git status

都會顯示Untracked files ... 。為了解決這個檔案,可以在Git工作區的根目錄下建立一個特殊的.gitignore檔案,這個檔案的作用就是告訴Git哪些檔案不需要添加到版本管理中。實際項目中,很多檔案都是不需要版本管理的,比如Python的.pyc檔案和一些包含密碼的配置檔案等等。這個檔案的内容是一些規則,Git會根據這些規則來判斷是否将檔案添加到版本控制中。

Git bash建立".gitignore" :

vim .gitignore

, GitHub中已經為我們準備了各種配置檔案,隻需要組合一下就可以使用了。所有配置檔案可以直接線上浏覽:

https://github.com/github/gitignore

常用的規則有:

1. /mtk/        #過濾整個檔案夾
2. *.zip          #過濾所有.zip檔案
3. /mtk/do.c   #過濾某個具體檔案
           
忽略檔案的原則是:
  • 忽略作業系統自動生成的檔案,比如縮略圖等;
  • 忽略編譯生成的中間檔案、可執行檔案等,也就是如果一個檔案是通過另一個檔案自動生成的,那自動生成的檔案就沒必要放進版本庫,比如Java編譯産生的.class檔案;
  • 忽略你自己的帶有敏感資訊的配置檔案,比如存放密碼的配置檔案。
Git學習筆記

git commit

git commit

記錄對存儲庫的更改資訊,此指令預設送出的是暫存區的内容,也就是 Changes to be committed 中的檔案,最常用的參數是<-m>,用來添加本次送出的相關資訊,如:git commit -m 'update file'

如果使用了<-a>參數,則除了将暫存區裡的檔案送出外,還送出 Changes but not updated 中的檔案。通常我們送出git的時候都是通過以下三大步:

git add .
git commit -m "some str"
git push
           

實際上,你隻需要兩條指令就夠了,除非有新的檔案(untracked file)要被添加進去。

git commit -am "some str"
git push
           

git pull

git pull指令的作用是,取回遠端主機指定分支的更新,再與本地的指定分支合并。實質上等同于先做git fetch,再做git merge.

#完整格式
$ git pull <遠端主機名> <遠端分支名>:<本地分支名>

#比如:取回origin主機的bugifx分支與本地的bugfix2分支合并,需要寫成下面這樣
git pull origin bugfix:bugfix2

#如果遠端分支是與目前分支合并,則本地分支名可以省略
$ git pull origin dev

#如果目前分支與遠端分支存在關聯關系,遠端分支名也可以省略
$ git pull origin

#如果目前分支隻有一個追蹤分支,則遠端主機名也可以省略
$ git pull
#上面指令表示為:目前分支自動與唯一一個追蹤分支進行合并

**********************************************************
#如果合并需要使用rebase模式,可以加上'-- rebase'選項
$ git pull --rebase <遠端主機名> <遠端分支名>:<本地分支名>
**********************************************************

#如果遠端主機删除了某個分支,預設情況下,git pull 不會在拉取遠端分支的時候,删除對應的本地分支。這是為了防止,由于其他人操作了遠端主機,導緻git pull不知不覺删除了本地分支。但是,你可以改變這個行為,加上參數 -p 就會在本地删除遠端已經删除的分支。
$ git pull -p
# 等同于下面的指令
$ git fetch --prune origin 
$ git fetch -p
           

git:檢視追蹤分支

#這個資訊實際是存在config 檔案中的,可以用下面的指令來檢視xxx分支的資訊
$ git config -l |grep 'branch.xxx'

# git v2.15+版本,可以使用以下指令檢視追蹤分支資訊
$ git branch -vv
           
Git學習筆記
Git學習筆記

git:手動設定追蹤分支

#方法一
$ git branch --set-upsteam XXX origin/xxxx

#方法二
#删掉本地分支,然後重新建立此分支,并且指定其 track 資訊
$ git checkout -b XXX --track origin/xxxx
           

git push

git push

指令用于将本地分支的更新,推送到遠端主機。它的指令格式與git pull指令相仿但不要搞混了,其實很容易了解區分的.

#完整格式
$ git push <遠端主機名> <本地分支名>:<遠端分支名>

#如果省略遠端分支名,則表示将本地分支推送與之存在"追蹤關系"的遠端分支(通常兩者同名)
#如果該遠端分支不存在,則會被建立。
$ git push origin dev

#如果省略本地分支名,則表示删除指定的遠端分支,因為這表示推送一個空的本地分支到遠端分支。
$ git push origin :dev
#注意origin 和冒号之間需要有空格

#如果目前分支與遠端分支存在關聯關系,遠端分支名也可以省略
$ git push origin
如果目前分支與遠端分支沒有追蹤關系,則會報錯:
fatal: The current branch bug-fixed2 has no upstream branch.
To push the current branch and set the remote as upstream, use
    git push --set-upstream origin bug-fixed2
    
#如果目前分支隻有一個追蹤分支,則遠端主機名也可以省略
$ git push
           

git log | git reflog

git log 用來檢視目前分支的送出曆史,不包含已經被撤銷的commit:

$ git log
commit 150089329868f665cfd6a1f1ac301d31ff232c75 (HEAD -> sprider)
Author: xxxxx <[email protected]>
Date:   Tue Feb 6 14:14:06 2018 +0800
    Revert "test"
    This reverts commit 5e2d6fc0bd652de0e612e50b84edb9b933d2d459.
commit 5e2d6fc0bd652de0e612e50b84edb9b933d2d459
Author: xxxxx <[email protected]>
Date:   Tue Feb 6 14:13:54 2018 +0800
    test
           

如果嫌輸出資訊太多,以試試加上--oneline參數:

$ git log --oneline
1500893 (HEAD -> sprider) Revert "test"
5e2d6fc test
a0eb8b5 update blog.txt
ec9734c Revert "start test"
1616640 Revert "blog"
           

顯示每次送出的内容差異可以使用< -p> 參數,<-n>則為僅顯示最近的n次曆史:

$ git log -p -1
commit 150089329868f665cfd6a1f1ac301d31ff232c75 (HEAD -> sprider)
Author: xxxxx <[email protected]>
Date:   Tue Feb 6 14:14:06 2018 +0800
    Revert "test"
    This reverts commit 5e2d6fc0bd652de0e612e50b84edb9b933d2d459.
diff --git a/blog b/blog
index 40a3b4a..9daeafb 100644
--- a/blog
+++ b/blog
@@ -1 +1 @@
-test111
+test
           

git reflog 用來顯示整個本地倉儲的commit, 包括所有branch的commit, 甚至包括已經撤銷的commit, 隻要HEAD發生了變化(如checkout branch, pull, commit等), 就會在reflog裡面看得到。

$ git reflog
1500893 (HEAD -> sprider) HEAD@{0}: checkout: moving from six to sprider
02cffe0 (six) HEAD@{1}: commit: branch six
1599863 (origin/dev, five) HEAD@{2}: checkout: moving from sprider to six
1500893 (HEAD -> sprider) HEAD@{3}: revert: Revert "test"
5e2d6fc HEAD@{4}: commit: test
           

git revert | git reset

git revert

用來復原一些現有的送出, 但并不是從項目曆史中移除這個commit,舊的commit還是保留在曆史項目裡面的,而git reset 則會删除舊的commit, 這樣做的好處是防止了項目丢失曆史。

用法:

git revert <commit-id>

$ git log --oneline | head -n 1
a0eb8b5 update blog.txt

$ git revert HEAD
[sprider 60d4654] Revert "update blog.txt"
 1 file changed, 1 insertion(+), 2 deletions(-)
 
$ git log --oneline | head -n 2
60d4654 Revert "update blog.txt"
a0eb8b5 update blog.txt
           

git reset <--hard|soft|mixed|merge|keep> commit 也是常用的版本復原指令,其中比較重要的參數是mode,也就是 --hard、--soft、--mixed。。。比較常見的是--hard和--soft;

--hard是指完全重設,會把回退到某版本之後的修改全部删除,

--soft這是個回退解體,讓版本庫回退到某個版本,這個版本之後的修改全部存在緩存區,這個時候在commit的話,又會把會退的部分重新加載到最新版本中;

git diff

git diff

用于比較兩次修改之間的差異。

  • 比較工作區與暫存區

git diff 不加參數即預設比較工作區與暫存區

$ git diff
diff --git a/b2.txt b/b2.txt
index be738a5..2ffe5d8 100644
--- a/b2.txt
+++ b/b2.txt
@@ -1,2 +1,2 @@
 test1
-test222
+22dsada2
           
  • 比較暫存區與最新本地版本庫

    git diff --cached

  • 比較工作區與最新本地版本庫

    git diff HEAD

  • 比較工作區與指定commit-id的差異

    git diff commit-id

  • 比較暫存區與指定commit-id的差異

    git diff --cached commit-id

  • 比較兩個commit-id之間的差異

    git diff commit-id commit-id

git stash

git stash 用來備份目前的工作區的内容,從最近的一次送出中讀取相關内容,讓工作區保證和上次送出的内容一緻。同時,将目前的工作區内容儲存到Git棧中。

git stash list 顯示Git棧内的所有備份,可以利用這個清單來決定從那個地方恢複。

git stash clear 清空Git棧.

git stash pop 從Git棧中讀取最近一次stash的内容,恢複工作區的相關内容。

兩種恢複方法:

  • 用git stash apply恢複,但是恢複後,stash内容并不删除,你需要用git stash drop來删除;
  • 用git stash pop,恢複的同時把stash内容也删了;

可以多次stash,恢複的時候,先用git stash list檢視,然後恢複指定的stash,用指令:

git stash apply stash@{0}

git rm

git rm

用于從從工作樹和暫存區中删除檔案,他作用的對象隻能是tracked files .

它的作用和

git add

類似,可以了解為一個是添加一個是修改。

git rm

要和

git commit

配合使用,才真正能起到删除的作用。

$ git rm test.txt stu.txt
rm 'stu.txt'
rm 'test.txt'
$ git status
On branch test
Your branch is up-to-date with 'origin/test'.
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

        deleted:    stu.txt
        deleted:    test.txt
$ git commit -m 'delete two files'
[test ccd7143] delete two files
 2 files changed, 4 deletions(-)
 delete mode 100644 stu.txt
 delete mode 100644 test.txt
$ git status
On branch test
Your branch is ahead of 'origin/test' by 1 commit.
  (use "git push" to publish your local commits)
nothing to commit, working tree clean

#删除檔案夾,-r表示遞歸删除,-f表示強制删除
$ git rm -rf qt/ 
rm 'qt/file.txt'

$ git rm -f rainbow.txt #不能對untracked file使用
fatal: pathspec 'rainbow.txt' did not match any files
           

git rm 和 rm 的差別

通過上面簡單的介紹,我們發現

git rm

和 shell 指令

rm

非常相似,我們是否可以不使用

git rm

,而是直接

rm

後,然後再

git add/commit

,這樣是否可以呢? 答案當然是可以的。

使用

git rm

來删除檔案,git同時會将操作月曆記錄下來,

git log

就可以看到;而使用

rm

來删除檔案,git并不會記錄,這也是十分易于了解的。直覺的來講,

git rm

删除過的檔案,執行

git commit -m "abc"

送出時,會自動将删除該檔案的操作送出上去;而對于用

rm

指令直接删除的檔案,執行

git commit -m "abc"

送出時,則不會将删除該檔案的操作送出上去。不過不要緊,即使你已經通過 rm 将某個檔案删除掉了,也可以再通過

git rm

指令重新将該檔案從 git 的記錄中删除掉,這樣的話,在執行

git commit -am "abc"

後,也能将這個删除操作送出上去。(

git commit -am

寫成

git commit -ma

會報錯)

一般說來,在git目錄下删除檔案時,可以選擇以下兩種方式:

  • git rm + git commit -m 'text'
  • rm + git commit -am 'text'

git mv

git mv

用來移動或重命名檔案、目錄或符号連結。

$ git mv b1.txt b2.txt
$ git mv rainbow.txt sprider/
$ git status
On branch sprider
Your branch is ahead of 'origin/sprider' by 1 commit.
  (use "git push" to publish your local commits)
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)
        renamed:    b1.txt -> b2.txt
        renamed:    rainbow.txt -> sprider/rainbow.txt
        
$ git commit -m 'rename and move'
[sprider b08e44d] rename and move
 2 files changed, 0 insertions(+), 0 deletions(-)
 rename b1.txt => b2.txt (100%)
 rename rainbow.txt => sprider/rainbow.txt (100%)
           

參考文檔

  1. Git 教程 ,廖雪峰
  2. Git遠端操作詳解 ,阮一峰
  3. Git忽略規則.gitignore梳理 ,散盡浮華
  4. git的reset和checkout的差別 ,chanjarster
  5. git add -A 和 git add . 的差別 ,PajamaCat
  6. git branch用法總結 ,KKK_Kevin
  7. Git自學之路(四) - gitbranch 分支 ,JunkChen-程開均
  8. Git中的upstream和downstream概述 ,易生一世
  9. “git rm” 和“rm”的差別 ,jfkidear
  10. git commit -m與git commit -am的差別
  11. Git的撤消操作 - 重置, 簽出 和 撤消