Git教程
推荐链接:
常用命令速查表
实战
彻底清除所有历史提交记录
1 | 创建新分支 |
确定清除历史记录的结果
1 | 1、查看提交日志 |
最后,登录远程仓库再次确认。
版本控制系统(VCS)
本地版本控制系统
最流行的一种叫做 RCS,现今许多计算机系统上都还看得到它的踪影。
RCS 工作原理:在硬盘上保存补丁集(补丁是指文件修订前后的变化);通过应用所有的补丁,可以重新计算出各个版本的文件内容。
缺点:
无法让不同系统上的开发者协同工作。
整个项目的变更历史被保存在单一位置,有丢失所有历史更新记录的风险。例如:磁盘损坏。
集中化的版本控制系统
Centralized Version Control Systems,简称 CVCS。
这类系统,诸如 CVS、Subversion(SVN) 、 Perforce 等,都有一个单一的集中管理的服务器保存所有文件的修订版本,而协同工作的人们都通过客户端连到这台服务器,取出最新的文件或者提交更新。多年以来,这已成为版本控制系统的标准做法。
优点:
个人都可以在一定程度上看到项目中的其他人正在做些什么。
管理员可以轻松掌控每个开发者的权限。
管理员只需管理这个集中服务器,而不需要在各个客户端上维护本地数据库。
缺点:
如果中央服务器出现单点故障,那么谁都无法提交更新,也就无法协同工作。
整个项目的变更历史被保存在单一位置,有丢失所有历史更新记录的风险。如果中心数据库所在的磁盘发生损坏,又没有做恰当备份,毫无疑问将丢失所有数据,只剩下各自机器上保留的单独快照。
分布式版本控制系统
Distributed Version Control System,简称 DVCS
这类系统,像 Git、Mercurial、Bazaar、Darcs 等,客户端并不只提取最新版本的文件快照,而是把代码仓库完整地镜像下来。
优点:
任何一处协同工作用的服务器发生故障,都可以用任何一个镜像出来的本地仓库恢复。 因为每一次的克隆操作,实际上都是一次对代码仓库的完整备份。
可以指定和若干不同的远端代码仓库进行交互,也就是说,可以在同一个项目中,分别和不同工作小组的人相互协作
可以根据需要设定不同的协作流程,比如层次模型式的工作流
Git 基础概念
Git 初期设定的目标
- 速度很快
- 设计简单
- 对非线性开发模式的强力支持(允许成千上万个并行开发的分支)
- 完全分布式
- 有能力高效管理类似 Linux 内核一样的超大规模项目(速度和数据量)
3+n个区域
三个本地区域 + n个远程区域:
Workspace:工作区
Index/Stage:暂存区、索引(文件内容的哈希值)
Repository:仓库区、本地仓库、存储库、Git仓库
Remote:远程仓库
名词解释:
工作区 : 对项目的某个版本独立提取出来的内容。这些从 Git 仓库的压缩数据库中提取出来的文件,放在磁盘上供你使用或修改。通过 git init
创建的代码库的所有文件但是不包括 .git
文件(版本库=暂存区+Git仓库)。
暂存区 : 一个文件,保存了下次将提交的文件列表信息,一般在 .git
目录,。通过 git add ./*/*Xxx/Xxxx*
添加的修改,都是进入到暂存区了,肉眼不可见 通过 git status
可以看到修改的状态。
Git仓库 : Git 用来保存项目的元数据和对象数据库的地方。从其它计算机克隆仓库时,拷贝的就是这里的数据。
3 种状态
文件的三种状态:
- 已修改(modified):做了修改但还没有放到暂存区域
- 已暂存(staged):做了修改并已放入暂存区域
- 已提交(committed):Git 仓库中保存着的特定版本文件
什么是修改:新增一行、删除一行、更改某些字符、删一些又加一些、创建一个新文件。
基本的 Git 工作流程:
- 在工作区添加或修改文件(已修改)
- 暂存文件,将文件的快照放入暂存区域(已暂存)
- 提交更新,找到暂存区域的文件,将快照永久性存储到 Git 仓库(已提交)
直接记录快照,而非差异比较
Git 和其它版本控制系统(包括 Subversion 和近似工具)的主要差别在于 Git 对待数据的方法。 概念上来区分,其它大部分系统以文件变更列表的方式存储信息。 这类系统(CVS、Subversion、Perforce、Bazaar 等等)将它们保存的信息看作是一组基本文件和每个文件随时间逐步累积的差异。存储每个文件与初始版本的差异,如下图所示:
Git 不按照以上方式对待或保存数据。 反之,Git 更像是把数据看作是对小型文件系统的一组快照。 每次你提交更新,或在 Git 中保存项目状态时,它主要对当时的全部文件制作一个快照并保存这个快照的索引。 为了高效,如果文件没有修改,Git 不再重新存储该文件,而是只保留一个链接指向之前存储的文件。 Git 对待数据更像是一个 快照流。如下图所示:
这是 Git 与几乎所有其它版本控制系统的重要区别。
Git 更像是一个小型的文件系统,提供了许多以此为基础构建的超强工具,而不只是一个简单的 VCS。
近乎所有操作都是本地执行
在 Git 中的绝大多数操作都只需要访问本地文件和资源,这意味着在离线或者没有 VPN 时,几乎可以进行任何操作。因为本地磁盘上就有项目的完整历史,所以大部分操作看起来瞬间完成。
Git 保证完整性
Git 中所有数据在存储前都计算校验和,然后以校验和来引用。 这意味着不可能在 Git 不知情时更改任何文件内容或目录内容。 这个功能建构在 Git 底层,是构成 Git 哲学不可或缺的部分。 若你在传送过程中丢失信息或损坏文件,Git 就能发现。
Git 用以计算校验和的机制叫做 SHA-1 散列(hash,哈希)。 这是一个由 40 个十六进制字符 (0-9 和 a-f) 组成字符串,基于 Git 中文件的内容或目录结构计算出来。 SHA-1 哈希看起来是这样:
1 | 80e7c5b72de33d7faee6dcf43a0aaca1e236d638 |
Git 中使用这种哈希值的情况很多,你将经常看到这种哈希值。 实际上,Git 数据库中保存的信息都是以文件内容的哈希值来索引,而不是文件名。
Git 一般只添加数据
你执行的 Git 操作,几乎只往 Git 数据库中增加数据。 很难让 Git 执行任何不可逆操作(不可恢复操作),或者让它以任何方式清除数据。同别的 VCS 一样,未提交更新时有可能丢失或弄乱修改的内容;但是一旦提交快照到 Git 中,就难以再丢失数据,特别是如果你定期的推送数据库到其它仓库的话。
更深度探讨 Git 如何保存数据及恢复丢失数据的话题,请参考 Git 修正错误 git reset 命令 。
Git 工作流
上面的官方链接介绍了常用的工作流程,但在实际的开发中,你会遇到许多可能适合你的特定工作流程的变种。
官网也给出了一些如何扮演不同工作流程中主要角色的更具体的例子,请参考 Git Book 。
Git 安装配置
Git 更新
1 | git update-git-for-windows |
Git 设置和取消http代理
为HTTP(应用层)协议配置SOCKS(会话层)代理:
1 | 查看当前代理设置, |
本地保存帐号密码
git bash 进入项目目录,输入:
git config --global credential.helper store
然后会在本地生成一个文本,上边记录着账号和密码。当然这些可以不用关心。
使用上述的命令配置好之后,再操作一次 git pull
,它会提示输入账号密码,之后就不会提示了。
Git 基本操作
git config
官方: https://git-scm.com/docs/git-config
git config
命令用于获取并设置存储库或全局选项。这些变量可以控制Git的外观和操作的各个方面。
配置文件的存储位置
这些变量可以被存储在三个不同的位置:
/etc/gitconfig
文件:包含了适用于操作系统所有用户和所有库的值。如果传递参数选项--system
给git config
,它将明确的读和写这个文件。Windows环境中,该文件在Git安装目录下,例如 D:\Program Files\Git\mingw64\etc。
~/.gitconfig
文件 :具体到当前用户(例如 Administrator)。可以通过传递--global
选项使 Git 读或写这个特定的文件。Windows环境中,该文件在系统当前用户目录下,例如 C:\Users\Administrator。
位于
.git
目录的config文件 (也就是.git/config
) :无论当前在用的库是什么,特定指向该单一的库。每个级别重写前一个级别的值。因此,在.git/config
中的值覆盖了在/etc/gitconfig
中的同一个值。Windows环境中,该文件在库目录下,例如 D:\git\git-test\.git。
优先级:.git/config
> ~/.gitconfig
> /etc/gitconfig
配置用户名和邮箱
当安装Git后首先要做的事情是设置用户名和e-mail地址。这是非常重要的,因为每次Git提交都会使用该信息。它被永远的嵌入到了你的提交中:
1 | git config --global user.name 'JonSnows' |
重申一遍,只需要做一次这个设置。如果传递了 --global
选项,那么Git将总是会使用该信息来处理在系统中所做的一切操作。如果希望在一个特定的项目中使用不同的名称或 e-mail
地址,可以在该项目中运行该命令而不要 --global
选项。
1 | $ git config user.name 'JonSnows' |
配置编缉器
可以配置默认的文本编辑器,Git在需要你输入一些消息时会使用该文本编辑器。缺省情况下,Git使用系统的缺省编辑器,这通常可能是 vi
或者 vim
。如果想使用一个不同的文本编辑器,例如:Emacs
,可以按照如下操作:
1 | $ git config --global core.editor emacs |
配置比较工具
另外一个你可能需要配置的有用的选项是缺省的比较工具,它用来解决合并时的冲突。例如,想使用 vimdiff
作为比较工具:
1 | $ git config --global merge.tool vimdiff |
Git可以接受 kdiff3, tkdiff, meld, xxdiff, emerge, vimdiff, gvimdiff, ecmerge, 和 opendiff 作为有效的合并工具。也可以设置一个客户端的工具;
检查配置
如果想检查你的设置,可以使用 git config --list
命令来列出Git可以在该处找到的所有的设置:
1 | git config --local --list # 局部配置,优先级最高 |
可能会看到一个关键字出现多次(如这里的:user.name
就有两个值),这是因为Git从不同的文件中(例如:/etc/gitconfig
以及~/.gitconfig
)读取相同的关键字。在这种情况下,对每个唯一的关键字,Git使用最后的那个值。
也可以查看Git认为的一个特定的关键字目前的值,使用如下命令 git config {key}
:
1 | git config user.name |
添加/删除配置项
添加配置项
参数
-–add
格式: git config [–local|–global|–system] –-add section.key value
(默认是添加在 local
配置中)
注意add后面的 section
, key
, value
一项都不能少,否则添加失败。比如执行:
1 | git config --add site.name www.JonSnows.com |
删除配置项
命令参数
-–unset
格式:git config [–local|–global|–system] –unset section.key
1 | 删除 local 配置中的 site.name 配置值 |
git help
如果在使用Git时需要帮助,有三种方法可以获得任何 git 命令的手册页(manpage)帮助信息:
1 | $ git help <verb> |
示例
1 | git help help |
git init
Git 使用 git init 命令来初始化一个 Git 仓库,Git 的很多命令都需要在 Git 的仓库中运行,所以 git init 是使用 Git 的第一个命令。
在执行完成 git init 命令后,Git 仓库会生成一个 .git 目录,该目录包含了资源的所有元数据,其他的项目目录保持不变(不像 SVN 会在每个子目录生成 .svn 目录,Git 只在仓库的根目录生成 .git 目录)。
用 git init
在目录中创建新的 Git 仓库,可以在任何时候、任何目录中这么做,完全是本地化的。
比如创建 runoob 项目:
1 | git init runoob #使用指定目录作为Git仓库 |
git clone
使用 git clone
拷贝一个 Git 仓库到本地,让自己能够查看该项目,或者进行修改,此操作将复制该项目的全部记录。
1 | git clone [url] |
默认情况下,Git 会按照 URL 所指示的项目名称创建本地项目目录。 通常就是 URL 最后一个 / 之后的项目名称,即 RepositoryName 。如果想要一个不一样的名字, 可以在该命令后加上想要的名称。
1 | git clone https://github.com/username/RepositoryName.git folderName/CustomName # 指定目录 |
可以使用不同的协议,包括 ssh, git, https 等。
1 | git clone git@github.com:username/RepositoryName.git CustomName # SSH协议 速度较快,可以配置公钥免输入密码 |
git add
将文件添加到缓存区(暂存区),缓存区中的文件都是未提交的
1 | git add [file1] [file2] # 添加一个或多个文件到暂存区 |
git status
查看项目的当前状态,简单讲,查看上次提交之后是否有修改,修改是否被缓存(被暂存)。
1 | git status #详细结果输出 |
新增文件 new.txt
,并填写内容,再执行 git status
和 git status -s
,如下图,表示该文件是新增文件,未添加到缓存,未提交到版本库。
执行 git add
命令添加文件到缓存区,再执行 git status
和 git status -s
,如下图,表示该文件是新增文件,无修改未添加到缓存,有修改未提交到版本库。
修改文件内容后,再执行 git status
和 git status -s
,如下图,表示该文件是新增文件,有修改未添加到缓存,有修改未提交到版本库。
修改版本库中的文件内容,如下图,表示该文件非新增文件,有修改未添加到缓存,有修改未提交到版本库。
修改版本库中的文件内容,并添加到缓存,如下图,表示该文件非新增文件,无修改未添加到缓存,有修改未提交到版本库。
总结:
控制台有颜色:
红色表示:有修改未添加到缓存,有修改未提交到版本库。
绿色表示:无修改未添加到缓存,有修改未提交到版本库。
控制台无颜色:_
表示空格,除了 ??
,第一位非空即绿,第二位非空即红。
??
表示:该文件是新增文件,未添加到缓存,未提交到版本库。
A_
表示:该文件是新增文件,无修改未添加到缓存,有修改未提交到版本库。
AM
表示:该文件是新增文件,有修改未添加到缓存,有修改未提交到版本库。
_M
表示:该文件非新增文件,有修改未添加到缓存,有修改未提交到版本库。
M_
表示:该文件非新增文件,无修改未添加到缓存,有修改未提交到版本库。
git diff
预览差异。执行 git diff
来查看执行 git status
的结果的详细信息。
git status
显示上次提交更新后的更改或者写入缓存的改动, 而 git diff
一行一行地显示这些改动具体是啥。
应用场景1
- 尚未缓存的改动:
git diff
- 查看已缓存的改动:
git diff --cached
- 查看已缓存的与未缓存的所有改动:
git diff HEAD
- 显示摘要而非整个 diff:
git diff --stat
新建文件 new.txt ,写入内容 “已缓存的修改” ,添加到缓存,再写入内容 “未缓存的修改” 。
应用场景2
在分支合并之前,也可以使用 git diff
命令预览差异:
1 | # 将target_branch分支合并到source_branch分支前预览差异 |
git commit
使用 git add
命令将想要快照的内容写入缓存区, 而执行 git commit
将缓存区内容提交到版本库中。
Git 为每一次提交都记录提交者的名字和电子邮箱地址,所以 commit 前需要配置用户名和邮箱地址。
1 | git config --global user.name 'JonSnows' |
接下来写入缓存,并提交对项目的所有改动,使用 -m 选项以在命令行中提供提交注释。
1 | git add * |
如果你没有设置 -m 选项,Git 会尝试为你打开一个编辑器以填写提交信息,退出即可,此时已经完成提交。
如果觉得 git add 提交暂存的流程太过繁琐,Git 也允许用 -a 选项跳过这一步,此命令无法提交新增文件。命令格式如下:
1 | git commit -am '提交注释' |
该命令将改动提交到了 HEAD,但是还没到远端仓库。
git reset HEAD
详解: https://www.yiibai.com/git/git_reset.html
git reset HEAD
命令用于取消已缓存的内容。
1 | git reset HEAD <file> #取消单个缓存 |
将一个新增文件 new2.txt
和 修改文件 new.txt
都提交到暂存区,然后一个个撤销暂存,操作如下:
简而言之,执行 git reset HEAD
以取消之前 git add
的添加。
git stash
https://www.yiibai.com/git/git_stash.html
git rebase
https://www.yiibai.com/git/git_rebase.html
git cherry-pick
https://www.ruanyifeng.com/blog/2020/04/git-cherry-pick.html
git rm
如果只是简单地从工作区中手工删除文件,运行 git status 时就会在 Changes not staged for commit 的提示。
要从 Git 中移除某个文件,就必须要从已跟踪文件清单中移除,然后提交。可以用以下命令完成此项工作
1 | git rm <file> |
如果删除之前修改过并且已经放到暂存区域的文件,会有如下图错误提示,必须要用强制删除选项 -f 。
1 | git rm -f <file> |
如果把文件从暂存区域移除,但仍然希望保留在当前工作目录中,换句话说,仅是从跟踪清单中删除,使用 –cached 选项即可。
1 | git rm --cached <file> |
git rm --cached <file>
和 git reset HEAD <file>
的区别?
git reset HEAD <file>
是取消已缓存的内容,提交到版本库后,此文件无任何改动。
git rm --cached <file>
是把文件从暂存区移除,提交到版本库后,此文件被删除。
git mv
git mv
命令用于移动或重命名一个文件、目录、软连接。
1 | git mv <file> <newFile> |
Git 分支管理
开始前先创建一个测试目录:
1 | git init gitdemo |
列出分支
列出分支基本命令:
1 | $ git branch |
此例的意思就是,我们有一个叫做 master 的分支,并且该分支是当前分支。
当你执行 git init 的时候,默认情况下 Git 就会为你创建 master 分支。
创建分支
创建分支命令:
1 | git branch <branchname> #已当前分支内容为基础创建分支 |
创建 testing 分支:
1 | $ git branch testing |
当你以此方式在上次提交更新之后创建了新分支,如果后来又有更新提交, 然后又切换到了 testing 分支,Git 将还原你的工作目录到你创建分支时候的样子。
切换分支
切换分支命令:
1 | git checkout <branchname> |
当切换分支的时候,Git 会用该分支的最后提交的快照替换工作目录(工作区)的内容, 所以多个分支不需要多个目录。
1 | $ ls |
当切换到 testing 分支的时候,添加的新文件 test.txt 被移除了。切换回 master 分支的时候,它们又重新出现了。
1 | $ git checkout master |
创建分支+切换
创建新分支并立即切换到该分支下:
1 | git checkout -b <branchname> # build |
例:
1 | $ git checkout master |
如你所见,我们创建了一个分支,在该分支的上移除了文件 test.txt,并添加了 runoob.php 文件,然后切换回主分支,删除的 test.txt 文件又回来了,且新增加的 runoob.php 不存在主分支中。
使用分支将工作切分开来,从而让我们能够在不同开发环境中做事,并来回切换。
删除分支
删除本地分支
1 | git branch -d <branchname> |
例如删除 testing 分支:
1 | $ git branch |
删除远程分支
1 | git push origin --delete <BranchName> |
分支合并
一旦某分支有了独立内容,终究会希望将它合并到主分支。 可以使用以下命令将任何分支合并到当前分支中去:
1 | git merge <branchname> |
可以多次合并到统一分支, 也可以选择在合并之后直接删除被并入的分支。
1 | $ git branch |
以上实例中我们将 newtest 分支合并到主分支去,test.txt 文件被删除。
合并完后就可以删除分支,删除未合并的分支会给出提示,要求使用 “git branch -D newtest” 命令删除,大写D。
1 | git branch -d newtest |
合并冲突
合并并不仅仅是简单的文件添加、移除的操作,Git 也会合并修改。
1 | $ git branch |
首先,创建一个叫做 change_site 的分支,切换过去,我们将 runoob.php 内容改为:
1 | <?php |
创建 change_site 分支:
1 | $ git checkout -b change_site |
将修改的内容提交到 change_site 分支中。 现在,切换回 master 分支,我们可以看到 runoob.php 是空文件,我们再次修改 runoob.php 文件。
1 | $ git checkout master |
接下来将 “change_site” 分支合并过来。
1 | $ git merge change_site |
现在已将 “change_site” 分支合并到 “master” 分支,发现一个合并冲突,接下来需要手动修改它。
1 | $ git diff |
在 Git 中,我们可以用 git add 要告诉 Git 文件冲突已经解决
解决合并的文件冲突后,添加到缓存区,并提交结果。
1 | $ git status -s |
Git 查看提交历史
1 | git log # 列出历史提交记录 |
更多 git log 命令可查看: https://git-scm.com/docs/git-log
Git 标签
Git 使用的标签有两种类型:轻量级的(lightweight)和含附注的(annotated)。
**轻量级标签:**就像是个不会变化的分支,实际上它就是个指向特定提交对象的引用。
**含附注标签:**实际上是存储在仓库中的一个独立对象,它有自身的校验和信息,包含着标签的名字,电子邮件地址和日期,以及标签说明,标签本身也允许使用 GNU Privacy Guard (GPG) 来签署或验证。
建议使用含附注标签,以便保留相关信息;当然,如果只是临时性加注标签,或者不需要旁注额外信息,用轻量级标签也没问题。
列显标签
1 | $ git tag # 列出现有标签 |
创建标签
注意:处于同一状态的项目可以创建多个标签。为了方便对比,下面示例中在创建标签之前会先做一次修改并提交,这样就避免了多个标签。
多个标签的情况:
轻量级标签
轻量级标签实际上就是一个保存着对应提交对象的校验和信息的文件。要创建这样的标签,一个 -a
,-s
或 -m
选项都不用,直接给出标签名字即可:
1 | git tag v1.0-lw |
含附注标签
1 | # 创建一个含附注类型的标签 |
查看标签
使用 git show
命令查看相应标签的版本信息,并连同显示打标签时的提交对象。
1 | $ git show # 不指定标签时,显示最新的标签,但不会显示标签详细信息 |
可以看到在提交对象信息上面,列出了此标签的提交者和提交时间,以及相应的标签说明。
删除标签
1 | git tag -d v1.0-lw |
签署标签
如果有自己的私钥,还可以用 GPG 来签署标签,只需要把之前的选项 -a
改为 -s
(译注: 取 signed 的首字母)即可:
1 | git tag -s v2.1 -m 'my signed 2.1 tag' |
验证标签
可以使用 git tag -v [tag-name]
(译注:取 verify 的首字母)的方式验证已经签署的标签。此命令会调用 GPG 来验证签名,所以你需要有签署者的公钥,存放在 keyring 中,才能验证:
1 | git tag -v v2.1 |
若是没有签署者的公钥,会报告类似下面这样的错误:
1 | git tag -v v2.1 |
后期加注标签
甚至可以在后期对早先的某次提交加注标签。比如在下面展示的提交历史中:
我们忘了在提交 v1.0-lw 版本提交
后为此项目打上版本号 v1.0-lw
,没关系,现在也能做。只要在打标签的时候跟上对应提交对象的校验和(或前几位字符)即可:
1 | git tag -a v1.0-lw -m '后期加注标签' 903fa8b |
分享标签
默认情况下,git push
并不会把标签传送到远端服务器上,只有通过显式命令才能分享标签到远端仓库。其命令格式如同推送分支,运行 git push origin [tagname]
即可:
1 | git push origin v2.1 |
回到 Github 发现:
如果要一次推送所有本地新增的标签上去,可以使用 --tags
选项:
1 | git push origin --tags |
Git 远程仓库(Github)
Git 并不像 SVN 那样有个中心服务器。
目前我们使用到的 Git 命令都是在本地执行,如果你想通过 Git 分享你的代码或者与其他开发人员合作。 你就需要将数据放到一台其他开发人员能够连接的服务器上。
服务器上的 Git - 协议
配置SSH密钥
Git传输协议 有很多,要使用 SSH 协议就需要配置 SSH Key; 也可以使用 HTTP 协议的用户名/密码的基础授权,免去设置 SSH 公钥 。
单个Git帐号的配置
使用以下命令生成 SSH Key:
1 | $ ssh-keygen -t rsa -C "youremail@example.com" |
后面的 your_email@youremail.com 改为你在 Github 上注册的邮箱,之后会要求确认路径和输入密码,我们这使用默认的一路回车就行。成功的话会在 ~/ 下生成 .ssh 文件夹,进去,打开 id_rsa.pub,复制里面的 key。
回到 github 上,进入 Account => Settings(账户配置)。
左边选择 SSH and GPG keys,然后点击 New SSH key 按钮,title 设置标题(随便填),粘贴刚生成的 key。
为了验证是否成功,在 git bash 下输入以下命令:
1 | $ ssh -T git@github.com |
如果是第一次会提示是否continue,输入yes就会看到以上输出,这就表示已成功连上github。
若已经拥有密钥对,就无需重新生成了。只需将私钥放到 ~/.ssh
目录,文件名必须是 id_rsa
,且无扩展名,并在 github 或 gitlab 个人设置里配置 ssh key 即可。
多个Git帐号的配置
推荐链接:
同时使用多个 Git
帐号,比如 Github
、OSChina
、Gitlib
等。
在 ~/.ssh/
目录下,新建一个 config
文件,配置多账户规范:
1 | 为SSH(应用层)协议配置SOCKS(会话层)代理: |
使用 ssh 的 ssh-add 命令将密钥添加到 ssh-agent 的高速缓存中,以缓存私钥的密码。这种方式让你只需要解锁一次密钥就可以重复地使用它,这样在会话中就不需要再次输入密钥密码了 。同理 gpg-agent。
1 | Windows PowerShell |
添加完后,可以使用 ssh-add
查看密钥列表。
配置远程库地址:打开项目下的 .git\config
文件并修改 remote url 。在配置 ssh 时,为每个 Hostname 配置了一个 host 的别名,用别名来代替 Hostname:
1 | [core] |
接下来就可以 push 、 pull 了。
配置用户名和邮箱
Git 为每一次提交都记录提交者的名字和电子邮箱地址,所以 commit 前需要配置用户名和邮箱地址。
1 | git config --local user.name 'JonSnows' |
创建仓库
然后我们在 github 上创建一个新的仓库
创建成功后,显示信息如下:
以上信息告诉我们,可以在命令行上创建新的存储库、可以从命令行推送现有存储库、可以从另一个存储库导入代码。
检出仓库
执行如下命令以创建一个本地仓库的克隆版本:
1 | git clone [url] |
具体参照 git clone
命令。
添加远程库
要添加一个新的远程仓库,可以指定一个别名,以便将来引用,命令格式如下:
1 | git remote add [alias] [url] |
远程仓库必须在 Github 中建立,如果添加的远程仓库不存在,push 时会提示如下错误:
1 | $ git remote add origin2 git@github.com:Jon-Snows/git-test2.git #此仓库链接不存在 |
在本地仓库下运行命令:
1 | $ mkdir git-test # 创建测试目录 |
接下返回 Github 创建的仓库,就可以看到文件已上传到 Github上:
查看远程库
查看本地添加的全部远程库
1 | $ git remote |
查看远程仓库
如果想要查看某一个远程仓库的更多信息,可以使用 git remote show [remote-name]
命令。 如果想以一个特定的缩写名运行这个命令,例如 origin
,会得到像下面类似的信息:
1 | Administrator@JonSnows MINGW64 /d/git/git-test (testing) # testing 是当前所在分支 |
这些信息非常有用,它告诉我们:
- 远程仓库的 URL。
- 远程仓库的全部 branch。
- 如果运行
git pull
,就会抓取所有的远程引用,然后将远程master
分支合并到本地master
分支。 - 如果在特定的分支上执行
git push
会自动地推送到哪一个远程分支。 - 哪些远程分支不在本地,这里是 testing2 分支。
更新并合并
提取远程仓库的两种方式:一、git fetch + git merge。二、git pull。
git fetch + git merge
Git 有两个命令用来提取远程仓库的更新。
1、从远程仓库抓取新推送的所有工作,然后将数据拉取到本地仓库, 它并不会自动合并或修改当前的工作。
1 | git fetch [远程主机alias] # 要更新所有分支,命令可以简写为:git fetch |
该命令执行完后需要执行 git merge
合并远程分支到当前分支。
2、从远端仓库提取数据并尝试合并远程分支到当前分支:
1 | git merge [alias]/[branch] |
该命令就是在执行 git fetch 之后紧接着执行 git merge 合并远程分支到当前所在的任意分支。
如果 git merge
操作没有需要解决的分歧,就叫做 “快进(fast-forward)”。即当试图合并两个分支时, 如果顺着一个分支走下去能够到达另一个分支,那么 Git 在合并两者的时候, 只会简单的将指针向前推进(指针右移)。
测试:
接下来我们在 Github 上点击” README.md” 并在线修改它:
然后在本地更新修改。
1 | $ git fetch origin |
以上信息 a531b58..560b6f6 master -> origin/master
说明 master 分支已被更新,我们可以使用以下命令将更新同步到本地:
1 | $ git merge origin/master |
查看 README.md 文件内容:
1 | $ cat README.md |
Git 分支 - 变基 (Merge 与 Rebase)
链接: Git 分支 - 变基 、 只会用 git pull ?有时候你可以尝试更优雅的处理方式
变基:改变基础。将复杂难懂、眼花缭乱的多分支提交历史,整合为一条直线,变基使得提交历史更加整洁。
使用前先了解: 变基的风险 、 用变基解决变基 、 变基 vs. 合并
如果习惯使用 git pull
,同时又希望默认使用选项 --rebase
,请参考以下配置:
1 | 更改pull.rebase的默认配置 |
git pull
链接: git pull命令
从服务器上抓取全部数据并自动尝试合并远程默认分支到当前分支。
1 | # git pull = git fetch + git merge |
要合并其他分支到你的当前分支(例如 master),执行:
1 | git merge (branchname) |
以上两种情况下,git 都会尝试去自动合并改动。遗憾的是,这可能并非每次都成功,并可能出现冲突(conflicts)。 这时候就需要修改这些文件来手动合并这些冲突(conflicts)。改完之后,需要执行如下命令以将它们标记为合并成功:
1 | git add <file> |
在合并分支之前,可以使用 git diff
命令预览差异:
1 | # 将target_branch分支合并到source_branch分支前预览差异 |
补充:
1 | # git pull [options] [<repository> [<refspec>…]] |
还原/回退/撤销
工作区
假如操作失误(当然,这最好永远不要发生),可以使用如下命令还原:
1 | git checkout -- <file> |
命令 git checkout -- readme.txt
意思就是,把 readme.txt
文件在工作区的修改全部撤销,这里有两种情况:
1、 readme.txt
自修改后还没有被放到暂存区,现在,撤销修改就回到和版本库一模一样的状态,即使用 HEAD 中的最新内容替换掉工作区的文件内容;
2、 readme.txt
已经添加到暂存区后,又做了修改,现在,撤销修改就回到添加到暂存区后的状态。
此命令无法还原暂存区的改动,且对新文件无效。
取消缓存使用 git reset HEAD
,见上文。
本地
假如想丢弃在本地的所有改动与提交(工作区、暂存区、版本库),可以到服务器上获取最新的版本历史,并将本地主分支指向它:
1 | # 丢弃所有本地改动:工作区、暂存区、版本库 这些都是本地操作 |
git reset –-soft
:回退到某个版本,只取消了commit的信息,代码更改并没有取消,不会恢复到index file一级。如果还要提交,直接commit即可;git reset -–hard
:彻底回退到某个版本,本地的源码也会变为上一个版本的内容,撤销的commit中所包含的更改被冲掉;
推送到远程仓库
链接: git push命令 、 git push.default 简析
默认配置项
1 | 2.0以前的默认配置项 |
推送新分支与数据到某个远端仓库命令:
1 | git push [alias] [branch] |
以上命令将 [branch] 分支推送成为 [alias] 远程仓库上的 [branch] 分支,实例如下。
1 | $ touch test.txt # 添加文件 |
重新回到 Github 仓库,可以看到文件已经推送上来了:
补充:
1 | # git push <远程主机名> <本地分支名>:<远程分支名> |
删除远程仓库
1 | git remote rm [alias] |
示例
1 | $ git remote -v |
服务器上的 Git
见官网,Git传输的四种协议、Git服务器搭建、生成SSH秘钥、配置服务器、Git守护进程等
在其它环境中使用 Git
见官网,图形界面工具、各种开发工具中的 Git 。
网上还有很多图形界面工具。