Git命令的使用和相關配置

fsmStudy發表於2018-09-15

安裝後初始化配置

配置全域性的使用者名稱(–global此電腦所有git倉庫都會使用該配置)

$ git config --global user.name "Your Name"

配置全域性的郵箱地址(–global此電腦所有git倉庫都會使用該配置)

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

檢視配置資訊

$ git config --system --list  ## 檢視系統配置
$ git config --global  --list ## 檢視當前使用者配置
$ git config --local  --list  ## 檢視當前倉庫配置

建立版本庫

建立一個空目錄作為版本庫目錄

$ mkdir learngit # 建立目錄learngit(即為版本庫)
$ cd learngit    # 進入該目錄
$ pwd            # 檢視路徑
/Users/michael/learngit

初始化該目錄,使其可以被git管理,此後該目錄會出現一個.git目錄(如果沒有可能被隱藏了,可以用:ls -ah檢視)

$ git init  # 初始化該目錄之後會出現以下提示
Initialized empty Git repository in /Users/michael/learngit/.git/
$ ls -ah # 檢視當前目錄檔案,包括隱藏檔案

在目錄下面新建一個檔案,用於做測試,內容隨便

$ ls
readme.php
$ cat readme.php
Git is a version control system.
Git is free software.

將檔案放入到倉庫只需要兩步

1). 告訴Git將要將要新增該檔案到倉庫(add後面可以跟多個檔案用空格隔開,也可以跟目錄,並且可以將檔案多次分別add,只要在commit之前都算一次提交)

$ git add readme.txt

2). 將檔案提交到倉庫

$ git commit -m "wrote a readme file" 
[master (root-commit) 74256b9] wrote a readme file
 2 files changed, 6 insertions(+)
 create mode 100644 reademe.php
 create mode 100644 readme.php

==注意:每次修改,如果不用git add到暫存區,那就不會加入到commit中==


對檔案進行修改,新增一個單詞,然後通過命令檢視狀態

$ 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.txt

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

告訴我們檔案被修改過了,但是還沒有準備提交的修改

檢視具體修改了哪些內容

$ git diff readme.php # 會顯示出修改的內容資訊

版本回退

檢視所有的版本日誌

$ git log # 如果需要精簡到一行的資訊加上引數 --pretty=oneline 即可
在Git中,用HEAD表示當前版本,也就是最新的提交1094adb...
(注意我的提交ID和你的肯定不一樣),
上一個版本就是HEAD^,
上上一個版本就是HEAD^^,
當然往上100個版本寫100個^比較容易數不過來,所以寫成HEAD~100

如下,回退到上一個版本,執行命令後用cat檢視發現內容已經變了

$ git reset --hard HEAD^

如果我回到過去的版本了,隨後又想恢復到原來的版本怎麼辦,只要命令框沒有關閉,還可以找到原來的版本號,取前幾位就可以,但是也不能太少,用以下命令

$  git reset --hard 3642b # 版本號寫前幾位就可以,但是也不能太短,能識別就行

但是如果手賤關閉了命令框,關閉了電腦,怎麼辦,回退版本後發現錯了,還想回來怎麼辦

$ git reflog # 這個命令可以檢視你所有操作命令的日誌,當然裡面是有版本號的了

工作區概念:就是你在本地電腦裡能看到的目錄

版本庫概念:工作區有一個隱藏目錄.git,這個不算工作區,而是Git的版本庫。

前面講了我們把檔案往Git版本庫裡新增的時候,是分兩步執行的:

第一步是用git add把檔案新增進去,實際上就是把檔案修改新增到暫存區;

第二步是用git commit提交更改,實際上就是把暫存區的所有內容提交到當前分支。

因為我們建立Git版本庫時,Git自動為我們建立了唯一一個master分支,所以,現在,git commit就是往master分支上提交更改。


撤銷更改

情況一:準備提交之前如果發現了錯誤(==add之前==)

  1. 一種是readme.txt自修改後還沒有被放到暫存區,現在,撤銷修改就回到和版本庫一模一樣的狀態;
  2. 一種是readme.txt已經新增到暫存區後,又作了修改,現在,撤銷修改就回到新增到暫存區後的狀態。
  3. 總之,就是讓這個檔案回到最近一次git commit或git add時的狀態。
