docs(Git): Git Pro note
This commit is contained in:
parent
6a3502db55
commit
90ed2dfd4f
2
dist/docusaurus.config.dev.js
vendored
2
dist/docusaurus.config.dev.js
vendored
@ -54,7 +54,7 @@ var config = {
|
||||
// 导航栏
|
||||
navbar: {
|
||||
title: '7Wate`s Wiki',
|
||||
hideOnScroll: true,
|
||||
// hideOnScroll: true,
|
||||
// logo: {
|
||||
// alt: 'Site Logo',
|
||||
// src: 'img/logo.svg',
|
||||
|
290
docs/开发/Git/分支.md
Normal file
290
docs/开发/Git/分支.md
Normal file
@ -0,0 +1,290 @@
|
||||
---
|
||||
id: 分支
|
||||
title: 分支
|
||||
sidebar_position: 3
|
||||
data: 2022年1月13日
|
||||
---
|
||||
|
||||
Git 的分支模型被称为它的「必杀技特性」,也正因为这一特性,使得 Git 从众多版本控制系统中脱颖而出。
|
||||
|
||||
## 分支简介
|
||||
|
||||
因为 Git 保存的不是文件的变化或者差异,而是一系列不同时刻的 快照 。
|
||||
|
||||
所以在进行提交操作时,Git 会保存一个提交对象(commit object)。该提交对象会包含一个指向暂存内容快照的指针,且还包含了作者的姓名和邮箱提交时输入的信息以及指向它的父对象的指针。 首次提交产生的提交对象没有父对象,普通提交操作产生的提交对象有一个父对象, 而由多个分支合并产生的提交对象有多个父对象。
|
||||
|
||||
**Git 的分支,其实本质上仅仅是指向提交对象的可变指针。**
|
||||
|
||||
### 创建分支
|
||||
|
||||
```
|
||||
// 创建分支
|
||||
git branch <branch-name>
|
||||
```
|
||||
|
||||
这会在当前所在的提交对象上创建一个指针。
|
||||
|
||||
### 分支切换
|
||||
|
||||
要切换到一个已存在的分支,你需要使用 git checkout 命令。
|
||||
|
||||
```
|
||||
// 切换到一个已存在的分支
|
||||
git checkout <branch-name>
|
||||
|
||||
// 在当前所在的提交对象上创建新分支,并切换到新分支。
|
||||
git checkout -b <branch-name>
|
||||
```
|
||||
|
||||
### 查看分支
|
||||
|
||||
```
|
||||
// 查看已创建的分支
|
||||
git branch
|
||||
```
|
||||
|
||||
### 合并分支
|
||||
|
||||
```
|
||||
// 合并分支到当前分支。
|
||||
git merge <branch-name>
|
||||
```
|
||||
|
||||
### 删除分支
|
||||
|
||||
```
|
||||
git branch -d <branch-name>
|
||||
```
|
||||
|
||||
## 分支实例
|
||||
|
||||
你将经历如下步骤:
|
||||
|
||||
1. 开发某个网站。
|
||||
|
||||
2. 为实现某个新的用户需求,创建一个分支。
|
||||
|
||||
3. 在这个分支上开展工作。
|
||||
|
||||
正在此时,你突然接到一个电话说有个很严重的问题需要紧急修补。 你将按照如下方式来处理:
|
||||
|
||||
1. 切换到你的线上分支(production branch)。
|
||||
2. 为这个紧急任务新建一个分支,并在其中修复它。
|
||||
3. 在测试通过之后,切换回线上分支,然后合并这个修补分支,最后将改动推送到线上分支。
|
||||
4. 切换回你最初工作的分支上,继续工作。
|
||||
|
||||
### 新建分支
|
||||
|
||||
首先,我们假设你正在你的项目上工作,并且在 master 分支上已经有了一些提交。
|
||||
|
||||
现在,你为实现某个新的需求,创建一个分支 iss53。
|
||||
|
||||
```
|
||||
git checkout -b iss53
|
||||
```
|
||||
|
||||
当我们做了一些提交的时候,iss53 分支在向前推进。
|
||||
|
||||
现在你接到那个电话,有个紧急问题等待你来解决,现在要做的就是切换回主分支。
|
||||
|
||||
```
|
||||
git checkout master
|
||||
```
|
||||
|
||||
接下来,你要修复这个紧急问题。新建一个 hotfix 分支,直至问题解决。
|
||||
|
||||
```
|
||||
git checkout -b hotfix
|
||||
```
|
||||
|
||||
### 分支的合并
|
||||
|
||||
然后将 hotfix 分支合并回你的 master 分支来部署线上。
|
||||
|
||||
```
|
||||
git checkout master
|
||||
git merge hotfix
|
||||
```
|
||||
|
||||
当你试图合并两个分支时, 如果顺着一个分支走下去能够到达另一个分支,那么 Git 在合并两者的时候, 只会简单的将指针向前推进(指针右移),因为这种情况下的合并操作没有需要解决的分歧——这就叫做 “快进(fast-forward)”。
|
||||
|
||||
此时,hotfix 分支已经不需要了,可以将它删除。
|
||||
|
||||
```
|
||||
git branch -d hotfix
|
||||
```
|
||||
|
||||
现在你切回你正在工作的分支,继续你的工作,并且拥有了新的提交。
|
||||
|
||||
假设这时你已经完成了 iss53 的需求,需要将 iss53 分支合并入 master 分支。
|
||||
|
||||
```
|
||||
git checkout master
|
||||
git merge iss53
|
||||
```
|
||||
|
||||
这和之前合并 hotfix 分支的时候看起来有点不一样。
|
||||
|
||||
在这种情况下,你的开发历史从一个更早的地方开始分叉开来(diverged)。 因为,master 分支所在提交并不是 iss53 分支所在提交的直接祖先,Git 不得不做一些额外的工作。 出现这种情况的时候,Git 会使用两个分支的末端所指的快照以及这两个分支的公共祖先,做一个简单的三方合并。
|
||||
|
||||
### 遇到冲突时的分支合并
|
||||
|
||||
有时候合并操作并不会如此顺利,因为如果涉及到同一个文件的同一处,就会在合并时产生冲突。此时 Git 做了合并,但是没有自动地创建一个新的合并提交。 Git 会暂停下来,等待你去解决合并产生的冲突。
|
||||
|
||||
任何因包含合并冲突而有待解决的文件,都会以未合并状态标识出来。 Git 会在有冲突的文件中加入标准的冲突解决标记,这样你可以打开这些包含冲突的文件然后手动解决冲突。
|
||||
|
||||
出现冲突的文件会包含一些特殊区段像下面这个样子:
|
||||
|
||||
```
|
||||
<<<<<<< HEAD:index.html
|
||||
<div id="footer">contact : email.support@github.com</div>
|
||||
=======
|
||||
<div id="footer">
|
||||
please contact us at support@github.com
|
||||
</div>
|
||||
>>>>>>> iss53:index.html
|
||||
```
|
||||
|
||||
这表示 HEAD 所指示的版本(也就是你的 master 分支所在的位置,因为你在运行 merge 命令的时候已经检出到了这个分支)在这个区段的上半部分(======= 的上半部分)。
|
||||
|
||||
而 iss53 分支所指示的版本在 ======= 的下半部分。 为了解决冲突,你必须选择使用由 ======= 分割的两部分中的一个,或者你也可以自行合并这些内容。
|
||||
|
||||
如,你可以通过把这段内容换成下面的样子来解决冲突:
|
||||
|
||||
```
|
||||
<div id="footer">
|
||||
please contact us at email.support@github.com
|
||||
</div>
|
||||
```
|
||||
|
||||
上述的冲突解决方案仅保留了其中一个分支的修改,并且 <<<<<<< , ======= , 和 >>>>>>> 这些行被完全删了。 在你解决了所有文件里的冲突之后,对每个文件使用 git add 命令来将其标记为冲突已解决。 一旦暂存这些原本有冲突的文件,Git 就会将它们标记为冲突已解决。
|
||||
|
||||
## 远程分支
|
||||
|
||||
远程引用是对远程仓库的引用(指针),包括分支、标签等等。请将它们看做书签, 这样可以提醒你该分支在远程仓库中的位置就是你最后一次连接到它们的位置。
|
||||
|
||||
### 推送分支
|
||||
|
||||
当你想要公开分享一个分支时,需要将其推送到有写入权限的远程仓库上。 **本地的分支并不会自动与远程仓库同步——你必须显式地推送想要分享的分支。**
|
||||
|
||||
```
|
||||
// 推送本地分支到正在跟踪远程分支
|
||||
git push <remote> <branch>
|
||||
|
||||
// 推送本地分支到远程分支(自定义远程分支命名)
|
||||
git push <remote> <branch>:<origin-branch-name>
|
||||
```
|
||||
|
||||
### 跟踪分支
|
||||
|
||||
从一个远程跟踪分支检出一个本地分支会自动创建所谓的“跟踪分支”(它跟踪的分支叫做“上游分支”)。跟踪分支是与远程分支有直接关系的本地分支。
|
||||
|
||||
```
|
||||
// 从远程分支新建本地跟踪分支
|
||||
git checkout --track <remote>/<branch>
|
||||
|
||||
// 从远程分支新建本地跟踪分支(自定义本地分支命名)
|
||||
git checkout -b <branch> <remote>/<branch>
|
||||
|
||||
// 修改跟踪的远程分支
|
||||
git branch -u <remote>/<branch>
|
||||
|
||||
// 查看设置的所有跟踪分支
|
||||
git branch -vv
|
||||
```
|
||||
|
||||
### 拉取
|
||||
|
||||
当从服务器上抓取本地没有的数据时,可以运行 git fetch 或 git pull。推荐单独显式地使用 fetch 与 merge 命令。
|
||||
|
||||
```
|
||||
// 仅拉取默认远程分支数据,不进行自动合并。
|
||||
git fetch <remote>
|
||||
|
||||
// 拉取远程分支,并尝试自动合并。
|
||||
git pull <remote>
|
||||
```
|
||||
|
||||
### 删除远程分支
|
||||
|
||||
```
|
||||
git push <remote> --delete <branch>
|
||||
```
|
||||
|
||||
## 变基
|
||||
|
||||
你可以使用 rebase 命令将提交到某一分支上的所有修改都移至另一分支上,就好像“重新播放”一样。在 Git 中,这种操作就叫做 变基(rebase)。
|
||||
|
||||
```
|
||||
git rebase <base-branch> <topic-branch>
|
||||
```
|
||||
|
||||
它的原理是首先找到这两个分支(假设当前分支 experiment、变基操作的目标基底分支 master) 的最近共同祖先,然后对比当前分支相对于该祖先的历次提交,提取相应的修改并存为临时文件, 然后将当前分支指向目标基底, 最后以此将之前另存为临时文件的修改依序应用。
|
||||
|
||||
|
||||
```
|
||||
// 1.切换 experiment 分支。
|
||||
git checkout experiment
|
||||
|
||||
// 2.变基至 master 分支。
|
||||
git rebase master
|
||||
|
||||
// 3.切换 master 分支。
|
||||
git checkout master
|
||||
|
||||
// 4.合并 experiment 分支。
|
||||
git merge experiment
|
||||
```
|
||||
|
||||
### 更有趣的变基例子
|
||||
|
||||
在对两个分支进行变基时,所生成的“重放”并不一定要在目标分支上应用,你也可以指定另外的一个分支进行
|
||||
应用。
|
||||
|
||||
你从 master 分支创建了一个 server 分支,添加功能并提交后。又基于提交后的 server 分支创建了 client 分支,同样添加功能并提交后。你回到了 server 分支,继续添加功能并提交。假设你希望将 client 中的修改合并到主分支并发布,但暂时并不想合并 server 中的修改,因为它们还需要经过更全面的测试。
|
||||
|
||||
这时,你就可以使用 git rebase 命令的 --onto 选项, 选中在 client 分支里但不在 server 分支里的修改,将它们在 master 分支上重放。
|
||||
|
||||
```
|
||||
// 1. 取出 client 分支,找出它从 server 分支分歧之后的补丁。然后把这些补丁在master 分支上重放一遍,让 client 看起来像直接基于 master 修改一样。
|
||||
git rebase --onto master server client
|
||||
|
||||
// 2. 切换 master 分支
|
||||
git checkout master
|
||||
|
||||
// 3. 合并 client 分支
|
||||
git merge client
|
||||
```
|
||||
|
||||
接下来你决定将 server 分支中的修改也整合进来。
|
||||
|
||||
```
|
||||
// 1.变基至 master分支
|
||||
git rebase master server
|
||||
|
||||
// 2.切换 master 分支
|
||||
git checkout master
|
||||
|
||||
// 3.合并分支
|
||||
git merge server
|
||||
|
||||
// 4.删除分支
|
||||
```
|
||||
|
||||
### 变基的风险
|
||||
|
||||
如果提交存在于你的仓库之外,而别人可能基于这些提交进行开发,那么不要执行变基。
|
||||
|
||||
如果你遵循这条金科玉律,就不会出差错。 否则,人民群众会仇恨你,你的朋友和家人也会嘲笑你,唾你。
|
||||
|
||||
### 变基 vs 合并
|
||||
|
||||
至此,你已在实战中学习了变基和合并的用法,你一定会想问,到底哪种方式更好。 在回答这个问题之前,让我们退后一步,想讨论一下提交历史到底意味着什么。
|
||||
|
||||
有一种观点认为,仓库的提交历史即是 记录实际发生过什么。 它是针对历史的文档,本身就有价值,不能乱改。 从这个角度看来,改变提交历史是一种亵渎,你使用 谎言 掩盖了实际发生过的事情。 如果由合并产生的提
|
||||
|
||||
交历史是一团糟怎么办? 既然事实就是如此,那么这些痕迹就应该被保留下来,让后人能够查阅。另一种观点则正好相反,他们认为提交历史是 项目过程中发生的事。 没人会出版一本书的第一版草稿,软件维护手册也是需要反复修订才能方便使用。 持这一观点的人会使用 rebase 及 filter-branch 等工具来编写故事,怎么方便后来的读者就怎么写。
|
||||
|
||||
现在,让我们回到之前的问题上来,到底合并还是变基好?希望你能明白,这并没有一个简单的答案。 Git 是一个非常强大的工具,它允许你对提交历史做许多事情,但每个团队、每个项目对此的需求并不相同。 既然你已经分别学习了两者的用法,相信你能够根据实际情况作出明智的选择。
|
||||
|
||||
总的原则是,只对尚未推送或分享给别人的本地修改执行变基操作清理历史, 从不对已推送至别处的提交执行变基操作,这样,你才能享受到两种方式带来的便利。
|
343
docs/开发/Git/基础.md
Normal file
343
docs/开发/Git/基础.md
Normal file
@ -0,0 +1,343 @@
|
||||
---
|
||||
id: 基础
|
||||
title: 基础
|
||||
sidebar_position: 2
|
||||
data: 2022年1月13日
|
||||
---
|
||||
|
||||
如果你只想通过阅读一章来学习 Git,那么本章将是你的不二选择。 本章涵盖了你在使用 Git完成各种工作时将会用到的各种基本命令。 在学习完本章之后,你应该能够配置并初始化一个仓库(repository)、开始或停止跟踪(track)文件、暂存(stage)或提交(commit)更改。 本章也将向你演示了如何配置 Git 来忽略指定的文件和文件模式、如何迅速而简单地撤销错误操作、如何浏览你的项目的历史版本以及不同提交(commits)之间的差异、如何向你的远程仓库推送(push)以及如何从你的远程仓库拉取(pull)文件。
|
||||
|
||||
## 获取 Git 仓库
|
||||
|
||||
通常有两种获取 Git 项目仓库的方式:
|
||||
|
||||
1. 将尚未进行版本控制的本地目录转换为 Git 仓库。
|
||||
2. 从其它服务器克隆一个已存在的 Git 仓库。
|
||||
|
||||
### 在目录中初始化仓库
|
||||
|
||||
```
|
||||
// 在当前目录初始化仓库
|
||||
git init
|
||||
```
|
||||
|
||||
该命令将创建一个名为 .git 的子目录,这个子目录含有你初始化的 Git 仓库中所有的必须文件,这些文件是 Git 仓库的骨干。
|
||||
|
||||
### 克隆现有的仓库
|
||||
|
||||
如果你想获得一份已经存在了的 Git 仓库的拷贝,比如说,你想为某个开源项目贡献自己的一份力,这时就要用到 git clone 命令。
|
||||
|
||||
```
|
||||
// 克隆远程仓库
|
||||
git clone <url>
|
||||
```
|
||||
|
||||
如果你想在克隆远程仓库的时候,自定义本地仓库的名字,你可以通过额外的参数指定新的目录名:
|
||||
|
||||
```
|
||||
// 指定仓库本地命名
|
||||
git clone <url> <name>
|
||||
```
|
||||
|
||||
克隆现有的仓库,实际上是多个命令的分解。首先初始化一个本地仓库,接着添加远程仓库,最后拉取远程仓库数据到本地。
|
||||
|
||||
## 记录每次更新到仓库
|
||||
|
||||
当我们成功拥有一个仓库后,可以运行 git status 当仓库状态。在未进行开发的情况下,仓库都是干净的。当我们在工作目录对文件进行了变动,此时工作目录下的每一个文件都不外乎这两种状态:
|
||||
|
||||
- **已跟踪**:指那些被纳入了版本控制的文件,在上一次快照中有它们的记录,在工作一段时间后, 它们的状态可能是未修改,已修改或已放入暂存区。简而言之,已跟踪的文件就是 Git 已经知道的文件。
|
||||
- **未跟踪**:工作目录中除已跟踪文件外的其它所有文件都属于未跟踪文件,它们既不存在于上次快照的记录中,也没有被放入暂存区。
|
||||
|
||||
运行 git status 就会显示我们对那些文件进行了变动,那些是已跟踪,那些是未跟踪。接着我们可以使用 git add 将文件添加至暂存区。添加至暂存区后可以提交更新或继续工作;如果继续工作,同时对已暂存的文件进行了更改,可以使用 git diff 查看该文件工作区和暂存区之间的差异。
|
||||
|
||||
如果提交新修改的文件至暂存区,暂存区的文件会被新提交的覆盖。完成所有的工作开发,并且提交至暂存区后,就运行 git commit 提交更新至 git 目录,记录此次快照。
|
||||
|
||||
进行多次开发之后,想要回顾一下提交历史,可以使用 git log 查看提交历史。
|
||||
|
||||
### 忽略文件
|
||||
|
||||
有些文件无需纳入 Git 的管理,也不希望它们总出现在未跟踪文件列表。在这种情况下,我们可以创建一个名为 .gitignore 的文件,列出要忽略的文件的模式。不同目录下可以拥有不同的 .gitignore 。
|
||||
|
||||
文件 .gitignore 的格式规范如下:
|
||||
|
||||
- 所有空行或者以 # 开头的行都会被 Git 忽略。
|
||||
- 可以使用标准的 glob 模式匹配,它会递归地应用在整个工作区中(glob 模式是指 shell 所使用的简化了的正则表达式)。
|
||||
- 匹配模式可以以(/)开头防止递归。
|
||||
- 匹配模式可以以(/)结尾指定目录。
|
||||
- 要忽略指定模式以外的文件或目录,可以在模式前加上叹号(!)取反。
|
||||
|
||||
> GitHub 有一个十分详细的针对数十种项目及语言的 .gitignore 文件列表, 你可以在 https://github.com/github/gitignore 找到它。
|
||||
|
||||
### 检查当前仓库状态
|
||||
|
||||
```
|
||||
// 查看当前仓库状态总览
|
||||
git status
|
||||
|
||||
// 查看当前仓库状态简览
|
||||
git status -s
|
||||
git status --short
|
||||
|
||||
// 当前文件和暂存区之间的具体差异
|
||||
git diff
|
||||
|
||||
// 暂存区和最后一次提交的具体差异
|
||||
git diff --staged
|
||||
git diff --cached
|
||||
```
|
||||
|
||||
### 踪新文件或暂存已修改的文件
|
||||
|
||||
```
|
||||
// 添加文件到暂存区
|
||||
git add <file>
|
||||
|
||||
// 添加路径到暂存区
|
||||
git add <path>
|
||||
```
|
||||
|
||||
### 提交更新
|
||||
|
||||
```
|
||||
// 提交更新,同时会启动文本编辑器来输入提交说明。
|
||||
git commit
|
||||
|
||||
// 将提交信息与命令放在同一行
|
||||
git commit -m <msg>
|
||||
|
||||
// 跳过暂存,直接提交已跟踪文件。
|
||||
git commit -a
|
||||
```
|
||||
|
||||
## 查看提交历史
|
||||
|
||||
### git log 的常用选项
|
||||
|
||||
```
|
||||
// 格式化输出一行显示提交历史
|
||||
git log --oneline
|
||||
```
|
||||
|
||||
| 选项 | 说明 |
|
||||
| --------------- | ------------------------------------------------------------ |
|
||||
| -p | 按补丁格式显示每个提交引入的差异。 |
|
||||
| --stat | 显示每次提交的文件修改统计信息。 |
|
||||
| --shortstat | 只显示 --stat 中最后的行数修改添加移除统计。 |
|
||||
| --name-only | 仅在提交信息后显示已修改的文件清单。 |
|
||||
| --name-status | 显示新增、修改、删除的文件清单。 |
|
||||
| --abbrev-commit | 仅显示 SHA-1 校验和所有 40 个字符中的前几个字符。 |
|
||||
| --relative-date | 使用较短的相对时间而不是完整格式显示日期(比如“2 weeks ago”)。 |
|
||||
| --graph | 在日志旁以 ASCII 图形显示分支与合并历史。 |
|
||||
| --pretty | 使用其他格式显示历史提交信息。可用的选项包括 oneline、short、full、fuller 和format(用来定义自己的格式)。 |
|
||||
| --oneline | --pretty=oneline --abbrev-commit 合用的简写。 |
|
||||
|
||||
### git log --pretty=format 常用的选项
|
||||
|
||||
```
|
||||
// format 可以定制记录的显示格式
|
||||
git log --pretty=format:"%h - %an, %ar : %s"
|
||||
```
|
||||
|
||||
| 选项 | 说明 |
|
||||
| ---- | --------------------------------------------- |
|
||||
| %H | 提交的完整哈希值 |
|
||||
| %h | 提交的简写哈希值 |
|
||||
| %T | 树的完整哈希值 |
|
||||
| %t | 树的简写哈希值 |
|
||||
| %P | 父提交的完整哈希值 |
|
||||
| %p | 父提交的简写哈希值 |
|
||||
| %an | 作者名字 |
|
||||
| %ae | 作者的电子邮件地址 |
|
||||
| %ad | 作者修订日期(可以用 --date=选项 来定制格式) |
|
||||
| %ar | 作者修订日期,按多久以前的方式显示 |
|
||||
| %cn | 提交者的名字 |
|
||||
| %ce | 提交者的电子邮件地址 |
|
||||
| %cd | 提交日期 |
|
||||
| %cr | 提交日期(距今多长时间) |
|
||||
| %s | 提交说明 |
|
||||
|
||||
### 限制 git log 输出的选项
|
||||
|
||||
| 选项 | 说明 |
|
||||
| ----------------- | ------------------------------------------ |
|
||||
| -n | 仅显示最近的 n 条提交。 |
|
||||
| --since, --after | 仅显示指定时间之后的提交。 |
|
||||
| --until, --before | 仅显示指定时间之前的提交。 |
|
||||
| --author | 仅显示作者匹配指定字符串的提交。 |
|
||||
| --committer | 仅显示提交者匹配指定字符串的提交。 |
|
||||
| --grep | 仅显示提交说明中包含指定字符串的提交。 |
|
||||
| -S | 仅显示添加或删除内容匹配指定字符串的提交。 |
|
||||
|
||||
|
||||
## 撤消操作
|
||||
|
||||
有时候我们提交完了才发现漏掉了几个文件没有添加,或者提交信息写错了。 此时,可以运行带有 --amend 选
|
||||
项的提交命令来重新提交:
|
||||
|
||||
```
|
||||
// 撤销上次提交
|
||||
git commit --amend
|
||||
```
|
||||
|
||||
此命令会将当前暂存区的文件一并提交,最终只会有一个提交——第二次提交将代替第一次提交的结果。
|
||||
|
||||
### 撤销已暂存的文件
|
||||
|
||||
```
|
||||
// 取消暂存区文件
|
||||
git reset HEAD <file>
|
||||
```
|
||||
|
||||
git reset 确实是个危险的命令,如果加上了 --hard 选项则更是如此。 然而在上述场景中,工作目录中的文件尚未修改,因此相对安全一些。
|
||||
|
||||
### 撤消对文件的修改
|
||||
|
||||
```
|
||||
// 撤销工作区的文件修改
|
||||
git checkout -- <file>
|
||||
```
|
||||
|
||||
请务必记得 `git checkout -- <file>` 是一个危险的命令。 你对那个文件在本地的任何修改都会消失——Git 会用最近提交的版本覆盖掉它。 除非你确实清楚不想要对那个文件的本地修改了,否则请不要使用这个命令。
|
||||
|
||||
## 远程仓库
|
||||
|
||||
为了能在任意 Git 项目上协作,你需要知道如何管理自己的远程仓库。远程仓库是指托管在因特网或其他网络中
|
||||
的你的项目的版本库。
|
||||
|
||||
你可以有好几个远程仓库,通常有些仓库对你只读,有些则可以读写。 与他人协作涉及管理远程仓库以及根据需要推送或拉取数据。 管理远程仓库包括了解如何添加远程仓库、移除无效的远程仓库、管理不同的远程分支并定义它们是否被跟踪等等。
|
||||
|
||||
### 查看远程仓库
|
||||
|
||||
可以运行 git remote 命令,查看你已经配置的远程仓库服务器。
|
||||
|
||||
```
|
||||
// 查看远程仓库
|
||||
git remote
|
||||
```
|
||||
|
||||
你也可以指定选项 -v,会显示需要读写远程仓库使用的 Git 保存的简写与其对应的 URL
|
||||
|
||||
```
|
||||
// 显示远程仓库简写及其 URL
|
||||
git remote -v
|
||||
```
|
||||
|
||||
### 添加远程仓库
|
||||
|
||||
你可以运行 `git remote add <shortname> <url>` 添加一个新的远程 Git 仓库,同时指定一个方便使用的简写:
|
||||
|
||||
```
|
||||
// 添加一个新的远程 Git 仓库
|
||||
git remote add <remote-name> <url>
|
||||
```
|
||||
|
||||
### 从远程仓库中抓取与拉取
|
||||
|
||||
当你添加远程仓库后,可以从远程仓库拉取数据。
|
||||
|
||||
```
|
||||
// 从远程仓库拉取数据,不自动合并。
|
||||
git fetch <remote-name>
|
||||
|
||||
// 从远程仓库抓取数据,并尝试自动合并到当前分支。
|
||||
git pull
|
||||
```
|
||||
|
||||
### 推送到远程仓库
|
||||
|
||||
当你想分享你的项目时,必须将其推送到上游。
|
||||
|
||||
```
|
||||
// 推送分支到远程仓库
|
||||
git push <remote> <branch>
|
||||
```
|
||||
|
||||
### 查看、重命名与移除远程仓库
|
||||
|
||||
你可以使用以下命令,对远程仓库进行查看、重命名与移除操作。
|
||||
|
||||
```
|
||||
// 查看远程仓库
|
||||
git remote show <remote>
|
||||
|
||||
// 远程仓库的重命名
|
||||
git remote rename <old> <new>
|
||||
|
||||
// 远程仓库的移除
|
||||
git remote remove <name>
|
||||
```
|
||||
|
||||
## 打标签
|
||||
|
||||
Git 可以给仓库历史中的某一个提交打上标签,以示重要。 比较有代表性的是人们会使用这个功能来标记发布结点( v1.0 、 v2.0 等等)
|
||||
|
||||
Git 支持两种标签:**轻量标签(lightweight)**与**附注标签(annotated)**。
|
||||
|
||||
轻量标签很像一个不会改变的分支——它只是某个特定提交的引用。
|
||||
|
||||
而附注标签是存储在 Git 数据库中的一个完整对象, 它们是可以被校验的,其中包含打标签者的名字、电子邮件地址、日期时间, 此外还有一个标签信息,并且可以使用 GNU Privacy Guard (GPG)签名并验证。 通常会建议创建附注标签,这样你可以拥有以上所有信息。
|
||||
|
||||
但是如果你只是想用一个临时的标签, 或者因为某些原因不想要保存这些信息,那么也可以用轻量标签。
|
||||
|
||||
### 创建标签
|
||||
|
||||
```
|
||||
// 创建轻量标签
|
||||
git tag <tagname>
|
||||
|
||||
// 创建附注标签
|
||||
git tag -a <tagname>
|
||||
```
|
||||
|
||||
你也可以对过去的提交打标签。,只需要输入提交的 SHA-1 数。
|
||||
|
||||
```
|
||||
// 后期打标签
|
||||
git tag <tagname> <commit-id>
|
||||
```
|
||||
|
||||
### 查看标签
|
||||
|
||||
```
|
||||
// 列出已有的标签
|
||||
git tag
|
||||
|
||||
// 显示标签信息
|
||||
git show <tagname>
|
||||
```
|
||||
|
||||
### 共享标签
|
||||
|
||||
默认情况下,git push 命令并不会传送标签到远程仓库服务器上。 在创建完标签后你必须显式地推送标签到共享服务器上。
|
||||
|
||||
```
|
||||
// 推送标签到远程仓库
|
||||
git push origin <tagname>
|
||||
|
||||
// 推送全部标签
|
||||
git push origin --tags
|
||||
```
|
||||
|
||||
### 删除标签
|
||||
|
||||
```
|
||||
// 删除标签
|
||||
git tag -d <tagname>
|
||||
|
||||
// 删除远程仓库标签
|
||||
git push origin --delete <tagname>
|
||||
```
|
||||
|
||||
## Git 别名
|
||||
|
||||
Git 并不会在你输入部分命令时自动推断出你想要的命令。 如果不想每次都输入完整的 Git 命令,可以通过 git
|
||||
config 文件来轻松地为每一个命令设置一个别名。如下:
|
||||
|
||||
```
|
||||
git config --global alias.co checkout
|
||||
git config --global alias.br branch
|
||||
git config --global alias.ci commit
|
||||
git config --global alias.st status
|
||||
```
|
||||
|
||||
接下来我们就可以使用 git co 等价代替 git checkout,其他同理。
|
262
docs/开发/Git/工作流.md
Normal file
262
docs/开发/Git/工作流.md
Normal file
@ -0,0 +1,262 @@
|
||||
---
|
||||
id: 工作流
|
||||
title: 工作流
|
||||
sidebar_position: 4
|
||||
data: 2022年1月13日
|
||||
---
|
||||
|
||||
|
||||
|
||||
你现在拥有了一个远程 Git 版本库,能为所有开发者共享代码提供服务,在一个本地工作流程下,你也已经熟悉了基本 Git 命令。你现在可以学习如何利用 Git 提供的一些分布式工作流程了。
|
||||
|
||||
## 分布式工作流程
|
||||
|
||||
与传统的集中式版本控制系统(CVCS)相反,Git 的分布式特性使得开发者间的协作变得更加灵活多样。 在集中式系统中,每个开发者就像是连接在集线器上的节点,彼此的工作方式大体相像。 而在 Git 中,每个开发者同时扮演着节点和集线器的角色——也就是说, 每个开发者既可以将自己的代码贡献到其他的仓库中,同时也能维护自己的公开仓库, 让其他人可以在其基础上工作并贡献代码。
|
||||
|
||||
### 集中式工作流
|
||||
|
||||
集中式系统中通常使用的是单点协作模型——集中式工作流。 一个中心集线器,或者说 仓库,可以接受代码,所有人将自己的工作与之同步。 若干个开发者则作为节点,即中心仓库的消费者与中心仓库同步。
|
||||
|
||||
### 集成管理者工作流
|
||||
|
||||
Git 允许多个远程仓库存在,使得这样一种工作流成为可能:每个开发者拥有自己仓库的写权限和其他所有人仓库的读权限。 这种情形下通常会有个代表“官方”项目的权威的仓库。 要为这个项目做贡献,你需要从该项目克隆出一个自己的公开仓库,然后将自己的修改推送上去。 接着你可以请求官方仓库的维护者拉取更新合并到主项目维护者可以将你的仓库作为远程仓库添加进来,在本地测试你的变更,将其合并入他们的分支并推送回官方仓库。这一流程的工作方式如下所示:
|
||||
|
||||
1. 项目维护者推送到主仓库。
|
||||
2. 贡献者克隆此仓库,做出修改。
|
||||
3. 贡献者将数据推送到自己的公开仓库。
|
||||
4. 贡献者给维护者发送邮件,请求拉取自己的更新。
|
||||
5. 维护者在自己本地的仓库中,将贡献者的仓库加为远程仓库并合并修改。
|
||||
6. 维护者将合并后的修改推送到主仓库。
|
||||
|
||||
### 主管与副主管工作流
|
||||
|
||||
这其实是多仓库工作流程的变种。 一般拥有数百位协作开发者的超大型项目才会用到这样的工作方式,例如著名的 Linux 内核项目。 被称为 副主管(lieutenant) 的各个集成管理者分别负责集成项目中的特定部分。 所有这些副主管头上还有一位称为 主管(dictator) 的总集成管理者负责统筹。 主管维护的仓库作为参考仓库,为所有协作者提供他们需要拉取的项目代码。 整个流程看起来是这样的:
|
||||
|
||||
1. 普通开发者在自己的主题分支上工作,并根据 master 分支进行变基。 这里是主管推送的参考仓库的 master 分支。
|
||||
2. 副主管将普通开发者的主题分支合并到自己的 master 分支中。
|
||||
3. 主管将所有副主管的 master 分支并入自己的 master 分支中。
|
||||
4. 最后,主管将集成后的 master 分支推送到参考仓库中,以便所有其他开发者以此为基础进行变基。
|
||||
|
||||
## 向一个项目贡献
|
||||
|
||||
描述如何向一个项目贡献的主要困难在于完成贡献有很多不同的方式。 因为 Git 非常灵活,人们可以通过不同的方式来一起工作,所以描述应该如何贡献并不是非常准确——每一个项目都有一点儿不同。 影响因素包括活跃贡献者的数量、选择的工作流程、提交权限与可能包含的外部贡献方法。
|
||||
|
||||
第一个影响因素是**活跃贡献者的数量**——积极地向这个项目贡献代码的用户数量以及他们的贡献频率。 在许多情况下,你可能会有两三个开发者一天提交几次,对于不活跃的项目可能更少。 对于大一些的公司或项目,开发者的数量可能会是上千,每天都有成百上千次提交。这很重要,因为随着开发者越来越多,在确保你的代码能干净地应用或轻松地合并时会遇到更多问题。 提交的改动可能表现为过时的,也可能在你正在做改动或者等待改动被批准应用时被合并入的工作严重损坏。 如何保证代码始终是最新的,并且提交始终是有效的?
|
||||
|
||||
下一个影响因素是**项目使用的工作流程**。 它是中心化的吗,即每一个开发者都对主线代码有相同的写入限?项目是否有一个检查所有补丁的维护者或整合者? 是否所有的补丁是同行评审后批准的? 你是否参与了那个过程? 是否存在副官系统,你必须先将你的工作提交到上面?
|
||||
|
||||
下一个影响因素是**提交权限**。 是否有项目的写权限会使向项目贡献所需的流程有极大的不同。 如果没有写权限,项目会选择何种方式接受贡献的工作? 是否甚至有一个如何贡献的规范? 你一次贡献多少工作? 你多久贡献一次?
|
||||
|
||||
### 提交准则
|
||||
|
||||
```
|
||||
首字母大写的摘要(不多于 50 个字符)
|
||||
|
||||
如果必要的话,加入更详细的解释文字。在大概 72 个字符的时候换行。
|
||||
在某些情形下,第一行被当作一封电子邮件的标题,剩下的文本作为正文。
|
||||
分隔摘要与正文的空行是必须的(除非你完全省略正文),
|
||||
如果你将两者混在一起,那么类似变基等工具无法正常工作。
|
||||
|
||||
使用指令式的语气来编写提交信息:使用“Fix bug”而非“Fixed bug”或“Fixes bug”。
|
||||
此约定与 git merge 和 git revert 命令生成提交说明相同。
|
||||
|
||||
空行接着更进一步的段落。
|
||||
|
||||
- 标号也是可以的。
|
||||
|
||||
- 项目符号可以使用典型的连字符或星号,后跟一个空格,行之间用空行隔开,
|
||||
但是可以依据不同的惯例有所不同。
|
||||
|
||||
- 使用悬挂式缩进
|
||||
```
|
||||
|
||||
### 私有小型团队
|
||||
|
||||
私有小型团队通常由两个以上开发者,工作流程相对简单:
|
||||
|
||||
1. 开发者 John,克隆了仓库,做了改动,然后本地提交。
|
||||
|
||||
2. 开发者 Jessica,做了同样的事情——克隆仓库并提交了一个改动:
|
||||
|
||||
3. Jessica 把她的工作推送到服务器上,一切正常。
|
||||
|
||||
4. John 稍候也做了些改动,将它们提交到了本地仓库中,然后试着将它们推送到同一个服务器。
|
||||
|
||||
5. 这时 John 会推送失败,因为之前 Jessica 已经推送了她的更改。
|
||||
|
||||
6. 因为 John 必须先抓取 Jessica 的上游改动并将它们合并到自己的本地仓库中,才能被允许推送。
|
||||
|
||||
7. 第一步,John 抓取 Jessica 的工作。
|
||||
|
||||
8. 第二步,John 合并工作。
|
||||
|
||||
…………
|
||||
|
||||
### 私有管理团队
|
||||
|
||||
型私有团队中贡献者基于特性进行协作,而这些团队的贡献将会由其他人整合。
|
||||
|
||||
1. John 与 Jessica 在一个特性分支(featureA)上工作。
|
||||
2. Jessica 同时与第三个开发者 Josie 在第二个特性分支(featureB)上工作。
|
||||
3. 公司使用了一种整合-管理者工作流程,独立小组的工作只能被特定的工程师整合, 主仓库的 master 分支只能被那些工程师更新。
|
||||
4. 在这种情况下,所有的工作都是在基于团队的分支上完成的,并且稍后会被整合者拉到一起。
|
||||
|
||||
…………
|
||||
|
||||
### 派生的公开项目
|
||||
|
||||
第一个例子描述在支持简单派生的 Git 托管上使用派生来做贡献。 许多托管站点支持这个功能(包括 GitHub、BitBucket、repo.or.cz 等等),许多项目维护者期望这种风格的贡献。
|
||||
|
||||
第二个例子会讨论偏好通过邮件接受贡献补丁的项目。
|
||||
|
||||
### 通过 Fork 的公开项目
|
||||
|
||||
首先,你可能想要克隆主仓库,为计划贡献的补丁或补丁序列创建一个主题分支,然后在那儿做工作。
|
||||
|
||||
```
|
||||
// 克隆远程仓库
|
||||
git clone <url>
|
||||
|
||||
// 切换至项目目录
|
||||
cd project
|
||||
|
||||
// 创建并切换至特性分支
|
||||
git checkout -b featureA
|
||||
|
||||
// ... 工作 ...
|
||||
git commit
|
||||
|
||||
// ... 工作 ...
|
||||
git commit
|
||||
```
|
||||
|
||||
当你的分支工作完成后准备将其贡献回维护者,去原始项目中然后点击 Fork 按钮,创建一份自己的可写的项目派生仓库。 然后需要在本地仓库中将该仓库添加为一个新的远程仓库,在本例中称作 myfork:
|
||||
|
||||
```
|
||||
// 添加 fork 仓库
|
||||
git remote add myfork <url>
|
||||
|
||||
// 推送特性分支
|
||||
git push -u myfork featureA
|
||||
```
|
||||
|
||||
当工作已经被推送到你的派生仓库后,你需要通知原项目的维护者你有想要他们合并的工作。 这通常被称作一个 拉取请求(Pull Request),**你通常可以通过网站生成它**。也可以运行 git request-pull 命令然后将随后的输出通过电子邮件手动发送给项目维护者。
|
||||
|
||||
在一个你不是维护者的项目上,通常有一个总是跟踪 origin/master 的 master 分支会很方便,在主题分支上做工作是因为如果它们被拒绝时你可以轻松地丢弃。 如果同一时间主仓库移动了然后你的提交不再能干净地应用,那么使工作主题独立于主题分支也会使你变基(rebase)工作时更容易。
|
||||
|
||||
例如,你想要提供第二个特性工作到项目,不要继续在刚刚推送的主题分支上工作——从主仓库的 master 分支重新开始:
|
||||
|
||||
### 通过邮件的公开项目
|
||||
|
||||
首先,你要克隆主仓库,然后在那儿做工作。
|
||||
|
||||
```
|
||||
// 克隆远程仓库
|
||||
git clone <url>
|
||||
|
||||
// 切换至项目目录
|
||||
cd project
|
||||
|
||||
// 创建并切换至特性分支
|
||||
git checkout -b topicA
|
||||
|
||||
// ... 工作 ...
|
||||
git commit
|
||||
|
||||
// ... 工作 ...
|
||||
git commit
|
||||
```
|
||||
|
||||
现在有两个提交要发送到邮件列表。 使用 git format-patch 来生成可以邮寄到列表的 mbox 格式的文件——它将每一个提交转换为一封电子邮件,提交信息的第一行作为主题,剩余信息与提交引入的补丁作为正文。
|
||||
|
||||
```
|
||||
git format-patch -M origin/master
|
||||
|
||||
// 补丁文件
|
||||
<file-name>.patch
|
||||
<file-name>.patch
|
||||
```
|
||||
|
||||
为了将其邮寄到邮件列表,你既可以将文件粘贴进电子邮件客户端,也可以通过命令行程序发送它。
|
||||
|
||||
```
|
||||
// 本地邮件服务器设置正确的前提下,使用此命令。
|
||||
git send-email <file-name>.patch
|
||||
```
|
||||
|
||||
## 维护项目
|
||||
|
||||
除了如何有效地参与一个项目的贡献之外,你可能也需要了解如何维护项目。 这包含接受并应用别人使用 format-patch 生成并通过电子邮件发送过来的补丁,或对项目添加的远程版本库分支中的更改进行整合。 但无论是管理版本库,还是帮忙验证、审核收到的补丁,都需要同其他贡献者约定某种长期可持续的工作方式。
|
||||
|
||||
### 在主题分支中工作
|
||||
|
||||
如同本地新建一个特性分支一般。在添加贡献者的提交分支通过本地测试后,就可以考虑是否将其合并到长期分支中了。
|
||||
|
||||
### 应用来自邮件的补丁
|
||||
|
||||
#### 使用 apply 命令应用补丁
|
||||
|
||||
如果你收到了一个使用 git diff 或 Unix diff 命令的变体(不推荐使用这种方式,具体见下一小节) 创建的补丁,可以使用 git apply 命令来应用。 假设你将补丁保存在了 /tmp/patch-ruby-client.patch 中,可以这样应用补丁:
|
||||
|
||||
```
|
||||
git apply /tmp/patch-ruby-client.patch
|
||||
```
|
||||
|
||||
#### 使用 am 命令应用补丁
|
||||
|
||||
如果补丁的贡献者也是一个 Git 用户,并且其能熟练使用 format-patch 命令来生成补丁,这样的话你的工作会变得更加轻松,因为这种补丁中包含了作者信息和提交信息供你参考。
|
||||
|
||||
要应用一个由 format-patch 命令生成的补丁,你应该使用 git am 命令。
|
||||
|
||||
```
|
||||
git am <file-name>.patch
|
||||
```
|
||||
|
||||
#### 检出远程分支
|
||||
|
||||
如果你的贡献者建立了自己的版本库,并且向其中推送了若干修改, 之后将版本库的 URL 和包含更改的远程分支发送给你,那么你可以将其添加为一个远程分支,并且在本地进行合并。
|
||||
|
||||
### 将贡献的工作整合进来
|
||||
|
||||
#### 合并工作流
|
||||
|
||||
一种基本的工作流就是将所有的工作直接合并到 master 分支。 在这种情况下,master 分支包含的代码是基本稳定的。 当你完成某个主题分支的工作,或审核通过了其他人所贡献的工作时,你会将其合并进入 master分支,之后将主题分支删除,如此反复。
|
||||
|
||||
#### 大项目合并工作流
|
||||
|
||||
Git 项目包含四个长期分支:master、next,用于新工作的 pu(proposed updates)和用于维护性向后移植工作(maintenance backports)的 maint 分支。 贡献者的新工作会以类似之前所介绍的方式收入主题分支中(见 管理复杂的一系列接收贡献的平行主题分支。)。 之后对主题分支进行测试评估,检查其是否已经能够合并,或者仍需要更多工作。 安全的主题分支会被合并入 next 分支,之后该分支会被推送使得所有人都可以尝试整合到一起的特性。
|
||||
|
||||
#### 变基与拣选工作流
|
||||
|
||||
为了保持线性的提交历史,有些维护者更喜欢在 master 分支上对贡献过来的工作进行变基和拣选,而不是直接将其合并。 当你完成了某个主题分支中的工作,并且决定要将其整合的时候,你可以在该分支中运行变基命令, 在当前 master 分支(或者是 develop 等分支)的基础上重新构造修改。
|
||||
|
||||
#### 为发布打标签
|
||||
|
||||
当你决定进行一次发布时,你可能想要打一个标签,这样在之后的任何一个提交点都可以重新创建该发布。
|
||||
|
||||
#### 生成一个构建号
|
||||
|
||||
Git 中不存在随每次提交递增的 v123 之类的数字序列,如果你想要为提交附上一个可读的名称, 可以对其运行 git describe 命令。作为回应,Git 将会生成一个字符串, 它由最近的标签名、自该标签之后的提交数目和你所描述的提交的部分 SHA-1 值(前缀的 g 表示 Git)构成:
|
||||
|
||||
```
|
||||
git describe master
|
||||
v1.6.2-rc1-20-g8c5b85c
|
||||
```
|
||||
|
||||
#### 准备一次发布
|
||||
|
||||
现在你可以发布一个构建了。 其中一件事情就是为那些不使用 Git 的可怜包们创建一个最新的快照归档。 使用
|
||||
git archive 命令完成此工作:
|
||||
|
||||
```
|
||||
git archive master > archive.zip
|
||||
```
|
||||
|
||||
#### 制作提交简报
|
||||
|
||||
现在是时候通知邮件列表里那些好奇你的项目发生了什么的人了。 使用 git shortlog 命令可以快速生成一份包含从上次发布之后项目新增内容的修改日志(changelog)类文档。
|
||||
|
||||
```
|
||||
// 包括了自 v1.0.1 以来的所有提交
|
||||
git shortlog --no-merges master --not v1.0.1
|
||||
```
|
87
docs/开发/Git/服务.md
Normal file
87
docs/开发/Git/服务.md
Normal file
@ -0,0 +1,87 @@
|
||||
---
|
||||
id: 服务
|
||||
title: 服务
|
||||
sidebar_position: 5
|
||||
data: 2022年1月13日
|
||||
---
|
||||
|
||||
|
||||
|
||||
|
||||
到目前为止,你应该已经有办法使用 Git 来完成日常工作。 然而,为了使用 Git 协作功能,你还需要有远程的 Git 仓库。 尽管在技术上你可以从个人仓库进行推送(push)和拉取(pull)来修改内容,但不鼓励使用这种方法,因为一不留心就很容易弄混其他人的进度。 此外,你希望你的合作者们即使在你的电脑未联机时亦能存取仓库 — 拥有一个更可靠的公用仓库十分有用。 因此,与他人合作的最佳方法即是建立一个你与合作者们都有权利访问,且可从那里推送和拉取资料的共用仓库。
|
||||
|
||||
架设一台 Git 服务器并不难。如果你不介意托管你的代码在其他人的服务器,且不想经历设置与维护自己服务器的麻烦,可以试试第三方仓库托管服务。
|
||||
|
||||
一个远程仓库通常只是一个裸仓库(bare repository)——即一个没有当前工作目录的仓库。 因为该仓库仅仅
|
||||
作为合作媒介,不需要从磁盘检查快照;存放的只有 Git 的资料。 简单的说,裸仓库就是你工程目录内的 .git
|
||||
子目录内容,不包含其他资料。
|
||||
|
||||
## Git 协议
|
||||
|
||||
Git 可以使用四种不同的协议来传输资料:
|
||||
|
||||
- 本地协议(Local)
|
||||
- HTTP 协议
|
||||
- SSH(Secure Shell)协议
|
||||
- Git协议
|
||||
|
||||
### 本地协议
|
||||
|
||||
最基本的就是 本地协议(Local protocol),其中的远程版本库就是同一主机上的另一个目录。 这常见于团队每一个成员都对一个共享的文件系统(例如一个挂载的 NFS)拥有访问权,或者比较少见的多人共用同一台电脑的情况。 后者并不理想,因为你的所有代码版本库如果长存于同一台电脑,更可能发生灾难性的损失。
|
||||
|
||||
**优点**
|
||||
|
||||
基于文件系统的版本库的优点是简单,并且直接使用了现有的文件权限和网络访问权限。 如果你的团队已经有共享文件系统,建立版本库会十分容易。 只需要像设置其他共享目录一样,把一个裸版本库的副本放到大家都可以访问的路径,并设置好读/写的权限,就可以了, 我们会在在服务器上搭建 Git 讨论如何导出一个裸版本库。这也是快速从别人的工作目录中拉取更新的方法。 如果你和别人一起合作一个项目,他想让你从版本库中拉取更新时,运行类似 git pull /home/john/project 的命令比推送到服务器再抓取回来简单多了。
|
||||
|
||||
**缺点**
|
||||
|
||||
这种方法的缺点是,通常共享文件系统比较难配置,并且比起基本的网络连接访问,这不方便从多个位置访问。如果你想从家里推送内容,必须先挂载一个远程磁盘,相比网络连接的访问方式,配置不方便,速度也慢。值得一提的是,如果你使用的是类似于共享挂载的文件系统时,这个方法不一定是最快的。 访问本地版本库的速度与你访问数据的速度是一样的。 在同一个服务器上,如果允许 Git 访问本地硬盘,一般的通过 NFS 访问版本库要比通过 SSH 访问慢。最终,这个协议并不保护仓库避免意外的损坏。 每一个用户都有“远程”目录的完整 shell 权限,没有方法可以阻止他们修改或删除 Git 内部文件和损坏仓库。
|
||||
|
||||
### HTTP 协议
|
||||
|
||||
Git 通过 HTTP 通信有两种模式:**智能 HTTP 协议、哑(Dumb) HTTP 协议。**
|
||||
|
||||
#### 智能 HTTP 协议
|
||||
|
||||
智能 HTTP 的运行方式和 SSH 及 Git 协议类似,只是运行在标准的 HTTP/S 端口上并且可以使用各种 HTTP 验证机制, 这意味着使用起来会比 SSH 协议简单的多,比如可以使用 HTTP 协议的用户名/密码授权,免去设置 SSH 公钥。
|
||||
|
||||
#### 哑(Dumb) HTTP 协议
|
||||
|
||||
如果服务器没有提供智能 HTTP 协议的服务,Git 客户端会尝试使用更简单的“哑” HTTP 协议。 哑 HTTP 协议里 web 服务器仅把裸版本库当作普通文件来对待,提供文件服务。 哑 HTTP 协议的优美之处在于设置起来简单。
|
||||
|
||||
**优点**
|
||||
|
||||
我们将只关注智能 HTTP 协议的优点。不同的访问方式只需要一个 URL 以及服务器只在需要授权时提示输入授权信息,这两个简便性让终端用户使用 Git 变得非常简单。 相比 SSH 协议,可以使用用户名/密码授权是一个很大的优势,这样用户就不必须在使用 Git 之前先在本地生成 SSH 密钥对再把公钥上传到服务器。 对非资深的使用者,或者系统上缺少 SSH 相关程序的使用者,HTTP 协议的可用性是主要的优势。 与 SSH 协议类似,HTTP 协议也非常快和高效。你也可以在 HTTPS 协议上提供只读版本库的服务,如此你在传输数据的时候就可以加密数据;或者,你甚至可以让客户端使用指定的 SSL 证书。另一个好处是 HTTPS 协议被广泛使用,一般的企业防火墙都会允许这些端口的数据通过。
|
||||
|
||||
**缺点**
|
||||
|
||||
在一些服务器上,架设 HTTPS 协议的服务端会比 SSH 协议的棘手一些。 除了这一点,用其他协议提供 Git 服务与智能 HTTP 协议相比就几乎没有优势了。如果你在 HTTP 上使用需授权的推送,管理凭证会比使用 SSH 密钥认证麻烦一些。 然而,你可以选择使用凭证存储工具,比如 macOS 的 Keychain 或者 Windows 的凭证管理器。 参考 凭证存储 如何安全地保存 HTTP 密码。
|
||||
|
||||
### SSH 协议
|
||||
|
||||
架设 Git 服务器时常用 SSH 协议作为传输协议。 因为大多数环境下服务器已经支持通过 SSH 访问 —— 即使没有也很容易架设。 SSH 协议也是一个验证授权的网络协议;并且,因为其普遍性,架设和使用都很容易。
|
||||
|
||||
**优势**
|
||||
|
||||
用 SSH 协议的优势有很多。 首先,SSH 架设相对简单 —— SSH 守护进程很常见,多数管理员都有使用经验,并
|
||||
且多数操作系统都包含了它及相关的管理工具。 其次,通过 SSH 访问是安全的 —— 所有传输数据都要经过授权和加密。 最后,与 HTTPS 协议、Git 协议及本地协议一样,SSH 协议很高效,在传输前也会尽量压缩数据。
|
||||
|
||||
**缺点**
|
||||
SSH 协议的缺点在于它不支持匿名访问 Git 仓库。 如果你使用 SSH,那么即便只是读取数据,使用者也 必须 通
|
||||
过 SSH 访问你的主机, 这使得 SSH 协议不利于开源的项目,毕竟人们可能只想把你的仓库克隆下来查看。 如果你只在公司网络使用,SSH 协议可能是你唯一要用到的协议。 如果你要同时提供匿名只读访问和 SSH 协议,那么你除了为自己推送架设 SSH 服务以外, 还得架设一个可以让其他人访问的服务。
|
||||
|
||||
### Git 协议
|
||||
|
||||
这是包含在 Git 里的一个特殊的守护进程;它监听在一个特定的端口(9418),类似于 SSH 服务,但是访问无需任何授权。 要让版本库支持 Git 协议,需要先创建一个 git-daemon-export-ok 文件 —— 它是 Git 协议守护进程为这个版本库提供服务的必要条件 —— 但是除此之外没有任何安全措施。 要么谁都可以克隆这个版本库,要么谁也不能。 这意味着,通常不能通过 Git 协议推送。 由于没有授权机制,一旦你开放推送操作,意味着网络上知道这个项目 URL 的人都可以向项目推送数据。 不用说,极少会有人这么做。
|
||||
|
||||
**优点**
|
||||
|
||||
目前,Git 协议是 Git 使用的网络传输协议里最快的。 如果你的项目有很大的访问量,或者你的项目很庞大并且不需要为写进行用户授权,架设 Git 守护进程来提供服务是不错的选择。 它使用与 SSH 相同的数据传输机制,但是省去了加密和授权的开销。
|
||||
|
||||
**缺点**
|
||||
|
||||
Git 协议缺点是缺乏授权机制。 把 Git 协议作为访问项目版本库的唯一手段是不可取的。 一般的做法里,会同时提供 SSH 或者 HTTPS 协议的访问服务,只让少数几个开发者有推送(写)权限,其他人通过 git:// 访问只有读权限。 Git 协议也许也是最难架设的。 它要求有自己的守护进程,这就要配置 xinetd、systemd 或者其他的程序,这些工作并不简单。 它还要求防火墙开放 9418 端口,但是企业防火墙一般不会开放这个非标准端口。而大型的企业防火墙通常会封锁这个端口。
|
||||
|
||||
## 第三方托管
|
||||
|
||||
现在已经拥有了很多更现代,功能更全的 Git 服务器,GitLab 便是其中最出名的一个,同时 GitHub、Gitte 都是很棒的开源社区。
|
136
docs/开发/Git/起步.md
Normal file
136
docs/开发/Git/起步.md
Normal file
@ -0,0 +1,136 @@
|
||||
---
|
||||
id: 起步
|
||||
title: 起步
|
||||
sidebar_position: 1
|
||||
data: 2022年1月13日
|
||||
---
|
||||
|
||||
本章介绍开始使用 Git 前的相关知识。我们会先了解一些版本控制工具的历史背景,然后试着让 Git 在你的系统上跑起来,直到最后配置好,可以正常开始开发工作。读完本章,你就会明白为什么 Git 会如此流行,为什么你应该立即开始使用它。
|
||||
|
||||
## 版本控制系统
|
||||
版本控制系统(Version Control Systems,简称 VCS)是一种记录一个或若干文件内容变化,以便将来查阅特定版本修订情况的系统。
|
||||
|
||||
### 本地版本控制系统
|
||||
|
||||
本地版本控制系统大多采用数据库来记录文件的历次更新差异。
|
||||
|
||||
其中最流行的一种叫做 RCS,现今许多计算机系统上都还看得到它的踪影。RCS 的工作原理是在硬盘上保存补丁集(补丁是指文件修订前后的变化);通过应用所有的补丁,可以重新计算出各个版本的文件内容。
|
||||
|
||||
### 集中化的版本控制系统
|
||||
|
||||
为了解决本地版本控制系统无法协同工作的问题,集中化的版本控制系统(Centralized Version Control Systems,简称 CVCS)应允而生。其采用一个单一集中管理的服务器,保存所有文件的修订版本;协作者通过客户端连接服务器,拉取最新文件或提交更新。
|
||||
|
||||
**优点**:相较于本地 VCS 来说。 现在,每个人都可以在一定程度上看到项目中的其他人正在做些什么。 而管理员也可以轻松掌控每个开发者的权限,并且管理一个 CVCS 要远比在各个客户端上维护本地数据库来得轻松容易。
|
||||
|
||||
**缺点**:显而易见的缺点是中央服务器的单点故障。例如宕机一小时,那么在这一小时内,谁都无法提交更新,也就无法协同工作;如果中心数据库所在的磁盘发生损坏,又没有做恰当备份,毫无疑问你将丢失所有数据——包括项目的整个变更历史,只剩下人们在各自机器上保留的单独快照。
|
||||
|
||||
### 分布式版本控制系统
|
||||
|
||||
为了解决集中化的版本控制系统的痛处,分布式版本控制系统(Distributed Version Control System,简称 DVCS)面世了。分布式顾名思义,每一个节点都基于公认中心节点服务器的镜像拷贝,故每个节点都拥有代码仓库的完整信息。因此不存在中心节点故障无法工作、物理损坏无法恢复、日志历史不完整导致协作者无法相互协作。
|
||||
|
||||
更进一步,许多这类系统都可以指定和若干不同的远端代码仓库进行交互。籍此,你就可以在同一个项目中,分别和不同工作小组的人相互协作。 你可以根据需要设定不同的协作流程,比如层次模型式的工作流,而这在以前的集中式系统中是无法实现的。
|
||||
|
||||
## Git 简史
|
||||
同生活中的许多伟大事物一样,Git 诞生于一个极富纷争大举创新的年代。
|
||||
|
||||
Linux 内核开源项目有着为数众多的参与者。 绝大多数的 Linux 内核维护工作都花在了提交补丁和保存归档的繁琐事务上(1991-2002年间)。到 2002 年,整个项目组开始启用一个专有的分布式版本控制系统 BitKeeper 来管理和维护代码。
|
||||
|
||||
到了 2005 年,开发 BitKeeper 的商业公司同 Linux 内核开源社区的合作关系结束,他们收回了 Linux 内核社区免费使用 BitKeeper 的权力。 这就迫使 Linux 开源社区(特别是 Linux 的缔造者 Linus Torvalds)基于使用BitKeeper 时的经验教训,开发出自己的版本系统。 他们对新的系统制订了若干目标:
|
||||
|
||||
- **速度**
|
||||
- **简单的设计**
|
||||
- **对非线性开发模式的强力支持(允许成千上万个并行开发的分支)**
|
||||
- **完全分布式**
|
||||
- **有能力高效管理类似 Linux 内核一样的超大规模项目(速度和数据量)**
|
||||
|
||||
自诞生于 2005 年以来,Git 日臻成熟完善,在高度易用的同时,仍然保留着初期设定的目标。 它的速度飞快,极其适合管理大项目,有着令人难以置信的非线性分支管理系统。
|
||||
## Git 特性
|
||||
那么,简单地说,Git 究竟是怎样的一个系统呢?它的主要特性是什么?
|
||||
|
||||
### 直接记录快照,而非差异比较
|
||||
|
||||
Git 与其他版本控制系统主要差别在于对待数据的方法;**Git 直接记录快照,而非差异比较**。Git 中每一次提交更新或保存项目状态都是对全部文件创建一个快照并保存这个快照的索引;如果文件没有修改,Git 则不再重新存储该文件,而是只保留一个链接指向之前存储的文件。Git 对待数据更像是一个快照流。
|
||||
|
||||
### 近乎所有操作都是本地执行
|
||||
|
||||
由于 Git 是分布式版本控制系统,在不对公认中心节点服务器操作的情况下,绝大多数操作都只需要访问本地文件资源。故 Git 大部分操作看起来瞬间完成,不存在网络延时。
|
||||
|
||||
### Git 保证数据完整性
|
||||
|
||||
Git 中所有的数据在存储前都用 SHA-1 散列(hash,哈希)计算校验和并以哈希值来索引,而不是文件名。这意味着不可能在 Git 不知情时更改任何文件内容或目录内容。
|
||||
|
||||
```
|
||||
// SHA-1 哈希
|
||||
24b9da6552252987aa493b52f8696cd6d3b00373
|
||||
```
|
||||
|
||||
### Git 一般只添加数据
|
||||
|
||||
因为 Git 一般只添加数据,所以你很难让 Git 执行任何不可逆操作,或者让它以任何方式清除数据。
|
||||
|
||||
### Git 的三种状态
|
||||
|
||||
Git 有三种状态,你的文件可能处于其中之一: **已提交(committed)**、**已修改(modified)** 和 **已暂存(staged)**。
|
||||
|
||||
- 已修改表示修改了文件,但还没保存到数据库中
|
||||
- 已暂存表示对一个已修改文件的当前版本做了标记,使之包含在下次提交的快照中。
|
||||
- 已提交表示数据已经安全地保存在本地数据库中。
|
||||
|
||||
这会让我们的 Git 项目拥有三个阶段:**工作区(Working Directory)**、**暂存区(Staging Area)** 以及 **Git 目录(Repository)**。
|
||||
|
||||
- 工作区对项目的某个版本独立提取出来的内容,放在磁盘上供你使用或修改。
|
||||
- 暂存区(术语:索引)保存了下次将要提交的文件列表信息。
|
||||
- Git 目录是 Git 用来保存项目的元数据和对象数据库的地方。
|
||||
|
||||
所以 Git 的基本工作流程如下:
|
||||
|
||||
1. 在工作区中修改文件(**已修改**)。
|
||||
2. 将你下次想要提交的更改选择性地暂存,这样只会将更改的部分添加到暂存区(**已暂存**)。
|
||||
3. 提交更新,找到暂存区的文件,将快照永久性存储到 Git 目录(**已提交**)。
|
||||
|
||||
## 首次运行 Git
|
||||
|
||||
安装 Git 后要先定制你的 Git 环境,仅需配置一次,升级时保留配置信息。
|
||||
### Git 配置
|
||||
|
||||
1. 系统配置:包含系统上每一个用户及其仓库的通用配置。
|
||||
2. 全局配置:只针对当前用户,对系统上所有仓库生效。
|
||||
3. 仓库配置:仅对当前仓库生效,为默认选项。
|
||||
|
||||
配置文件作用域采用就近原则,每一个级别会覆盖上一级别的配置。修改不同的配置文件,需要在执行 git config 时传递不同参数。
|
||||
|
||||
```
|
||||
git config --system
|
||||
git config --global
|
||||
git config --local
|
||||
```
|
||||
|
||||
### 用户信息
|
||||
|
||||
务必设置用户名和邮件地址,这一点至关重要,因为每一个 Git 提交都会使用这些信息,并且写入到每一次提交中,不可更改。
|
||||
|
||||
```
|
||||
git config --global user.name <user-name>
|
||||
git config --global user.email <email@email.com)
|
||||
```
|
||||
|
||||
### 查看配置
|
||||
|
||||
```
|
||||
// 所有 Git 配置
|
||||
git config --list
|
||||
|
||||
// 检查 Git 的某一项配置
|
||||
git config <key>
|
||||
```
|
||||
|
||||
### 获取帮助
|
||||
|
||||
```
|
||||
git help <verb>
|
||||
git <verb> --help
|
||||
man git-<verb>
|
||||
|
||||
// 简明的帮助文件
|
||||
git <verb> -h
|
||||
```
|
@ -58,7 +58,7 @@ const config = {
|
||||
// 导航栏
|
||||
navbar: {
|
||||
title: '7Wate`s Wiki',
|
||||
hideOnScroll: true,
|
||||
// hideOnScroll: true,
|
||||
// logo: {
|
||||
// alt: 'Site Logo',
|
||||
// src: 'img/logo.svg',
|
||||
|
Loading…
Reference in New Issue
Block a user