Git 的常见使用命令 | 青训营

55 阅读11分钟

前言

由于想以团队合作的形式在青训营完成极简版抖音的项目,所以在开发工作进行以前,特此学习了 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指针:

创建testing分支

git通过HEAD指针来判断当前处于哪个分支:

当前处于哪个分支

4.分支切换

如果想要切换到已经创建好的分支,可以执行如下命令:

git checkout testing

此时的HEAD指针就会指向testing,如图所示: 切换到testing分支

如果此时我们在testing分支上对文件做了一些修改,然后执行git commit提交,就会变成下图所示的样子:

修改testing分支后提交

我们的testing分支向后移动了,但是master分支却没有,它仍然指向运行git checkout时所指的对象。而如果我们切换回master分支,再对其进行修改后提交,就会变成这个样子:

切换回master后修改

5.分支的合并(merge)

假设你新建了一个分支iss53进行开发工作,此时突然接到通知要紧急修复bug,于是git commit当前的分支后,新建了hotfix分支修复bug并进行提交,此时的结构如下所示:

hotfix branch

而下面要做的就是将你已经修改好的bug,即hotfix分支,合并到master分支上,可以执行如下命令:

git checkout master
git merge hotfix

最终,合并后的情况如图所示:

hotfix合并后

在解决完这个bug后,hotfix分支没有了存在的意义,于是可以执行如下命令删除它:

git branch -d hotfix

随后切换到iss53分支继续进行开发工作,如图所示:

切换回iss53

假设此时iss53分支上的开发工作已经完毕,需要合并进master分支,可以执行如下命令:

git checkout master
git merge iss53

但这次的合并和上一次有不同的地方。在这种情况下,开发历史从一个更早的地方开始分叉开来(diverged)。因为,master分支所在提交并不是iss53分支所在提交的直接祖先,Git不得不做一些额外的工作。

merge iss53

出现这种情况的时候,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, 最后以此将之前另存为临时文件的修改依序应用,如下所示:

将C4中的修改rebase到C3上

随后切换回master分支进行一次合并:

git checkout master
git merge experiment

合并回master 注:由于自己对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

快进合并master分支,使之包含来自client分支的修改

接下来你决定将server分支中的修改也整合进来。使用git rebase <basebranch> <topicbranch>命令可以直接将主题分支(即本例中的server)变基到目标分支(即master)上。这样做能省去你先切换到server分支,再对其执行变基命令的多个步骤:

git rebase master server

如图,将server中的修改变基到master上 所示,server中的代码被“续”到了master后面。

将server中的修改变基到master上

然后就可以快进合并主分支master了:

git checkout master
git merge server
# 此时client和serve分支都没用了,可以删掉
git branch -d client
git branch -d server

最终的提交历史

rebase的风险:如果提交存在于你的仓库之外,而别人可能基于这些提交进行开发,那么不要执行变基。