1. 程式人生 > >Git從入門到熟練使用

Git從入門到熟練使用

Git 基礎

基本原理

  • 客戶端並不是只提取最新版本的檔案快照,而是把程式碼倉庫完整的映象下來。這樣一來,任何一處協同工作用的伺服器發生故障,事後都可以用任何一個映象出來的本地倉庫恢復。每一次的克隆操作,實際上都是一次對程式碼倉庫的完整備份。

Git的優勢

直接記錄快照

  • Git 更像是把資料看作是對小型檔案系統的一組快照。 每次你提交更新,或在 Git 中儲存專案狀態時,它主要對當時的全部檔案製作一個快照並儲存這個快照的索引。 為了高效,如果檔案沒有修改,Git 不再重新儲存該檔案,而是隻保留一個連結指向之前儲存的檔案。 Git 對待資料更像是一個 快照流

  • 如圖,在version2中的 B 即是因為 File B 沒有改變,所以直接儲存了一個指向 FileB 的連結。只有修改了的檔案才會產生一個新的檔案,覆蓋原來的檔案。

git儲存專案雖時間改變的快照.png

幾乎所有操作都在本地執行

  • 在 Git 中的絕大多數操作都只需要訪問本地檔案和資源,一般不需要來自網路上其它計算機的資訊。因為你在本地磁碟上就有專案的完整歷史,所以大部分操作看起來瞬間完成。

Git保證完整性

  • Git 中所有資料在儲存前都計算校驗和,然後以校驗和來引用。Git 用以計算校驗和的機制叫做 SHA-1 雜湊(hash,雜湊)。Git 資料庫中儲存的資訊都是以檔案內容的雜湊值來確定的,而不是檔名。
  • 這意味著不可能在 Git 不知情時更改任何檔案內容或目錄內容。 這個功能建構在 Git 底層,是構成 Git 哲學不可或缺的部分。 若你在傳送過程中丟失資訊或損壞檔案,Git 就能發現。

Git一般只新增資料

  • 你執行的 Git 操作,幾乎只往 Git 資料庫中增加資料。 很難讓 Git 執行任何不可逆操作,或者讓它以任何方式清除資料。 同別的 VCS 一樣,未提交更新時有可能丟失或弄亂修改的內容;但是一旦你提交快照到 Git 中,就難以再丟失資料,特別是如果你定期的推送資料庫到其它倉庫的話。這個特性使得我們可以盡情的嘗試對Git進行操作而不用害怕把它改壞了,只需要回滾即可。

需要注意的重點

三種狀態

  • 已提交 committed :資料已經儲存在本地 Git 倉庫

  • 已修改 modified : 修改了檔案,但是還沒儲存在倉庫中

  • 已暫存 staged : 對一個已修改的檔案的當前版本做了標記

工作目錄,暫存區域及Git倉庫.png

三個區域

  • 工作目錄 Working Directory :對專案的某個版本獨立提取出來的內容,這些從Git倉庫的壓縮資料庫提取出來的檔案,放在磁碟上供你使用或修改。
  • 暫存區域 Staging Area :是一個檔案儲存了下次將提交的檔案列表,是待提交檔案的暫存區域。一般在Git倉庫的目錄中,有時也被稱為索引。
  • Git倉庫:用來儲存專案的元資料和物件資料庫的地方。是Git中最重要的部分,從其他計算機克隆倉庫時拷貝的就是這裡的資料

基本的Git工作流程

  • 在工作目錄中修改檔案
  • 暫存檔案,將檔案的快照儲存在暫存區域
  • 提交更新,找到暫存區域的位置,將快照永久性儲存到Git倉庫目錄
    • 提交狀態:如果Git目錄中儲存著特定版本的檔案,就屬於已提交狀態。
    • 暫存狀態:如果做了修改並且已經放入暫存區域,就屬於暫存狀態。
    • 已修改狀態:如果自上次取出後,做了修改但是還沒有存在暫存區域,就是已修改狀態。

基本的Git操作流程

