Git学习(二)
文章目录
一、版本管理
1.1 撤销修改
git commit --amend
这个命令会将暂存区中的文件提交。 如果自上次提交以来你还未做任何修改(例如,在上次提交后马上执行了此命令), 那么快照会保持不变,而你所修改的只是提交信息。
例如,你提交后发现忘记了暂存某些需要的修改,可以像下面这样操作:
$ git commit -m ‘initial commit’
$ git add forgotten_file
$ git commit --amend
最终你只会有一个提交——第二次提交将代替第一次提交的结果。
当你在修补最后的提交时,并不是通过用改进后的提交 原位替换 掉旧有提交的方式来修复的, 理解这一点非常重要。从效果上来说,就像是旧有的提交从未存在过一样,它并不会出现在仓库的历史中。
修补提交最明显的价值是可以稍微改进你最后的提交,而不会让“啊,忘了添加一个文件”或者 “小修补,修正笔误”这种提交信息弄乱你的仓库历史。
取消暂存
$ git reset HEAD readme.txt
撤销修改
$ git checkout – readme.txt
1.2 删除文件
rm test.txt
此时,工作区和版本库就不一致了
$ git rm test.txt
rm ‘test.txt’
$ git commit -m “remove test.txt”
现在,文件就从版本库中被删除了。
小提示:先手动删除文件,然后使用git rm 和git add效果是一样的。
$ git checkout – test.txt
一种情况是删错了,因为版本库里还有呢,所以可以很轻松地把误删的文件恢复到最新版本
如果从来没提交到版本库,是没法还原
1.3 小结
-
场景1:当你改乱了工作区某个文件的内容,想直接丢弃工作区的修改时,用命令
git checkout -- file
-
场景2:当你不但改乱了工作区某个文件的内容,还添加到了暂存区时,想丢弃修改,分两步,第一步用命令
git reset HEAD <file>
,就回到了场景1,第二步按场景1操作 -
场景3:已经提交了不合适的修改到版本库时,想要撤销本次提交,可以用命令
git reset --hard commit_id
,不过前提是没有推送到远程库
二、分支管理
2.1 git 分支原理
假设现在有一个工作目录,里面包含了三个将要被暂存和提交的文件。
Git 仓库对象变化详解:
现在,Git 仓库中有五个对象:三个 blob 对象(保存着文件快照)、一个 树 对象 (记录着目录结构和 blob 对象索引)以及一个 提交 对象(包含着指向前述树对象的指针和所有提交信息)。
做些修改后再次提交,那么这次产生的提交对象会包含一个指向上次提交对象(父对象)的指针。
Git 的分支,其实本质上仅仅是指向提交对象的可变指针。 Git 的默认分支名字是 master。 在多次提交操作之后,你其实已经有一个指向最后那个提交对象的 master 分支。 master 分支会在每次提交时自动向前移动。
在 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
分支:
2.2 修改不同的分支
2.2.1 创建分支
首先,我们创建dev分支,然后切换到dev分支
$ git checkout -b dev
Switched to a new branch ‘dev’
git checkout命令加上-b参数表示创建并切换,相当于以下两条命令:
$ git branch dev
$ git checkout dev
Switched to branch ‘dev’
2.2.1 查看当前分支
$ git branch
可以在dev
分支上正常提交,比如对readme.txt
做个修改,提交:
$ git add readme.txt
$ git commit -m “branch test”
dev
分支的工作完成,我们就可以切换回master
分支
$ git checkout master
切换回master
分支后,再查看一个readme.txt
文件,刚才添加的内容不见了!因为那个提交是在dev
分支上,而master
分支此刻的提交点并没有变:
2.3 git 合并分支
2.3.1 合并分支
现在,我们把dev
分支的工作成果合并到master
分支上:
$ git merge dev
2.3.2 删除分支
合并完成后,就可以放心地删除dev分支了:
$ git branch -d dev
查看
我们注意到切换分支使用git checkout <branch>
,而 Git 中撤销修改则是git checkout -- <file>
,同一个命令,有两种作用,确实有点令人迷惑。
实际上,切换分支这个动作,用switch
更科学。因此,最新版本的 Git 提供了新的git switch
命令来切换分支:
git switch
创建并切换到新的dev
分支,可以使用:
$ git switch -c dev
直接切换到已有的master
分支,可以使用:
$ git switch master
使用新的git switch
命令,比git checkout
要更容易理解。
2.4 git 合并策略
通常,合并分支时,如果可能,Git 会用Fast forward
模式,但这种模式下,删除分支后,会丢掉分支信息。
如果要强制禁用Fast forward
模式,Git 就会在merge
时生成一个新的commit
,这样,从分支历史上就可以看出分支信息。
下面我们看一看--no-ff
方式的git merge
:
$ git merge --no-ff -m “merge with no-ff” dev
因为本次合并要创建一个新的commit
,所以加上-m
参数,把commit
描述写进去。
合并后,我们用git log看看分支历史:
$ 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
分支上合并就可以了。
所以,团队合作的分支看起来就像这样:
2.5 实战(1): 准备新分支
$ git checkout -b dev
2.6 实战(2): 修改master分支
$ git checkout master