git basic principles and common case handling methods

git basic principles and common case handling methods

Alt text

In the current project development, many people are basically involved, which requires a version control system to manage our projects. Like most things, git was born in a time of great contention and innovation.

0. Brief History

The Linux kernel open source project has a large number of participants. The vast majority of Linux kernel maintenance was spent on the tedious business of submitting patches and keeping archives (between 1991 and 2002). By 2002, the entire project team began to enable BitKeeper, a proprietary distributed version control system, to manage and maintain the code. 
In 2005, the partnership between the commercial companies that developed BitKeeper and the Linux kernel open source community ended, and they took back the Linux kernel community's right to use BitKeeper for free. This forced the Linux open source community (especially the creator of Linux, Linus Torvalds) to develop its own versioning system based on lessons learned from using BitKeeper. They set several goals for the new system:

  • speed
  • simple design
  • Strong support for non-linear development mode (allows thousands of parallel development branches)
  • fully distributed
  • Ability to efficiently manage very large-scale projects like the Linux kernel (speed and data volume)

Since its inception in 2005, Git has matured and matured, maintaining its original goals while being highly usable. It's fast, great for managing large projects, and has an incredibly non-linear branch management system (suffocating branch management).

1. Basic principles

1.1 Direct File Snapshot Concept

The main difference between Git and other version control systems is that Git only cares about whether the overall file data has changed, while most other systems only care about specific differences in file content.

Git maintains data integrity at all times through fingerprint strings. The fingerprint string is a SHA-1 hash value calculated by Git using the SHA-1 algorithm through the content of the file and the structure of the directory. This string is composed of 40 hexadecimal strings, as follows, we often see: 
696503be5f0630b43fce06cca01a9426c683bfb9, which is our commitId.

1.2 Three states of a file

git 在管理项目时,项目中的文件存在如下三种状态:

  • 已提交(committed)
  • 已修改(modified)
  • 已暂存(staged)

Alt text

我们项目的文件都处于 working directory,当文件进行了修改,文件的状态就会变为 modified。通过 git add . 的命令,文件就会被提交到 staging area,变为 staged 状态。最后通过 git commit 命令,文件就会被提交到 git directory,文件状态就更新为 committed 。以上,就是 git 操作一个最基本的流程,以及这个过程中的状态变化。

1.3 提交

例如,项目的根目录下有三个文件,进行第一次 commit ,git 仓库中会有这样的结构产生:

Alt text

我们会看到上图这样一个对象的链式结构:它们各自都代表什么呢?三个 blob 对象是三个文件的快照块,tree 对象记录目录树及其内容,最后有一个包含了指向 tree 对象的索引和其他提交信息元数据的 commit 对象。

我们提交几次代码后,就会出现这样的链:

Alt text

由 commit 对象构成的链式结构,每个 commit 对象指向了项目文件的快照。那么,千呼万唤始出来,这个链其实就是我们 《1.4》要分析的分支了。

1.4 分支

分支到底是什么呢?其实,本质上,Git 中的分支仅仅是个指向 commit 对象的可变指针。默认使用 master 作为分支的默认名字。每一次提交,这个指针都会向前移动,指向最后一次提交对象,如下图:

Alt text

创建分支 
那么,到现在我们就应该知道,git 创建一个新的分支,其实就是创建了一个新的分支指针。例如,我们新建 testing,如下图:

Alt text

切换分支

Alt text

如上图,我们会看到除了 master 和 testing 还有另外一个指针,那就是 HEADHEAD 指针的指向,代表了我们当前所在的分支。例如上图,HEAD 现在指向 master,那么当前的分支就是 master 分支。切换分支,就是改变 HEAD 指针的指向,例如下图:

Alt text

现在,我们就把分支切换到 testing 分支了。 
切换分支之后,我们可以继续提交更新文件,就会出现下图这样结果:

Alt text

看到这个图,大家就应该知道我们后面会讲什么了,那就是:—–

分支合并 
我们来看一下图这样的情况:

Alt text

如图,我们项目的 git 管理情况,存在三个分支,分别是:masterhotfix 和 iss53。这个对应怎样的一种场景呢?例如:master 是我们项目的主分支,我们现在接到一个新的需要要开发,就切了分支 iss53,并且进行了一次 commit 。突然,发现一个紧急的线上问题,我们要修复,所以我们切回了 master 分支,然后又切出了一个 hotfix 分支,切到 hotfix ,修复完问题之后,我们进行了一次 commit。要提交上线了,那么我们就要合并分支了~~ 
操作:

1.$ git checkout master
2. $ git merge hotfix

结果:

Alt text

hotfix 与 mater 进行了合并了。这是最简单的分支合并情况,下面来个复杂一些的,我们回到 iss53 继续开发。。。。。。。。项目变成了下面这样:

Alt text

