1. 程式人生 > 實用技巧 >天吶!Linus兩週搞出個Git,快來看看咋用滴!

天吶!Linus兩週搞出個Git,快來看看咋用滴!

大家好,我是Sean!

轉載一篇非常實用的Git教程,在一個小工具看到的,在此感謝這位不為人知作者的辛勤寫作。

Git

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

補充說明

git命令 很多人都知道,Linus在1991年建立了開源的Linux,從此,Linux系統不斷髮展,已經成為最大的伺服器系統軟體了。

Linus雖然建立了Linux,但Linux的壯大是靠全世界熱心的志願者參與的,這麼多人在世界各地為Linux編寫程式碼,那Linux的程式碼是如何管理的呢?

事實是,在2002年以前,世界各地的志願者把原始碼檔案通過diff的方式發給Linus,然後由Linus本人通過手工方式合併程式碼!

你也許會想,為什麼Linus不把Linux程式碼放到版本控制系統裡呢?不是有CVS、SVN這些免費的版本控制系統嗎?因為Linus堅定地反對CVS和SVN,這些集中式的版本控制系統不但速度慢,而且必須聯網才能使用。有一些商用的版本控制系統,雖然比CVS、SVN好用,但那是付費的,和Linux的開源精神不符。

不過,到了2002年,Linux系統已經發展了十年了,程式碼庫之大讓Linus很難繼續通過手工方式管理了,社群的弟兄們也對這種方式表達了強烈不滿,於是Linus選擇了一個商業的版本控制系統BitKeeper,BitKeeper的東家BitMover公司出於人道主義精神,授權Linux社群免費使用這個版本控制系統。

安定團結的大好局面在2005年就被打破了,原因是Linux社群牛人聚集,不免沾染了一些梁山好漢的江湖習氣。開發Samba的Andrew試圖破解BitKeeper的協議(這麼幹的其實也不只他一個),被BitMover公司發現了(監控工作做得不錯!),於是BitMover公司怒了,要收回Linux社群的免費使用權。

Linus可以向BitMover公司道個歉,保證以後嚴格管教弟兄們,嗯,這是不可能的。實際情況是這樣的:

Linus花了兩週時間自己用C寫了一個分散式版本控制系統,這就是Git!一個月之內,Linux系統的原始碼已經由Git管理了!牛是怎麼定義的呢?大家可以體會一下。

Git迅速成為最流行的分散式版本控制系統,尤其是2008年,GitHub網站上線了,它為開源專案免費提供Git儲存,無數開源專案開始遷移至GitHub,包括jQuery,PHP,Ruby等等。

歷史就是這麼偶然,如果不是當年BitMover公司威脅Linux社群,可能現在我們就沒有免費而超級好用的Git了。

Git常用命令清單鏈接

語法

git [--version] [--help] [-C <path>] [-c name=value]
   [--exec-path[=<path>]] [--html-path] [--man-path] [--info-path]
  # [-p | --paginate | --no-pager] [--no-replace-objects] [--bare]
   [--git-dir=<path>] [--work-tree=<path>] [--namespace=<name>]
   <command> [<args>]

選項

add              將檔案內容新增到索引
bisect           通過二進位制查詢引入錯誤的更改
branch           列出,建立或刪除分支
checkout         檢查分支或路徑到工作樹
clone            將儲存庫克隆到新目錄中
commit           將更改記錄到儲存庫
diff             顯示提交,提交和工作樹等之間的更改
fetch            從另一個儲存庫下載物件和引用
grep             列印匹配圖案的行
init             建立一個空的Git倉庫或重新初始化一個現有的
log              顯示提交日誌
merge            加入兩個或更多的開發歷史
mv               移動或重新命名檔案,目錄或符號連結
pull             從另一個儲存庫或本地分支獲取併合並
push             更新遠端引用以及相關物件
rebase           轉發埠本地提交到更新的上游頭
reset            將當前HEAD復位到指定狀態
rm               從工作樹和索引中刪除檔案
show             顯示各種型別的物件
status           顯示工作樹狀態
tag              建立,列出,刪除或驗證使用GPG簽名的標籤物件

例子

init

git init #初始化

status

git status #獲取狀態

add

