git的學習匯總--原創

tools/git/git-banner

這篇博文是自己在學習git過程中的思考總結。本文僅僅代表個人的看法,如有不妥地方還請本文文末留言。 ??

原文鏈接git的學習匯總--原創

GIT是什么

GIT是一個免費并且開源的分布式版本控制系統,能夠高速有效的處理或小或大的項目。(以上的話是自己翻譯github官網)

至今,自己用過了window系統的TortoiseSVN, mac系統的CornerStone,最近的大半年也在用GIT(主要管理自己的github項目)。比較下來,還是GIT優勢比較明顯。

GIT跨平臺

GIT可以在不同的操作系統中使用。也許你注意到了,我在window上和mac系統上工作的時候是使用兩個不同的svn。如果我在linux上工作會不會又是一個呢。

GIT是分布式版本控制系統,而svn是集中式版本控制系統

集中式版本控制系統是集中放在中央服務器上面的,而團隊的人需要從中央服務器上面拉取最新的代碼,然后進行開發,最后推送到中央服務器上面,就像串聯的電路。而分布式版本控制系統沒有中央服務器,團隊的每個人的電腦就是一個完整的版本庫,就好像并聯的電路(自我理解)。

集中式版本控制系統必須聯網才能工作,如果是在局域網內還好,帶寬足夠大,速度足夠快,但是遇到網速慢的話,那心里就一萬個羊駝??在蹦騰了。

集中式版本控制系統安全性比較低,如果中央系統崩潰了,那就有點悲催了。當然你不嫌麻煩,可以定期備份的啦。而分布式中央系統就比較安全,團隊的每個成員的電腦就是一個完整的版本庫。如果其中一個壞掉了,你可以從團隊另外一個的人員電腦那里拷貝一份就行了。對了,GIT也會有一臺中央的機子,主要是為了方便團隊的交流,它是可以不存在的。

GIT安裝

GIT支持不同的系統,看者可以在鏈接https://git-scm.com/downloads中,找到和自己電腦系統匹配的GIT版本,下載安裝包后根據提示進行安裝。當然,GIT還提供圖形界面管理工具,看者也可以在鏈接中下載GUI Clients,如下圖所示--

tools/git/git_install

根據提示安裝完成后,要驗證是否安裝成功??凑呖纱蜷_命令行工具,輸入git --version命令,如果安裝成功,控制臺輸出安裝的版本號(當然,安裝前就應該輸入git --version查看是否安裝了git),我這里安裝的GIT版本是2.10.0

GIT配置

GIT在使用前,需要進行相關的配置。每臺計算機上面只需要配置一次,程序升級的時候會保留配置信息。當然,看者可以在任何時候再次通過運行命令行來修改它們。

用戶信息

設置GIT的用戶名稱和郵件地址,這個很重要,因為每個GIT的提交都會使用這些信息,并且它會寫入到每一次的提交中。你可以在自己的倉庫中使用git log,控制臺上面顯示的每次的提交都有Author字段,它的值就是用戶名稱 <郵件地址>。方便查看某次的提交的負責人是誰。

$ git config --global user.name "你的用戶名"
$ git config --global user.email 你的郵箱地址 

?? GIT一般和github配合使用,看者應該設置用戶名稱為你的github用戶名。當然,還有和gitlab等配合使用...

?? 如果配置中使用了--global選項,那么該命令只需要運行一次,因為之后無論你在該系統上做任何事情,GIT都會使用這些信息。但是,當你想針對特定項目使用不同的用戶名稱與郵件地址的時候,可以在那個倉庫目錄下運行不使用global選項的命令來配置。

檢查配置信息

通過git config --list命令可以列出所有GIT能找到的配置。如下:(我的git版本為2.10.0)

...
user.name=reng99
user.email=1837895991@qq.com
color.ui=true
core.repositoryformatversion=0
core.filemode=true
core.bare=false
...

當然,你可以通過git config <key>來檢查GIT的某一項配置。比如$ git config user.name。

幫助中心

在使用GIT的時候,遇到問題尋求幫助的時候,可以運行git helpgit --helpgit命令來查看。在控制臺上會展示相關的幫助啦。

usage:
    ...
start a working area (see also: git help tutorial)
    ...
work on the current change (see also: git help everyday)
    ...
examine the history and state (see alse: git help revisions)
    ...
grow,mark and tweak your common history
    ...
collaborate (see also: git help workflows)
    ...

更加詳細的內容,請點擊傳送門

創建版本庫

版本庫又名倉庫(repository),可以理解成一個目錄,這個目錄里面所有文件都可以被GIT管理起來,每個文件的修改、刪除,GIT都能跟蹤,以便任何時刻都能可以追蹤歷史,或者在將來某個時刻可以還原。

創建一個版本庫,首先得選擇一個存放目錄的地方,我這里選擇了桌面,并且創建一個空的目錄。

$ cd desktop
$ mkdir -p learngit
$ cd learngit
$ pwd
/Users/reng/desktop/learngit

mkdir -p dirnanme是創建一個子目錄,這里的-p確保目錄的名稱存在,如果目錄不存在的就新建一個,如果你確定目錄不存在,直接使用mkdir dirname就可以了。pwd(Print Working Directory)是顯示當前目錄的整個路徑名。

然后,通過命令行git init,將創建的目錄變成GIT可以管理的倉庫:

$ git init 
Initialized empty Git repository in /Users/reng/Desktop/learngit/.git/

初始化好倉庫后就可以愉快的玩耍了,但是,得先來了解下GIT整個工作流程先。

GIT工作流程

為了更好的學習,自己用Axure RP 8粗略的畫了下流程圖,如下--

tools/git/git_brief_process

本地倉庫(repo)包含工作區和版本庫,那么什么是工作區和版本庫呢?基本的流程又是什么呢?

