Git的理解和使用
Git介紹
Git(the stupid content tracker)是一個源自Linux核心專案的原始碼管理工具。和傳統的CVS、SVN不同,git是一個分散式原始碼管理工具。
Git命令 | 簡單說明 |
---|---|
git init | 初始化一個本地的程式碼倉庫。 |
git clone | 從遠端複製一個程式碼倉庫。 |
git config | git選項設定。 |
git add | 新增檔案/目錄。 |
git commit | 提交修改。 |
git status | 顯示工作目錄的狀態以及緩衝區內的快照。 |
git log | 已提交快照的日誌。 |
git branch | 建立分支。 |
git checkout | 遷出/拉出/切換到一個分支。 |
git merge | 合併分支。 |
git revert | 撤銷commit快照。 |
git reset | 撤銷本地工作目錄的修改。 |
git clean | 刪除程式碼倉庫以外的檔案。 |
git remote | 管理遠端git。 |
git fetch | 從遠端獲取分支。 |
git pull | 從遠端獲取分支。 |
git push | 把程式碼推到遠端分支。 |
這裡列舉幾個常見的git命令,讓大家過過目
基本操作
git init //初始化版本庫
git clone //克隆版本庫
07 >git add //新增新檔案
git commit //提交到本地版本庫
git checkout //檢出(分支、標籤)
分支
git branch //列出分支
git branch -r //列出遠端分支
git branch -a //列出所有分支
git branch newBranch //基於當前分支建立新分支newBranch
git branch -D branchName //刪除分支branchName
git branch -d branchName //僅刪除已合併分支branchName
git merge <--> //合併分支<br>>git tag
歷史
git log //顯示全部歷史
git log -p //顯示版本歷史,以及版本間的內容差異
git log -5 //顯示最近的5個提交
git log -5 -p //顯示最近的5個提交,以及版本間的內容差異
...(很多很多引數...)
git diff 112 115 //顯示112和115版本的差別
基本概念
檔案狀態
Git倉庫中的檔案有幾種狀態:
- untracked - 還沒新增到倉庫中。
- unmodified - 自上次提交以來,檔案未曾修改過。
- modified - 檔案修改了還沒提交。
- staged - 檔案提交到了暫存區中。一旦執行git commit就會轉換為unmodified狀態。
當我們往工作目錄新增一個檔案的時候,這個檔案預設是未跟蹤狀態的,我們肯定不希望編譯生成的一大堆臨時檔案預設被跟蹤還要我們每次手動將這些檔案清除出去。用以下命令可以跟蹤檔案:
git add <file>
Git暫存區(Staged Area)的意思是:你把一個檔案託付給Git跟蹤(git add),然後又修改了它,此時這個檔案就位於暫存區了。暫存區內的檔案幾乎只做一件事:等待你執行git commit,把它提交。
上圖中右邊3個狀態都是已跟蹤狀態,其中的灰色箭頭只表示untracked<-->tracked的轉換而不是untracked<-->unmodified的轉換,新新增的檔案肯定算是被修改過的。那麼,staged狀態又是什麼呢?這就要搞清楚GIT的三個工作區域:本地資料(倉庫)目錄,工作目錄,暫存區,如下圖所示:
git directory就是我們的本地倉庫.git目錄,裡面儲存了所有的版本資訊等內容。
working driectory,工作目錄,就是我們的工作目錄,其中包括未跟蹤檔案及已跟蹤檔案,而已跟蹤檔案都是從git directory取出來的檔案的某一個版本或新跟蹤的檔案。
staging area,暫存區,不對應一個具體目錄,其時只是git directory中的一個特殊檔案。
當我們修改了一些檔案後,要將其放入暫存區然後才能提交,每次提交時其實都是提交暫存區的檔案到git倉庫,然後清除暫存區。而checkout某一版本時,這一版本的檔案就從git倉庫取出來放到了我們的工作目錄。
快照(snapshot)
Git與其他版本控制系統的區別在於:Git只關心檔案是否變化,而不關心檔案內容的變化。大多數版本控制系統都會忠實地記錄版本間的檔案差異(diff),但Git不關心這些具體差異(哪一行有什麼變動),Git只關心哪些檔案修改了哪些沒有修改,修改了的檔案直接複製形成新的blob(這就是所謂的快照snapshot)。當你需要切換到或拉出一個分支時,Git就直接載入當時的檔案快照即可,這就是Git快的原因。說起來,這也是用空間換取時間的經典案例。
從這個角度看,Git更像是一個小型檔案系統,並在這個系統上提供一系列的工具來輔助開發。
Git的地理觀
Git是一個分散式的版本控制系統,因此沒有所謂的中心。粗略來看Git可分為本地庫(local repository)和遠端庫(remote repository),細緻地看可分為以下幾個部分:
- Working Directory - 工作目錄。Git倉庫位於工作目錄之下,工作目錄下的檔案有加入Git倉庫(tracked)和沒加入Git倉庫(untracked)的區別。
- Stage Area - 暫存區。如上所述,已加入Git倉庫並被修改(尚未提交)的檔案。
- Local Repository - 本地倉庫。
- Remote Repository - 遠端倉庫。
檔案通常是:加入Git倉庫(git add)-> 修改後即位於暫存區 -> 提交到本地庫(git commit) -> 推送到遠端庫(git push)。
origin/master
這裡主要筆記一些在Git上下文中經常遇見的術語。origin/master指遠端倉庫origin的master分支。
遠端倉庫/分支
這樣的形式。雖然Git是分散式的系統,但通常把git clone的源頭叫做origin,origin也被視為中心倉庫(Central Repository)。
git入門
建立目錄,並用git init
初始化:
$ mkdir learn-git && cd learn-git $ git init Initialized empty Git repository in /tmp/learn-git/.git/
從git init
輸出可知,git
建立了一個名為.git
的隱藏目錄。
建立一個檔案,並用git add
新增到倉庫,用git
commit
提交:
$ echo "hello git" > README.txt $ git add . $ git commit -m "readme file" [master (root-commit) cd27ac1] readme file 1 file changed, 1 insertion(+) create mode 100644 README.txt
接下來對已提交檔案做一些修改,並新新增一個檔案:
$ echo "learn files here" >> README.txt $ cp ~/.vimrc .
用git diff
檢視檔案差異(每次commit前應該先diff對比差異詳情):
$ git diff diff --git a/README.txt b/README.txt index 8d0e412..0219596 100644 --- a/README.txt +++ b/README.txt @@ -1 +1,2 @@ hello git +learn files here
差異對比可以用git diff --cached
儲存下來(如此差異則不輸出到螢幕)。
用git status
檢視git倉庫狀態:
$ 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 # # Untracked files: # (use "git add <file>..." to include in what will be committed) # # .vimrc no changes added to commit (use "git add" and/or "git commit -a")
這裡顯示README.txt
被修改了,而.vimrc
則等待新增。接下來,我們將.vimrc
新增到git倉庫中,且將所有修改一併提交(git
commit -a
):
$ git commit -a -m "update readme && add vimrc" [master f6162f0] update readme && add vimrc 2 files changed, 123 insertions(+) create mode 100755 .vimrc
git log
輸出git日誌,包括提交編號(如"f6162f04170e3665bc03744e43f764c903e4e38d"這樣的字串)、提交者、提交日期和提交日誌。
git log
的其他輸出:
$ git log -p # 詳細日誌,並輸出到分頁程式 $ git log --stat --summary
美化git log輸出
$ git log --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' --abbrev-commit --
修改全域性配置:
$ 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 branch exp
檢視當前git倉庫的所有分支:
$ git branch exp * master
切換到exp
分支:
$ git checkout exp Switched to branch 'exp'
修改檔案,並提交:
$ echo "start branch: exp" >> README.txt $ git commit -a -m "modified readme in exp branch" [exp 2e825a4] modified readme in exp branch 1 file changed, 1 insertion(+)
切換回master
分支:
$ git checkout master Switched to branch 'master'
在master
分支檢查檔案,可見exp
分支的修改並沒影響到master
分支(注意,在exp分支的修改都已提交;如果沒有提交,則切換回master分支會看到檔案已變)。接下來我們製造一個衝突:
$ echo "return branch: master" >> README.txt $ git commit -a -m "modified readme in master branch" [master 8dd9fb2] modified readme in master branch 1 file changed, 1 insertion(+)
用git merge exp
合併分支:
$ git merge exp Auto-merging README.txt CONFLICT (content): Merge conflict in README.txt Automatic merge failed; fix conflicts and then commit the result.
從git輸出可見,git嘗試自動合併但失敗了,因此提示需要解決衝突再提交
用git diff
檢視差異,且差異檔案被修改:
$ git diff ... $ cat README.txt hello git learn files here <<<<<<< HEAD return branch: master ======= start branch: exp >>>>>>> exp
手工解決衝突並再次提交:
(edit file) $ git commit -a -m "do merge"
接下來,可以刪除exp
分支:
$ git branch -d exp Deleted branch exp (was 2e825a4).
git branch -d
刪除分支時會檢查分支是否完全合併到主幹,如果不是,則會刪除失敗,並提示需要合併:
$ git branch exp # 建立exp分支 $ git checkout exp # 切換到exp分支 $ echo "exp again" >> README.txt # 修改並提交 $ git commit -a -m "exp again" [exp 868e68c] exp again 1 file changed, 1 insertion(+) $ git checkout master # 切換回master Switched to branch 'master' $ git branch -d exp # 刪除失敗 error: The branch 'exp' is not fully merged. If you are sure you want to delete it, run 'git branch -D exp'.
可以用git branch -D exp
忽略修改,完全刪除分支:
$ git branch -D exp Deleted branch exp (was 868e68c).
檢視遠端git
基礎命令是:git remote show, git remote show X。
$ git remote show
origin
web
檢視GitHub預設設定的origin
$ git remote show origin * remote origin Fetch URL: git@github.com:berlinix/blog.git Push URL: git@github.com:berlinix/blog.git HEAD branch: master Remote branch: master tracked Local branch configured for 'git pull': master merges with remote master Local ref configured for 'git push': master pushes to master (fast-forwardable)
git命令快查
以下列出一些常用的git命令
命令 | 說明 |
---|---|
基礎操作 | |
git init | 初始化git倉庫 |
git add X | 新增X檔案/路徑到git倉庫 |
git commit -m "COMMENTS" | 提交更新 |
分支管理 | |
git branch X | 建立一個名為X的分支 |
git checkout X | 切換到X分支 |
git merge X | 自動合併X分支 |
git branch -d X | 刪除X分支,需要先merge |
git branch -D X | 強制刪除X分支,忽略其修改,無須先merge |
與遠端git互動 | |
git remote show | 顯示遠端git倉庫 |
git remote show X | 顯示遠端git一個名為X的倉庫 |
git push origin master | 更新提交到GitHub |
Git日常問題
撤銷commit
剛與master合併並提交後就後悔了現在要做的是撤銷commit(revoke/undo merge/commit)。
檢視當前所在分支:
$ git branch bs3 * coin dev master
檢視日誌:
$ git log --oneline 9b7ba39 merged with master 73a66e8 update FAQ
用以下2個命令來撤銷提交(把COMMIT_SHA替換為實際的SHA值;把HEAD~N中的N替換為一個數字,表示回退幾步):
$ git reset --hard COMMIT_SHA $ git reset --hard HEAD~N
例如回退到合併前:
$ git reset --hard 73a66e8 HEAD is now at 73a66e8 update FAQ
回退後發現不對,因為現在這個commit還是在master中的(在merge之前master已經走的太遠),趕緊再次reset到merge時的狀態:
$ git reset --hard 9b7ba39 HEAD is now at 9b7ba39 merged with master
如此一來就是就是merge後commit之前的狀態。接下來就是要完成undo merge(已經undo commit了):
$ git revert -m 1 9b7ba39
這下就徹底回到merge前了,以防萬一再次檢查:
$ git diff --name-status master..coin
看起來沒什麼問題了,檢查下日誌:
$ git log --oneline 2691516 Revert "merged with master" 9b7ba39 merged with master 73a66e8 update FAQ
用git找回已刪除檔案
首先找到與目標檔案相關的最後一次commit。如果目標檔案沒有出現在HEAD commit中,那麼在這次commit時,檔案就被刪除了:
$ git rev-list -n 1 HEAD -- htdocs/myfile.php 1e8182f58dc038c8e6bc2025e8430f463d372030
接下來就是恢復工作了:
$ git checkout 1e8182f58dc038c8e6bc2025e8430f463d372030^ -- htdocs/myfile.php
合併分支的部分檔案
有時候只想合併分支裡的部分檔案,而不是整個分支,可以用這個命令:
git checkout BRANCH FILE ...
例如,從test_branch分支中合併file_modified檔案:
$ git checkout test_branch file_modified
參考Git Tip: How to "Merge" Specific Files from Another Branch。
相關文章
- git:rebase(變基)的使用和理解Git
- git的理解Git
- Git理解Git
- promise的理解和使用Promise
- NSProxy的理解和使用
- 【git revert】使用以及理解(詳解)Git
- Git詳解和Github的使用Github
- 全面理解GitGit
- redis api的使用和理解RedisAPI
- 圖解git,用手繪圖帶你理解git中分支的原理和應用圖解Git繪圖
- 簡單對比git pull和git pull --rebase的使用Git
- 理解Git的工作流程Git
- Git命令的使用和相關配置Git
- git的使用命令和講解Git
- python 程式的使用和理解Python
- 深入理解 GitGit
- 如何理解git rebase?Git
- git 生成patch和使用patchGit
- [Git] Git整理(四) git rebase 的使用Git
- 對git的rebase(變基)的理解Git
- redis list 使用和理解Redis
- git使用之一——git的基本使用Git
- git的使用Git
- git 的使用Git
- git的使用+Git
- ES6 Promise的使用和理解Promise
- 三、Quartz中Scheduler的理解和使用quartz
- 正確使用Github 的方法 + Git 和 GitHub 教程和技巧Github
- git安裝及配置教程 windows windows上git的安裝和使用GitWindows
- 理解Git工作流Git
- 使用nginx反向代理docker中的git和redmineNginxDockerGit
- 對比git rm和rm的使用區別Git
- 探索 .git 目錄,讓你真正理解 gitGit
- 探索 .git 目錄,讓你真正了理解gitGit
- 理解和使用SQL Server中的並行SQLServer並行
- Git,Github和Gitlab簡介和基本使用GithubGitlab
- git rebase的使用Git
- Git的日常使用Git