Git從入門到熟練使用

Git 基礎(chǔ)

基本原理

  • 客戶端并不是只提取最新版本的文件快照,而是把代碼倉庫完整的鏡像下來。這樣一來,任何一處協(xié)同工作用的服務(wù)器發(fā)生故障,事后都可以用任何一個鏡像出來的本地倉庫恢復(fù)。每一次的克隆操作,實際上都是一次對代碼倉庫的完整備份。

Git的優(yōu)勢

直接記錄快照

  • Git 更像是把數(shù)據(jù)看作是對小型文件系統(tǒng)的一組快照。 每次你提交更新,或在 Git 中保存項目狀態(tài)時,它主要對當(dāng)時的全部文件制作一個快照并保存這個快照的索引。 為了高效,如果文件沒有修改,Git 不再重新存儲該文件,而是只保留一個鏈接指向之前存儲的文件。 Git 對待數(shù)據(jù)更像是一個 快照流。

  • 如圖,在version2中的 B 即是因為 File B 沒有改變,所以直接存儲了一個指向 FileB 的鏈接。只有修改了的文件才會產(chǎn)生一個新的文件,覆蓋原來的文件。

git存儲項目雖時間改變的快照.png

幾乎所有操作都在本地執(zhí)行

  • 在 Git 中的絕大多數(shù)操作都只需要訪問本地文件和資源,一般不需要來自網(wǎng)絡(luò)上其它計算機的信息。因為你在本地磁盤上就有項目的完整歷史,所以大部分操作看起來瞬間完成。

Git保證完整性

  • Git 中所有數(shù)據(jù)在存儲前都計算校驗和,然后以校驗和來引用。Git 用以計算校驗和的機制叫做 SHA-1 散列(hash,哈希)。Git 數(shù)據(jù)庫中保存的信息都是以文件內(nèi)容的哈希值來確定的,而不是文件名。
  • 這意味著不可能在 Git 不知情時更改任何文件內(nèi)容或目錄內(nèi)容。 這個功能建構(gòu)在 Git 底層,是構(gòu)成 Git 哲學(xué)不可或缺的部分。 若你在傳送過程中丟失信息或損壞文件,Git 就能發(fā)現(xiàn)。

Git一般只添加數(shù)據(jù)

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

需要注意的重點

三種狀態(tài)

  • 已提交 committed :數(shù)據(jù)已經(jīng)保存在本地 Git 倉庫

  • 已修改 modified : 修改了文件,但是還沒保存在倉庫中

  • 已暫存 staged : 對一個已修改的文件的當(dāng)前版本做了標(biāo)記

工作目錄,暫存區(qū)域及Git倉庫.png

三個區(qū)域

  • 工作目錄 Working Directory :對項目的某個版本獨立提取出來的內(nèi)容,這些從Git倉庫的壓縮數(shù)據(jù)庫提取出來的文件,放在磁盤上供你使用或修改。
  • 暫存區(qū)域 Staging Area :是一個文件保存了下次將提交的文件列表,是待提交文件的暫存區(qū)域。一般在Git倉庫的目錄中,有時也被稱為索引。
  • Git倉庫:用來保存項目的元數(shù)據(jù)和對象數(shù)據(jù)庫的地方。是Git中最重要的部分,從其他計算機克隆倉庫時拷貝的就是這里的數(shù)據(jù)

基本的Git工作流程

  • 在工作目錄中修改文件
  • 暫存文件,將文件的快照存儲在暫存區(qū)域
  • 提交更新,找到暫存區(qū)域的位置,將快照永久性存儲到Git倉庫目錄
    • 提交狀態(tài):如果Git目錄中保存著特定版本的文件,就屬于已提交狀態(tài)。
    • 暫存狀態(tài):如果做了修改并且已經(jīng)放入暫存區(qū)域,就屬于暫存狀態(tài)。
    • 已修改狀態(tài):如果自上次取出后,做了修改但是還沒有存在暫存區(qū)域,就是已修改狀態(tài)。

基本的Git操作流程

基礎(chǔ)設(shè)置

  • 首先最基礎(chǔ)的是需要配置用戶信息

    $ git config --global user.name "lanya"
    $ git config --global user.email shenglanya@corp.netease.com
    

    關(guān)于 config 的種類

    Config file location
    # global 表示配置全局信息,配置之后無論你在該系統(tǒng)上做任何事情,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 指令檢查全部配置信息,結(jié)果如下:

    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
    user.email=shenglanya@corp.netease.com
    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倉庫

方法一:在現(xiàn)有目錄中初始化倉庫(創(chuàng)建一個新的自己的倉庫)
  • git init 該命令將創(chuàng)建一個名為 .git 的子目錄,這個子目錄含有你在初始化的Git倉庫中所有的必須文件,這些文件是Git倉庫的骨干。但是,在這個時候,我們僅僅是做了一個初始化的操作,你的項目里的文件還沒有被跟蹤。

  • 如果你是在一個已經(jīng)存在文件的文件夾(而不是空文件夾)中初始化 Git 倉庫來進行版本控制的話,你應(yīng)該開始跟蹤這些文件并提交。 你可通過 git add 命令來實現(xiàn)對指定文件的跟蹤,然后執(zhí)行 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 可查看隱藏文件,發(fā)現(xiàn)存在名為 .git 的子目錄
    $ ls -a
    .     .DS_Store   .localized
    ..        .git        pic
    
    # 接著進入子目錄,發(fā)現(xiàn)此目錄中包含你初始化倉庫中所有的必須文件,這些文件是 Git 倉庫的骨干
    $ cd .git
    $ ls
    HEAD      config      hooks       objects
    branches  description info        refs
    
    # 接著需要跟蹤項目里的文件,需要注意的是,當(dāng)創(chuàng)建一個新的項目里的文件時,它默認(rèn)是未被跟蹤的,所以此時我們需要手動的將它添加到版本控制中,也就是被跟蹤
    