工作區和版本庫

我們新建一個倉庫,就像我們新建的learngit倉庫,現在在里面添加一個文件README.md,用sublime打開learngit目錄。此時會出現如下圖的情況(當然你設置了其他東西例外)--

tools/git/working_version_area

如上圖,出現的內容就是工作區( 電腦上能看到的此目錄下的內容),這里工作區只有README.md一個文件。工作區有一個隱藏的目錄.git,這個不算工作區,而是GIT的版本庫。版本庫又包括暫存區和GIT倉庫。暫存區是一個文件,保存了下次將提交的文件列表信息,而GIT倉庫目錄是GIT用來保存項目的元數據和對象數據庫的地方。這是GIT中最重要的部分,從其他計算機克隆倉庫的時候,拷貝的就是這里的數據。當執行git add .或者git add path/to/filename的時候,文件從工作區轉到暫存區;執行git commit -m"here is the message described the file you add"的時候,文件從緩存區添加到GIT倉庫。

基本的工作流

基本的GIT工作流可以簡單總結如下--

  1. 在工作區目錄中修改文件
  2. 暫存區中暫存文件,將文件的快照放入暫存區域
  3. 提交更新,找到暫存區域的文件,將快照永久性存儲到GIT倉庫目錄

時光機穿梭

到目前為止,在自己創建的本地倉庫--learngit中已經初具形態了。進入learngit,執行ls,可看到目前倉庫中已有的文件README.md。

$ cd desktop/learngit
$ ls
README.md
$ cat README.md
## content

上面展示了本地learngit內的相關的內容。運行下git status查看現在的狀態。

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

這時候會提示沒有內容可以提交,工作區是干凈的。因為我之前已經提交(git commit)過了。上面還提示了目前是位于主分支上面,GIT在初始化(git init)的時候會自動創建一個HEAD指針指向默認master分支,也只有一個分支,看者可以通過git branch查看。

現在,在README.md上添加一些內容。

## content

### first change

此刻再通過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:   README.md

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

這時候顯示出一堆的東西,告訴我們現在是位于主分支上面,然后告訴我們修改的文件啊,可以使用的命令進行下一步的操縱。那么我們來進行下一步的操作了,git add . 或者 git add README.md將修改的文件添加到暫存區域。

$ git add .
$ git status
On branch master
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

    modified:   README.md

對了,有時候需要在添加的之前(執行git add . 或者 git add path/to/filename)的時候,需要看下修改了哪些內容可以執行下git diff。那么,現在先回退到修改的前一個版本。

$ git reset HEAD README.md
Unstaged changes after reset:
M   README.md
$ git checkout -- README.md
$ ls
README.md
$ cat README.md
## content

回退正確,現在像上次那樣添加內容### first change,然后執行命令git diff來查看更改的內容。

$ git diff
diff --git a/README.md b/README.md
index 75759ec..0bc52b9 100644
--- a/README.md
+++ b/README.md
@@ -1 +1,3 @@
-## content
\ No newline at end of file
+## content
+
+### first change
\ No newline at end of file

現在就顯示了修改前的內容---前為修改前的內容,和修改后的內容--+前修改后的內容。查看完之后,覺得沒有問題了,就可以進行添加(git add),提交(git commit)。當然,一般不常用git diff的,因為自己修改的東西自己心里總有點數吧,可能合作中團隊的其他人需要查看文件前后的不同點就需要用到git diff啦。

版本回退

為了方便講解下版本回退,我先將上面添加的### first change提交以下--git add . && git commit -m "add first change"。下面通過git log就可以查看自己提交的記錄了。

$ git log
commit 5c2639ee54bd7c8ef2cbf186f5dc4798e72a4a67
Author: reng99 <1837895991@qq.com>
Date:   Sun Dec 17 17:11:53 2017 +0800

    init README.md
    
$ git add . && git commit -m "add first change"
[master 0ac49ba] add first change
 1 file changed, 3 insertions(+), 1 deletion(-)
 
$ git log
commit 0ac49bae6ab55df9c05d0770de347665a2568f31
Author: reng99 <1837895991@qq.com>
Date:   Mon Dec 18 15:26:06 2017 +0800

    add first change

commit 5c2639ee54bd7c8ef2cbf186f5dc4798e72a4a67
Author: reng99 <1837895991@qq.com>
Date:   Sun Dec 17 17:11:53 2017 +0800

    init README.md

在上面中,自己先執行了git log來顯示提交的日志,顯示只有一條,然后執行了add和commit的命令,打印的內容是現實主分支、commit的id、commit的信息、多少個文件的更改、多少個插入以及多少個刪除。之后再次執行git log打印日志,顯示了兩次提交。?? 注意:當提交(commit)的次數較多之后,控制臺會顯示不下(最多現實4條)那么多的條數,可以通過按鍵盤的向上或向下鍵查看日志的內容,需要退出查看日志命令的話,在英文輸入法的狀態按下q,意思就是quit(退出)。

版本的回退就是改變HEAD指針的指向。通過git reset --hard HEAD^返回上一個版本,通過git reset --hard HEAD^^返回上上個版本...由此推論,往上100個版本的話就是100個^,當然,這樣你數到明天也未必數得正確,所以寫成git reset --hard HEAD~100。另外一種是,你知道提交的id,例如commit 5c2639ee54bd7c8ef2cbf186f5dc4798e72a4a67的前7位就是commit的id(5c2639e),執行git reset --hard 5c2639e就回到此版本啦。

$ reng$ git reset --hard HEAD^
HEAD is now at 5c2639e init README.md
$ git log
commit 5c2639ee54bd7c8ef2cbf186f5dc4798e72a4a67
Author: reng99 <1837895991@qq.com>
Date:   Sun Dec 17 17:11:53 2017 +0800

    init README.md
