Git的使用以及团队协作 | 青训营笔记

108 阅读9分钟

这是我参与「第五届青训营 」笔记创作活动的第16天

1. Git是什么

Git is a free and open source distributed version control system designed to handle everything from small to very large projects with speed and efficiency

Git是一个免费的开源分布式版本管理系统,旨在快速高效地处理从小型到超大型的所有项目

1.1 版本控制

一种记录一个或若干文件内容变化,以便将来查阅特定版本修订情况的系统

image-20230112220718110

为什么需要版本控制?

  • 更好的关注变更,来接每个版本的改动是什么,方便对改动的代码进行检查,预防事故发生;
  • 也能够随时切换到不同的版本回滚误删误改的问题代码

1.2 Git基本原理

  • 每个库都存有完整的提交历史,可以直接在本地进行代码提交
  • 每次提交记录的都是完整的文件快照,而不是记录增量
  • 通过push等操作来完成和远端代码的同步

优点

  • 分布式开发,每个库都是完整的提交历史,支持本地提交,强调个体
  • 分支管理功能强大,方便团队合作,多人协同开发
  • 【校验和机制】保证完整性,一般只添加数据,很少执行删除操作,不容易导致代码丢失。(删除可通过新建分支,然后让删除内容的分支成为新的分支)

缺点

  • 相对SVN更复杂,学习成本更高
  • 对于大文件的支持不是特别友好(git-lfs工具可以弥补这个功能)

2. Git基本使用方式

2.1 Git Config

Git 有如下从高到低三个级别的配置,每个级别的配置可能重复,但是低级别的配置会覆盖高级别的配置。

  • --system
  • --global
  • --local

常见Git配置

  • 用户名配置

     git config --global user.name "anthony_4926"
     git config --global user.email "Anthony_4926@163.com"
    
  • Git命令别名配置

     git config --global alias.cin "commit --amend --no-edit"
    

2.2开始版本控制

首先,找一个合适的地方创建一个需要进行版本控制的文件夹:

 # mkdir demo
 # cd demo

然后,通过git init命令初始化demo这个文件夹,使之成为能够进行版本控制

 # git init

创建完成之后会在当前目录下生成一个隐藏文件。

 tree .git
 .git
 ├── branches
 ├── config
 ├── description
 ├── HEAD
 ├── hooks
 │   ├── applypatch-msg.sample
 │   ├── commit-msg.sample
 │   ├── fsmonitor-watchman.sample
 │   ├── post-update.sample
 │   ├── pre-applypatch.sample
 │   ├── pre-commit.sample
 │   ├── pre-merge-commit.sample
 │   ├── prepare-commit-msg.sample
 │   ├── pre-push.sample
 │   ├── pre-rebase.sample
 │   ├── pre-receive.sample
 │   ├── push-to-checkout.sample
 │   └── update.sample
 ├── info
 │   └── exclude
 ├── objects
 │   ├── info
 │   └── pack
 └── refs
     ├── heads
     └── tags

2.2.1 工作区和版本库

刚刚初始化的文件夹有一个隐藏文件夹.git,这个隐藏的文件夹就是版本库。我们能看到的就是工作区。

image-20230113123712704

向版本库中添加文件的时候是分两步执行的:

第一步是用git add把文件添加进去,实际上就是把文件修改添加到暂存区;

第二步是用git commit提交更改,实际上就是把暂存区(stage)的所有内容提交到当前分支。

因为我们创建Git版本库时,Git自动为我们创建了唯一一个master分支,所以,现在,git commit就是往master分支上提交更改。

你可以简单理解为,需要提交的文件修改通通放到暂存区,然后,一次性提交暂存区的所有修改,然后清空暂存区。需要注意的是,只有放在暂存区中的内容才能提交到分支中,保存下这个改动的版本。

2.2.2 撤销修改

现在再工作区中新建一个文件,touch readme.md,并写入一些内容

image-20230113131437454

把readme.md添加到暂存区,使用 git status可以查看当前版本库的状态

image-20230113131630712

你可以发现,Git会告诉你,git restore --staged <文件>...可以取消暂存,就是把添加到暂存区的文件从暂存区移除。

现在我不想移除,我接着对工作区的文件进行了修改。

image-20230113132401045

现在经理给了你一个任务,新的修改都不要了,还是要上一个版本的。这时,可以通过git checkout -- readme.md命令,使版本库的内容覆盖工作区中的内容,即恢复到上一个add时的版本。

image-20230113132752353

git checkout -- file命令中的--很重要,没有--,就变成了“切换到另一个分支”的命令,我们在后面的分支管理中会再次遇到git checkout命令。

2.2.3 删除文件

现在我们为删除文件做一些准备, 新建一个文件,然后添加到暂存区,最后提交。

image-20230113133352010

我们开始我们的删除实战。

通常我们会在文件夹内直接删除deleted_file.txt,这个时候Git是知道我们删除了文件的。通过git status命令就可以知道哪些文件被删除了。

image-20230113134415474

现在我们可以做两个操作

  • 确实要删除deleted_file.txt,此时我们可以用git rm命令删除,并且git commit

image-20230113135348522

  • 删错了,使用 git checkout -- deleted_file.txt从版本库中覆盖到工作区

image-20230113134521415

2. 3 分支管理

每次提交,都会生成一个提交节点,可以理解为我们的工作是基于祖先节点继续向下进行的。Git把每个提交节点穿成一条线,这个线就是分支。