基礎設定

  • 首先最基礎的是需要配置使用者資訊

    $ git config --global user.name "lanya"
    $ git config --global user.email [email protected]
    

    關於 config 的種類

    Config file location
    # global 表示配置全域性資訊,配置之後無論你在該系統上做任何事情,Git都會使用這些資訊。
        --global              use global config file
        --system              use system config file
        --local               use repository config file
        -f, --file <file>     use given config file
        --blob <blob-id>      read config from given blob object
    
  • 接著需要檢查你的配置資訊,使用 $ git config --list 指令檢查全部配置資訊,結果如下:

    core.excludesfile=~/.gitignore
    core.legacyheaders=false
    core.quotepath=false
    mergetool.keepbackup=true
    push.default=simple
    color.ui=auto
    color.interactive=auto
    repack.usedeltabaseoffset=true
    alias.s=status
    alias.a=!git add . && git status
    alias.au=!git add -u . && git status
    alias.aa=!git add . && git add -u . && git status
    alias.c=commit
    alias.cm=commit -m
    alias.ca=commit --amend
    alias.ac=!git add . && git commit
    alias.acm=!git add . && git commit -m
    alias.l=log --graph --all --pretty=format:'%C(yellow)%h%C(cyan)%d%Creset %s %C(white)- %an, %ar%Creset'
    alias.ll=log --stat --abbrev-commit
    alias.lg=log --color --graph --pretty=format:'%C(bold white)%h%Creset -%C(bold green)%d%Creset %s %C(bold green)(%cr)%Creset %C(bold blue)<%an>%Creset' --abbrev-commit --date=relative
    alias.llg=log --color --graph --pretty=format:'%C(bold white)%H %d%Creset%n%s%n%+b%C(bold blue)%an <%ae>%Creset %C(bold green)%cr (%ci)' --abbrev-commit
    alias.d=diff
    alias.master=checkout master
    alias.spull=svn rebase
    alias.spush=svn dcommit
    alias.alias=!git config --list | grep 'alias\.' | sed 's/alias\.\([^=]*\)=\(.*\)/\1\   => \2/' | sort
    include.path=~/.gitcinclude
    include.path=.githubconfig
    include.path=.gitcredential
    diff.exif.textconv=exif
    credential.helper=osxkeychain
    core.excludesfile=/Users/shenglanya/.gitignore_global
    difftool.sourcetree.cmd=opendiff "$LOCAL" "$REMOTE"
    difftool.sourcetree.path=
    mergetool.sourcetree.cmd=/Applications/Sourcetree.app/Contents/Resources/opendiff-w.sh "$LOCAL" "$REMOTE" -ancestor "$BASE" -merge "$MERGED"
    mergetool.sourcetree.trustexitcode=true
    user.name=shenglanya
    [email protected]
    commit.template=/Users/shenglanya/.stCommitMsg
    core.repositoryformatversion=0
    core.filemode=true
    core.bare=false
    core.logallrefupdates=true
    core.ignorecase=true
    core.precomposeunicode=true
    remote.origin.url=https://git.ms.netease.com/netease-precious-metals-client/ios-client.git
    remote.origin.fetch=+refs/heads/*:refs/remotes/origin/*
    branch.essential.remote=origin
    branch.essential.merge=refs/heads/essential
    branch.r_4.4.remote=origin
    branch.r_4.4.merge=refs/heads/r_4.4
    
  • 使用 $ git config <key> 來檢查某一項配置資訊

    $ git config user.name
    shenglanya
    

查閱幫助手冊方法

  • 以下方法均可找到 Git 命令手冊

    $ git help <verb>
    $ git <verb> --help
    $ man git-<verb>
    

獲取Git倉庫

方法一:在現有目錄中初始化倉庫(建立一個新的自己的倉庫)

  • git init 該命令將建立一個名為 .git 的子目錄,這個子目錄含有你在初始化的Git倉庫中所有的必須檔案,這些檔案是Git倉庫的骨幹。但是,在這個時候,我們僅僅是做了一個初始化的操作,你的專案裡的檔案還沒有被跟蹤。

  • 如果你是在一個已經存在檔案的資料夾(而不是空資料夾)中初始化 Git 倉庫來進行版本控制的話,你應該開始跟蹤這些檔案並提交。 你可通過 git add 命令來實現對指定檔案的跟蹤,然後執行 git commit提交:

    $ git add *.c
    $ git add LICENSE
    $ git commit -m 'initial project version'
    
  • 具體操作流程

    # 首先
    $ git init
    Initialized empty Git repository in /Users/shenglanya/Desktop/.git/
    
    #然後使用 ls -a 可檢視隱藏檔案,發現存在名為 .git 的子目錄
    $ ls -a
    .     .DS_Store   .localized
    ..        .git        pic
    
    # 接著進入子目錄,發現此目錄中包含你初始化倉庫中所有的必須檔案,這些檔案是 Git 倉庫的骨幹
    $ cd .git
    $ ls
    HEAD      config      hooks       objects
    branches  description info        refs
    
    # 接著需要跟蹤專案裡的檔案,需要注意的是,當建立一個新的專案裡的檔案時,它預設是未被跟蹤的,所以此時我們需要手動的將它新增到版本控制中,也就是被跟蹤
    

方法二:克隆現有倉庫(clone別人的)

  • 如果你想獲得一份已經存在了的 Git 倉庫的拷貝,比如說,你想為某個開源專案貢獻自己的一份力,這時就要用到 git clone 命令。Git 克隆的是該 Git 倉庫伺服器上的幾乎所有資料,而不是僅僅複製完成你的工作所需要檔案。 當你執行 git clone 命令的時候,預設配置下遠端 Git 倉庫中的每一個檔案的每一個版本都將被拉取下來。

    $ git clone https://github.com/libgit2/libgit2
    

    Git 支援多種資料傳輸協議。 上面的例子使用的是 https:// 協議,不過你也可以使用 git:// 協議或者使用 SSH 傳輸協議,比如 [email protected]:path/to/repo.git

記錄每次更新到倉庫

  • 你工作目錄下的每一個檔案都不外乎這兩種狀態:已跟蹤或未跟蹤。 已跟蹤的檔案是指那些被納入了版本控制的檔案,在上一次快照中有它們的記錄,在工作一段時間後,它們的狀態可能處於未修改,已修改或已放入暫存區。 工作目錄中除已跟蹤檔案以外的所有其它檔案都屬於未跟蹤檔案,它們既不存在於上次快照的記錄中,也沒有放入暫存區。 初次克隆某個倉庫的時候,工作目錄中的所有檔案都屬於已跟蹤檔案,並處於未修改狀態。

檢查當前檔案狀態

  • 要檢視哪些檔案處於什麼狀態,可以用 git status 命令。 如果在克隆倉庫後立即使用此命令,會看到類似這樣的輸出:

    $ git status
    On branch master
    nothing to commit, working directory clean
    

    這說明你現在的工作目錄相當乾淨。表示所有已跟蹤檔案在上次提交後都未被更改過。 此外,上面的資訊還表明,當前目錄下沒有出現任何處於未跟蹤狀態的新檔案,否則 Git 會在這裡列出來。 最後,該命令還顯示了當前所在分支,並告訴你這個分支同遠端伺服器上對應的分支沒有偏離。 現在,分支名是 “master”,這是預設的分支名。

  • 如果你在當前已經有倉庫管理的專案中添加了一個檔案,名字叫做 README 。然後使用 git status 命令,你會發現會出現:

    $ echo 'My Project' > README
    $ git status
    On branch master
    Untracked files:
      (use "git add <file>..." to include in what will be committed)
    
        README
    
    nothing added to commit but untracked files present (use "git add" to track)
    

    表示 README 還未被跟蹤,表示 Git 之前的提交中沒有這些檔案。Git也不會自動跟蹤它,這使得你不必擔心將生成的二進位制檔案或者其他不想被包含的檔案包含進來。若你想跟蹤它,則需要明明白白的告訴它你想跟蹤這個檔案,使用 git add 指令。

跟蹤新檔案

  • 使用 git add 可以跟蹤新檔案。所以可以使用 git add README , 然後再執行 git status 會看到

    $ git status
    On branch master
    
    No commits yet
    
    Changes to be committed:
      (use "git rm --cached <file>..." to unstage)
    
      new file:   pic/git儲存專案雖時間改變的快照.png
      new file:   pic/lifecycle.png
      new file:   pic/工作目錄,暫存區域及Git倉庫.png
    
    Untracked files:
      (use "git add <file>..." to include in what will be committed)
    
      pic/實習學習筆記.md
    
    # 使用 git add 後
    $ git add pic/實習學習筆記.md
    $ git status
    On branch master
    
    No commits yet
    
    Changes to be committed:
      (use "git rm --cached <file>..." to unstage)
    
      new file:   pic/git儲存專案雖時間改變的快照.png
      new file:   pic/lifecycle.png
      new file:   pic/實習學習筆記.md
      new file:   pic/工作目錄,暫存區域及Git倉庫.png
    

    只要在 Changes to be committed 這行下面的,就說明是已暫存狀態。 如果此時提交,那麼該檔案此時此刻的版本將被留存在歷史記錄中。 你可能會想起之前我們使用 git init 後就運行了 git add (files) 命令,開始跟蹤當前目錄下的檔案。 git add 命令使用檔案或目錄的路徑作為引數;如果引數是目錄的路徑,該命令將遞迴地跟蹤該目錄下的所有檔案。

  • 關於 git add 指令還有別的作用:

    • 用於追蹤新檔案
    • 用於將已跟蹤的檔案放入暫存區
    • 用於合併時把有衝突的檔案標記為已解決

暫存已修改檔案

  • 修改已被跟蹤的檔案。比如說修改了一個名為 實習學習筆記.md 的檔案,然後執行 git status

    $ git status
    On branch master
    
    No commits yet
    
    Changes to be committed:
      (use "git rm --cached <file>..." to unstage)
    
      new file:   pic/git儲存專案雖時間改變的快照.png
      new file:   pic/lifecycle.png
      new file:   pic/實習學習筆記.md
      new file:   pic/工作目錄,暫存區域及Git倉庫.png
    
    # 說明已跟蹤檔案內容發生了變化,但是還未放入暫存區。如果想暫存這次更新,需要使用 git add 指令。 git add 指令是一個多功能命令:可以用它來跟蹤新檔案,或者把已經跟蹤的檔案放到暫存區中,還能用於合併時把有衝突的檔案標記為已解決狀態等。
    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:   pic/實習學習筆記.md
      
      
    # 使用 git add 指令將其新增到暫存區
    $ git add pic/實習學習筆記.md
    $ git status
    On branch master
    
    No commits yet
    
    Changes to be committed:
      (use "git rm --cached <file>..." to unstage)
    
      new file:   pic/git儲存專案雖時間改變的快照.png
      new file:   pic/lifecycle.png
      new file:   pic/實習學習筆記.md
      new file:   pic/工作目錄,暫存區域及Git倉庫.png
    
  • 需要注意的是,當已經使用了 git add 指令暫存的版本又經過修改之後,需在再重新使用 git add 指令將最新的修改放入暫存區,否則此時暫存區裡只有上一次修改的內容。

提交檔案到倉庫

  • 使用 git commit 指令可以使得暫存在暫存區的檔案被提交到倉庫中去。

    $ git commit
    [master (root-commit) 2713657] 第一次的修改提交
     4 files changed, 22 insertions(+)
     create mode 100644 pic/git儲存專案雖時間改變的快照.png
     create mode 100644 pic/lifecycle.png
     create mode 100644 pic/實習學習筆記.md
     create mode 100644 pic/工作目錄,暫存區域及Git倉庫.png
    

基本的 Git 操作指令

git status 命令概述

  • 使用 git status 時,實際上可以使用更為方便的指令來達到更為緊湊的格式輸出。比如使用 git status -s

    $ git status -s
    
    #  M 靠右的 M 表示修改過的檔案並且還未被放入暫存區
     M README
     
    # MM 靠左的 M 表示該檔案被修改後放入了暫存區,靠右的表示修改過的檔案並且還未被放入暫存區,所以 Rakefile 檔案被修改過後放入了暫存區,但是之後又進行了修改,還未將最後一次修改放入暫存區
    MM Rakefile
    
    # A 表示新新增到暫存區的檔案
    A  lib/git.rb
    
    # M 靠左的 M 表示該檔案被修改後放入了暫存區
    M  lib/simplegit.rb
    
    # ?? 表示還未被跟蹤
    ?? LICENSE.txt  
    
    # 所以此時暫存區中的檔案有 Rakefile, lib/git.rb, lib/simplegit.rb
    

git diff 命令概述

  • git diff 可以說是 git status 的具體版本,git status 只能檢視修改了哪些檔案,而 git diff 能夠具體到該檔案的某一部分。通常有以下兩個用法

    • 當前做的更新哪些還沒有暫存?

      首先修改 pic/實習學習筆記.md 檔案,然後使用 git status 指令

      $ git status
      On branch 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:   pic/實習學習筆記.md
          
      # 表示該檔案修改後還沒有暫存
      

      此時使用 git diff 可以檢視當前未暫存檔案更新了哪些部分

      $ git diff
      diff --git a/pic/實習學習筆記.md b/pic/實習學習筆記.md
      index 2b4e07b..a50f1a2 100644
      --- a/pic/實習學習筆記.md
      +++ b/pic/實習學習筆記.md
      @@ -14,7 +14,7 @@
      -* 有額外時間的話,需要將之前沒讀完的書繼續讀下去。
      +* 有額外時間的話,需要將之前沒讀完的書繼續讀下去。呵呵呵
      

      此時就可以檢視未暫存檔案修改的部分了。

      • 有哪些更新已經暫存起來了準備好了下次提交?

        可以使用 git diff --staged 指令檢視,首先需要使用 git add 指令將剛剛修改的檔案加入暫存區

        $ git add pic/實習學習筆記.md
        shenglanyadeMacBook-Pro:desktop shenglanya$ git diff --staged
        diff --git a/pic/實習學習筆記.md b/pic/實習學習筆記.md
        index 2b4e07b..a50f1a2 100644
        --- a/pic/實習學習筆記.md
        +++ b/pic/實習學習筆記.md
        @@ -14,7 +14,7 @@
        -* 有額外時間的話,需要將之前沒讀完的書繼續讀下去。
        +* 有額外時間的話,需要將之前沒讀完的書繼續讀下去。呵呵呵
        
  • 當我們將檔案暫存後繼續編輯時,使用 git status 指令檢視如下:

    $ git status
    On branch master
    Changes to be committed:
      (use "git reset HEAD <file>..." to unstage)
    
      modified:   pic/實習學習筆記.md
    
    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:   pic/實習學習筆記.md
    
    # 該檔案同時出現在了暫存區和修改部分。
    
  • 現在執行 git diff 檢視暫存前後的變化

    git diff
    diff --git a/pic/實習學習筆記.md b/pic/實習學習筆記.md
    index a50f1a2..2b4e07b 100644
    --- a/pic/實習學習筆記.md
    +++ b/pic/實習學習筆記.md
    @@ -14,7 +14,7 @@
    -* 有額外時間的話,需要將之前沒讀完的書繼續讀下去。呵呵呵
    +* 有額外時間的話,需要將之前沒讀完的書繼續讀下去。
    
  • 再使用 git diff --staged 檢視變化

    $ git diff --staged
    diff --git a/pic/實習學習筆記.md b/pic/實習學習筆記.md
    index 2b4e07b..a50f1a2 100644
    --- a/pic/實習學習筆記.md
    +++ b/pic/實習學習筆記.md
    @@ -14,7 +14,7 @@
    -* 有額外時間的話,需要將之前沒讀完的書繼續讀下去。
    +* 有額外時間的話,需要將之前沒讀完的書繼續讀下去。呵呵呵
    

    表示這個指令檢視的是暫存區中檔案的修改。

git commit 命令概述

  • 當使用 git commit 命令提交暫存區域的檔案時,一定要確認是否還有什麼修改過或新建的檔案還未放入暫存區,否則一旦提交,這些檔案或修改都會只留在本地磁碟,不會加入版本控制中。所以每次提交前都需要執行 git status 命令來檢視是否都暫存起來了

  • 可以在 commit 命令後新增 -m 選項,將提交資訊與命令放在同一行

    $ git commit -m "Story 182: Fix benchmarks for speed"
    
    # 表示當前在 master 分支上提交的,本次提交的完整 SHA-1 校驗和是 463dc4f
    [master 463dc4f] Story 182: Fix benchmarks for speed
    
     2 files changed, 2 insertions(+)
     create mode 100644 README
    
  • 注意:提交的是放在暫存區的快照,任何還未暫存的仍然保持已修改狀態,可以在下次提交時再納入版本管理。每一次提交都是對專案的一次快照,以後可以回到這個狀態或進行比較。

  • 使用 git commit -a 可以跳過暫存這一步驟,git 會自動把所有已經跟蹤過的檔案暫存起來並且提交,即跳過 git add 步驟。

git rm 命令概述

  • 要從 Git 中移除某個檔案,就必須從已經跟蹤的檔案清單中刪除,然後提交。

  • 刪除有兩種方式

    • 第一種是簡單的從暫存區中刪除。但是檔案還在被跟蹤著。
    • 第二種是直接在未暫存區域中移除檔案,表示直接將檔案移除版本控制中。不再跟蹤。
  • 下面來演示一下,首先對工作區域中的檔案刪除,使用 rm pic/實習學習筆記.md

    $ rm pic/實習學習筆記.md
    $ git status
    On branch master
    Changes not staged for commit:
      (use "git add/rm <file>..." to update what will be committed)
      (use "git checkout -- <file>..." to discard changes in working directory)
    
      deleted:    pic/實習學習筆記.md
    
    no changes added to commit (use "git add" and/or "git commit -a")
    
    # 此時將檔案從暫存區域中刪除,但是檔案還在被追蹤
    
  • 然後再將檔案從跟蹤中刪除,這裡兩種指令 $ git rm pic/實習學習筆記.md$ git add pic/實習學習筆記.md 都能達到同樣效果。

    $ git add pic/實習學習筆記.md
    $ git status
    On branch master
    Changes to be committed:
      (use "git reset HEAD <file>..." to unstage)
    
      deleted:    pic/實習學習筆記.md
    
    
  • 需要注意的是,如果刪除檔案之前檔案修改過並且已經放入了暫存區域,則必須使用強制刪除選項-f 才能將其刪除。主要是為了防止誤刪。

  • 當我們想要將檔案從 Git 倉庫中刪除但是卻想讓他仍在我們的工作區域中時,(即儲存在本地磁碟並且不被 Git 跟蹤),為了達到這一目的,使用 --cached 選項。

    $ git rm --cached pic/git儲存專案雖時間改變的快照.png
    rm 'pic/git儲存專案雖時間改變的快照.png'
    
    # 執行完此命令後,pic/git儲存專案雖時間改變的快照.png 檔案還在本地磁碟上,並沒有被刪除。
    

git mv 命令概述

  • Git 並不顯式的跟蹤檔案移動操作。所以如果 Git 重新命名某個檔案,倉庫中儲存的元資料並不會體現出這是一次改名操作。

  • 當我們想在 Git 中對檔案進行改名可以使用 git mv a b 方式來操作

    $ git mv pic/實習學習筆記.md pic/note.md
    $ git diff --staged
    diff --git a/pic/實習學習筆記.md b/pic/note.md
    similarity index 100%
    rename from pic/實習學習筆記.md
    rename to pic/note.md
    
  • git mv 等價於

    $ mv pic/實習學習筆記.md pic/note.md
    $ git rm pic/實習學習筆記.md
    $ git add pic/note.md
    

忽略檔案

  • 我們有時會有些檔案不需要 Git 來進行管理,也不希望他們總是出現在未跟蹤列表中,所以此時,我們可以建立一個名為 .gitignore 的檔案,並在其中列出要忽略掉檔案模式。

    # 先建立此忽略檔案並向其中新增需要忽略的檔案
    $ vi .gitignore
    
    # 檢視此檔案
    $ cat .gitignore
    .localized
    
    # 表示忽略所有以 .o 或 .a 結尾的檔案
    *.[oa]
    
    # 表示忽略所有以波浪符(~)結尾的檔案
    *~
    
  • 一些規範如下

    • 所有空行或者以 開頭的行都會被 Git 忽略。
    • 可以使用標準的 glob 模式匹配。glob 即是指 shell 簡化了的正則表示式。
      • 其中 * 可以匹配 0 ~ n 個字元
      • ? 只能匹配一個字元
      • [0-9]表示匹配所有 0 到 9 的數字
      • ** 表示匹配任意中間目錄 比如 a/**/z 可以匹配 a/z, a/b/z, a/b/c/z 等
    • 匹配模式可以以(/)開頭防止遞迴。
    • 匹配模式可以以(/)結尾指定目錄。
    • 要忽略指定模式以外的檔案或目錄,可以在模式前加上驚歎號(!)取反。

