基本功Git

Git 工作原理,基本操作,创建与合并分支

2018-08-22  本文已影响15人  专职跑龙套

前东家使用 Perforce 做版本控制,现东家使用 Git。

Git 工作原理

Git 和其他版本控制系统的主要差别在于,Git 只关心文件数据的整体是否发生变化,而大多数其他系统则只关心文件内容的具体差异。
这类系统(CVS,Subversion,Perforce,Bazaar 等等)每次记录有哪些文件作了更新,以及都更新了哪些行的什么内容:


其他系统在每个版本中记录着各个文化的具体差异

Git 并不保存这些前后变化的差异数据。实际上,Git 更像是把变化的文件作快照后,记录在一个微型的文件系统中。每次提交更新时,它会纵览一遍所有文件的指纹信息并对文件作一快照,然后保存一个指向这次快照的索引。为提高性能,若文件没有变化,Git 不会再次保存,而只对上次保存的快照作一链接。Git 的工作方式就如下图所示:


Git保存每次更新时的文件快照

工作区 Working Directory VS 暂存区 Staging Directory

Git 工作流

本地仓库由 Git 维护的三棵“树“组成:

通过下面这个图可以清晰的表示不同区的切换:
引用自:http://marklodato.github.io/visual-git-guide/index-zh-cn.html

不同区的切换

文件的三种状态

版本库

工作区中的隐藏目录 .git,就是 Git 的版本库。
.git 目录结构如下:

.git 目录结构

其中:

什么是 HEAD

HEAD 默认指向指向当前分支的最新提交。


HEAD 默认指向指向当前分支的最新提交

也可以通过 git show HEAD 命令看到当前 HEAD 的位置:

通过 git show HEAD 命令看到当前 HEAD 的位置

什么是 origin 和 master

通过 Git 来修改代码,主要包括如下三步:

涉及到两个 repository:

找到最近创建的一个 Github 项目:https://github.com/chenxiangcyr/spring-cloud-config-repo-demo
现在我们通过如下命令 Clone 到本地:
git clone git@github.com:chenxiangcyr/spring-cloud-config-repo-demo.git

在 Clone 完成之后,Git 会自动为你将此远程仓库命名为 origin,并下载其中所有的数据,建立一个指向它的 master 分支的指针。
因此 origin 是远程仓库的名字,master 是分支的名字。
我们用 (远程仓库名)/(分支名) 这样的形式表示远程分支,所以 origin/master 指向的是一个远程分支 remote branch。我们实际上是从这个远程分支 remote branch 中 Clone 数据到本地,但你无法在本地更改远程分支 remote branch 中的数据。
通过 git branch -r 可以查看远程分支:

查看远程分支

我们也可以通过 cat .git/config 看到 origin 的含义:

[core]
    repositoryformatversion = 0
    filemode = true
    bare = false
    logallrefupdates = true
    ignorecase = true
    precomposeunicode = true
[remote "origin"]
    url = git@github.com:chenxiangcyr/spring-cloud-config-repo-demo.git
    fetch = +refs/heads/*:refs/remotes/origin/*
[branch "master"]
    remote = origin
    merge = refs/heads/master

同时,Git 会建立一个属于你自己的本地 master 分支,它指向的是你刚刚从远程分支 remote branch 传到你本地的副本。
通过 git branch 可以查看本地分支:

本地分支

总结:

随着你不断的改动文件,git add, git commitmaster 的指向会自动移动。最终你还要通过 git push 命令来将修改推送到远程分支。
git push origin master:master

Git 基本操作

引用自:http://marklodato.github.io/visual-git-guide/index-zh-cn.html


上面的四条命令在工作目录、暂存目录(也叫做索引)和仓库之间复制文件。

也可以跳过暂存区域直接从仓库取出文件或者直接提交代码:


diff 查看两次提交之间的变动

checkout

checkout 命令用于从历史提交(或者暂存区域)中拷贝文件到工作目录,也可用于切换分支。

reset

reset 命令把当前分支指向另一个位置,并且有选择的变动工作目录和索引。也用来在从历史仓库中复制文件到索引,而不动工作目录。

如果不给选项,那么当前分支指向到那个提交。如果用 --hard 选项,那么工作目录也更新,如果用 --soft选项,那么都不变。
如果没有给出提交点的版本号,那么默认用 HEAD。这样,分支指向不变,但是索引会回滚到最后一次提交,如果用 --hard 选项,工作目录也同样。

reset

cherry pick

cherry-pick 命令"复制"一个提交节点并在当前分支做一次完全一样的新提交。

cherry pick

rebase

交互式变基 (rebase)。它可以用来编辑提交信息,或者将多个提交压缩成一个提交。
git rebase -i HEAD~n

Git 创建与合并分支

Git 关于分支的操作主要包括:

每次提交,Git 都把它们串成一条时间线,这条时间线就是一个分支。在 Git 里,这个分支叫主分支,即 master 分支。HEAD 严格来说不是指向提交,而是指向 mastermaster 才是指向提交的,所以, HEAD 指向的就是当前分支。每次提交,master 分支都会向前移动一步,这样,随着你不断提交,master 分支的线也越来越长:

一个具体的 Case

我们目前在 master 分支上,下一阶段要开发一个新需求付款,因此需要在一个新的分支 payment 上开发,测试,最后合并到 master 分支上。

创建新分支:

git checkout -b payment

以上操作相当于:

git branch payment
git checkout payment

随后我们在 payment 分支在不断的向前推进:

这时候,突然来了一个线上的 Issue,需求紧急修复,因此我们停下手动上的工作,需要在一个新的分支 bugfix 上开发,测试,最后合并到 master 分支上。

创建新分支:

git checkout -b bugfix

随后我们在 bugfix 分支上进行修改:

测试没问题后,合并到 master 分支上:

git checkout master
git merge bugfix

在合并的时候,由于当前 master 分支所指向的提交是 bugfix 的直接上游,所以 Git 只是简单的将指针向前移动。 换句话说,当你试图合并两个分支时,如果顺着一个分支走下去能够到达另一个分支,那么 Git 在合并两者的时候,只会简单的将指针向前推进(指针右移),因为这种情况下的合并操作没有需要解决的分歧,这就叫做 “快进(fast-forward)”。

随后我们上线该紧急修复,然后可以使用命令来删除 bugfix 分支:

git branch -d bugfix

接下来,我们切换到之前的 payment 分支上继续工作:

测试没问题后,合并到 master 分支上:

git checkout master
git merge payment

这和你之前合并 bugfix 分支的时候看起来有一点不一样。在这种情况下,你的开发历史从一个更早的地方开始分叉开来。 因为 master 分支所在提交并不是 payment 分支所在提交的直接祖先,Git 不得不做一些额外的工作。

出现这种情况的时候,Git 会使用两个分支的末端所指的快照(蓝色部分)以及这两个分支的工作祖先(黄色部分),做一个简单的三方合并。


引用:
Git 教程 创建与合并分支
3.2 Git 分支 - 分支的新建与合并
浅析 Git 思想和工作原理
图解Git
Git 的origin和master分析(转)

上一篇 下一篇

猜你喜欢

热点阅读