git的分支,多人協作,標簽管理
一.分支
1.分支的簡介
在進行提交操作時,Git 會保存一個提交對象(commit object),
2.分支的創建
創建一個 testing 分支, 你需要使用 git branch
命令:
$ git branch testing
3.分支的切換
$ git checkout testing
再提交一次:
$ vim test.rb $ git commit -a -m ‘made a change‘
首先,我們創建dev
分支,然後切換到dev
分支:
$ git checkout -b dev Switched to a new branch‘dev‘
git checkout
命令加上-b
參數表示創建並切換,相當於以下兩條命令:
$ git branch dev $ git checkout dev Switched to branch ‘dev‘
用git branch
命令查看當前分支:
$ git branch * dev master
git branch
命令會列出所有分支,當前分支前面會標一個*
號。
對readme.txt做個修改,加上一行:
Creating a new branch is quick.
4.分支的刪除
使用帶 -d
選項的 git branch
$ git branch -d hotfix
Deleted branch hotfix (3a0874c).
5.分支的合並
檢出到你想合並入的分支,然後運行 git merge
命令:
$ git checkout master Switched to branch ‘master‘ $ git merge iss53 Merge made by the ‘recursive‘ strategy. index.html | 1 + 1 file changed, 1 insertion(+)
遇到沖突時的分支合並
有時候合並操作不會如此順利。 如果你在兩個不同的分支中,對同一個文件的同一個部分進行了不同的修改,Git 就沒法幹凈的合並它們。 如果你對 #53 問題的修改和有關 hotfix
$ git merge iss53
Auto-merging index.html
CONFLICT (content): Merge conflict in index.html
Automatic merge failed; fix conflicts and then commit the result.
此時 Git 做了合並,但是沒有自動地創建一個新的合並提交。 Git 會暫停下來,等待你去解決合並產生的沖突。 你可以在合並沖突後的任意時刻使用 git status
命令來查看那些因包含合並沖突而處於未合並(unmerged)狀態的文件:
$ git status On branch master You have unmerged paths. (fix conflicts and run "git commit") Unmerged paths: (use "git add <file>..." to mark resolution) both modified: index.html no changes added to commit (use "git add" and/or "git commit -a")
任何因包含合並沖突而有待解決的文件,都會以未合並狀態標識出來。 Git 會在有沖突的文件中加入標準的沖突解決標記,這樣你可以打開這些包含沖突的文件然後手動解決沖突。 出現沖突的文件會包含一些特殊區段,看起來像下面這個樣子:
<<<<<<< HEAD:index.html <div id="footer">contact : [email protected]</div> ======= <div id="footer"> please contact us at [email protected] </div> >>>>>>> iss53:index.html
這表示 HEAD
所指示的版本(也就是你的 master
分支所在的位置,因為你在運行 merge 命令的時候已經檢出到了這個分支)在這個區段的上半部分(=======
的上半部分),而 iss53
分支所指示的版本在 =======
的下半部分。 為了解決沖突,你必須選擇使用由 =======
分割的兩部分中的一個,或者你也可以自行合並這些內容。 例如,你可以通過把這段內容換成下面的樣子來解決沖突:
<div id="footer"> please contact us at [email protected] </div>
上述的沖突解決方案僅保留了其中一個分支的修改,並且 <<<<<<<
, =======
, 和 >>>>>>>
這些行被完全刪除了。 在你解決了所有文件裏的沖突之後,對每個文件使用 git add
命令來將其標記為沖突已解決。 一旦暫存這些原本有沖突的文件,Git 就會將它們標記為沖突已解決。
6.分支管理
$ git branch iss53 * master testing
master
分支前的 *
字符:它代表現在檢出的那一個分支
Bug分支
有了bug就需要修復,在Git中,由於分支是如此的強大,所以,每個bug都可以通過一個新的臨時分支來修復,修復後,合並分支,然後將臨時分支刪除。
Git還提供了一個stash
功能,可以把當前工作現場“儲藏”起來,等以後恢復現場後繼續工作:
$ git stash Saved working directory and index state WIP on dev: f52c633 add merge
首先確定要在哪個分支上修復bug,假定需要在master
分支上修復,就從master
創建臨時分支:
$ git checkout master Switched to branch ‘master‘ Your branch is ahead of ‘origin/master‘ by 6 commits. (use "git push" to publish your local commits)
$ git checkout -b issue-101
Switched to a new branch ‘issue-101‘
現在修復bug,需要把“Git is free software ...”改為“Git is a free software ...”,然後提交:
$ git add readme.txt $ git commit -m "fix bug 101" [issue-101 4c805e2] fix bug 101 1 file changed, 1 insertion(+), 1 deletion(-)
修復完成後,切換到master
分支,並完成合並,最後刪除issue-101
分支:
$ git checkout master Switched to branch ‘master‘ Your branch is ahead of ‘origin/master‘ by 6 commits. (use "git push" to publish your local commits) $ git merge --no-ff -m "merged bug fix 101" issue-101 Merge made by the ‘recursive‘ strategy. readme.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
現在,是時候接著回到dev
分支
$ git checkout dev Switched to branch ‘dev‘ $ git status On branch dev nothing to commit, working tree clean
工作區是幹凈的,剛才的工作現場存到哪去了?用git stash list
命令看看:
$ git stash list
stash@{0}: WIP on dev: f52c633 add merge
工作現場還在,Git把stash內容存在某個地方了,但是需要恢復一下,有兩個辦法:
一是用git stash apply
恢復,但是恢復後,stash內容並不刪除,你需要用git stash drop
來刪除;
另一種方式是用git stash pop
,恢復的同時把stash內容也刪了:
$ git stash pop On branch dev Changes to be committed: (use "git reset HEAD <file>..." to unstage) new file: hello.py 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 Dropped refs/stash@{0} (5d677e2ee266f39ea296182fb2354265b91b3b2a)
再用git stash list
查看,就看不到任何stash內容了:
$ git stash list
你可以多次stash,恢復的時候,先用git stash list
查看,然後恢復指定的stash,用命令:
$ git stash apply stash@{0}
7.dev 分支
準備開發:
$ git checkout -b dev-vulcan Switched to a new branch ‘dev-vulcan‘
5分鐘後,開發完畢:
$ git add vulcan.py $ git status On branch dev-vulcan Changes to be committed: (use "git reset HEAD <file>..." to unstage) new file: vulcan.py $ git commit -m "add feature vulcan" [feature-vulcan 287773e] add feature vulcan 1 file changed, 2 insertions(+) create mode 100644 vulcan.py
切回dev
,準備合並:
$ git checkout dev
銷毀
$ git branch -d dev-vulcan error: The branch ‘dev-vulcan‘ is not fully merged. If you are sure you want to delete it, run ‘git branch -D dev-vulcan‘.
銷毀失敗。Git友情提醒,dev-vulcan
分支還沒有被合並,如果刪除,將丟失掉修改,如果要強行刪除,需要使用大寫的-D
參數。
$ git branch -D dev-vulcan
Deleted branch dev-vulcan (was 287773e).
參考:https://blog.51cto.com/wangfeng7399/2352662
二.多人協作
克隆倉庫的命令格式是git clone [url]
$ git clone https://github.com/libgit2/libgit2
自定義本地倉庫的名字,你可以使用如下命令:
$ git clone https://github.com/libgit2/libgit2 mylibgit
發生沖突時:先pull,在本地合並,然後才能push成功。合並後,分支變成了下面:
$ git log --graph --pretty=oneline --abbrev-commit * d1be385 (HEAD -> master, origin/master) init hello * e5e69f1 Merge branch ‘dev‘ |\ | * 57c53ab (origin/dev, dev) fix env conflict | |\ | | * 7a5e5dd add env | * | 7bd91f1 add new env | |/ * | 12a631b merged bug fix 101 |\ \ | * | 4c805e2 fix bug 101 |/ / * | e1e9c68 merge with no-ff |\ \ | |/ | * f52c633 add merge |/ * cf810e4 conflict fixed
Git有一種稱為rebase的操作,有人把它翻譯成“變基”
在和遠程分支同步後,我們對hello.py
這個文件做了兩次提交。用git log
命令看看:
$ git log --graph --pretty=oneline --abbrev-commit * 582d922 (HEAD -> master) add author * 8875536 add comment * d1be385 (origin/master) init hello * e5e69f1 Merge branch ‘dev‘ |\ | * 57c53ab (origin/dev, dev) fix env conflict | |\ | | * 7a5e5dd add env | * | 7bd91f1 add new env ...
推送本地分支:
$ git push origin master To github.com:michaelliao/learngit.git ! [rejected] master -> master (fetch first) error: failed to push some refs to ‘[email protected]:michaelliao/learngit.git‘ hint: Updates were rejected because the remote contains work that you do hint: not have locally. This is usually caused by another repository pushing hint: to the same ref. You may want to first integrate the remote changes hint: (e.g., ‘git pull ...‘) before pushing again. hint: See the ‘Note about fast-forwards‘ in ‘git push --help‘ for details.
這樣就失敗了,這說明有人先於我們推送了遠程分支。按照經驗,先pull一下:
$ git pull remote: Counting objects: 3, done. remote: Compressing objects: 100% (1/1), done. remote: Total 3 (delta 1), reused 3 (delta 1), pack-reused 0 Unpacking objects: 100% (3/3), done. From github.com:michaelliao/learngit d1be385..f005ed4 master -> origin/master * [new tag] v1.0 -> v1.0 Auto-merging hello.py Merge made by the ‘recursive‘ strategy. hello.py | 1 + 1 file changed, 1 insertion(+)
再用git status
看看狀態:
$ git status On branch master Your branch is ahead of ‘origin/master‘ by 3 commits. (use "git push" to publish your local commits) nothing to commit, working tree clean
用git log
看看:
$ git log --graph --pretty=oneline --abbrev-commit * e0ea545 (HEAD -> master) Merge branch ‘master‘ of github.com:michaelliao/learngit |\ | * f005ed4 (origin/master) set exit=1 * | 582d922 add author * | 8875536 add comment |/ * d1be385 init hello ...
現在把本地分支push到遠程,有沒有問題?有,不好看
輸入命令git rebase
試試:
$ git rebase First, rewinding head to replay your work on top of it... Applying: add comment Using index info to reconstruct a base tree... M hello.py Falling back to patching base and 3-way merge... Auto-merging hello.py Applying: add author Using index info to reconstruct a base tree... M hello.py Falling back to patching base and 3-way merge... Auto-merging hello.py
再用git log
看看:
$ git log --graph --pretty=oneline --abbrev-commit * 7e61ed4 (HEAD -> master) add author * 3611cfe add comment * f005ed4 (origin/master) set exit=1 * d1be385 init hello ...
最後,通過push操作把本地分支推送到遠程:
Mac:~/learngit michael$ git push origin master Counting objects: 6, done. Delta compression using up to 4 threads. Compressing objects: 100% (5/5), done. Writing objects: 100% (6/6), 576 bytes | 576.00 KiB/s, done. Total 6 (delta 2), reused 0 (delta 0) remote: Resolving deltas: 100% (2/2), completed with 1 local object. To github.com:michaelliao/learngit.git f005ed4..7e61ed4 master -> master
再用git log
看看效果:
$ git log --graph --pretty=oneline --abbrev-commit * 7e61ed4 (HEAD -> master, origin/master) add author * 3611cfe add comment * f005ed4 set exit=1 * d1be385 init hello ...
遠程分支
1.推送
$ git push origin serverfix Counting objects: 24, done. Delta compression using up to 8 threads. Compressing objects: 100% (15/15), done. Writing objects: 100% (24/24), 1.91 KiB | 0 bytes/s, done. Total 24 (delta 2), reused 0 (delta 0) To https://github.com/schacon/simplegit * [new branch] serverfix -> serverfix
抓取數據時
$ git fetch origin remote: Counting objects: 7, done. remote: Compressing objects: 100% (2/2), done. remote: Total 3 (delta 0), reused 3 (delta 0) Unpacking objects: 100% (3/3), done. From https://github.com/schacon/simplegit * [new branch] serverfix -> origin/serverfix
如果想要在自己的 serverfix
分支上工作,可以將其建立在遠程跟蹤分支之上:
$ git checkout -b serverfix origin/serverfix Branch serverfix set up to track remote branch serverfix from origin. Switched to a new branch ‘serverfix‘
2.跟蹤分支
$ git checkout --track origin/serverfix Branch serverfix set up to track remote branch serverfix from origin. Switched to a new branch ‘serverfix‘
如果想要將本地分支與遠程分支設置為不同名字,你可以輕松地增加一個不同名字的本地分支的上一個命令:
$ git checkout -b sf origin/serverfix Branch sf set up to track remote branch serverfix from origin. Switched to a new branch ‘sf‘
設置已有的本地分支跟蹤一個剛剛拉取下來的遠程分支,或者想要修改正在跟蹤的上遊分支,你可以在任意時間使用 -u
或 --set-upstream-to
選項運行 git branch
來顯式地設置。
$ git branch -u origin/serverfix Branch serverfix set up to track remote branch serverfix from origin.
如果想要查看設置的所有跟蹤分支,可以使用 git branch
的 -vv
選項
$ git branch -vv iss53 7e424c3 [origin/iss53: ahead 2] forgot the brackets master 1ae2a45 [origin/master] deploying index fix * serverfix f8674d9 [teamone/server-fix-good: ahead 3, behind 1] this should do it testing 5ea463a trying something new
3.刪除遠程分支
$ git push origin --delete serverfix To https://github.com/schacon/simplegit - [deleted] serverfix
參考:https://blog.51cto.com/wangfeng7399/2352667
三.忽略特殊文件
1.忽略特殊文件的原則:
- 忽略操作系統自動生成的文件,比如縮略圖等;
- 忽略編譯生成的中間文件、可執行文件等,也就是如果一個文件是通過另一個文件自動生成的,那自動生成的文件就沒必要放進版本庫,比如Java編譯產生的
.class
文件; - 忽略你自己的帶有敏感信息的配置文件,比如存放口令的配置文件。
有些時候,你想添加一個文件到Git,但發現添加不了,原因是這個文件被.gitignore
忽略了:
$ git add App.class The following paths are ignored by one of your .gitignore files: App.class Use -f if you really want to add them.
確實想添加該文件,可以用-f
強制添加到Git:
$ git add -f App.class
可以用git check-ignore
命令檢查:
$ git check-ignore -v App.class .gitignore:3:*.class App.class
.gitignore
的第3行規則忽略了該文件,於是我們就可以知道應該修訂哪個規則。
忽略某些文件時,需要編寫.gitignore
;
.gitignore
文件本身要放到版本庫裏,並且可以對.gitignore
做版本管理!
四.標簽的管理
1.列出標簽
$ git tag v0.1 v1.3
如果只對 1.8.5 系列感興趣,可以運行:
$ git tag -l ‘v1.8.5*‘ v1.8.5 v1.8.5-rc0 v1.8.5-rc1 v1.8.5-rc2 v1.8.5-rc3 v1.8.5.1 v1.8.5.2 v1.8.5.3 v1.8.5.4 v1.8.5.5
2.創建標簽
輕量標簽(lightweight)與附註標簽(annotated)
2.1 附註標簽 附註標簽是存儲在 Git 數據庫中的一個完整對象
$ git tag -a v1.4 -m ‘my version 1.4‘ $ git tag v0.1 v1.3 v1.4
-m
選項指定了一條將會存儲在標簽中的信息
通過使用 git show
命令可以看到標簽信息與對應的提交信息:
$ git show v1.4 tag v1.4 Tagger: Ben Straub <[email protected]> Date: Sat May 3 20:19:12 2014 -0700 my version 1.4 commit ca82a6dff817ec66f44342007202690a93763949 Author: Scott Chacon <[email protected]> Date: Mon Mar 17 21:52:11 2008 -0700 changed the version number
2.2 輕量標簽 輕量標簽本質上是將提交校驗和存儲到一個文件中 - 沒有保存任何其他信息
$ git tag v1.4-lw $ git tag v0.1 v1.3 v1.4 v1.4-lw v1.5
如果在標簽上運行 git show
,你不會看到額外的標簽信息。 命令只會顯示出提交信息:
$ git show v1.4-lw commit ca82a6dff817ec66f44342007202690a93763949 Author: Scott Chacon <[email protected]> Date: Mon Mar 17 21:52:11 2008 -0700 changed the version number
3.後期打標簽
$ git log --pretty=oneline 15027957951b64cf874c3557a0f3547bd83b3ff6 Merge branch ‘experiment‘ a6b4c97498bd301d84096da251c98a07c7723e65 beginning write support 0d52aaab4479697da7686c15f77a3d64d9165190 one more thing 6d52a271eda8725415634dd79daabbc4d9b6008e Merge branch ‘experiment‘ 0b7434d86859cc7b8c3d5e1dddfed66ff742fcbc added a commit function 4682c3261057305bdd616e23b64b0857d832627b added a todo file 166ae0c4d3f420721acbb115cc33848dfcc2121a started write support 9fceb02d0ae598e95dc970b74767f19372d61af8 updated rakefile 964f16d36dfccde844893cac5b347e7b3d44abbc commit the todo 8a5cbc430f1a9c3d00faaeffd07798508422908a updated readme
假設在 v1.2 時你忘記給項目打標簽,也就是在 “updated rakefile” 提交。 你可以在之後補上標簽。 要在那個提交上打標簽,你需要在命令的末尾指定提交的校驗和(或部分校驗和):
$ git tag -a v1.2 9fceb02
4.共享標簽
$ git push origin v1.5 Counting objects: 14, done. Delta compression using up to 8 threads. Compressing objects: 100% (12/12), done. Writing objects: 100% (14/14), 2.05 KiB | 0 bytes/s, done. Total 14 (delta 3), reused 0 (delta 0) To [email protected]:schacon/simplegit.git * [new tag] v1.5 -> v1.5
如果想要一次性推送很多標簽,也可以使用帶有 --tags
選項的 git push
命令
$ git push origin --tags Counting objects: 1, done. Writing objects: 100% (1/1), 160 bytes | 0 bytes/s, done. Total 1 (delta 0), reused 0 (delta 0) To [email protected]:schacon/simplegit.git * [new tag] v1.4 -> v1.4 * [new tag] v1.4-lw -> v1.4-lw
5.刪除標簽
要刪除掉你本地倉庫上的標簽,可以使用命令 git tag -d <tagname>
可以使用下面的命令刪除掉一個輕量級標簽:
$ git tag -d v1.4-lw Deleted tag ‘v1.4-lw‘ (was e7d5add)
應該註意的是上述命令並不會從任何遠程倉庫中移除這個標簽,你必須使用 git push <remote> :refs/tags/<tagname>
來更新你的遠程倉庫:
$ git push origin :refs/tags/v1.4-lw To /[email protected]:schacon/simplegit.git - [deleted] v1.4-lw
6. 檢出標簽
如果你想查看某個標簽所指向的文件版本,可以使用 git checkout
命令
參考:https://blog.51cto.com/wangfeng7399/2352670
git的分支,多人協作,標簽管理