git stash 命令概述

  • 當我們已經在一個分支上修改檔案後,如果必須要切換到其他分支展開其他的工作,而當前分支的工作還沒有完成,此時我們需要使用 $ git stash$ git stash save 命令將當前分支上的工作暫存到棧上,這時你的工作目錄就乾淨了,就可以切換到其他分支工作,等工作完成後,再切換回原來的分支,可以使用 $ git stash apply 將你剛剛的儲藏重新應用。如果想檢視你當前一共有多少個儲藏,可以使用 $ git stash list 來檢視。如果你並不想應用最新的分支,而是想應用某一個早些時間的分支,你可以使用 $ git stash apply [email protected]{1} ,其中最後一個括號內的數字為你某一次提交到工作棧上的暫存記錄。如果你不指定 apply 的引數,git 將認為你想要應用最近一次的儲藏。

  • 當我們返回原本的分支後,使用 $ git stash apply 指令恢復了工作棧中暫存的資料,但是如果當你提交這個分支之前,已經在暫存區快取了一部分工作內容,並且使用 stash 儲存了工作狀態,此時當你恢復工作棧中的資料後,實際上暫存區中的內容將會被移出暫存區,而被放在了工作目錄中修改的部分,你需要手動將它再放回暫存區,否則可以使用 $ git stash apply --index 來嘗試重新將暫存區的檔案恢復到暫存區中。當你把這個修改放入暫存區後,實際上堆疊上還有這個修改的記錄,此時你可以使用 $ git stash drop [email protected]{1} 來從棧中移除它,或者直接使用 $ git stash pop 來應用儲藏棧這樣它就會自動從儲藏棧上消失了。

  • $ git stash --keep-index 指令的作用在於告訴 Git 不要儲藏任何你通過 git add 命令已經暫存的東西,也就是說比如你現在已經修改了一部分工作目錄中的內容,並且還有一部分已經被你暫存了下來。此時你暫時不想繼續改工作目錄中的內容了,可是你也不想將它暫存到暫存區,此時可以使用這個指令將它暫存到工作棧上。

    $ git status -s
    M  index.html
     M lib/simplegit.rb
    
    $ git stash --keep-index
    Saved working directory and index state WIP on master: 1b65b17 added the index file
    HEAD is now at 1b65b17 added the index file
    
    $ git status -s
    M  index.html
    
  • $ git stash -u 可以儲藏還未跟蹤的檔案到工作棧

  • $ git stash branch 如果使用 stash 儲藏了一些工作,然後繼續在儲藏的分支上工作,在重新應用 stash 儲藏的檔案工作時可能會有問題。 如果應用嘗試修改剛剛儲藏的修改的檔案,也就是兩次同時修改了一個檔案,你會得到一個合併衝突並不得不解決它。 如果想要一個輕鬆的方式來再次測試儲藏的改動,可以執行 git stash branch 建立一個新分支,檢出儲藏工作時所在的提交,重新在那應用工作,然後在應用成功後扔掉儲藏

    $ git stash branch testchanges
    Switched to a new branch "testchanges"
    # On branch testchanges
    # Changes to be committed:
    #   (use "git reset HEAD <file>..." to unstage)
    #
    #      modified:   index.html
    #
    # Changed but not updated:
    #   (use "git add <file>..." to update what will be committed)
    #
    #      modified:   lib/simplegit.rb
    #
    Dropped refs/[email protected]{0} (f0dfc4d5dc332d1cee34a634182e168c4efc3359)
    
  • $ git stash -all 可以移除工作目錄中所有未跟蹤的檔案並且儲存在工作棧上,相應的一個不怎麼安全的方法是 $ git clean 直接清除了內容,無法追溯回。不過可以使用 git clean 命令去除冗餘檔案或者清理工作目錄。 使用git clean -f -d命令來移除工作目錄中所有未追蹤的檔案以及空的子目錄。 -f 意味著 強制 或 “確定移除”。在使用 $ git clean 之前,我們可以先使用 $ git clean -d -n 來看一下這樣做的後果是什麼,也就是有什麼檔案會被移除。

