Git相關知識點

gamebus發表於2021-09-09

本文主要介紹了git使用SSH金鑰、入門知識、分支管理以及常用命令,掌握了一下內容,你就可以輕鬆的在工作送使用Git了。

SSH金鑰

git使用https協議,每次pull, push都要輸入密碼,相當的煩。
使用git協議,然後使用ssh金鑰。這樣可以省去每次都輸密碼。

需要三個步驟:

一、本地生成金鑰對;

二、設定github上的公鑰;

三、修改git的remote url為git協議。

1、生成金鑰

大多數 Git 伺服器都會選擇使用 SSH 公鑰來進行授權。系統中的每個使用者都必須提供一個公鑰用於授權,沒有的話就要生成一個。生成公鑰的過程在所有作業系統上都差不多。首先先確認一下是否已經有一個公鑰了。SSH 公鑰預設儲存在賬戶的主目錄下的 ~/.ssh 目錄。進去看看:

$ cd ~/.ssh 
$ ls
authorized_keys2  id_dsa       known_hosts config            id_dsa.pub

關鍵是看有沒有用 something 和 something.pub 來命名的一對檔案,這個 something 通常就是 id_dsa 或 id_rsa。有 .pub 字尾的檔案就是公鑰,另一個檔案則是金鑰。假如沒有這些檔案,或者乾脆連 .ssh 目錄都沒有,可以用 ssh-keygen 來建立。該程式在 Linux/Mac 系統上由 SSH 包提供,而在 Windows 上則包含在 MSysGit 包裡:

$ ssh-keygen -t rsa -C "your_email@youremail.com"

# Creates a new ssh key using the provided email # Generating public/private rsa key pair. 

# Enter file in which to save the key (/home/you/.ssh/id_rsa):

直接Enter就行。然後,會提示你輸入密碼,如下(建議輸一個,安全一點,當然不輸也行):

Enter passphrase (empty for no passphrase): [Type a passphrase] 
# Enter same passphrase again: [Type passphrase again]

完了之後,大概是這樣。

Your identification has been saved in /home/you/.ssh/id_rsa. 
# Your public key has been saved in /home/you/.ssh/id_rsa.pub. 
# The key fingerprint is: # 01:0f:f4:3b:ca:85:d6:17:a1:7d:f0:68:9d:f0:a2:db your_email@youremail.com

這樣。你本地生成金鑰對的工作就做好了。

2、新增公鑰到你的github帳戶

2-1、檢視你生成的公鑰:大概如下:

$ cat ~/.ssh/id_rsa.pub  

ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAklOUpkDHrfHY17SbrmTIpNLTGK9Tjom/BWDSU GPl+nafzlHDTYW7hdI4yZ5ew18JH4JW9jbhUFrviQzM7xlE
LEVf4h9lFX5QVkbPppSwg0cda3 Pbv7kOdJ/MTyBlWXFCR+HAo3FXRitBqxiX1nKhXpHAZsMciLq8V6RjsNAQwdsdMFvSlVK/7XA t3FaoJoAsncM1Q9x5+3V
0Ww68/eIFmb1zuUFljQJKprrX88XypNDvjYNby6vw/Pb0rwert/En mZ+AW4OZPnTPI89ZPmVMLuayrD2cE86Z/il8b+gw3r3+1nKatmIkjn2so1d01QraTlMqVSsbx NrRFi9wrf+M7Q== schacon@agadorlaptop.local

2-2、登陸你的github帳戶。然後 Account Settings -> 左欄點選 SSH Keys -> 點選 Add SSH key

2-3、然後你複製上面的公鑰內容,貼上進“Key”文字域內。 title域,你隨便填一個都行。

2-4、完了,點選 Add key。

這樣,就OK了。然後,驗證下這個key是不是正常工作。

$ ssh -T git@github.com
# Attempts to ssh to github

如果,看到:

Hi username! You've successfully authenticated, but GitHub does not # provide shell access.

就表示你的設定已經成功了。

3、修改你本地的ssh remote url. 不用https協議,改用git 協議

確保:

  • 你已經init了一個空倉庫。

  • 你已經把遠端git的url新增到了本地git倉庫的配置檔案

================================================

可以用git remote -v 檢視你當前的remote url

$ git remote -v
origin  (fetch)
origin  (push)

可以看到是使用https協議進行訪問的。

你可以使用瀏覽器登陸你的github,在上面可以看到你的ssh協議相應的url。類似如下:

git@github.com:someaccount/someproject.git

這時,你可以使用 git remote set-url 來調整你的url。

git remote set-url origin git@github.com:someaccount/someproject.git

完了之後,你便可以再用 git remote -v 檢視一下。

$ git remote -v
origin  (fetch)
origin  (push)

OK。

至此,你就可以省去輸入密碼的麻煩,也可以很安全的進行push,pull,fetch,checkout等操作了。

你可以用git fetch, git pull , git push。

「注意:」

第一次使用git push之前,需要對git push進行配置:

1.simple方式:

git config --global push.default.simple

2.matching方式:

git config --global push.default.matching

matching means git push will push all your local branches to the ones with the same name on the remote. This makes it easy to accidentally push a branch you didn't intend to.

matching與simple方式的push的區別是:matching會把你所有本地的分支push到遠端倉庫中對應匹配的分支。

simple means git push will push only the current branch to the one that git pull would pull from, and also checks that their names match. This is a more intuitive behavior, which is why the default is getting changed to this.

simple方式,只會push你已經從遠端倉庫pull過的分支,意思是你曾經pull了分支dev,那麼當你使用預設git push時,當前分支為dev,遠端分支dev就會收到你的commit。

