一. git
1 - 版本管理
① 什么是版本管理
版本管理是一种记录文件变化的方式,以便将来查阅特定版本的文件内容。

② 人为维护文档版本的问题
- 文档数量多且命名不清晰导致文档版本混乱
- 每次编辑文档需要复制,不方便
- 多人同时编辑同一个文档,容易产生覆盖

2 - Git 是什么
Git是一个版本管理控制系统(缩写VCS),它可以在任何时间点,将文档的状态作为更新记录保存起来,也可以在任何时间点,将更新记录恢复回来。

3 - Git 安装
下载地址:https://git-scm.com/downloads,在安装的过程中,所有选项使用默认值即可。
如果是MAC电脑,安装Xcode之后默认就安装 git 了(默认自带python环境)。
使用 git --version
查看git版本,能看到版本号,则说明git安装成功。
4 - Git 使用前配置
在使用 git 前,需要告诉 git 你是谁,在向 git 仓库中提交时需要用到。
- 配置提交人姓名:
git config --global user.name 提交人姓名
- 配置提交人姓名:
git config --global user.email 提交人邮箱
- 查看git配置信息:
git config --list
注意:
- 如果要对配置信息进行修改,重复上述命令即可。
- 配置只需要执行一次。
- 除了使用命令配置之外,还可以点击自己电脑名字的目录,找到
.gitconfig
文件,用编辑器打开进行修改,保存文件即可,如下:

5 - 工作区、暂存区和Git版本库
工作区 | 暂存区 | Git版本库 |
---|---|---|
被Git管理的项目目录 | 临时存放被修改文件 | 用于存放提交记录 |

① 工作区
就是你在电脑里能看到的目录,比如你的项目目录。工作区同级会有一个.git
隐藏文件夹,用来记录版本相关的东西。


② 暂存区
一般存放在".git目录下" 下的index文件(.git/index)中,所以我们把暂存区有时也叫作索引(index)。(如果没有index,提交一次就有了)

③ Git版本库
工作区有一个隐藏目录.git
,这个不算工作区,而是Git的版本库。.git中的refs/heads是本地分支,或者说本地版本库,.git中的refs/remotes是远程分支,refs/tags是打的标签,stash是暂存的代码,如下:

下面这个图展示了工作区、暂存区、Git版本库之间的关系:

图中左侧为工作区,右侧为版本库。在版本库中标记为"index" 的区域是暂存区(index),标记为 "master"的是 master 分支所代表的目录树。
当执行 "git status" 命令扫描工作区改动的时候,先依据.git/index文件中记录的已跟踪的文件的时间戳、长度等信息判断工作区文件是否改变。如果工作区的文件时间戳改变,说明文件的内容可能被改变了,这个时候就需要打开文件,读取文件内容,和更改前的记录的原始文件相比较,判断文件内容是否被更改。如果文件内容有改变,则将该文件新的时间戳记录到.git/index文件中。因此.git/index的时间戳也跟着变化了。为什么要这样做?因为判断文件是否更改,使用时间戳、文件长度等信息进行比较要比直接通过文件内容比较要快的多,所以Git这样的实现方式可以让工作区状态扫描速度更快。
.git/index实际上就是一个包含文件索引的目录树,像是一个虚拟的工作区。在这个虚拟工作区的目录树中,记录了文件名、文件的状态信息(时间戳、文件长度等),文件的内容并不存储其中,而是保存在Git对象库(.git/objects)中,他们通过这个索引和对象实体是对应着的。从上面的图我们可以看出:
- 图中左侧为工作区,右侧为版本库。在版本库中标记为 "index" 的区域是暂存区(stage, index),标记为 "master" 的是 master 分支所代表的目录树。
- 图中我们可以看出此时"HEAD"实际是指向master分支的一个“游标”。所以图示的命令中出现HEAD的地方可以用master来替换。
- 图中的 objects 标识的区域为Git的对象库,实际位于 ".git/objects" 目录下。
- 当对工作区修改(或新增)的文件执行"git add"命令时,暂存区的目录树被更新。同时工作区修改(或新增)的文件内容被写入到对象库中的一个新的对象中,而该对象的id被记录在暂存区的文件索引中。
- 当执行提交操作(git commit)时,暂存区的目录树写到版本库(对象库)中,master 分支会做相应的更新,即 master 指向的目录树就是提交时暂存区的目录树。
④ 代码提交流程
远程仓库 pull —> 工作区 add —> 暂存区 commit —> Git版本库 push —> 远程仓库,一旦提交后,如果你又没有对工作区做任何修改,那么工作区就是“干净”的。
6 - Git 常用命令
cd到项目目录,执行以下命令:
-
git init
初始化git仓库
初始化之后会生成一个.git
文件夹。打印如下:
Initialized empty Git repository in /Users/zjnx1111/Desktop/前端学习笔记/15-16阿里百秀/day01/code/A/git-demo/.git/
-
git status
查看文件状态
文件有两种状态:被git管理,不被git管理,从而提醒开发人员要将哪些文件提交到暂存区中,从而被git管理。打印如下:
On branch master // 当前在master分支
No commits yet // 还没被提交
Untracked files: // 未被跟踪(管理)的文件如下:
(use "git add <file>..." to include in what will be committed)
.gitignore(1)
1(1).html
2.html
3.html
index.html
readme.md
test.html
// 除了存在未跟踪(管理)的文件外,没有添加任何内容以提交(使用“git add”跟踪(管理))
nothing added to commit but untracked files present (use "git add" to track)
-
git add 文件列表
追踪文件
这一步就是将你想要被 git 管理的文件添加到暂存区中,如果是 git add .
就是将工作区所有修改的文件添加到暂存区。
执行 git add index.html
之后,再次执行 git status
打印如下:
Changes to be committed:
(use "git rm --cached <file>..." to unstage)
new file: index.html
-
git commit -m 提交信息
将暂存区中的文件提交到仓库中,打印如下:
[master (root-commit) e1fbc36] 第一次提交
1 file changed, 10 insertions(+) // 一个文件修改 插入了10行数据
create mode 100755 index.html
-
git log
查看提交记录,打印如下:
commit e1fbc36b87cf2d1966ded2a386925f2493ba925c (HEAD -> master) // 这次提交的id
Author: 徐金城 <xujincheng@example.com> // 提交人信息
Date: Tue Jan 19 10:50:23 2021 +0800 // 日期
第一次提交 // 信息
- 撤销操作
将 git 仓库中指定的更新记录恢复出来,并且覆盖暂存区和工作目录:git reset --hard commitID(提交之后的id)
,除了使用reset还可以使用revert,reset是HEAD后移,不会产生记录,revert是HEAD一直往前,会产生新的记录。
比如:工作目录中的代码存在问题,git仓库中的提交记录也存在问题,希望将更早的提交记录恢复出来并且删除那些存在问题的提交记录。

7 - 分支
使用分支,可以让我们从开发主线上分离出来,在不同的分支上做不同的事情,以免影响开发主线。

1. 分支的分类
分支主要分为:主分支、开发分支、功能分支
① 主分支(master)
第一次向 git 仓库中提交更新记录时自动产生的一个分支。

主分支中的代码一般都是可以用于向外界发布的代码,所以开发工作一般不在主分支,一般在开发分支开发,然后经过测试没啥问题之后,再将开发分支的代码合并到主分支上。
② 开发分支(develop)
作为开发的分支,基于 master 分支创建。

③ 功能分支(feature)
作为开发具体功能的分支,基于开发分支创建。