git log 命令概述

  • 在提交了若干更新,又或者克隆了某個專案之後,你也許想回顧下提交歷史。 此時便需要 git log 命令。預設不加其他引數時, git log 惠安提交時間列出所有更新。

    $ git log
    commit fb40f7a259de8ec2f2edbada6f85aa855f4a6585 (HEAD -> master)
    Author: shenglanya <[email protected]>
    Date:   Wed Mar 7 11:34:54 2018 +0800
    
        add pic
    
    commit ec50914561593b769a98ff468de6697a6d964cbd
    Author: shenglanya <[email protected]>
    Date:   Wed Mar 7 11:33:36 2018 +0800
    
        xiugai
    
    commit a7372097ab8f063e17beca6fa8f82a15bb11c5e3
    Author: shenglanya <[email protected]>
    Date:   Wed Mar 7 11:20:05 2018 +0800
    
        提交
    
  • 常用選項 -p ,用來顯示每次提交的內容差異,可以加上 -2 來僅僅顯示最近兩次提交

    $ git log -p
    commit fb40f7a259de8ec2f2edbada6f85aa855f4a6585 (HEAD -> master)
    Author: shenglanya <[email protected]>
    Date:   Wed Mar 7 11:34:54 2018 +0800
    
        add pic
    
    diff --git a/pic/git儲存專案雖時間改變的快照.png b/pic/git儲存專案雖時間改變的快照.png
    new file mode 100644
    index 0000000..1036a42
    Binary files /dev/null and b/pic/git儲存專案雖時間改變的快照.png differ
    
    commit ec50914561593b769a98ff468de6697a6d964cbd
    Author: shenglanya <[email protected]>
    Date:   Wed Mar 7 11:33:36 2018 +0800
    
        xiugai
    
    diff --git a/pic/git儲存專案雖時間改變的快照.png b/pic/git儲存專案雖時間改變的快照.png
    deleted file mode 100644
    index 1036a42..0000000
    Binary files a/pic/git儲存專案雖時間改變的快照.png and /dev/null differ
    
  • --stat 選項可以看到每次提交的簡略統計資訊

    $ git log --stat
    commit fb40f7a259de8ec2f2edbada6f85aa855f4a6585 (HEAD -> master)
    Author: shenglanya <[email protected]>
    Date:   Wed Mar 7 11:34:54 2018 +0800
    
        add pic
    
     pic/git儲存專案雖時間改變的快照.png | Bin 0 -> 20722 bytes
     1 file changed, 0 insertions(+), 0 deletions(-)
    
    commit ec50914561593b769a98ff468de6697a6d964cbd
    Author: shenglanya <[email protected]>
    Date:   Wed Mar 7 11:33:36 2018 +0800
    
        xiugai
    
     pic/git儲存專案雖時間改變的快照.png | Bin 20722 -> 0 bytes
     pic/實習學習筆記.md                       |  22 ++++++++++++++++++++++
     2 files changed, 22 insertions(+)
    
    commit a7372097ab8f063e17beca6fa8f82a15bb11c5e3
    Author: shenglanya <[email protected]>
    Date:   Wed Mar 7 11:20:05 2018 +0800
    
    
  • 常用選項 --pretty 可以指定使用不同於預設格式的方式展示提交資訊。比如 oneline 將每個提交放在一行顯示,檢視到提交數很大時非常有用。另外還有 short full 等。

    $ git log --pretty=oneline
    fb40f7a259de8ec2f2edbada6f85aa855f4a6585 (HEAD -> master) add pic
    ec50914561593b769a98ff468de6697a6d964cbd xiugai
    a7372097ab8f063e17beca6fa8f82a15bb11c5e3 提交
    2713657f264a3a019580dc3a489d303fade5dc5c 第一次的修改提交
    
  • format 選項可以定製要顯示的記錄格式。這樣的輸出對後期提取分析格外有用。

    $git log --pretty=format:"%h - %an, %ar : s"
    fb40f7a - shenglanya, 60 minutes ago : add pic
    ec50914 - shenglanya, 61 minutes ago : xiugai
    a737209 - shenglanya, 74 minutes ago : 提交
    2713657 - shenglanya, 3 hours ago : 第一次的修改提交
    

    常用選項以及其代表意義

    選項        說明
    %H    提交物件(commit)的完整雜湊字串
    %h        提交物件的簡短雜湊字串
    %T        樹物件(tree)的完整雜湊字串
    %t        樹物件的簡短雜湊字串
    %P        父物件(parent)的完整雜湊字串
    %p        父物件的簡短雜湊字串
    %an       作者(author)的名字
    %ae       作者的電子郵件地址
    %ad       作者修訂日期(可以用 --date= 選項定製格式)
    %ar       作者修訂日期,按多久以前的方式顯示
    %cn       提交者(committer)的名字
    %ce       提交者的電子郵件地址
    %cd       提交日期
    %cr       提交日期,按多久以前的方式顯示
    %s        提交說明
    
  • 選項 --graph 可以形象的展示分支,合併歷史

    $ git log --pretty --graph
    * commit fb40f7a259de8ec2f2edbada6f85aa855f4a6585 (HEAD -> master)
    | Author: shenglanya <[email protected]>
    | Date:   Wed Mar 7 11:34:54 2018 +0800
    | 
    |     add pic
    | 
    * commit ec50914561593b769a98ff468de6697a6d964cbd
    | Author: shenglanya <[email protected]>
    | Date:   Wed Mar 7 11:33:36 2018 +0800
    | 
    |     xiugai
    | 
    * commit a7372097ab8f063e17beca6fa8f82a15bb11c5e3
    | Author: shenglanya <[email protected]>
    | Date:   Wed Mar 7 11:20:05 2018 +0800
    | 
    |     提交
    
  • git log 的常用選項

    選項                說明
    -p                按補丁格式顯示每個更新之間的差異。
    --stat            顯示每次更新的檔案修改統計資訊。
    --shortstat       只顯示 --stat 中最後的行數修改新增移除統計。
    --name-only       僅在提交資訊後顯示已修改的檔案清單。
    --name-status 顯示新增、修改、刪除的檔案清單。
    --abbrev-commit   僅顯示 SHA-1 的前幾個字元,而非所有的 40 個字元。
    --relative-date   使用較短的相對時間顯示(比如,“2 weeks ago”)。
    --graph           顯示 ASCII 圖形表示的分支合併歷史。
    --pretty      使用其他格式顯示歷史提交資訊。可用的選項包括 oneline,short,full,fuller 和 format(後跟指定格式)。
    
    
  • 限制 git log 輸出的選項

    選項                說明
    -(n)          僅顯示最近的 n 條提交
    --since, --after僅顯示指定時間之後的提交。
    --until, --before僅顯示指定時間之前的提交。
    --author      僅顯示指定作者相關的提交。
    --committer       僅顯示指定提交者相關的提交。
    --grep            僅顯示含指定關鍵字的提交
    -S                僅顯示新增或移除了某個關鍵字的提交
    