3.或者使用git push [遠端倉庫] [本地分支]

入門知識

Git簡介

Git是目前世界上最先進的分散式版本控制系統。

  1. 版本控制

    典型代表Word檔案的編輯,你的資料夾中是不是有這樣的情況:

    word20160301.doc
    word備份的.doc
    word(小王).doc
    word-03.doc
    word.doc

    而某一天,你可能需要以前修改過的版本(因為,經常會遇到這種抽風的上司或者客戶)

    而由版本控制給你帶來的是:

    版本    使用者    說明    日期
    1   張三    刪除了軟體服務條款5    7/12 10:38
    2    張三    增加了License人數限制    7/12 18:09
    3    李四    財務部門調整了合同金額    7/13 9:51
    4    張三    延長了免費升級週期    7/14 15:17

    而且,你想退回到哪裡,就可以退回到哪裡!

    記住第一個關鍵詞:(無盡的)後悔藥

  2. 分散式 VS 集中式

    集中式,典型的代表就是SVN,版本庫是集中存放在中央伺服器的,而幹活的時候,用的都是自己的電腦,所以要先從中央伺服器取得最新的版本,然後開始幹活,幹完活了,再把自己的活推送給中央伺服器。

    分散式,分散式版本控制系統根本沒有“中央伺服器”,每個人的電腦上都是一個完整的版本庫,分散式版本控制系統的安全性要高很多,因為每個人電腦裡都有完整的版本庫,某一個人的電腦壞掉了不要緊,隨便從其他人那裡複製一個就可以了。而集中式版本控制系統的中央伺服器要是出了問題,所有人都沒法幹活了。

    Git不單是不必聯網這麼簡單,Git更強大的是分支管理。後面講到~~~~~

    關於更多SVN&Git的區別可以參見:

    記住第二個關鍵詞:分散式

Git環境搭建

安裝Git

  • 在Linux(Debian)上安裝Git:
    apt-get install git

  • Mac OS X上安裝Git:
    第一種方法是安裝homebrew,然後透過homebrew安裝Git,具體方法請參考homebrew的文件:。
    第二種方法更簡單,也是推薦的方法,就是直接從AppStore安裝Xcode,Xcode整合了Git,不過預設沒有安裝,你需要執行Xcode,選擇選單“Xcode”->“Preferences”,在彈出視窗中找到“Downloads”,選擇“Command Line Tools”,點“Install”就可以完成安裝了。

  • 在Windows上安裝Git
    從這裡下載,雙擊安裝
    安裝完成後,可以在右鍵選單/開始選單中找到“Git”->“Git Bash”,蹦出一個類似命令列視窗的東西,就說明Git安裝成功!

全域性變數設定

就像Java需要設定Path一樣,Git需要設定一些全域性變數。

“Git”->“Git Bash”

$ git config --global user.name "Your Name"
$ git config --global user.email "email@example.com"

設定使用者與Email,相當於自報家門,讓版本庫有一個記錄。注意:git config命令的--global是全域性設定的意思。

任何一個命令或者參考:git [命令] --help來檢視幫助,或者登陸官方來學習命令

參考資料:

建立版本庫

  1. windows下,需要建立的版本庫的地方,右鍵git bash->

    $ git init

    瞬間Git就把倉庫建好了,而且告訴你是一個空的倉庫(empty Git repository),細心的讀者可以發現當前目錄下多了一個.git的目錄,這個目錄是Git來跟蹤管理版本庫的,沒事千萬不要手動修改這個目錄裡面的檔案,不然改亂了,就把Git倉庫給破壞了。

    PS:如果你沒有看到.git目錄,那是因為這個目錄預設是隱藏的

  2. Linux中:

如果,需要在learngit目錄下建立一個Git倉庫,可以如下操作

$ mkdir learngit
$ cd learngit
$ git init

你也可以這樣:

$ git init learngit

試一試吧!

基本操作

Git工作區和暫存區:

我們看到目錄為工作區(/learngit);需要進行提交到版本庫的檔案放在暫存區(看不到,需要使用git status來檢視)。

git status命令:可以讓我們時刻掌握倉庫當前的狀態。

git diff命令:讓我們檢視檔案與版本庫中的區別。

獲取遠端倉庫程式碼(前提是init之後)
  1. 克隆倉庫:

    $ git clone [user@]example.com:path/to/repo.git/
  2. 或者新增遠端倉庫:

    使用git remote add命令,新增一個遠端倉庫的連結,命令格式:git remote add [遠端倉庫別名] [遠端倉庫地址]

    $ git remote add origin git@github.com:michaelliao/learngit.git
  3. 拉取程式碼。

    如果已經被git管理的專案,則使用git pullgit fetch來管理程式碼的拉取與更新:

    使用git pull拉取遠端程式碼的HEAD頭標記,即最新的程式碼。

    命令格式:$ git pull <遠端主機名> <遠端分支名>:<本地分支名>

    $ git pull
提交程式碼

把所有的檔案更改提交到暫存區:

$ git add -a

為所有暫存區的程式碼寫入日誌並提交到本地倉庫:

$ git commit -m "(something)"

把所有本地倉庫的提交,更新到遠端倉庫:

$ git push