$ ls
README.md
$ cat README.md
## content

現在你已經回到了最初的版本,這里演示的是通過HEAD,你也可以通過commit id來實現的。執行上面的代碼后,README.md文件里面只有一### content文字內容,但是過了段時間后,你想恢復到原先的版本,通過git log命令行,控制臺顯示的以前的信息,通過它找不到回退前的commit id,怎么辦?GIT提供一個git reflog顯示提交的歷史記錄,在那里可以查看提交的id、HEAD的指針歷史和操作的信息記錄。下面演示回退到最新的版本(也就是commit -m "add first change")--

$ git log
commit 5c2639ee54bd7c8ef2cbf186f5dc4798e72a4a67
Author: reng99 <1837895991@qq.com>
Date:   Sun Dec 17 17:11:53 2017 +0800

    init README.md
$ git reflog
5c2639e HEAD@{0}: reset: moving to HEAD^
0ac49ba HEAD@{1}: commit: add first change
5c2639e HEAD@{2}: commit (initial): init README.md
$ git reset --hard 0ac49ba
HEAD is now at 0ac49ba add first change
$ ls
README.md
$ cat README.md
## content

### first 

現在又回到了最新的版本,又能夠愉快的玩耍了。??

管理修改

GIT比其他版本控制系統設計優秀,其中一點是--GIT跟蹤并管理的是修改,而非文件。

下面在README.md內添加信息### second change。之后看下變化后的文件的狀態和差異等。

$ ls
README.md
$ cat README.md
## content

### first change

#### second change
$ 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:   README.md

no changes added to commit (use "git add" and/or "git commit -a")
$ git add README.md
$ git status
On branch master
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

    modified:   README.md

此時,對README.md進行第三次的修改,添加內容### third change

$ git status
On branch master
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

    modified:   README.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:   README.md

$ cat README.md
## content

### first change

#### second change

### third change
$ git commit -m "test file modify"
[master 18f86ba] test file modify
 1 file changed, 3 insertions(+), 1 deletion(-)
$ 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:   README.md

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