撤銷操作指令

  • 重新提交:有時候我們提交完了才發現漏掉了幾個檔案沒有新增,或者提交資訊寫錯了。 此時,可以執行帶有 --amend 選項的提交命令嘗試重新提交:$ git commit --amend 這個命令將暫存區中的檔案提交,如果自從上次提交以來還未做任何修改,則快照保持不變,你修改的只有提交資訊。例如你提交後發現忘記了暫存某些需要的修改,可以像下面這樣操作:

    $ git commit -m 'initial commit'
    $ git add forgotten_file
    $ git commit --amend
    
    # 最終只會有一個提交,第二次提交將代替第一次提交的結果
    
  • 取消暫存的檔案:可以使用 git reset HEAD yourfile 來進行取消暫存區域內檔案的暫存操作。

  • 撤銷對檔案的修改:如果你不想儲存對檔案的修改,如何方便的將其還原成上次提交的樣子?使用 $ gitcheckout -- pic/實習學習筆記.md 撤銷之前所做的修改。

Git 遠端倉庫的使用

  • 檢視遠端倉庫 : 使用 git remote 命令可以列出你指定的每個遠端伺服器的簡寫。如果已經克隆了自己的倉庫,那麼至少能看到 origin

    $ cd ios-client
    $ git remote
    origin
    

    可以指定引數 -v 可以檢視你的讀寫許可權

    $ git remote -v
    origin    https://git.ms.netease.com/netease-precious-metals-client/ios-client.git (fetch)
    origin    https://git.ms.netease.com/netease-precious-metals-client/ios-client.git (push)
    
  • 新增遠端倉庫: 執行 git remote add <shortname> <url> 新增一個新的遠端 Git 倉庫

    $ git remote
    origin
    $ git remote add test https://github.com/lanyasheng/NTAlgorithm.git
    $ git remote -v
    origin    https://git.ms.netease.com/netease-precious-metals-client/ios-client.git (fetch)
    origin    https://git.ms.netease.com/netease-precious-metals-client/ios-client.git (push)
    test  https://github.com/lanyasheng/NTAlgorithm.git (fetch)
    test  https://github.com/lanyasheng/NTAlgorithm.git (push)
    

    現在就可以使用 test 來代替整個 URL ,例如使用 git fetch test 來拉取遠端 Git 倉庫中有但你沒有的資訊。

    $ git fetch test
    warning: no common commits
    remote: Counting objects: 84, done.
    remote: Total 84 (delta 0), reused 0 (delta 0), pack-reused 83
    Unpacking objects: 100% (84/84), done.
    From https://github.com/lanyasheng/NTAlgorithm
     * [new branch]          develop    -> test/develop
     * [new branch]          master     -> test/master
    

    現在可以在本地訪問 test/master 分支了,實際上對應遠端的 master 分支。

  • 從倉庫中抓取: git fetch 會訪問遠端倉庫,從中拉取所有你沒有的資訊。執行完後,你會擁有該倉庫的所有分支引用可以用來隨時合併和檢視。當使用了 git clone 命令克隆一個遠端倉庫時,命令會自動將其新增為遠端倉庫並預設以 “origin” 為簡寫。git fetch origin 會抓取克隆(或上一次抓取)後新推送的所有工作。 必須注意 git fetch 命令會將資料拉取到你的本地倉庫 - 它並不會自動合併或修改你當前的工作。 當準備好時你必須手動將其合併入你的工作。

  • 從倉庫上拉取: git pull 可以用來自動的抓取然後合併遠端分支到當前分支,前提是你有一個分支設定為跟蹤一個遠端的分支。所以 git pull == git fetch + git merge。預設情況下, git clone 會自動設定本地的 master 分支跟蹤遠端倉庫的 master 分支,執行 git pull 通常會從最初克隆的伺服器上抓取資料並自動嘗試合併到當前所在的分支。

  • 推送到遠端分支git push [remote-name][branch-name] 指令可以將你的專案推送到伺服器。例如當你想將 master 推到 origin 時,可以使用 $ git push origin master 只有當你有所克隆伺服器的寫入許可權,並且之前沒有人推送過時,這條命令才能生效。 當你和其他人在同一時間克隆,他們先推送到上游然後你再推送到上游,你的推送就會毫無疑問地被拒絕。 你必須先將他們的工作拉取下來並將其合併進你的工作後才能推送

  • 檢視遠端倉庫: 如果想檢視一個遠端倉庫的更多資訊,可以使用 $ git remote show test

    $ git remote show test
    * remote test
      Fetch URL: https://github.com/lanyasheng/NTAlgorithm.git
      Push  URL: https://github.com/lanyasheng/NTAlgorithm.git
      HEAD branch: master
      Remote branches:
        develop tracked
        master  tracked
        
      Local branches configured for 'git pull':
        develop merges with remote develop
        master  merges with remote master
      Local refs configured for 'git push':
        develop pushes to develop (local out of date)
        master  pushes to master  (local out of date)
    

    這個命令列出了當你在特定的分支上執行 git push 會自動地推送到哪一個遠端分支。 它也同樣地列出了哪些遠端分支不在你的本地,哪些遠端分支已經從伺服器上移除了,還有當你執行 git pull 時哪些分支會自動合併

  • 遠端倉庫的移除與命名:執行 git remote rename <shortname> <url> 重新命名遠端倉庫

    $ git remote rename test testNea
    $ git remote
    origin
    testNea
    
  • 移除遠端倉庫:

    $ git remote rm testNea
    $ git remote
    origin
    

