Git使用指南
因为搭建博客的时候,用到了Git,但实际上自己对Git还是一知半解。所以看了比较易懂的廖雪峰老师的Git教程,顺便做个笔记总结,方便之后查询。
what is Git?
Git是最流行的分布式版本控制系统,简单来说,就是管理不同人员对文本的修改记录,达到协同编辑的目的。
the use of Git
create repository
版本库(repository)又名仓库,可以简单理解成一个目录,Git负责跟踪每个文件的修改删除,并保存修改历史。
- 创建一个空目录(GUI操作也可以)
$ mkdir learngit
$ cd learngit
$ pwd
/Users/michael/learngit
- 初始化一个Git仓库
使用git init命令
- 添加文件到Git仓库,分两步:
使用命令git add <file>
,注意,可反复多次使用,添加多个文件;
使用命令git commit -m <message>
,完成。
status
git status
命令可以让我们时刻掌握仓库当前的状态,如:是否修改
git diff
命令可以查看修改内容
HEAD
HEAD指向的版本就是当前版本,因此,Git允许我们在版本的历史之间穿梭,使用命令git reset --hard commit_id
。commit_id就是版本号,并且不必写全,Git会自动填全。
穿梭前,用git log
可以查看提交历史,以便确定要回退到哪个版本,可以加上--pretty=oneline
参数简化输出信息,得到的每一行开头的字符,是版本号。
要重返未来,用git reflog
查看命令历史,以便确定要回到未来的哪个版本。
Working Directory , stage and Repository
用git add
把文件添加进去,实际上就是把文件修改添加到暂存区(stage);
用git commit
提交更改,实际上就是把暂存区的所有内容提交到当前分支(master)。
注:只有使用git add
,将修改放到暂存区,使用git commit
才有作用。
而协同编辑中还要引入远程库的概念,在此之前提到的所有操作都是在本地进行。
unstage
场景1:当你改乱了工作区某个文件的内容,想直接丢弃工作区的修改时,用命令git checkout -- file
。让这个文件回到最近一次git commit
或git add
时的状态
场景2:当你不但改乱了工作区某个文件的内容,还添加到了暂存区时,想丢弃修改,分两步,第一步用命令git reset HEAD <file>
,就回到了场景1,第二步按场景1操作。
场景3:已经提交了不合适的修改到版本库时,想要撤销本次提交,参考版本回退一节,不过前提是没有推送到远程库。
delete file
命令git rm
用于删除一个文件。如果一个文件已经被提交到版本库,那么你永远不用担心误删,但是要小心,你只能恢复文件到最新版本,你会丢失最近一次提交后你修改的内容(git checkout
其实是用版本库里的版本替换工作区的版本)
remote
git remote add origin git@github.com:michaelliao/learngit.git
michaelliao为账户名,修改为自己的,learngit是在GitHub上创建的远程库
把本地库的内容推送到远程,用git push
命令,实际上是把当前分支master推送到远程,第一次推送:git push -u origin master
,之后使用git push origin master
即可。
clone
GitHub给出的地址不止一个,还可以用https://github.com/michaelliao/gitskills.git这样的地址。实际上,Git支持多种协议,默认的git://使用ssh,但也可以使用https等其他协议。
使用https除了速度慢以外,还有个最大的麻烦是每次推送都必须输入口令,但是在某些只开放http端口的公司内部就无法使用ssh协议而只能用https。
branch
创建dev分支,然后切换到dev分支
git checkout -b dev
命令查看当前分支
git branch
合并时,要先切换回master分支git checkout master
然后:git merge dev
合并完成后,就可以放心地删除dev分支了
git branch -d dev
实际上,切换分支这个动作,用switch更科学。因此,最新版本的Git提供了新的git switch命令来切换分支:
创建并切换到新的dev分支,可以使用:
git switch -c dev
直接切换到已有的master分支,可以使用:
git switch master
使用新的git switch命令,比git checkout要更容易理解。
conflict
这种情况下,Git无法执行“快速合并”,只能试图把各自的修改合并起来,但这种合并就可能会有冲突,必须手动解决冲突后再提交。
用git log --graph
命令可以看到分支合并图。也可以简化输出结果
git log --graph --pretty=oneline --abbrev-commit
通常,合并分支时,如果可能,Git会用Fast forward模式,但这种模式下,删除分支后,会丢掉分支信息。
如果要强制禁用Fast forward模式,Git就会在merge时生成一个新的commit,这样,从分支历史上就可以看出分支信息。
合并分支时,使用–no-ff参数,表示禁用Fast forward
如:git merge --no-ff -m "merge with no-ff" dev
stash
Git还提供了一个stash功能,可以把当前工作现场“储藏”起来,等以后恢复现场后继续工作:git stash
查看“储藏区”:git stash list
恢复:git stash apply
,恢复后,stash内容并不删除,你需要用git stash drop
来删除
恢复并删除“储藏区”:git stash pop
bug
当我们在master分支修复bug之后,dev是早期master分支分出来的,所以bug在dev分支上依然存在。
同样的bug,要在dev上修复,我们只需要把4c805e2 fix bug 101这个提交所做的修改“复制”到dev分支。注意:我们只想复制4c805e2 fix bug 101这个提交所做的修改,并不是把整个master分支merge过来
cherry-pick <commit>
命令,让我们能复制一个特定的提交到当前分支
delete branch
如果要丢弃一个没有被合并过的分支,可以通过git branch -D <name>
强行删除
collaboration
查看远程库信息,使用git remote -v
;
本地新建的分支如果不推送到远程,对其他人就是不可见的;
从本地推送分支,使用git push origin branch-name
,如果推送失败,先用git pull
抓取远程的新提交;
在本地创建和远程分支对应的分支,使用git checkout -b branch-name origin/branch-name
,本地和远程分支的名称最好一致;
建立本地分支和远程分支的关联,使用git branch --set-upstream branch-name origin/branch-name
;
从远程抓取分支,使用git pull
,如果有冲突,要先处理冲突。
Rebase
git rebase
操作可以把本地未push的分叉提交历史整理成直线;
rebase的目的是使得我们在查看历史提交的变化时更容易,因为分叉的提交需要三方对比。
tag
标签不是按时间顺序列出,而是按字母排序的 ,创建的标签都只存储在本地,不会自动推送到远程。
命令git tag <tagname>
用于新建一个标签,默认为HEAD,也可以指定一个commit id;
命令git tag -a <tagname> -m "blablabla..."
可以指定标签信息;
命令git show <tagname>
查看标签信息和说明文字
命令git tag
可以查看所有标签
命令git push origin <tagname>
可以推送一个本地标签;
命令git push origin --tags
可以推送全部未推送过的本地标签;
命令git tag -d <tagname>
可以删除一个本地标签;
命令git push origin :refs/tags/<tagname>
可以删除一个远程标签。
GitHub
在GitHub上,可以任意Fork开源仓库;
自己拥有Fork后的仓库的读写权限;
in --tags`可以推送全部未推送过的本地标签;
命令git tag -d <tagname>
可以删除一个本地标签;
命令git push origin :refs/tags/<tagname>
可以删除一个远程标签。
GitHub
在GitHub上,可以任意Fork开源仓库;
自己拥有Fork后的仓库的读写权限;
可以推送pull request给官方仓库来贡献代码。