上面的演示流程是這樣的第一次修改(#### second change) -> git add -> 第二次修改(### third change) -> git commit。但是最后查看狀態的時候(git status),第二次的修改并沒有被提交上去。因為GIT管理的是修改,當使用git add命令的時候,在工作區的第一次修改被放入暫存區,準備提交,但是在工作區的第二次修改并沒有放入到暫存區,而git commit是將暫存區的修改提交到GIT倉庫,所以第二次修改的內容是不會被提交的。這也是說明為什么可以多次添加(git add),一次提交(git commit)的原因了。

撤銷修改

文件的撤銷修改分成三種情況,一種是修改在工作區的內容,一種是修改在暫存區的內容,另一種是修改在GIT倉庫的內容。也許會有看者說,不能修改在遠程庫中的內容嗎?有啊,就是git add->git commit->git push將遠程倉庫的內容覆蓋被,不過團隊人在克隆遠程庫下來的時候,還是可以查看到你提交的錯誤內容的。我們現在只針對本地倉庫的三種情況談下自己的看法--

情況一:撤銷工作區的內容

在管理修改中,自己的工作區還是沒有提交,此時想放棄當前工作區的編輯內容執行git checkout -- file。接著上面的內容,我這里的工作區內有的內容是### third change,現在我要放棄第三次修改,只要執行git checkout -- README.md就可以了。

$ 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:   README.md

no changes added to commit (use "git add" and/or "git commit -a")
$ ls
README.md
$ cat README.md
## content

### first change

#### second change

### third change
$ git checkout -- README.md
$ cat README.md
## content

### first change

#### second change
$ git status
On branch master
nothing to commit, working tree clean

情況二:撤銷暫存區的內容

當你不但改亂了工作區的某個文件的內容,還添加(git add)到了暫存區時,想丟棄修改,那么得分兩步來撤銷文件。先是通過git reset HEAD file,將暫存區的文件退回到工作區,然后通過git checkout -- file放棄修改改文件的內容。為了方便演示,我這里的暫存區沒什么內容,所以添加內容### tentative content并將它添加到緩存區。之后,演示將緩存區的內容撤回--

$ cat README.md
## content

### first change

#### second change

### tentative content
$ git add .
$ git status
On branch master
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

    modified:   README.md

$ git reset HEAD README.md
Unstaged changes after reset:
M   README.md
$ git checkout -- README.md
$ cat README.md
## content

### first change

#### second change
$ git status
On branch master
nothing to commit, working tree clean

情況三:撤銷GIT倉庫的內容

如果你不僅添加(git add)了內容到暫存區并且提交(git commit)了內容到GIT倉庫中了。你需要撤銷上一次的內容,也就是要回退到上一個版本,執行git reset --hard HEAD^就可以啦,詳細的內容查看版本回退。如下--

$ git status
On branch master
nothing to commit, working tree clean
$ cat README.md
## content

### first change

#### second change
$ git reset --hard HEAD^
HEAD is now at 0ac49ba add first change
$ cat READMEmd
## content

### first change

遠程倉庫

遠程倉庫的使用能夠提高你和團隊的工作效率,無論何時何地,團隊的人員都可以在聯網的情況下將代碼進行拉取,修改和更新。因為我是使用github來管理項目的,所以我的遠程倉庫是放在github里面。這里默認看者已經安裝了github,當然也可以用碼云、gitlab等。

本地庫添加到遠程庫

這點很容易,登錄自己注冊的github,如果打不開,請開下VPN。進入自己的首頁(https://github.com/username),點擊+號創建(new repository)一個名為learngit的倉庫(注意哦?? 名稱是本地倉庫已經初始化過的,我這里本地有個同名初始化的learngit倉庫),其他的字段自選來填寫。點擊Create repository創建此遠程倉庫。緊接著就是進行本地倉庫和遠程倉庫的關聯啦,github很友好的提示了你怎么進行一個遠程倉庫的關聯。

tools/git/related_github_step1

tools/git/related_github_step2

tools/git/related_github_step3

現在按照上圖來關聯下遠程倉庫。

$ git remote add origin https://github.com/reng99/learngit.git
$ git push -u origin master
Counting objects: 6, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (2/2), done.
Writing objects: 100% (6/6), 456 bytes | 0 bytes/s, done.
Total 6 (delta 0), reused 0 (delta 0)
To https://github.com/reng99/learngit.git
 * [new branch]      master -> master
Branch master set up to track remote branch master from origin.

注意?? 第一次向遠程倉庫(關聯)push的時候是$ git push -u origin master,不能忽略-u,以后的push不用帶-u。至此,打開你的github的相關的倉庫就可以看到添加了README.md文件,我這里地址是https://github.com/reng99/learngit,因為我是使用markdown語法寫的,控制臺顯示的內容和倉庫的顯示內容有所區別啦。<del>(?? 后期我將learngit倉庫刪除啦,所以你訪問鏈接是找不到這個倉庫的,畢竟不想放一個沒什么內容的倉庫在我的github上)</del>。

遠程庫克隆到本地

從遠程倉庫克隆東西到本地同樣很簡單,只需要進入你想克隆的倉庫,將倉庫的url復制下來(當然你也可以復制window.location.href的內容),運行git clone address?,F在我將本地桌面的learngit的倉庫刪除,然后從遠程將learngit克隆到本地。

tools/git/git_clone_repository
$ cd desktop
$ rm -rf learngit
$ find learngit
find: learngit: No such file or directory
$ git clone https://github.com/reng99/learngit
Cloning into 'learngit'...
remote: Counting objects: 6, done.
remote: Compressing objects: 100% (2/2), done.
remote: Total 6 (delta 0), reused 6 (delta 0), pack-reused 0
Unpacking objects: 100% (6/6), done.

成功將gitlearn從遠程克隆下來,接下來又可以愉快的玩耍啦。

分支管理

分支管理允許創建另一條線/方向上開發,能夠讓你在不影響他人工作的情況下,正常的工作。當在自己創建的分支中完成自己的功過后,合并到主分支就行了(git init初始化的時候已經默認創建了master主分支)。一般團隊的合作是不在主分支上進行的,個人項目除外(個人理解)。

創建分支

當前learngit倉庫上只有一個分支,那就是master分支,看者可以通過git branch命令來查看當前的分支,git branch branchName命令來創建一個新的分支,我這里創建的是dev分支。

$ cd desktop/learngit
$ git branch
* master
$ git branch dev
$ git branch
  dev
* master

現在已經創建了dev分支,有兩個分支了,分支前面帶有一個星號的分支說明是當前的正在工作的分區。執行上面的分支后,可以簡單的畫下現在的情況了,有個HEAD指針指向主分支的最新點,剛才新創建的dev分支我這里默認是一個dev的指針指向了dev分支的最新點。

.
.       HEAD指針
.       │
├────────*master
└────────dev
        │   
        dev指針   

切換分支

我們一般是很少在主分支進行工作的,所以在創建出新的分支之后,我們就切換到新的分支進行相關的工作。可以通過git checkout branchName切換到已經存在的分支工作,通過分支前面的*可查看目前位于哪個分支內?,F在我切換到創建的dev分支。

$ git branch
  dev
* master
$ git checkout dev
Switched to branch 'dev'
$ git branch
* dev
  master

合并分支

在創建好分支后,我們在新的分支上工作完成后,就需要往主分支上進行合并啦。我修改了分支dev上的README.md的內容,就是添加文字### new branch content。合并分支可以分成兩個合并的方式,一種是本地合并到materz主分支之后,推送(push)到遠程庫,一種是直接將分支推送到遠程庫,在遠程庫進行合并。

本地合并推送

在合并分支前,需要切換到要合并到哪個分支(一般是master主分支),通過git merge branchName將需要的合并的分支合并到當前分支,我是將dev分支合并到master分支。

$ git branch
* dev
  master
$ git checkout master
M   README.md
Switched to branch 'master'
Your branch is up-to-date with 'origin/master'.
$ git merge dev
$ Already up-to-date.
$ git add .
$ git commit -m "merge dev branch"
[master d705e73] merge dev branch
 1 file changed, 3 insertions(+), 1 deletion(-)
$ git push origin master
Counting objects: 3, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (2/2), done.
Writing objects: 100% (3/3), 282 bytes | 0 bytes/s, done.
Total 3 (delta 0), reused 0 (delta 0)
To https://github.com/reng99/learngit
   0ac49ba..d705e73  master -> master

合并之后,此時,HEAD指針就指向了dev指針,也就是兩者同時指向了master主分支的最新處。具體的內容參考傳送門

.
.           
.           
├────────*master
└────────dev
        │   
        dev指針    ── HEAD指針

遠程庫推送合并

遠程庫內合并的話,要先將dev的分支推送到遠程庫,然后在遠程庫進行合并。我這里在dev分支上添加了### add new branch content into again然后demo演示推送(git push origin dev)以及合并。

$ git branch
  dev
* master
$ git checkout dev
Switched to branch 'dev'
$ git add .
$ git commit -m "add dev branch commit again"
[dev dc817c4] add dev branch commit again
 1 file changed, 3 insertions(+), 1 deletion(-)
$ git push origin dev
Counting objects: 3, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (2/2), done.
Writing objects: 100% (3/3), 300 bytes | 0 bytes/s, done.
Total 3 (delta 0), reused 0 (delta 0)
To https://github.com/reng99/learngit
 * [new branch]      dev -> dev

接下來就是進入我的遠程learngit倉庫進行合并,你會看到下面圖示的提示。點擊Compare && pull request,然后寫點相關的comment(選填),點擊Create pull request。之后在綠色勾的提示下Merge pull request,緊接著點擊Confirm merge按鈕確定合并此分支,這時候返回主分支就可以看到dev內合并的內容了(后期我改動了dev的內容)??凑呷绻吹貌幻靼祝约荷鲜謬L試一下唄!

tools/git/merge_branch

完成后,你會看到learngit倉庫的Pull requests量為1,branches量為2。你可以點擊進入分支,在ALL branches里面查看分支的具體內容。

刪除分支

在創建了分支,然后將分支的內容合并到主分支后,分支的使命就完成了,你就可以將分支刪除了,這里的刪除個人認為可以是兩種,一種是本地倉庫的分支刪除,一種是遠程倉庫的分支的刪除。當然啦,留著分支也沒啥,可以留著唄<del>,自己認為有點礙眼</del>。

本地分支的刪除

在本地的learngit的目錄下,執行命令行git branch -D branchName就可以刪除了。我這里刪除的是dev分支。注意?? ,刪除的分支不應該是當前工作的分支,需要切換到其他分支,我這里切換的是master分支,畢竟我只有兩個分支呢。

$ git branch
* dev
  master
$ git branch -D dev
error: Cannot delete branch 'dev' checked out at '/Users/reng/desktop/learngit'
$ git checkout master
Switched to branch 'master'
Your branch is up-to-date with 'origin/master'.
$ git branch
  dev
* master
$ git branch -D dev
Deleted branch dev (was dc817c4).
$ git branch
* master

遠程庫分支的刪除

刪除遠程庫的分支,只要執行git push origin :branchName命令就行了?,F在我要刪除我遠程庫中的dev分支,執行git push origin :dev。

$ git push origin :dev
To https://github.com/reng99/learngit
 - [deleted]         dev

此時,打開我的遠程庫learngit,發現之前的Pull requests量為0,branch量為1。

重命名分支

通過git branch -m oldBranchName newBranchName來重命名分支。我這里沒有分支了,現在創建一個reng分支,然后將它重命名為dev分支。

$ git branch
* master
$ git branch reng
$ git branch
* master
  reng
$ git branch -m reng dev
$ git branch
  dev
* master

解決沖突

在我們開發的時候,不知道分支和分支之間的進度情況是什么,難免會產生沖突。當產生沖突的時候,就得將沖突的內容更正,然后提交。為了方便演示,我將本地的learngit刪除,重新拉取遠程的gitlearn倉庫(因為我不知道我之前在本地倉庫做的修改是啥,對了,我將遠程的分支刪除了,只剩下master主分支)??寺∠聛砗螅绻€存在本地分支,也將它刪除,之后我將在masterdev分支中重新填充里面的README.md的內容。

$ cd desktop
$ git clone https://github.com/reng99/learngit.git
Cloning into 'learngit'...
remote: Counting objects: 43, done.
remote: Compressing objects: 100% (17/17), done.
remote: Total 43 (delta 4), reused 38 (delta 1), pack-reused 0
Unpacking objects: 100% (43/43), done.
$ cd learngit
$ git branch
* master
$ ls
README.md
$ cat README.md
## master branch content
$ git add .
$ git commit -m "add master branch content"
[master 1cfa0aa] add master branch content
 1 file changed, 1 insertion(+), 1 deletion(-)
$ git push origin master
Counting objects: 3, done.
Writing objects: 100% (3/3), 271 bytes | 0 bytes/s, done.
Total 3 (delta 0), reused 0 (delta 0)
To https://github.com/reng99/learngit.git
   d2f936f..1cfa0aa  master -> master
$ git branch dev
$ git checkout dev
Switched to branch 'dev'
$ cat README.md
## master branch content

### dev branch content
$ git add .
$ git commit -m "add dev branch content"
[dev 80faf6d] add dev branch content
 1 file changed, 2 insertions(+)
$ git checkout master
Switched to branch 'master'
Your branch is up-to-date with 'origin/master'.
$ cat README.md
## master content

### new master branch content
$ git add .
$ git commit -m "change master content"
[master ec18715] change master content
 1 file changed, 3 insertions(+), 1 deletion(-)
$ git merge dev
Auto-merging README.md
CONFLICT (content): Merge conflict in README.md
Automatic merge failed; fix conflicts and then commit the result.

README.md文件中沖突內容--

<<<<<<< HEAD (當前更改)
## master content

### new master branch content
=======
## master branch content

### dev branch content
>>>>>>> dev (傳入更改)

手動修改了README.md文件中沖突的內容--

## master branch content
### new master branch content
### dev branch content

然后命令行執行--

$ git add .
$ git commit -m "fix confict content"
[master dd848b4] fix confict content
$ git log --graph
*   commit 980788b7690d8bcf14610072fc072460bee7e9f1
|\  Merge: c49d09e 2929dca
| | Author: reng99 <1837895991@qq.com>
| | Date:   Thu Dec 21 11:14:10 2017 +0800
| | 
| |     fix confict content
| |   
| * commit 2929dca91ef8f493adba7744cdad19656538334f
| | Author: reng99 <1837895991@qq.com>
| | Date:   Thu Dec 21 11:11:49 2017 +0800
| | 
| |     add dev branch content
| |   
* | commit c49d09e33e7098d67b59c845d18e9c6f8a8f4fea
|/  Author: reng99 <1837895991@qq.com>
|   Date:   Thu Dec 21 11:12:50 2017 +0800
|   
|       change master content
|  
* commit b07f0be8280e4e437cccf2a3f8fac6beef03ff41
| Author: reng99 <1837895991@qq.com>
| Date:   Thu Dec 21 11:10:51 2017 +0800
| 
:

上面操作過程是,我先從遠程庫中克隆learngit倉庫到本地,目前的本地learngit的分支只有master分支,然后我在master分支的README.md中添加相關的文字(見代碼),接著把它推送到遠程庫。然后創建并切換dev分支,在README.md文件中添加新內容(見代碼),接著將它提交到GIT倉庫。又切換到master分支,修改README.md到內容(見代碼),提交到GIT倉庫后開始執行merge命令合并dev分支的內容。此時,產生了沖突,這就需要手動將沖突的內容解決,重新commitGIT倉庫,最后你就可以提交到遠程庫了(這步我沒有演示,也就是git push origin master一行命令行的事情)。最后我還使用git log ----graph打印出整個分支合并圖(從下往上看),方便查看。?? 此時退出git log --graph是書寫英文狀態按鍵盤的q鍵。

說這么多,目的只有一個 --> 產生沖突后,需要手動調整??

分支管理策略

先放上一張分支管理策略圖,然后再慢慢講解相關的內容...

tools/git/manager_branch_tactics

在分支管理中,我們不斷的新建分支,開發,合并分支,刪除分支的操作。這里需要注意合并分子的操作,之前我們進行分支的時候是直接將dev開發的分支使用git merge dev進行合并,這樣有個缺點:我們看不出分支信息。因為在默認情況下,合并分支的時候,GIT是使用了Fast Foward的模式,在這種模式下,刪除分支后,會丟掉分支的信息。下面我重新克隆下我遠程learngit倉庫,然后創建并更改dev分支的信息,使用默認的模式進行合并。

$ git branch
* master
$ git branch dev
$ git checkout dev
Switched to branch 'dev'
$ cat README.md
## master branch content
### new master branch content
### dev branch content
### new dev branch content
$ git add .
$ git commit -m "add new dev contentt"
[dev 750e1f1] add new dev content
 1 file changed, 1 insertion(+)
$ git checkout master
Switched to branch 'master'
Your branch is up-to-date with 'origin/master'.
$ git merge dev
Updating 980788b..750e1f1
Fast-forward
 README.md | 1 +
 1 file changed, 1 insertion(+)
$ git log --graph
* commit 750e1f17854872eed4d6cff8315e404079ecb18f
| Author: reng99 <1837895991@qq.com>
| Date:   Fri Dec 22 10:05:36 2017 +0800
| 
|     add new dev content
|    
*   commit 980788b7690d8bcf14610072fc072460bee7e9f1
...

上面的合并就是將master分支上面的HEAD指向dev指針,如下:

# 記錄是從上往下
- before merge
    master
    * (begin)
    |
    |
    *
    \
     \
      *
      |
      |
      *  (end)
     dev
     
- after merge
    master
    * (begin)
    |
    |
    *
    |
    |
    * 
    |
    |
    * (end)

為了保留分支的情況,保證版本演進的清晰,我們就得使用普通模式合并,也就是在Fast Foward的模式基礎上加上--no-ff參數,即git merge --no-ff branchName,不過我們一般加上你合并的相關信息,即git merge --no-ff -m "your msg here" banchName?,F在更改dev分支的內容,再進行合并。

$ git checkout dev
Switched to branch 'dev'
$ cat README.md
## master branch content
### new master branch content
### dev branch content
### new dev branch content
### merge with no-ff
$ git add .
$ git commit -m "add no-ff mode content"
[dev 80b628c] add no-ff mode content
 1 file changed, 2 insertions(+), 1 deletion(-)
$ git checkout master
Switched to branch 'master'
Your branch is ahead of 'origin/master' by 1 commit.
  (use "git push" to publish your local commits)
$ git merge dev --no-ff -m "merge with no-ff" dev
Merge made by the 'recursive' strategy.
 README.md | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)
$ git log --graph
*   commit 98746d93a9b64ea02b8ff1c7f0fa5e915405c0e6
|\  Merge: 750e1f1 80b628c
| | Author: reng99 <1837895991@qq.com>
| | Date:   Fri Dec 22 14:39:32 2017 +0800
| | 
| |     merge with no-ff
| |   
| * commit 80b628c334618711b77da81fa805ffc246a2cf7d
|/  Author: reng99 <1837895991@qq.com>
|   Date:   Fri Dec 22 14:38:17 2017 +0800
|   
|       add no-ff mode content
|  
* commit 750e1f17854872eed4d6cff8315e404079ecb18f
...

使用--no-ff參數的普通模式合并,會執行正常合并,在master主分支上面會生成一個新的節點,如下(我上面的分支管理策略圖里面的合并就是使用了普通的模式):

# 記錄是從上往下
- --no-ff合并
    master
    * (before)
    |
    |
    *
    |\ 
    | \
    |  *dev
    |  |
    |  |
    |  *
    | /
    |/
    * (after) 

我們在開發中,分支管理可以分成master主分支、dev開發分支、feature功能分支、release預發布分支、hotfixes修補bug分支。其中功能分支、預發布分支和修補bug分支可以歸為臨時分支臨時分支在進行分支的合并之后就可以被刪除了。下面就一一講解自己眼中的各種分支。

主分支master

主分支是在你初始化倉庫的時候(git init),自動生成的一個master分支,刪除不了的哦(演示待會給)。主分支是有且僅有一個,也是發布上線的分支,團隊合作的最終代碼都會在master主分支上面體現出來。也許你也注意到了分支管理策略圖里面的主分支會被打上TAG的標簽,這是為了方便到某個時間段對版本的查找,標簽tag的學習總結后面給出。

# 記錄是從上往下
    master
    |
    |
    *(tag 1.0)
    |
    |
    *(tag 1.1)
    |
    |
    *(tag 1.2)

下面代碼演示下不能放刪除master的情況:

$ cd learngit
$ git branch
  dev
* master
$ git branch -D master
error: Cannot delete branch 'master' checked out at '/Users/reng/desktop/learngit'

開發分支develop

在開發的過程中,項目合作者應該保持自己本地有一個開發環境的分支,在進行分支開發之前,需要進行git pull拉取master主分支的最新內容,或者通過其他的方法。在獲取到最新的內容之后才可以進行本地的新功能的開發。在開發完成后將內容merge到主分支之后,不用將dev分支刪除,因為你開發的就是在這里進行,何必刪除后再新建一個開發環境的分支呢。

接著上面的情況,我目前已經擁有了dev開發分支:

$ cd learngit
$ git branch
  dev
* master

功能(特性)分支feature

一個軟件就是一個個功能疊加起來的,在軟件的開發中,我們總不能在主分支開發,將主分支搞亂吧。當然,你可以在dev分支中開發,一般新建功能分支來開發,然后功能開發完再合并到dev分支,之后刪除功能分支。需要的時候就可以將dev開發分支合并到master主分支,這樣就隨時保證dev分支功能的完整性。

下面演示功能分支user開發(隨便寫點內容)的合并(這里也演示了合并到master主分支,跳過了release分支的測試),刪除。

$ git checkout dev
Switched to branch 'dev'
$ git branch user
$ git branch
* dev
  master
  user
$ git checkout user
Switched to branch 'user'
$ cat README.md
## master branch content
### new master branch content
### dev branch content
### new dev branch content
### merge with no-ff
### function user
$ git add .
$ git commit -m "function user was acheive"
[user 26beda3] function user was acheive
 1 file changed, 2 insertions(+), 1 deletion(-)
$ git checkout dev
Switched to branch 'dev'
$ git merge --no-ff -m "merge user feature" user
Merge made by the 'recursive' strategy.
 README.md | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)