git add file # .或*代表全部新增
git rm --cached <added_file_to_undo> # 在commit之前撤銷git add操作
git reset head # 好像比上面git rm --cached更方便

commit

git commit -m "message" #此處注意亂碼

remote

git remote add origin [email protected]:JSLite/test.git #新增源

push

git push -u origin master # push同事設定預設跟蹤分支  
git push origin master  
git push -f origin master # 強制推送檔案,縮寫 -f(全寫--force)
clone

git clone git://github.com/JSLite/JSLite.js.git
git clone git://github.com/JSLite/JSLite.js.git mypro #克隆到自定義資料夾
git clone [user@]example.com:path/to/repo.git/ #SSH協議還有另一種寫法。

git clone支援多種協議,除了HTTP(s)以外,還支援SSH、Git、本地檔案協議等,下面是一些例子。git clone <版本庫的網址> <本地目錄名>

$ 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 -T [email protected] 測試。

修改專案中的個人資訊

git help config # 獲取幫助資訊,檢視修改個人資訊的引數  
git config --global user.name "小弟調調"           # 修改全域性名字
git config --global user.email "[email protected]"  # 修改全域性郵箱
git config --list         # 檢視配置的資訊  
配置自動換行
自動轉換坑太大,提交到git是自動將換行符轉換為lf

git config --global core.autocrlf input

常見使用場景

建立SSH金鑰

這個金鑰用來跟 github 通訊,在本地終端裡生成然後上傳到 github

ssh-keygen -t rsa -C '[email protected]' # 生成金鑰  
ssh-keygen -t rsa -C "[email protected]" -f ~/.ssh/ww_rsa # 指定生成目錄檔名字
ssh -T [email protected] # 測試是否成功  

多賬號ssh配置

  1. 生成指定名字的金鑰
ssh-keygen -t rsa -C "郵箱地址" -f ~/.ssh/jslite_rsa
會生成 jslite_rsa 和 jslite_rsa.pub 這兩個檔案
  1. 金鑰複製到託管平臺上
vim ~/.ssh/jslite_rsa.pub
開啟公鑰檔案 jslite_rsa.pub ,並把內容複製至程式碼託管平臺上
  1. 修改config檔案
vim ~/.ssh/config #修改config檔案,如果沒有建立 config

Host jslite.github.com
  HostName github.com
  User git
  IdentityFile ~/.ssh/jslite_rsa

Host work.github.com
  HostName github.com

  # Port 伺服器open-ssh埠(預設:22,預設時一般不寫此行)

  # PreferredAuthentications 配置登入時用什麼許可權認證 

  #                          publickey|password publickey|keyboard-interactive等

  User git
  IdentityFile ~/.ssh/work_rsa
  • Host 這裡是個別名可以隨便命名
  • HostName 一般是網站如:[email protected]:username/repo.git 填寫 github.com
  • User 通常填寫git
  • IdentityFile 使用的公鑰檔案地址
  1. 測試
ssh -T [email protected]  # `@`後面跟上定義的Host  
ssh -T work.github.com        # 通過別名測試
ssh -i ~/公鑰檔案地址 Host別名  # 如 ssh -i ~/.ssh/work_rsa work.github.com
  1. 使用
# 原來的寫法
git clone [email protected]:<jslite的使用者名稱>/learngit.git

# 現在的寫法
git clone [email protected]:<jslite的使用者名稱>/learngit.git
git clone [email protected]:<work的使用者名稱>/learngit.git

5.注意

如果你修改了id_rsa的名字,你需要將ssh key新增到SSH agent中,如:

ssh-add ~/.ssh/jslite_rsa
ssh-add -l  # 檢視所有的key
ssh-add -D  # 刪除所有的key
ssh-add -d  ~/.ssh/jslite_rsa # 刪除指定的key

免密碼登入遠端伺服器

$ ssh-keygen -t rsa -P '' -f ~/.ssh/aliyunserver.key
$ ssh-copy-id -i ~/.ssh/aliyunserver.key.pub [email protected] # 這裡需要輸入密碼一次

編輯 ~/.ssh/config

編輯 ~/.ssh/config

Host aliyun1
  HostName 192.168.182.112
  User root
  PreferredAuthentications publickey
  IdentityFile ~/.ssh/aliyunserver.key

上面配置完了,可以通過命令登入,不需要輸入IP地址和密碼 ssh aliyun1