当在功能分支开发完一个具体的功能之后,就可以将功能分支的代码合并到开发分支,这时候功能分支就可以删除了,当开发分支的代码累积到一定程度时,再将开发分支的代码合并到主分支。这样做才可以保持开发分支最大的稳定性。除了开发功能可以建立分支以外,修复bug也可以建立分支。
2. 需求为主的git版本控制规则
- 一般有master分支(主分支)、uat分支(开发分支)、dev分支(功能分支)。
- dev分支是通过uat分支创建的,dev分支开发完之后,再将dev分支的代码通过提交合并请求的方式合并到uat分支。
- uat分支是通过master分支创建的,uat分支不允许提交代码,只能通过提交合并请求的方式将dev的代码合并到uat。
- master分支上的代码是通过在uat的合并请求里面拣选得到的,只拣选确定会上线的代码。
master分支上的代码不是直接通过合并uat得到的,为什么呢?现在,uat分支是所有需求的代码,dev分支是单个需求的代码,如果有些需求最后不上线呢?所以master分支上的代码不能直接通过合并uat得到,只能一个一个拣选。 - 每次上线后给master打一个tag,并且删除无用的dev分支。
3. 分支命令
-
git branch
查看本地所有分支 -
git checkout -b 分支名称
在当前分支创建新的本地分支 -
git checkout 分支名称
切换本地分支
注意:切换分支之前,当前分支的内容要提交到仓库中,要保持当前分支的工作目录是干净的(因为分支和分支之间应该互不影响),否则切换分支的时候当前工作目录会有其他分支的东西。 -
git merge 来源分支
合并本地分支
比如:如果是开发分支合并到主分支,首先要切换到主分支git checkout master
,然后合并分支git merge develop
,就可以将开发分支合并到主分支上来了。 -
git branch -d 分支名称
删除本地分支
注意:首先切换到主分支才可以删除其他分支,删除其他分支之前必须保证其他分支的代码已经提交并且合并到主分支了,否则报错如下。如果其他分支没合并也想删除,可以执行强制删除命令git branch -D develop
。error: The branch 'develop' is not fully merged. // 提示没有合并 If you are sure you want to delete it, run 'git branch -D develop'. // 强制删除
4. 临时存储功能
上面合并分支我们说了,切换分支之前,当前分支的内容要提交到仓库中,要保持当前分支的工作目录是干净的(因为分支和分支之间应该互不影响),否则切换分支的时候当前工作目录会有其他分支的东西。但是平时工作中如果需要临时切换分支并且当前分支的开发工作还没完成怎么办?
在git中,可以暂时提取分支上所有的改动并存储,让开发人员得到一个干净的工作副本,临时转向其他工作。使用场景:分支临时切换。
- 存储临时改动:
git stash
- 恢复改动:
git stash pop
注意:git提供的临时存储功能是独立于分支的,也就是说其他分支也可以使用这个命令,如果在其他分支上执行这个命令就会将改动恢复到其他分支上,所以恢复改动之前一定要查看当前是什么分支。
8 - merge和rebase的区别
merge和rebase都是用来合并分支的命令
- merge 会新生成 commit,并将新生成的 commit 添加在当前分支提交记录的后面。
- rebase 不会生成新的commit,在效果上,它的目标是要合并出一个干净的、含有每次提交的记录,但是把分支合并记录去掉。
有不同的场景:
- 如果你在开发阶段,尤其是多人协作的时候,需要清晰的知道代码的来龙去脉,使用 merge。
- 如果你写了一个代码库发布出去给别人用,你需要保持一个干净版本历史,这时你的分支合并信息就是冗余的了,推荐使用 rebase。
9 - reset和revert的区别
- reset的英文原意就是重置,这里重置的是指针,就是重置HEAD指针到指定的commit,reset是HEAD后移,不会产生记录。
- revert的英文原意是使恢复原状,这里就是把文件内容恢复成指定commit的样子,revert是HEAD一直往前,会产生一个新的commit记录。
比如,不良的开发商,在风景区建了别墅,被政府发现了,责令开发商恢复原样。开发商只好把盖好的别墅拆了,恢复到没盖别墅时的样子,所以在时间上就多了一个拆别墅的事件。对比的话,虽然最后的结果都是这个风景区现在没有别墅了,但是reset就是好像盖别墅这个事从来没发生过一样。而revert就是盖别墅这事是发生过的,只是因为又发生了一件拆别墅的事,从而导致别墅没有了。
10 - tag的作用
① 什么是tag
tag是git版本库的一个标记,指向某个commit的指针。tag主要用于发布版本的管理,一个版本发布之后,我们可以为git打上 v.1.0.1 v.1.0.2 ...这样的标签。
tag感觉跟branch有点相似,但是本质上和分工上是不同的:
- tag 对应某次commit,是一个点,是不可移动的。
- branch 对应一系列commit,是很多点连成的一根线,有一个HEAD 指针,是可以依靠 HEAD 指针移动的。
两者的区别决定了使用方式,改动代码用 branch,不改动只查看用 tag。tag 和 branch 的相互配合使用,有时候起到非常方便的效果。例如:已经发布了 v1.0 v2.0 v3.0 三个版本,这个时候,我突然想不改现有代码的前提下,在 v2.0 的基础上加个新功能,作为 v4.0 发布。就可以检出 v2.0 的代码作为一个 branch ,然后作为开发分支。
② 添加tag
- 如果使用Tower,添加标签就很简单,右键某一次commit记录,即可添加本地标签。本地标签添加之后,就会有黄色的标签,如下的:
v111
、v222
、v3333
、v444
都是添加的本地标签。

