Git

快速入门

1 Git概述

Git是一个分布式版本控制软件。

  • 软件:需要安装在电脑上使用的工具
  • 版本控制:开发过程中需要保存修改历史,方便更改历史记录等
  • 分布式:是版本控制的一种方式

后面两个概念不太好理解,我们分别来介绍。

2 版本控制

版本控制(Revision control)是一种在开发的过程中用于管理我们对文件、目录或工程等内容的修改历史,方便查看更改历史记录,备份以便恢复以前的版本的软件工程技术。简单说就是用于管理多人协同开发项目的技术。

没有进行版本控制或者版本控制本身缺乏正确的流程管理,在软件开发过程中将会引入很多问题,如软件代码的一致性、软件内容的冗余、软件过程的事物性、软件开发过程中的并发性、软件源代码的安全性,以及软件的整合等问题。

2.1 常见的版本控制器

主流的版本控制器有如下这些:

  • Git
  • SVN(Subversion)
  • CVS(Concurrent Versions System)
  • VSS(Micorosoft Visual SourceSafe)
  • TFS(Team Foundation Server)
  • Visual Studio Online

版本控制产品非常的多(Perforce、Rational ClearCase、RCS(GNU Revision Control System)、Serena Dimention、SVK、BitKeeper、Monotone、Bazaar、Mercurial、SourceGear Vault),现在影响力最大且使用最广泛的是Git与SVN

2.2 版本控制分类

1)本地版本控制

记录文件每次的更新,可以对每个版本做一个快照,或是记录补丁文件,适合个人用,如RCS。

2)集中版本控制

所有的版本数据都保存在服务器上,协同开发者从服务器上同步更新或上传自己的修改。

所有的版本数据都存在服务器上,用户的本地只有自己以前所同步的版本,如果不连网的话,用户就看不到历史版本,也无法切换版本验证问题,或在不同分支工作。而且,所有数据都保存在单一的服务器上,有很大的风险这个服务器会损坏,这样就会丢失所有的数据,当然可以定期备份。SVN就是这种版本控制。

3)分布式版本控制

所有版本信息仓库全部同步到本地的每个用户,这样就可以在本地查看所有版本历史,可以离线在本地提交,只需在连网时push到相应的服务器或其他用户那里。由于每个用户那里保存的都是所有的版本数据,只要有一个用户的设备没有问题就可以恢复所有的数据,但这增加了本地存储空间的占用。Git属于这种版本控制。

2.3 Git和SVN的区别

SVN是集中式版本控制系统,版本库是集中放在中央服务器的,而工作的时候,用的都是自己的电脑,所以首先要从中央服务器得到最新的版本,然后工作,完成工作后,需要把自己做完的活推送到中央服务器。集中式版本控制系统是必须联网才能工作,对网络带宽要求较高。

Git是分布式版本控制系统,没有中央服务器,每个人的电脑就是一个完整的版本库,工作的时候不需要联网,因为版本都在自己电脑上。协同的方法是这样的:比如说自己在电脑上改了文件A,其他人也在电脑上改了文件A,这时,你们两之间只需把各自的修改推送给对方,就可以互相看到对方的修改了。

3 Git的安装

官网下载:https://git-scm.com/

安装之后在开始菜单中会有Git菜单,有3个程序,推荐使用git bash

4 常用术语

1)仓库(Repository) 受版本控制的所有文件修订历史的共享数据库

2)工作空间(Workspace) 本地硬盘或Unix 用户帐户上编辑的文件副本

3)工作树/区(Working tree) 工作区中包含了仓库的工作文件。您可以修改的内容和提交更改作为新的提交到仓库。

4)暂存区(Staging area) 暂存区是工作区用来提交更改(commit)前可以暂存工作区的变化。

5)索引(Index) 索引是暂存区的另一种术语。

6)签入(Checkin) 将新版本复制回仓库

7)签出(Checkout) 从仓库中将文件的最新修订版本复制到工作空间

8)提交(Commit) 对各自文件的工作副本做了更改,并将这些更改提交到仓库

9)冲突(Conflict) 多人对同一文件的工作副本进行更改,并将这些更改提交到仓库

10)合并(Merge) 将某分支上的更改联接到此主干或同为主干的另一个分支

11)分支(Branch) 从主线上分离开的副本,默认分支叫master

