關於git的基本理解
git:一種分佈式版本控制系統
git保存的是每一次改動,而不是文件本身。
git有三個區:
工作區(Working Directory)
這個區就是你在電腦上創建項目的地方,文件的編輯修改都在這個區中進行。
暫存區(Stage Area)
暫存區存放的是待提交到repo的修改,當你使用git add命令時,就是把工作區的修改添加到暫存區。
版本庫/倉庫(Git Directory/Repository)
每次使用git commit命令,就是把暫存區中的內容全部提交到repo中。
關於分支:
新建分支默認是master。
master分支應該是一個穩定的,可用的應用,平時不在這個分支上工作。
當要添加新功能時,可從master分支新建一個分支,如feature分支,當新功能完成時,再合併到master分支上,這樣,master分支始終是穩定可用的。
多人合作時,可以每個人在各自的分支上工作,時不時合併到同一個分支上,當功能完善時,再合併到master分支。
分支之間大概是這種感覺(假設A、B兩個人開發):
當master分支上的應用出現bug時,可以在master分支上新建一個bug分支,如issue-101,修復bug後再合併到master分支上,然後刪除bug分支。
基本流程
假設你已經安裝了git
以下考慮最基本的git使用流程,開發時遇到的情況很多,以下流程暫不列出刪除、撤銷、回退的步驟,後面再單獨列出來。
暫不考慮多人合作與遠程repo,後面再補充,因爲了解了怎麼自己玩git,也就明白怎麼跟基友一起玩github了。
因此以下流程都是在本地進行,跟github啥的暫時沒什麼關係。
新建repo->修改文件->添加修改到暫存區->提交修改到repo->創建分支->修改文件->添加修改到暫存區->提交修改到repo->合併分支->解決衝突
創建bug分支->修復bug->合併分支
流程步驟
新建repo
在項目根目錄下使用git init
初始化git倉庫
修改文件
我們在項目目錄下新建一個hello.txt文件,裏面輸入內容hello world
(注意不要用Windows自帶的記事本創建、編輯)
然後輸入git status
,會看到輸出了這些信息:
On branch master
Initial commit
Untracked files:
(use "git add <file>..." to include in what will be committed)
hello.txt
nothing added to commit but untracked files present (use "git add" to track)
這邊git提示我們有一個Untracked file,可以用git add <file>
來添加要提交的文件。
添加修改到暫存區
按照提示,我們輸入git add hello.txt
把文件添加到暫存區(使用git add .
添加更改過的全部文件)
再次輸入git status
,這次看到輸出信息:
On branch master
Initial commit
Changes to be committed:
(use "git rm --cached <file>..." to unstage)
new file: hello.txt
hello.txt已經被存放到暫存區了
提交修改到repo
使用git commit -m 'add hello.txt'
來提交這個文件的更改
輸出信息:
[master (root-commit) 88aa3e8] add hello.txt
1 file changed, 1 insertion(+)
create mode 100644 hello.txt
這時候,文件的更改已經提交到repo中。
創建分支
在master分支下:
git checkout -b feature
創建並切換到feature分支
創建分支是git branch feature
,創建feature分支
切換分支是git checkout feature
,切換到feature分支
合併分支
我們切換到feature分支,git checkout feature
打開剛纔的hello.txt
把內容修改成goodbye world
然後用git add
跟git commit
命令提交到repo中
切換到master分支,在hello.txt文件結尾加上一行hello world again
,然後提交
這時候,兩個分支各有一個提交(commit)
我們切換到master分支git checkout master
然後把feature分支合併到master分支上,git merge --no-ff -m 'merge feature' feature
這時候會提示有衝突:
Auto-merging hello.txt
CONFLICT (content): Merge conflict in hello.txt
Automatic merge failed; fix conflicts and then commit the result.
git提示我們解決了衝突再把結果commit。
解決衝突
衝突在多人合作中應該是常有的事。
我們打開hello.txt,發現內容變成了這樣
hello world
<<<<<<< HEAD
hello world again
=======
goodbye world
>>>>>>> feature
於是我們把hello.txt修改成:
hello world
goodbye world
然後提交
git add hello.txt
git commit -m 'fix conflict'
[master 40cd928] fix conflict
分支合併成功。
可以用git log --graph --pretty=oneline --abbrev-commit
來查看合併的情況
* 40cd928 fix conflict
|\
| * 3cbd4df modified hello.txt
* | a40c0bc add "again"
|/
* 10fb7e4 add hello.txt
log的順序是按時間順序從下到上。
bug分支
假設現在master分支上發現了個bug,需要緊急修復,但你現在正在feature分支上工作
假設現在hello.txt的內容是:
hello world
goodbye world
feature branch unfinished work
現在feature分支上的功能還未完成,無法提交,但是需要修復bug。這時,就需要使用git stash
保存工作現場。
於是,在feature分支上,輸入git stash
,看到輸出信息:
Saved working directory and index state WIP on feature: 3cbd4df modified hello.txt
HEAD is now at 3cbd4df modified hello.txt
這時候,再輸入git status
,發現輸出:
On branch feature
nothing to commit, working tree clean
現場已被保存,打開hello.txt,後面的那句feature branch unfinished work
也不見了。
好,現在我們可以切換到master分支,並新建一個bug分支來修復這個bug了。
git checkout master
git checkout -b issue-101
在hello.txt中添加一行issue-101 bug fixed
,提交到repo
然後切回master分支,把issue-101分支合並進來。
git add hello.txt
git commit -m 'bug fixed'
git checkout master
git merge --no-ff -m 'merge issue-101' issue-101
輸出信息:
Merge made by the 'recursive' strategy.
hello.txt | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
合併完成,然後我們回到feature分支繼續工作。
git checkout feature
但是現在hello.txt裏面的內容還是
hello world
goodbye world
我們需要把之前未完成的工作現場恢復過來。
使用git stash list
可以查看保存了哪些工作現場:
stash@{0}: WIP on feature: 3cbd4df modified hello.txt
可以看到,這邊只有一條數據,我們可以使用git stash pop
來恢復這個現場。
輸出的信息:
On branch feature
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: hello.txt
no changes added to commit (use "git add" and/or "git commit -a")
Dropped refs/stash@{0} (643bef60d9b9540f66675d2fe1e8d9ad9d35f4fd)
可以看到,hello.txt裏面的feature branch unfinished work
又回來了
並且在恢復現場後,Dropped refs/stash@{0} (643bef60d9b9540f66675d2fe1e8d9ad9d35f4fd)
刪除了stash的內容。
如果有多條stash數據,可以用git stash apply
來恢復,如
git stash apply stash@{0}
但是用這種方式,stash內容並不會被刪除,如果要刪除某條stash,用git stash drop
刪除、撤銷、回退
刪除
刪除文件
假設我們有個文件,已經commit到repo中了,需要刪除。
爲此,我們新建一個文本文件delete.txt來模擬這個文件,把它提交到repo中。
這時候我們可以用兩種方法來刪除delete.txt。
1、使用git rm delete.txt
執行這句之後,會輸出一句rm 'delete.txt'
,這時候到工作區查看,會發現delete.txt已經不在工作區了。
輸入git status
,發現輸出如下信息:
On branch feature
Changes to be committed:
(use "git reset HEAD <file>..." to unstage)
deleted: delete.txt
暫存區已經記錄了刪除delete.txt的操作,接下來只要git commit
就可以把delete.txt從repo中刪除了。
2、直接從工作區目錄中刪除delete.txt,然後git add
,git commit
提交修改。
刪除分支
git branch -d <name>
可以刪除分支。
例如我們可以刪除之前用來修bug的issue-101分支
git branch -d issue-101
執行後輸出的信息:
Deleted branch issue-101 (was 5d97433).
用git branch
查看分支,輸出信息中表示只剩master分支跟feature分支了。
如果要刪除一個未合併的分支,默認git會報錯,例如我們創建一個delete分支,在hello.txt中添加一行內容delete branch
,然後進行一個commit
git checkout -b delete
git add hello.txt
git commit -m 'update delete branch'
然後切回master分支,刪除delete分支
git checkout master
git branch -d delete
輸出了一個error:
error: The branch 'delete' is not fully merged.
If you are sure you want to delete it, run 'git branch -D delete'.
git告訴你這個分支沒被合併,如果確定要刪除,使用git branch -D delete
。
執行git branch -D delete
,成功刪除。
這個操作通常用來刪除做到一半後面計劃不做了的功能分支。
撤銷
場景:從工作區撤銷
你在hello.txt中寫下了新的一行:I prefer svn
這時候你還沒執行git add
輸入git status
,會發現有個提示,(use "git checkout -- <file>..." to discard changes in working directory)
於是按照提示,執行git checkout -- hello.txt
再回去hello.txt看看,新增的那句話已經被撤銷了。
實際上,git checkout
所做的,就是把工作區的修改替換成暫存區的。
場景:從暫存區撤銷到工作區
你在hello.txt中寫下了新的一行:I prefer svn
執行了git add hello.txt
,把修改添加到暫存區
這時候git會提示你,(use "git reset HEAD <file>..." to unstage)
說得很清楚了,於是我們執行git reset HEAD hello.txt
再執行git status
查看,發現修改又回到了工作區。
場景:從repo中撤銷
……,,,遇到這種情況,看接下來的 回退 吧
回退
概念:git中有個HEAD指針,指向當前分支的當前版本,當我們進行回退操作時,其實就是改變HEAD指針,使其指向不同的commit節點。
理解了這個概念,就知道,既然是移動HEAD指針,那我們就可以在任意commit節點間進行跳轉,無論是之前的版本,還是回退到之前版本後,想要回到未來的版本,只要知道commit的id就可以跳轉版本。
使用git reset HEAD --hard <commit_id>
來回退。
類似10fb7e42c63586db6948f7a9221bafb32f19409d
這樣的就是一個commit id,也可以輸入前面幾位,只要跟其他id有區別就行,如10fb7e4
commit_id可以使用git reflog
來查看。(使用git log
不能看到回退後未來的commit id)
多人合作
看到這裏,清楚了git的基本操作,包括分支與解決衝突,單人玩git應該可以了,那麼多人合作,其實是類似的,處理好分支與衝突的解決,多人合作也是沒問題的。
遠程repo
github是目前流行的遠程repo之一。具體使用就不細說了。
當對本地repo進行了修改,用git push
命令推送到遠程repo就行了,包括分支的改動。
如果別人對遠程的repo進行了修改,或者自己在另一臺電腦上進行之前的項目,用git pull
拉取下來就行,這個過程中也可能遇到衝突。
幾個命令
git init
初始化repo
git status
列出未被添加到暫存區與未被提交到repo的修改(經常使用這個命令,對文件的修改以及提交情況會比較清楚)
git add <file>
添加修改到暫存區
git commit -m '<msg>'
提交修改到repo,並附上說明
git push
推送到遠程倉庫
git pull
從遠程倉庫拉取更新,並與本地對應分支合併
git branch
查看本地分支
git branch -a
查看遠程分支
git branch <branch_name>
創建分支
git checkout <branch_name>
切換分支
git checkout -b <branch_name>
新建並切換分支
git merge
合併分支
git stash
保存工作區工作現場
git stash list
查看stash
git stash pop
恢復最後一個stash並刪除stash數據
git stash apply <stash>
恢復指定stash
git stash drop <stash>
刪除指定stash
git rm <file>
將文件從工作區刪除
git branch -d <branch_name>
刪除分支
git branch -D <branch_name>
強制刪除未合併分支
git checkout -- <file>
把修改從工作區撤銷
git reset HEAD <file>
把修改從暫存區撤銷到工作區
git reset HEAD --hard <commit_id>
repo版本回退到某個commit
git log
查看commit歷史
git reflog
查看每個操作的log