文章目录
前言
本文主要介绍Git相关知识,包括文件管理、提交commit、分支branch、合并merge、远程等内容。
一、Git是什么?
1. Git介绍
- Git是一种分布式版本控制系统。Git 和其他版本控制系统的主要差别在于,Git直接记录快照,而非差异比较,而大多数其他系统则只关心文件内容的具体差异。这类系统(CVS, Subversion, Perforce, Bazaar 等等)每次记录有哪些文件作了更新,以及都更新了哪些行的什么内容。
- Git 不按照以上方式对待或保存数据。反之,Git 更像是把数据看作是对小型文件系统的一系列快照。 在Git中,每当你提交更新或保存项目状态时,它基本上就会对当时的全部文件创建一个快照并保存这个快照的索引。 为了效率,如果文件没有修改,Git 不再重新存储该文件,而是只保留一个链接指向之前存储的文件。 Git 对待数据更像是一个快照流。
- 在 Git 中的绝大多数操作都只需要访问本地文件和资源,不需要网络上其它计算机的信息。
- Git 中所有的数据在存储前都计算校验和,然后以校验和来引用。 这意味着不可能在 Git 不知情时更改任何文件内容或目录内容。 这个功能建构在 Git 底层,是构成 Git 哲学不可或缺的部分。 若你在传送过程中丢失信息或损坏文件,Git 就能发现。
- Git 用以计算校验和的机制叫做 SHA-1 散列(hash)。 这是一个由40个十六进制字符(0-9 和 a-f)组成的字符串,基于 Git 中文件的内容或目录结构计算出来。Git 数据库中保存的信息都是以文件内容的哈希值来索引,而不是文件名。
2. Git状态模型
-
Git 有三种状态,你的文件可能处于其中之一: 已提交(committed)、已修改(modified) 和 已暂存(staged)。
- 已修改表示修改了文件,但还没保存到数据库中。
- 已暂存表示对一个已修改文件的当前版本做了标记,使之包含在下次提交的快照中。
- 已提交表示数据已经安全地保存在本地数据库中。
-
Git项目拥有三个阶段:工作区、暂存区以及 Git 目录。
- 工作区是对项目的某个版本独立提取出来的内容。 这些从 Git 仓库的压缩数据库中提取出来的文件,放在磁盘上供你使用或修改。
- 暂存区是一个文件,保存了下次将要提交的文件列表信息,一般在 Git 仓库目录中。 按照 Git 的术语叫做“索引”,不过一般说法还是叫“暂存区”。
- Git 仓库目录是 Git 用来保存项目的元数据和对象数据库的地方。 这是 Git 中最重要的部分,从其它计算机克隆仓库时,复制的就是这里的数据。
3. Git工作流程
-
在工作区中修改文件。
-
将你想要下次提交的更改选择性地暂存,这样只会将更改的部分添加到暂存区。
-
提交更新,找到暂存区的文件,将快照永久性存储到 Git 目录。
了解Git请查看权威Git书籍ProGit(中文版)
二、Git使用
1. 配置用户信息
安装完 Git 之后,要做的第一件事就是设置你的用户名和邮件地址。 这一点很重要,因为每一个 Git 提交都会使用这些信息,它们会写入到你的每一次提交中,不可更改:
$ git config --global user.name "XXX"
$ git config --global user.email XXX@XXX
如果使用了 --global 选项,那么该命令只需要运行一次,因为之后无论你在该系统上做任何事情, Git 都会使用那些信息。 当你想针对特定项目使用不同的用户名称与邮件地址时,可以在那个项目目录下运行没有 --global 选项的命令来配置。
2. 文件暂存
- 将文件加入暂存区
git add file/folder
- 删除文件
要从 Git 中移除某个文件,就必须要从已跟踪文件清单中移除(确切地说,是从暂存区域移除),然后提交。 可以用 git rm 命令完成此项工作,并连带从工作目录中删除指定的文件,这样以后就不会出现在未跟踪文件清单中了。
$ rm TESTS.md
$ git status
On branch master
Your branch is up-to-date with 'origin/master'.
Changes not staged for commit:
(use "git add/rm <file>..." to update what will be committed)
(use "git checkout -- <file>..." to discard changes in working directory)
deleted: TESTS.md
no changes added to commit (use "git add" and/or "git commit -a")
然后再运行 git rm 记录此次移除文件的操作:
$ git rm TESTS.md
rm 'TESTS.md'
$ git status
On branch master
Your branch is up-to-date with 'origin/master'.
Changes to be committed:
(use "git reset HEAD <file>..." to unstage)
deleted: TESTS.md
下一次提交时,该文件就不再纳入版本管理了。 如果要删除之前修改过或已经放到暂存区的文件,则必须使用强制删除选项 -f。 这是一种安全特性,用于防止误删尚未添加到快照的数据,这样的数据不能被 Git 恢复。
另外一种情况是,我们想把文件从 Git 仓库中删除(亦即从暂存区域移除),但仍然希望保留在当前工作目录中。 换句话说,你想让文件保留在磁盘,但是并不想让 Git 继续跟踪。 当你忘记添加 .gitignore 文件,不小心把一个很大的日志文件或一堆 .a 这样的编译生成文件添加到暂存区时,这一做法尤其有用。 为达到这一目的,使用 --cached 选项:
$ git rm --cached TEST
- 文件重命名,Git 中对文件改名:
$ git mv TEST.md TEST
$ git status
On branch master
Your branch is up-to-date with 'origin/master'.
Changes to be committed:
(use "git reset HEAD <file>..." to unstage)
renamed: TEST.md -> README
运行 git mv 就相当于运行了下面三条命令:
$ mv TEST.md TEST
$ git rm TEST.md
$ git add TEST
3. 提交更改
- 将暂存内容提交到本地仓库,生成一个新版本。
git commit
git commit -m "message"
git commit -a
message通常记录更改的原因和内容,便于定位或回溯,参考message编写规范。
<type>(<scope>): <short summary>
│ │ │
│ │ └─⫸ Summary in present tense. Not capitalized. No period at the end.
│ │
│ └─⫸ Commit Scope: animations|bazel|benchpress|common|compiler|compiler-cli|core|
│ elements|forms|http|language-service|localize|platform-browser|
│ platform-browser-dynamic|platform-server|router|service-worker|
│ upgrade|zone.js|packaging|changelog|docs-infra|migrations|
│ devtools
│
└─⫸ Commit Type: build|ci|docs|feat|fix|perf|refactor|test
- 在提交了若干更新,又或者克隆了某个项目之后,回顾下提交历史,使用 git log 命令。git log常用选项如下表所示。
选项 | 说明 |
---|---|
-p | 按补丁格式显示每个提交引入的差异 |
–stat | 显示每次提交的文件修改统计信息 |
–abbrev-commit | 仅显示 SHA-1 校验和所有 40 个字符中的前几个字符 |
–graph | 在日志旁以 ASCII 图形显示分支与合并历史 |
–pretty | 使用其他格式显示历史提交信息。可用的选项包括 oneline、short、full、fuller 和 format(用来定义自己的格式) |
–oneline | –pretty=oneline --abbrev-commit 合用的简写 |
- 每个提交都有一个哈希标识符(40位十六进制数),id 在不重复前提下可以只写前几位
git show id
- 检出之前的id版本
git checkout id
4. 打版本标签
- 创建标签
Git 支持两种标签:轻量标签与附注标签。
轻量标签很像一个不会改变的分支——它只是某个特定提交的引用。而附注标签是存储在 Git 数据库中的一个完整对象, 它们是可以被校验的,其中包含打标签者的名字、电子邮件地址、日期时间, 此外还有一个标签信息,并且可以使用 GNU Privacy Guard (GPG)签名并验证。
通常会建议创建附注标签,这样你可以拥有以上所有信息。但是如果你只是想用一个临时的标签, 或者因为某些原因不想要保存这些信息,那么也可以用轻量标签。 - 附注标签
运行 tag 命令时指定 -a 选项,-m 选项指定了一条将会存储在标签中的信息。 如果没有为附注标签指定一条信息,Git 会启动编辑器要求你输入信息。
git tag -a v1.0 -m "test version 1.0"
- 轻量标签
轻量标签本质上是将提交校验和存储到一个文件中——没有保存任何其他信息。 创建轻量标签,不需要使用 -a、-s 或 -m 选项,只需要提供标签名字:
git tag v1.0
- 版本号命名规范参考Semantic Versioning 2.0.0
标准的版本号必须(MUST)采用 X.Y.Z 的格式,其中 X、Y 和 Z 为非负的整数,且禁止(MUST NOT)在数字前方补零。X 是主版本号、Y 是次版本号、而 Z 为修订号。每个元素必须(MUST)以数值来递增。例如:1.9.1 -> 1.10.0 -> 1.11.0。
5. 分支管理
工作中经常遇到分支的新建与合并场景,例如:正在开发一个工业软件,为实现某条新需求,创建了一个分支,在这个分支上开发代码。正在此时,有个很严重的软件bug需要紧急修补。
切换到你的线上分支,为这个紧急任务新建一个分支,并在其中修复它。在测试通过之后,切换回线上分支,然后合并这个修补分支,最后将改动推送到线上分支。切换回你最初工作的分支上,继续工作。
- 创建分支,比如创建一个名为issue07的分支
git branch issue07
- 切换分支,比如切换到新建的分支issue07上
git checkout issue07
- 创建并切换分支
为解决一个软件issue07,新建一个分支并同时切换到那个分支上,你可以运行一个带有 -b 参数的 git checkout 命令:
git checkout -b issue07
- 继续在 issue07问题上开发,并且做了一些提交。 在此过程中,issue07分支在不断的向前推进(HEAD 指针指向了 issue07分支)
- 现在有个紧急问题issue17要解决。不必把这个紧急问题和 issue07的修改混在一起, 也不需要还原关于 issue07 问题的修改,然后再添加关于这个紧急问题的修改,最后将这个修改提交到线上分支。 所要做的仅仅是切换回 master 分支。
- 在切换分支前建议提交所有的修改,再切换到master分支
git checkout master
- 为修复新的紧急问题issue17,建立一个issue17分支,在该分支上工作直到问题解决
git checkout -b issue17
- 将 issue17分支合并回你的master分支来部署到线上,使用 git merge 命令:
$ git checkout master
$ git merge issue17
Updating f42c576..3a0874c
Fast-forward
test.cpp | 2 ++
1 file changed, 2 insertions(+)
- 在这个紧急问题修复之后,要回到被打断之前时的工作中,应该先删除 issue17分支,已经不再需要它了,master 分支已经指向了issue17同一个位置。 可以使用带-d选项的git branch命令来删除分支:
$ git branch -d issue17
Deleted branch issue17 (3a0874c)
- 现在切换回正在工作的分支继续开发,也就是针对issue07问题的那个分支(issue07分支):
$ git checkout issue07
Switched to branch "issue07"
在issue17分支上所做的工作并没有包含到 issue07分支中。 如果需要拉取issue17所做的修改,可以使用 git merge master 命令将 master 分支合并入issue07分支,或者也可以等到 issue07分支完成修复,再将其合并回 master 分支。
- 分支合并
假设修复了issue07问题,并且打算将工作合并入master分支。 为此,需要合并issue07分支到master分支,这和之前合并issue17分支所做的工作差不多。 只需要检出到你想合并入的分支,然后运行 git merge 命令:
$ git checkout master
Switched to branch 'master'
$ git merge issue07
Merge made by the 'recursive' strategy.
test.cpp | 1 +
1 file changed, 1 insertion(+)
和之前合并issue17分支的时候看起来有一点不一样。 在这种情况下,开发历史从一个更早的地方开始分叉开来(diverged)。 master 分支所在提交并不是issue17分支所在提交的直接祖先,Git 不得不做一些额外的工作。 出现这种情况的时候,Git 会使用两个分支的末端所指的快照以及这两个分支的公共祖先,做一个简单的三方合并。
和之前将分支指针向前推进所不同的是,Git 将此次三方合并的结果做了一个新的快照并且自动创建一个新的提交指向它。 这个被称作一次合并提交,它的特别之处在于他有不止一个父提交。
- 删除分支
合并后即可删除issue07分支:
git branch -d issue07
6. 远程仓库的使用
- 克隆
如果从远程服务器仓库克隆,Git 的 clone 命令会自动将其命名为 origin,拉取它的所有数据, 创建一个指向它的 master 分支的指针,并且在本地将其命名为origin/master。 Git 也会给一个与origin的master分支在指向同一个地方的本地master分支,这样就有工作的基础。 - 推送
想要公开分享一个分支时,需要将其推送到有写入权限的远程仓库上。 本地的分支并不会自动与远程仓库同步——你必须显式地推送想要分享的分支。 这样就可以把不愿意分享的内容放到私人分支上,而将需要和别人协作的内容推送到公开分支。
如果希望和别人一起在名为newbranch的分支上工作,你可以像推送第一个分支那样推送它。 运行 git push :
git push origin newbranch
- 拉取
运行 git pull 通常会从最初克隆的服务器上抓取数据并自动尝试合并到当前所在的分支。(包含git fetch 和 git merge 两个步骤)
三、Github操作和协作
1. GitHub账户的创建和配置
2. 创建公钥
- 习惯使用 SSH 远程,你需要配置一个公钥(参考生成 SSH 公钥) ,使用窗口右上角的链接打开你的账户设置
- 在左侧选择“SSH keys”部分
- 在这个页面点击“Add an SSH key”按钮,给你的公钥起一个名字,将你的 ~/.ssh/id_rsa.pub (或者自定义的其它名字)公钥文件的内容粘贴到文本区,然后点击“Add key”
3. 邮箱设置
GitHub 使用用户邮件地址区分 Git 提交。 如果你在自己的提交中使用了多个邮件地址,希望 GitHub 可以正确地将它们连接起来, 你需要在管理页面的 Emails 部分添加你拥有的所有邮箱地址。
4. 集成Git的IDE
- 使用Visual Studio中的Git操作VS Git
- 使用Visual Studio Code中的Git操作VS Code Git
总结
本文简要介绍了Git是什么、Git基础使用以及Github操作和协作内容。