12)锁(Lock) 获得修改文件的专有权限。

13)头(HEAD) 头是一个象征性的参考,最常用以指向当前选择的分支。

14)修订(Revision) 表示代码的一个版本状态。Git通过用SHA1 hash算法表示的ID来标识不同的版本。

15)标记(Tags) 标记指的是某个分支某个特定时间点的状态。通过标记,可以很方便的切换到标记时的状态。

5 Git工作原理

5.1 工作区域

Git本地有三个工作区域:工作目录(Working Directory)、暂存区(Stage/Index)、资源库(Repository或Git Directory)。如果在加上远程的git仓库(Remote Directory)就可以分为四个工作区域。文件在这四个区域之间的转换关系如下:

  • Workspace:工作区,就是你平时存放项目代码的地方
  • Index / Stage:暂存区,用于临时存放你的改动,事实上它只是一个文件,保存即将提交到文件列表信息
  • Repository:仓库区(或本地仓库),就是安全存放数据的位置,这里面有你提交到所有版本的数据。其中HEAD指向最新放入仓库的版本
  • Remote:远程仓库,托管代码的服务器,可以简单的认为是你项目组中的一台电脑用于远程数据交换

本地的三个区域确切的说应该是git仓库中HEAD指向的版本

  • Directory:使用Git管理的一个目录,也就是一个仓库,包含我们的工作空间和Git的管理空间。
  • WorkSpace:需要通过Git进行版本控制的目录和文件,这些目录和文件组成了工作空间。
  • .git:存放Git管理信息的目录,初始化仓库的时候自动创建。
  • Index/Stage:暂存区,或者叫待提交更新区,在提交进入repo之前,我们可以把所有的更新放在暂存区。
  • Local Repo:本地仓库,一个存放在本地的版本库;HEAD会只是当前的开发分支(branch)。
  • Stash:隐藏,是一个工作状态保存栈,用于保存/恢复WorkSpace中的临时状态。

5.2 工作流程

git的工作流程一般是这样的:

1、在工作目录中添加、修改文件;

2、将需要进行版本管理的文件放入暂存区域;

3、将暂存区域的文件提交到git仓库。

因此,git管理的文件有三种状态:已修改(modified),已暂存(staged),已提交(committed)

Git使用

1 基础配置

获取 git 仓库

要使用git进行版本控制需要获取git仓库。通常有两种获取 git 项目仓库的方式:

  1. 将尚未进行版本控制的本地目录转换为 Git 仓库
  2. 从其它服务器 克隆 一个已存在的 Git 仓库

首先是1,我们需要创建一个git仓库:

==初始化命令==

1
git init [文件夹名]

如果没有文件夹名,git会将当前目录下的所有文件进行管理。

我们在桌面创建test文件夹,使用git bash输入命令对文件夹进行管理。

在这个文件夹下会生成一个.git的隐藏文件夹。这个文件夹含有你初始化的git仓库中所有的必须文件,这些文件是 Git 仓库的骨干。

查看当前文件状态

现在我们的机器上有了一个git仓库,你可以对这些文件做些修改,每当想要保存它时,就将它提交到仓库。 git仓库可以对目录下的所有文件进行管理,这里我们要了解一下文件的状态

==检查当前文件状态== 使用命令查看哪些文件处于什么状态

1
git status

我们在刚刚创建的文件夹下,新建一个txt文件,再次执行查看状态命令

未跟踪的文件意味着git在之前的快照(提交)中没有这些文件;git不会自动将之纳入跟踪范围,除非你明明白白地告诉它“我需要跟踪该文件”。这样的处理让你不必担心将生成的二进制文件或其它不想被跟踪的文件包含进来。不过现在的例子中,我们确实想要跟踪管理这个文件。

设置用户信息

在使用git之前,还需要做的一件事就是设置你的用户名和邮件地址。这一点很重要,因为每一个 Git 提交都会使用这些信息,它们会写入到你的每一次提交中。

==设置用户名和邮箱==

1
2
git config --global user.name "hiltay"
git config --global user.email "904108079@qq.com"

2 文件操作

添加文件进暂存区

接下来,我们将要对未跟踪的文件进行管理。 ==跟踪新文件==

1
2
git add [文件名]
git add .

我们可以指定文件;也可以管理所有,.表示将所有文件添加到暂存区。

