Git 是目前世界上最先进的分布式版本控制系统。
Git 操作流程图:

Git 基本原理:
哈希是一个系列的加密算法(例如有: MD5、SHA-1、CRC32 等),各个不同的哈希算法虽然加密强度不同,但是有以下几个共同点:
- 哈希算法确定,输入数据确定,输出数据能够保证不变。
- 哈希算法确定,输入数据有变化,输出数据一定有变化,而且通常变化很大。
- 不管输入数据的数据量有多大,输入同一个哈希算法,得到的加密结果长度固定。
- 哈希算法不可逆。
哈希算法可以被用来验证文件,原理入下图所示:
Git 底层采用的是 SHA-1 算法,会通过 SHA-1 算法生成校验和。
-
git init初始化 Git 仓库后,会生成.git目录,这个就是 Git 仓库的核心,其中开发人员提交的代码存储在 objects 目录下的。

- hooks:包含客户端或服务端的钩子脚本。
- info:包含一个全局性排除文件。
- logs:保存日志信息。
- objects:保存提交的代码。
- refs:存储指向数据的提交对象的指针(分支)。
- config:包含项目特有的配置选项。
- description:用来显示对仓库的描述信息。
- HEAD:指示目前被检出的分支。
- index:保存暂存区信息。
-
git add .将index.js和utils.js添加到暂存区,可以看到 objects 文件夹下多了一个 1a 和 33 的文件夹,其中保存的就是刚刚添加的已经被转成了二进制数据的index.js和utils.js文件的内容。通过
git cat-file -t 【目录名+文件名头两位】可以查看 objects 文件夹下的文件类型。
通过get cat-file -p 【目录名+文件名头两位】可以查看 objects 文件夹下的文件内容。
-
git commit -m '测试'提交代码,可以看到 objects 文件夹下多了一个 1e 和 7e 的文件夹。在进行 commit 提交操作时,Git 会保存一个提交对象,其中包含了作者的姓名、邮箱、提交时输入的信息、指向它父对象的指针以及指向暂存内容快照的指针。
首次提交产生的提交对象没有父对象。普通提交产生的提交对象有一个父对象,由多个分支合并产生的提交对象有多个父对象。
git add只是添加到了暂存区,它只是将文件以二进制的形式保存到了 objects 中,此时无法通过索引一一步步找到它;只有git commit之后,才能通过索引一步步找到它。-
可以发现,commit 提交的校验和就是 1ea6 ,因此通过 commit 的校验和就可以找到 1ea6 文件。

-
可以发现, 1ea6 文件中 tree 的校验和就是 7ea6,因此通过 tree 的校验和就可以找到 7ea6 文件。

-
可以发现,通过 7ea6 文件中的 333e 和 1a15 就可以找到真正保存数据的文件。

-

Git 保存版本的机制:
每次提交更新时,Git 都会对当前的全部文件制作一个快照并保存这个快照的索引(如果某个文件没有修改, Git 不再重新存储该文件,而是只保留一个链接指向之前存储的文件),所以 Git 的工作方式可以称之为快照流。需要的硬盘空间会相对大一点,但是回滚速度极快。其实,Git 团队对代码做了极致的压缩,最终需要的实际空间比 SVN 多不了太多。

集中式版本控制工具在管理项目时,采用的是增量式管理的方式,保存的是项目版本与版本之间的差异,需要的硬盘空间会相对小一点,但是回滚的速度会很慢(例如:想要回退到 Version3 的版本,需要使用 Version3 的差异 + Version2 的差异 + Version1 的原始内容)。
Git 安装:
在 Windows 上安装 Git:
-
在 Git 官网
https://git-scm.com/download/win下载完安装包之后,双击 exe 安装包,按默认选项安装。 -
右击桌面可以看到
Git Bash Here,就代表已经安装成功了。安装 Git 时,同时会默认安装
Git Bash(Git 的命令行工具)、Git CMD(其实就是 Windows 系统的命令行工具 CMD),Git GUI(Git 的图形化界面工具。)Git Bash是一个 shell,是 Windows 下的 Git 命令行工具,用来执行 Linux 命令。它是基于 CMD 的,在 CMD 的基础上增添了一些新的命令与功能,使用更加方便。

