分布式版本控制系统 Git

29
五月
2021

一、版本控制概要

1.1 什么是版本控制

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

  • 实现跨区域多人协同开发
  • 追踪和记载一个或者多个文件的历史记录
  • 组织和保护你的源代码和文档
  • 统计工作量
  • 并行开发、提高开发效率
  • 跟踪记录整个软件的开发过程
  • 减轻开发人员的负担,节省时间,同时降低人为错误

简单说就是用于管理多人协同开发项目的技术。

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

63651-20170904231244710-1748418928.png

1.2 常用术语

1. 工作树/区(Workspace)
程序员进行开发(改动)的地方,是当前能看到的文件夹。

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

.git 目录下的 index 文件, 暂存区会记录 git add 添加文件的相关信息(文件名、大小、timestamp…),不保存文件实体, 通过id指向每个文件实体。

可以使用 git status 查看暂存区的状态!

3. 本地仓库(Local Repository)

git commit 后同步 index 的目录树到本地仓库,方便从下一步通过 git push 同步本地仓库与远程仓库。

说明1:只有把修改提交 (commit) 到本地仓库,该修改才能在仓库中留下痕迹
说明2:可以在任何地方新建本地仓库,只需要在目标目录下执行 git init 指令,就会将此目录自动初始化为本地仓库,同时它会新建 “.git” 目录

4. 远程仓库(Remote Repository)
内容可能被分布在多个地点的处于协作关系的本地仓库修改,因此它可能与本地仓库同步,也可能不同步。

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

6. 签入(Check in)
将新版本复制回仓库。

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

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

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

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

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

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

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

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

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

1.3 常见的版本控制器

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

  • Git
  • SVN(Subversion)
  • CVS(Concurrent Versions System)
  • VSS(Microsoft 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。

1.4 版本控制分类

1.4.1 本地版本控制

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

05163110-c8a48b29015245b78dc0127429ef5213.png

1.4.2 集中版本控制

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

63651-20170904213634085-673206677.png

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

1.4.3 分布式版本控制

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

63651-20170904214244944-1222535795.png

1.5 Git 与 SVN 最主要区别

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

63651-20170904215630788-377479009.png

63651-20170904215806085-1977930707.png
63651-20170904215943554-1806020988.png

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

二、Git 安装与配置

63651-20170904222351757-505218464.png

2.1 什么是 Git

Git 是目前世界上最先进的分布式版本控制系统。

Git 是免费、开源的。

最初 Git 是为辅助 Linux 内核开发的,来替代 BitKeeper 。

63651-20170904223054569-1226906652.png

作者:Linux 和 Git 之父 李纳斯·托沃兹(Linus Torvalds)1969、芬兰.

优点:

  • 适合分布式开发,强调个体
  • 公共服务器压力和数据量都不会太大
  • 速度快、灵活
  • 任意两个开发者之间可以很容易地解决冲突
  • 支持离线工作

缺点:

  • 模式上比 SVN 更加复杂
  • 不符合常规思维
  • 代码保密性差,一旦开发者把整个库克隆下来就可以完全公开所有代码和版本信息

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

源码: https://github.com/git/git/

2.2 搭建 Git 工作环境

2.2.1 下载 Git

打开 git官网,下载git对应操作系统的版本

63651-20170904224935226-646404598.png

选择版本:

63651-20170904225056351-1443818096.png

这里我选择下载 64-bit Git for Windows Setup

63651-20170904225407569-334038713.png

2.2.2 安装 Git

63651-20170904225914054-2025747538.png

选择安装配置信息

63651-20170904225939491-904441630.png

一直 Next 默认就好了,如果需要设置就要仔细读一下安装界面上的选项

2.2.3 启动 Git

安装成功后在开始菜单中会有Git项,菜单下有3个程序:

63651-20170904230524616-939776409.png

Git Bash: Unix 与 Linux 风格的命令行,使用最多,推荐最多

63651-20170904230713476-944403758.png

与 DOS 风格的命令有些区别,不习惯可以选择 Git CMD

Git CMD: Windows 风格的命令行

63651-20170904230927897-26895067.png

Git GUI:图形界面的 Git,不建议初学者使用,尽量先熟悉常用命令

63651-20170904231104460-2046803495.png

点击 Create New Repository 可以直接创建一个新的仓库。

2.2.4 Linux 与 Mac OS 安装 Git

Linux 安装 Git:sudo apt-get install git 命令行就可以安装了。

Mac OS 安装 Git: https://git-scm.com/download/mac,下载双击 .pkg 安装

2.2.5 Bash 基本操作命令

  1. cd:改变目录
  2. cd . . :回退到上一个目录,直接cd进入默认目录
  3. pwd:显示当前所在的目录路径
  4. ls(ll):都是列出当前目录中的所有文件,只不过ll(两个ll)列出的内容更为详细
  5. touch:新建一个文件 如 touch index.js 就会在当前目录下新建一个index.js文件
  6. rm:删除一个文件, rm index.js 就会把index.js文件删除
  7. mkdir:新建一个目录,就是新建一个文件夹
  8. rm -r:删除一个文件夹, rm -r src 删除src目录, 好像不能用通配符
  9. mv:移动文件, mv index.html src index.html 是我们要移动的文件, src 是目标文件夹,当然, 这样写,必须保证文件和目标文件夹在同一目录下
  10. reset:重新初始化终端/清屏
  11. clear:清屏
  12. history:查看命令历史
  13. help:帮助
  14. exit:退出
  15. #:表示注释

2.3 Git 配置 git config

2.3.1 查看配置 git config -l

使用 git config -l 可以查看现在的 git 环境详细配置

63651-20170905111941679-369062685.png

查看不同级别的配置文件:

#查看系统(system)配置信息
$ git config --system --list

#查看当前用户(global)配置信息
$ git config --global --list

#查看当前仓库(local)配置信息
$ git config --local --list

2.3.2 Git 配置文件分类

在 Windows 系统中,Git 在 $HOME 目录中查找 .gitconfig 文件(一般位于 C:\Documents and Settings$USER 下)

Git 相关的配置文件有三个:

  1. /etc/gitconfig: 包含了适用于系统所有用户和所有项目的值 (Win:C:\Program Files\Git\mingw64\etc\gitconfig) --system 系统级

63651-20170905155620835-541203307.png

  1. ~/.gitconfig: 只适用于当前登录用户的配置。(Win:C:\Users\Administrator.gitconfig) --global 全局

63651-20170905112611116-974195699.png

  1. 位于 git 项目目录中的 .git/config:适用于特定 git 项目的配置。(Win:C:\gitProject) --local 当前项目

注意:对于同一配置项,三个配置文件的优先级是 1<2<3

这里可以直接编辑配置文件,通过命令设置后会响应到这里。

2.3.3 设置用户名与邮箱

当你安装 Git 后首先要做的事情是设置你的用户名称和 e-mail 地址,这是非常重要的,因为每次 Git 提交都会使用该信息,它被永远的嵌入到了你的提交中:

$ git config --global user.name "w"  	       #名称
$ git config --global user.email ***@qq.com    #邮箱

只需要做一次这个设置,如果你传递了–global 选项,因为 Git 将总是会使用该信息来处理你在系统中所做的一切操作。如果你希望在一个特定的项目中使用不同的名称或 e-mail 地址,你可以在该项目中运行该命令而不要 --global 选项。

总之 --global 为全局配置,不加为某个项目的特定配置。

63651-20170905135629991-890437951.png

2.3.4 添加或删除配置项

1)添加配置项