Git 標籤

建立標籤

  • 輕量標籤 — 就像一個不會改變的分支,只是一個特定提交的引用,建立輕量標籤只需要提供版本號即可。git tag v1.4-1w

    $ git tag v1.4-1w
    $ git show
    commit fb40f7a259de8ec2f2edbada6f85aa855f4a6585 (HEAD -> master, tag: v1.4-1w, tag: v1.3)
    Author: shenglanya <[email protected]>
    Date:   Wed Mar 7 11:34:54 2018 +0800
    
        add pic
    
    diff --git a/pic/git儲存專案雖時間改變的快照.png b/pic/git儲存專案雖時間改變的快照.png
    new file mode 100644
    index 0000000..1036a42
    Binary files /dev/null and b/pic/git儲存專案雖時間改變的快照.png differ
    
  • 附註標籤 — 一個儲存在 Git 資料庫中的一個完整物件,他們可以被校驗。其中包含打標籤者的名字,電子郵件地址、日期時間,標籤資訊。並且可以使用 GNU Privacy Guard (GPG)簽名與驗證。可以使用$ git tag -a v1.3 這樣就給當前版本打上了 v1.3 標籤。也可以使用 $ git tag -a v1.3 -m 'my version 1.3' 這樣就直接標備註了。 git show 可以檢視標籤資訊與對應的提交資訊

    $ git tag -a v1.3
    $ git show
    commit fb40f7a259de8ec2f2edbada6f85aa855f4a6585 (HEAD -> master, tag: v1.3)
    Author: shenglanya <[email protected]>
    Date:   Wed Mar 7 11:34:54 2018 +0800
    
        add pic
    
    diff --git a/pic/git儲存專案雖時間改變的快照.png b/pic/git儲存專案雖時間改變的快照.png
    new file mode 100644
    index 0000000..1036a42
    Binary files /dev/null and b/pic/git儲存專案雖時間改變的快照.png differ
    