$ git checkout -- readme.php

情況二:已經提交到暫存區了(==add之後commit之前==)
1). git reset命令既可以回退版本,也可以把暫存區的修改回退到工作區。當我們用HEAD時,表示最新的版本。

$ git reset HEAD readme.php

2). 此時就變為了情況一,暫存區沒有了,但是工作區還有

$ git checkout -- readme.php

情況三:已經提交到了分支(==commit之後==)

可以採用版本回退的方法

情況四:不僅提交到了分支,還推送到了遠端版本庫

那麼恭喜你,本次撤銷修改是不可能的了


刪除檔案

當你從本地刪除了一個檔案,可以有兩種選擇:
1). 確定要刪除了,然後將分支中的檔案也刪除掉

$ git rm test.php
$ git commit -m "remove test.php"

2). 發現刪錯了,想要將其從分支恢復回來

$ git checkout -- test.php

遠端倉庫操作

新增遠端倉庫
[1]. 第一步:==建立SSH Key==。在使用者主目錄下,看看有沒有.ssh目錄,如果有,再看看這個目錄下有沒有id_rsa和id_rsa.pub這兩個檔案,如果已經有了,可直接跳到下一步。如果沒有,開啟Shell(Windows下開啟Git Bash),建立SSH Key:

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

注意:需要把郵件地址換成你自己的郵件地址,然後一路回車,使用預設值即可,密碼沒必要設定,如果一切順利的話,可以在使用者主目錄裡找到.ssh目錄,裡面有id_rsa和id_rsa.pub兩個檔案,這兩個就是SSH Key的祕鑰對, ==id_rsa是私鑰==,不能洩露出去,==id_rsa.pub是公鑰==,可以放心地告訴任何人

[2]. 第二步:登陸GitHub,開啟“Account settings”,“SSH Keys”頁面:
然後,點“==Add SSH Key==”,填上任意Title,在Key文字框裡貼上id_rsa.pub檔案的內容

==為什麼GitHub需要SSH Key呢?==

因為GitHub需要識別出你推送的提交確實是你推送的,而不是別人冒充的,而Git支援SSH協議,所以,GitHub只要知道了你的公鑰,就可以確認只有你自己才能推送。

當然,GitHub允許你新增多個Key。假定你有若干電腦,你一會兒在公司提交,一會兒在家裡提交,只要把每臺電腦的Key都新增到GitHub,就可以在每臺電腦上往GitHub推送了。

最後友情提示,在GitHub上免費託管的Git倉庫,任何人都可以看到喔(但只有你自己才能改)。所以,不要把敏感資訊放進去。

[3]. ==在github上新建空的版本庫==

$ git remote add origin git@github.com:KeepFang/learngit.git

注意:要將KeepFang換成自己的github使用者名稱,learngit換成自己的遠端庫名字

新增後,遠端庫的名字就是origin,這是Git預設的叫法,也可以改成別的,但是origin這個名字一看就知道是遠端庫。

[4]. 將本地內容推送到遠端庫

$ git push -u origin master # 將本地庫內容推送到遠端庫

把本地庫的內容推送到遠端,用git push命令,實際上是把當前分支master推送到遠端。

由於遠端庫是空的,我們第一次推送master分支時,加上了-u引數,Git不但會把本地的master分支內容推送到遠端新的master分支,還會把本地的master分支和遠端的master分支關聯起來,在以後的推送或者拉取時就可以簡化命令。

從現在起,只要本地作了提交,就可以通過命令:

$ git push origin master

==SSH警告==

當你第一次使用Git的clone或者push命令連線GitHub時,會得到一個警告