$ git config [--local|--global|--system]  section.key value
[--local|--global|--system]  #可选的,对应本地,全局,系统不同级别的设置,请看2.3.2
section.key 				 #区域下的键
value 						 #对应的值
  • –local 项目级
  • –global 当前用户级
  • –system 系统级

例如我们要在 student 区域下添加一个名称为 height 值为198的配置项,执行结果如下:

63651-20170905160142351-561831872.png

2)删除配置项

$ git config [--local|--global|--system] --unset section.key

将系统级的 height 配置项移除

63651-20170905161225726-295254907.png

2.3.5 更多配置项

$ git config --global color.ui true     # 打开所有的默认终端着色
$ git config --global alias.ci commit   # 别名 ci 是commit的别名
[alias]  
co = checkout  
ci = commit  
st = status  
pl = pull  
ps = push  
dt = difftool  
l = log --stat  
cp = cherry-pick  
ca = commit -a  
b = branch 

user.name  #用户名
user.email  #邮箱
core.editor  #文本编辑器  
merge.tool  #差异分析工具  
core.paper "less -N"  #配置显示方式  
color.diff true  #diff颜色配置  
alias.co checkout  #设置别名
$ git config user.name  #获得用户名
$ git config core.filemode false  #忽略修改权限的文件  

2.3.6 *config 命令相关参数

usage(语法): git config [<options>]        
        
Config file location(文件位置)
    --global                  #use global config file 使用全局配置文件
    --system                  #use system config file 使用系统配置文件
    --local                   #use repository config file    使用存储库配置文件
    -f, --file <file>         #use given config file    使用给定的配置文件
    --blob <blob-id>          #read config from given blob object    从给定的对象中读取配置

Action(动作)
    --get                     #get value: name [value-regex]    获得值:[值]名[正则表达式]
    --get-all                 #get all values: key [value-regex]    获得所有值:[值]名[正则表达式]
    --get-regexp              #get values for regexp: name-regex [value-regex]    得到的值根据正则
    --get-urlmatch            #get value specific for the URL: section[.var] URL    为URL获取特定的值
    --replace-all             #replace all matching variables: name value [value_regex]    替换所有匹配的变量:名称值[ value_regex ]
    --add                     #add a new variable: name value    添加一个新变量:name值
    --unset                   #remove a variable: name [value-regex]    删除一个变量名[值]:正则表达式
    --unset-all               #remove all matches: name [value-regex]    删除所有匹配的正则表达式:名称[值]
    --rename-section          #rename section: old-name new-name    重命名部分:旧名称 新名称
    --remove-section          #remove a section: name    删除部分:名称
    -l, --list                #list all    列出所有
    -e, --edit                #open an editor    打开一个编辑器
    --get-color               #find the color configured: slot [default]    找到配置的颜色:插槽[默认]
    --get-colorbool           #find the color setting: slot [stdout-is-tty]    发现颜色设置:槽[ stdout是TTY ]

Type(类型)
    --bool                    #value is "true" or "false"    值是“真”或“假”。
    --int                     #value is decimal number    值是十进制数。
    --bool-or-int             #value is --bool or --int    值--布尔或int
    --path                    #value is a path (file or directory name)    值是路径(文件或目录名)
        
Other(其他)
    -z, --null                #terminate values with NUL byte    终止值与null字节
    --name-only               #show variable names only    只显示变量名
    --includes                #respect include directives on lookup    尊重包括查找指令
    --show-origin             #show origin of config (file, standard input, blob, command line)    显示配置(文件、标准输入、数据块、命令行)的来源

三、Git 理论基础

3.1 工作区域

Git 本地有三个工作区域:

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

63651-20170905201017069-171460014.png

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

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

63651-20170906230652788-1835188684.png

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

3.2 工作流程

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

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

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

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

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

63651-20170905201033647-1915833066.png

3.3 图解教程

个人认为 Git 的原理相比别的版本控制器还是复杂一些的,有一份图解教程比较直观:

图解教程英文原版

图解教程中文版

63651-20170914100820891-2098204183.png

四、Git 操作

4.1 创建工作目录与常用指令

工作目录(Workspace)一般就是你希望 Git 帮助你管理的文件夹,可以是你项目的目录,也可以是一个空目录,建议不要有中文

日常使用只要记住下图的 6个命令:

63651-20170905212837976-775285128.png

4.2 获得 Git 仓库

创建本地仓库的方法有两种:一种是创建全新的仓库(git init),另一种是克隆远程仓库(git clone)。

63651-20170905214339226-738603749.png

4.2.1 创建全新仓库

需要用 GIT 管理的项目的根目录执行:

# 在当前目录新建一个 Git 代码库
$ git init

执行:

63651-20170905215656866-1398401674.png

63651-20170905215735366-1289732483.png

执行后可以看到,仅仅在项目目录多出了一个 .git 目录,关于版本等的所有信息都在这个目录里面。

当然如果使用如下命令,可以把创建目录与仓库一起完成:

# 新建一个目录,将其初始化为 Git 代码库
$ git init [project-name]

执行:

63651-20170905220337507-804117637.png

4.2.2 克隆远程仓库

另一种方式是克隆远程目录,由于是将远程服务器上的仓库完全镜像一份至本地,而不是取某一个特定版本,所以用 clone 而不是 checkout ,语法格式如下:

# 克隆一个项目和它的整个代码历史(版本信息)
$ git clone [url]

执行:

比如我们要从克隆的远程仓库托管在 GitHub 上:

63651-20170905221014272-913470815.png

63651-20170905221312116-63802822.png

结果:

63651-20170905221458694-121760087.png

4.3 Git 文件操作

版本控制就是对文件的版本控制,要对文件进行修改、提交等操作,首先要知道文件当前在什么状态,不然可能会提交了现在还不想提交的文件,或者要提交的文件没提交上。GIT不关心文件两个版本之间的具体差别,而是关心文件的整体是否有改变,若文件被改变,在添加提交时就生成文件新版本的快照,而判断文件整体是否改变的方法就是用 SHA-1算法 计算文件的校验和。

4.3.1 文件 4 种状态

  • Untracked: 未跟踪, 此文件在文件夹中, 但并没有加入到 git 库, 不参与版本控制. 通过 git add 状态变为Staged .
  • Unmodified: 文件已经入库, 未修改, 即版本库中的文件快照内容与文件夹中完全一致. 这种类型的文件有两种去处, 如果它被修改, 而变为 Modified. 如果使用 git rm 移出版本库, 则成为 Untracked 文件.
  • Modified: 文件已修改, 仅仅是修改, 并没有进行其他的操作. 这个文件也有两个去处, 通过 git add 可进入暂存 staged 状态, 使用 git checkout 则丢弃修改过, 返回到 Unmodified 状态, 这个 git checkout 即从库中取出文件, 覆盖当前修改.
  • Staged: 暂存状态. 执行 git commit 则将修改同步到库中, 这时库中的文件和本地文件又变为一致, 文件为 Unmodify 状态. 执行 git reset HEAD filename 取消暂存, 文件状态为 Modified .

63651-20170909091456335-1787774607.jpg

4.3.2 查看文件状态(status)

上面说文件有4种状态,通过如下命令可以查看到文件的状态:

#查看指定文件状态
$ git status [filename]

#查看所有文件状态
$ git status