现在分支的合并就不会像上次 hotfix 那样直接合并移动指针那么简单了。 
因为你的开发历史在更早地方就开始分叉了。看下图,master 分支的当前提交对象(C4)并不是 iss53 分支的直接祖先,git 需要做额外的处理。git 会用到两个分支的末端(C4 和 C5)以及它们的共同祖先 (C2)进行一次简单的三方合并计算。如下图红框标出的要进行合并的三个提交对象:

Alt text

合并后的结果是重新生成一个新的快照,并自动创建一个新的提交对象 C6 指向这个快照。这个提交对象会有两个祖先(C4 和 C5)。

Alt text

这样,我们的分支就算合并完成了。分支的改动到合并到了 master,iss53 如果不在使用,就可以删除掉了。

1.$ git branch -d iss53

以上是 git 的一些基本原理,下面我们会讲一个好用但有时又让人害怕的命令git reset。 
git reset命令充分利用到了上述的 git 基本原理,下面我们通过学习分析git reset的用法与原理,来加深一下对 git 基本原理的理解~~

2. git reset 的原理

2.1 名词解释

image

  • working directory(git 的工作目录)

  • staging area(暂存区域)

  • git directory(repository)(本地仓库)

  • HEAD (当前分支头指针位置)

2.2 git reset 常用来干什么呢

  • git reset 之前

Alt text

  • git reset 之后

Alt text

可以修改当前 Head 指针的位置。

我们常用 git reset commitId 回退到之前的 commitId 的状态,就是将当前分支的 HEAD 指针进行了移动,但是,git reset 一般常用的参数会有三种,这三种参数产生的效果是不同的:

(1)--mixed(default)

Alt text 
上图是 --mixed 的效果。图示,使用 --mixed 回到某个 commit(例如CommitId2)的时候,HEAD Repository 与 Staging Area 的状态是一致,与当前这个 CommitId2 的状态保持一致,但是,Working Direcotry 还是之前 CommitId3 的状态。

(2)--soft

Alt text

上图是 --soft 的效果。图示,使用 --soft 回到某个 commit(例如CommitId2) 的时候,只有 HEAD Repository 回到了CommitId2的状态, Staging Area 和 Working Direcotry 会与 CommitId3 的状态一致。

(3)--hard

Alt text

上图是 --hard 的效果。图示,使用 --hard 回到某个 commit(例如CommitId2) 的时候,HEAD Repository 、 Staging Area 和 Working Direcotry 的状态是一致,都与 CommitId2 的状态一样。也就是说,刚刚的一些修改操作,一些保存到 Staging Area 的修改,都会随着你的 --hard而消失的。

3. 常见 case 处理

3.1 删除远程仓库的某次错误提交

case one: 
假设你有 3 个 commit 如下:

1.commit 3
2.commit 2
3.commit 1

其中最后一次 commit 3 是错误的,那么可以执行:

1.git reset --hard HEAD~1

此时,HEAD is now at commit 2

然后可以使用 git push --force 将本次变更强行推送至服务器。这样,在服务器上的最后一次错误提价也彻底消失了。

Pay Attention:此类操作存在风险因素,例如:在你的 commit 3 之后,其它小伙伴又提交了新的 commit 4,那么你强制推送之后,小伙伴的 commit 4 也会跟着一起消失了。

3.2 修改上次提交的代码,做一次更完美的 commit

case two: 
假如你上次提交的代码有些问题,不够完美,希望做一次更完美的 commit,且此时有很多代码你是出于修改状态的,你可以按如下流程做: 
(1) git reset commitId (注: 不要带 –hard) 到上一个版本 
(2) git stash,暂存修改 
(3) git push --force,强制 push,远程的最新的一次 commit 被删除 
(4) git stash pop,释放暂存的修改,开始继续修改代码 
(5) git add . -> git commit -> git push 完成新的commit提交

4. 常用 git 技巧

(1)修改最后一次提交 
有时候我们刚提交(git commit)完,会发现漏掉了几个文件没有添加,又或者是 commit 的信息填写有误。想要撤销刚才的提交操作,可以使用下面的命令: 
git commit --amend 
完整的例子:

1.$ git commit -m 'initial commit'
2.$ git add forgotten_file
3.$ git commit --amend -m "new commit des"

(2)别名的使用 
习惯使用 git 命令后,往往会有 “偷懒” 的想法,别名的使用可以让你少敲几个字母,提高效率。(当然,前提是你记得自己的别名,并且熟练使用它~~),如下:

1.$ git config -- global alias .co checkout
2.$ git config -- global alias .br branch
3.$ git config -- global alias .ci commit
4.$ git config -- global alias .st status

After this configuration, the future is  git co , git checkout and so on, and so on. .
The use of aliases is not limited to the above commands, you can configure more aliases according to your own habits~~

End

Don't forget the well digger when drinking water~~ Worship the great god Linus

Alt text

ps: I recommend everyone to take a look at his public courses. NetEase should have them. The idea of ​​God is still very different~~

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325686292&siteId=291194637