方法二:克隆現(xiàn)有倉庫(clone別人的)
  • 如果你想獲得一份已經(jīng)存在了的 Git 倉庫的拷貝,比如說,你想為某個開源項目貢獻自己的一份力,這時就要用到 git clone 命令。Git 克隆的是該 Git 倉庫服務(wù)器上的幾乎所有數(shù)據(jù),而不是僅僅復(fù)制完成你的工作所需要文件。 當(dāng)你執(zhí)行 git clone 命令的時候,默認(rèn)配置下遠(yuǎn)程 Git 倉庫中的每一個文件的每一個版本都將被拉取下來。

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

    Git 支持多種數(shù)據(jù)傳輸協(xié)議。 上面的例子使用的是 https:// 協(xié)議,不過你也可以使用 git:// 協(xié)議或者使用 SSH 傳輸協(xié)議,比如 user@server:path/to/repo.git 。

記錄每次更新到倉庫

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

檢查當(dāng)前文件狀態(tài)

  • 要查看哪些文件處于什么狀態(tài),可以用 git status 命令。 如果在克隆倉庫后立即使用此命令,會看到類似這樣的輸出:

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

    這說明你現(xiàn)在的工作目錄相當(dāng)干凈。表示所有已跟蹤文件在上次提交后都未被更改過。 此外,上面的信息還表明,當(dāng)前目錄下沒有出現(xiàn)任何處于未跟蹤狀態(tài)的新文件,否則 Git 會在這里列出來。 最后,該命令還顯示了當(dāng)前所在分支,并告訴你這個分支同遠(yuǎn)程服務(wù)器上對應(yīng)的分支沒有偏離。 現(xiàn)在,分支名是 “master”,這是默認(rèn)的分支名。

  • 如果你在當(dāng)前已經(jīng)有倉庫管理的項目中添加了一個文件,名字叫做 README 。然后使用 git status 命令,你會發(fā)現(xiàn)會出現(xiàn):

    $ 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也不會自動跟蹤它,這使得你不必?fù)?dān)心將生成的二進制文件或者其他不想被包含的文件包含進來。若你想跟蹤它,則需要明明白白的告訴它你想跟蹤這個文件,使用 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/工作目錄,暫存區(qū)域及Git倉庫.png
    
    Untracked files:
      (use "git add <file>..." to include in what will be committed)
    
      pic/實習(xí)學(xué)習(xí)筆記.md
    
    # 使用 git add 后
    $ git add pic/實習(xí)學(xué)習(xí)筆記.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/實習(xí)學(xué)習(xí)筆記.md
      new file:   pic/工作目錄,暫存區(qū)域及Git倉庫.png
    

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

  • 關(guān)于 git add 指令還有別的作用:

    • 用于追蹤新文件
    • 用于將已跟蹤的文件放入暫存區(qū)
    • 用于合并時把有沖突的文件標(biāo)記為已解決

暫存已修改文件

  • 修改已被跟蹤的文件。比如說修改了一個名為 實習(xí)學(xué)習(xí)筆記.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/實習(xí)學(xué)習(xí)筆記.md
      new file:   pic/工作目錄,暫存區(qū)域及Git倉庫.png
    
    # 說明已跟蹤文件內(nèi)容發(fā)生了變化,但是還未放入暫存區(qū)。如果想暫存這次更新,需要使用 git add 指令。 git add 指令是一個多功能命令:可以用它來跟蹤新文件,或者把已經(jīng)跟蹤的文件放到暫存區(qū)中,還能用于合并時把有沖突的文件標(biāo)記為已解決狀態(tài)等。
    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/實習(xí)學(xué)習(xí)筆記.md
      
      
    # 使用 git add 指令將其添加到暫存區(qū)
    $ git add pic/實習(xí)學(xué)習(xí)筆記.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/實習(xí)學(xué)習(xí)筆記.md
      new file:   pic/工作目錄,暫存區(qū)域及Git倉庫.png
    
  • 需要注意的是,當(dāng)已經(jīng)使用了 git add 指令暫存的版本又經(jīng)過修改之后,需在再重新使用 git add 指令將最新的修改放入暫存區(qū),否則此時暫存區(qū)里只有上一次修改的內(nèi)容。

提交文件到倉庫

  • 使用 git commit 指令可以使得暫存在暫存區(qū)的文件被提交到倉庫中去。

    $ 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/實習(xí)學(xué)習(xí)筆記.md
     create mode 100644 pic/工作目錄,暫存區(qū)域及Git倉庫.png
    

基本的 Git 操作指令