执行:

63651-20170905225929726-953984446.png

结果:

foo.htm 文件的状态为 untracked(未跟踪),提示通过 git add 可以暂存。

GIT 在这一点做得很好,在输出每个文件状态的同时还说明了怎么操作,像上图就有怎么暂存、怎么跟踪文件、怎么取消暂存的说明:
use “git add …” to include in what will be committed.

4.3.3 添加文件与目录(add)

63651-20170905231716304-244902919.png

工作区(Working Directory)就是你在电脑里能看到的目录。

版本库(Repository)工作区有一个隐藏目录 .git,这个不算工作区,而是 Git 的版本库。

Git 的版本库里存了很多东西,其中最重要的就是称为 stage(或者叫 index)的暂存区,还有 Git 为我们自动创建的第一个分支 master,以及指向 master 的一个指针叫 HEAD

将untracked状态的文件添加到暂存区,语法格式如下:

# 添加指定文件到暂存区
$ git add [file1] [file2] ...

# 添加指定目录到暂存区,包括子目录
$ git add [dir]

# 添加当前目录的所有文件到暂存区
$ git add .

执行:

63651-20170905230902819-1267851128.png

4.3.4 移除文件与目录(撤销 add)

201751509379751.png

当执行如下命令时,会直接从暂存区删除文件,工作区则不做出改变:

# 直接从暂存区删除文件,工作区则不做出改变
$ git rm --cached <file>

执行命令:

63651-20170905234240804-1332106185.png

通过重写目录树移除 add 文件:

# 如果已经用 add 命令把文件加入 stage 了,就先需要从 stage 中撤销
$ git reset HEAD <file>...

当执行 git reset HEAD 命令后,暂存区(stage)的目录树会被重写,被 master 分支指向的目录树所替换,但是工作区不受影响

执行: 把 f1.txt 文件从暂存区撤回工作区

63651-20170906214833804-177821547.png

移除所有未跟踪文件:

# 移除所有未跟踪文件
# 一般会加上参数-df,-d表示包含目录,-f表示强制清除。
$ git clean [options] 

执行:

63651-20170906151958444-1958472278.png

移除前:

63651-20170906152037054-939716292.png

执行移除:

63651-20170906152107147-393725026.png

移除后:

63651-20170906152135616-1007222940.png

rm、mv

# 只从 stage 中删除,保留物理文件!
$ git rm --cached readme.txt 

# 不但从 stage 中删除,同时删除物理文件!
$ git rm readme.txt 

# 把 a.txt 改名为 b.txt
$ git mv a.txt b.txt 

4.3.4 conclusion:

  1. 当执行提交操作 git commit 时,暂存区的目录树写到版本库(对象库)中,master 分支会做相应的更新。即 master 指向的目录树就是提交时暂存区的目录树。

  2. 当执行 git reset HEAD 命令时,暂存区的目录树会被重写,被 master 分支指向的目录树所替换,但是工作区不受影响。

  3. 当执行 git rm –cached <file> 命令时,会直接从暂存区删除文件,工作区则不做出改变。

  4. 当执行 git checkout 或者 git checkout — <file> 命令时,会用暂存区全部或指定的文件替换工作区的文件。这个操作很危险,会清除工作区中未添加到暂存区的改动。

  5. 当执行 git checkout HEAD 或者 git checkout HEAD <file> 命令时,会用 HEAD 指向的 master 分支中的全部或者部分文件替换暂存区和以及工作区中的文件! 这个命令也是极具危险性的,因为不但会清除工作区中未提交的改动,也会清除暂存区中未提交的改动。

4.3.5 查看文件修改后的差异(diff)

git diff 用于显示 Workspace 中的文件和暂存区文件的差异

git status 只能查看对哪些文件做了改动,如果要看改动了什么,可以用:

# 查看文件修改后的差异
$ git diff [files]

执行:

63651-20170906141531554-463319760.png

—a 表示修改之前的文件,+++b 表示修改后的文件

# 比较暂存区的文件与之前已经提交过的文件
$ git diff --cached

也可以把 Workspace 中的状态和 repo 中的状态进行 diff,命令如下:

# 比较 repo 与工作空间中的文件差异
$ git diff HEAD~n

63651-20170914095506203-2063795525.png

4.3.6 签出(checkout)

如果仓库中已经存在文件 f4.txt,在工作区中对 f4.txt 修改了,如果想撤销可以使用 checkout,签出覆盖

检出命令 git checkout 是 git 最常用的命令之一,同时也是一个很危险的命令,因为这条命令会重写工作区.

语法:

# 用法一
$ git checkout [-q] [<commit>] [--] <paths>...
# 用法二
$ git checkout [<branch>]
# 用法三
$ git checkout [-m] [[-b]--orphan] <new_branch>] [<start_point>]

是可选项,如果省略则相当于从暂存区(index)进行检出。

63651-20170906224842804-513302659.png

# 检出branch分支。要完成图中的三个步骤,更新HEAD以指向branch分支,以及用branch指向的树更新暂存区和工作区。
$ git checkout branch

# 汇总显示工作区、暂存区与HEAD的差异。
$ git checkout

# 同上
$ git checkout HEAD

# 用暂存区中filename文件来覆盖工作区中的filename文件。相当于取消自上次执行git add filename以来(如果执行过)的本地修改。
$ git checkout -- filename

# 维持HEAD的指向不变。用branch所指向的提交中filename替换暂存区和工作区中相应的文件。注意会将暂存区和工作区中的filename文件直接覆盖。
$ git checkout branch -- filename

# 注意 git checkout 命令后的参数为一个点(“.”)。这条命令最危险!会取消所有本地的修改(相对于暂存区)。
# 相当于用暂存区的所有文件直接覆盖本地文件,不给用户任何确认的机会!
$ git checkout -- . 或写作 $ git checkout .

# 如果不加commit_id,那么git checkout -- file_name 表示恢复文件到本地版本库中最新的状态。
$ git checkout commit_id -- file_name

示例:

63651-20170906223105851-2141952910.png

4.3.6 忽略文件(.gitignore)

有些时候我们不想把某些文件纳入版本控制中,比如数据库文件,临时文件,设计文件等