$ git checkout master
Switched to branch 'master'
Your branch is ahead of 'origin/master' by 3 commits.
  (use "git push" to publish your local commits)
$ git merge --no-ff -m "merge dev branch" dev
Merge made by the 'recursive' strategy.
 README.md | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)
$ git log --graph
*   commit f15a1e9012635fc21e944ab76c4cd4bbd539f82f
|\  Merge: 98746d9 0ca83c6
| | Author: reng99 <1837895991@qq.com>
| | Date:   Fri Dec 22 16:35:43 2017 +0800
| | 
| |     merge dev branch
| |     
| *   commit 0ca83c654df64724743a966f5f0989477e504cbc
| |\  Merge: 80b628c 26beda3
| | | Author: reng99 <1837895991@qq.com>
| | | Date:   Fri Dec 22 16:33:27 2017 +0800
| | | 
| | |     merge user feature
| | |    
| | * commit 26beda3b8246e047f10ac0461ca11d1a6f132819
| |/  Author: reng99 <1837895991@qq.com>
| |   Date:   Fri Dec 22 16:31:41 2017 +0800
| |   
| |       function user was acheive
| |     
* |   commit 98746d93a9b64ea02b8ff1c7f0fa5e915405c0e6
|\ \  Merge: 750e1f1 80b628c
| |/  Author: reng99 <1837895991@qq.com>
:
$ git branch -D user
Deleted branch user (was 26beda3).
$ git branch
  dev