後期打標籤

  • 也可以對過去提交打標籤。例如提交歷史如下

    $ git log --pretty=oneline
    fb40f7a259de8ec2f2edbada6f85aa855f4a6585 (HEAD -> master, tag: v1.4-1w, tag: v1.3) add pic
    ec50914561593b769a98ff468de6697a6d964cbd xiugai
    a7372097ab8f063e17beca6fa8f82a15bb11c5e3 提交
    20c944dba3f056aef30aada88d0a452e8faffcbc hehe
    2713657f264a3a019580dc3a489d303fade5dc5c 第一次的修改提交
    

    可以使用 $ git tag -a v1.2 2713657 表示對該校驗和的版本打上標籤。

    $ git tag
    v1.2
    v1.3
    v1.4-1w
    $ git show v1.2
    tag v1.2
    Tagger: shenglanya <[email protected]>
    Date:   Wed Mar 7 15:00:31 2018 +0800
    
    對之前的打標籤`
    
    commit 2713657f264a3a019580dc3a489d303fade5dc5c (tag: v1.2)
    Author: shenglanya <[email protected]>
    Date:   Wed Mar 7 09:41:21 2018 +0800
    
        第一次的修改提交
    
    diff --git a/pic/git儲存專案雖時間改變的快照.png b/pic/git儲存專案雖時間改變的快照.png
    new file mode 100644
    index 0000000..1036a42
    Binary files /dev/null and b/pic/git儲存專案雖時間改變的快照.png differ
    diff --git a/pic/lifecycle.png b/pic/lifecycle.png
    new file mode 100644
    index 0000000..922b02c
    Binary files /dev/null and b/pic/lifecycle.png differ
    diff --git a/pic/實習學習筆記.md b/pic/實習學習筆記.md
    new file mode 100644
    

Git 分支

分支簡介

簡介

  • Git 儲存到不是檔案的變化或差異,而是一系列不同時刻的檔案快照。當提交時,Git 會儲存一個提交的物件。該提交物件會包含一個指向暫存內容快照的指標,還會包含作者姓名和郵箱,提交時輸入的資訊以及指向他的父物件的指標。首次提交產生的提交物件沒有父物件,普通提交操作產生的提交物件有一個父物件,而由多個分支合併產生的提交物件有多個父物件。

  • 我們假設現在有一個工作目錄,裡面包含了三個將要被暫存和提交的檔案。 暫存操作會為每一個檔案計算校驗和然後會把當前版本的檔案快照儲存到 Git 倉庫中,最終將校驗和加入到暫存區域等待提交:

建立分支

  • Git 建立新分支的本質就是建立一個可以移動的新的指標。比如建立一個 testing 分支。$ git branch testing 這會在當前所提交的物件上建立一個指標,此時如圖:

two-branches.png

  • 如何判斷 Git 當前在哪一個分支?此時就要依靠 HEAD 指標。該指標指向當前所在的本地分支。如圖

    head-to-master.png

此時 HEAD 指標指向 master 指標,也就是實際上 HEAD 指標指向的時當前所在的本地分支。在本例中,我們仍在 master 分支上,因為 git branch 命令僅僅是建立了一個新分支,並沒有切換到它上面。可以使用以下命令來檢視各個分支當前所指的物件

$ git log --oneline --decorate
5a5f9fe (HEAD -> master) rename
fb40f7a (tag: v1.4-1w, tag: v1.3, testing) add pic
ec50914 xiugai
a737209 提交
2713657 (tag: v1.2) 第一次的修改提交

可以看到,當前 HEAD 和 master 分支均指向 5a5f9fe 開頭的物件

分支切換

  • 使用 git checkout 命令可以切換分支

    $ git checkout testing
    Switched to branch 'testing'
    $ git log --oneline --decorate
    fb40f7a (HEAD -> testing, tag: v1.4-1w, tag: v1.3) add pic
    ec50914 xiugai
    a737209 提交
    2713657 (tag: v1.2) 第一次的修改提交
    

    可以看到,此時 HEAD 指標指向了 testing 指標,表示當前的本地分支切換為 testing 分支。然後在 testing 分支上進行一些操作

    $ git commit -a -m 'made a change on tesing'
    [testing 844332b] made a change on tesing
     3 files changed, 1 insertion(+)
     create mode 100644 pic/head-to-master.png
     create mode 100644 pic/test.md
     create mode 100644 pic/two-branches.png
    $ git log --oneline --decorate
    844332b (HEAD -> testing) made a change on tesing
    fb40f7a (tag: v1.4-1w, tag: v1.3) add pic
    ec50914 xiugai
    a737209 提交
    20c944d hehe
    2713657 (tag: v1.2) 第一次的修改提交
    

    此時可以發現 HEAD 指標指向 testing 指標指向了新提交的檔案。[圖片上傳失敗...(image-dde0a4-1520604809580)]

    此時再切換到 master 分支看一下

    $ git checkout master
    Switched to branch 'master'
    $ git log --oneline --decorate
    5a5f9fe (HEAD -> master) rename
    fb40f7a (tag: v1.4-1w, tag: v1.3) add pic
    ec50914 xiugai
    a737209 提交
    2713657 (tag: v1.2) 第一次的修改提交
    

    可以發現此時 master 分支還指向剛剛它指向的位置,也就是[圖片上傳失敗...(image-85e5da-1520604809580)]

  • git checkout master 一共做了兩件事:

    • 使 HEAD 指向 master 分支
    • 將工作目錄恢復成 master 分支所指向的快照內容,也就是忽略 testing 分支所做的修改。
  • 若我們此時再對 master 分支上的檔案上進行修改,就會產生分叉。因為你剛建立了一個新分支,並且切換過去進行了一些工作,然後後切換回了 master 分支進行了一些額外的工作。上述改動針對的是不同分支,你可以在不同分支之間來回切換並在某一時刻將他們合併。

專案分叉歷史

  • 可以使用 git log 命令檢視分叉歷史。執行 git log --oneline --decorate --graph —all,他會輸出你的提交歷史各個分支的指向以及專案的分支分叉情況。

    $ git log --oneline --decorate --graph --all
    * b551643 (HEAD -> master) made a change on master
    * 5a5f9fe rename
    | * 844332b (testing) made a change on tesing
    |/  
    * fb40f7a (tag: v1.4-1w, tag: v1.3) add pic
    * ec50914 xiugai
    * a737209 提交
    * 20c944d hehe
    * 2713657 (tag: v1.2) 第一次的修改提交
    

    由於 Git 的分支實際上只是包含所指物件的校驗和,建立一個新分支僅僅相當於往一個檔案中寫入 41 個位元組。

分支操作

分支的新建與合併

  • 需要注意的地方:
    • 首先當你想直接從當前分支建立並切換到新分支時,可以使用 $ git checkout -b yourname 來進行操作,這個命令等價於 $ git branch yourname + $ git checkout yourname
    • 當你在新分支上工作時,突然需要切換到之前開始分叉的 master 分支並且需要在 master 分支上開一個新的分支進行工作,則首先需要暫存你在 yourname 分支上還未進行暫存的修改,然後將其提交到倉庫。否則可能會跟你即將檢出的分支產生衝突。
    • 當你在 master 分支上開了一個新分支並且已經解決完問題後,可以將 master 和 hotfix 進行合併,使用 $ git checkout master, $ git merge hotfix 進行合併。
      • 快進 (Fast forward):在合併時,如果當前的 master 分支是你要合併分支的直接上游,則 Git 會直接將 master 指標向前推進到 hotfix 上面。然後就可以將 hotfix 進行刪除。 使用 $ git branch -d hotfix
      • 合併提交:而如果 master 不是你要合併分支的直接上游,比如此時 master 分支已經指向了原本 hotfix 指向的位置,則將它與 yourname 分支合併起來會比較麻煩。由於此時 master 分支已經更新了,如果我們需要它新的內容可以將 master 合併到 yourname 上,如果不需要可以直接等 yourname 分支任務完成後,將其合併到 master 上面。如果我們想將 yourname 合併到 master 上,首先會記錄他們兩個指標所指向的最後一個快照,然後記錄他們共同的祖先快照,最後將三方合併的結果做一個新的快照並且自動建立一個新的提交指向它。合併後可以刪除 yourname 分支。
  • 遇到衝突的分之合併:可以直接使用 git status 狀態來檢視具體是哪個檔案產生了衝突,然後直接開啟該檔案刪除亂碼部分和不需要的部分。

分支管理(git branch 命令)

  • $ git branch 命令不僅可以建立或刪除分支,當不加引數時,其作用為可以檢視當前分支

    $ git branch
    * master
      testing
    

    其中 * 表示當前分支

  • $ git branch -v 可以檢視每個分支的最後一次提交

    $ git branch -v
    * master  b551643 made a change on master
      testing 844332b made a change on tesing
    
  • $ git branch --merged 可以檢視哪些分支已經合併到當前分支上,同理 $ git branch --no-merged

    $ git branch --merged
    * master
    $ git branch --no-merged
      testing
    
  • $ git branch -d yourname 可以用來刪除已經合併的分支,如果是未合併的分支則會報錯。

分支開發工作流程

  • 長期分支(最常用)
    • 如只在 master 上保留穩定的程式碼,有可能僅僅是已經發布的程式碼。還有一些其他的分支如 develop 和 next 平行分支用來進行後續開發,一旦在在這些分支上達到了穩定,再將他們合併到 master 分支上。這樣在確保這些已完成的特性分支能夠通過所有的測試,並且不會引入 bug 後再將他們合併到 master 上等待下一次釋出。
  • 特性分支
    • 特性分支被用來實現單一特性或相關工作,一旦工作完成它就會被刪除。這項技術可以使你快速的進行上下文切換。當你做這麼多操作時,這些分支要確保存於本地,而不會與伺服器進行互動。

遠端分支

  • 遠端引用是指對遠端倉庫的引用,包括分支標籤等。他們是你不能移動的本地引用,當你做任何網路通訊操作時,他們會自動移動。遠端跟蹤分支像是你上次連線到遠端倉庫時,那些分支所處狀態的書籤。他們的命名格式為 (remote)/(branch) 。如果你想要看你最後一次與遠端 origin 分支通訊時 master 分支的狀態,則可以檢視 origin / master 分支。你與同事合作解決一個問題並且他們推送了一個 iss53 分支,你可能有自己的本地 iss53 分支;但是在伺服器上的分支會指向 origin/iss53 的提交。
  • 當與遠端倉庫共同工作時,如果你不抓取fetch遠端 orgin/master ,則它將會一直指向在你上次 fetch 的那個檔案。此時即使你本地的 master 已經指向很遠的地方了,遠端的 orgin/master 還依舊指向你上次 fetch 的那個位置。直到你下一次 fetch。

需要注意的問題

  • 當我們使用分支合併時,要確定是誰合併到誰:當我們需要使用其他分支的內容時,可以把其他分支合併到我們的分支上。但是當我們在開發時,有時可能是從 master 或 develop 分支上拉取的工作分支,此時如果 master 或 develop 分支有更新並且我們需要用到,可以將 master 或 develop 分支拉取到我們的分支。否則,則應該等開發完畢後,將我們的分支合併到 master 或 develop 分支上。當開發完畢後,首先需要檢出 master 分支,然後將工作分支合併到 master 上即可。 $ git checkout master $ git merge workBranch 。合併完成後,可以將工作分支刪除。$ git branch -d workBranch,需要注意的是,當我們刪除的分支還包含未提交的內容,分支刪除會失效。強制刪除可以使用 -D

  • 當 merge 出現衝突時,我們可以先 $ git status 來檢視是哪裡出現了問題,然後 cd 進入該檔案,直接將衝突部分刪除即可解決問題。合併完成後再次執行 $ git status 來檢視問題是否解決。若問題解決,即可提交。

  • 當已經使用了 git add 指令暫存的版本又經過修改之後,需在再重新使用 git add 指令將最新的修改放入暫存區,否則此時暫存區裡只有上一次修改的內容

  • $ git commit 指令僅僅是將暫存區內的檔案快照提交到本地倉庫中,想要推送到遠端倉庫則還需要 push 操作,在 push 操作之前我們需要先 $ git fetch 操作將遠端倉庫的需要合併的檔案抓取到本地,然後進行合併,合併完成後使用 $ git status 指令進行檢視,沒問題後再推送到遠端。這裡其實也可以使用 $ git pull 來拉取遠端分支的快照,但是這容易產生衝突,若產生衝突則可以找到產生衝突的檔案,修改衝突部分再重新提交。提交完成後若想刪掉遠端工作分支,則可以使用 $ git push origin --delete 指令。

  • 當我們想刪除本地暫存區中的內容,可以使用$ git rm --cache 檔名 指令,當我們想刪除工作區的某個檔案可以使用 $ git rm -f

  • 當我們想要刪除錯誤提交到本地倉庫的 commit

    • $ git reset --soft 版本庫ID 僅僅撤銷已經提交的版本庫,不會修改暫存區和工作區
    • $ git reset --mixed 版本庫ID 僅僅撤銷提交到版本庫和暫存區的內容,不會修改工作區的內容
    • $ git reset --hard 版本庫ID 將工作區,暫存區,和版本庫記錄恢復到指定版本。
  • $ git stash branch 如果使用 stash 儲藏了一些工作,然後繼續在儲藏的分支上工作,在重新應用 stash 儲藏的檔案工作時可能會有問題。 如果應用嘗試修改剛剛儲藏的修改的檔案,也就是兩次同時修改了一個檔案,你會得到一個合併衝突並不得不解決它。 如果想要一個輕鬆的方式來再次測試儲藏的改動,可以執行 git stash branch 建立一個新分支,檢出儲藏工作時所在的提交,重新在那應用工作,然後在應用成功後自動扔掉儲藏。

  • 可以使用 $ git stash -all 來清除工作目錄中所有冗餘的未被跟蹤的檔案,並且他們會被儲存在工作棧上,當你想要恢復時也可以使用 $ git stash apply 恢復使用。

  • 當在本地新建立一個分支時,需要先 push 到遠端倉庫,遠端倉庫才會有這個分支,否則會報錯

    error: the requested upstream branch 'origin/f_tradeReverse' does not exist
    hint:
    hint: If you are planning on basing your work on an upstream
    hint: branch that already exists at the remote, you may need to
    hint: run "git fetch" to retrieve it.
    hint:
    hint: If you are planning to push out a new local branch that
    hint: will track its remote counterpart, you may want to use
    hint: "git push -u" to set the upstream config as you push.
    $ git fetch
    $ git status
    On branch f_tradeReverse
    nothing to commit, working tree clean
    $ git push
    fatal: The current branch f_tradeReverse has no upstream branch.
    To push the current branch and set the remote as upstream, use
    
        git push --set-upstream origin f_tradeReverse
    
    $  git push