Git時光機

  1. git log命令:檢視每次修改的日誌檔案。

    ,記得幾點:git log是順著當前分支往前去查詢提交記錄,而git reflog並不像git log去遍歷提交歷史,它都不是倉庫的一部分,它不包含推送、更新或者克隆,而是作為本地提交記錄的清單。簡單理解:本地後悔藥。

  2. git reset命令:回退命令。

    首先,Git必須知道當前版本是哪個版本,在Git中,用HEAD表示當前版本,上一個版本就是HEAD^,上上一個版本就是HEAD^^,當然往上100個版本寫100個^比較容易數不過來,所以寫成HEAD~100

    $ git reset --hard HEAD^
    HEAD is now at ea34578 add distributed

    回退add命令提交到快取區的檔案,並不會把檔案恢復快取區,需要區別(3)git checkout命令:

    $ git reset HEAD
  3. git checkout --命令:丟棄快取區檔案的修改,把檔案恢復到git add之前的狀態。

  4. git diff HEAD --命令可以檢視工作區和版本庫裡面最新版本的區別

  5. git rm刪除檔案。

標籤管理

釋出一個版本時,我們通常先在版本庫中打一個標籤,這樣,就唯一確定了打標籤時刻的版本。將來無論什麼時候,取某個標籤的版本,就是把那個打標籤的時刻的歷史版本取出來。所以,標籤也是版本庫的一個快照。

Git的標籤雖然是版本庫的快照,但其實它就是指向某個commit的指標(跟分支很像對不對?但是分支可以移動,標籤不能移動),所以,建立和刪除標籤都是瞬間完成的。

  1. 建立標籤(快照)

    在Git中打標籤非常簡單,首先,切換到需要打標籤的分支上:

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

    然後,敲命令git tag就可以打一個新標籤:

    $ git tag v1.0

    可以用命令git tag檢視所有標籤:

    $ git tag
    v1.0

    預設標籤是打在最新提交的commit上的。有時候,如果忘了打標籤,比如,現在已經是週五了,但應該在週一打的標籤沒有打,怎麼辦?

    方法是找到歷史提交的commit id,然後打上就可以了:

    $ git log --pretty=oneline --abbrev-commit
    6a5819e merged bug fix 101
    cc17032 fix bug 101
    7825a50 merge with no-ff
    6224937 add merge
    59bc1cb conflict fixed
    400b400 & simple
    75a857c AND simple
    fec145a branch test
    d17efd8 remove test.txt

    比方說要對add merge這次提交打標籤,它對應的commit id是6224937,敲入命令:

    $ git tag v0.9 6224937

    再用命令git tag檢視標籤:

    $ git tag
    v0.9
    v1.0

    注意,標籤不是按時間順序列出,而是按字母排序的。

    可以用git show檢視標籤資訊:

    $ git show v0.9
    commit 622493706ab447b6bb37e4e2a2f276a20fed2ab4
    Author: Brian 
    Date:   Thu Aug 22 11:22:08 2013 +0800
        add merge
    ...

可以看到,v0.9確實打在add merge這次提交上。

還可以建立帶有說明的標籤,用-a指定標籤名,-m指定說明文字:

   $ git tag -a v0.1 -m "version 0.1 released" 3628164

用命令git show可以看到說明文字:

   $ git show v0.1
   tag v0.1
   Tagger: Brian 
   Date:   Mon Aug 26 07:28:11 2013 +0800
   
   version 0.1 released
   
   commit 3628164fb26d48395383f8f31179f24e0882e1e0
   Author: Brian 
   Date:   Tue Aug 20 15:11:49 2013 +0800
   
   append GPL

還可以透過-s用私鑰簽名一個標籤:

   $ git tag -s v0.2 -m "signed version 0.2 released" fec145a

參考資料:

  1. 標籤操作(刪除,推送)

    命令git push origin可以推送一個本地標籤;

    命令git push origin --tags可以推送全部未推送過的本地標籤;

    命令git tag -d可以刪除一個本地標籤;

    命令git push origin :refs/tags/可以刪除一個遠端標籤。

    如果標籤已經推送到遠端,要刪除遠端標籤就麻煩一點,先從本地刪除:

    $ git tag -d v0.9
    Deleted tag 'v0.9' (was 6224937)

    然後,從遠端刪除。刪除命令也是push,但是格式如下:

    $ git push origin :refs/tags/v0.9
    To git@github.com:michaelliao/learngit.git
     - [deleted]         v0.9

使用.gitignore忽略檔案

有些時候,你必須把某些檔案放到Git工作目錄中,但又不能提交它們,比如儲存了資料庫密碼的配置檔案啦,等等,每次git status都會顯示Untracked files …,有強迫症的童鞋心裡肯定不爽。

好在Git考慮到了大家的感受,這個問題解決起來也很簡單,在Git工作區的根目錄下建立一個特殊的.gitignore檔案,然後把要忽略的檔名填進去,Git就會自動忽略這些檔案。

不需要從頭寫.gitignore檔案,GitHub已經為我們準備了各種配置檔案,只需要組合一下就可以使用了。所有配置檔案可以直接線上瀏覽:

忽略檔案的原則是:

  • 忽略作業系統自動生成的檔案,比如縮圖等;

  • 忽略編譯生成的中間檔案、可執行檔案等,也就是如果一個檔案是透過另一個檔案自動生成的,那自動生成的檔案就沒必要放進版本庫,比如Java編譯產生的.class檔案;

  • 忽略你自己的帶有敏感資訊的配置檔案,比如存放口令的配置檔案。

舉個例子:

假設你在Windows下進行Python開發,Windows會自動在有圖片的目錄下生成隱藏的縮圖檔案,如果有自定義目錄,目錄下就會有Desktop.ini檔案,因此你需要忽略Windows自動生成的垃圾檔案:

# Windows:
Thumbs.db
ehthumbs.db
Desktop.ini

然後,繼續忽略Python編譯產生的.pyc.pyodist等檔案或目錄:

# Python:
*.py[cod]
*.so
*.egg
*.egg-info
dist
build