git status 命令概述

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

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

git diff 命令概述

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

    • 當(dāng)前做的更新哪些還沒有暫存?

      首先修改 pic/實習(xí)學(xué)習(xí)筆記.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/實習(xí)學(xué)習(xí)筆記.md
          
      # 表示該文件修改后還沒有暫存
      

      此時使用 git diff 可以查看當(dāng)前未暫存文件更新了哪些部分

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

      此時就可以查看未暫存文件修改的部分了。

      • 有哪些更新已經(jīng)暫存起來了準(zhǔn)備好了下次提交?

        可以使用 git diff --staged 指令查看,首先需要使用 git add 指令將剛剛修改的文件加入暫存區(qū)

        $ git add pic/實習(xí)學(xué)習(xí)筆記.md
        shenglanyadeMacBook-Pro:desktop shenglanya$ git diff --staged
        diff --git a/pic/實習(xí)學(xué)習(xí)筆記.md b/pic/實習(xí)學(xué)習(xí)筆記.md
        index 2b4e07b..a50f1a2 100644
        --- a/pic/實習(xí)學(xué)習(xí)筆記.md
        +++ b/pic/實習(xí)學(xué)習(xí)筆記.md
        @@ -14,7 +14,7 @@
        -* 有額外時間的話,需要將之前沒讀完的書繼續(xù)讀下去。
        +* 有額外時間的話,需要將之前沒讀完的書繼續(xù)讀下去。呵呵呵
        
  • 當(dāng)我們將文件暫存后繼續(xù)編輯時,使用 git status 指令查看如下:

    $ git status
    On branch master
    Changes to be committed:
      (use "git reset HEAD <file>..." to unstage)
    
      modified:   pic/實習(xí)學(xué)習(xí)筆記.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/實習(xí)學(xué)習(xí)筆記.md
    
    # 該文件同時出現(xiàn)在了暫存區(qū)和修改部分。
    
  • 現(xiàn)在運行 git diff 查看暫存前后的變化

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

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

    表示這個指令查看的是暫存區(qū)中文件的修改。

git commit 命令概述

  • 當(dāng)使用 git commit 命令提交暫存區(qū)域的文件時,一定要確認(rèn)是否還有什么修改過或新建的文件還未放入暫存區(qū),否則一旦提交,這些文件或修改都會只留在本地磁盤,不會加入版本控制中。所以每次提交前都需要執(zhí)行 git status 命令來查看是否都暫存起來了

  • 可以在 commit 命令后添加 -m 選項,將提交信息與命令放在同一行

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

  • 使用 git commit -a 可以跳過暫存這一步驟,git 會自動把所有已經(jīng)跟蹤過的文件暫存起來并且提交,即跳過 git add 步驟。

git rm 命令概述

  • 要從 Git 中移除某個文件,就必須從已經(jīng)跟蹤的文件清單中刪除,然后提交。

  • 刪除有兩種方式

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

    $ rm pic/實習(xí)學(xué)習(xí)筆記.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/實習(xí)學(xué)習(xí)筆記.md
    
    no changes added to commit (use "git add" and/or "git commit -a")
    
    # 此時將文件從暫存區(qū)域中刪除,但是文件還在被追蹤
    
  • 然后再將文件從跟蹤中刪除,這里兩種指令 $ git rm pic/實習(xí)學(xué)習(xí)筆記.md$ git add pic/實習(xí)學(xué)習(xí)筆記.md 都能達到同樣效果。

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

  • 當(dāng)我們想要將文件從 Git 倉庫中刪除但是卻想讓他仍在我們的工作區(qū)域中時,(即保存在本地磁盤并且不被 Git 跟蹤),為了達到這一目的,使用 --cached 選項。

    $ git rm --cached pic/git存儲項目雖時間改變的快照.png
    rm 'pic/git存儲項目雖時間改變的快照.png'
    
    # 執(zhí)行完此命令后,pic/git存儲項目雖時間改變的快照.png 文件還在本地磁盤上,并沒有被刪除。
    

git mv 命令概述

  • Git 并不顯式的跟蹤文件移動操作。所以如果 Git 重命名某個文件,倉庫中存儲的元數(shù)據(jù)并不會體現(xiàn)出這是一次改名操作。

  • 當(dāng)我們想在 Git 中對文件進行改名可以使用 git mv a b 方式來操作

    $ git mv pic/實習(xí)學(xué)習(xí)筆記.md pic/note.md
    $ git diff --staged
    diff --git a/pic/實習(xí)學(xué)習(xí)筆記.md b/pic/note.md
    similarity index 100%
    rename from pic/實習(xí)學(xué)習(xí)筆記.md
    rename to pic/note.md
    
  • git mv 等價于

    $ mv pic/實習(xí)學(xué)習(xí)筆記.md pic/note.md
    $ git rm pic/實習(xí)學(xué)習(xí)筆記.md
    $ git add pic/note.md
    

