参考:《 git 的入门课 》
Git 基础命令
-
git init
:初始化本地仓库。在本地的项目目录下生成.git
文件夹git remote add origin <远程仓库url>
:本地仓库关联远程仓库,用于git push origin
-
git clone <远程仓库url>
:克隆现有的远程仓库 -
git add
:把文件添加到仓库$ git add readme.txt 或:添加当前目录下的全部修改 $ git add .
-
git commit
:把文件提交到仓库$ git commit -m "wrote a readme file"
-
git status
:时刻掌握仓库当前的状态,并且会有提示 -
git diff [filename]
:查看相较于上一次暂存都修改了些什么内容 -
git log
:显示从最近到最远的提交日志
如果嫌输出信息太多,看得眼花缭乱的,可以试试加上--pretty=oneline
参数:git log --pretty=oneline
git log --graph --pretty=oneline --abbrev-commit
:图示提交历史和分支历史
-
git reset
:回退版本
git reset --hard [HEAD~ 或者 commit hash]
:--hard
表示直接把更改内容写入当前文件,修改立刻见效首先,Git 必须知道当前版本是哪个版本,在 Git 中,用
HEAD
表示当前版本,也就是最新的提交,上一个版本就是HEAD^
,上上一个版本就是HEAD^^
,当然往上 100 个版本写 100 个 ^ 比较容易数不过来,所以写成HEAD~100
。 -
git reflog
:用来记录每一次命令$ git reflog 50ed06b (HEAD -> master) HEAD@{0}: reset: moving to HEAD~ e55063a HEAD@{1}: reset: moving to HEAD e55063a HEAD@{2}: commit: add distributed 50ed06b (HEAD -> master) HEAD@{3}: commit (initial): wrote a readme file ESC
第一列就是 commit hash
Git 分支
git 分支: Git 会把仓库中的每次提交串成一条时间线,这条时间线就是一个分支。在 Git 里,每个仓库都会有一个主分支,即 master 分支。`HEAD` 严格来说不是指向提交,而是指向 master,master 才是指向提交的,所以,`HEAD` 指向的就是当前分支。一开始的时候,master 分支是一条线,Git 用 master 指向最新的提交,再用 HEAD
指向 master,就能确定当前分支,以及当前分支的提交点:
每次提交,master 分支都会向前移动一步,这样,随着你不断提交,master 分支的线也越来越长。
当我们创建新的分支,例如 dev 时,Git 新建了一个指针叫 dev,指向 master 相同的提交,再把 HEAD
指向 dev,就表示当前分支在 dev 上:
你看,Git 创建一个分支很快,因为除了增加一个 dev 指针,改改 HEAD
的指向,工作区的文件都没有任何变化!
不过,从现在开始,对工作区的修改和提交就是针对 dev 分支了,比如新提交一次后,dev 指针往前移动一步,而 master 指针不变:
假如我们在 dev 上的工作完成了,就可以把 dev 合并到 master 上。Git 怎么合并呢?最简单的方法,就是直接把 master 指向 dev 的当前提交,就完成了合并:
所以 Git 合并分支也很快!就改改指针,工作区内容也不变!
合并完分支后,甚至可以删除 dev 分支。删除 dev 分支就是把 dev 指针给删掉,删掉后,我们就剩下了一条 master 分支:
了解了 git 分支的工作原理后,接下来让我们实际操作体验一下。首先,我们创建 dev 分支,然后切换到 dev 分支:
-
git checkout -b dev
=git switch -c dev
:创建分支 -
git branch
:查看当前分支 -
git switch master
=git checkout master
:切换到 master 分支 -
git merge dev
:合并 dev 分支到 master(须当前在 master 分支) -
git branch -d dev
:删除分支 -
git push origin master
=git push
:推送到远程 master 分支(须当前在 master 分支) -
git push origin dev
:推送到远程 dev 分支(须当前在 dev 分支)
通常,合并分支时,如果可能,Git 会用 Fast forward
模式,但这种模式下,删除分支后,会丢掉分支信息。
下面我们看一看 --no-ff
方式的 git merge
,表示禁用 Fast forward
:
git merge --no-ff -m "merge with no-ff" dev
:$ git log --graph --pretty=oneline --abbrev-commit * fc76cf7 (HEAD -> master) merge with no-ff |\ | * f52c633 (dev) add merge |/ * cf810e4 conflict fixed ...
可以看到,不使用 Fast forward
模式,merge 后就像这样:
在实际开发中,我们应该按照几个基本原则进行分支管理:
- 首先,master 分支应该是非常稳定的,也就是仅用来发布新版本,平时不能在上面干活;
- 其次,干活都在 dev 分支上,也就是说,dev 分支是不稳定的,到某个时候,比如 1.0 版本发布时,再把 dev 分支合并到 master 上,并在 master 分支发布 1.0 版本;
- 你和你的小伙伴们每个人都在 dev 分支上干活,每个人都有自己的分支,时不时地往 dev 分支上合并就可以了。
所以,团队合作的分支看起来就像这样:
Cherry Pick
-
git cherry-pick <commitHash>
:将指定的提交 commit 应用于当前分支。 -
git cherry-pick dev
=git merge dev
:将 dev 分支的最近一次提交,转移到当前分支。
举例来说,代码仓库有 master 和 dev 两个分支:
a - b - c - d master
\
e - f - g dev
现在将提交f应用到 master 分支:
a - b - c - d - f master
\
e - f - g dev
master 分支的末尾增加了一个提交 f。
Git 标签
参考: Git 标签 (#9)
Git 的标签虽然是版本库的快照,但其实它就是指向某个 commit 的指针(跟分支很像对不对?但是分支可以移动,标签不能移动),所以,创建和删除标签都是瞬间完成的。
-
git tag v1.0
:默认在当前分支的最新 commit 打一个标签 ”v1.0“ -
git tag v1.0 <commitHash>
:在指定的 commit 上打标签(通过git reflog
查看 commitHash) -
git tag
:查看所有标签(按字母排序,不是按创建时间) -
git show v1.0
:查看标签信息 -
git tag -a v0.9 -m "version v0.9 released" <commitHash>
:创建带有说明的标签(附注标签) -
git tag -d v1.0
:删除指定标签 -
git push origin v1.0 或 --tags
:把指定(v1.0
)或所有(--tags
)标签推送到远程仓库 -
git push --delete origin v1.0
=git push origin :refs/tags/v1.0
:删除远程仓库的标签(本地的标签要通过git tag -d v1.0
手动删除)