The authenticity of host `github.com (xx.xx.xx.xx)` can`t be established.
RSA key fingerprint is xx.xx.xx.xx.xx.
Are you sure you want to continue connecting (yes/no)?

這是因為Git使用SSH連線,而SSH連線在第一次驗證GitHub伺服器的Key時,需要你確認GitHub的Key的指紋資訊是否真的來自GitHub的伺服器,輸入yes回車即可。

Git會輸出一個警告,告訴你已經把GitHub的Key新增到本機的一個信任列表裡了:

Warning: Permanently added `github.com` (RSA) to the list of known hosts.

==克隆遠端庫檔案到本地==

git clone git@github.com:使用者名稱/版本庫名.git

你也許還注意到,GitHub給出的地址不止一個,還可以用https://github.com/michaellia…。實際上,Git支援多種協議,預設的git://使用ssh,但也可以使用https等其他協議。

使用https除了速度慢以外,還有個最大的麻煩是每次推送都必須輸入口令,但是在某些只開放http埠的公司內部就無法使用ssh協議而只能用https。

分支

分支在實際中怎麼用呢?

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

1). 建立分支

$ git checkout -b dev # 建立分支dev並切換到該分支

等價於

$ git branch dev # 建立分支
$ git checkout dev # 切換分支
$ git branch  # 列出所有分支,當前分支前面會標一個 * 號

2). 合併分支

$ git checkout master  # 切換到主分支
$ git merge dev  # 將dev分支與當前分支合併
$ git branch -d dev # 合併完成之後就可以刪除dev分支了
$ git branch  # 刪除之後再次檢視分支,發現只剩下master分支了

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

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

$ git merge --no-ff -m "merge with no-ff" dev # 禁用fast forward快速合併模式,
## 合併分支時,加上--no-ff引數就可以用普通模式合併,
## 合併後的歷史有分支,能看出來曾經做過合併,
## 而fast forward合併就看不出來曾經做過合併。
$ git log --graph --pretty=oneline --abbrev-commit # 然後再檢視分支歷史

3). 解決衝突

當Git無法自動合併分支時,就必須首先解決衝突。解決衝突後,再提交,合併完成。

解決衝突就是把Git合併失敗的檔案手動編輯為我們希望的內容,再提交。

合併之後,刪除沒用的分支

$ git log --graph --pretty=oneline --abbrev-commit # graph引數是檢視分支合併圖

分支策略

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

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

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

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

bug分支

當你正在開發一個新功能的時候,突然有人反饋原先的專案存在一個bug,很自然想到新建一個分支來進行修復然後合併,但是現在你的工作還沒完成,又不能提交,這時候就需要用到 ==儲存現場== 功能

$ git stash # 將當前工作的現場儲存起來
$ git status # 這時候再看發現工作區是乾淨的可以放心建立分支

1). 確定在哪個分支修復bug,就從哪個分支建立臨時分支,假設是master

$ git checkout master  # 切換到master分支
$ git checkout -b issue-101 # 建立並切換到bug分支
$ git add readme.txt 
$ git commit -m "fix bug 101" # 模擬修復bug
$ git checkout master # 切換到主分支
$ $ git merge --no-ff -m "merged bug fix 101" issue-101 # 將bug分支與主分支合併

2). 修復bug後繼續dev分支開發


$ git checkout dev # 繼續返回dev寫未完成的工作
$ git status # 此時工作區是乾淨的,那之前儲存的現場在哪裡呢
$ git stash list # 檢視儲存的工作現場

3).恢復之前的現場

$ git stash pop # 恢復現場並刪除該stash
$ git stash list # 再次檢視發現,已經沒有stash了

等價於

$ git stash apply # 恢復現場
$ git stash drop  # 刪除stash
$ git stash list # 再次檢視發現,已經沒有stash了

還可以多次stash,恢復指定現場

$ git stash apply stash@{0} # 恢復指定編號的現場

feature分支(新功能分支)

開發一個新功能,最好新建一個分支,至於怎麼新建分支這個上面已經有概述

特殊情況:如果需要丟棄一個未合併的分支

$ git branch -D feature-vulcan # 如果要強制丟棄一個未合併的分支需要用大寫的D引數

多人協作

1). 檢視遠端倉庫資訊

$ git remote # 檢視遠端倉庫資訊
$ git remote -v # 檢視遠端倉庫詳細資訊

2). 推送分支到遠端庫

$ git push origin dev # 推送當前分支到指定的遠端分支

但是,==並不是一定要把本地分支往遠端推送==,那麼,哪些分支需要推送,哪些不需要呢?

master分支是主分支,因此要時刻與遠端同步;

dev分支是開發分支,團隊所有成員都需要在上面工作,所以也需要與遠端同步;

bug分支只用於在本地修復bug,就沒必要推到遠端了,除非老闆要看看你每週到底修復了幾個bug;

feature分支是否推到遠端,取決於你是否和你的小夥伴合作在上面開發。

總之,就是在Git中,分支完全可以在本地自己藏著玩,是否推送,視你的心情而定!

3). 抓取分支

3.1. 模擬一個你的小夥伴,可以在另一臺電腦(注意要把SSH Key新增到GitHub)或者同一臺電腦的另一個目錄下克隆:

$ git clone git@github.com:使用者名稱/倉庫名.git # 從伺服器上拉取專案到本地
$ git branch # 拉取下來之後本地預設只能看到一個master分支

3.2. 現在你的小夥伴要在dev分支上面進行開發了,於是他需要建立dev分支在本地

$ git checkout -b dev origin/dev # 建立=(遠端)=的dev分支到本地

3.3. 現在就可以開發dev分支,並時不時提交到遠端

$ git add env.txt # 模擬開發dev分支
$ git commit -m "add env" 
$ git push origin dev # 提交分支到遠端

3.4. 如果多個人都在開發dev分支呢,為了保證一致性,需要先更新再提交

$ git add env.txt # 模擬你的提交
$ git commit -m "add new env" 
$ git push origin dev # 假設你的隊友已經修改過dev分支了,那麼會推送失敗
$ git pull # 需要先pull更新程式碼為最新,可能還會報錯,
## 因為沒有建立本地dev與遠端dev分支的直接連結
$ git branch --set-upstream-to=origin/dev dev # 按照報錯資訊建立連結
$ git pull # 這時候返回pull成功,但是可能你和隊友修改了同樣地方會提示有衝突
$ git commit -m "fix env conflict" # 解決衝突後,先提交,然後push
$ git push origin dev# 修復衝突後再次推送

rebase(變基:說白了就是美化分支線)

多人協作,分支很混亂,如果有強迫症非要整理成一條線呢

1). 原來分支圖是這樣

$ git log --graph --pretty=oneline --abbrev-commit # 檢視分支線
* 582d922 (HEAD -> master) add author
* 8875536 add comment
* d1be385 (origin/master) init hello
*   e5e69f1 Merge branch `dev`
|  
| *   57c53ab (origin/dev, dev) fix env conflict
| |  
| | * 7a5e5dd add env
| * | 7bd91f1 add new env
...

注意到Git用(HEAD -> master)和(origin/master)標識出當前分支的HEAD和遠端origin的位置分別是582d922 add author和d1be385 init hello,本地分支比遠端分支快兩個提交。

2). 當我們再次提交,很不幸,有個人已經提前提交了,出現了衝突,按照習慣先pull一下

$ git push origin master # 假設失敗了
$ git pull # 先pull一下
$ git status # 檢視狀態
$ git log --graph --pretty=oneline --abbrev-commit # 再次檢視分支線,發現分叉了,
## 但是現在繼續提交時完全沒有問題的,就是線不好看
$ git rebase # 用命令美化線為一條
$ git log --graph --pretty=oneline --abbrev-commit # 再次檢視分支線,發現變為了一條直線
$ git push origin master # 最後提交分支到遠端

==rebase的目的是使得我們在檢視歷史提交的變化時更容易,因為分叉的提交需要三方對比==。

標籤管理

tag就是一個讓人容易記住的有意義的名字,它跟某個commit綁在一起。例如:v1.2

1). 建立標籤

$ git branch # 檢視分支
$ git checkout master # 切換到分支
$ git tag v1.0 # 打標籤
$ git tag # 檢視所有標籤

如果前面的忘記打標籤現在要補上怎麼辦

$ git log --pretty=oneline --abbrev-commit # 找到對應版本號
$ git tag v0.9 f52c633 # 指定版本號打標籤
$ git tag # 檢視標籤

標籤不是按時間順序列出,而是按字母排序的。可以用git show <tagname>檢視標籤資訊

$ git show v0.9 # 檢視標籤資訊
$ git tag -a v0.1 -m "version 0.1 released" 1094adb # 要想帶上標籤說明,可以用-m引數
$ git show v0.1 # 這個命令同樣可以檢視到標籤的說明資訊

2). 操作標籤

刪除本地標籤

$ git tag -d v0.1

推送某個標籤到遠端

$ git push origin v1.0

一次性推送全部尚未推送到遠端的本地標籤

$ git push origin --tags

刪除遠端標籤

$ git tag -d v0.9 # 先從本地刪除
$ git push origin :refs/tags/v0.9 # 刪除遠端標籤

Github上參與別人的開發

在GitHub上,可以任意Fork開源倉庫;

自己擁有Fork後的倉庫的讀寫許可權;

可以推送pull request給官方倉庫來貢獻程式碼。

使用國內的碼雲(gitee)

1). 先註冊賬號後配置公鑰

2). 如果已經有了一個本地倉庫,想要關聯到碼雲

[1]. 首先在碼雲上面建立這個專案
[2]. 將本地庫只與碼雲庫關聯

$ git remote add origin git@gitee.com:使用者名稱/專案名.git

==如果在使用命令git remote add時報錯,說明本地已經關聯了一個遠端庫==

此時先檢視遠端庫資訊

$ git remote -v

然後刪除遠端庫資訊,關聯到gitee

$ git remote rm origin # 刪除遠端庫
$ git remote add origin git@gitee.com:使用者名稱/專案名.git # 關聯碼雲庫
$ git remote -v # 再次檢視遠端庫資訊

[3]. 同時關聯github和碼雲

使用多個遠端庫時,我們要注意,git給遠端庫起的預設名稱是origin,如果有多個遠端庫,我們需要用不同的名稱來標識不同的遠端庫。

1). 先刪除已關聯的名為origin的遠端庫

$ git remote rm origin

2). 新增Github連結

$ git remote add github git@github.com:使用者名稱/倉庫名.git 
# 注意遠端庫叫github不叫origin了

3). 新增碼雲連結

git remote add gitee git@gitee.com:使用者名稱/倉庫名.git
# 注意遠端庫叫gitee不叫origin了
$ git remote -v # 此時發現關聯了github和gitee等多個遠端庫

[4]. 然後就可以正常的pull和push了

## 更新程式碼為最新
git pull gitee master
git pull github master

## 推送到github遠端庫
$ git push github master
## 推送到gitee遠端庫
$ git push gitee master
## 如果不行就用
git push -u gitee master

忽略特殊檔案(不能提交到遠端庫)

有些檔案必須在專案目錄,但是又不能提交他們,比如資料庫密碼配置檔案

解決方法:在Git工作區的根目錄下建立一個特殊的.gitignore檔案,然後把要忽略的檔名填進去,Git就會自動忽略這些檔案,詳情參考廖雪峰git。

忽略檔案的原則是:

  1. 忽略作業系統自動生成的檔案,比如縮圖等;
  2. 忽略編譯生成的中間檔案、可執行檔案等,也就是如果一個檔案是通過另一個檔案自動生成的,那自動生成的檔案就沒必要放進版本庫,比如Java編譯產生的.class檔案;
  3. 忽略你自己的帶有敏感資訊的配置檔案,比如存放口令的配置檔案。

有些時候,你想新增一個檔案到Git,但發現新增不了,原因是這個檔案被.gitignore忽略了

這個時候可以採用兩種方法

1). 一種是-f直接強制提交

$ git add -f App.class

2). 一種是檢查是不是過濾用的配置檔案寫錯了

$ git check-ignore -v App.class

配置別名(給git命令新增別名)

配製方法:

$ git config --global alias.st status # 執行之後,就可以用st代替status
$ git config --global alias.unstage `reset HEAD` # 用unstage代替reset HEAD

配置檔案:配置好的規則實際上儲存在本地的檔案裡面

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

每個倉庫的Git配置檔案都放在.git/config檔案中,[alias]下面就是別名,可直接新增、修改或刪除

[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

相關文章