加上你自己定義的檔案,最終得到一個完整的.gitignore檔案,內容如下:

# Windows:
Thumbs.db
ehthumbs.db
Desktop.ini

# Python:
*.py[cod]
*.so
*.egg
*.egg-info
dist
build

# My configurations:
db.ini
deploy_key_rsa

最後一步就是把.gitignore也提交到Git,就完成了!當然檢驗.gitignore的標準是git status命令是不是說working directory clean。

使用Windows的童鞋注意了,如果你在資源管理器裡新建一個.gitignore檔案,它會非常弱智地提示你必須輸入檔名,但是在文字編輯器裡“儲存”或者“另存為”就可以把檔案儲存為.gitignore了。

或者可以使用以下方法,在git bash中輸入以下命令:

$ touch .gitignore
$ vi .gitignore

Git忽略規則及.gitignore規則不生效的解決辦法:

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

PS:注意–cached後面有一個”.”,add後面也有一個“.”

完成上述操作後,再重新修改.gitnore檔案,並git add .新增檔案到快取區

配置命令別名

有沒有經常敲錯命令?比如git status?status這個單詞真心不好記。

如果敲git st就表示git status那就簡單多了,當然這種偷懶的辦法我們是極力贊成的。

我們只需要敲一行命令,告訴Git,以後st就表示status

$ git config --global alias.st status

好了,現在敲git st看看效果。

當然還有別的命令可以簡寫,很多人都用co表示checkoutci表示commitbr表示branch

$ git config --global alias.co checkout
$ git config --global alias.ci commit
$ git config --global alias.br branch

以後提交就可以簡寫成:

$ git ci -m "bala bala bala..."

--global引數是全域性引數,也就是這些命令在這臺電腦的所有Git倉庫下都有用。

在撤銷修改一節中,我們知道,命令git reset HEAD file可以把暫存區的修改撤銷掉(unstage),重新放回工作區。既然是一個unstage操作,就可以配置一個unstage別名:

$ git config --global alias.unstage 'reset HEAD'

當你敲入命令:

$ git unstage test.py

實際上Git執行的是:

$ git reset HEAD test.py

配置一個git last,讓其顯示最後一次提交資訊:

$ git config --global alias.last 'log -1'

這樣,用git last就能顯示最近一次的提交:

$ git last
commit adca45d317e6d8a4b23f9811c3d7b7f0f180bfe2
Merge: bd6ae48 291bea8
Author: Michael Liao 
Date:   Thu Aug 22 22:49:22 2013 +0800

merge & fix hello.py

甚至還有人喪心病狂地把lg配置成了:

git config --global alias.lg "log --color --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' --abbrev-commit"

來看看git lg的效果:

為什麼不早點告訴我?別激動,我們不是為了多記幾個英文單詞嘛!

配置檔案

配置Git的時候,加上--global是針對當前使用者起作用的,如果不加,那隻針對當前的倉庫起作用。

配置檔案放哪了?每個倉庫的Git配置檔案都放在.git/config檔案中:

$ cat .git/config 
[core]
    repositoryformatversion = 0
    filemode = true
    bare = false
    logallrefupdates = true
    ignorecase = true
    precomposeunicode = true
