前言
由于想以团队合作的形式在青训营完成极简版抖音的项目,所以在开发工作进行以前,特此学习了 git 的使用,争取做到在开发的过程中不坑队友吧。
一、本地仓库
1.在已存在目录中初始化仓库
通过命令行进入该目录,然后执行:
git init
追踪这些文件并进行初始提交:
git add *
git add LICENSE
git commit -m 'initial project version'
2.克隆现有的仓库
git clone https://github.com/libgit2/libgit2 mylibgit
3.查看当前仓库中文件的状态
git status
git status -s
4.追踪新文件
此时在工作区中新加了文件ReadME.md
,它将处于未跟踪状态。
git add ReadME.md
会跟踪ReadME.md
并置为暂存状态。
5.暂存已修改的文件
假设仓库初始时拥有文件init.md
,此时对该文件进行编辑后,想要暂存此次更新,同样可以执行git add
命令。此命令可以:
- 开始跟踪新文件;
- 把已跟踪的文件放到暂存区;
- 合并时把有冲突的文件标记为已解决状态等。
6.忽略文件
如果项目中拥有一些不想被git追踪的文件,例如日志信息等,可以创建一个名为.gitignore
的文件,列出要忽略的文件的模式,下面为一个实例:
# 忽略所有的 .a 文件
*.a
# 但跟踪所有的 lib.a,即便你在前面忽略了 .a 文件
!lib.a
# 只忽略当前目录下的 TODO 文件,而不忽略 subdir/TODO
/TODO
# 忽略任何目录下名为 build 的文件夹
build/
# 忽略 doc/notes.txt,但不忽略 doc/server/arch.txt
doc/*.txt
# 忽略 doc/ 目录及其所有子目录下的 .pdf 文件
doc/**/*.pdf
7.提交更新
在执行提交操作前,请确认是否有已修改或新建的文件还没git add
过,否则提交的时候不会记录这些尚未暂存的变化。所以,每次准备提交前,先用git status
看下所需要的文件是否都已暂存,然后再运行提交命令:
git commit
git commit -m "0427: First attempt"
git commit -a #跳过git add步骤,自动把所有已经跟踪过的文件暂存起来一并提交
8.移除文件
要从Git中移除某个文件,就必须要从暂存区域移除,然后提交。
rm PROJECTS.md #删除文件
git rm PROJECTS.md #记录此次移除文件的操作
还有一种情况是,需要在不删除文件的情况下,取消Git对它的跟踪,可以采用如下命令:
git rm --cached README
git rm *~ #删除log/目录下扩展名为.log的所有文件
9.移动文件
在需要对文件进行重命名或移动位置时,可以执行以下命令:
git mv file_from file_to
#相当于执行以下命令
mv README.md README
git rm README.md
git add README
10.查看提交历史
若想要查看仓库的提交历史,可执行以下命令:
git log
git log -p -2 #显示2条每次提交所引入的差异
git log --stat #查看每次提交的简略统计信息
git log --pretty=format:"%h - %an, %ar : %s" #格式化显示日志信息
git log --since=2.weeks #查看最近两周的所有提交
11.撤销操作
如果在一次提交之后漏掉了几个文件,或者写错了提交信息,想撤销此次提交重新提交,可以执行如下命令:
git commit -m 'initial commit' #第一次提交
git add forgotten_file #添加漏掉的文件
git commit --amend #重新提交
12.撤销对文件的修改
在劈里啪啦修改完一顿文件后,发现并不理想,想撤销所有改动,从上一次提交的状态重新开始修改,可以执行如下命令:
git checkout -- CONTRIBUTING.md
二、远程仓库
1.查看远程仓库
如果想要查看已经配置的远程仓库信息,可以执行如下命令:
git remote
git remote -v #显示需要读写远程仓库使用的Git保存的简写与其对应的URL
2.添加远程仓库
若想添加一个新的远程Git仓库,并给它一个名称简写,可以执行如下命令:
git remote add pb https://github.com/paulboone/ticgit
3.从远程仓库中拉取
如果想要拉取远程分支中所有你还没有的数据,可以执行如下命令:
git fetch <remote>
4.推送到远程仓库
当想把代码推送到远程仓库时,可执行如下命令:
git push <remote> <branch>
git push origin master #将master分支推送到origin服务器
5.查看某个远程仓库
如果想查看某个远程仓库的详细信息,可以执行如下命令:
git remote show <remote>
6.远程仓库的重命名与移除
如果想要修改远程仓库的简写名,或移除远程仓库,可执行如下命令:
git remote rename pb paul #将简写名由pb改为paul
git remote remove paul #移除远程仓库paul
三、标签
1.列出已有标签
如果想要列出仓库中已有的标签,可以执行如下命令:
git tag
git tag -l "v1.8.5*" #查找v1.8.5为开头的标签
2.创建标签
如果想要在提交代码的时候创建标签,可以执行如下命令:
git tag -a v1.4 -m "my version 1.4" #-a为创建标签,-m定了一条将会存储在标签中的信息
git show #查看标签信息和与之对应的提交信息
#后期打标签
git log #查看提交的历史记录
git tag -a v1.2 9fceb02 #给9fceb02这条历史记录打标签为v1.2
3.共享标签
默认情况下,git push命令并不会传送标签到远程仓库服务器上。,所以需要执行如下命令显式地推送标签:
git push origin v1.5
git push origin --tags #一次性推送很多标签
4.删除标签
如果想要对标签进行删除操作,可以执行如下命令:
git tag -d v1.4-lw
但上述命令不会删除在远程仓库中的标签,所以要使用git push <remote> :refs/tags/<tagname>
更新远程仓库:
git push origin :refs/tags/v1.4-lw
To /git@github.com:schacon/simplegit.git
当然,还有一种更直观的删除远程仓库标签的方式:
git push origin --delete <tagname>
四、分支
1.前置知识
现在假设仓库中初始有三个文件,随后执行了git add让文件处于跟踪状态,再执行git commit提交,就会形成如下的结构: 其中blob分别保存了三个文件的快照,tree记录着目录结构和blob对象的索引,commit对象保存着提交信息以及tree的索引。 当再修改几次进行提交时,会形成如下的结构:
当有了这些基础知识后,我们来介绍一下git的分支。
2.分支介绍
Git的分支,本质上是指向提交对象的可变指针。Git的默认分支名是master。在多次提交操作之后,其实已经有一个指向最后那个提交对象的master分支。master分支会在每次提交时自动向前移动,如下所示:
3.创建分支
在创建分支时,git只是帮我们创建了一个可以移动的新的指针,具体命令如下:
git branch testing #创建一个testing分支
随后git就会帮我们在当前所在的提交对象上创建一个testing指针:
git通过HEAD
指针来判断当前处于哪个分支:
4.分支切换
如果想要切换到已经创建好的分支,可以执行如下命令:
git checkout testing
此时的HEAD
指针就会指向testing,如图所示:
如果此时我们在testing分支上对文件做了一些修改,然后执行git commit提交,就会变成下图所示的样子:
我们的testing分支向后移动了,但是master分支却没有,它仍然指向运行git checkout时所指的对象。而如果我们切换回master分支,再对其进行修改后提交,就会变成这个样子:
5.分支的合并(merge)
假设你新建了一个分支iss53
进行开发工作,此时突然接到通知要紧急修复bug,于是git commit当前的分支后,新建了hotfix
分支修复bug并进行提交,此时的结构如下所示:
而下面要做的就是将你已经修改好的bug,即hotfix
分支,合并到master
分支上,可以执行如下命令:
git checkout master
git merge hotfix
最终,合并后的情况如图所示:
在解决完这个bug后,hotfix
分支没有了存在的意义,于是可以执行如下命令删除它:
git branch -d hotfix
随后切换到iss53
分支继续进行开发工作,如图所示:
假设此时iss53
分支上的开发工作已经完毕,需要合并进master
分支,可以执行如下命令:
git checkout master
git merge iss53
但这次的合并和上一次有不同的地方。在这种情况下,开发历史从一个更早的地方开始分叉开来(diverged)。因为,master分支所在提交并不是iss53分支所在提交的直接祖先,Git不得不做一些额外的工作。
出现这种情况的时候,Git会使用两个分支的末端所指的快照(C4和C5)以及这两个分支的公共祖先(C2),做一个简单的三方合并,如图所示:
随后iss53
分支也完成了它的使命,可以执行git branch -d iss53
对其进行删除。
6.分支管理
对于分支的创建、合并、删除操作已经介绍完毕,接下来看一些其他的管理操作。
git branch #得到当前所有分支的列表
git branch -v #查看每一个分支的最后一次提交
git branch --merged #查看哪些分支已经合并到当前分支
git branch --no-merged #查看所有包含未合并工作的分支
7.分支的变基(rebase)
假设当前的开发任务分成了两个分支,并分别提交了更新:
上面介绍的操作是进行merge
,即让git进行c3、c4和它们的公共祖先c2的三方合并:
但还有一种方法,我们可以提取在C4中引入的补丁和修改,然后在C3的基础上应用一次。在Git中,这种操作就叫做变基(rebase)。可以使用rebase
命令将提交到某一分支上的所有修改都移至另一分支上。可以执行如下命令:
git checkout experiment
git rebase master
它的原理是首先找到这两个分支(即当前分支experiment、变基操作的目标基底分支master)的最近共同祖先C2,然后对比当前分支相对于该祖先的历次提交,提取相应的修改并存为临时文件,然后将当前分支指向目标基底C3, 最后以此将之前另存为临时文件的修改依序应用,如下所示:
随后切换回master
分支进行一次合并:
git checkout master
git merge experiment
注:由于自己对rebase操作不太熟悉,所以下面放一下手册中更详细的例子介绍,帮助自己理解
你创建了一个主题分支server,为服务端添加了一些功能,提交了C3和C4。然后从C3上创建了主题分支client,为客户端添加了一些功能,提交了C8和C9。最后,你回到server分支,又提交了C10。
假设你希望将client中的修改合并到主分支并发布,但暂时并不想合并server中的修改,因为它们还需要经过更全面的测试。这时,你就可以使用git rebase命令的--onto选项,选中在client分支里但不在server分支里的修改(即C8和C9):
git rebase --onto master server client
以上命令的意思是:“取出client分支,找出它从server分支分歧之后的补丁,然后把这些补丁在master分支上重放一遍,让client看起来像直接基于master修改一样”。
现在可以快进合并master分支了:
git checkout master
git merge client
接下来你决定将server分支中的修改也整合进来。使用git rebase <basebranch> <topicbranch>
命令可以直接将主题分支(即本例中的server)变基到目标分支(即master)上。这样做能省去你先切换到server分支,再对其执行变基命令的多个步骤:
git rebase master server
如图,将server中的修改变基到master上 所示,server中的代码被“续”到了master后面。
然后就可以快进合并主分支master了:
git checkout master
git merge server
# 此时client和serve分支都没用了,可以删掉
git branch -d client
git branch -d server
rebase的风险:如果提交存在于你的仓库之外,而别人可能基于这些提交进行开发,那么不要执行变基。