在主目录下建立 .gitignore 文件,此文件有如下规则:

  1. 忽略文件中的空行或以井号(#)开始的行将会被忽略
  2. 可以使用Linux通配符。例如:星号(*)代表任意多个字符,问号(?)代表一个字符,方括号([abc])代表可选字符范围,大括号({string1,string2,…})代表可选的字符串等
  3. 如果名称的最前面有一个感叹号(!),表示例外规则,将不被忽略
  4. 如果名称的最前面是一个路径分隔符(/),表示要忽略的文件在此目录下,而子目录中的文件不忽略
  5. 如果名称的最后面是一个路径分隔符(/),表示要忽略的是此目录下该名称的子目录,而非文件(默认文件或目录都忽略)
#为注释
*.txt 		#忽略所有 .txt结尾的文件
!lib.txt 	#lib.txt除外
/temp 		#仅忽略项目根目录下的TODO文件,不包括其它目录temp
build/ 		#忽略build/目录下的所有文件
doc/*.txt 	#会忽略 doc/notes.txt 但不包括 doc/server/arch.txt

示例: 创建一个 .gitignore 文件忽视所有的日志文件

63651-20170906150554460-1028534587.png

查看状态:

63651-20170906150711069-480648048.png

从上图中可以看出2个日志文件并没有添加到暂存区,直接被忽视了。

针对各种语言与项目的Git忽视文件:https://github.com/github/gitignore

例:通用的 java .gitignore 文件

# Compiled class file
*.class

# Log file
*.log

# BlueJ files
*.ctxt

# Mobile Tools for Java (J2ME)
.mtj.tmp/

# Package Files #
*.jar
*.war
*.ear
*.zip
*.tar.gz
*.rar

# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
hs_err_pid*

更多规则请点这里

4.3.7 提交(commit)

通过 add 只是将文件或目录添加到了 index 暂存区,使用 commit 可以实现将暂存区的文件提交到本地仓库。

# 提交暂存区到仓库区
$ git commit -m [message]

# 提交暂存区的指定文件到仓库区
$ git commit [file1] [file2] ... -m [message]

# 提交工作区自上次commit之后的变化,直接到仓库区,跳过了add, 对新文件无效!!!
$ git commit -a

# 提交时显示所有diff信息
$ git commit -v

# 使用一次新的commit,替代上一次提交
# 如果代码没有任何新变化,则用来改写上一次commit的提交信息
$ git commit --amend -m [message]

# 重做上一次commit,并包括指定文件的新变化
$ git commit --amend [file1] [file2] ...

示例:

提交前的状态

63651-20170906153238929-20184387.png

提交

63651-20170906153319819-191287492.png

提交后的状态:

63651-20170906153352694-1534298704.png

从上图中可以看出暂存区中没有了 bar.htm

修订提交

如果我们提交过后发现有个文件改错了,或者只是想修改提交说明,这时可以对相应文件做出修改,将修改过的文件通过 git add 添加到暂存区,然后执行以下命令:

# 修订提交
$ git commit --amend

撤销提交(commit)

原理就是放弃工作区和 index 的改动,同时 HEAD 指针指向前一个 commit 对象

# 撤销上一次的提交
$ git reset --hard HEAD~1

要通过 git log 查看提交日志,也可直接指定提交编号或序号

示例:

63651-20170906215817304-744932869.png

撤销提交:git revert <commit-id>
这条命令会把指定的提交的所有修改回滚,并同时生成一个新的提交。

4.3.8 日志与历史(log)

查看提交日志可以使用git log指令,语法格式如下:

# 查看提交日志
$ git log [<options>] [<revision range>] [[\--] <path>]

示例:

63651-20170906162101757-272912226.png

git log --graph 以图形化的方式显示提交历史的关系,这就可以方便地查看提交历史的分支信息,当然是控制台用字符画出来的图形。

git log -1 则表示显示1行。

使用 history 可以查看你在 bash 下输入过的指令:

63651-20170906162304663-1459403979.png

查看所有分支日志

git reflog 中会记录这个仓库中所有的分支的所有更新记录,包括已经撤销的更新。

63651-20170907101206757-412323808.png

4.3.9 查看文件列表

使用 git ls-files 指令可以查看指定状态的文件列表,格式如下:

# 查看指定状态的文件
$ git ls-files [-z] [-t] [-v] (--[cached|deleted|others|ignored|stage|unmerged|killed|modified])* (-[c|d|o|i|s|u|k|m])*

示例:

63651-20170906213836397-1160093052.png

4.3.10 撤销更新(reset)

1. 撤销暂存区更新

使用 git add 把更新提交到了暂存区。这时 git status 的输出中提示我们可以通过 git reset HEAD <file>... 把暂存区的更新移出到 Workspace 中。

示例: f6已经提交,工作区修改,暂存区修改,撤销

63651-20170906233841179-595609603.png

2. 撤销本地仓库更新

使用 git log 查看提交日志

63651-20170906234944507-1852886113.png

撤销提交有两种方式:使用HEAD指针使用 commit-id

在 Git 中,有一个 HEAD 指针指向当前分支中最新的提交。当前版本,我们使用 HEAD^ ,那么再前一个版本可以使用 HEAD^^ ,如果想回退到更早的提交,可以使用 HEAD~n (也就是 HEAD^ = HEAD-1,HEAD^^ = HEAD-2

$ git reset --hard HEAD^
$ git reset --hard HEAD~1
$ git reset --59cf9334cf957535cb328f22a1579b84db0911e5

示例: 回退到添加 f6

回退前:

63651-20170906235156351-597175458.png

回退后:

63651-20170906235057710-1820019779.png

现在又想恢复被撤销的提交可用 git reflog 查看仓库中所有的分支的所有更新记录,包括已经撤销的更新,撤销方法与前面一样。

$ git reset --hard HEAD@{7}s
$ git reset --hard e0e79d7

–hard:撤销并删除相应的更新

–soft:撤销相应的更新,把这些更新的内容放到 Stage 中

4.3.11 删除文件

1. 删除未跟踪文件

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

63651-20170907105943507-935637930.png

2. 删除已提交文件

63651-20170907110401929-1828626391.png

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

撤销删除:

# to discard changes in working directory
$ git checkout -- <file>...

63651-20170907111343257-1372946435.png

3. 删除暂存区的文件,不删除工作区的文件

63651-20170907111546679-1645938864.png

使用 git reset HEAD <file>... 同样可以实现上面的功能

4.3.12 文件操作小结

061510341401056.png

Git 很强大,很灵活,这是毋庸置疑的,但也正因为它的强大造就了它的复杂。

4.4 Git 分支

分支在 Git 中相对较难.

分支就是科幻电影里面的平行宇宙,当你正在电脑前努力学习 Git 的时候,另一个你正在另一个平行宇宙里努力学习 SVN.

如果两个平行宇宙互不干扰,那对现在的你也没啥影响。不过,在某个时间点,两个平行宇宙合并了,结果,你既学会了 Git 又学会了 SVN !

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

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

Git 分支的速度非常快。

截止到目前,只有一条时间线,在 Git 里,这个分支叫主分支,即 master 分支。HEAD 严格来说不是指向提交,而是指向 master,master 才是指向提交的,所以,HEAD 指向的就是当前分支

20194528-f5bf7e93960148a782f9d72f93a134bc.png

63651-20170905212648335-1801547172.jpg

231044049057798.png

*git 分支中常用指令:

# 列出所有本地分支
$ git branch

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

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

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

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

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

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

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

# 删除分支
$ git branch -d [branch-name]
# The branch 'feature-a' is not fully mergerd.
# If you are sure you want to delete it, run 'git branch -D feature-a'.
$ git branch -D [branch-name]

# 删除远程分支(以下两个命令略有不同)
$ git push origin :master					# $ git push 命令处会讲解!
$ git push origin --delete [branch-name]	# 删除本地仓库中远程仓库分支的记录的同时,删除远程仓库的分支(物理删除)
$ git branch -dr [remote/branch]			# 仅仅删除远程分支在 .git/refs/remotes/ 文件夹中的记录(逻辑分支)

# 新建一个分支,与指定的远程分支建立追踪关系!(是新建分支同时追踪!)
$ git branch --track [branch] [remote-branch]

# 建立追踪关系,在现有分支与指定的远程分支之间!(是现有分支!)
# fatal: the '--set-upstream' option is no longer supported. 
# Please use '--track' or '--set-upstream-to' instead.
$ git branch --set-upstream [branch] [remote-branch]	# 过时!
$ git branch --set-upstream-to [remote-branch] [branch] # 现用!

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

# *选择一个commit,合并进当前分支
$ git cherry-pick [<options>] [commit-ish]
可选options:
    --quit                退出当前的chery-pick序列
    --continue            继续当前的chery-pick序列
    --abort               取消当前的chery-pick序列,恢复当前分支
    -n, --no-commit       不自动提交!
    -e, --edit            编辑提交信息

注意:

  1. If you are planning on basing your work on an upstream
    hint: branch that already exists at the remote, you may need to run git fetch to retrieve it.

    • git fetch :用 GitHub 远程仓库更新本地 remotes 文件夹,而不是 head 文件夹(**例如:当远程仓库新建分支,使用 git fetch 可以使得本地仓库可以检索(retrieve)到远程新分支,**否则无从得知!)
      • .git/refs/head/: [本地分支]
    • .git/refs/remotes/: [正在跟踪的分支]
    • 总之:更改远端跟踪分支只能用 git fetch,或者是 git push 后作为副产品(side-effect)来改变。我们无法直接对远程跟踪分支操作,我们必须先切回本地分支然后创建一个新的 commit 提交。
  2. git 是分布式版本库,每个 git 版本库彼此是独立的,默认是没有通知机制的,任意一个版本库更新了,其他人压根不知道,git 也不会主动联网去获取更新。这就避免了同 SVN/CVS 一样必须联网才能使用的诟病。git clone 之后,每个人得到的都是完整的一份版本库的拷贝,因此就算中央仓库挂掉了,随便找个人的版本库放上去就能恢复了。

4.4.1 新建分支与切换分支

默认分支是这样的,master 是主分支

1. 新建一个分支,但依然停留在当前分支,使用:$ git branch [branch-name]

63651-20170908102319366-860612118.png

切换分支到dev1后的结果:

63651-20170908110413257-321369438.png

关于分支廖雪峰解释得比较清楚,引用一下。

当我们创建新的分支,例如 dev 时,Git 新建了一个指针叫 dev,指向 master 相同的提交,再把 HEAD 指向 dev,就表示当前分支在dev上.

Git 创建一个分支很快,因为除了增加一个 dev 指针,改改 HEAD 的指向,工作区的文件都没有任何变化!

不过,从现在开始,对工作区的修改和提交就是针对 dev 分支了,比如新提交一次后,dev 指针往前移动一步,而 master 指针不变.

假如我们在 dev 上的工作完成了,就可以把 dev 合并到 master 上。Git 怎么合并呢?最简单的方法,就是直接把 master 指向 dev 的当前提交,就完成了合并 .

所以 Git 合并分支也很快!就改改指针,工作区内容也不变!

合并完分支后,甚至可以删除 dev 分支。删除 dev 分支就是把 dev 指针给删掉,删掉后,我们就剩下了一条 master 分支.

2. 切换分支,git branch <name> ,如果name为 - 则为上一个分支:

63651-20170908132937991-1683911580.png

切换为上一个分支

63651-20170908133024413-690367079.png

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

63651-20170908111024772-643503878.png

63651-20170908111155288-294742108.png

4. 新建一个分支,指向指定 commit-ish 使用命令:$ git branch [branch] [commit-ish]

63651-20170908134134241-2117296784.png

上面创建了 dev3 分支且指向了 master 中首次提交的位置,切换到 dev3 查看日志如下:

63651-20170908134438476-888421004.png

master 上本来有两个提交记录的,此时的 dev3 指向的是第1次提交的位置

63651-20170908134547913-960980351.png

5. 新建一个分支,与指定的远程分支建立追踪关系使用命令:$ git branch --track [branch] [remote-branch]

63651-20170908160347741-1146762696.png

4.4.2 查看分支

1. 列出所有本地分支使用 $ git branch

63651-20170908160532413-665563097.png

2. 列表所有远程分支使用 $ git branch -r

63651-20170908160625554-32272071.png

3. 列出所有本地分支和远程分支使用 $ git branch -a

63651-20170908160704413-490309889.png

4.4.3 分支合并

合并指定分支到当前分支使用指令 $ git merge [branch]

这里的合并分支就是对分支的指针操作,我们先创建一个分支再合并到主分支:

63651-20170908200941007-525713587.png

这里的 file11.txt 主分支与 dev6 的内容现在是不同的,因为在 dev6 中已被修改过,可以使用指令查看:

63651-20170908201243038-1579475148.png

现在我们将 dev6 合并到主分支中去,从下图中可以看出 dev6 中有一次提交,而 master 并没有

63651-20170908201946241-1502411831.png

63651-20170908202307929-640297009.png

合并后在 master 上查看 file11.txt 文件内容与 dev6 上的内容就一样了,合并后 dev6 中多出的提交在 master 也拥有了。

63651-20170908202408257-864175348.png

4.4.4 解决冲突

如果同一个文件在合并分支时都被修改了则会引起冲突,如下所示:

提交前两个分支的状态:

63651-20170908210135757-25776448.png

在 dev6 分支中同样修改 file11.txt:

63651-20170908210227741-1265576286.png

dev6 与 master 分支中 file11.txt 文件都被修改且提交了,现在合并分支:

63651-20170908210610835-267872418.png

提示冲突,现在我们看看 file11.txt 在 master 分支中的状态:

63651-20170908210749319-1779643226.png

Git 用 <<<<<<<,====,>>>>>>> 标记出不同分支的内容,其中 <<<HEAD 是指主分支修改的内容>>>>>dev6 是指dev6上修改的内容。

解决的办法是我们可以修改冲突文件后重新提交,请注意当前的状态 master | MERGING:

63651-20170908211751257-770094797.png

重新提交后冲突解决:

63651-20170908212011241-1014866334.png

手动解决完冲突后就可以把此文件添加到索引 (index) 中去,用 git commit 命令来提交,就像平时修改了一个文件 一样。

git log --graph命令可以看到分支合并图。

63651-20170908212534382-1166076106.png

分支策略:

master 主分支应该非常稳定,用来发布新版本,一般情况下不允许在上面工作,工作一般情况下在新建的 dev 分支上工作,工作完后,比如上要发布,或者说 dev 分支代码稳定后可以合并到主分支 master 上来。

4.4.5 删除分支

删除本地分支可以使用命令:$ git branch -d [branch-name]-D (大写)强制删除

63651-20170908213554257-570203049.png

删除远程分支可以使用如下指令:

$ git push origin --delete [branch-name] 
$ git branch -dr [remote/branch]

-d:表示删除分支。分支必须完全合并在其上游分支,或者在 HEAD 上没有设置上游
-r: 表示远程的意思 remotes,如果 -dr 则表示删除远程分支.

63651-20170908215310460-364059006.png

4.5 Git GUI 操作

通过命令行可以深刻地理解 Git,Git GUIIDE 插件 却可以更加直观操作 Git,常用的 Git GUI 有如下这些:

4.5.1 GitHub for Desktop

全球开发人员交友俱乐部提供的强大工具,功能完善,使用方便。对于使用GitHub的开发人员来说是非常便捷的工具。

63651-20170907140035413-1131037433.png

GitHub for Desktop 不带三方合并工具,你必须自己手动解决冲突才可以。

  • 免费
  • 同时支持 Windows 和 Mac:对于需要经常在不同的操作系统间切换的开发人员来说非常方便
  • 漂亮的界面:作为每天盯着看的工具,颜值是非常重要的
  • 支持 Pull Request:直接从客户端提交PR,很方便
  • Timeline 支持:直接在时间线上显示每次提交的时间点和大小
  • 支持 git LFS:存储大文件更加节省空间和高效
  • 不支持三方合并:需要借助第三方工具才行

4.5.2 Source Tree

SourceTree 是老牌的 Git GUI 管理工具了,也号称是最好用的 Git GUI 工具。强大,功能丰富,基本操作和高级操作都设计得非常流畅,适合初学者上手,支持 Git Flow。

63651-20170907140158757-544911682.png

  • 免费
  • 功能强大:无论你是新手还是重度用户,SourceTree 都会让你觉得很顺手。对于非常重度用户,Source Tree还支持自定义脚本的执行。
  • 同时支持 Windows 和 Mac 操作系统
  • 同时支持 Git 和 Mercurial 两种 VCS
  • 内置 GitHub, BitBucket 和 Stash 的支持:直接绑定帐号即可操作远程 repo

4.5.3 Tortoise Git

小乌龟,SVN 的超广泛使用也使得这个超好用的 SVN 客户端成了几乎每个开发人员的桌面必备软件。小乌龟只提供 Windows 版本,提供中文版支持的。

63651-20170907140326304-1891514624.png

  • 免费
  • 只支持 Windows 操作系统:与文件管理器的良好集成
  • 中文界面
  • 与 Tortoise SVN 一脉相承的操作体验

4.5.4 Git 集成 GUI 工具

安装 Git 时会集成安装 GUI 工具,在 Git 菜单下可以找到,特点是:免费、简单、不需要额外安装

63651-20170907140832085-1204207971.png

4.6 IDE 集成的 Git 客户端

对于使用 IDE 进行开发的程序员来说,可以不离开常用的 IDE 就直接操作源代码管理系统是最好的选择,以下是几个常见的 IDE 集成的 git 客户端:

4.6.1 Eclipse – Egit

作为 Java 集成开发环境的代表,Eclipse 内置了 egit 这个插件来提供 git 的集成支持。实话实说,这个插件的功能非常丰富,无论是普通的 clone, commit, pull/push 操作,还是复杂一些的 git flow 都有支持。

63651-20170907160153538-341592917.png

4.6.2 Visual Studio – Git Integration & GitHub Extension

VS 里面的 Git 支持已经相当的完善。直接克隆 GitHub 上的 repo

63651-20170907175457757-369811937.png

63651-20170907160233319-365419113.png

4.6.3 IntelliJ IDEA

63651-20170907160932882-1312828188.png

63651-20170907161123257-1702754976.png

4.7 帮助与代码统计

1. 帮助文档

完整地安装了 Git 后有一个官方帮助,这是最权威的资料,方法如下:

比如我们要查看 git commit 的使用

63651-20170908220526257-321639384.png

执行时会打开对应的 git 帮助文档,其实就在本地,当然您也可以去官网在线搜索.

地址: https://git-scm.com/docs。

63651-20170908220755226-1752282117.png

2. 信息查看与统计命令

# 统计某人的代码提交量,包括增加,删除:
$ git log --author="$(git config --get user.name)" --pretty=tformat: --numstat | gawk '{ add += $1 ; subs += $2 ; loc += $1 - $2 } END { printf 
"added lines: %s removed lines : %s total lines: %s\n",add,subs,loc }' -

# 仓库提交者排名前 5(如果看全部,去掉 head 管道即可):
$ git log --pretty='%aN' | sort | uniq -c | sort -k1 -n -r | head -n 5

# 仓库提交者(邮箱)排名前 5:这个统计可能不会太准,因为很多人有不同的邮箱,但会使用相同的名字
$ git log --pretty=format:%ae | gawk -- '{ ++c[$0]; } END { for(cc in c) printf "%5d %s\n",c[cc],cc; }' | sort -u -n -r | head -n 5 

# 贡献者统计:
$ git log --pretty='%aN' | sort -u | wc -l

# 提交数统计:
$ git log --oneline | wc -l 

# 显示有变更的文件
$ git status

# 显示当前分支的版本历史
$ git log

# 显示commit历史,以及每次commit发生变更的文件
$ git log --stat

# 搜索提交历史,根据关键词
$ git log -S [keyword]

# 显示某个commit之后的所有变动,每个commit占据一行
$ git log [tag] HEAD --pretty=format:%s

# 显示某个commit之后的所有变动,其"提交说明"必须符合搜索条件
$ git log [tag] HEAD --grep feature

# 显示某个文件的版本历史,包括文件改名
$ git log --follow [file]
$ git whatchanged [file]

# 显示指定文件相关的每一次diff
$ git log -p [file]

# 显示过去5次提交
$ git log -5 --pretty --oneline

# 显示所有提交过的用户,按提交次数排序
$ git shortlog -sn

# 显示指定文件是什么人在什么时间修改过
$ git blame [file]

# 显示暂存区和工作区的差异
$ git diff

# 显示暂存区和上一个commit的差异
$ git diff --cached [file]

# 显示工作区与当前分支最新commit之间的差异
$ git diff HEAD

# 显示两次提交之间的差异
$ git diff [first-branch]...[second-branch]

# 显示今天你写了多少行代码
$ git diff --shortstat "@{0 day ago}"

# 显示某次提交的元数据和内容变化
$ git show [commit]

# 显示某次提交发生变化的文件
$ git show --name-only [commit]

# 显示某次提交时,某个文件的内容
$ git show [commit]:[filename]

# 显示当前分支的最近几次提交
$ git reflog

示例:

63651-20170908221829116-134750466.png

五、远程仓库

Git 是分布式版本控制系统,同一个 Git 仓库,可以分布到不同的机器上,但开发参与者必须在同一个网络中,且必须有一个项目的原始版本,通常的办法是让一台电脑充当服务器的角色,每天24小时开机,其他每个人都从这个“服务器”仓库克隆一份到自己的电脑上,并且各自把各自的提交推送到服务器仓库里,也从服务器仓库中拉取别人的提交。完全可以自己搭建一台运行Git的服务器但现在更适合的做法是使用免费的托管平台。

同时相较于传统的代码都是管理到本机或者内网。 一旦本机或者内网机器出问题,代码可能会丢失,使用远端代码仓库将永远存在一个备份。同时也免去了搭建本地代码版本控制服务的繁琐。 云计算时代 Git 以其强大的分支和克隆功能,更加方便了开发者远程协作。

5.1 托管平台

Git 代码托管平台,首先推荐的是 GitHub,好多好的开源项目都来自 GitHub,但是 GitHub 只能新建公开的 Git 仓库,私有仓库要收费,有时候访问比较卡,如果你做的是一个开源项目,可以首选 GitHub。下面推荐几个比较好的 Git 代码托管平台:

5.1.1 GitHub

关于 GitHub 相信大家都有耳闻,这里就不详细介绍了。

63651-20170907163230647-1553459974.png

5.1.2 GitLab

对于有些人,提到 GitHub 就会自然的想到 GitLab, GitLab 支持无限的公有项目和私有项目。GitLab地址: https://about.gitlab.com/

63651-20170908232416038-78562400.png

5.1.3 Bitbucket

bitbucket 免费支持5个开发成员的团队创建无限私有代码托管库

bitbucket 地址:http://git.oschina.net/

63651-20170908232541022-628927929.png

5.1.4 开源中国代码托管

开源中国一个账号最多可以创建1000个项目,包含公有和私有,开源中国代码托管地址

63651-20170908231825210-161687220.png

5.1.5 coding.net

谈到 coding.net(推荐),首先必须提的是速度快,功能与开源中国相似,同样一个账号最多可以创建1000个项目(5个私有),也支持任务的创建等。

coding.net地址: https://coding.net/

1618268127204.png

个人比较推荐 Coding.net、GitHub

当然还有许多,如 CSDN,百度,阿里等

选择国外的主机请考虑网速,选择国内的主机请考虑稳定与安全性

5.2 申请帐号与设置

因为 coding.net 免费,可以创建私有项目,且速度不错,这里以 coding.net 为托管平台完成远程仓库的帐号申请与操作。

5.2.1 申请帐号

  1. 打开 https://coding.net/,点击右上角的注册按钮:

img

  1. 填写好注册信息通过邮箱或手机验证后注册就成功了,登录到个人首页

img

如果是QQ邮箱请注意激活邮件可能会被当着垃圾邮件,到垃圾箱中可以找到

img

5.2.2 创建项目

登录成功后,点击左侧菜单项目,点击 “+” 新建项目,这里创建的是一个公开项目,没有 Readme.md、许可证与忽视文件,原因是如果你本地已经有一个项目了,想提交到远程仓库而新创建的3个文件本地没有,当然有办法。但初学避免麻烦就不添加这三个文件了,输入相关信息后点击创建就成功了。

img

5.2.3 提交源代码到远程仓库

img

从上图可以看出创建地址有两种:

  • https 类型
  • SSH 类型

HTTPS(推荐轻量级用户使用)

使用加密的网页访问通道读写仓库,使用用户名及密码进行鉴权。 避免重复输入密码,查看 怎样在每次 Push 时不用重复输入密码?

提示:Git 用户名为 Coding 的账户邮箱或者个性后缀,密码为 Coding 的账户密码。
注意:HTTPS 方式 push 大文件可能引发错误,查看 Push 出错怎么办?

SSH(推荐资深用户或经常推送大型文件用户使用)

SSH全称(Secure Shell)是一种网络协议,顾名思义就是非常安全的 shell,主要用于计算机间加密传输。
使用加密通道读写仓库,无单次上传限制,需先设置 “账户 SSH 公钥”,完成配对验证。

导入仓库可以将已存在的 Git 项目或 SVN 项目直接导入。

在命令行创建项目:

# 1、创建目录
$ mkdir project7

# 2、进入目录
$ cd project7

# 3、初始化目录为git项目
$ git init

# 4、创建md文件追加内容# project7(一级标题)
$ echo "# project7" >> README.md

# 5、添加说明文件到暂存区
$ git add README.md

# 6、提交到本地仓库并写日志
$ git commit -m "first commit"

# 7、添加远程主机,主机名为 origin 地址为 https://git.coding.net/zhangguoGit/project7.git
$ git remote add origin https://git.coding.net/zhangguoGit/project7.git

# 8、本地的master分支推送到origin主机,同时指定origin为默认主机,后面就可以不加任何参数使用git push了,-u 参数指定一个默认主机
$ git push -u origin master

5.2.4 Markdown

Markdown 是一种轻量级标记语言,它允许人们使用易读易写的纯文本格式编写文档,然后转换成有效的 XHTML(或者HTML)文档。

Markdown 语法的目标是:成为一种适用于网络的书写语言。

1. 标题
# 一级标题
## 二级标题
### 三级标题
#### 四级标题
##### 五级标题
###### 六级标题

img

2. 列表

有序列表

1. 1
2. 2
3. 3

无序列表

- 1
- 2
- 3
3. 引用
> 这是引用
4. 图片和链接

两者格式区别在于 " ! "

![图片描述](图片链接)

[链接描述](链接地址)
5. 粗体和斜体
**这是粗体**
*这是斜体*
6. 表格
| Tables | Are | Cool |
| ------------ |:------------:| -----:|
| col 3 is | right-aligned| $1600 |
| col 2 is | centered | $12 |
| zebra stripes| are neat | &1 |
7. 代码框
用 `这个把代码包裹起来`
8. 分割线

输入 --- 即可

9. 示例

img

img

img

在线实时预览

5.3 远程仓库操作

申请到了 Git 远程仓库的帐号并创建了一个空的远程仓库现在我们就可以结合本地的仓库与远程仓库一起协同工作了,模拟多人协同开发。

5.3.1 *常用操作命令

# 下载远程仓库的所有变动
$ 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 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]

5.3.2 git clone

远程操作的第一步,通常是从远程主机克隆一个版本库,这时就要用到 git clone 命令。

$ git clone <版本库的地址>

实例:

$ git clone https://github.com/zhangguo5/AngularJS04_BookStore.git

该命令会在本地主机生成一个目录,与远程主机的版本库同名;如果要指定不同的目录名,可以将目录名作为 git clone 命令的第二个参数。

$ git clone <版本库的地址> <本地目录名>

该命令支持多种协议,除了HTTP(s)以外,还支持 SSH、Git、本地文件协议等,下面是一些例子:

$ git clone http[s]://example.com/path/to/repo.git/
$ git clone ssh://example.com/path/to/repo.git/
$ git clone git://example.com/path/to/repo.git/
$ git clone /opt/git/project.git 
$ git clone file:///opt/git/project.git
$ git clone ftp[s]://example.com/path/to/repo.git/
$ git clone rsync://example.com/path/to/repo.git/

SSH 协议还有另一种写法。

$ git clone [user@]example.com:path/to/repo.git/

通常来说,Git 协议下载速度最快,SSH 协议用于需要用户认证的场合。

各种协议优劣的详细讨论请参考 官方文档。

执行:

img

结果:

img

5.3.3 git remote

为了便于管理,Git 要求每个远程主机都必须指定一个主机名。git remote 命令就用于管理主机名。

不带选项的时候,git remote 命令列出所有远程主机。

$ git remote

img

使用 -v 选项,可以参看远程主机的网址。

$ git remote -v

img

上面命令表示,当前只有一台远程主机,叫做 origin,以及它的地址。

克隆版本库的时候,所使用的远程主机自动被 Git 命名为 origin

如果想用其他的主机名,需要用 git clone 命令的 -o 选项指定。

$ git clone -o WeUI https://github.com/Tencent/weui.git
$ git remote

img

上面命令表示,克隆的时候,指定远程主机叫做 WeUI。

git remote show :命令加上主机名,可以查看该主机的详细信息。

$ git remote show <主机名>

img

git remote add :命令用于添加远程主机。

$ git remote add <主机名> <网址>

img

git remote rm :命令用于删除远程主机。

$ git remote rm <主机名>

img

git remote rename :命令用于远程主机的改名。

$ git remote rename <原主机名> <新主机名>

img

5.3.4 git fetch

一旦远程主机的版本库有了更新/提交(Git术语叫做 commit),需要将这些更新取回本地,这时就要用到 git fetch 命令。

$ git fetch <远程主机名>

img

上面命令将某个远程主机的更新,全部取回本地。

git fetch命令通常用来查看其他人的进程,因为它取回的代码对你本地的开发代码没有影响。

默认情况下,git fetch 取回所有分支(branch)的更新。如果只想取回特定分支的更新,可以指定分支名。

$ git fetch <远程主机名> <分支名>

img

比如,取回 origin 主机的 master 分支。

$ git fetch origin master

所取回的更新,在本地主机上要用 “远程主机名/分支名” 的形式读取。比如 origin 主机的 master ,就要用 origin/master 读取。

git branch

  • -r 选项:可以用来查看远程分支
  • -a 选项:查看所有分支
$ git branch -r
origin/master

$ git branch -a
* master
  remotes/origin/master

上面命令表示,本地主机的当前分支是 master ,远程分支是 origin/master

取回远程主机的更新以后,可以在它的基础上,使用 git checkout -b 命令创建一个新的分支。

# 在 `origin/master` 的基础上,创建一个新分支!
$ git checkout -b newBrach origin/master

此外,也可以使用 git merge 命令或者 git rebase 命令,在本地分支上合并远程分支。

$ git merge origin/master
# 或者
$ git rebase origin/master

上面命令表示在当前分支上,合并 origin/master

5.3.5 git pull

git pull取回远程主机某个分支的更新,再与本地的指定分支合并。

$ git pull <远程主机名> <远程分支名>:<本地分支名>

比如,取回 origin 主机的 next 分支,与本地的 master 分支合并:

$ git pull origin next:master

img

如果远程分支是与当前分支合并,则冒号后面的部分可以省略。

# next --> 远程分支名
$ git pull origin next
# master --> 远程分支名
$ git pull --rebase origin master

*git pull origin next 命令表示:取回 origin/next 分支,再与当前分支合并

*实质上,这等同于先做 git fetch,再做 git merge.

$ git fetch origin
$ git merge origin/next

在某些场合,Git 会自动在本地分支与远程分支之间,建立一种追踪关系(tracking)。比如,git clone 的时候,所有本地分支默认与远程主机的同名分支,建立追踪关系。也就是说,本地的 master 分支自动 “追踪” origin/master分支。

Git 也允许手动建立追踪关系.

$ git branch --set-upstream-to origin/next master

上面命令指定 master 分支追踪 origin/next 分支。

追踪的原因:如果当前分支与远程分支存在追踪关系,git pull 就可以省略远程分支名。

# 在当前分支不仅仅只有一个追踪分支的情况下,需要加 <远程主机名>
$ git pull origin

上面命令表示,本地的当前分支自动与对应的 origin 主机"追踪分支"(remote-tracking branch)进行合并。

如果当前分支只有一个追踪分支,连远程主机名(origin)都可以省略。

$ git pull

上面命令表示,当前分支自动与唯一 一个追踪分支进行合并。

如果合并需要采用 rebase 模式,可以使用 --rebase 选项。

$ git pull --rebase <远程主机名> <远程分支名>:<本地分支名>

如果远程主机删除了某个分支,默认情况下,git pull 不会在拉取远程分支的时候,删除对应的本地分支。这是为了防止,由于其他人操作了远程主机,导致 git pull 不知不觉删除了本地分支。

但是,你可以改变这个行为,加上参数 -p 就会在执行 git pull 后在本地删除远程已经删除的分支。

$ git pull -p
# 等同于下面的命令
$ git fetch --prune origin 
$ git fetch -p

5.3.6 git push

git push:命令用于将本地分支的更新,推送到远程主机;它的格式与 git pull 命令相仿。

$ git push <远程主机名> <本地分支名>:<远程分支名>

注意:分支推送顺序的写法是 <来源地>:<目的地>,所以 git pull 是<远程分支>:<本地分支>,而git push是<本地分支>:<远程分支>。

如果省略远程分支名,则表示将本地分支推送与之存在 “追踪关系” 的远程分支(通常两者同名),如果该远程分支不存在,则会被新建。

$ git push origin master

img

上面命令表示,将本地的 master 分支推送到 origin 主机的 master 分支。如果后者不存在,则会被新建。

如果省略本地分支名,则表示删除指定的远程分支,因为这等同于推送一个空的本地分支到远程分支。

$ git push origin :master
# 等同于
$ git push origin --delete master

img

上面命令表示删除 origin 主机的 master 分支。

如果当前分支与远程分支之间存在追踪关系,则本地分支和远程分支都可以省略。

$ git push origin

上面命令表示,将当前分支推送到 origin 主机的对应分支。

img

如果是新建分支第一次 push,会提示:
fatal: The current branch dev1 has no upstream branch. To push the current branch and set the remote as upstream, use git push --set-upstream origin dev1.

输入这行命令,然后输入用户名和密码,就 push 成功了。

以后的 push 就只需要输入 git push origin

# 因为在git的全局配置中,有一个 push.default 属性,其决定了 git push 操作的默认行为。
# 在Git 2.0之前,这个属性的默认被设为 'matching',2.0之后则被更改为了 'simple'。

# 我们可以通过 git version 确定当前的git版本(如果小于2.0,更新是个更好的选择)
# 通过 git config --global push.default 'option' 改变 push.default 的默认行为(或者也可直接编辑~/.gitconfig文件)。

push.default 有以下几个可选值option:
	nothing: push操作无效,除非显式指定远程分支,例如 $ git push origin develop
	current: push当前分支到远程同名分支,如果远程同名分支不存在则自动创建同名分支
	upstream: push当前分支到它的 upstream 分支上(这一项其实用于经常从本地分支 push/pull 到同一远程仓库的情景,这种模式叫做central workflow)
	simple: simple和upstream是相似的,只有一点不同,simple 必须保证本地分支和它的远程 upstream 分支同名,否则会拒绝 push 操作
	matching: push所有本地和远程两端都存在的同名分支

因此如果我们使用了git2.0之前的版本,push.default = matching,git push后则会推送当前分支代码到远程分支,而2.0之后,push.default = simple,如果没有指定当前分支的upstream分支,就会收到上文的fatal提示。

如果当前分支只有一个追踪分支,那么主机名都可以省略。

$ git push

如果当前分支与多个主机存在追踪关系,则可以使用 -u 选项指定一个默认主机,这样后面就可以不加任何参数使用 git push

$ git push -u origin master

上面命令将本地的 master 分支推送到 origin 主机,同时指定 origin 为默认主机,后面就可以不加任何参数使用 git push 了。

不带任何参数的 git push,默认只推送当前分支,这叫做 simple 方式。此外,还有一种 matching 方式,会推送所有有对应的远程分支的本地分支。Git 2.0 版本之前,默认采用 matching 方法,现在改为默认采用 simple 方式。如果要修改这个设置,可以采用 git config 命令。

$ git config --global push.default matching
# 或者
$ git config --global push.default simple

还有一种情况,就是不管是否存在对应的远程分支,将本地的所有分支都推送到远程主机,这时需要使用 --all 选项。

$ git push --all origin

上面命令表示,将所有本地分支都推送到 origin 主机。

如果远程主机的版本比本地版本更新,推送时Git会报错,要求先在本地做 git pull 合并差异,然后再推送到远程主机。这时,如果你一定要推送,可以使用 --force选项。

$ git push --force origin 

上面命令使用 --force 选项,结果导致远程主机上更新的版本被覆盖。除非你很确定要这样做,否则应该尽量避免使用 --force 选项。

最后,git push 不会推送标签(tag),除非使用 --tags 选项。

$ git push origin --tags

以上就是有关 Git 的常用操作啦~

😆码字不易,感谢阅读~
💖特别鸣谢:zhangguo https://blog.csdn.net/zhangguo5
🐱‍👓GitHub Zone

TAG

网友评论

共有访客发表了评论
请登录后再发布评论,和谐社会,请文明发言,谢谢合作! 立即登录 注册会员