在 Mac 上安装:
- 在 Git 官网
https://git-scm.com/download/mac下载安装程序,下载下来之后可以看到一个 dmg 压缩文件,双击打开可以看到里面有一个 pkg 文件, 再次双击 pkg 文件进行默认安装。
Git 初始化配置:
一般在新的系统上,都需要先配置下自己的 Git 工作环境。要配置的是个人的用户名称和电子邮件地址,这两条配置很重要,每次 Git 提交时都会引用这两条信息,说明是谁提交了更新,会随更新内容一起被永久纳入历史记录。
git config --global user.name "damu"
git config --global user.email damu@example.com
要删除配置信息,可以使用
git config --global --unset user.email。
要查看已有的配置信息,可以使用git config --list命令。
Git 提供了一个叫做
git config的命令来配置工作环境变量。这些变量可以存放在以下三个不同的地方:级别优先级:就近原则,项目级别 > 系统用户级别 > 系统级别。
/etc/gitconfig文件:系统中对所有用户都普遍适用的配置。若使用git config时用--system选项,读写的就是这个文件。一般不会使用。一台电脑系统中是可以有多个用户的。
~/.gitconfig文件:用户目录下的配置文件只适用于该用户。若使用git config时用--global选项,读写的就是这个文件。工作中一般使用的就是这个,.git/config文件:当前项目的 Git 目录中的配置文件(也就是工作目录中的.git/config文件),这里的配置仅仅针对当前项目有效。一般不会使用。
Git 忽略文件:
可以在项目根目录下创建一个名为 .gitignore 的文件,列出要忽略的文件模式,告诉 Git 哪些文件不需要添加到版本管理中。
本地仓库不会管理被忽略的文件,push 到远程仓库的时候也不会上传。
.gitignore 文件的格式规范:
- 所有空行或者以
#开头的行都会被忽略。 - 要忽略指定模式以外的文件或目录,可以在模式前加上感叹号
!取反。 - 使用两个星号
**表示匹配任意目录,例如a/**/z可以匹配a/z、a/b/z或者a/b/c/z等。
常用的 Git 操作:
没有本地仓库,克隆远程仓库到本地:
git clone git@github.com:michaelliao/gitskills.git
已有本地仓库,将本地仓库与远程仓库关联起来:
- 关联远程仓库:
git remote add origin https://github.com/huadangya/test.git此时仅仅只是将本地仓库和远程仓库关联了起来,还不知道远程仓库中有哪些分支和内容。
- 拉取远程仓库 master 分支中的内容到本地仓库:
git fetch origin master。远程仓库中的分支拉取到本地仓库后,在本地仓库中的映射为
【远程仓库别名】/【分支名】。 - 将拉取到本地仓库中的远程仓库分支的映射
origin/master设置为本地的 master 分支的上游分支:git branch --set-upstream-to origin/master。之后,操作 pull、push、merge 等时,将会自动使用上游分支。
- 将拉取到本地仓库中的远程仓库的映射
origin/master的内容合并到本地的 master 分支中:git merge --allow-unrelated-histories由于此时,master 分支和
origin/master分支还没有共同的 base 祖先节点,因此无法合并。需要加--allow-unrelated-histories参数来强制合并。 - 如果本地分支与远程分支不同名时,还需要
git config push.default upstream,设置 push 时推送到上游分支,否则 push 时默认会去找与本地分支同名的远程分支,将会报错。创建远程仓库,之前会默认创建一个 master 分支,现在是 main 分支。
给电脑中安装 Git,git init时默认会创建一个 master 分支,但是有选项可以输入默认创建的分支名。
因此,有可能本地分支与远程分支不同名。
推送本地仓库的内容到远程仓库:
git add .git commit -m "xxx"git pullgit push
从已有分支创建一个新的分支 dev,并推到远程:
git checkout -b dev从已有的分支创建新的分支,并切换到新的分支。git push提交该分支到远程仓库。
切换到 dev 分支。如果本地没有,则会从远程 dev 分支拉取代码,在本地新建分支并切换;如果有,则会直接切换:
git checkout -b dev origin/dev,也可以简写为 git checkout dev。
本来在 dev 修改内容,但是需要切换到 dev2去 修改其他一些东西:
切换分支之前先 commit 或 stash,不然的话未提交的改动会随着切换分支到另一个分支的。
commit 了很多次且尚未提交到远程,想撤回这些 commit:
git reset commitId回退到指定的 commitId,已修改的内容仍会存在。- git add commit push
commit 了很多次且已经提交到远程,想撤回这些 commit:
重要警示:一定要确认这个分支只有自己操作,只有一个人操作的分支才可以这样。
git reset commitId回退到指定的 commitId,已修改的内容仍会存在。- add commit
git push -f-f是-force的缩写,意思是强制更新,将自己本地仓库的代码直接推送至远程仓库,完全以该命令提交为准,之前提交都会被覆盖。
合并分支(如 dev 分支合并到 master,则进入 master 目录):
- 在 dev 分支 pull add commit push
- git checkout master
- 在 master 分支 pull
- git merge dev
- 在 master 分支 push
只修改了父模块,未修改子模块,需提交到远程:
- 只需在父模块 git pull add commit push
既修改了父模块,也修改了子模块,需提交到远程:
- 在子模块自己的开发分支 git pull add commit push
- 在父模块自己的开发分支 git pull add commit push
只修改了父模块,未修改子模块,合并到 dev 分支:
此时父模块的 commitId 指向的是子模块公共的 commitId,没有问题。
- 在父模块的当前分支 git pull add commit push
- 在父模块 git checkout dev
- 在父模块 git merge 当前分支
- 在父模块 git push
既修改了父模块,也修改了子模块,都已提交到远程,现需合并到 dev 分支:
此时父模块 commitId 指向的是子模块自己开发分支的 commitId,有问题。
- 在子模块切换到 dev 分支 git checkout dev
- git pull
- 在子模块 git merge 当前分支
- 在子模块 git push
此时父模块的 commitId 指向的是子模块公共的 commitId,没有问题。所以需要在父模块 git add commit push一次
- 在父模块的开发分支 git add commit push // 此次 commit 只是单纯修改了指向的子模块的 commitId
- 在父模块切换到 dev 分支 git checkout dev
- 在父模块 git pull
- 在父模块 git merge 当前分支
- 在父模块 git push



1285






