本文按照 設(shè)置工程、分支與合并、本地操作、分享和更新 四步來簡單說一下 Git 基本命令的用法。
- Git 命令參考手冊;
- A Visual Git Reference(不錯(cuò));
- Pro Git 2nd Edition (2014);
- NDP Software git-cheatsheet (Andrew Peterson);
- Getting Git Right @ Atlassian;
- Commit Often, Perfect Later, Publish Once: Git Best Practices;
- Git 有很多 GUI 客戶端軟件。git 包中通常包含 git gui 和 gitk 這兩個(gè)內(nèi)置 tools。
注:git 命令如此之豐富,可以說,不論你有什么需求,遇到些什么問題,通過查命令都可以解決。如果命令一時(shí)看不懂,則 Google 一下或者直接上 stackoverflow,別人的做法會(huì)給你啟發(fā)。
一句話,有問題不是事兒。不但不是事兒,反而是 get 新技能的契機(jī)。
命令幫助
每個(gè)命令的 Examples 部分是一個(gè)很好的學(xué)習(xí)命令使用的示例。
- git --help
- git <command> -h,git <command> --help
- git branch
- git checkout -h
- git clone -h
- git commit -h
- git config
- git difftool
- git fetch
- git log -h
- git show
- git ls-files
- git merge -h
- git pull -h
- git push -h
- git remote 查看遠(yuǎn)程路徑
- git reset
- git status
使用 git 命令行?還是 GUI 工具?
命令行對(duì) git 所有命令都適用,也最安全,不容易出問題;而圖形界面工具則不一定了,不過常用命令沒什么大問題。
設(shè)置運(yùn)行環(huán)境
git config --global user.name "
your name" ; 設(shè)置你的稱呼
git config --global user.email "your_email@example.com" ;設(shè)置你的郵箱;
git config --global push.default simple ;This is the safest option and is suited for beginners. 在 git push 時(shí)不必指定 [<repository> [<refspec>...]]
git config --global core.quotepath false ;解決 Windows Git Bash、Linux 下的中文轉(zhuǎn)碼問題;
git config --global core.editor /usr/bin/vim ;OS X 下 merge 命令 vi error 問題;通常 core.editor=vim。
git config --global core.autocrlf true ;Win Git Bash 時(shí)設(shè)置,見 git replacing LF with CRLF。
git config --unset ;清除設(shè)置項(xiàng)。
git config --global credential.helper wincred ;Win Git Bash 啟用 http/https 協(xié)議時(shí)設(shè)置。
git config -l ;查看所有的(name.key)/(value) -l | --list
設(shè)置工程(Clone repositories)
-
git clone ; 從遠(yuǎn)程復(fù)制資源庫到本地庫。
git clone <repository> [<directory>]
1. repository:遠(yuǎn)程庫地址;
2. directory:本地目錄名;不指定,則默認(rèn)為遠(yuǎn)程庫名。如果目錄已存在則必須是一個(gè)空目錄;
# ssh:// URL 形式,看起來和 https URL 形式相似。ssh 需要的私鑰文件在 ~/.ssh/config 文件中由 IdentityFile 參數(shù)指定。
git clone ssh://user@gitserver/path/to/project.git
# 示例:git clone ssh://192.168.99.236/home/git/wanpinghui/wphdoc.git
# scp-like 語法
git clone user@gitserver:/path/to/project.git
# 示例:git clone 192.168.99.236:/home/git/wanpinghui/wphdoc.git
服務(wù)器的 git 庫約定以 .git 結(jié)尾,clone 后的工作區(qū)中的 git 庫則不包含 .git。
-
設(shè)置 .gitignore 文件
在該文件中,設(shè)置 commit 時(shí)要忽略的文件匹配模式,避免提交一些臨時(shí)文件到庫里。
# 在工程根目錄下建一個(gè)文件 .gitignore,是一個(gè)受控文件。以下為文件內(nèi)容示例。
# 忽略 PHP 臨時(shí)工作文件
.buildpath
.project
.settings/
# 忽略 Mac 臨時(shí)工作文件
.DS_Store
- build和lib 實(shí)際上是空文件夾,保留.gitkeep僅為在 git 上受控。
# cat .gitignore
build/*
!build/.gitkeep
lib/*
!lib/.gitkeep
git ls-files -o -i -X .gitignore 僅查看 ignored 的文件,匹配模式從 .gitignore 文件中獲?。?-others,--ignored,--exclude-from)。了解 git ls-files。
git status --ignored 也會(huì)列出 ignored 的文件;了解 git status。
git ls-files -o --directory 可以查看非受控文件和目錄列表(--others)。
分支與合并(Create branches)
git branch; 看本地當(dāng)前分支( local branches)情況,以及當(dāng)前工作區(qū)位于哪個(gè)分支。
git branch -r看遠(yuǎn)程跟蹤分支(remote-tracking branches)情況,--remotes。
git branch -d <branch>;刪除 <branch>,--delete;
git branch -a;查看本地和遠(yuǎn)程所有分支情況,--all;
git branch -m <new-branch-name>:修改當(dāng)前分支名,詳見 How To Change Branch Name on Git。git checkout <branch>;將工作區(qū)切換到分支,這有點(diǎn)類似于 svn checkout。master 也是一個(gè)分支。
示例:git checkout v0.1 ; v0.1 表示分支名稱。git branch <new_branch> [<start-point>]; 在本地開分支。注意:僅僅開分支,并不自動(dòng)將工作區(qū)切換到分支;[<start-point>] 表示從哪里開始分支,默認(rèn)指向當(dāng)前 HEAD;
git branch v0.7e v0.7d,表示 從 v0.7d 開一個(gè)新分支 v0.7e;git checkout -b <new_branch> [<start-point>];開后即刻簽出;
git merge(合并)
Join two or more development histories together。git reset --merge: 在git merge iwifi合并分支操作后,你發(fā)現(xiàn)有問題,則執(zhí)行此句可立馬恢復(fù)所做的合并。git reset 恢復(fù)
git reset [<commit>] 在沒有 push 前將本地庫恢復(fù)到指定 <commit>。-
git log --name-status --oneline常用命令
可以查看變化的文件列表 git log --pretty=oneline|medium
列出 commit 全值,以便類似于 svn 取出指定 revision,甚至某一個(gè)文件:git checkout <commit> [path/file]。git log --patchgit log --stat (列出簡略的統(tǒng)計(jì)數(shù)據(jù):abbreviated stats for each commit)
git shortlog
在工作區(qū)和本地庫操作(Basic Snapshotting | Commit changes)
- git add ; 新文件或者本地修改了的文件,都需要 add。
-
git status
git status -s ; Short Status -
git commit
git commit -m '注釋':--message
git commit -uno:不要列出 untracked-files
git commit -a -m '注釋';-a | --all 表示包含所有 modified and deleted files,但新文件需提前 git add。相比添加文件,修改文件是個(gè)更常見動(dòng)作,加 -a 參數(shù)即可省略 git add。
分享和更新(Share code)
將你的修改分享出去到遠(yuǎn)程庫和從遠(yuǎn)程庫更新到本地庫。
-
git fetch(下載)
Download objects and refs from another repository 從遠(yuǎn)程主機(jī)將變更下載到本地,但不進(jìn)行合并。 - git push --set-upstream origin v0.1 ; set upstream for git pull/status, [-u | --set-upstream].
Pushing to Your Remotes 將你本地的變更推送到遠(yuǎn)程主機(jī)。多人協(xié)同開發(fā),請(qǐng)及時(shí) push。 - git pull [<repository> [<refspec>...]] (常用)
Fetch from and integrate with another repository or a local branch 從遠(yuǎn)程主機(jī)將變更取到本地庫,同時(shí)進(jìn)行合并。pull 實(shí)際是把 fetch 和 merge 兩個(gè)命令的操作放到一個(gè)命令里了。使用 pull 通常沒有太大問題。不過仍然建議分開使用 fetch and merge。
示例:git pull origin v0.1 ; 從遠(yuǎn)程 origin 的分支 v0.1 更新到本地庫 - git remote -v
$ git remote --verbose
origin git@192.168.1.91:/path/to/wphdoc.git (fetch)
origin git@192.168.1.91:/path/to/wphdoc.git (push)
- 遠(yuǎn)程地址變化
git remote set-url origin <新地址>或者remove+add。
git tag
- 打 Tag 是很容易的,tag 其實(shí)就是一個(gè) commit 的別名;自然刪除 tag 也是極容易的;
- 打 Tag:
git tag -m <tag name> [<commit>]- 其中 -m <msg> 表示 tag 備注,每個(gè)tag都必須給出說明。多個(gè) -m 就是多個(gè)段落,對(duì) tag 可以有了更詳細(xì)的描述。
- 推送到遠(yuǎn)程:
git push <remote> <tag name> - 對(duì)于 GitHub 來說,打了一個(gè) Tag 就有了一個(gè) Release;
- 在 GitHub 上通過自定義腳本,可以同步更新 Packagist 上的 composer 包;
- GitHub 上的 Release 的命名有類似 v1.8的,也有 1.8,1.8-rc1 的;
文件對(duì)比 git diff
在開發(fā)中,經(jīng)常會(huì)修改文件,提交時(shí)或者 review 時(shí)也就經(jīng)常需要對(duì)比文件:
- 工作區(qū)和庫中比對(duì)
- 在不同 commit 間比對(duì)
- 在不同 branch 間比對(duì)(branch 也是一個(gè) commit,故也是 commit 比對(duì))
-
git diff --name-only# 列出有變化的文件;
How to list only the file names that changed between two commits? - vim -p
git diff --name-only
vim 編輯所有有變化的文件,編輯時(shí),一個(gè)文件一個(gè)tab。 -
git diff HEAD
See the difference between your current files and your last commit. -
git diff --staged
See the difference between your staged files and your last commit. -
git stash
Temporarily store changes in a "dirty" working directory.
使用 git diff 進(jìn)行比對(duì)的可視化程度比較低,不論 markdown(md) 文檔還是 code,都差強(qiáng)人意。相反 git difftool 卻值得推薦。
使用 git difftool
使用第三方的 difftool 來進(jìn)行比對(duì),我們選用 vimdiff 這個(gè)比對(duì)工具。vimdiff 一般就是一個(gè) vim 的 link。也就是說 vim 編輯器本身是支持進(jìn)行文件比對(duì)的。vim 是一個(gè)程序員絕對(duì)要熟悉的工具。
- vim --help
- Vim Cheat Sheet;
- 配置 difftool
git config --global diff.tool vimdiff
git config --global merge.tool vimdiff
git config --global difftool.prompt false
difftool.prompt 關(guān)閉提示是必要的。你在執(zhí)行 git difftool 命令時(shí),如果有多個(gè)待比對(duì)文件,則每次 vim 啟動(dòng)比對(duì)時(shí)都詢問,你會(huì)感到不爽的。關(guān)閉提示最好。當(dāng)然 git difftool --no-prompt 也可以。
git difftool .
git difftool <specific file>
git difftool <commit> [<commit>] [path]
git difftool HEAD^ # HEAD 和其前一次 commit 比對(duì),即查看最新一次提交的修改記錄;
- 比對(duì)時(shí),查看不同點(diǎn)的快捷鍵
[c上一個(gè)不同點(diǎn)
]c下一個(gè)不同點(diǎn)
關(guān)于導(dǎo)出代碼
- git checkout-index;
-
Do a “git export” (like “svn export”)?
直接導(dǎo)出純代碼,不包含.git等歷史記錄和控制信息。
git checkout-index -a -f --prefix=/destination/path/
注意:path 后面必須有/,作為最后一級(jí)目錄,path 必須未創(chuàng)建。如果 path 已經(jīng)創(chuàng)建或者path后面沒有/,就會(huì)簽出到 /destination/目錄下,簽出的文件和目錄以 path 作為前綴。
關(guān)于 checkout 的 examples(放棄修改,重新簽出文件)
The following sequence checks out the master branch, reverts the Makefile to two revisions back, deletes hello.c by mistake, and gets it back from the index.
$ git checkout master **(1)**
$ git checkout master~2 Makefile **(2)**
$ rm -f hello.c
$ git checkout hello.c **(3)**
(1) switch branch
(2) take a file out of another commit
(3) restore hello.c from the index
簽出某一個(gè) branch 或者 commit 下的 某個(gè)文件
git checkout <branch|commit> [path/file]工作區(qū)的修改(放棄修改)
git checkout <filename>:放棄指定文件;
git checkout .:放棄所有修改;
git checkout -- .:放棄當(dāng)前目錄及其子目錄下的修改;本地庫的修改
如果文件已經(jīng)提交,但尚未 push 到遠(yuǎn)程,則 git reset <commit> 即可(這個(gè)commit 之后所做的修改都保留在工作區(qū),即默認(rèn) --soft?;貪L到上次就是git reset HEAD^),git reset --hard <commit> 則直接放棄所做修改(慎重)。
問題:Git cannot add a completely empty directory
Git 不支持加一個(gè)空目錄,原因是 Git 處理的是文件,Git 不把目錄作為對(duì)象進(jìn)行處理。建議你在空目錄下加一個(gè) .gitignore 文件,提交上去即可,那個(gè)目錄看起來是一個(gè)空目錄。
# Ignore everything in this directory
*
# Except this file
!.gitignore
注:如果你連 .gitignore 也不想加,通過 touch README.md 加一個(gè)零字節(jié)空文件也不是不行。
使用 git fetch 查看遠(yuǎn)程庫有否修改
有時(shí)候,你僅僅想 查看一下遠(yuǎn)程庫有否修改,而不想對(duì)本地做任何更改,使用 git fetch 即可。
$ git status
On branch v0.3
Your branch is up-to-date with 'origin/v0.3'.
nothing to commit, working directory clean
從以上 git status 的輸出可以看到,本地沒有變更。下面看一下 git fetch 的輸出:
$ git fetch --dry-run --verbose
POST git-upload-pack (957 bytes)
remote: Counting objects: 1194, done.
remote: Compressing objects: 100% (12/12), done.
remote: Total 1194 (delta 13), reused 12 (delta 12), pack-reused 1170
Receiving objects: 100% (1194/1194), 9.05 MiB | 740.00 KiB/s, done.
Resolving deltas: 100% (751/751), completed with 7 local objects.
From https://github.com/w..p...h../web
cc796ed..19cc48e v0.3 -> origin/v0.3
= [up to date] master -> origin/master
以上 git fetch 的輸出可以看到,本地 v0.3 缺少從 cc796ed 直到 19cc48e 的 commits,即遠(yuǎn)程庫有修改。
使用 git fetch 下載,可以查看每次 commit 的修改記錄
$ git fetch origin v0.3
From https://github.com/w..p...h../web
* branch v0.3 -> FETCH_HEAD
cc796ed..19cc48e v0.3 -> origin/v0.3
$ git status
On branch v0.3
Your branch is behind 'origin/v0.3' by 133 commits, and can be fast-forwarded.
(use "git pull" to update your local branch)
nothing to commit, working directory clean
$ git log FETCH_HEAD
(略) 你就能看到遠(yuǎn)程庫所做的修改;
git remote update && git status
git remote;
stackoverflow: Check if pull needed in Git;
stackoverflow: check for changes on remote;git remote show <remote>查看遠(yuǎn)程 <remote> 的狀態(tài)
示例:git remote show origin | grep -e 'local out of date' 表示本地已落后。git remote set-url origin 新的遠(yuǎn)程倉庫地址。變更后使用git remote -v查看即可看到已更新。
請(qǐng)區(qū)別 HEAD | origin/HEAD | origin/master:
- git reset --hard HEAD
- git reset --hard origin/HEAD
- git reset --hard origin/master
關(guān)于 git log
從 Viewing the Commit History 了解 git log 比較容易。
- --decorate: Print out the ref names of any commits that are shown.
- --all: Pretend as if all the refs in refs/ are listed on the command line as <commit>.
git log --pretty=oneline --decorate --all -3
7055c613f081be5bd063d4695bbd2f9e593039bd (origin/v0.3, origin/HEAD) 修改個(gè)人信息頁
5e8668d78c92875d9efc5707f5fadb4a071f9b36 (HEAD -> v0.3) 為了遷就壓縮,js統(tǒng)統(tǒng)放到dists目錄下
f2882da667ba6d3a83edd331c8e51317b053f9b5 @@include參數(shù)必須用雙引號(hào),單引號(hào)發(fā)布失敗

-
git log --name-status --oneline --decorate --graph --all
查看所有分支情況,簡單、清晰圖形標(biāo)識(shí)分支; -
git log --name-status -n 5 --pretty=format:"%an %ad %s"
列出發(fā)生變更的文件的名字及其狀態(tài),限于 5 個(gè) commits,格式:author name, author date, subject。這個(gè)和 svn 格式比較貼近。通過 git config --global format.pretty "%an %ad %s" 設(shè)置格式。
如何搜索查看已刪除文件?
有時(shí)我們刪除了一個(gè)文件,但又記不起在哪個(gè) commit 刪除的,怎么辦?
-
git log --all **/<filename>
git log --all --name-status **/*<partoffilename>*
--name-status 列出文件目錄,**/表示任意路徑; - Get a list of the deleted files and copy the full path of the deleted file.
git log --diff-filter=D --summary | grep delete