忽略文件

  • 我們有時會有些文件不需要 Git 來進行管理,也不希望他們總是出現(xiàn)在未跟蹤列表中,所以此時,我們可以創(chuàng)建一個名為 .gitignore 的文件,并在其中列出要忽略掉文件模式。

    # 先創(chuàng)建此忽略文件并向其中添加需要忽略的文件
    $ vi .gitignore
    
    # 查看此文件
    $ cat .gitignore
    .localized
    
    # 表示忽略所有以 .o 或 .a 結(jié)尾的文件
    *.[oa]
    
    # 表示忽略所有以波浪符(~)結(jié)尾的文件
    *~
    
  • 一些規(guī)范如下

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

git stash 命令概述

  • 當(dāng)我們已經(jīng)在一個分支上修改文件后,如果必須要切換到其他分支展開其他的工作,而當(dāng)前分支的工作還沒有完成,此時我們需要使用 $ git stash$ git stash save 命令將當(dāng)前分支上的工作暫存到棧上,這時你的工作目錄就干凈了,就可以切換到其他分支工作,等工作完成后,再切換回原來的分支,可以使用 $ git stash apply 將你剛剛的儲藏重新應(yīng)用。如果想查看你當(dāng)前一共有多少個儲藏,可以使用 $ git stash list 來查看。如果你并不想應(yīng)用最新的分支,而是想應(yīng)用某一個早些時間的分支,你可以使用 $ git stash apply stash@{1} ,其中最后一個括號內(nèi)的數(shù)字為你某一次提交到工作棧上的暫存記錄。如果你不指定 apply 的參數(shù),git 將認(rèn)為你想要應(yīng)用最近一次的儲藏。

  • 當(dāng)我們返回原本的分支后,使用 $ git stash apply 指令恢復(fù)了工作棧中暫存的數(shù)據(jù),但是如果當(dāng)你提交這個分支之前,已經(jīng)在暫存區(qū)緩存了一部分工作內(nèi)容,并且使用 stash 保存了工作狀態(tài),此時當(dāng)你恢復(fù)工作棧中的數(shù)據(jù)后,實際上暫存區(qū)中的內(nèi)容將會被移出暫存區(qū),而被放在了工作目錄中修改的部分,你需要手動將它再放回暫存區(qū),否則可以使用 $ git stash apply --index 來嘗試重新將暫存區(qū)的文件恢復(fù)到暫存區(qū)中。當(dāng)你把這個修改放入暫存區(qū)后,實際上堆棧上還有這個修改的記錄,此時你可以使用 $ git stash drop stash@{1} 來從棧中移除它,或者直接使用 $ git stash pop 來應(yīng)用儲藏棧這樣它就會自動從儲藏棧上消失了。

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

    $ 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 儲藏了一些工作,然后繼續(xù)在儲藏的分支上工作,在重新應(yīng)用 stash 儲藏的文件工作時可能會有問題。 如果應(yīng)用嘗試修改剛剛儲藏的修改的文件,也就是兩次同時修改了一個文件,你會得到一個合并沖突并不得不解決它。 如果想要一個輕松的方式來再次測試儲藏的改動,可以運行 git stash branch 創(chuàng)建一個新分支,檢出儲藏工作時所在的提交,重新在那應(yīng)用工作,然后在應(yīng)用成功后扔掉儲藏

    $ 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/stash@{0} (f0dfc4d5dc332d1cee34a634182e168c4efc3359)
    
  • $ git stash -all 可以移除工作目錄中所有未跟蹤的文件并且存儲在工作棧上,相應(yīng)的一個不怎么安全的方法是 $ git clean 直接清除了內(nèi)容,無法追溯回。不過可以使用 git clean 命令去除冗余文件或者清理工作目錄。 使用git clean -f -d命令來移除工作目錄中所有未追蹤的文件以及空的子目錄。 -f 意味著 強制 或 “確定移除”。在使用 $ git clean 之前,我們可以先使用 $ git clean -d -n 來看一下這樣做的后果是什么,也就是有什么文件會被移除。

git log 命令概述

  • 在提交了若干更新,又或者克隆了某個項目之后,你也許想回顧下提交歷史。 此時便需要 git log 命令。默認(rèn)不加其他參數(shù)時, git log 惠安提交時間列出所有更新。

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

    $ git log -p
    commit fb40f7a259de8ec2f2edbada6f85aa855f4a6585 (HEAD -> master)
    Author: shenglanya <shenglanya@corp.netease.com>
    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 <shenglanya@corp.netease.com>
    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 選項可以看到每次提交的簡略統(tǒng)計信息

    $ git log --stat
    commit fb40f7a259de8ec2f2edbada6f85aa855f4a6585 (HEAD -> master)
    Author: shenglanya <shenglanya@corp.netease.com>
    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 <shenglanya@corp.netease.com>
    Date:   Wed Mar 7 11:33:36 2018 +0800
    
        xiugai
    
     pic/git存儲項目雖時間改變的快照.png | Bin 20722 -> 0 bytes
     pic/實習(xí)學(xué)習(xí)筆記.md                       |  22 ++++++++++++++++++++++
     2 files changed, 22 insertions(+)
    
    commit a7372097ab8f063e17beca6fa8f82a15bb11c5e3
    Author: shenglanya <shenglanya@corp.netease.com>
    Date:   Wed Mar 7 11:20:05 2018 +0800
    
    
  • 常用選項 --pretty 可以指定使用不同于默認(rèn)格式的方式展示提交信息。比如 oneline 將每個提交放在一行顯示,查看到提交數(shù)很大時非常有用。另外還有 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 <shenglanya@corp.netease.com>
    | Date:   Wed Mar 7 11:34:54 2018 +0800
    | 
    |     add pic
    | 
    * commit ec50914561593b769a98ff468de6697a6d964cbd
    | Author: shenglanya <shenglanya@corp.netease.com>
    | Date:   Wed Mar 7 11:33:36 2018 +0800
    | 
    |     xiugai
    | 
    * commit a7372097ab8f063e17beca6fa8f82a15bb11c5e3
    | Author: shenglanya <shenglanya@corp.netease.com>
    | Date:   Wed Mar 7 11:20:05 2018 +0800
    | 
    |     提交
    
  • git log 的常用選項

    選項                說明
    -p                按補丁格式顯示每個更新之間的差異。
    --stat            顯示每次更新的文件修改統(tǒng)計信息。
    --shortstat       只顯示 --stat 中最后的行數(shù)修改添加移除統(tǒng)計。
    --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      僅顯示指定作者相關(guān)的提交。
    --committer       僅顯示指定提交者相關(guān)的提交。
    --grep            僅顯示含指定關(guān)鍵字的提交
    -S                僅顯示添加或移除了某個關(guān)鍵字的提交
    