image-20230113144812589

现在我们只有一个main分支,*表示我们当前正在哪个节点上。

执行 git log,我们能看到提交记录。下图commit后边的一串黄色字符串,如“2e6e365a67787dc9a13aa305823271d92b95aadd”,是每次提交的HashID,对应到我们的蓝色的图上就是各个节点。

image-20230113160541913

2.3.1 Git Branch & Git Checkout

接下来,我们将要创建一个到名为 newImage 的分支。

 git branch newImage

image-20230113145751339

newImage 分支是基于C2节点创建的,即newImage 分支的线将从C2节点开始。但是,现在我么只是创建了一个分支而已,并没有站在这个分支上。要想在newImage 分支上向下工作,我们需要使用git checkout newImage命令切换到该分支上。我们也可以不先使用git branch命令创建分支,而是直接使用git checkout -b newImage命令,同样可以实现我们创建分支并切换的目的。

image-20230113150256596

 git checkout newImage

现在我么看到,*是在newImage 分支上了。接下来我们可以在该分支上进行一些工作,然后提交我们的工作节点。

image-20230113150631680

我们发现main仍然停留在C2节点上,也就是说newImage 分支上的操作,不会影响其他分支。接下来我们再提交一次,更深刻理解一下。

image-20230113150722795

2.3.2 Git Merge

我们准备了两个分支,每个分支上各有一个独有的提交。现在我们假设,C2C3C1的修改没有公共部分(如果修改了公共的部分,在合并时需要决定采用哪个修改,也就是要解决冲突)。

我们要把 bugFix 合并到 main 里。我们知道,当前分支是不能对其他分支进行操作的,要想把bugFix 合并到 main里其实是改变了main。所以,我们应该切换到main,然后把bugFix拉过来。

image-20230113152234519

$ git checkout main
$ git merge bugFix

在拉的过程中,为了保留C2这个节点不被更改,Git在把C2复制了一份,然后把C3C1的修改合并过来,得到C4节点,main分支前进一步。

image-20230113152716666

2.3.3 Git Rebase

第二种合并分支的方法是 git rebase。Rebase 实际上就是取出一系列的提交记录,“复制”它们,然后在另外一个地方逐个的放下去。

Rebase 的优势就是可以创造更线性的提交历史,这听上去有些难以理解。如果只允许使用 Rebase 的话,代码库的提交历史将会变得异常清晰。

咱们还是实际操作一下吧……

image-20230113155325288

现在让bufFixmain为父节点。Git会把C3C1的修改,融入到C2的副本C2’中,这样C2’就拥有了对C1的全部修改。

image-20230113155817259

2.3.4 分离HEAD

我们首先看一下 “HEAD”。 HEAD 是一个对当前检出记录的符号引用 —— 也就是指向你正在其基础上进行工作的提交记录,图中是*

HEAD 总是指向当前分支上最近一次提交记录。大多数修改提交树的 Git 命令都是从改变 HEAD 的指向开始的。

HEAD 通常情况下是指向分支名的(如 bugFix)。在你提交时,改变了 bugFix 的状态,这一变化通过 HEAD 变得可见。

image-20230113161149654

我们现在想基于C3节点向下开发,不在基于C4了,就可以执行

git checkout c3

image-20230113161318230

2.3.5 再说撤销修改

image-20230113162647010

现在我们再某个分支上提交了很多次,然后对C3进行了一些修改,突然来个需求,说C2的修改不好,重新接着C1向下修改。于是我们就可以重新定位到C1上,接着C1向下工作。

$ git checkout c1
$ git commit

image-20230113162831329

2.3.6 Git Cherry-pick

git cherry-pick是一个真的就像是他的名字一样,是把其他节点摘过来的。

image-20230113175816400

现在的位置是C1,我们接下来要把C3C4C7摘到C1下。

git cherry-pick c3 c4 c7

image-20230113180032387

2.3.7 可视化分支关系

我们可以使用下边这个命令在命令行查看蓝色图那样的分支历史

git log --graph --pretty=oneline --abbrev-commit

2.4 Git Remote

2.4.1 绑定远程仓库

现在的状态是,我们本地已经有一个受版本控制的文件夹了,一般称之为仓库。现在想在GitHub上创建一个Git仓库,并且让本地的仓库远程的仓库同步。

首先,登录GitHub,在右上角新建一个仓库

image-20230113140207824

image-20230113140602827

image-20230113140950416

创建完毕后,这是一个空的仓库,也没有与本地的仓库绑定。我们可以通过GitHub给的提示在本地执行该命令git remote add origin git@github.com:Anthony-4926/demo.git,使本地与远程绑定。

通过 git remote -v可以查看我们绑定的远程仓库。我们会发现,下边有一个fetch的远程仓库,和一个push的远程仓库。

  • fetch的远程仓库是指我们从哪里拉项目到本地,覆盖本地的仓库。
  • push的远程仓库是指本地的版本仓库推到哪里,覆盖远程的仓库。

image-20230113141344681

我们可以添加多个不同的fetchpush

2.4.2 从远程仓库克隆

克隆远程的仓库必须知道它的地址,Github上有。

执行git clone git@github.com:Anthony-4926/demo.git,就可以克隆到本地了。克隆到本地的仓库自动和远程绑定。

image-20230113143136396

2.4.3 推送分支

这里我们先大概知道一下推送分支使用git push命令,具体的我们在再讲

3. Git开发

参考