Git是一個分布式文件版本管理系統。Git 直接記錄文件快照,而非差異比較,所以在切換分支速度極快,幾乎是秒切。所有操作基本上都是本地執行,時刻保持數據完整性,每臺機器上都有完整的 Git 提交歷史,即使不聯網,也能任意切換到歷史版本。多數操作僅添加數據,也就是說,操作都是可恢復的。
初始化目錄
# 創建空的 Git 目錄
git init
git add README
git commit -m 'initial project version'
# 或者使用 clone 方式從遠程復制一個
git clone git://git.kernel.org/pub/scm/git/git.git [mygit]
文件狀態
工作目錄下面的所有文件都不外乎這兩種狀態:已跟蹤或未跟蹤。已跟蹤的文件是指本來就被納入版本控制管理的文件,在上次快照中有它們的記錄,工作一段時間后,它們的狀態可能是未更新(nothing to commit),已修改(Changes not staged for committed)或者已放入暫存區(Changes to be committed)。而所有其他文件都屬于未跟蹤文件(Untracked files),它們既沒有上次更新時的快照,也不在當前的暫存區域。如下圖
-
README.txt
已放入暫存區,等待被提交。使用git commit -m 'change log'
提交 -
benchmarks.rb
已修改,但修改未放入暫存區。使用git add benchmarks.rb
添加到暫存區 -
b.txt
未根據,需要用命令git add b.txt
添加到暫存區。
需要注意的是,每次修改文件都需要執行git add filename
將修改添加到暫存區,而不僅僅只是新文件。也就是說,每次更改,都要執行兩個命令,git add
和git commit
才能將更改添加到版本庫中。一次完整的提交過程:
# 將當前目前下的所有更改添加到暫存區,或者根據情況,只添加某些文件的更改,將 . 換成文件名
git add .
# 將暫存區的內容添加到 Git 版本庫中,永久存儲。這一步無法選擇要提交哪些內容,所有暫存區的內容都會被提交。
git commit -m 'change log'
.gitignore
有時候,我們可能不想跟蹤一些文件,比如工程文件的配置文件,編譯生成的二進制文件。這些文件無需納入版本管理,否則在團隊協作,合并代碼時容易發生沖突。在項目的根目錄下,新建.gitignore
文件,將不需要跟蹤的文件添加到里面,如下:
# 此為注釋 – 將被 Git 忽略
# 忽略所有 .DS_Store 結尾的文件
*.DS_Store
# 但 lib.a 除外
!lib.a
# 僅僅忽略項目根目錄下的 TODO 文件,不包括 subdir/TODO
/TODO
# 忽略 build/ 目錄下的所有文件
build/
# 會忽略 doc/notes.txt 但不包括 doc/server/arch.txt
doc/*.txt
# ignore all .txt files in the doc/ directory
doc/**/*.txt
# A **/ pattern is available in Git since version 1.8.2.
如果在創建.gitignore
文件前,這些文件已經進入版本管理時,需要先將它們從暫存區中刪除:git rm —cached filename
或 git rm -rf —cached .
,讓.gitignore
生效。
對比
git diff
可以查看當前修改和某次提交之后都改動了哪些東西。
- 查看已暫存和未暫存的更新 :git diff
- 查看已暫存和上次提交時的快照之間的變化: git diff —cached 或 git diff —staged
- 對比當前提交和某個提交:git diff 99734f7ff
- 對比當前分支和其他某個分支:git diff test
查看提交歷史
- 查看提交日志,只列出時間和提交信息:git log
- 查看最近2次提交的歷史,并列出改動的內容差異:git log -p -2
- 以圖表的形式列出提交歷史: git log --oneline --graph
撤銷操作
- 修改最后一次提交信息:git commit --amend
- 取消已經暫存的文件:git reset HEAD filename
- 取消對文件的修改:git checkout -- filename
- 返回到某個節點,不保留修改:git reset --hard HASH
- 返回到某個節點,保留修改:git reset --soft HASH
遠程倉庫
- 查看:git remote -v
- 添加遠程倉庫:git remote add pb git://github.com/paulboone/ticgit.git
- 拉取遠程倉庫的代碼到本地倉庫:git fetch pb
- 修改遠程倉庫地址:git remote set-url origin git://github.com/newuser/ticgit.git
打標簽
每次推送一個新的版本到遠程倉庫的 master 時,需要打一個版本號的標簽。
- 查看標簽:git tag -l
- 打標簽:git tag -a v1.4 -m 'my version 1.4'
- 查看相應標簽的版本信息:git show v1.4
- 推送標簽到遠程:git push origin v1.5 或者 git push origin --tags
分支
在 Git 中提交時,會保存一個提交(commit)對象,該對象包含一個指向暫存內容快照的指針。Git 中的分支,本質上是個指向 commit 對象的可變指針。
新建分支
git branch test
git checkout test
# 或者直接 checkout -b, -b 參數表示新創建一個分支
git checkout -b test
合并分支
將 issue-1 分支合并到 master:
git checkout master
git merge issue-1
# 合并后刪除
git branch -d issue-1
沖突解決
在merge
代碼的時候,如果兩個分支對同一行文件做了不一樣的修改,便會產生沖突。解決沖突需要人為介入,編輯沖突的文件,選擇正確的一行代碼,然后重新提交。
如果代碼產生沖突,沖突的文件會出現類似下面的內容:
<<<<<<< HEAD
<div id="footer">contact us at support@github.com</div>
=======
<div id="footer">
please contact us at support@github.com
</div>
>>>>>>> issue-1
<<<<<<< HEAD
到=======
之間是當前分支的代碼,=======
到>>>>>>> issue-1
是issue-1
分支的代碼,這行代碼不一致,這里我們選擇issue-1
的代碼,修改后這幾行變為
<div id="footer">
please contact us at support@github.com
</div>
修改完之后,運行git add .; git commit -m 'merged'
提交當前修改后的代碼,沖突便解決了,代碼也合并了。
管理分支
列出當前所有本地分支: git branch
包含各分支最后提交信息: git branch -v
查看當前分支已合并的分支: git branch --merged
刪除分支:git branch -d testing
遠程分支
遠程分支(remote branch)是對遠程倉庫中的分支的索引,遠程分支的表示形式:(遠程倉庫名)/(分支名) 。如 origin/master,origin 是遠程倉庫名,master是分支名。
查看遠程分支: git branch -r
推送本地分支: git push origin master
拉取遠程分支并合并到當前分支:git pull origin master
獲取遠程代碼到本地倉庫:git fetch origin
合并遠程分支到本地分支代碼:git merge origin/master
本地新建遠程分支:git checkout -b hotfix origin/master # 從遠程 master 分支上新建本地 hotfix 分支
刪除遠程分支,在分支名前加冒號:git push origin :hotfix # 刪除遠程 hostfix 分支
git pull = git fetch + git merge
Stash
要切換到其他分支又不提交當前的修改時,使用 git stash 保存當前修改到一個堆棧中,需要時重新應用修改
- 保存修改:git stash
- 應用保存起來的修改:git stash apply 或 git stash pop
- 查看已保存的stashing:git stash list
- 刪除stash:git stash drop