撤銷操作指令

  • 重新提交:有時候我們提交完了才發(fā)現(xiàn)漏掉了幾個文件沒有添加,或者提交信息寫錯了。 此時,可以運行帶有 --amend 選項的提交命令嘗試重新提交:$ git commit --amend 這個命令將暫存區(qū)中的文件提交,如果自從上次提交以來還未做任何修改,則快照保持不變,你修改的只有提交信息。例如你提交后發(fā)現(xiàn)忘記了暫存某些需要的修改,可以像下面這樣操作:

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

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

Git 遠(yuǎn)程倉庫的使用

  • 查看遠(yuǎn)程倉庫 : 使用 git remote 命令可以列出你指定的每個遠(yuǎn)程服務(wù)器的簡寫。如果已經(jīng)克隆了自己的倉庫,那么至少能看到 origin

    $ cd ios-client
    $ git remote
    origin
    

    可以指定參數(shù) -v 可以查看你的讀寫權(quán)限

    $ 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)
    
  • 添加遠(yuǎn)程倉庫: 運行 git remote add <shortname> <url> 添加一個新的遠(yuǎn)程 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)
    

    現(xiàn)在就可以使用 test 來代替整個 URL ,例如使用 git fetch test 來拉取遠(yuǎn)端 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
    

    現(xiàn)在可以在本地訪問 test/master 分支了,實際上對應(yīng)遠(yuǎn)端的 master 分支。

  • 從倉庫中抓取: git fetch 會訪問遠(yuǎn)端倉庫,從中拉取所有你沒有的信息。執(zhí)行完后,你會擁有該倉庫的所有分支引用可以用來隨時合并和查看。當(dāng)使用了 git clone 命令克隆一個遠(yuǎn)端倉庫時,命令會自動將其添加為遠(yuǎn)程倉庫并默認(rèn)以 “origin” 為簡寫。git fetch origin 會抓取克隆(或上一次抓?。┖笮峦扑偷乃泄ぷ?。 必須注意 git fetch 命令會將數(shù)據(jù)拉取到你的本地倉庫 - 它并不會自動合并或修改你當(dāng)前的工作。 當(dāng)準(zhǔn)備好時你必須手動將其合并入你的工作。

  • 從倉庫上拉取: git pull 可以用來自動的抓取然后合并遠(yuǎn)程分支到當(dāng)前分支,前提是你有一個分支設(shè)置為跟蹤一個遠(yuǎn)程的分支。所以 git pull == git fetch + git merge。默認(rèn)情況下, git clone 會自動設(shè)置本地的 master 分支跟蹤遠(yuǎn)程倉庫的 master 分支,運行 git pull 通常會從最初克隆的服務(wù)器上抓取數(shù)據(jù)并自動嘗試合并到當(dāng)前所在的分支。

  • 推送到遠(yuǎn)程分支git push [remote-name][branch-name] 指令可以將你的項目推送到服務(wù)器。例如當(dāng)你想將 master 推到 origin 時,可以使用 $ git push origin master 只有當(dāng)你有所克隆服務(wù)器的寫入權(quán)限,并且之前沒有人推送過時,這條命令才能生效。 當(dāng)你和其他人在同一時間克隆,他們先推送到上游然后你再推送到上游,你的推送就會毫無疑問地被拒絕。 你必須先將他們的工作拉取下來并將其合并進你的工作后才能推送

  • 查看遠(yuǎn)程倉庫: 如果想查看一個遠(yuǎn)程倉庫的更多信息,可以使用 $ 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)
    

    這個命令列出了當(dāng)你在特定的分支上執(zhí)行 git push 會自動地推送到哪一個遠(yuǎn)程分支。 它也同樣地列出了哪些遠(yuǎn)程分支不在你的本地,哪些遠(yuǎn)程分支已經(jīng)從服務(wù)器上移除了,還有當(dāng)你執(zhí)行 git pull 時哪些分支會自動合并

  • 遠(yuǎn)程倉庫的移除與命名:運行 git remote rename <shortname> <url> 重命名遠(yuǎn)程倉庫

    $ git remote rename test testNea
    $ git remote
    origin
    testNea
    
  • 移除遠(yuǎn)程倉庫:

    $ git remote rm testNea
    $ git remote
    origin
    