[remote "origin"]
    url = git@github.com:michaelliao/learngit.git
    fetch = +refs/heads/*:refs/remotes/origin/*
[branch "master"]
    remote = origin
    merge = refs/heads/master
[alias]
    last = log -1

別名就在[alias]後面,要刪除別名,直接把對應的行刪掉即可。

而當前使用者的Git配置檔案放在使用者主目錄下的一個隱藏檔案.gitconfig中:

$ cat .gitconfig
[alias]
    co = checkout
    ci = commit
    br = branch
    st = status
[user]
    name = Your Name
    email = your@email.com

Git恢復流程

當中心倉庫由於不可抗拒因素而垮了之後:

專案Git恢復流程:

方法一:恢復指定分支

1.註冊賬號→輸入SSH keys→新建專案。

2.在原專案資料夾下,使用git remote -v命令檢視

$ git remote -v
origin  git@192.168.1.222:kanlidy/HelloGit.git (fetch)
origin  git@192.168.1.222:kanlidy/HelloGit.git (push)

使用git remote remove origin刪除原有倉庫地址。

3.使用新的倉庫地址:

git remote add origin [ssh倉庫地址]

如:

git remote add origin ssh://git@github.com/kanlidy/HelloGit.git

4.新增檔案,並Commit提交,最後push上遠端指定分支

git add .

git commit -m "add my repo"

#這條命令會把當前分支,推送到遠端的master分支
git push origin master 

#如果需要把dev分支,推送到遠端的dev分支
git push origin dev:dev

方法二:恢復專案所有分支:

git remote remove origin

git remote add origin [新的SSH倉庫地址]

git push --mirror ssh://git@github.com/kanlidy/LearnPython.git

本地多個SSH金鑰檔案

有的時候,不僅github使用ssh key,工作專案或者其他雲平臺可能也需要使用ssh key來認證,如果每次都覆蓋了原來的id_rsa檔案,那麼之前的認證就會失效。這個問題我們可以透過在~/.ssh目錄下增加config檔案來解決。

  1. 第一步依然是配置git使用者名稱和郵箱

    git config user.name "使用者名稱"
    git config user.email "郵箱"
  2. 生成ssh key時同時指定儲存的檔名

    ssh-keygen -t rsa -f ~/.ssh/id_rsa.company -C "email"

    上面的id_rsa.company就是我們指定的檔名,這時~/.ssh目錄下會多出id_rsa.companyid_rsa.company.pub兩個檔案,id_rsa.company.pub裡儲存的就是我們要使用的key。

  3. 新增並配置config檔案

    新增config檔案

    如果config檔案不存在,先新增;存在則直接修改

    touch ~/.ssh/config

    在config檔案裡新增如下內容(User表示你的使用者名稱)

    Host 域名或者IP
        IdentityFile ~/.ssh/id_rsa.company
        User test

    如:

    Host 192.168.1.222
    IdentityFile ~/.ssh/id_rsa.company
    User kanlidy
  4. 上傳key到雲平臺後臺(省略)

  5. 測試ssh key是否配置成功

    ssh -T git@域名或者IP

    如:

    ssh -T git@192.168.1.222 -p 8082

    成功的話會顯示:

    Welcome to GitLab, kanlidy!

    至此,本地便成功配置多個ssh key。日後如需新增,則安裝上述配置生成key,並修改config檔案即可。

Git分支管理

還記得《星際穿越》中的平行空間嗎?兩個獨立的空間互不干擾,當你正在電腦前努力學習Git的時候,另一個你正在另一個平行宇宙裡努力學習SVN。在某一個時間點,兩個平行的時空合併了,結果,你既學會了Git又學會了SVN!

**分支在實際中有什麼用呢?**假設你準備開發一個新功能,但是需要兩週才能完成,第一週你寫了50%的程式碼,如果立刻提交,由於程式碼還沒寫完,不完整的程式碼庫會導致別人不能幹活了。如果等程式碼全部寫完再一次提交,又存在丟失每天進度的巨大風險。

**分支的獨立性:**現在有了分支,就不用怕了。你建立了一個屬於你自己的分支,別人看不到,還繼續在原來的分支上正常工作,而你在自己的分支上幹活,想提交就提交,直到開發完畢後,再一次性合併到原來的分支上,這樣,既安全,又不影響別人工作。

**git分支的高效:**其他版本控制系統如SVN等都有分支管理,但是用過之後你會發現,這些版本控制系統建立和切換分支比蝸牛還慢,簡直讓人無法忍受,結果分支功能成了擺設,大家都不去用。

但Git的分支是與眾不同的,無論建立、切換和刪除分支,Git在1秒鐘之內就能完成!無論你的版本庫是1個檔案還是1萬個檔案。

理解HEAD頭指標

一開始的時候,HEAD頭指標指向的是主分支,即master分支。而HEAD指向的是當前分支,master指向的是提交。

如果,在master分支上新建了一個分支dev,此時HEAD指向了dev,Git建立分支的過程很快,因為除了增加一個dev指標,改改HEAD的指向,工作區的檔案都沒有任何變化!

不過,從現在開始,對工作區的修改和提交就是針對dev分支了,比如新提交一次後,dev指標往前移動一步,而master指標不變。

建立dev分支

建立分支使用git branch命令,命令格式:git branch [分支別名]

$ git branch dev

可以使用$ git branch來檢視所有本地分支,$ git branch -a檢視所有分支(包括遠端分支)。

使用git checkout [分支名]切換到對應的分支,如:

$ git checkout dev

此時,HEAD頭指標會指向dev,如果在dev上提交,dev指標會往前移,而其他分支不變。(master分支及指標不變)

當使用git checkout master時,HEAD頭指標會重新指向master,此時再提交,master指標會往前移。

這個過程,需要自己親身的試驗才能體會到它們的作用和變化。

$gitk

使用Git自帶的圖形介面,可以很好的來管理分支。

衝突解決

衝突產生:當兩個分支中修改的相同的檔案並提交(add->commit),合併(merge)這兩個分支的時候,會產生衝突。

如下例:

$ git checkout -b feature1
  1. 在新的feature1分支下修改了readme.txt:

    vi readme.txt
    //修改,新增Creating a new branch is quick AND simple.
    $ git add readme.txt 
    $ git commit -m "AND simple"
  2. 切換到master分支:

    $ git checkout master
    
    vi readme.txt
    //在`master`分支上把readme.txt檔案的最後一行改為:Creating a new branch is quick & simple
    $ git add readme.txt 
    $ git commit -m "& simple"
  3. 試圖合併masterfeature1

    $ git merge feature1
    Auto-merging readme.txt
    CONFLICT (content): Merge conflict in readme.txt
    Automatic merge failed; fix conflicts and then commit the result.

    (1)使用:$ git status來檢視衝突檔案:

    $ git status
    # On branch master
    # Your branch is ahead of 'origin/master' by 2 commits.
    #
    # Unmerged paths:
    #   (use "git add/rm ..." as appropriate to mark resolution)
    #
    #       both modified:      readme.txt
    #
    no changes added to commit (use "git add" and/or "git commit -a")

    (2)直接檢視readme.txt檔案內容:

    Git is a distributed version control system.
    Git is free software distributed under the GPL.
    Git has a mutable index called stage.
    Git tracks changes of files.
    <<<<<<< HEAD
    Creating a new branch is quick & simple.
    =======
    Creating a new branch is quick AND simple.
    >>>>>>> feature1

    Git用<<<<<<<=======>>>>>>>標記出不同分支的內容,我們修改如下後儲存:

    Creating a new branch is quick and simple.
  4. 再提交:

    $ git add readme.txt 
    $ git commit -m "conflict fixed"
    [master 59bc1cb] conflict fixed

    PS: 用帶引數的git log也可以看到分支的合併情況:

    $ git log --graph --pretty=oneline --abbrev-commit
    *   59bc1cb conflict fixed
    |
    | * 75a857c AND simple
    * | 400b400 & simple
    |/
    * fec145a branch test
    ...
  5. 最後,刪除feature1分支:

    $ git branch -d feature1
    Deleted branch feature1 (was 75a857c).

分支管理策略

通常,合併分支時,如果可能,Git會用Fast forward模式,但這種模式下,刪除分支後,會丟掉分支資訊。

如果要強制禁用Fast forward模式,Git就會在merge時生成一個新的commit,這樣,從分支歷史上就可以看出分支資訊。

下面我們實戰一下--no-ff方式的git merge

首先,仍然建立並切換dev分支:

$ git checkout -b dev
Switched to a new branch 'dev'

修改readme.txt檔案,並提交一個新的commit

$ git add readme.txt 
$ git commit -m "add merge"
[dev 6224937] add merge
 1 file changed, 1 insertion(+)

現在,我們切換回master

$ git checkout master
Switched to branch 'master

準備合併dev分支,請注意--no-ff引數,表示禁用Fast forward

$ git merge --no-ff -m "merge with no-ff" dev
Merge made by the 'recursive' strategy.
 readme.txt |    1 +
 1 file changed, 1 insertion(+)

分支策略

在實際開發中,我們應該按照幾個基本原則進行分支管理:

首先,master分支應該是非常穩定的,也就是僅用來發布新版本,平時不能在上面幹活;

那在哪幹活呢?幹活都在dev分支上,也就是說,dev分支是不穩定的,到某個時候,比如1.0版本釋出時,再把dev分支合併到master上,在master分支釋出1.0版本;

你和你的小夥伴們每個人都在dev分支上幹活,每個人都有自己的分支,時不時地往dev分支上合併就可以了。

所以,團隊合作的分支看起來就像這樣:

Bug分支

軟體開發中,bug就像家常便飯一樣。有了bug就需要修復,在Git中,由於分支是如此的強大,所以,每個bug都可以透過一個新的臨時分支來修復,修復後,合併分支,然後將臨時分支刪除。

當你接到一個修復一個代號101的bug的任務時,很自然地,你想建立一個分支issue-101來修復它,但是,等等,當前正在dev上進行的工作還沒有提交:

$ git status
# On branch dev
# Changes to be committed:
#   (use "git reset HEAD ..." to unstage)
#
#       new file:   hello.py
#
# Changes not staged for commit:
#   (use "git add ..." to update what will be committed)
#   (use "git checkout -- ..." to discard changes in working directory)
#
#       modified:   readme.txt
#

並不是你不想提交,而是工作只進行到一半,還沒法提交,預計完成還需1天時間。但是,必須在兩個小時內修復該bug,怎麼辦?

幸好,Git還提供了一個stash功能,可以把當前工作現場“儲藏”起來,等以後恢復現場後繼續工作:

$ git stash
Saved working directory and index state WIP on dev: 6224937 add merge
HEAD is now at 6224937 add merge

現在,用git status檢視工作區,就是乾淨的(除非有沒有被Git管理的檔案),因此可以放心地建立分支來修復bug。

首先確定要在哪個分支上修復bug,假定需要在master分支上修復,就從master建立臨時分支:

$ git checkout master
$ git checkout -b issue-101

現在修復bug,需要把“Git is free software …”改為“Git is a free software …”,然後提交:

$ git add readme.txt 
$ git commit -m "fix bug 101"

修復完成後,切換到master分支,並完成合並,最後刪除issue-101分支:

$ git checkout master
$ git merge --no-ff -m "merged bug fix 101" issue-101
$ git branch -d issue-101

太棒了,原計劃兩個小時的bug修復只花了5分鐘!現在,是時候接著回到dev分支幹活了!

$ git checkout dev
Switched to branch 'dev'
$ git status
# On branch dev
nothing to commit (working directory clean)

工作區是乾淨的,剛才的工作現場存到哪去了?用git stash list命令看看:

$ git stash list
stash@{0}: WIP on dev: 6224937 add merge

工作現場還在,Git把stash內容存在某個地方了,但是需要恢復一下,有兩個辦法:

**一種方式:**用git stash apply恢復,但是恢復後,stash內容並不刪除,你需要用git stash drop來刪除;

**另一種方式:**是用git stash pop,恢復的同時把stash內容也刪了:

$ git stash pop
# On branch dev
# Changes to be committed:
#   (use "git reset HEAD ..." to unstage)
#
#       new file:   hello.py
#
# Changes not staged for commit:
#   (use "git add ..." to update what will be committed)
#   (use "git checkout -- ..." to discard changes in working directory)
#
#       modified:   readme.txt
#
Dropped refs/stash@{0} (f624f8e5f082f2df2bed8a4e09c12fd2943bdd40)

再用git stash list檢視,就看不到任何stash內容了:

$ git stash list

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

$ git stash apply stash@{0}

刪除分支

軟體開發中,總有無窮無盡的新的功能要不斷新增進來。

新增一個新功能時,你肯定不希望因為一些實驗性質的程式碼,把主分支搞亂了,所以,每新增一個新功能,最好新建一個feature分支,在上面開發,完成後,合併,最後,刪除該feature分支。

還記得嗎?

建立新的分支:git checkout -b feature-new

工作提交:git add --agit commit -m "something..."

回到dev開發分支:git checkout dev

合併分支:git merge --no-ff feature-new

一切順利的話,feature分支和bug分支是類似的,合併,然後刪除。

但是,就在此時,接到上級命令,因經費不足,新功能必須取消!雖然白乾了,但是這個分支還是必須就地銷燬:

(1)如果沒有合併之前,可以簡單的使用git branch -d [分支名]來刪除分支(使用-D命令,強制刪除分支)

(2)如果已經合併,除了上面的需要刪除以外,還需要使用前面講到的git reset --hard HEAD^來退回到上一個版本。

PS:分支的刪除,不會影響到其他分支上已經合併的分支內容。

多人協作

多人協作的工作模式通常是這樣:

首先,可以試圖用git push origin branch-name推送自己的修改;

如果推送失敗,則因為遠端分支比你的本地更新,需要先用git pull試圖合併;

如果合併有衝突,則解決衝突,並在本地提交;

沒有衝突或者解決掉衝突後,再用git push origin branch-name推送就能成功!

如果git pull提示“no tracking information”,則說明本地分支和遠端分支的連結關係沒有建立,用命令git branch --set-upstream branch-name origin/branch-name。

這就是多人協作的工作模式,一旦熟悉了,就非常簡單。

注:所有工作流建立在已經建立了個人賬戶,並新增了SSH key到個人的文件中。見Profile Settings → SSH keys → Before you can add an SSH key you need to [generate it].

  1. 普通開發人員

    情況一:程式設計師A是後加入到專案中的,專案已經存在程式碼倉庫。

    如:

    (1)克隆版本倉庫

    git clone git@github.com:kanlidy/HelloGit.git

    (2)建立分支

    git checkout -b (分支名)

    (3)提交程式碼

    檢視程式碼修改的狀態:

    git status

    新增到工作區:

    git add .

    提交到本地倉庫:

    git commit -m "(寫下提交日誌)"

    推送到伺服器:

    git push origin 分支名

    (4)在伺服器上建立Merge Request,把自己的提交到遠端的分支,Merge到Dev(開發分支)

    情況二:程式設計師B是在一個新專案中,本地有一些程式碼,需要建立一個版本控制倉庫

    (1)在專案目錄下,初始化倉庫

    git init

    (2)新增到git版本控制系統:

    git remote add origin git@github.com:kanlidy/HelloGit.git

    (3)新增所有已經存在的檔案到專案中:

    git add .

    (4)提交程式碼到本地倉庫:

    git commit -m "寫下日誌"

    (5)提交程式碼遠端伺服器

    git push origin <本地分支名>:<遠端分支名>
    
    git push origin master:master

    對於單人專案,情況二足以滿足程式碼控制要求。→呂揚、劉揚。

  2. 倉庫管理人員

    情況一:手工合併程式碼

    (1)在指定分支上獲取更新

    git checkout <指定分支>

    (2)拉取伺服器上的程式碼

    git pull origin <指定分支>

    (3)切換到dev,並獲取dev上的更新,合併指定分支上的程式碼

    git checkout dev
    git pull origin dev
    git merge <指定分支>

    情況二:直接在gitlab上進行操作

    直接點選accept merge request進行分支合併。

    程式碼回撤參考git reset命令,獲取更新參考git fetch命令,分支檢視git branch,邏輯流程圖gitk,狀態命令git status,日誌命令git refloggit log

    參考資料:

Git常用命令

這一部分介紹了git的常用命令,如git clone、git pull、git push等等。

git clone

該命令會在本地主機生成一個目錄,與遠端主機的版本庫同名。如果要指定不同的目錄名,可以將目錄名作為git clone命令的第二個引數。

克隆倉庫git clone的語法:

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

git clone支援多種協議,除了HTTP(s)以外,還支援SSH、Git、本地檔案協議等,下面是一些例子。

$ git clone http[s]://example.com/path/to/repo.git/
$ git clone ssh://example.com/path/to/repo.git/
$ git clone git://example.com/path/to/repo.git/
$ git clone /opt/git/project.git 
$ git clone file:///opt/git/project.git
$ git clone ftp[s]://example.com/path/to/repo.git/
$ git clone rsync://example.com/path/to/repo.git/

SSH協議還有另一種寫法。

$ git clone [user@]example.com:path/to/repo.git/

還可以使用-b和標籤名來克隆指定的分支和tags

git clone -b r01 

git remote

為了便於管理,Git要求每個遠端主機都必須指定一個主機名。git remote命令就用於管理主機名。
不帶選項的時候,git remote命令列出所有遠端主機。

$ git remote
origin

使用-v選項,可以參看遠端主機的網址。

$ git remote -v
origin  git@github.com:jquery/jquery.git (fetch)
origin  git@github.com:jquery/jquery.git (push)

上面命令表示,當前只有一臺遠端主機,叫做origin,以及它的網址。
克隆版本庫的時候,所使用的遠端主機自動被Git命名為origin。如果想用其他的主機名,需要用git clone命令的-o選項指定。

$ git clone -o jQuery 
$ git remote
jQuery

上面命令表示,克隆的時候,指定遠端主機叫做jQuery。
git remote show命令加上主機名,可以檢視該主機的詳細資訊。

$ git remote show <主機名>
git remote add命令用於新增遠端主機。

$ git remote add <主機名> <網址>
git remote rm命令用於刪除遠端主機。

$ git remote rm <主機名>
git remote rename命令用於遠端主機的改名。

$ git remote rename <原主機名> <新主機名>

git fetch

一旦遠端主機的版本庫有了更新(Git術語叫做commit),需要將這些更新取回本地,這時就要用到git fetch命令。

$ git fetch <遠端主機名>

上面命令將某個遠端主機的更新,全部取回本地。
git fetch命令通常用來檢視其他人的程式,因為它取回的程式碼對你本地的開發程式碼沒有影響。
預設情況下,git fetch取回所有分支(branch)的更新。如果只想取回特定分支的更新,可以指定分支名。

$ git fetch <遠端主機名> <分支名>

比如,取回origin主機的master分支。

$ git fetch origin master

所取回的更新,在本地主機上要用”遠端主機名/分支名”的形式讀取。比如origin主機的master,就要用origin/master讀取。
git branch命令的-r選項,可以用來檢視遠端分支,-a選項檢視所有分支。

$ git branch -r
origin/master

$ git branch -a
* master
  remotes/origin/master

上面命令表示,本地主機的當前分支是master,遠端分支是origin/master。
取回遠端主機的更新以後,可以在它的基礎上,使用git checkout命令建立一個新的分支。

$ git checkout -b newBrach origin/master

上面命令表示,在origin/master的基礎上,建立一個新分支。
此外,也可以使用git merge命令或者git rebase命令,在本地分支上合併遠端分支。

$ git merge origin/master
# 或者
$ git rebase origin/master

上面命令表示在當前分支上,合併origin/master。

git pull

git pull命令的作用是,取回遠端主機某個分支的更新,再與本地的指定分支合併。它的完整格式稍稍有點複雜。

$ git pull <遠端主機名> <遠端分支名>:<本地分支名>

比如,取回origin主機的next分支,與本地的master分支合併,需要寫成下面這樣。

$ git pull origin next:master

如果遠端分支是與當前分支合併,則冒號後面的部分可以省略。

$ git pull origin next

上面命令表示,取回origin/next分支,再與當前分支合併。實質上,這等同於先做git fetch,再做git merge

$ git fetch origin
$ git merge origin/next

在某些場合,Git會自動在本地分支與遠端分支之間,建立一種追蹤關係(tracking)。比如,在git clone的時候,所有本地分支預設與遠端主機的同名分支,建立追蹤關係,也就是說,本地的master分支自動”追蹤”origin/master分支。
Git也允許手動建立追蹤關係。

git branch --set-upstream master origin/next

上面命令指定master分支追蹤origin/next分支。
如果當前分支與遠端分支存在追蹤關係,git pull就可以省略遠端分支名。

$ git pull origin

上面命令表示,本地的當前分支自動與對應的origin主機”追蹤分支”(remote-tracking branch)進行合併。
如果當前分支只有一個追蹤分支,連遠端主機名都可以省略。

$ git pull

上面命令表示,當前分支自動與唯一一個追蹤分支進行合併。
如果合併需要採用rebase模式,可以使用--rebase選項。

$ git pull --rebase <遠端主機名> <遠端分支名>:<本地分支名>

如果遠端主機刪除了某個分支,預設情況下,git pull 不會在拉取遠端分支的時候,刪除對應的本地分支。這是為了防止,由於其他人操作了遠端主機,導致git pull不知不覺刪除了本地分支。
但是,你可以改變這個行為,加上引數 -p 就會在本地刪除遠端已經刪除的分支。

$ git pull -p
# 等同於下面的命令
$ git fetch --prune origin 
$ git fetch -p

git push

git push命令用於將本地分支的更新,推送到遠端主機。它的格式與git pull命令相仿。

$ git push <遠端主機名> <本地分支名>:<遠端分支名>

注意,分支推送順序的寫法是<來源地>:<目的地>,所以git pull是<遠端分支>:<本地分支>,而git push<本地分支>:<遠端分支>
如果省略遠端分支名,則表示將本地分支推送與之存在”追蹤關係”的遠端分支(通常兩者同名),如果該遠端分支不存在,則會被新建。

$ git push origin master

上面命令表示,將本地的master分支推送到origin主機的master分支。如果後者不存在,則會被新建。
如果省略本地分支名,則表示刪除指定的遠端分支,因為這等同於推送一個空的本地分支到遠端分支。

$ git push origin :master
# 等同於
$ git push origin --delete master

上面命令表示刪除origin主機的master分支。
如果當前分支與遠端分支之間存在追蹤關係,則本地分支和遠端分支都可以省略。

$ git push origin

上面命令表示,將當前分支推送到origin主機的對應分支。
如果當前分支只有一個追蹤分支,那麼主機名都可以省略。

$ git push

如果當前分支與多個主機存在追蹤關係,則可以使用-u選項指定一個預設主機,這樣後面就可以不加任何引數使用git push

$ git push -u origin master

上面命令將本地的master分支推送到origin主機,同時指定origin為預設主機,後面就可以不加任何引數使用git push了。
不帶任何引數的git push,預設只推送當前分支,這叫做simple方式。此外,還有一種matching方式,會推送所有有對應的遠端分支的本地分支。Git 2.0版本之前,預設採用matching方法,現在改為預設採用simple方式。如果要修改這個設定,可以採用git config命令。

$ git config --global push.default matching
# 或者
$ git config --global push.default simple

還有一種情況,就是不管是否存在對應的遠端分支,將本地的所有分支都推送到遠端主機,這時需要使用–all選項。

$ git push --all origin

上面命令表示,將所有本地分支都推送到origin主機。
如果遠端主機的版本比本地版本更新,推送時Git會報錯,要求先在本地做git pull合併差異,然後再推送到遠端主機。這時,如果你一定要推送,可以使用--force選項。

$ git push --force origin

上面命令使用--force選項,結果導致遠端主機上更新的版本被覆蓋。除非你很確定要這樣做,否則應該儘量避免使用--force選項。
最後,git push不會推送標籤(tag),除非使用--tags選項。

$ git push origin --tags

以上就是關於Git你需要知道的知識點啦,掌握以上知識點,你在工作上就可以輕鬆玩轉Git版本控制了。


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/4687/viewspace-2825742/,如需轉載,請註明出處,否則將追究法律責任。

相關文章