https協議下提交程式碼免密碼

git clone https://github.com/username/rep.git
通過上面方式克隆可能需要密碼,解決辦法:進入當前克隆的專案 vi rep/.git/config 編輯 config, 按照下面方式修改,你就可以提交程式碼不用輸入密碼了。

  • [core]
        repositoryformatversion = 0
        filemode = true
        bare = false
        logallrefupdates = true
        ignorecase = true
        precomposeunicode = true
    [remote "origin"]
    
    -    url = https://github.com/username/rep.git
    
    +    url = https://使用者名稱:密碼@github.com/username/rep.git
         fetch = +refs/heads/*:refs/remotes/origin/*
         [branch "master"]
         remote = origin
         merge = refs/heads/master
    

檔案推向3個git庫

  1. 增加3個遠端庫地址
git remote add origin https://github.com/JSLite/JSLite.git  
git remote set-url --add origin https://gitlab.com/wang/JSLite.js.git  
git remote set-url --add origin https://oschina.net/wang/JSLite.js.git  
  1. 刪除其中一個 set-url 地址
usage: git remote set-url [--push] <name> <newurl> [<oldurl>]
   or: git remote set-url --add <name> <newurl>
   or: git remote set-url --delete <name> <url>
git remote set-url --delete origin https://oschina.net/wang/JSLite.js.git
  1. 推送程式碼
git push origin master
git push -f origin master  # 強制推送  
  1. 拉程式碼

只能拉取 origin 裡的一個url地址,這個fetch-url
預設為你新增的到 origin的第一個地址

git pull origin master   
git pull --all # 獲取遠端所有內容包括tag  
git pull origin next:master # 取回origin主機的next分支,與本地的master分支合併  
git pull origin next # 遠端分支是與當前分支合併  

# 上面一條命令等同於下面兩條命令   
git fetch origin  
git merge origin/next  

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

$ git pull -p

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

只需要更改config檔案裡,那三個url的順序即可,fetch-url會直接對應排行第一的那個utl連線。

修改遠端倉庫地址

git remote remove origin  # 刪除該遠端路徑  
git remote add origin [email protected]:JSLite/JSLite.git  # 新增遠端路徑 

撤銷遠端記錄

git reset --hard HEAD~1 # 撤銷一條記錄   
git push -f origin HEAD:master # 同步到遠端倉庫  

放棄本地的檔案修改

git reset --hard FETCH_HEAD # FETCH_HEAD表示上一次成功git pull之後形成的commit點。然後git pull
git reset --hard FETCH_HEAD 

出現錯誤
git pull
You are not currently on a branch, so I cannot use any
'branch.<branchname>.merge' in your configuration file.
Please specify which remote branch you want to use on the command
line and try again (e.g. 'git pull <repository> <refspec>').
See git-pull(1) FOR details.

解決方法:

git checkout -b temp # 新建+切換到temp分支 
git checkout master

最簡單放棄本地修改內容

# 如果有的修改以及加入暫存區的話
git reset --hard 

# 還原所有修改,不會刪除新增的檔案
git checkout . 

# 下面命令會刪除新增的檔案
git clean -xdf

通過儲存暫存區stash,在刪除暫存區的方法放棄本地修改。

git stash && git stash drop 

回滾到某個commit提交

git revert HEAD~1 # 撤銷一條記錄 會彈出 commit 編輯
git push # 提交回滾

回退到某一個版本

git reset --hard <hash>

# 例如 git reset --hard a3hd73r

# --hard代表丟棄工作區的修改,讓工作區與版本程式碼一模一樣,與之對應,

# --soft引數代表保留工作區的修改。

去掉某個commit

# 實質是新建了一個與原來完全相反的commit,抵消了原來commit的效果
git revert <commit-hash> 

新建一個空分支

# 這種方式新建的分支(gh-pages)是沒有 commit 記錄的
git checkout --orphan gh-pages

# 刪除新建的gh-pages分支原本的內容,如果不刪除,提交將作為當前分支的第一個commit
git rm -rf .

# 檢視一下狀態 有可能上面一條命令,沒有刪除還沒有提交的的檔案
git state 

合併多個commit

# 這個命令,將最近4個commit合併為1個,HEAD代表當前版本。
# 將進入VIM介面,你可以修改提交資訊。
git rebase -i HEAD~4 
# 可以看到其中分為兩個部分,上方未註釋的部分是填寫要執行的指令,
# 而下方註釋的部分則是指令的提示說明。指令部分中由前方的命令名稱、commit hash 和 commit message 組成
# 當前我們只要知道 pick 和 squash 這兩個命令即可。
# --> pick 的意思是要會執行這個 commit
# --> squash 的意思是這個 commit 會被合併到前一個commit
# 我們將 需要保留的 這個 commit 前方的命令改成 squash 或 s,然後輸入:wq以儲存並退出
# 這是我們會看到 commit message 的編輯介面
# 其中, 非註釋部分就是兩次的 commit message, 你要做的就是將這兩個修改成新的 commit message。
# 
# 輸入wq儲存並退出, 再次輸入git log檢視 commit 歷史資訊,你會發現這兩個 commit 已經合併了。
# 將修改強制推送到前端
git push -f origin master

修改遠端Commit記錄

git commit --amend

# amend只能修改沒有提交到線上的,最後一次commit記錄

git rebase -i HEAD~3

# 表示要修改當前版本的倒數第三次狀態

# 將要更改的記錄行首單詞 pick 改為 edit

pick 96dc3f9 doc: Update quick-start.md
pick f1cce8a test(Transition):Add transition test (#47)
pick 6293516 feat(Divider): Add Divider component.

# Rebase eeb03a4..6293516 onto eeb03a4 (3 commands)
#
# Commands:
# p, pick = use commit
# r, reword = use commit, but edit the commit message
# e, edit = use commit, but stop for amending
# s, squash = use commit, but meld into previous commit
# f, fixup = like "squash", but discard this commit's log message
# x, exec = run command (the rest of the line) using shell
# d, drop = remove commit

儲存並退出,會彈出下面提示

# You can amend the commit now, with
# 
#   git commit --amend
# 
# Once you are satisfied with your changes, run
# 
#   git rebase --continue
# 通過這條命令進入編輯頁面更改commit,儲存退出
git commit --amend
# 儲存退出確認修改,繼續執行 rebase, 
git rebase --continue
# 如果修改多條記錄反覆執行上面兩條命令直到完成所有修改
# 最後,確保別人沒有提交進行push,最好不要加 -f 強制推送
git push -f origin master

新增忽略檔案

echo node_modules/ >> .gitignore

利用commit關閉一個issue

這個功能在Github上可以玩兒,Gitlab上特別老的版本不能玩兒哦,那麼如何跟隨著commit關閉一個issue呢? 在confirm merge的時候可以使用一下命令來關閉相關issue:

fixes #xxx、 fixed #xxx、 fix #xxx、 closes #xxx、 close #xxx、 closed #xxx、

同步fork的上游倉庫

設定新增多個遠端倉庫地址

在同步之前,需要建立一個遠端點指向上游倉庫(repo).如果你已經派生了一個原始倉庫,可以按照如下方法做。

$ git remote -v

# List the current remotes (列出當前遠端倉庫)
# origin  https://github.com/user/repo.git (fetch)
# origin  https://github.com/user/repo.git (push)
$ git remote add upstream https://github.com/otheruser/repo.git
# Set a new remote (設定一個新的遠端倉庫)

$ git remote -v
# Verify new remote (驗證新的倉庫)
# origin    https://github.com/user/repo.git (fetch)
# origin    https://github.com/user/repo.git (push)
# upstream  https://github.com/otheruser/repo.git (fetch)
# upstream  https://github.com/otheruser/repo.git (push)

同步更新倉庫內容

同步上游倉庫到你的倉庫需要執行兩步:首先你需要從遠端拉取,之後你需要合併你希望的分支到你的本地副本分支。從上游的儲存庫中提取分支以及各自的提交內容。 master 將被儲存在本地分支機構 upstream/master

git fetch upstream

# remote: Counting objects: 75, done.
# remote: Compressing objects: 100% (53/53), done.
# remote: Total 62 (delta 27), reused 44 (delta 9)
# Unpacking objects: 100% (62/62), done.
# From https://github.com/ORIGINAL_OWNER/ORIGINAL_REPOSITORY
#  * [new branch]      master     -> upstream/master

檢查你的 fork's 本地 master 分支

git checkout master

# Switched to branch 'master'

合併來自 upstream/master 的更改到本地 master 分支上。 這使你的前 fork's master 分支與上游資源庫同步,而不會丟失你本地修改。

git merge upstream/master

# Updating a422352..5fdff0f
# Fast-forward
#  README                    |    9 -------
#  README.md                 |    7 ++++++
#  2 files changed, 7 insertions(+), 9 deletions(-)
#  delete mode 100644 README
#  create mode 100644 README.md

批量修改歷史commit中的名字和郵箱

1.克隆倉庫

注意引數,這個不是普通的clone,clone下來的倉庫並不能參與開發

git clone --bare https://github.com/user/repo.git
cd repo.git

2.命令列中執行程式碼

OLD_EMAIL原來的郵箱
CORRECT_NAME更正的名字
CORRECT_EMAIL更正的郵箱

將下面程式碼複製放到命令列中執行

git filter-branch -f --env-filter '
OLD_EMAIL="[email protected]"
CORRECT_NAME="小弟調調"
CORRECT_EMAIL="更正的郵箱@qq.com"
if [ "$GIT_COMMITTER_EMAIL" = "$OLD_EMAIL" ]
then
    export GIT_COMMITTER_NAME="$CORRECT_NAME"
    export GIT_COMMITTER_EMAIL="$CORRECT_EMAIL"
fi
if [ "$GIT_AUTHOR_EMAIL" = "$OLD_EMAIL" ]
then
    export GIT_AUTHOR_NAME="$CORRECT_NAME"
    export GIT_AUTHOR_EMAIL="$CORRECT_EMAIL"
fi
' --tag-name-filter cat -- --branches --tags
執行過程

Rewrite 160d4df2689ff6df3820563bfd13b5f1fb9ba832 (479/508) (16 seconds passed, remaining 0 predicted)
Ref 'refs/heads/dev' was rewritten
Ref 'refs/heads/master' was rewritten

3.同步到遠端倉庫

同步到push遠端git倉庫
git push --force --tags origin 'refs/heads/*'

我還遇到了如下面錯誤,lab預設給master分支加了保護,不允許強制覆蓋。Project(專案)->Setting->Repository 選單下面的Protected branches把master的保護去掉就可以了。修改完之後,建議把master的保護再加回來,畢竟強推不是件好事。

remote: GitLab: You are not allowed to force push code to a protected branch on this project.

當上面的push 不上去的時候,先 git pull 確保最新程式碼

git pull  --allow-unrelated-histories

# 或者指定分枝
git pull origin master --allow-unrelated-histories

檢視某個檔案歷史

git log --pretty=oneline 檔名  # 列出檔案的所有改動歷史  
git show c178bf49   # 某次的改動的修改記錄  
git log -p c178bf49 # 某次的改動的修改記錄  
git blame 檔名     # 顯示檔案的每一行是在那個版本最後修改。  
git whatchanged 檔名  # 顯示某個檔案的每個版本提交資訊:提交日期,提交人員,版本號,提交備註(沒有修改細節)  

打造自己的git命令

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

配置好後再輸入git命令的時候就不用再輸入一大段了,例如我們要檢視狀態,只需:

git st

中文亂碼的解決方案

git config --global core.quotepath false

新建倉庫

init

git init #初始化

status

git status #獲取狀態

add

git add file # .或*代表全部新增
git rm --cached <added_file_to_undo> # 在commit之前撤銷git add操作
git reset head # 好像比上面git rm --cached更方便

commit

git commit -m "message" #此處注意亂碼

remote

git remote add origin [email protected]:JSLite/test.git #新增源

push

git push -u origin master # push同時設定預設跟蹤分支  
git push origin master  
git push -f origin master # 強制推送檔案,縮寫 -f(全寫--force)

clone

git clone git://github.com/JSLite/JSLite.js.git
git clone git://github.com/JSLite/JSLite.js.git mypro #克隆到自定義資料夾
git clone [user@]example.com:path/to/repo.git/ #SSH協議還有另一種寫法。

git clone支援多種協議,除了HTTP(s)以外,還支援SSH、Git、本地檔案協議等,下面是一些例子。git clone <版本庫的網址> <本地目錄名>

$ 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/

本地

help

git help config # 獲取幫助資訊  

add

git add *   # 跟蹤新檔案   
git add -u [path]   # 新增[指定路徑下]已跟蹤檔案

rm

rm *&git rm *          # 移除檔案  
git rm -f *            # 移除檔案  
git rm --cached *      # 取消跟蹤  
git mv file_from file_to  # 重新命名跟蹤檔案  
git log   # 檢視提交記錄  

commit

git commit #提交更新   
git commit -m 'message' #提交說明   
git commit -a #跳過使用暫存區域,把所有已經跟蹤過的檔案暫存起來一併提交   
git commit --amend #修改最後一次提交   
git commit log #檢視所有提交,包括沒有push的commit    
git commit -m "#133" #關聯issue 任意位置帶上# 符號加上issue號碼  
git commit -m "fix #133" commit關閉issue  
git commit -m '概要描述'$'\n\n''1.詳細描述'$'\n''2.詳細描述' #提交簡要描述和詳細描述

reset

git reset HEAD *  # 取消已經暫存的檔案   
git reset --mixed HEAD * # 同上   
git reset --soft HEAD *  # 重置到指定狀態,不會修改索引區和工作樹   
git reset --hard HEAD *  # 重置到指定狀態,會修改索引區和工作樹   
git reset -- files *     # 重置index區檔案   

revert

git revert HEAD   # 撤銷前一次操作   
git revert HEAD~  # 撤銷前前一次操作   
git revert commit # 撤銷指定操作   

checkout

git checkout -- file  # 取消對檔案的修改(從暫存區——覆蓋worktree file)  
git checkout branch|tag|commit -- file_name  # 從倉庫取出file覆蓋當前分支   
git checkout HEAD~1 [檔案]  # 將會更新 working directory 去匹配某次 commit   
git checkout -- .          # 從暫存區取出檔案覆蓋工作區   
git checkout -b gh-pages  0c304c9  # 這個表示 從當前分支 commit 雜湊值為 0c304c9 的節點,分一個新的分支gh-pages出來,並切換到 gh-pages   

diff

git diff file     # 檢視指定檔案的差異   
git diff --stat   # 檢視簡單的diff結果   
git diff  # 比較Worktree和Index之間的差異   
git diff --cached   # 比較Index和HEAD之間的差異   
git diff HEAD       # 比較Worktree和HEAD之間的差異   
git diff branch     # 比較Worktree和branch之間的差異   
git diff branch1 branch2  # 比較兩次分支之間的差異   
git diff commit commit    # 比較兩次提交之間的差異   
git diff master..test   # 上面這條命令只顯示兩個分支間的差異  
git diff master...test    # 你想找出‘master’,‘test’的共有 父分支和'test'分支之間的差異,你用3個‘.'來取代前面的兩個'.'  

stash

git stash # 將工作區現場(已跟蹤檔案)儲藏起來,等以後恢復後繼續工作。   
git stash list  # 檢視儲存的工作現場   
git stash apply # 恢復工作現場   
git stash drop  # 刪除stash內容   
git stash pop   # 恢復的同時直接刪除stash內容   
git stash apply stash@{0} # 恢復指定的工作現場,當你儲存了不只一份工作現場時。

merge

git merge --squash test # 合併壓縮,將test上的commit壓縮為一條   
cherry-pick
git cherry-pick commit    # 揀選合併,將commit合併到當前分支   
git cherry-pick -n commit # 揀選多個提交,合併完後可以繼續揀選下一個提交

rebase

git rebase master   # 將master分支上超前的提交,變換到當前分支  
git rebase --onto master 169a6  # 限制回滾範圍,rebase當前分支從169a6以後的提交  
git rebase --interactive # 互動模式,修改commit   
git rebase --continue    # 處理完衝突繼續合併   
git rebase --skip        # 跳過   
git rebase --abort       # 取消合併    

分支branch

刪除

git push origin :branchName  # 刪除遠端分支  
git push origin --delete new # 刪除遠端分支new   
git branch -d branchName     # 刪除本地分支,強制刪除用-D  
git branch -d test      # 刪除本地test分支   
git branch -D test      # 強制刪除本地test分支   
git remote prune origin # 遠端刪除了,本地還能看到遠端存在,這條命令刪除遠端不存在的分支

提交

git push -u origin branchName # 提交分支到遠端origin主機中

拉取

git fetch -p #拉取遠端分支時,自動清理 遠端分支已刪除,本地還存在的對應同名分支。

分支合併

git merge branchName      # 合併分支 - 將分支branchName和當前所在分支合併   
git merge origin/master   # 在本地分支上合併遠端分支。   
git rebase origin/master  # 在本地分支上合併遠端分支。   
git merge test            # 將test分支合併到當前分支

重新命名

git branch -m old new #重新命名分支

檢視

git branch      # 列出本地分支   
git branch -r   # 列出遠端分支   
git branch -a   # 列出所有分支   
git branch -v   # 檢視各個分支最後一個提交物件的資訊   
git branch --merge      # 檢視已經合併到當前分支的分支   
git branch --no-merge   # 檢視為合併到當前分支的分支   
git remote show origin  # 可以檢視remote地址,遠端分支

新建

git branch test # 新建test分支  
git branch newBrach 3defc69 # 指定雜湊3defc69,新建分支名字為newBrach
git checkout -b newBrach origin/master # 取回遠端主機的更新以後,在它的基礎上建立一個新的分支  
git checkout -b newBrach 3defc69 # 以雜湊值3defc69,新建 newBrach 分支,並切換到該分支

連線

git branch --set-upstream dev origin/dev     # 將本地dev分支與遠端dev分支之間建立連結  
git branch --set-upstream master origin/next # 手動建立追蹤關係 

分支切換

git checkout test     # 切換到test分支   
git checkout -b test  # 新建+切換到test分支   
git checkout -b test dev # 基於dev新建test分支,並切換   

遠端

git fetch <遠端主機名> <分支名>   # fetch取回所有分支(branch)的更新  
git fetch origin remotebranch[:localbranch]   #  從遠端拉去分支[到本地指定分支]   
git merge origin/branch   # 合併遠端上指定分支   
git pull origin remotebranch:localbranch  #  拉去遠端分支到本地分支   
git push origin branch    # 將當前分支,推送到遠端上指定分支   
git push origin localbranch:remotebranch  # 推送本地指定分支,到遠端上指定分支   
git push origin :remotebranch   # 刪除遠端指定分支   
git checkout -b [--track] test origin/dev # 基於遠端dev分支,新建本地test分支[同時設定跟蹤] 

submodule

克隆專案同時克隆submodule

git clone https://github.com/jaywcjlove/handbook.git --depth=1 --recurse-submodules
克隆專案,之後再手動克隆 submodule 子專案

git submodule add --force '倉庫地址' '路徑'

# 其中,倉庫地址是指子模組倉庫地址,路徑指將子模組放置在當前工程下的路徑。

# 注意:路徑不能以 / 結尾(會造成修改不生效)、不能是現有工程已有的目錄(不能順利 Clone)

git submodule init # 初始化submodule
git submodule update # 更新submodule(必須在根目錄執行命令)
git submodule update --init --recursive  # 下載的工程帶有submodule
當使用git clone下來的工程中帶有submodule時,初始的時候,submodule的內容並不會自動下載下來的,此時,只需執行如下命令:

git submodule foreach git pull  # submodule 裡有其他的 submodule 一次更新
git submodule foreach git pull origin master # submodule更新

git submodule foreach --recursive git submodule init
git submodule foreach --recursive git submodule update

刪除檔案

git rm -rf node_modules/
remote
git是一個分散式程式碼管理工具,所以可以支援多個倉庫,在git裡,伺服器上的倉庫在本地稱之為remote。個人開發時,多源用的可能不多,但多源其實非常有用。

git remote add origin1 [email protected]:yanhaijing/data.js.git  
git remote    # 顯示全部源  
git remote -v # 顯示全部源+詳細資訊  
git remote rename origin1 origin2 # 重新命名  
git remote rm origin    # 刪除  
git remote show origin  # 檢視指定源的全部資訊  

標籤tag

當開發到一定階段時,給程式打標籤是非常棒的功能。

git tag -a v0.1 -m 'my version 1.4' # 新建帶註釋標籤   
git push origin --tags              # 一次性推送所有分支 
git push origin v1.5                # 推送單個tag到orgin源上 
git tag -v v1.4.2.1                 # 驗證標籤,驗證已經簽署的標籤
git show v1.5                       # 看到對應的 GPG 籤

git tag        # 列出現有標籤   
git tag v0gi.1 # 新建標籤   
git checkout tagname   # 切換到標籤       
git tag -d v0.1 # 刪除標籤   
git push origin :refs/tags/v0.1 # 刪除遠端標籤   
git pull --all # 獲取遠端所有內容包括tag  
git --git-dir='<絕對地址>/.git' describe --tags HEAD # 檢視本地版本資訊  

日誌log

git config format.pretty oneline  #顯示歷史記錄時,每個提交的資訊只顯示一行   
git config color.ui true #彩色的 git 輸出   
git log #檢視最近的提交日誌   
git log --pretty=oneline #單行顯示提交日誌   
git log --graph --pretty=oneline --abbrev-commit   
git log -num #顯示第幾條log(倒數)   
git reflog #檢視所有分支的所有操作記錄   
git log --since=1.day #一天內的提交;你可以給出各種時間格式,比如說具體的某一天(“2008-01-15”),或者是多久以前(“2 years 1 day 3 minutes ago”)。   
git log --pretty="%h - %s" --author=自己的名字 #檢視自己的日誌   
git log -p -2 #展開兩次更新顯示每次提交的內容差異   
git log --stat #要快速瀏覽其他協作者提交的更新都作了哪些改動   
git log --pretty=format:"%h - %an, %ar : %s"#定製要顯示的記錄格式   
git log --pretty=format:'%h : %s' --date-order --graph # 拓撲順序展示   
git log --pretty=format:'%h : %s - %ad' --date=short #日期YYYY-MM-DD顯示   
git log <last tag> HEAD --pretty=format:%s # 只顯示commit   
git config --global format.pretty '%h : %s - %ad' --date=short #日期YYYY-MM-DD顯示 寫入全域性配置
選項	說明	選項	說明
%H	提交物件(commit)的完整雜湊字串	%ad	作者修訂日期(可以用 -date= 選項定製格式)
%h	提交物件的簡短雜湊字串	%ar	作者修訂日期,按多久以前的方式顯示
%T	樹物件(tree)的完整雜湊字串	%cn	提交者(committer)的名字
%t	樹物件的簡短雜湊字串	%ce	提交者的電子郵件地址
%P	父物件(parent)的完整雜湊字串	%cd	提交日期
%p	父物件的簡短雜湊字串	%cr	提交日期,按多久以前的方式顯示
%an	作者(author)的名字	%s	提交說明
%ae	作者的電子郵件地址	-	-
Pretty Formats

重寫歷史

git commit --amend    # 改變最近一次提交  
git rebase -i HEAD~3  # 修改最近三次的提交說明,或者其中任意一次  
git commit --amend    # 儲存好了,這些指示很明確地告訴了你該幹什麼  
git rebase --continue # 修改提交說明,退出編輯器。  
pick f7f3f6d changed my name a bit
pick 310154e updated README formatting and added blame
pick a5f4a0d added cat-file
改成

pick 310154e updated README formatting and added blame
pick f7f3f6d changed my name a bit

刪除倉庫

cd ..
rm -rf repo.git

其它

git help *  # 獲取命令的幫助資訊  
git status  # 獲取當前的狀態,非常有用,因為git會提示接下來的能做的操作  

報錯問題解決

  1. git fatal: protocol error: bad line length character: No s

解決辦法:更換remote地址為 http/https 的

  1. The requested URL returned error: 403 Forbidden while accessing

解決github push錯誤的辦法:

#vim 編輯器開啟 當前專案中的config檔案
vim .git/config

#修改
[remote "origin"]  
    url = https://github.com/jaywcjlove/example.git  

#為下面程式碼
[remote "origin"]  
    url = https://[email protected]/jaywcjlove/example.git  
  1. git status 顯示中文問題

在檢視狀態的時候 git status 如果是中文就顯示下面的情況

\344\272\247\345\223\201\351\234\200\346\261\202

解決這個問題方法是:

git config --global core.quotepath false

今天就分享到這裡啦!感謝各位的閱讀!碼字不易,如果本文對你有幫助的話,幫忙點個贊吧~