Git 標(biāo)簽

創(chuàng)建標(biāo)簽

  • 輕量標(biāo)簽 — 就像一個不會改變的分支,只是一個特定提交的引用,創(chuàng)建輕量標(biāo)簽只需要提供版本號即可。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 <shenglanya@corp.netease.com>
    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
    
  • 附注標(biāo)簽 — 一個存儲在 Git 數(shù)據(jù)庫中的一個完整對象,他們可以被校驗。其中包含打標(biāo)簽者的名字,電子郵件地址、日期時間,標(biāo)簽信息。并且可以使用 GNU Privacy Guard (GPG)簽名與驗證??梢允褂?code>$ git tag -a v1.3 這樣就給當(dāng)前版本打上了 v1.3 標(biāo)簽。也可以使用 $ git tag -a v1.3 -m 'my version 1.3' 這樣就直接標(biāo)備注了。 git show 可以查看標(biāo)簽信息與對應(yīng)的提交信息

    $ git tag -a v1.3
    $ git show
    commit fb40f7a259de8ec2f2edbada6f85aa855f4a6585 (HEAD -> master, tag: v1.3)
    Author: shenglanya <shenglanya@corp.netease.com>
    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
    

后期打標(biāo)簽

  • 也可以對過去提交打標(biāo)簽。例如提交歷史如下

    $ 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 表示對該校驗和的版本打上標(biāo)簽。

    $ git tag
    v1.2
    v1.3
    v1.4-1w
    $ git show v1.2
    tag v1.2
    Tagger: shenglanya <shenglanya@corp.netease.com>
    Date:   Wed Mar 7 15:00:31 2018 +0800
    
    對之前的打標(biāo)簽`
    
    commit 2713657f264a3a019580dc3a489d303fade5dc5c (tag: v1.2)
    Author: shenglanya <shenglanya@corp.netease.com>
    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/實習(xí)學(xué)習(xí)筆記.md b/pic/實習(xí)學(xué)習(xí)筆記.md
    new file mode 100644
    

Git 分支

分支簡介

簡介

  • Git 保存到不是文件的變化或差異,而是一系列不同時刻的文件快照。當(dāng)提交時,Git 會保存一個提交的對象。該提交對象會包含一個指向暫存內(nèi)容快照的指針,還會包含作者姓名和郵箱,提交時輸入的信息以及指向他的父對象的指針。首次提交產(chǎn)生的提交對象沒有父對象,普通提交操作產(chǎn)生的提交對象有一個父對象,而由多個分支合并產(chǎn)生的提交對象有多個父對象。

  • 我們假設(shè)現(xiàn)在有一個工作目錄,里面包含了三個將要被暫存和提交的文件。 暫存操作會為每一個文件計算校驗和然后會把當(dāng)前版本的文件快照保存到 Git 倉庫中,最終將校驗和加入到暫存區(qū)域等待提交:

創(chuàng)建分支

  • Git 創(chuàng)建新分支的本質(zhì)就是創(chuàng)建一個可以移動的新的指針。比如創(chuàng)建一個 testing 分支。$ git branch testing 這會在當(dāng)前所提交的對象上創(chuàng)建一個指針,此時如圖:
two-branches.png
  • 如何判斷 Git 當(dāng)前在哪一個分支?此時就要依靠 HEAD 指針。該指針指向當(dāng)前所在的本地分支。如圖
    head-to-master.png

此時 HEAD 指針指向 master 指針,也就是實際上 HEAD 指針指向的時當(dāng)前所在的本地分支。在本例中,我們?nèi)栽?master 分支上,因為 git branch 命令僅僅是創(chuàng)建了一個新分支,并沒有切換到它上面??梢允褂靡韵旅顏聿榭锤鱾€分支當(dāng)前所指的對象

$ 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) 第一次的修改提交

可以看到,當(dāng)前 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 指針,表示當(dāng)前的本地分支切換為 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) 第一次的修改提交
    

    此時可以發(fā)現(xiàn) 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) 第一次的修改提交
    

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

    ?

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

    • 使 HEAD 指向 master 分支
    • 將工作目錄恢復(fù)成 master 分支所指向的快照內(nèi)容,也就是忽略 testing 分支所做的修改。
  • 若我們此時再對 master 分支上的文件上進行修改,就會產(chǎn)生分叉。因為你剛創(chuàng)建了一個新分支,并且切換過去進行了一些工作,然后后切換回了 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 的分支實際上只是包含所指對象的校驗和,創(chuàng)建一個新分支僅僅相當(dāng)于往一個文件中寫入 41 個字節(jié)。

分支操作

分支的新建與合并

  • 具體實例總結(jié)在此文章中 分支的新建與合并
  • 需要注意的地方:
    • 首先當(dāng)你想直接從當(dāng)前分支創(chuàng)建并切換到新分支時,可以使用 $ git checkout -b yourname 來進行操作,這個命令等價于 $ git branch yourname + $ git checkout yourname
    • 當(dāng)你在新分支上工作時,突然需要切換到之前開始分叉的 master 分支并且需要在 master 分支上開一個新的分支進行工作,則首先需要暫存你在 yourname 分支上還未進行暫存的修改,然后將其提交到倉庫。否則可能會跟你即將檢出的分支產(chǎn)生沖突。
    • 當(dāng)你在 master 分支上開了一個新分支并且已經(jīng)解決完問題后,可以將 master 和 hotfix 進行合并,使用 $ git checkout master, $ git merge hotfix 進行合并。
      • 快進 (Fast forward):在合并時,如果當(dāng)前的 master 分支是你要合并分支的直接上游,則 Git 會直接將 master 指針向前推進到 hotfix 上面。然后就可以將 hotfix 進行刪除。 使用 $ git branch -d hotfix
      • 合并提交:而如果 master 不是你要合并分支的直接上游,比如此時 master 分支已經(jīng)指向了原本 hotfix 指向的位置,則將它與 yourname 分支合并起來會比較麻煩。由于此時 master 分支已經(jīng)更新了,如果我們需要它新的內(nèi)容可以將 master 合并到 yourname 上,如果不需要可以直接等 yourname 分支任務(wù)完成后,將其合并到 master 上面。如果我們想將 yourname 合并到 master 上,首先會記錄他們兩個指針?biāo)赶虻淖詈笠粋€快照,然后記錄他們共同的祖先快照,最后將三方合并的結(jié)果做一個新的快照并且自動創(chuàng)建一個新的提交指向它。合并后可以刪除 yourname 分支。
  • 遇到?jīng)_突的分之合并:可以直接使用 git status 狀態(tài)來查看具體是哪個文件產(chǎn)生了沖突,然后直接打開該文件刪除亂碼部分和不需要的部分。

分支管理(git branch 命令)

  • $ git branch 命令不僅可以創(chuàng)建或刪除分支,當(dāng)不加參數(shù)時,其作用為可以查看當(dāng)前分支

    $ git branch
    * master
      testing
    

    其中 * 表示當(dāng)前分支

  • $ git branch -v 可以查看每個分支的最后一次提交

    $ git branch -v
    * master  b551643 made a change on master
      testing 844332b made a change on tesing
    
  • $ git branch --merged 可以查看哪些分支已經(jīng)合并到當(dāng)前分支上,同理 $ git branch --no-merged

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

分支開發(fā)工作流程

  • 長期分支(最常用)
    • 如只在 master 上保留穩(wěn)定的代碼,有可能僅僅是已經(jīng)發(fā)布的代碼。還有一些其他的分支如 develop 和 next 平行分支用來進行后續(xù)開發(fā),一旦在在這些分支上達到了穩(wěn)定,再將他們合并到 master 分支上。這樣在確保這些已完成的特性分支能夠通過所有的測試,并且不會引入 bug 后再將他們合并到 master 上等待下一次發(fā)布。
  • 特性分支
    • 特性分支被用來實現(xiàn)單一特性或相關(guān)工作,一旦工作完成它就會被刪除。這項技術(shù)可以使你快速的進行上下文切換。當(dāng)你做這么多操作時,這些分支要確保存于本地,而不會與服務(wù)器進行交互。

遠(yuǎn)程分支

  • 遠(yuǎn)程引用是指對遠(yuǎn)程倉庫的引用,包括分支標(biāo)簽等。他們是你不能移動的本地引用,當(dāng)你做任何網(wǎng)絡(luò)通信操作時,他們會自動移動。遠(yuǎn)程跟蹤分支像是你上次連接到遠(yuǎn)程倉庫時,那些分支所處狀態(tài)的書簽。他們的命名格式為 (remote)/(branch) 。如果你想要看你最后一次與遠(yuǎn)程 origin 分支通信時 master 分支的狀態(tài),則可以查看 origin / master 分支。你與同事合作解決一個問題并且他們推送了一個 iss53 分支,你可能有自己的本地 iss53 分支;但是在服務(wù)器上的分支會指向 origin/iss53 的提交。
  • 當(dāng)與遠(yuǎn)端倉庫共同工作時,如果你不抓取fetch遠(yuǎn)端 orgin/master ,則它將會一直指向在你上次 fetch 的那個文件。此時即使你本地的 master 已經(jīng)指向很遠(yuǎn)的地方了,遠(yuǎn)端的 orgin/master 還依舊指向你上次 fetch 的那個位置。直到你下一次 fetch。

需要注意的問題

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

  • 當(dāng) merge 出現(xiàn)沖突時,我們可以先 $ git status 來查看是哪里出現(xiàn)了問題,然后 cd 進入該文件,直接將沖突部分刪除即可解決問題。合并完成后再次執(zhí)行 $ git status 來查看問題是否解決。若問題解決,即可提交。

  • 當(dāng)已經(jīng)使用了 git add 指令暫存的版本又經(jīng)過修改之后,需在再重新使用 git add 指令將最新的修改放入暫存區(qū),否則此時暫存區(qū)里只有上一次修改的內(nèi)容

  • $ git commit 指令僅僅是將暫存區(qū)內(nèi)的文件快照提交到本地倉庫中,想要推送到遠(yuǎn)程倉庫則還需要 push 操作,在 push 操作之前我們需要先 $ git fetch 操作將遠(yuǎn)程倉庫的需要合并的文件抓取到本地,然后進行合并,合并完成后使用 $ git status 指令進行查看,沒問題后再推送到遠(yuǎn)端。這里其實也可以使用 $ git pull 來拉取遠(yuǎn)端分支的快照,但是這容易產(chǎn)生沖突,若產(chǎn)生沖突則可以找到產(chǎn)生沖突的文件,修改沖突部分再重新提交。提交完成后若想刪掉遠(yuǎn)端工作分支,則可以使用 $ git push origin --delete 指令。

  • 當(dāng)我們想刪除本地暫存區(qū)中的內(nèi)容,可以使用$ git rm --cache 文件名 指令,當(dāng)我們想刪除工作區(qū)的某個文件可以使用 $ git rm -f 。

  • 當(dāng)我們想要刪除錯誤提交到本地倉庫的 commit

    • $ git reset --soft 版本庫ID 僅僅撤銷已經(jīng)提交的版本庫,不會修改暫存區(qū)和工作區(qū)
    • $ git reset --mixed 版本庫ID 僅僅撤銷提交到版本庫和暫存區(qū)的內(nèi)容,不會修改工作區(qū)的內(nèi)容
    • $ git reset --hard 版本庫ID 將工作區(qū),暫存區(qū),和版本庫記錄恢復(fù)到指定版本。
  • $ git stash branch 如果使用 stash 儲藏了一些工作,然后繼續(xù)在儲藏的分支上工作,在重新應(yīng)用 stash 儲藏的文件工作時可能會有問題。 如果應(yīng)用嘗試修改剛剛儲藏的修改的文件,也就是兩次同時修改了一個文件,你會得到一個合并沖突并不得不解決它。 如果想要一個輕松的方式來再次測試儲藏的改動,可以運行 git stash branch 創(chuàng)建一個新分支,檢出儲藏工作時所在的提交,重新在那應(yīng)用工作,然后在應(yīng)用成功后自動扔掉儲藏。

  • 可以使用 $ git stash -all 來清除工作目錄中所有冗余的未被跟蹤的文件,并且他們會被存儲在工作棧上,當(dāng)你想要恢復(fù)時也可以使用 $ git stash apply 恢復(fù)使用。

  • 當(dāng)在本地新創(chuàng)建一個分支時,需要先 push 到遠(yuǎn)端倉庫,遠(yuǎn)端倉庫才會有這個分支,否則會報錯

    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 --set-upstream origin f_tradeReverse
    Username for 'https://git.ms.netease.com': shenglanya
    Password for 'https://shenglanya@git.ms.netease.com':
    Total 0 (delta 0), reused 0 (delta 0)
    remote:
    remote: Create merge request for f_tradeReverse:
    remote:   https://git.ms.netease.com/preciousmetals/LDPMTrade/merge_requests/new?merge_request%5Bsource_branch%5D=f_tradeReverse
    remote:
    To https://git.ms.netease.com/preciousmetals/LDPMTrade.git
     * [new branch]        f_tradeReverse -> f_tradeReverse
    Branch 'f_tradeReverse' set up to track remote branch 'f_tradeReverse' from 'origin'.
    
  • git 拉取遠(yuǎn)程分支并且創(chuàng)建本地分支 $ git checkout -b 本地分支名x origin/遠(yuǎn)程分支名x

  • 如果寫錯名字,重命名遠(yuǎn)程為dev1。思路:刪除遠(yuǎn)程分支、重命名本地分支、重新提交一個遠(yuǎn)程分支

    1、git push --delete origin dev——刪除遠(yuǎn)程分支

    2、git branch -m dev dev1——重命名本地分支為dev1

    3、git push origin dev1——重新推送遠(yuǎn)端倉庫分支名稱為dev1

  • 如何刪除本地的文件的修改?

    • 如果是刪除已經(jīng)暫存的文件,則直接使用 $ git reset HEAD 文件名
    • 如果是要刪除未暫存的文件,使用 $ git checkout --文件名 這樣會使得這個文件去掉所有還未暫存的修改
    • 如果刪除未跟蹤的文件,使用 $ git clean -df
    • 刪除不想要的修改 $ git stash && $ git stash clear
    • 刪除本地分支 $ git branch -D BranchName
  • 刪除遠(yuǎn)端分支

    • 刪除本地的遠(yuǎn)端分支 $ git branch -r -D origin/BranchName
    • 刪除遠(yuǎn)端服務(wù)器的分支 $ git push origin -d BranchName
  • 打 tag

    • 在本地打 tag :$ git tag 4.20.1
    • 將 tag 推送到遠(yuǎn)端 : $ git push origin :4.20.1
  • 查看遠(yuǎn)端分支 $ git branch -r

  • 從遠(yuǎn)端拉取分支 $ git checkout -b x origin/x

總結(jié)

  • 本次 Git 基礎(chǔ)學(xué)習(xí)總結(jié)到現(xiàn)在就告一段落,文章由于時間,精力和自己本身能力原因并未能夠完整的寫完,留到日后的學(xué)習(xí)工作中當(dāng)有時間和精力,以及對 Git 的使用更加了解后,將繼續(xù)完善。

參考資料

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容