- 本地标签还需要推送到远程,推送方式如下,就是在push的界面勾选
Push All Tags
就会把这个分支的所有标签全部推送到远程。

标签推送到远程之后就可以在远程查看了,如下:

11 - Git忽略清单
git忽略清单文件名称:.gitignore
,想要被git忽略的文件夹或者文件的名称都可以写在这。比如node_modules
添加到此文件中,在执行git命令的时候,git就会忽略这些文件。
注意:.git
文件,.gitignore
文件和README.md
文件都在同级目录下。
https://github.com/github/gitignore 里面搜集了很多语言的忽略文件模板,强烈推荐参考一下。
12 - 添加README.md文件
我们只需要在项目的根目录下创建一个README.md文件,这个文件是MarkDown格式的,添加README.md文件之后,这个文件的内容会自动被读取并显示在github仓库文件列表下面。
二. github
上面我们讲的都是操作本地仓库,本地仓库在每一个开发人员的计算机上,远程仓库是在互联网上或者本地局域网上。
在版本控制系统中,大约90%的操作都是在本地仓库中进行的:暂存,提交,查看状态或者历史记录等等,除此之外,如果仅仅只有你一个人在这个项目里工作,你永远没有机会需要设置一个远程仓库。
只有当你需要和你的开发团队共享数据时,设置一个远程仓库才有意义。你可以把它想象成一个 “文件管理服务器”,利用这个服务器可以与开发团队的其他成员进行数据交换。
1 - 注册
- 访问github首页,点击 Sign up 连接。(注册)

- 填写用户名、邮箱地址、GitHub登陆密码

- 选择计划

- 填写 GitHub 问题

- 验证邮箱

- GitHub 个人中心

2 - 多人协作开发流程
假如A是项目经理,B是开发人员。
- A在自己的计算机中创建本地仓库
- A在github中创建远程仓库
- A将本地仓库推送到远程仓库
- B克隆远程仓库到本地进行开发
- B将开发的代码先提交到他电脑的本地仓库
- B将本地仓库推送到远程仓库
- A将远程仓库中的最新内容拉去到本地
第一次的时候B需要克隆(clone)代码:

接下来,B可以像A一样拉取(pull)和提交(push)代码:

3 - 创建仓库
A项目经理需要做的操作如下:
- 创建本地仓库:进入项目目录,使用
git init
,初始化仓库,然后初始化项目,使用add
命令添加到暂存区,然后使用commit
提交到本地仓库 - 创建远程仓库:填写仓库基本信息

4 - 将本地仓库推送到远程仓库
A项目经理需要将本地分支的代码推送到远程仓库:

如何将本地仓库推送到远程仓库呢?github推荐了三种方式:
- 在命令行中初始化一个新的本地仓库,然后推送到远程仓库
- 在命令行中将一个已经存在的本地仓库推送到远程仓库
- 通过其他仓库导入到远程仓库
① 一般方式
很显然我们使用第二种方式,执行命令:git push 远程仓库地址 分支名称
,也就是执行git push https://github.com/iamkata/git-demo1.git master
,命令的意思就是将本地仓库的当前分支推送到远程仓库的 master 分支。
这时候会让你输入github的用户和密码,输入完就好了:
Username for 'https://github.com': 你的邮箱
Password for 'https://imkata@163.com@github.com': 你的密码
// 下面是推送代码
Enumerating objects: 9, done.
Counting objects: 100% (9/9), done.
Delta compression using up to 12 threads
Compressing objects: 100% (6/6), done.
Writing objects: 100% (9/9), 1.00 KiB | 1.00 MiB/s, done.
Total 9 (delta 0), reused 0 (delta 0)
To https://github.com/iamkata/git-demo1.git
* [new branch] master -> master
这时候在github刷新页面就可以看到文件了。
注意:推送的时候会把当前分支的代码推送到远程,所以要注意当前是什么分支。
② 远程仓库起别名
每次推送的时候都需要写远程仓库地址,很麻烦,我们可以给远程仓库起一个别名:git remote add origin https://github.com/iamkata/git-demo1.git
,命令的意思就是给远程仓库起别名 origin,这样下次推送直接写git push origin master
就可以了。
再次执行push命令的时候就不需要输入用户名、密码了,因为电脑自动记住了,如果在钥匙串中将记住的密码删除,下次就还需要输入密码,如下:

③ 记住推送地址及分支
但是我感觉git push origin master
命令还是比较长,我们可以输入git push -u origin master
推送代码,-u
代表记住推送地址及分支,下次推送只需要输入git push
即可。
☆☆ git提交代码步骤 ☆☆
git branch //查看当前分支 login
git status //查看文件状态
git add . //添加到暂存区
git commit -m "提交消息" //将代码提交到本地
git branch //查看当前分支 login
git checkout master //切换到主分支
git megre login //将login分支合并到主分支
//到这里本地的login和master分支的代码都是最新的了,接下来要将本地代码进行远程推送
git push //将本地的master分支推送到云端
//这时候云端只有一个master分支,如何将本地的login分支也推送到云端login分支呢?
git checkout login //切换到本地login分支
git push -u origin login //push的时候云端如果没有login分支会自动创建login分支,然后再执行push,这样云端就也有login分支了
如果要开发新功能,还需要创建新的分支,然后书写代码:
git branch //查看当前分支 login
git checkout master //切换到master分支
git checkout -b user //在master分支基础上创建user分支
//然后就可以在user分支写代码了
//代码写完,先要将代码提交到本地
git add . //添加到暂存区
git commit -m "提交消息" //将代码提交到本地
git branch //查看当前分支 user
git checkout master //切换到主分支
git megre user //将user分支合并到主分支
//这时候云端只有master和login分支,我们需要将master分支代码和user分支代码推送到码云
git push -u origin master //将本地master推送到云端master
git checkout user
git push -u origin user // 这样云端就也有user分支了
总结:
- 本地创建新的分支:
git checkout -b user
- 云端创建新的分支:
git push -u origin user
- 如果本地分支和云端的分支一模一样,如果直接执行
git push
那么会把本地的同名分支推送到云端的同名分支,这样可以简化命令
5 - 拉取操作
B程序员刚要开发,需要做的操作如下:
① 克隆仓库
cd到另外一个目录,执行:git clone 仓库地址
,克隆远端数据仓库到本地。
克隆是不需要身份验证的,因为我们创建的仓库是public的。
② 推送代码
B程序员克隆项目之后,在提交代码前,同样需要告诉 git 你是谁,在向 git 仓库中提交时需要用到。
- 配置提交人姓名:
git config --global user.name 提交人姓名
- 配置提交人姓名:
git config --global user.email 提交人邮箱
- 查看git配置信息:
git config --list
配置完之后,以后B提交代码后,使用git log
就可以看到B提交的记录了。
注意:这时候B是没有远程仓库的推送权限的,需要A邀请B,在Settings -> Collaborators填入B的github账号,得到一个邀请链接,B登录github,进入这个邀请链接,接受邀请就有推送权限了。
如果是同一台电脑,在B推送代码之前还需要把钥匙串自动记住的github账号密码给删除,这样B下次在推送的时候就可以输入自己的账号密码进行推送了。
B克隆的时候,连仓库添加的远程推送地址的别名都克隆过来了,所以B可以直接使用git push origin master
进行推送。
③ 拉取远程仓库中最新的版本
这时候A是没有B远程推送的代码的,需要A拉取远程仓库中最新的版本:git pull 远程仓库地址/远程仓库地址别名 分支名称
,例如:git pull origin master
。拉取操作是读操作,不需要身份验证。
④ git clone和git pull命令的区别
- git clone 只执行第一次就好了,是直接将项目完全克隆下来,是在没有本地仓库的基础上进行的。
- git pull 只会拉取远程仓库中最新的版本,这个最新的版本是和本地仓库中的版本进行比较的,git pull命令是在有本地仓库的基础上进行的。
- 如果远程仓库中的版本高于本地仓库中的版本,此时本地仓库是不能向远程仓库进行提交的,本地仓库必须先git pull远程仓库中的最新代码,然后再进行提交。
6 - 解决冲突
在多人同时开发一个项目时,如果两个人修改了同一个文件的同一个地方,就会发生冲突,冲突需要人为解决。
当A和B修改了同一个文件的同一个地方时,A是可以推送成功的,B如果想推送必须要先pull最新的代码,但是B拉取的时候,A和B修改的同一个文件的同一个地方的代码就会冲突,这时候需要B本地解决冲突,然后才可以推送代码。
B拉取代码之后,终端会提示conflict冲突,然后冲突的文件会有<<<<<<< HEAD表示冲突的开始,>>>>>>>表示冲突的结束,=======
表示冲突的分割线,其中HEAD代表下面是你的代码,我们只需要删除这些符号,删除和保留一些代码就可以解决冲突了。
最后一定不要忘了,冲突解决完成之后,使用add
、commit
将代码提交到本地仓库,然后使用push
就可以将本地仓库的代码推送到远程仓库了。
7 - 跨团队协作
上面的A和B是一个团队的,如果其他团队的C想要修改仓库中的内容,怎么办呢?
- 程序员 C fork仓库(fork之后这个仓库就完全属于程序员C了)
- 程序员 C 将仓库克隆在本地进行修改(使用
git clone 程序员C fork之后的自己的仓库的地址
) - 程序员 C 将代码提交到本地仓库并且推送到自己fork的远程仓库
- 程序员 C 发起Pull reqests,填写标题和信息,然后提交。这样程序员 C修改的代码以及填写的信息都会被发送给这个仓库的原作者。
- 原仓库作者的Pull reqests里面会收到消息,然后原仓库作者在Files changed里面可以看到修改的代码,然后进行审核。
- 审核完之后,原仓库作者点击Merge pull request合并代码。
8 - ssh免登陆
https协议仓库地址推送代码的时候每次都需要提供用户名和密码,但是每次输入用户名和密码很麻烦(我们上面没有每次都输入账号密码是因为钥匙串自动记住了),所以github提供了ssh免登陆。
① 生成秘钥
终端执行 ssh-keygen
一路回车,生成秘钥,秘钥存储在用户目录下面,如下:
- 公钥名称:id_rsa.pub 放在github网站中
- 私钥名称:id_rsa 保留在开发者电脑中

② 上传公钥
使用编辑器打开公钥,复制之后粘贴到下图的Key里面。


完成之后就可以使用ssh协议开头的地址进行代码推送了,推送操作和https协议的推送操作完全相同。
github会自动把它的公钥和程序员电脑上的私钥进行配对,配对成功就自动推送代码了,再也不用输入账号和密码了。
网友评论