* master

預發布分支release

在進行一系列的功能的開發和合并后,在滿足迭代目標的時候,就可以打包送測了。這里就需要一個預發布分支release。預發布分支是指在發布正式版本之前( 即合并到master分支之前,可查看上面分支管理策略圖),需要一個有預發布的版本(可以理解為灰度環境)進行測試。

預發布環境是從dev分支上面分出來的,預發布結束之后,必須合并到devmaster分支上面。這里我就不演示了,跟功能分支差不多,就是合并的時候要合并到devmaster上,這時候dev分支和master的同步的代碼,就不需要將dev分支合并到master了。最后將預發布分支刪除掉。

修復bug分支 bug/hotfixes

在寫代碼的過程中,由于種種原因 -> 比如功能考慮不周全,版本上線時間有限,產品突然改需求等,我們寫的代碼就出現一些或大或小的bug或者需要緊急修復。那么我們就可以使用bug分支(其實就是新建一個分支處理bug而已啦,命名隨意起的),然后在這個分支上處理編碼出現的問題。我在分支管理策略圖上面已經展示了一種出現bug的情況 -> 就是在測試發布版本看似沒問題的情況下,將release版本整合到masterdev中,這時候火眼精金發現了遺留的一個bug,然后新建一個bug分支處理,再合并到masterdev中,之后將bug分支移除啦。

