Git 命令详解
Git 命令详解
1 Git 下载和安装
1.1 Git 下载地址
- 官网下载地址(速度较慢):https://git-scm.com/downloads
- 国内镜像地址(速度较快): https://pan.baidu.com/s/1kU5OCOB#list/path=%2Fpub%2Fgit
根据自己电脑型号下载对应版本即可。本机是win10 64位,下载对应64位版本。
1.2 Git 安装
- 默认安装到C盘,一路next点击就行。
- 指定安装,本机指定安装到D:\Git,修改路径一路next点击就行。
git有名为git-bash的终端,使用该终端执行git命令。
2 创建版本库
2.1 用户配置
使用如下命令为所有版本库配置用户名和Email地址,因为Git是分布式版本控制系统,每位用户需要自报家门。
$ git config --global user.name "Your Name" $ git config --global user.email "email@example.com"
–-global参数表示为本机器上所有Git仓库都使用这个配置,当然也可以为每个Git仓库配置不同的用户名和Email地址。
2.2 创建仓库
使用git init命令可以将任何目录夹创建成Git仓库,本机Git仓库存放目录为D:\Git\Repository,打开git-bash,进入上述所述目录,然后使用git init命令将learngit目录创建为仓库:
$ cd D:/Git/Repository/learngit/ $ git init
Tips:windows使用git-bash终端输入文件路径是使用斜杠而不是反斜杠。
3 添加和提交文件到仓库
在learngit目录下新建一个readme.txt文件,并用Notepad++编辑如下内容并保存:
$ Git is a version control system. $ Git is free sofware.
Tips:不要用记事本进行编辑,windows的记事本进行编辑,以为它会在每个文件开头添加了0xefbbbf(十六进制)的字符,你会遇到很多不可思议的问题,比如,网页第一行可能会显示一个“?”。
编辑保存完readme.txt文件后,按如下步骤将其放入版本库:
1.使用git add命令将readme.txt添加到仓库。
$ git add readme.txt
2.使用git commit命令将readme.txt提交到仓库。
$ git commit -m "wrote a readme file"
–m参数表示本次提交的说明,最好填写有意义的内容。
Tips:git add 可以一次添加多个文件,文件之间用空格分开。git commit 一次可以提交多个文件。
4 查询仓库当前状态
修改readme.txt文件内容如下:
$ Git is a distributed version control system. $ Git is free software.
使用git status命令查看仓库当前状态:
$ 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 no changes added to commit (use "git add" and/or "git commit -a")
结果显示readme.txt被修改过,但是还没准备提交。
使用git diff命令查看readme.txt哪些地方被修改过:
$ git diff readme.txt diff --git a/readme.txt b/readme.txt index d8036c1..013b5bc 100644 --- a/readme.txt +++ b/readme.txt @@ -1,2 +1,2 @@ -Git is a version control system. +Git is a distributed version control system. Git is free software. \ No newline at end of file
Tips:在提交之前查看被修改的地方是有必要的。
接下来将文件添加到仓库:
$ git add readme.txt
再用git status查看仓库当前状态:
$ git status On branch master Changes to be committed: (use "git reset HEAD <file>..." to unstage) modified: readme.txt
结果显示将要被提交的修改包括readme.txt。
这个时候如果使用git diff命令是查看不到readme.txt哪些地方被修改了:
$ git diff readme.txt
没有任何输出结果,但是可以使用git diff命令来查看工作区中的readme.txt和版本库中最新readme.txt的不同:
$ git diff HEAD -- readme.txt diff --git a/readme.txt b/readme.txt index d8036c1..013b5bc 100644 --- a/readme.txt +++ b/readme.txt @@ -1,2 +1,2 @@ -Git is a version control system. +Git is a distributed version control system. Git is free software. \ No newline at end of file
接下来可以放心提交:
$ git commit -m "add distributed" [master 1245bca] add distributed 1 file changed, 1 insertion(+), 1 deletion(-)
提交完成后,用git status命令查看当前仓库状态:
$ git status
On branch master
nothing to commit, working tree clean
结果显示没有需要提交的修改,而且工作目录是干净的。
5 版本回退
修改readme.txt文件如下:
Git is a distributed version control system. Git is free software distributed under the GPL.
然后尝试提交:
$ git commit -m "add GPL" [master 49c07cc] add GPL 1 file changed, 1 insertion(+), 1 deletion(-)
每一次的commit就相当于保存一个快照,一旦你将文件弄乱或者误删了文件,就可以从最近的一个commit恢复,继续工作。
可以使用git log命令来查看历史版本:
$ git log commit 49c07cc0c5b1bd1bf5df2199129a7ed063709f4e (HEAD -> master) Author: StrivePy <1013974267@qq.com> Date: Sun Mar 18 19:49:59 2018 +0800 add GPL commit 73a55c6fadf4380e784380b28e8e3ca49b85ba40 Author: StrivePy <1013974267@qq.com> Date: Sun Mar 18 19:42:16 2018 +0800 add distributed
使用–pretty=oneline参数可以简化输出:
$ git log --pretty=oneline 49c07cc0c5b1bd1bf5df2199129a7ed063709f4e (HEAD -> master) add GPL 73a55c6fadf4380e784380b28e8e3ca49b85ba40 add distributed
49c07cc0c5b1bd1bf5df2199129a7ed063709f4e一串表示commit id,只要知道任何commit id就可以使用git reset命令切换到该提交版本:
$ git reset --hard 73a55 HEAD is now at 73a55c6 add distributed
结果显示已经回退到add distributed版本。
若想回到add GPL版本,同样适用commit id:
$ git reset --hard 49c07 HEAD is now at 49c07cc add GPL
结果显示回到add GPL版本。
也可以使用HEAD指针来进行版本回退,Git中,用HEAD表示当前版本,HEAD^表示上一版本,HEAD^^表示上上版本,当然往上100个版本写100个^数不过来,用HEAD~100表示。用HEAD指针进行回退:
$ git reset --hard HEAD^ HEAD is now at 73a55c6 add distributed
结果显示已经回退到add distributed版本。
现在关闭git-bash,再重新打开并进入learngit目录,使用git log命令:
$ git log commit 73a55c6fadf4380e784380b28e8e3ca49b85ba40 (HEAD -> master) Author: StrivePy <1013974267@qq.com> Date: Sun Mar 18 19:42:16 2018 +0800 add distributed
结果已经看不见add GPL版本了,想使用commit id前进到add GPL版本但是没有commit id,此时可以使用git reflog来查看每一次你输入的命令:
$ git reflog 73a55c6 (HEAD -> master) HEAD@{0}: reset: moving to HEAD^ 49c07cc HEAD@{1}: reset: moving to 49c07 73a55c6 (HEAD -> master) HEAD@{2}: reset: moving to 73a55 49c07cc HEAD@{3}: commit: add GPL 73a55c6 (HEAD -> master) HEAD@{4}: commit: add distributed
结果显示add GPL的commit id为49c07cc,使用该id进行回退:
$ git reset --hard 49c07cc HEAD is now at 49c07cc add GPL
结果显示已经回退到add GPL版本。
小结:
-
HEAD指向的是当前版本,可以使用如下命令在版本之间穿梭:
$ git reset --hard commit_id
-
穿梭前,可以使用如下命令查看历史版本的commit_id:
$ git log
-
要重返未来,可以使用如下命令查看commit_id:
$ git reflog
6 管理修改
Git管理的是修改而不是文件,文件内容的增减,文件的创建和删除都属于修改。
对readme.txt新增一行后保存:
Git is a distributed version control system. Git is free software distributed under the GPL. Git tracks changes.
然后添加到仓库:
$ git add readme.txt
查看仓库当前状态:
$ git status On branch master Changes to be committed: (use "git reset HEAD <file>..." to unstage) modified: readme.txt
结果显示readme.txt的修改将被提交,然后再修改readme.txt如下后保存:
Git is a distributed version control system. Git is free software distributed under the GPL. Git tracks changes of files.
然后提交修改:
$ git commit -m "git tracks changes" [master 6ea23a0] git tracks changes 1 file changed, 2 insertions(+), 1 deletion(-)
再查看仓库当前状态:
$ git status On branch master Changes to be committed: (use "git reset HEAD <file>..." to unstage) modified: readme.txt
结果显示,readme.txt还有修改没有提交。原因是commit是负责提交缓存区的修改,第二次的修改没有添加到缓存区,所以没有没提交到版本库。可以用git diff HEAD — readme.txt命令开查看readme.txt第二次修改和版本库中的不同。
Tips:Git跟踪的是修改,若修改没有用git add命令添加到缓存区,就不会被git commit命令提交到版本库。
7 撤销修改
先查看learngit仓库的当前状态:
$ git status
On branch master
nothing to commit, working tree clean
结果显示工作区是干净的,现对readme.txt做如下修改:
Git is a distributed version control system. Git is free software distributed under the GPL. Git tracks changes of files. Git revokes modification.
但此时不想要最后添加的一行了,可以直接在编辑器中删除,也可以使用git checkout命令来撤销工作区中的修改:
$ git checkout -- readme.txt
然后查看readme.txt,果然修改被撤销了:
$ cat readme.txt Git is a distributed version control system. Git is free software distributed under the GPL. Git tracks changes of files.
Tips:撤销修改的git checkout命令后面必须带上—,不然变成了切换分支命令。
现在继续加上最后一行的修改,并将readme.txt添加到缓存区继续工作:
$ git add readme.txt
查看仓库当前状态:
$ git status On branch master Changes to be committed: (use "git reset HEAD <file>..." to unstage) modified: readme.txt
结果显示readme.txt的修改将被提交,但是现在不想提交,因为工作就剩一步就完成了,然后一起提交,但是当工作快完成的时候,最后一步的思路被完全打乱,文件非常混乱怎么都整理不好了,readme.txt文件被修改如下:
$ cat readme.txt Git is a distributed version control system. Git is free software distributed under the GPL. Git tracks changes of files. Git revokes modification. My stupied boss still prefers SVN.
此时可以使用git checkout命令回到上一次git add状态:
$ git checkout -- readme.txt
查看readme.txt:
$ cat readme.txt Git is a distributed version control system. Git is free software distributed under the GPL. Git tracks changes of files. Git revokes modification.
结果显示git add后的修改被撤销了,回到了上一次git add时的状态,查看仓库当前状态:
$ git status On branch master Changes to be committed: (use "git reset HEAD <file>..." to unstage) modified: readme.txt
结果显示上上次的修改添加到缓存区了将要被提交。此时接到新的需求,已经提交到缓存区的修改也不需要了,可以使用git reset命令撤销已经添加到缓存区中的修改,回到最初的工作区状态:
$ git reset HEAD readme.txt
Unstaged changes after reset:
M readme.txt
查看仓库当前状态:
$ 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 no changes added to commit (use "git add" and/or "git commit -a")
结果显示readme.txt的修改还没有被添加到缓存区,查看readme.txt:
$ cat readme.txt Git is a distributed version control system. Git is free software distributed under the GPL. Git tracks changes of files. Git revokes modification.
结果显示修改还保存在工作区,继续使用git checkout命令撤销工作区的需改:
$ git checkout -- readme.txt
查看仓库当前状态:
$ git status
On branch master
nothing to commit, working tree clean
结果显示工作区是干净的,工作区的修改已经被撤销。查看readme.txt:
$ cat readme.txt Git is a distributed version control system. Git is free software distributed under the GPL. Git tracks changes of files.
确认修改已经被撤销。
小结:
-
当弄乱了工作区,想要撤销修改,可以使用命令:
$ git checkout -- filename
当弄乱了工作区,并已经添加到缓存区,可以使用如下命令后,再使用上述命令:
-
$ git reset HEAD filename
- 当已经提交不合适的内容到版本库,可以使用版本回退命令回到你想要的版本,参考版本回退。如果已经推送到远程仓库,那就。。呵呵。
8 删除文件
Git中删除和新增文件也是修改操作,在learngit仓库中新增test.txt文件,产看仓库仓前状态:
$ git status On branch master Untracked files: (use "git add <file>..." to include in what will be committed) test.txt nothing added to commit but untracked files present (use "git add" to track)
结果显示test.txt还没有被跟踪,现在将test.txt添加到仓库并提交:
$ git commit -m "add test.txt" [master 07332c3] add test.txt 1 file changed, 1 insertion(+) create mode 100644 test.txt
一般要删除test.txt可以直接在文件资源管理器中直接删除,或者使用rm命令删除:
$ rm test.txt
此时,Git知道你删除了哪些文件,可以用git status命令查看哪些文件被删除了:
$ git status On branch master Changes not staged for commit: (use "git add/rm <file>..." to update what will be committed) (use "git checkout -- <file>..." to discard changes in working directory) deleted: test.txt no changes added to commit (use "git add" and/or "git commit -a")
结果显示,test.txt文件被删除了,但是这个修改还没有被提交到版本库,也就是说版本库中test.txt文件还存在。现在有两种情况:
-
确定要删除该文件,并且需要删除版本库中的该文件。用git rm命令删除版本库中的test.txt文件,并用git commit提交修改:
$ git rm test.txt rm \'test.txt\'
查看仓库当前状态:
$ git status On branch master Changes to be committed: (use "git reset HEAD <file>..." to unstage) deleted: test.txt
提交修改:
$ git commit -m "delete test.txt" [master bd9ecd8] delete test.txt 1 file changed, 1 deletion(-) delete mode 100644 test.txt
至此,版本库中的test.txt文件就被删除了。
-
只是在工作区误删了该文件,可以使用git checkout — filename命令可以撤销该文件的删除操作。
查看仓库当前状态:
$ git status On branch master Changes not staged for commit: (use "git add/rm <file>..." to update what will be committed) (use "git checkout -- <file>..." to discard changes in working directory) deleted: test.txt no changes added to commit (use "git add" and/or "git commit -a")
小结:
-
要删除版本库中的文件,使用命令:
$ git rm filename
-
如果一个文件已经提交到版本库,你永远不用担心误删,可以使用如下命令恢复到你最近一次提交到版本库时的版本,但你会丢失提交后的修改:
$ git checkout -- filename
9 远程仓库
将Github作为远程仓库,该网站提供Git仓库托管服务。
9.1 创建SSH Key
在用户主目录下看有没有.ssh目录,若有看该目录有没有id_rsa和id_rsa.pub文件,这两个文件就是SSH Key的密钥对,id_rsa是私钥,不能泄露出去,id_rsa.pub是公钥,可以告诉任何人。如果没有这两个文件,可以打开git-bash输入以下命令:
$ ssh-keygen -t rsa -C "youremail@example.com"
将上述email地址换成自己的,一路回车即可,然后可以看见.ssh目录下生成了这两个文件。可以直接在git-bash下使用cat命令来查看id_rsa.pub文件的内容。
9.2 给Github账户添加SSH Key
登陆GitHub,打开Account settings,SSH Keys页面。然后,点Add SSH Key,填上任意Title,在Key文本框里粘贴id_rsa.pub文件的内容
9.3 创建Github仓库
在Github上创建一个名为learngit的空仓库,该仓库有两个地址:
- SSH地址:git@github.com:StrivePy/learngit.git
- HTTPS地址:https://github.com/StrivePy/learngit.git
一般使用是SSH地址,传输速度较快,HTTPS地址除传输速度慢外,还需要额外输入端口地址。
9.4 关联Github仓库
现在本机上有一个名为learngit的本地仓库,Github上有一个名为learngit的远程仓库,使用git remote命令可以将本地仓库和远程仓库关联起来:
$ git remote add origin git@github.com:StrivePy/learngit.git
StrivePy是本机用户的Github用户名,该账户已经添加了本机的SSH Key,可以进行关联和推送,但是其它机器也可以关联,但是SSH Key不在StrivePy账户的SSH Key列表中,所以不能推送消息到该用户的仓库。origin表示远程仓库的名字,当然也可以取你自己喜欢的名字。
9.5 向远程仓库推送文件
远程仓库关联完成后,就可以使用git push命令将本地仓库当前分支文件推送到远程仓库:
$ git push -u origin master Counting objects: 18, done. Delta compression using up to 4 threads. Compressing objects: 100% (18/18), done. Writing objects: 100% (18/18), 1.80 KiB | 614.00 KiB/s, done. Total 18 (delta 5), reused 0 (delta 0) remote: Resolving deltas: 100% (5/5), done. To github.com:StrivePy/learngit.git be0db50..07332c3 master -> master Branch \'master\' set up to track remote branch \'master\' from \'origin\'.
进入Github的learngit仓库,可以看见仓库里面有文件,而且文件和本地learngit仓库文件一样,说明推送成功。本次是将本地master分支内容到远程仓库的master分支,-u参数表示在将本地master分支推送到远程master分支的同时,并将两个master分支关联起来,以后就可以使用简化的git push命令进行推送。 现在只要在本地仓库做了提交,就可以使用git push命令将提交推送到远程仓库:
$ git push origin master
以上是理想的状况,实际操作中,Github新建的仓库默认会有一个README.md文件,在使用git push -u origin master命令时,会提示远程仓库还有文件没有同步到本地,推送失败,而且会提示本地分支和远程仓库没有关联,可以使用如下命令进行关联:
$ git branch --set-upstream-to=origin/remote_branch your_branch
然后再用git push命令进行推送,但是还会提示:
fatal: refusing to merge unrelated histories
原因是在合并了两个不同的提交仓库时(本地仓库和远程仓库),git会发现这两个仓库可能不是同一个,为了防止推送错误,所以给出上述提示。
如果的却清楚需要合并,可是在git pull命令后加上参数–allow-unrelated-histories来进行版本的合并:
$ git pull origin master --allow-unrelated-histories
如果还不能合并,看是否存在冲突,解决冲突后再进行合并。
小结:
-
关联远程仓库使用命令:
$ git remote add origin git@github.com:StrivePy/learngit.git
-
第一次推送分支使用命令:
$ git push -u origin master
-
此后,本地提交后若有需要推送到远程仓库,使用命令:
$ git push origin master
9.6 从远程仓库克隆
在本地仓库learngit的同级目录下新建一个名为clone的目录,使用git-bash进入clone目录,使用如下命令将远程仓库learngit克隆到该目录:
$ git clone git@github.com:StrivePy/learngit.git
进入clone目录可以看见远程仓库learngit已经被克隆下来了。
小结:
-
要克隆一个远程仓库,必须先知道该仓库的地址,然后使用如下命令进行克隆:
$ git clone repository_address
- Git支持多种协议,包括https,但通过ssh支持的原生git协议速度最快。
10 分支管理
10.1 创建与合并分支
master是默认的主分支,我们一般不在上面进行工作,只是将其它分支合并到该分支,如有需要再将master分支推送到远程仓库。
首先创建名为dev的分支,并切换到该分支,使用如下命令:
$ git checkout -b dev Switched to a new branch \'dev\'
–b参数表示创建并切换,该命令等效于:
$ git branch dev $ git checkout dev Switched to branch \'dev\'
然后用git branch命令查看当前分支:
$ git branch * dev master
现在我们就可以在dev分支上正常工作了,因为是从master分支创建的dev分支,所有现在dev分支现在的工作区和master分支的工作区是一样的,现在在readme.txt加上一行:
Creating a new branch is quick.
然后添加并提交:
$ git add readme.txt $ git commit -m "branch test" [dev a9f9dbb] branch test 1 file changed, 4 insertions(+), 9 deletions(-)
现在切回master分支:
$ git checkout master Switched to branch \'master\' Your branch is up to date with \'origin/master\'.
查看readme.txt内容发现刚刚添加的一样没有添加上,原因是在dev分支上添加的,现在将dev分支的工作合并到master分支上:
$ git merge dev Updating d17efd8..fec145a Fast-forward readme.txt | 1 + 1 file changed, 1 insertion(+)
git merge用于合并指定分支到当前分支,合并后发现dev的添加的一行合并过来了,Fast-forward表示快进合并,直接把master指向dev,最后删除dev分支:
$ git branch -d dev
Deleted branch dev (was fec145a).
再查看分支:
$ git branch
* master
小结:
-
查看分支:
$ git branch
- 创建分支:
$ git branch name
- 切换分支:
$ git checkout branch_name
- 创建并切换分支:
$ git checkout -b name
-
合并某分支到当前分支:
$ git merge name
- 删除分支:
$ git branch -d name
10.2 解决冲突
有时候合并并不是一帆风顺的,例如新建并切换到feature1分支:
$ git checkout -b feature1 Switched to a new branch \'feature1\'
在readme.txt最后添加一行:
Creating a new branch is quick AND simple.
添加并提交:
$ git add readme.txt $ git commit -m "AND simple" [feature1 ddd008d] AND simple 1 file changed, 2 insertions(+), 1 deletion(-)
然后切换到master分支:
$ git checkout master Switched to branch \'master\' Your branch is ahead of \'origin/master\' by 1 commit. (use "git push" to publish your local commits)
结果显示本地仓库比远程仓库要新,这个不用管。在master分支对readme.txt最后添加一行:
Creating a new branch is quick & simple.
添加并提交:
$ git add readme.txt $ git commit -m "& simple" [master 8368fab] & simple 1 file changed, 2 insertions(+), 1 deletion(-)
接下来合并,但是这种情况下,Git无法执行快进合并,只能尝试把各自的修改合并起来,有可能产生冲突,接下来尝试一下:
$ git merge feature1 Auto-merging readme.txt CONFLICT (content): Merge conflict in readme.txt Automatic merge failed; fix conflicts and then commit the result.
结果提示产生冲突,需要手动解决冲突后再提交,使用git status可以查看冲突的文件:
$ git status On branch master Your branch is ahead of \'origin/master\' by 2 commits. (use "git push" to publish your local commits) You have unmerged paths. (fix conflicts and run "git commit") (use "git merge --abort" to abort the merge) Unmerged paths: (use "git add <file>..." to mark resolution) both modified: readme.txt no changes added to commit (use "git add" and/or "git commit -a")
可以查看一下readme.txt:
$ cat readme.txt Git is a distributed version control system. Git is free software distributed under the GPL. Git has a mutable index called stage. Git tracks changes of files. <<<<<<< HEAD Creating a new branch is quick & simple. ======= Creating a new branch is quick AND simple. >>>>>>> feature1
Git用<<<<<<<,=======,>>>>>>>标记出不同分支的内容,我们修改如下后保存:
Creating a new branch is quick and simple.
再提交:
$ git commit -m "confict fixed" [master 4de6f5f] confict fixed
用带参数的git log命令查看分支合并情况:
$ git log --graph --pretty=oneline --abbrev-commit * 4de6f5f (HEAD -> master) confict fixed |\ | * ddd008d (feature1) AND simple * | 8368fab & simple |/ * 14b0a6e modify readme.txt
最后删除feature1分支:
$ git branch -d feature1
Deleted branch feature1 (was ddd008d)
小结:
- Git无法自动完成合并时,需要手动解决冲突,再提交,完成合并。
-
查看分支合并图可以使用如下命令:
$ git log --graph
11 分支管理策略
11.1 禁用Fast Forward合并模式
Git默认采用的是快进合并模式,快进合并模式下,删除分支后,会丢掉分支信息。如果要强制禁用Fast forward模式,Git在merge时会产生一个新的commit,这样在分支历史上就可以看出分支信息,接下来实验一下。
首先创建并切换到分支dev:
$ git checkout -b dev Switched to a new branch \'dev\'
在readme.txt后增加一行内容:
Git fast forward merge.
并将修改提交:
$ git commit -m "no fast forward merge" [dev 44e4f6f] no fast forward merge 1 file changed, 1 insertion(+), 1 deletion(-)
现在切换回master分支:
$ git checkout master Switched to branch \'master\' Your branch is ahead of \'origin/master\' by 13 commits. (use "git push" to publish your local commits)
然后用–no-ff模式将dev分支合并到master分支:
$ git merge --no-ff -m "merge with --no-ff" dev Merge made by the \'recursive\' strategy. readme.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
Tips:因为本次合并要新建一个commit所以带上-m参数添加提交说明
然后用git log命令查看日志:
$ git log --graph --pretty=oneline --abbrev-commit * df99854 (HEAD -> master) merge with --no-ff |\ | * 44e4f6f (dev) no fast forward merge |/ * 9e4a116 merge with --no-ff model
日志图形结果显示了分支的历史信息。
小结:
- 使用git merge命令带上–no-ff参数就表示用普通模式进行合并,合并后的历史有分支,能看出来曾经做过合并,而Fast forward模式则看不出来曾经做过合并。
11.2 Bug分支
每一个Bug都可以通过一个新的临时分支来修复,然后在合并分支,最后将临时分支删除。假设正在dev分支上工作,对readme.txt文件修改工作,但接到任务说master分支上有一个名为issue-001的Bug被发现了,需要紧急修改,此时看一下dev分支的工作状态:
$ git status On branch dev 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 no changes added to commit (use "git add" and/or "git commit -a")
结果显示dev分支上还有没有提交的修改,但是修改只进行了一半,无法立刻提交,而现在又要去修改Bug,该怎么处理,好在Git有一个git stash命令可以将工作现场暂时保存起来,等待以后恢复现场继续工作:
$ git stash Saved working directory and index state WIP on dev: df99854 merge with --no-ff
再查看工作区的状态:
$ git status
On branch dev
nothing to commit, working tree clean
结果显示工作区是干净的。接下来就可以到master分支上去修复Bug了。 切换到master分支,再该分支上创建并切换到名为issue-001的分支来修复Bug:
$ git checkout master Switched to branch \'master\' Your branch is ahead of \'origin/master\' by 15 commits. (use "git push" to publish your local commits)
$ git checkout -b issue-001 Switched to a new branch \'issue-001\'
现在修复Bug需要删除readme.txt的最后一行,修改完毕后添加并提交:
$ git add readme.txt $ git commit -m "fixed issue-001" [issue-001 3dfa376] fixed issue-001 1 file changed, 1 insertion(+), 1 deletion(-)
然后切换到master分支,完成合并,并删除issue-001分支:
$ git checkout master Switched to branch \'master\' Your branch is ahead of \'origin/master\' by 15 commits. (use "git push" to publish your local commits)
$ git merge --no-ff -m "merge bug fix issue-001" issue-001 Merge made by the \'recursive\' strategy. readme.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
$ git branch -d issue-001
Deleted branch issue-001 (was 3dfa376).
Bug修复完毕,回到dev分支继续工作,查看工作区状态:
$ git status
On branch dev
nothing to commit, working tree clean
结果显示工作区是空的,使用git stash list查看工作现场的保存地址:
$ git stash list
stash@{0}: WIP on dev: df99854 merge with --no-ff
恢复工作现场的两种方式:
- 使用git stash apply stash@{0},但是恢复后,stash的内容并不会被删除,需要使用git stash drop stash@{0}命令来删除stash内容。
-
使用git stash pop命令直接恢复并删除stash内容:
$ git stash pop On branch dev 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 no changes added to commit (use "git add" and/or "git commit -a") Dropped refs/stash@{0} (eb9fe8bbd71a8abc5a6e3badaa6a526d6c774ee8)
可以看见工作现场恢复了,而且使用git stash list命令查看不到任何stash内容。
可以多次保存stash,然后用git stash list查看,然后用git stash apply stash@{number}来恢复指定的现场。
小结:
- 修复Bug时,新建临时分支,解决完Bug后,合并分支,最后删除分支。
- 使用git stash可以保存工作现场,然后去完成其工作,最后回来恢复现场继续工作。
- 要丢弃一个没有合并的分支,可以使用git branch -D name强行铲除分支。
12 多人协作
12.1 远程仓库信息
当从远程仓库clone时,Git实际上把本地的master分支和远程master分支关联起来,并且远程仓库的默认名称为origin,要查看远程仓库信息。
用git remote命令:
$ git remote
origin
或者用git remote -v查看远程仓库更详细的信息:
$ git remote -v origin git@github.com:StrivePy/learngit.git (fetch) origin git@github.com:StrivePy/learngit.git (push)
上面显示了抓取和推送origin的地址。如果没有推送权限,就看不见origin的推送地址。
12.2 推送分支
推送分支,就是把本地分支上的所有提交推送到远程仓库。推送时加上分支名,Git就把该本地分支上的所有提交推送到对应的远程分支上:
$ git push origin master
要推送其它分支,使用对应的分支名称即可:
$ git push origin dev
并不是所有的分支都需要推送到远程仓库,需要推送到远程仓库的分支:
- master分支作为主分支,需要时刻与远程仓库同步。
- dev作为开发分支,团队成员都需要在上面工作,也需要时刻与远程仓库同步。
- bug分支只在本地修改bug,不需要推送到分支。
- feature分支是否推送到远程仓库,取决于是否和团队成员在该分支上合作开发。
12.3 抓取分支
多人协作时,团队成员都会时不时往master分支和dev分支推送自己的修改。
在本地learngit仓库同级目录下新建一个cooperation目录来模拟另一个团队成员,进入cooperation目录将远程learngit仓库克隆下来:
$ git clone git@github.com:StrivePy/learngit.git Cloning into \'learngit\'... remote: Counting objects: 81, done. remote: Compressing objects: 100% (49/49), done. remote: Total 81 (delta 28), reused 77 (delta 25), pack-reused 0 Receiving objects: 100% (81/81), 7.71 KiB | 281.00 KiB/s, done. Resolving deltas: 100% (28/28), done.
默认情况下,clone完成后只能看见master分支:
$ git branch
* master
想要在dev分支上进行开发,就必须创建远程origin的dev分支到本地:
$ git checkout -b dev origin/dev Switched to a new branch \'dev\' Branch \'dev\' set up to track remote branch \'dev\' from \'origin\'.
此时就能dev分支上进行工作了:
$ git branch * dev master
先查看readme.txt的内容:
$ cat readme.txt git is a distributed version control system git is a free software distributed under GPL git has a mutable index called stage git tracks changes of files test git merge create a new branch is simple And quick add merge test stash add usr/bin/evn
将最后一行修改为:
add usr/bin/evn/test
然后提交并推送到远程仓库:
$ git add readme.txt
$ git commit -m "add usr/bin/evn/test" [dev 62c782a] add usr/bin/evn/test 1 file changed, 1 insertion(+), 1 deletion(-)
$ git push origin dev Counting objects: 3, done. Delta compression using up to 4 threads. Compressing objects: 100% (3/3), done. Writing objects: 100% (3/3), 293 bytes | 293.00 KiB/s, done. Total 3 (delta 2), reused 0 (delta 0) remote: Resolving deltas: 100% (2/2), completed with 2 local objects. To github.com:StrivePy/learngit.git 23625fd..62c782a dev -> dev
此时,回到本地非clone的learngit仓库,查看readme.txt内容:
$ cat readme.txt git is a distributed version control system git is a free software distributed under GPL git has a mutable index called stage git tracks changes of files test git merge create a new branch is simple And quick add merge test stash add usr/bin/evn/
将最有一行修改为:
add usr/bin/evn/tests
然后提交修改并尝试推送到远程仓库:
$ git commit -m "add usr/bin/evn/tests" [dev 9c1fa27] add usr/bin/ 1 file changed, 1 insertion(+), 1 deletion(-)
$ git push origin dev To github.com:StrivePy/learngit.git ! [rejected] dev -> dev (fetch first) error: failed to push some refs to \'git@github.com:StrivePy/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.
结果因为另外的远程推送导致本次推送失败,你可能需要先整合(合并)远程修改再进行推送,所以使用git pull命令拉一下远程仓库:
$ git pull remote: Counting objects: 3, done. remote: Compressing objects: 100% (1/1), done. remote: Total 3 (delta 2), reused 3 (delta 2), pack-reused 0 Unpacking objects: 100% (3/3), done. From github.com:StrivePy/learngit 9c1fa27..1dacdbc dev -> origin/dev Auto-merging readme.txt CONFLICT (content): Merge conflict in readme.txt Automatic merge failed; fix conflicts and then commit the result.
git pull失败,结果提示合并时,在readme.txt文件中有冲突,查看readme.txt文件:
$ cat readme.txt git is a distributed version control system git is a free software distributed under GPL git has a mutable index called stage git tracks changes of files test git merge create a new branch is simple And quick add merge test stash <<<<<<< HEAD add usr/bin/evn/tests ======= add usr/bin/evn/test >>>>>>> 1dacdbc0ca9202c1e11c366ce6b9c13f44cb5b47
将最后一行修改为:
add usr/bin/evn/
然后提交到本地仓库,再远程推送:
$ git add readme.txt
$ git commit -m "merge and fixed" [dev 1a26ae2] merge and fixed
$ git push origin dev Counting objects: 6, done. Delta compression using up to 4 threads. Compressing objects: 100% (6/6), done. Writing objects: 100% (6/6), 572 bytes | 286.00 KiB/s, done. Total 6 (delta 4), reused 0 (delta 0) remote: Resolving deltas: 100% (4/4), completed with 2 local objects. To github.com:StrivePy/learngit.git 1dacdbc..1a26ae2 dev -> dev
结果显示推送成功,远程仓库中的readme.txt文件以解决冲突后文件为准。
小结:
-
查看远程库信息,使用命令:
$ git remote -v
- 本地创建的分支,如果不推送到远程,对其他人是不可见的。
-
多人协作的工作模式:
- 首先可试图用命令git push origin branch_name远程推送对自己的修改。
- 如果推送失败,则因为远程分支要比本地分支更新,用命令git pull拉取一下试图合并,如果拉取时提示no tracking information,用命令git branch –set-upstream=origin/remote_branch your_branch建立本地分支和远程分支的联系。
- 如何合并失败,手动解决冲突,并在本地提交。
- 没有冲突或者解决冲突后,使用命令git push origin your_branch推送。
13 标签管理
13.1 创建标签
要创建标签,首先切换到要打标签的分支:
$ git branch * dev master
$ git checkout master Switched to branch \'master\' Your branch is up to date with \'origin/master\'.
然后使用git tag tag_name创建标签:
$ git tag v1.0
可以使用git tag命令查看所有标签:
$ git tag
v1.0
默认标签是打在最新提交的commit上的,可以使用git tag tag_name commit_id命令对任何提交打上标签:
$ git log --pretty=oneline --abbrev-commit 1ba8102 (HEAD -> master, tag: v1.0, origin/master) delete dev cd05c0d merge bug fix issue-001 3dfa376 fixed issue-001 df99854 merge with --no-ff 44e4f6f no fast forward merge 9e4a116 merge with --no-ff model 3a6b35d merge test.. ce6ca91 merge test 3f0ad45 conflict fixed 4de6f5f confict fixed 8368fab & simple
如果相对fixed issue-001这次提交打上标签:
$ git tag v0.9 3dfa376
用git show tag_name查看标签信息:
$ git show v0.9 commit 3dfa3760095617a41a068cf8b839c2a278e249c4 (tag: v0.9) Author: StrivePy <1013974267@qq.com> Date: Mon Mar 19 20:19:37 2018 +0800 fixed issue-001 diff --git a/readme.txt b/readme.txt index 23580ea..294d3b9 100644 --- a/readme.txt +++ b/readme.txt @@ -3,4 +3,4 @@ Git is free software distributed under the GPL. Git has a mutable index called stage. Git tracks changes of files. Creating a new branch is quick and simple. -Git fast forward merge. +
标签确实打在fixed issue-001这次提交上。
可以使用git tag -a tag_name -m “information” commit_id打上带说明信息的标签,-a表示标签名,-m表示说明信息:
$ git tag -a v0.1 -m "version 0.1 released" cd05c0d
查看标签信息:
$ git show v0.1 tag v0.1 Tagger: StrivePy <1013974267@qq.com> Date: Thu Mar 22 19:40:32 2018 +0800 version 0.1 released commit cd05c0d4223a76abfa4dd6d55fb1dcc7eac8c10c (tag: v0.1) Merge: df99854 3dfa376 Author: StrivePy <1013974267@qq.com> Date: Mon Mar 19 20:23:09 2018 +0800 merge bug fix issue-001
小结:
-
对默认的最新提交打标签使用命令:
$ git tag tag_name
-
要标签上带上说明信息,使用如下命令:
$ git tag -a tag_name -m "information" commit_id
-
用PGP签名标签,使用如下命令:
$ git tag -s tag_name -m "information" commit_id
-
显示所有标签,使用命令:
$ git tag
-
显示标签详细信息,使用命令:
$ git show tag_name
13.2 操作标签
想要删除一个标签,使用git tag -d tag_name命令:
$ git tag -d v0.1 Deleted tag \'v0.1\' (was 4630d67)
推送本地标签到远程:
$ git tag v0.9 v1.0
$ git push origin v0.9 Total 0 (delta 0), reused 0 (delta 0) To github.com:StrivePy/learngit.git * [new tag] v0.9 -> v0.9
或者使用如下命令,将本地所有未推送的标签一次性推送到远程仓库:
$ git push origin --tags Total 0 (delta 0), reused 0 (delta 0) To github.com:StrivePy/learngit.git * [new tag] v1.0 -> v1.0
如果标签已经推送到了远程仓库,可以用以下步骤删除远程仓库标签:
-
先删除本地标签:
$ git tag -d v0.9 Deleted tag \'v0.9\' (was 3dfa376)
-
再删除远程仓库的标签:
$ git push origin :refs/tags/v0.9 To github.com:StrivePy/learngit.git - [deleted] v0.9
登陆Github查看该标签确实被删除了。
小结:
-
推送一个本地标签,使用命令:
$ git push origin tag_name
-
推送本地所有未推送的标签,使用命令:
$ git push origin --tags
-
删除一个本地标签,使用命令:
$ git tag -d tag_name
-
删除一个远程标签,使用命令:
$ git push origin :refs/tags/tag_name
14 参考资料
廖雪峰老师Git 教程:https://www.liaoxuefeng.com/wiki/0013739516305929606dd18361248578c67b8067c8c017b000