提交暂存区文件

现在的暂存区已经准备就绪,可以提交了。在此之前,请务必确认还有什么已修改或新建的文件还没有被添加进暂存区,否则提交的时候不会记录这些尚未暂存的变化。 ==提交暂存区文件==

1
git commit [-m "注释信息"]

在每次提交时,填写注释信息,来记录本次提交修改了什么、新增了什么,方便以后回忆起这次更新的内容。

假如我们此时修改一下abc.txt,并且新增一个d.txt,查看文件状态

我们将他们一并添加到暂存区并提交。

查看提交历史

在提交了若干更新,又或者克隆了某个项目之后,你也许想回顾下提交历史。

1
git log

我们可以看到刚刚的两次提交,以及提交时间、作者信息、注释、版本号。 git log还有更多参数,详见这里

撤销本地仓库更新

有时候需要撤销提交,也就是回滚。撤销提交有两种方式:使用HEAD指针和使用版本号commit id

1
git reset --hard 版本号或HEAD指针

在Git中,有一个HEAD指针指向当前分支中最新的提交。

1
前一个版本,我们使用"HEAD^",那么再前一个版本可以使用"HEAD^^",如果想回退到更早的提交,可以使用"HEAD~n"。(也就是,HEAD^=HEAD~1,

使用HEAD 如果又想恢复被撤销的提交,可用命令

1
git reflog

查看仓库中所有的分支的所有更新记录,包括撤销记录。撤销方法与前面一样。

删除文件

如果文件还是未跟踪状态,直接删除文件就可以了,bash中使用rm可以删除文件,示例如下。

如果已经add了,也可以删除

1
git rm -f 文件名

-f 强制删除,物理删除,同时删除工作区和暂存区中的文件

忽略文件

一般我们总会有些文件无需纳入git的管理,也不希望它们总出现在未跟踪文件列表。通常都是些自动生成的文件,比如日志文件,或者编译过程中创建的临时文件等。在这种情况下,我们可以创建一个名为.gitignore的文件,列出要忽略的文件的模式。 文件的格式规范如下:

  • 所有空行或者以 # 开头的行都会被 Git 忽略
  • 可以使用标准的 glob 模式匹配,它会递归地应用在整个工作区中
  • 匹配模式可以以(/)开头防止递归
  • 匹配模式可以以(/)结尾指定目录
  • 要忽略指定模式以外的文件或目录,可以在模式前加上叹号(!)取反
1
2
3
4
5
6
7
所谓的 glob 模式是指 shell 所使用的简化了的正则表达式。

星号(*)匹配零个或多个任意字符;
[abc] 匹配任何一个列在方括号中的字符 (这个例子要么匹配一个 a,要么匹配一个 b,要么匹配一个 c);
问号(?)只匹配一个任意字符;
如果在方括号中使用短划线分隔两个字符, 表示所有在这两个字符范围内的都可以匹配(比如 [0-9] 表示匹配所有 0 到 9 的数字)。
使用两个星号(**)表示匹配任意中间目录,比如 a/**/z 可以匹配 a/z 、 a/b/z 或 a/b/c/z 等。

我们看一个 .gitignore 文件的例子:

1
2
3
4
5
6
7
8
9
10
11
12
# 忽略所有的 .a 文件
*.a
# 但跟踪所有的 lib.a,即便你在前面忽略了 .a 文件
!lib.a
# 只忽略当前目录下的 TODO 文件,而不忽略 subdir/TODO
/TODO
# 忽略任何目录下名为 build 的文件夹
build/
# 忽略 doc/notes.txt,但不忽略 doc/server/arch.txt
doc/*.txt
# 忽略 doc/ 目录及其所有子目录下的 .pdf 文件
doc/**/*.pdf

GitHub上有一个十分详细的针对数十种项目及语言的 .gitignore 文件模版,点击这里查看

比如你使用java,就找到Java.gitignore文件,将它添加到你的项目中去,之后再使用查看状态命令git status看看还有哪些文件需要被忽略。

有关gitignore详细,这篇博客了解更多

3 分支开发

几乎所有的版本控制系统都以某种形式支持分支。 有人把 Git 的分支模型称为它的“必杀技特性”,也正因为这一特性,使得 Git 从众多版本控制系统中脱颖而出。 为何 Git 的分支模型如此出众呢? Git 处理分支的方式可谓是难以置信的轻量,创建新分支这一操作几乎能在瞬间完成,并且在不同分支之间的切换操作也是一样便捷。

分支在实际中有什么用呢?假设你准备开发一个新功能,但是需要两周才能完成,第一周你写了50%的代码,如果立刻提交,由于代码还没写完,不完整的代码库会导致别人不能干活了。如果等代码全部写完再一次提交,又存在丢失每天进度的巨大风险。

现在有了分支,就不用怕了。你创建了一个属于你自己的分支,别人看不到,还继续在原来的分支上正常工作,而你在自己的分支上干活,想提交就提交,直到开发完毕后,再一次性合并到原来的分支上,这样,既安全,又不影响别人工作。

为了更好理解分支,建议先看看官方文档的介绍。点我查看

git分支操作的关键字是branch

常用的分支命令

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
# 列出所有本地分支
git branch

# 列出所有远程分支
git branch -r

# 列出所有本地分支和远程分支
git branch -a

# 新建一个分支,但依然停留在当前分支
git branch [branch-name]

# 新建一个分支,并切换到该分支
git checkout -b [branch]

# 新建一个分支,指向指定commit
git branch [branch] [commit]

# 新建一个分支,与指定的远程分支建立追踪关系
git branch --track [branch] [remote-branch]

# 切换到指定分支,并更新工作区
git checkout [branch-name]

# 切换到上一个分支
git checkout -

# 建立追踪关系,在现有分支与指定的远程分支之间
git branch --set-upstream [branch] [remote-branch]

# 合并指定分支到当前分支
git merge [branch]

# 选择一个commit,合并进当前分支
git cherry-pick [commit]

# 删除分支
git branch -d [branch-name]

# 删除远程分支
git push origin --delete [branch-name]
git branch -dr [remote/branch]

举例来说明上述命令的用法

创建和切换分支

我们新建一个dev分支用于开发,把master分支作为主分支,开发阶段的所有改动都在dev进行。

假设我们开发了新的功能 这里我们将它提交到了dev分支下,此时我们再切换回master分支下看看 在使用git checkout master时,这条命令做了两件事。一是使HEAD指回master分支,二是将工作目录恢复成master分支所指向的快照内容。也就是说,你现在做修改的话,项目将始于一个较旧的版本。本质上来讲,这就是忽略dev分支所做的修改,以便于向另一个方向进行开发。

这里的动画更直观地理解分支: 1.直线开发 2.切换分支

合并分支

假设你正在dev分支开发新功能,你先前的项目出了一些差错需要热修。此时并不需要把手头的开发回滚,也不需要把这个问题与手头的开发一起解决,只需要切换回master分支。 这里我们新创建hotfix分支,在这里修复bug。 假设你修复好了这个错误,确保你的修改是正确的,hotfix分支的使命就完成了。现在你可以将hotfix与master合并。 关于合并要注意,当前我们处在哪个分支,就会合并到哪个分支。 比如我们处在master分支下,对hotfix分支进行合并,这些内容会记录在master下。

冲突解决

我们轻松完成了bug修复,现在可以回到dev分支下继续开发了。

假设此时我们完成了dev分支的开发,此时可以与主分支合并。如果成功,就会在主分支创建新的提交历史。

但有时候合并操作不会如此顺利。如果你在两个不同的分支中,对同一个文件的同一个部分进行了不同的修改,就没法干净的合并它们。 我们刚才在hotfix分支中,修改了abc文件的内容,在dev分支中,同样也修改了abc文件同样部分的内容,此时合并就不是那么轻松了。 下图演示了此时合并的情况: Git会暂停下来,等待你去解决合并产生的冲突。 你可以在合并冲突后的任意时刻使用git status命令来查看那些因包含合并冲突而处于未合并(unmerged)状态的文件 我们此时需要打开冲突文件,手动对发生冲突的地方进行修改。 我们对冲突部分进行修改,然后再次提交,然后合并

删除分支

我们刚刚已经合并了两次,其实dev分支和hotfix分支早就完成使命,我们需要将它们删除掉。

4 远程开发

到目前为止,你应该已经有办法使用 Git 来完成日常工作。 然而,为了使用 Git 协作功能,你还需要有远程的 Git 仓库。 尽管在技术上你可以从个人仓库进行推送(push)和拉取(pull)来修改内容,但不鼓励使用这种方法,因为一不留心就很容易弄混其他人的进度。 此外,你希望你的合作者们即使在你的电脑未联机时亦能存取仓库 — 拥有一个更可靠的公用仓库十分有用。 因此,与他人合作的最佳方法即是建立一个你与合作者们都有权利访问,且可从那里推送和拉取资料的共用仓库。

为了能在任意 Git 项目上协作,你需要知道如何管理自己的远程仓库。 远程仓库是指托管在因特网或其他网络中的你的项目的版本库。 你可以有好几个远程仓库,通常有些仓库对你只读,有些则可以读写。 与他人协作涉及管理远程仓库以及根据需要推送或拉取数据。 管理远程仓库包括了解如何添加远程仓库、移除无效的远程仓库、管理不同的远程分支并定义它们是否被跟踪等等。

查看远程仓库

1
git remote

如果想查看你已经配置的远程仓库服务器,可以运行该命令。 它会列出你指定的每一个远程服务器的简写。 如果你已经克隆了自己的仓库,那么至少应该能看到 origin ——这是 Git 给你克隆的仓库服务器的默认名字。

你也可以指定选项 -v,会显示需要读写远程仓库使用的 Git 保存的简写与其对应的 URL。

添加远程仓库

1
git clone <url>

如果你想获得一份已经存在了的 Git 仓库的拷贝,比如说,你想为某个开源项目贡献自己的一份力,这时就要用到该命令。

url为远程仓库的url,这会在当前目录下创建一个目录,并在这个目录下初始化一个 .git 文件夹, 从远程仓库拉取下所有数据放入 .git 文件夹,然后从中读取最新版本的文件的拷贝。

这种方式从已经存在的仓库获得一份拷贝。还有另一种方式,我们自己来添加它。

1
git remote add <shortname> <url> 

使用该命令添加一个新的远程 Git 仓库,同时指定一个方便使用的简写。

从远程仓库中抓取与拉取

从远程仓库中获得数据,可以执行:

1
git fetch <remote>

这个命令会访问远程仓库,从中拉取所有你还没有的数据。 执行完成后,你将会拥有那个远程仓库中所有分支的引用,可以随时合并或查看。必须注意 git fetch 命令只会将数据下载到你的本地仓库——它并不会自动合并或修改你当前的工作。 当准备好时你必须手动将其合并入你的工作。

如果想要直接并入你的工作,可以使用

1
git pull [remote] [branch]

git pull 命令基本上就是 git fetchgit merge 命令的组合体,Git 从你指定的远程仓库中抓取内容,然后马上尝试将其合并进你所在的分支中。

推送到远程仓库

当你想分享你的项目时,必须将其推送到上游。 这个命令很简单

1
git push <remote> <branch>

你想要将 master 分支推送到 origin 服务器时(再次说明,克隆时通常会自动帮你设置好那两个名字),那么运行这个命令就可以将你所做的备份到服务器:

1
git push origin master

远程仓库的重命名与移除

你可以运行 git remote rename 来修改一个远程仓库的简写名。 例如,想要将 pb 重命名为 paul,可以用 git remote rename 这样做

1
git remote rename pb paul

如果因为一些原因想要移除一个远程仓库。可以使用 git remote removegit remote rm

1
git remote remove paul

一旦你使用这种方式删除了一个远程仓库,那么所有和这个远程仓库相关的远程跟踪分支以及配置信息也会一起被删除。

常用远程操作命令

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
# 下载远程仓库的所有变动
git fetch [remote]

# 显示所有远程仓库
git remote -v

# 显示某个远程仓库的信息
git remote show [remote]

# 增加一个新的远程仓库,并命名
git remote add [shortname] [url]

# 取回远程仓库的变化,并与本地分支合并
git pull [remote] [branch]

# 上传本地指定分支到远程仓库
git push [remote] [branch]

# 强行推送当前分支到远程仓库,即使有冲突
git push [remote] --force

# 推送所有分支到远程仓库
git push [remote] --all

#简单查看远程---所有仓库
git remote (只能查看远程仓库的名字)#查看单个仓库
git remote show [remote-branch-name]

#新建远程仓库
git remote add [branchname] [url]

#修改远程仓库
git remote rename [oldname] [newname]

#删除远程仓库
git remote rm [remote-name]

#获取远程仓库数据
git fetch [remote-name] (获取仓库所有更新,但不自动合并当前分支)
git pull (获取仓库所有更新,并自动合并到当前分支)

#上传数据,如git push origin master
git push [remote-name] [branch]

GitHub

GitHub 是最大的 Git 版本库托管商,是成千上万的开发者和项目能够合作进行的中心。 大部分 Git 版本库都托管在 GitHub,很多开源项目使用 GitHub 实现 Git 托管、问题追踪、代码审查以及其它事情。 所以,尽管这不是 Git 开源项目的直接部分,但如果想要专业地使用 Git,你将不可避免地与 GitHub 打交道,所以这依然是一个绝好的学习机会。

我们这里以github为例,讲解远程开发。首先是注册登录不再赘述,然后新建仓库。

1 推送代码

进入到我们的仓库,首页会提示你如何操作

1
2
3
4
5
6
7
8
9
10
11
12
# 如果你没有仓库,需要新建一个
echo "# gittest" >> README.md
git init
git add README.md
git commit -m "first commit"
git branch -M main
git remote add origin https://github.com/hiltay/gittest.git
git push -u origin main
# 如果你已经拥有本地仓库,只需要上面的后三行代码即可
git remote add origin https://github.com/hiltay/gittest.git
git branch -M main
git push -u origin main

以后你在本地的开发完成后,先提交到本地,然后push到远程仓库即可。

==注意,协同开发时,每次push代码之前,一定要先pull代码。==

2 获取代码

如果我们不是项目的创建者,想要给某个项目贡献代码;或者是你自己的项目在公司开发,回到家后想用个人电脑继续开发,都需要从远程仓库下拉(PULL)代码到本地。

初次拉取代码,使用克隆。比如

1
git clone https://github.com/hiltay/gittest.git

后续我们使用pull

1
git pull origin master

3 SSH

这里简单介绍非对称加密,非对称加密需要两个密钥:公钥 (publickey) 和私钥 (privatekey)。公钥和私钥是一对,如果用公钥对数据加密,那么只能用对应的私钥解密。如果用私钥对数据加密,只能用对应的公钥进行解密。因为加密和解密用的是不同的密钥,所以称为非对称加密。非对称加密算法的保密性好,它消除了最终用户交换密钥的需要。但是加解密速度要远远慢于对称加密,在某些极端情况下,甚至能比对称加密慢上1000倍。

了解这些之后,我们介绍一下SSH。简单说,SSH是一种网络协议,用于计算机之间的加密登录。

我们这里介绍如何使用SSH与github连接。

首先打开一个git bash

1
ssh-keygen -t ed25519 -C "your_email@example.com"

这将创建一个新的 SSH 密钥,使用提供的电子邮件作为标签。创建好SSH之后,一般会在家目录下生成.ssh文件夹,命令行会有提示。

.ssh文件夹目前包含两个文件,一个公钥一个私钥。

创建好后,我们复制公钥到剪贴板。我们可以使用文本编辑器打开这个文件,然后复制;也可以使用命令。

1
clip < ~/.ssh/id_ed25519.pub

这里的id_ed25519.pub如果与你的公钥不同,自行修改即可。

在GitHub页面的右上角,进入settings设置页面。

在侧边栏中,单击SSH and GPG keys。然后在右上方单击New SSH Key 在“Title”字段中,为新键添加描述性标签。例如,如果你使用的是个人Mac,你可以将此键称为“我的MacBook Air”。 在“Key“字段中,将刚刚复制的公钥粘贴到这里。 单击添加按钮即可。

有关更多GitHub添加SSH的内容,单击这里查看

添加完成后,接下来我们使用SSH连接github仓库。

1
git clone git@github.com:hiltay/gittest.git

第一次执行时,会询问是否同意连接,这里选yes即可

1
2
3
4
The authenticity of host 'github.com (20.205.243.166)' can't be established.
RSA key fingerprint is SHA256:nThbg6kXUpJWGl7E1IGOCspRomTxdCARLviKw6E5SY8.
This key is not known by any other names
Are you sure you want to continue connecting (yes/no/[fingerprint])?

这样就顺利地clone下来了。并且,在.ssh文件夹下,会生成一个known_hosts的文件,SSH会把每个与你连接的其他人的公钥都记录在~/.ssh/known_hosts。当第二次进行连接时,SSH会核对公钥。如果公钥不同,SSH会发出警告, 避免你受到一些网络攻击。

后续的操作与https连接一模一样。

Git配置

首先,这里是Git-config的官方文档

1 配置文件位置

全局配置文件

全局配置文件通常在C:\Users\Administrator\.gitconfig,Administrator不同电脑有所区别,例:C:\Users\hiltay.gitconfig,这是我本机配置文件所在的位置。

用文本编辑器打开,可以发现里面有user.name和user.email的配置信息。

局部配置文件

在本地的每个git仓库里,都有一个.git文件夹,进入这个文件夹可以看到有config文件,这个是局部配置文件的位置。

2 git使用代理

代理分为http代理和ssh代理,这两者的区别,举个简单的例子就是当你clone项目的时候,选择http还是ssh方式。

2.1 设置http代理

socks代理

为http和https设置,通过命令

1
2
git config --global http.proxy 'socks5://127.0.0.1:10808'
git config --global https.proxy 'socks5://127.0.0.1:10808'

也可以直接修改.gitconfig文件(实际上上面的命令就是修改该文件),在文件中添加如下两项,使用全局还是局部看需求。

1
2
3
4
[http]
proxy = socks5://127.0.0.1:10808
[https]
proxy = socks5://127.0.0.1:10808
http/https代理
1
2
git config --global http.proxy http://127.0.0.1:8080
git config --global https.proxy https://127.0.0.1:8080

也可以修改文件,同上。这里建议优先使用socks代理,因为它位于OSI协议中的会话层,而http位于应用层,前者更底层。

只为github配置代理

前面的配置会给所有的git配置代理,有时候我们希望只为github配置代理:

1
git config --global http.https://github.com.proxy socks5://127.0.0.1:7890

取消代理

1
2
git config --global --unset http.proxy
git config --global --unset https.proxy

修改后最好重启所有 git bash 保证设置生效。

查看配置文件信息

1
git config -l --global

2.2 使用ssh代理

在linux或mac系统下,ssh配置文件位于:~/.ssh/config,如果没有可以自己在这个位置创建一个。下面是我在macos上的配置。

打开该文件新增一个条目:

1
2
3
4
Host github.com
AddKeysToAgent yes
IdentityFile /xxx/.ssh/github_id_rsa
ProxyCommand nc -v -x 127.0.0.1:7890 %h %p

使用命令测试连接:

1
ssh -T -v git@github.com 

这种代理配置走22端口,如果代理节点对22端口做限制,或者节点本身不稳定,都可能会出现下面的错误:

1
kex_exchange_identification: Connection closed by remote host

也可以修改配置如下,使用443端口,具体可以参考官方文档

1
2
3
4
5
6
7
Host github.com
AddKeysToAgent yes
Hostname ssh.github.com
IdentityFile /xxx/.ssh/github_id_rsa
User git
Port 443
ProxyCommand nc -v -x 127.0.0.1:7890 %h %p

常见问题

常见问题,会在这里持续补充。。

1 多个帐号使用SSH不产生冲突

多个github帐号如何使用SSH不产生冲突

2 如何关闭git pull产生的merge信息

局部生效:编辑~/.gitconfig文件,添加一条:

1
2
[core]
mergeoptions = --no-edit

全局生效:

1
git config --global core.mergeoptions --no-edit

3 将一个Git远程仓库同步到另一个远程仓库

首先,clone一个remote:

1
git clone https://xxxxxx.git

clone之后,本地默认是master分支,也仅有master。 代码的完整信息,其实已经下载下来了,不过都在.git/refs/remotes/origin/,不在.git/refs/heads/下。

新增另一个远程仓库,这里以gitee为例:

1
git remote add gitee git@gitee.com:xxx/xxx.git

如果直接进行git push gitee,只是push master,达不到同步其它分支的目的。

从一个remote推送到另一个,可以使用如下命令:

1
git push gitee refs/remotes/origin/*:refs/heads/* --tags

这里的gitee换成实际的远程仓库即可。

通过*,对所有branch、tag都进行了push。

4 同步所有远程分支到本地

1
git branch -r | grep -v '\->' | while read remote; do git branch --track "${remote#origin/}" "$remote"; done