在開發的過程中,無論咋樣都是這樣 : 新建bug分支 -> 把分支合并 -> 刪除分支,這里的demo就不演示了,可以參考上面的功能(特性)分支feature。

這里需要注意??的一點,當在開發的過程中,開發到一定的程度,需要停下來需改緊急的bug,那么需要停下手頭的工作需改bug啦。這時候需要將工作現場儲藏(stash功能)起來,等以后回復現場了后接著工作。現在我在原先的gitlearn倉庫中README.md文件文末添加### modify content內容來進行演示。

$ cd desktop
$ cd learngit
$ cat README.md
## master branch content
### new master branch content
### dev branch content
### new dev branch content
### merge with no-ff
$ git status
On branch dev
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")
$ git stash
Saved working directory and index state WIP on dev: 80b628c add no-ff mode content
HEAD is now at 80b628c add no-ff mode content
$ git status
On branch dev
nothing to commit, working tree clean

然后過段時間(這里省略修改的演示),代碼已經修改好合并后,需要回到最新的內容區域進行工作,這就需要還原最新的內容了,demo如下:

$ cd learngit
$ git stash list
stash@{0}: WIP on dev: 80b628c add no-ff mode content
$ git stash pop
On branch dev
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")
Dropped refs/stash@{0} (9e85bcc8435ae38c17db59ddc3cd8401af404827)
$ git stash list

?? git stash不僅可以隱藏工作區的內容,也可以隱藏暫存區的內容。git stash list是查看隱藏的列表。git stash pop是將隱藏的內容恢復并刪除,git stash pop相當于git stash apply && git stash drop,這里的git stash apply是恢復隱藏內容,git stash drop是刪除隱藏內容。

多人協作

簡單談下自己git協作的過程吧。在負責人將搭建好的倉庫上傳到遠程的倉庫后(一般是包含了master默認的分支和dev分支),自己將遠程倉庫克隆到本地,然后在本地的倉庫上新建一個dev分支,將遠程的dev分支重新拉取下git pull origin dev,開發完成后就可以提交自己的代碼到遠程的dev分支了,如果提交之前或者之后需要修改bug或者添加新的需求的話,需要新建一個相關的分支并完成開發,將他們合并到本地dev分支后上傳到遠程dev分支。如果新建的遠程倉庫中只有master分支,我是這樣處理的:依然要在本地新建一個dev分支,然后在完成特定版本的開發后,將分支合并到本地master分支然后再推送到遠程master分支,本地的dev分支保留哦。我自己比較偏向于第一種情況。

標簽管理

發布一個版本前,為了唯一確定時刻的版本,我們通常在版本庫中打一個標簽(tag),方便在發布版本以后,可以在某個時刻將某個歷史的版本提取出來(因為標簽tag也是版本庫的一個快照)。

創建標簽

創建標簽是默認在你切換的分支最新提交處創建的。我這里在本地桌面的learngit倉庫master分支上打一個v1.0標簽

$ cd desktop/learngit
$ git branch
* dev
  master
$ git checkout master
Switched to branch 'master'
Your branch is up-to-date with 'origin/master'.
$ git tag
$ git tag v1.0
$ git tag
v1.0

當然,你可以在非新commit的地方進行標簽。這就需要你查找到需要打標簽處的commit的id,然后執行git tag tagName commitId。這里我隨意找master分支中的commit id進行標簽v0.9的標簽創建。

$ git log --pretty=oneline --abbrev-commit
f15a1e9 merge dev branch
0ca83c6 merge user feature
26beda3 function user was acheive
98746d9 merge with no-ff
...

現在在commit id為 98746d9處打標簽。

$ git tag v0.9 98746d9
$ git tag
v0.9
v1.0

操作標簽

在上面創建標簽,我們已經有了標簽v0.9 v1.0。有時候我們標簽打錯了,需要進行刪除,那么就得更改啦,運用git tag -d tagName

$ git tag -d v0.9
Deleted tag 'v0.9' (was 98746d9)
$ git tag
v1.0
$ git tag v0.8 80b628c -m "version 0.8"
$ git tag
v0.8
v1.0
$ git show v0.8
$ git show v0.8
tag v0.8
Tagger: reng99 <1837895991@qq.com>
tag v0.8
Tagger: reng99 <1837895991@qq.com>
Date:   Wed Dec 27 16:07:46 2017 +0800

version 0.8

在上面的演示中,我刪除了v0.9,然后在創建v0.8的時候追加了打標簽的信息,之后使用git show tagName查看簽名信息。

我們還可以進行分支切換標簽,類似于分支的切換,我這里打的兩個標簽的內容是不同的,我可以通過觀察內容的改表來得知時候成功切換標簽了。

$ git tag
v0.8
v1.0
$ git checkout v1.0
HEAD is now at f15a1e9... merge dev branch
$ cat README.md
## master branch content
### new master branch content
### dev branch content
### new dev branch content
### merge with no-ff
### function user
$ git checkout v0.8
Previous HEAD position was f15a1e9... merge dev branch
HEAD is now at 80b628c... add no-ff mode content
$ cat README.md
## master branch content
### new master branch content
### dev branch content
### new dev branch content
### merge with no-ff

在確認好標簽后,就可以像遠程推送標簽了,我這里推送v1.0。

$ git push origin v1.0
Total 0 (delta 0), reused 0 (delta 0)
To https://github.com/reng99/learngit.git
 * [new tag]         v1.0 -> v1.0

上面是使用git push origin tagName推送特定的tag到遠程庫,但是我們能不能推送全部的tag呢?答案是肯定的,看者可以通過git push origin --tags進行推送。有時候,我們推送了tag標簽到遠程庫中了,現在想刪除掉怎么辦?這個就略微麻煩點,我們不能像上面提到的刪除本地庫的標簽那樣,通過git tag -d tagName那樣,而是通過git push origin :refs/tags/tagName,這里不演示,如果看者感興趣可以自己來把弄一下哦。

參考內容

廖雪峰官方網站--Git教程

易百教程--Git教程

git官網

分支管理模型圖

Git分支管理策略 - 阮一峰的網絡日志

原文鏈接

git的學習匯總--原創

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • 1. 安裝 Github 查看是否安裝git: $ git config --global user.name "...
    Albert_Sun閱讀 13,721評論 9 163
  • 1.git的安裝 1.1 在Windows上安裝Git msysgit是Windows版的Git,從https:/...
    落魂灬閱讀 12,713評論 4 54
  • Git是目前最流行的版本管理系統,也是最先進的分布式版本控制系統(distributed version cont...
    pro648閱讀 5,770評論 1 17
  • 選擇遺忘,我只是為了更好的活下去。 那種疼,你不懂,你也不在乎。 就像我們是兩個世界的人,僅僅只是過客。 你的不在...
    千層云林閱讀 545評論 4 17
  • 前言 永澄老師在StepAs模型學習課上布置了第一個作業 選定一個任務,然后產生成果,并書寫下成果產生方式。 擔心...
    想飛的小粉豬閱讀 266評論 0 0