一个小时学会Git

最近要与部门同事一起做技术分享,我选择了Git,因为Git 是一种在全球范围都广受欢迎的版本控制系统。在开发过程中,为了跟踪代码,文档,项目等信息中的变化,版本控制变得前所未有的重要。

一、版本控制概要

1.1、什么是版本控制

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

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

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

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

未分类

1.2、常用术语

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)

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

1.3、常见的版本控制器

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

  • 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

1.4、版本控制分类

1.4.1、本地版本控制

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

未分类

1.4.2、集中版本控制

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

未分类

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

1.4.3、分布式版本控制

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

未分类

1.5、Git与SVN最主要区别

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

未分类

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

二、Git安装与配置

未分类

2.1、什么是Git

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

Git是免费、开源的

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

未分类

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

优点:

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

缺点:

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

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

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

2.2、搭建Git工作环境

2.2.1、下载Git

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

未分类

选择版本:

未分类

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

未分类

2.2.2、安装Git

未分类

选择安装配置信息

未分类

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

2.2.3、启动Git

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

未分类

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

未分类

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

Git CMD:Windows风格的命令行

未分类

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

未分类

点击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环境详细配置

未分类

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

#查看系统config
git config --system --list
  
#查看当前用户(global)配置
git config --global  --list

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

2.3.2、Git配置文件分类

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

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

1)、 /etc/gitconfig:包含了适用于系统所有用户和所有项目的值。(Win:C:Program FilesGitmingw64etcgitconfig) –system 系统级

未分类

2)、~/.gitconfig:只适用于当前登录用户的配置。(Win:C:UsersAdministrator.gitconfig) –global 全局

未分类

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

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

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

2.3.3、设置用户名与邮箱(用户标识,必要)

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

$ git config --global user.name "zhangguo"  #名称
$ git config --global user.email [email protected]   #邮箱

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

未分类

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的配置项,执行结果如下:

未分类

**2)、删除配置项 **

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

将系统级的height配置项移除

未分类

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  #忽略修改权限的文件  

所有config命令参数

语法: git config [<options>]        

文件位置        
    --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    从给定的对象中读取配置

动作        
    --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 ]

类型        
    --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)    值是路径(文件或目录名)

其它        
    -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操作

4.1、git基础

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

未分类

未分类

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

未分类

  • Workspace:工作区
  • Index / Stage:暂存区
  • Repository:仓库区(或本地仓库)
  • Remote:远程仓库

未分类

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

4.2、获得GIT仓库

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

未分类

4.2.1、创建全新仓库

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

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

执行:

未分类

结果:

未分类

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

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

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

执行命令与运行结果:

未分类

4.2.2、克隆远程仓库

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

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

执行:

比如我们要从克隆的远程仓库托管在github上,地址为:https://github.com/zhangguo5/SuperPlus.git,这是一个公开的项目

未分类

未分类

结果:

未分类

4.3、GIT文件操作

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

4.3.1、文件4种状态

未分类

  • Untracked: 未跟踪, 此文件在文件夹中, 但并没有加入到git库, 不参与版本控制. 通过git add 状态变为Staged.

  • Unmodify: 文件已经入库, 未修改, 即版本库中的文件快照内容与文件夹中完全一致. 这种类型的文件有两种去处, 如果它被修改, 而变为Modified. 如果使用git rm移出版本库, 则成为Untracked文件

  • Modified: 文件已修改, 仅仅是修改, 并没有进行其他的操作. 这个文件也有两个去处, 通过git add可进入暂存staged状态, 使用git checkout 则丢弃修改过, 返回到unmodify状态, 这个git checkout即从库中取出文件, 覆盖当前修改

  • Staged: 暂存状态. 执行git commit则将修改同步到库中, 这时库中的文件和本地文件又变为一致, 文件为Unmodify状态. 执行git reset HEAD filename取消暂存, 文件状态为Modified

未分类

4.3.2、查看文件状态

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

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

#查看所有文件状态
git status

命令:

未分类

结果:

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

GIT在这一点做得很好,在输出每个文件状态的同时还说明了怎么操作,像上图就有怎么暂存、怎么跟踪文件、怎么取消暂存的说明。

4.3.3、添加文件与目录

未分类

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

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

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

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

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

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

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

执行:

未分类

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

未分类

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

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

执行命令

未分类

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

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

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

示例:把f1.txt文件从暂存区撤回工作区

未分类

移除所有未跟踪文件

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

示例:

未分类

移除前:

未分类

执行移除:

未分类

移除后:

未分类

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

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

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

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

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

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

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

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

4.3.5、查看文件修改后的差异

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

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

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

命令:

未分类

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

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

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

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

4.3.6、签出

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

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

语法:

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

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

未分类

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

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

$ git checkout HEAD
#同上

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

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

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

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

示例:

未分类

4.3.6、忽略文件

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

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

  • 忽略文件中的空行或以井号(#)开始的行将会被忽略。

  • 可以使用Linux通配符。例如:星号(*)代表任意多个字符,问号(?)代表一个字符,方括号([abc])代表可选字符范围,大括号({string1,string2,…})代表可选的字符串等。

  • 如果名称的最前面有一个感叹号(!),表示例外规则,将不被忽略。

  • 如果名称的最前面是一个路径分隔符(/),表示要忽略的文件在此目录下,而子目录中的文件不忽略。

  • 如果名称的最后面是一个路径分隔符(/),表示要忽略的是此目录下该名称的子目录,而非文件(默认文件或目录都忽略)。

如:

#为注释
*.txt #忽略所有 .txt结尾的文件
!lib.txt #但lib.txt除外
/temp #仅忽略项目根目录下的TODO文件,不包括其它目录temp
build/ #忽略build/目录下的所有文件
doc/*.txt #会忽略 doc/notes.txt 但不包括 doc/server/arch.txt

更多规则: http://www.cnblogs.com/kevingrace/p/5690241.html

示例:

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

未分类

查看状态:

未分类

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

针对各种语言与项目的Git忽视文件:

https://github.com/kaedei/gitignore https://github.com/github/gitignore

通用的java忽视文件:

# 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*

通用的Visual Studio开发项目忽视文件:

## Ignore Visual Studio temporary files, build results, and
## files generated by popular Visual Studio add-ons.
##
## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore

# User-specific files
*.suo
*.user
*.userosscache
*.sln.docstates

# User-specific files (MonoDevelop/Xamarin Studio)
*.userprefs

# Build results
[Dd]ebug/
[Dd]ebugPublic/
[Rr]elease/
[Rr]eleases/
x64/
x86/
bld/
[Bb]in/
[Oo]bj/
[Ll]og/

# Visual Studio 2015 cache/options directory
.vs/
# Uncomment if you have tasks that create the project's static files in wwwroot
#wwwroot/

# MSTest test Results
[Tt]est[Rr]esult*/
[Bb]uild[Ll]og.*

# NUNIT
*.VisualState.xml
TestResult.xml

# Build Results of an ATL Project
[Dd]ebugPS/
[Rr]eleasePS/
dlldata.c

# Benchmark Results
BenchmarkDotNet.Artifacts/

# .NET Core
project.lock.json
project.fragment.lock.json
artifacts/
**/Properties/launchSettings.json

*_i.c
*_p.c
*_i.h
*.ilk
*.meta
*.obj
*.pch
*.pdb
*.pgc
*.pgd
*.rsp
*.sbr
*.tlb
*.tli
*.tlh
*.tmp
*.tmp_proj
*.log
*.vspscc
*.vssscc
.builds
*.pidb
*.svclog
*.scc

# Chutzpah Test files
_Chutzpah*

# Visual C++ cache files
ipch/
*.aps
*.ncb
*.opendb
*.opensdf
*.sdf
*.cachefile
*.VC.db
*.VC.VC.opendb

# Visual Studio profiler
*.psess
*.vsp
*.vspx
*.sap

# TFS 2012 Local Workspace
$tf/

# Guidance Automation Toolkit
*.gpState

# ReSharper is a .NET coding add-in
_ReSharper*/
*.[Rr]e[Ss]harper
*.DotSettings.user

# JustCode is a .NET coding add-in
.JustCode

# TeamCity is a build add-in
_TeamCity*

# DotCover is a Code Coverage Tool
*.dotCover

# AxoCover is a Code Coverage Tool
.axoCover/*
!.axoCover/settings.json

# Visual Studio code coverage results
*.coverage
*.coveragexml

# NCrunch
_NCrunch_*
.*crunch*.local.xml
nCrunchTemp_*

# MightyMoose
*.mm.*
AutoTest.Net/

# Web workbench (sass)
.sass-cache/

# Installshield output folder
[Ee]xpress/

# DocProject is a documentation generator add-in
DocProject/buildhelp/
DocProject/Help/*.HxT
DocProject/Help/*.HxC
DocProject/Help/*.hhc
DocProject/Help/*.hhk
DocProject/Help/*.hhp
DocProject/Help/Html2
DocProject/Help/html

# Click-Once directory
publish/

# Publish Web Output
*.[Pp]ublish.xml
*.azurePubxml
# Note: Comment the next line if you want to checkin your web deploy settings,
# but database connection strings (with potential passwords) will be unencrypted
*.pubxml
*.publishproj

# Microsoft Azure Web App publish settings. Comment the next line if you want to
# checkin your Azure Web App publish settings, but sensitive information contained
# in these scripts will be unencrypted
PublishScripts/

# NuGet Packages
*.nupkg
# The packages folder can be ignored because of Package Restore
**/packages/*
# except build/, which is used as an MSBuild target.
!**/packages/build/
# Uncomment if necessary however generally it will be regenerated when needed
#!**/packages/repositories.config
# NuGet v3's project.json files produces more ignorable files
*.nuget.props
*.nuget.targets

# Microsoft Azure Build Output
csx/
*.build.csdef

# Microsoft Azure Emulator
ecf/
rcf/

# Windows Store app package directories and files
AppPackages/
BundleArtifacts/
Package.StoreAssociation.xml
_pkginfo.txt
*.appx

# Visual Studio cache files
# files ending in .cache can be ignored
*.[Cc]ache
# but keep track of directories ending in .cache
!*.[Cc]ache/

# Others
ClientBin/
~$*
*~
*.dbmdl
*.dbproj.schemaview
*.jfm
*.pfx
*.publishsettings
orleans.codegen.cs

# Since there are multiple workflows, uncomment next line to ignore bower_components
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
#bower_components/

# RIA/Silverlight projects
Generated_Code/

# Backup & report files from converting an old project file
# to a newer Visual Studio version. Backup files are not needed,
# because we have git ;-)
_UpgradeReport_Files/
Backup*/
UpgradeLog*.XML
UpgradeLog*.htm

# SQL Server files
*.mdf
*.ldf
*.ndf

# Business Intelligence projects
*.rdl.data
*.bim.layout
*.bim_*.settings

# Microsoft Fakes
FakesAssemblies/

# GhostDoc plugin setting file
*.GhostDoc.xml

# Node.js Tools for Visual Studio
.ntvs_analysis.dat
node_modules/

# Typescript v1 declaration files
typings/

# Visual Studio 6 build log
*.plg

# Visual Studio 6 workspace options file
*.opt

# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
*.vbw

# Visual Studio LightSwitch build output
**/*.HTMLClient/GeneratedArtifacts
**/*.DesktopClient/GeneratedArtifacts
**/*.DesktopClient/ModelManifest.xml
**/*.Server/GeneratedArtifacts
**/*.Server/ModelManifest.xml
_Pvt_Extensions

# Paket dependency manager
.paket/paket.exe
paket-files/

# FAKE - F# Make
.fake/

# JetBrains Rider
.idea/
*.sln.iml

# CodeRush
.cr/

# Python Tools for Visual Studio (PTVS)
__pycache__/
*.pyc

# Cake - Uncomment if you are using it
# tools/**
# !tools/packages.config

# Tabs Studio
*.tss

# Telerik's JustMock configuration file
*.jmconfig

# BizTalk build output
*.btp.cs
*.btm.cs
*.odx.cs
*.xsd.cs

4.3.7、提交

通过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] ...

示例:

提交前的状态

未分类

提交:

未分类

提交后的状态:

未分类

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

修订提交

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

#修订提交
git commit --amend

撤销提交(commit)

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

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

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

示例:

未分类

撤销提交

git revert <commit-id>

这条命令会把指定的提交的所有修改回滚,并同时生成一个新的提交。

4.3.8、日志与历史

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

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

示例:

未分类

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

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

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

未分类

几乎所有输入过的都被记录下来的,不愧是做版本控制的。

查看所有分支日志

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

未分类

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])*

示例:

未分类

4.3.10、撤销更新

1)、撤销暂存区更新

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

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

未分类

2)、撤销本地仓库更新

使用git log查看提交日志

未分类

撤销提交有两种方式:使用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

回退前:

未分类

回退后:

未分类

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

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

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

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

4.3.11、删除文件

1)、删除未跟踪文件

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

未分类

2)、删除已提交文件

未分类

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

撤销删除:

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

未分类

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

未分类

使用git reset HEAD …同样可以实现上面的功能

4.3.12、文件操作小结

未分类

Git很强大,很灵活,这是毋庸置疑的。但也正因为它的强大造成了它的复杂,因此会有很多奇奇怪怪的问题出现,多用就好了。

4.4、GIT分支

分支在GIT中相对较难

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

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

未分类

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

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

Git分支的速度非常快。

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

未分类

未分类

未分类

git分支中常用指令:

# 列出所有本地分支
$ 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]

4.4.1、新建分支与切换分支

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

未分类

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

未分类

切换分支到dev1后的结果:

未分类

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

当我们创建新的分支,例如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为-则为上一个分支

未分类

切换为上一个分支

未分类

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

未分类

未分类

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

未分类

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

未分类

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

未分类

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

未分类

4.4.2、查看分支

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

未分类

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

未分类

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

未分类

4.4.3、分支合并

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

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

未分类

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

未分类

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

未分类

未分类

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

未分类

4.4.4、解决冲突

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

提交前两个分支的状态

未分类

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

未分类

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

未分类

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

未分类

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

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

未分类

重新提交后冲突解决:

未分类

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

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

未分类

**分支策略*

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

4.4.5、删除分支

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

未分类

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

$ git push origin --delete [branch-name]

$ git branch -dr [remote/branch]

-d表示删除分支。分支必须完全合并在其上游分支,或者在HEAD上没有设置上游

-r表示远程的意思remotes,如果-dr则表示删除远程分支

未分类

4.5、Git GUI 操作

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

4.5.1、GitHub for Desktop

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

未分类

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

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

4.5.2、Source Tree

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

未分类

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

4.5.3、TortoiseGit

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

未分类

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

4.5.4、Git集成Gui工具

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

未分类

4.6、IDE集成的Git客户端

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

4.6.1、Eclipse – Egit

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

未分类

4.6.2、Visual Studio – Git Integration & GitHub Extension

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

未分类

未分类

4.6.3、IntelliJ IDEA

未分类

未分类

4.7、帮助与代码统计

1)、帮助文档

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

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

未分类

执行时会打开对应的git帮助文档,其实就在本地,当然您也可以去官网在线搜索,地址是:https://git-scm.com/docs。

未分类

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: %sn",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 %sn",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

示例:

未分类

五、远程仓库

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

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

5.1、托管平台

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

5.1.1、GitHub

关于GItHub相信大家都有耳闻,我就不详细介绍了。GitHub地址:https://github.com/,其首页如图:

未分类

5.1.2、Gitlab

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

未分类

5.1.3、Bitbucket

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

未分类

5.1.4、开源中国代码托管

开源中国一个账号最多可以创建1000个项目,包含公有和私有,开源中国代码托管地址:http://git.oschina.net/,其首页如图:

未分类

5.1.5、(推荐)coding.net

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

未分类

我个人比较推荐Coding.net、GItHub。

当然还有许多,如CSDN,百度,阿里等,欢迎大家比较后推荐。

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

5.2、申请帐号与设置

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

5.2.1、申请帐号

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

未分类

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

未分类

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

未分类

5.2.2、创建项目

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

未分类

5.2.3、提交源代码到远程仓库

未分类

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

https 类型的:https://git.coding.net/zhangguoGit/project7.git

SSH类型的:[email protected]:zhangguoGit/project7.git

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

如果创建已经创建则只需要第7步与第8步就好了。

5.2.4、Markdown文件(.md文件)

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

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

1.标题

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

####### 七级标题

效果:

未分类

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.分割线

输入***即可。

示例:

大标题      
===================================    
  大标题一般显示工程名,类似html的<h1><br />     
  你只要在标题下面跟上=====即可     


中标题     
-----------------------------------     
  中标题一般显示重点项,类似html的<h2><br />     
  你只要在标题下面输入------即可     
#       
### 小标题     
  小标题类似html的<h3><br />     
  小标题的格式如下 ### 小标题<br />     
  注意#和标题字符中间要有空格     

### 注意!!!下面所有语法的提示我都先用小标题提醒了!!!      

### 单行文本框     
    这是一个单行的文本框,只要两个Tab再输入文字即可     

### 多行文本框       
    这是一个有多行的文本框     
    你可以写入代码等,每行文字只要输入两个Tab再输入文字即可     
    这里你可以输入一段代码     

### 比如我们可以在多行文本框里输入一段代码,来一个Java版本的HelloWorld吧     
public class HelloWorld {     

/**     
* @param args     
*/     
public static void main(String[] args) {     
   ```System.out.println("HelloWorld!"); ```     
   }     
}    
### 链接     
1.[点击这里你可以链接到www.baidu.com](http://www.baidu.com)<br />     
2.[点击这里我你可以链接到我的博客](<a target=_blank href="http://www.cnblogs.com/best">http://www.cnblogs.com/best</a>)<br />     

###只是显示图片     
![github](https://pic.cnblogs.com/avatar/63651/20170217085118.png"github") 

### 文字被些字符包围     
> 文字被些字符包围     
>     
> 只要再文字前面加上>空格即可     
>     
> 如果你要换行的话,新起一行,输入>空格即可,后面不接文字     
> 但> 只能放在行首才有效     

### 文字被些字符包围,多重包围     
> 文字被些字符包围开始     
>     
> > 只要再文字前面加上>空格即可     
>     
>  > > 如果你要换行的话,新起一行,输入>空格即可,后面不接文字     
>     
> > > > 但> 只能放在行首才有效     

### 特殊字符处理     
有一些特殊字符如<,#等,只要在特殊字符前面加上转义字符即可<br />     
你想换行的话其实可以直接用html标签<br />

对应的HTML:

<h1>大标题      </h1>

<p>大标题一般显示工程名,类似html的<h1><br /> <br>
  你只要在标题下面跟上=====即可     </p>

<h2>中标题     </h2>

<p>中标题一般显示重点项,类似html的<h2><br /> <br>
  你只要在标题下面输入------即可     </p>

<h1> </h1>

<h3>小标题</h3>

<p>小标题类似html的<h3><br /> <br>
  小标题的格式如下 ### 小标题<br /> <br>
  注意#和标题字符中间要有空格     </p>

<h3>注意!!!下面所有语法的提示我都先用小标题提醒了!!!</h3>

<h3>单行文本框</h3>

<pre><code>这是一个单行的文本框,只要两个Tab再输入文字即可     
</code></pre>

<h3>多行文本框</h3>

<pre><code>这是一个有多行的文本框     
你可以写入代码等,每行文字只要输入两个Tab再输入文字即可     
这里你可以输入一段代码     
</code></pre>

<h3>比如我们可以在多行文本框里输入一段代码,来一个Java版本的HelloWorld吧</h3>

<p>public class HelloWorld {     </p>

<p>/** <br>
* @param args <br>
*/ <br>
public static void main(String[] args) { <br>
   <code>System.out.println("HelloWorld!");</code> <br>
   } <br>
}    </p>

<h3>链接</h3>

<p>1.<a href="http://www.baidu.com">点击这里你可以链接到www.baidu.com</a><br /> <br>
2.[点击这里我你可以链接到我的博客](<a target=_blank href="http://www.cnblogs.com/best">http://www.cnblogs.com/best</a>)<br />     </p>

<h3>只是显示图片</h3>

<p><img src="https://pic.cnblogs.com/avatar/63651/20170217085118.png" alt="github" title="github" /> </p>

<h3>文字被些字符包围</h3>

<blockquote>
  <p>文字被些字符包围     </p>

  <p>只要再文字前面加上>空格即可     </p>

  <p>如果你要换行的话,新起一行,输入>空格即可,后面不接文字 <br>
  但> 只能放在行首才有效     </p>
</blockquote>

<h3>文字被些字符包围,多重包围</h3>

<blockquote>
  <p>文字被些字符包围开始     </p>

  <blockquote>
    <p>只要再文字前面加上>空格即可     </p>

    <blockquote>
      <p>如果你要换行的话,新起一行,输入>空格即可,后面不接文字     </p>

      <blockquote>
        <p>但> 只能放在行首才有效     </p>
      </blockquote>
    </blockquote>
  </blockquote>
</blockquote>

<h3>特殊字符处理</h3>

<p>有一些特殊字符如&lt;,#等,只要在特殊字符前面加上转义字符即可<br /> <br>
你想换行的话其实可以直接用html标签<br />    </p>

结果:

未分类

未分类

未分类

在线实时预览工具

未分类

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 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]

5.3.2、git clone 克隆

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

$ git clone <版本库的网址>

比如,克隆一个上课示例的版本库。

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

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

$ 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协议用于需要用户认证的场合。各种协议优劣的详细讨论请参考官方文档。

示例:

未分类

结果:

未分类

5.3.3、git remote

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

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

$ git remote

未分类

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

$ git remote -v

未分类

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

克隆版本库的时候,所使用的远程主机自动被Git命名为origin。如果想用其他的主机名,需要用git clone命令的-o选项指定。

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

未分类

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

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

$ git remote show <主机名>

未分类

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

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

未分类

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

$ git remote rm <主机名>

未分类

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

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

未分类

5.3.4、git fetch

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

$ git fetch <远程主机名>

未分类

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

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

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

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

未分类

比如,取回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命令创建一个新的分支。

$ git checkout -b newBrach origin/master

上面命令表示,在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

未分类

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

$ 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 master origin/next

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

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

$ git pull origin

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

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

$ git pull

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

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

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

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

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

$ 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

未分类

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

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

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

未分类

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

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

$ git push origin

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

未分类

如果是新建分支第一次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 有以下几个可选值:
nothing, current, upstream, simple, matching

其用途分别为:
nothing - push操作无效,除非显式指定远程分支,例如git push origin develop(我觉得。。。可以给那些不愿学git的同事配上此项)。
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

5.4、在命令行中同步本地仓库示例

假定我们创建好了一个远程仓库地址为:https://coding.net/u/zhangguo5/p/project7/git,现在我们在本地创建一个项目并同步到远程仓库中。

1)、创建文件添加到暂存区

未分类

2)、提交到本地仓库

未分类

3)、提交到远程仓库

添加远程主机地址:

未分类

推送文件:

未分类

结果:

未分类

说明:这里我使用的是SSH方式提交的,所有并没有让我输入用户名与密码,如果你使用https方式提交则要配置用户名与邮箱,还要输入密码。

99%的时间在使用的Git命令

Git是目前最流行的分布式版本控制系统,它是Linus献给软件行业的两件礼物之一,另外一件礼物是目前最大的服务器系统软件Linux。

Git出现之前,linux的源代码使用BitMover公司的BitKeeper进行版本控制。这是一个商业的版本控制系统,一开始授权Linux社区免费使用,后来由于某种原因,BitMover公司打算收回了Linux社区的免费使用权。这个时候,Linus花了两周时间自己用C写了一个分布式版本控制系统,并在一个月之内托管了linux系统的源码,这一年,是2005年。

最常用的4条命令

Git是一个非常强大的工具,各种命令组合上千种。不过,我们90%的时间估计都在用这4条命令。

$ git status # 查看工作区和缓冲区状态
$ git add --all # 将工作区修改暂存到缓冲区
$ git commit -m"<comment>" # 提交到仓库
$ git push origin master # 推送到远程分支

如果只是个人开发,几天便结束的小项目,使用Git仅为了方便回退到某个点,记录开发进度,这几条命令当然就够了。

为了合作与规范,这还远远不够

关联远程仓库

  • 如果还没有Git仓库,你需要
$ git init
  • 如果你想关联远程仓库
$ git remote add <name> <git-repo-url>
# 例如 git remote add origin https://github.com/xxxxxx
  • 如果你想关联多个远程仓库
$ git remote add <name> <another-git-repo-url>
# 例如 git remote add coding https://coding.net/xxxxxx

是远程仓库的名称,通常为 origin

  • 忘了关联了哪些仓库或者地址
$ blog-react git:(master) git remote -v
# origin https://github.com/gzdaijie/koa-react-server-render-blog.git (fetch)
# origin https://github.com/gzdaijie/koa-react-server-render-blog.git (push)
  • 如果远程有仓库,你需要clone到本地
$ git clone <git-repo-url>

关联的远程仓库将被命名为origin,这是默认的。

  • 如果你想把别人仓库的地址改为自己的
$ git remote set-url origin <your-git-url>

切换分支

  • 新建仓库后,默认生成了master分支

  • 如果你想新建分支并切换

$ git checkout -b <new-branch-name>
# 例如 git checkout -b dev
# 如果仅新建,不切换,则去掉参数 -b
  • 看看当前有哪些分支
$ git branch
# * dev
#   master

标*号的代表当前所在的分支

  • 看看当前本地&远程有哪些分支
$ git branch -a
# * dev
#   master
#   remotes/origin/master
  • 切换到现有的分支
$ git checkout master
  • 你想把dev分支合并到master分支
$ git merge <branch-name>
# 例如 git merge dev
  • 你想把本地master分支推送到远程去
$ git push origin master

你可以使用git push -u origin master将本地分支与远程分支关联,之后仅需要使用git push即可。

  • 远程分支被别人更新了,你需要更新代码
$ git pull origin <branch-name>

之前如果push时使用过-u,那么就可以省略为git pull

  • 本地有修改,能不能先git pull
$ git stash # 工作区修改暂存
$ git pull  # 更新分支
$ git stash pop # 暂存修改恢复到工作区

撤销操作

  • 恢复暂存区文件到工作区
$ git checkout <file-name>
  • 恢复暂存区的所有文件到工作区
$ git checkout .
  • 重置暂存区的某文件,与上一次commit保持一致,但工作区不变
$ git reset <file-name>
  • 重置暂存区与工作区,与上一次commit保持一致
$ git reset --hard <file-name>

如果是回退版本(commit),那么file,变成commit的hash码就好了。

  • 去掉某个commit
$ git revert <commit-hash>

实质是新建了一个与原来完全相反的commit,抵消了原来commit的效果

版本回退与前进

  • 查看历史版本
$ git log
  • 你可能觉得这样的log不好看,试试这个
$ git log --graph --decorate --abbrev-commit --all
  • 检出到任意版本
$ git checkout a5d88ea

hash码很长,通常6-7位就够了

  • 远程仓库的版本很新,但是你还是想用老版本覆盖
$ git push origin master --force
# 或者 git push -f origin master
  • 觉得commit太多了?多个commit合并为1个
$ git rebase -i HEAD~4

这个命令,将最近4个commit合并为1个,HEAD代表当前版本。将进入VIM界面,你可以修改提交信息。推送到远程分支的commit,不建议这样做,多人合作时,通常不建议修改历史。

  • 想回退到某一个版本
$ git reset --hard <hash>
# 例如 git reset --hard a3hd73r

–hard代表丢弃工作区的修改,让工作区与版本代码一模一样,与之对应,–soft参数代表保留工作区的修改。

  • 想回退到上一个版本,有没有简便方法?
$ git reset --hard HEAD^
  • 回退到上上个版本呢?
$ git reset --hard HEAD^^

HEAD^^可以换作具体版本hash值。

  • 回退错了,能不能前进呀
$ git reflog

这个命令保留了最近执行的操作及所处的版本,每条命令前的hash值,则是对应版本的hash值。使用上述的git checkout 或者 git reset命令 则可以检出或回退到对应版本。

  • 刚才commit信息写错了,可以修改吗
$ git commit --amend
  • 看看当前状态吧
$ git status

配置属于你的Git

  • 看看当前的配置
$ git config --list
  • 估计你需要配置你的名字
$ git config --global user.name "<name>"

–global为可选参数,该参数表示配置全局信息

  • 希望别人看到你的commit可以联系到你
$ git config --global user.email "<email address>"
  • 有些命令很长,能不能简化一下
$ git config --global alias.logg "log --graph --decorate --abbrev-commit --all"

之后就可以开心地使用 git logg了

最后

这篇文章是对平时工作中最常用到的命令的一个总结,无论是初学者,还是已经使用了Git几年的你,都能有所收获吧。

如果你是第一次接触Git,那么这篇文章并不适合你,你需要先去了解Git的四个状态、三个区等概念。

使用Zabbix+Grafana监控

部署代码

https://github.com/liqiang311/zabbix-grafana

部署步骤

准备工作

下载部署代码,并且下载granafa插件

git clone https://github.com/liqiang311/zabbix-grafana.git
git clone https://github.com/alexanderzobnin/grafana-zabbix.git zabbix-grafana/grafana/plugins/grafana-zabbix

下载docker镜像

如何安装Docker和Docker-Compose见http://www.liqiang311.com/2017/09/docker-install/

docker pull mysql:5.7
docker pull zabbix/zabbix-server-mysql:latest
docker pull zabbix/zabbix-web-nginx-mysql:latest
docker pull grafana/grafana:latest

启动命令

cd zabbix-grafana
docker-compose up -d

配置

Zabbix

登录ip:10052,帐号为Admin,密码为zabbix

进入后右上角可以更改语言为中文

Grafana

webip:3000

默认帐号admin/admin

Plugins->app->Zabbix->点击Enable

添加Data Source

点击左上角Grafana图标,选择Data Sources->Add data Source

填写以下内容

Name: zabbix
Type: Zabbix
url: http://localhost:10052/api_jsonrpc.php
Access: proxy
Basic Auth: √
Basic Auth Details User: admin
Basic Auth Details Password: zabbix
Zabbix API details Username: admin
Zabbix API details Password: zabbix

然后点击下方 Save & Test。若成功连接,则按钮上方会显示绿色信息:

Success
Zabbix API version: 3.2.5

客户端安装

若要监控磁盘使用率、CPU等,需在主机上安装如下软件

apt-get install zabbix-agent

然后编辑如下配置文件

vim /etc/zabbix/zabbix_agentd.conf

将其中的85行的Server改为上文Zabbix配置的IP,如127.0.0.1

将其中的126行的ServerActive配置为上文Zabbix的server IP,如127.0.0.1:10051

保存文件退出。

重启zabbix-agent

service zabbix-agent restart

自定义监控选项

参考http://www.cnblogs.com/jjzd/p/6474193.html

在/etc/zabbix/zabbix_agentd.conf中底部添加如下代码:

UserParameter=gpu0.temp, nvidia-smi -q -g 0 2>&1|grep -i "gpu current temp"|awk '{print $5}'| sed s/%//g
UserParameter=gpu1.temp, nvidia-smi -q -g 1 2>&1|grep -i "gpu current temp"|awk '{print $5}'| sed s/%//g

UserParameter=cpu0.temp, sensors coretemp-isa-0000|grep Physical|awk '{print $4}'|cut -d "." -f1
UserParameter=cpu1.temp, sensors coretemp-isa-0001|grep Physical|awk '{print $4}'|cut -d "." -f1

重启zabbix-agent service zabbix-agent restart

在server中添加监控, 键值名为 gpu0.temp

Centos 7 Zabbix Agent 客户端源码编译安装配置

Zabbix Agent 安装在远程系统上,需要通过Zabbix服务器进行监控。Zabbix Agent在客户端系统上收集资源利用和应用程序数据,并向Zabbix服务器提供这些信息。Zabbix支持Ping,ZBX、SNMP、JMX、IPMI等监控方式。

1. 安装扩展包以及依赖包

$ yum -y install epel-release
$ yum install pcre pcre-devel openssl openssl-devel -y

2. 添加Zabbix用户和组

$ groupadd zabbix
$ useradd zabbix -g zabbix -s /sbin/nologin

3. 安装Zabbix-Agent

下载地址:https://www.zabbix.com/download

$ cd /tmp
$ tar -zxvf zabbix-3.4.1.tar.gz
$ cd zabbix-3.4.1
$ ./configure --prefix=/usr/local/zabbix --enable-agent --with-mysql --with-openssl
$ make && make install

4. 创建Zabbix日志目录并生成(PSK)密钥

$ mkdir -p /usr/local/zabbix/logs/
$ chown -R zabbix.zabbix /user/local/zabbix
$ sh -c "openssl rand -hex 32 > /usr/local/zabbix/etc/zabbix_agentd.psk"
$ cat /usr/local/zabbix/etc/zabbix_agentd.psk
fd1ac849e5f787dfc04300ae997d158e6f6f0c2209d66e7d2e687da2032ecbae

5. 配置zabbix_agentd.conf

以下是配置完成后的内容:

$ egrep -v "(^#|^$)" /usr/local/zabbix/etc/zabbix_agentd.conf

EnableRemoteCommands=1 #来至zabbix服务器的远程命令是否允许被执行
PidFile=/usr/local/zabbix/zabbix_agentd.pid
LogFile=/usr/local/zabbix/logs/zabbix_agentd.log
Server=10.10.204.65 #Zabbix Server IP 地址
ServerActive=10.10.204.65 #地址同上 主动向 Zabbix Server 发送监控内容
Hostname=101020465 #本机主机名 内容要和Zabbix Server 配置的 Host Name 一致
HostMetadataItem=system.uname #用于Item获取数据
User=zabbix
UnsafeUserParameters=1 #是否启用自定义key,zabbix监控mysql、tomcat等数据时需要自定义key
#下面使用预共享密钥(PSK)来保护服务器和客户端之间的连接
TLSConnect=psk
TLSAccept=psk
TLSPSKIdentity=PSK 001
TLSPSKFile=/usr/local/zabbix/etc/zabbix_agentd.psk

注意:关于更多Agent配置参数优化,请参阅这里(https://www.zabbix.com/documentation/3.4/zh/manual/appendix/config/zabbix_agentd)。

6. 创建systemctl系统Zabbix agent 单元文件

$ vim /usr/lib/systemd/system/zabbix-agent.service

[Unit]
Description=Zabbix Agent
After=syslog.target
After=network.target

[Service]
Environment="CONFFILE=/usr/local/zabbix/etc/zabbix_agentd.conf"
#EnvironmentFile=/usr/local/zabbix/etc/zabbix_agentd.conf.d/
Type=forking
Restart=on-failure
#PIDFile=/tmp/zabbix_agentd.pid
KillMode=control-group
ExecStart=/usr/local/zabbix/sbin/zabbix_agentd -c $CONFFILE
ExecStop=/bin/kill -SIGTERM $MAINPID
RestartSec=10s

[Install]
WantedBy=multi-user.target

7. 启动 Zabbix Agentd 客户端服务并加入开机自启动

$ systemctl start zabbix-agent
$ systemctl enable zabbix-agent

8. 设置 Firewalld 防火墙

$ firewall-cmd --permanent --add-port=10050/tcp
$ firewall-cmd --reload

已经完成 Zabbix Agent 的安装。后期我还会写一些关于zabbix的使用以及优化。

xtrabackup备份还原MySQL数据库

mysqldump 备份鉴于其自身的某些特性(锁表,本质上备份出来insert脚本或者文本,不支持差异备份),不太适合对实时性要求比较高的情况

Xtrabackup可以解决mysqldump存在的上述的一些问题,生产环境应用的也会更多一些。

本文简单测试一下Xtrabackup对MySQL数据库的备份还原操作。

本着先把功能先撸起来再深入细节的原则,粗略地实现了一个备份还原,并未深入细节。

网上有不少xtrabackup的文章,因为环境不一样,有些需要配置xtrabackup的配置文件,
但是我在xtrabackup 2.4.7版本下测试就需要需求任何配置文件。可能是每个版本都的细节上都不一样,因此参考资料的时候要注意版本和环境。

innobackupex 备份

xtrabackup和MySQL的版本如下

未分类

完整备份

innobackupex --defaults-file=/etc/my.cnf --user=root --password=root --socket=/var/lib/mysql/mysql.sock /data/backup

说明:

1、 –defaults-file=/etc/my.cnf文件必须在最前面
2、 –user=root –password=root,–use=与 –password= 中间一定要有空格,

如截图,完整备份完成

未分类

如截图,完整备份会创建一个日期(年月日时分秒,yyyy-MM-dd_hh-mm-ss)命名的文件

完整备份出来的内存,实际上是对所备份的数据库的数据文件的copy加上备份时候产生的一些信息,
比如xtrabackup_checkpoints就是当前完整备份的一些个信息,这个信息对差异备份非常重要。

未分类

差异备份

差异备份之所以能够做到差异,就是依赖于完整备份的,在完整备份的基础上进行完整备份之后的差异的备份。
  
而如何确定完整的备份之后备份到哪里,就依赖于完整备份之后的xtrabackup_checkpoints这个文件的。
 

innobackupex --defaults-file=/etc/my.cnf --user=root --password=root --socket=/var/lib/mysql/mysql.sock --incremental /data/backup --incremental-basedir=/data/backup/2017-06-22_13-40-29

如截图,差异备份完成

未分类

如果在进行差异备份的时候,指定的完整备份的文件错误或者是未指定完整备份文件,会发现xtrabackup提示找不到xtrabackup_checkpoints这个文件。

未分类

innobackupex 还原

准备阶段

1、 恢复完整备份,也即完整备份应用(–apply-log)日志
    

innobackupex --defaults-file=/etc/my.cnf --apply-log --redo-only --socket=/var/lib/mysql/mysql.sock /data/backup/2017-06-22_13-40-29

2、 分别将增量备份应用到完整备份
  

innobackupex --defaults-file=/etc/my.cnf --apply-log --redo-only --socket=/var/lib/mysql/mysql.sock --incremental /data/backup/2017-06-22_13-40-29 --incremental-basedir=/data/backup/2017-06-22_13-41-48

未分类 

如果有多个差异备份,分别应用差异备份到完整备份。

恢复阶段

1、 完成差异备份的全部应用到完整备份之后,将恢复后的差异备份copy到原数据目录
    
默认情况下,如果数据路径下存在文件,则copy失败,需要清空数据文件路径下的文件。
    

innobackupex --copy-back /data/backup/2017-06-22_13-40-29

如截图,完成copy-back

未分类

2、启动MySQL服务

启动mysql服务,发现启动失败

未分类

看一下错误日志(启动错误信息),mysql5.7yum安装默认的errorlog位于/var/log/mysqld.log中,且默认不会滚动,意味着所有的错误信息都记录在这个文件中。

未分类

数据文件还原之后,需要读数据文件路径授予可读写的权限
  
这里直接授权数据文件路径777,chmod -R 777 /var/lib/mysql
  
然后启动mysql服务,可以正常启动。

未分类  

xtrabackupex才刚刚开始,留下一大堆问题,有时间再一个一个验证。

1、 怎么实现单个库(表)的备份与还原,毕竟实际环境中,因为每个库备份的频率和方式(备份方案)是不一样的?

2、 怎么用全备+差异备份然后结合二进制日志做基于时间点的方式还原?

3、 如何验证备份文件的有效性?

使用Vagrant和VirtualBox一步步地创建一个Base Box

Vagrant和VirtualBox软件的安装步骤省略,去官网下载最新的版本然后下一步下一步地安装就行了,和正常的安装软件没有什么区别。下面看看利用vagrant和virtualbox如果一步步打造出自己的可复用性强的开发环境。

开始前确保您的计算机支持虚拟化技术,在BIOS中可以开启。

一、在virtualbox中新建一个虚拟机

我这里使用的是CentOS-6.5-x86_64-minimal.iso这个镜像文件来安装的,1G内存,8G虚拟硬盘的配置(后面可以修改)。虚拟机名为centos。

安装好后该虚拟机已经自带了ssh服务,如果没有,需要自己先进行安装。

未分类

开启虚拟机,并登陆root用户。

二、配置虚拟机

创建admin用户组

[root@localhost ~]# groupadd admin

创建vagrant用户并添加到admin用户组

[root@localhost ~]# useradd -g admin vagrant

为vagrant用户设置密码,密码为vagrant(会提示密码太弱,可以不用管它)

[root@localhost ~]# passwd vagrant

修改sudoers文件

[root@localhost ~]# vi /etc/sudoers

在该文件添加下面两行代码,并注释掉requiretty行

Defaults env_keep="SSH_AUTH_SOCK"
%admin ALL=NOPASSWD: ALL

配置网卡:将ONBOOT=no 改为 ONBOOT=yes

[root@localhost ~]# vi /etc/sysconfig/network-scripts/ifcfg-eth0
DEVICE=eth0
HWADDR=08:00:27:25:4A:9A
TYPE=Ethernet
UUID=751ae3bb-eb75-4f60-b5c3-7f1afa1dfce1
ONBOOT=yes
NM_CONTROLLED=yes
BOOTPROTO=dhcp

配置好网卡后需要重启网络服务:

[root@localhost ~]# service network restart

三、设置端口转发

配置virtualbox端口转发(NAT模式)

未分类

主机ip127.0.0.1

主机端口22(或者其他未被占用端口,最好还是设置成22)

子系统ip可以在虚拟通过ifconfg命令查看到,即eth0网卡的ip地址

子系统端口为22

设置好端口转发规则之后,就能在本地的命令行工具(Xshell,putty..)里通过命令 ssh [email protected] 连接到该虚拟机。

四、添加vagrant公钥,使vagrant用户可以免密码ssh连接该虚拟机

在虚拟机里切换到vagrant用户

[root@localhost ~]# su vagrant
[vagrant@localhost root]$ cd ~
[vagrant@localhost ~]$

然后执行:

[vagrant@localhost ~]$ mkdir ~/.ssh/
[vagrant@localhost ~]$ cd ~/.ssh
[vagrant@localhost .ssh]$ sudo yum -y install wget
[vagrant@localhost .ssh]$ wget http://github.com/mitchellh/vagrant/raw/master/keys/vagrant
[vagrant@localhost .ssh]$ wget http://github.com/mitchellh/vagrant/raw/master/keys/vagrant
[vagrant@localhost .ssh]$ mv vagrant.pub authorized_keys

清理缓存

[vagrant@localhost .ssh]$ sudo yum clean all

然后关闭此虚拟机,通过virtualbox将其电源关闭

五、打包生成box文件

在本地命令行进入该虚拟机目录

cd UsersAdminVirtualBox VMscentos

进行打包

vagrant package --output mycentos.box --base centos

未分类

完成之后你将会在C:UsersAdminVirtualBox VMscentos目录下看到一个mycentos.box文件,我的这个文件有544M。

VirtualBox VMs这个目录可以在virtualbox全局设定-常规里进行修改

到此一个Base Box就制作完成了。

这个box是很干净的,然后可以在这个box的基础上去搭建自己的开发环境,比如lnmp等等。再次进行打包,最后一个带开发环境的box就做好了,可以自己用也可以分发给其他小伙伴使用,不用以后每次都要去搭建一遍环境。

六、附上vagrant常用操作命令

vagrant box list 查看在vagrant里已经安装了哪些box

vagrant box add name boxname.box 添加一个本地的box镜像到vagrant 这个box镜像可以自己制作也可以使用网上的(vagrant box add ubuntu ubuntu/trusty64)

vagrant init name 初始化一个虚拟机,这个name是通过vagrant box list查看

vagrant up 启动虚拟机 在virtualbox中可以看到启动后的虚拟机,第一次启动时时间会长一点

vagrant ssh 连接虚拟机

vagrant reload 重启虚拟机

vagrant status 查看虚拟机当前状态

七、常见问题处理

问题1:

default: in which case you may ignore this message.
==> default: Mounting shared folders...
default: /vagrant => E:/vagrantbox/centos67
Vagrant was unable to mount VirtualBox shared folders. This is usually
because the filesystem "vboxsf" is not available. This filesystem is
made available via the VirtualBox Guest Additions and kernel module.
Please verify that these guest additions are properly installed in the
guest. This is not a bug in Vagrant and is usually caused by a faulty
Vagrant box. For context, the command attempted was:

mount -t vboxsf -o uid=500,gid=500 vagrant /vagrant

The error output from the command was:

mount: unknown filesystem type 'vboxsf'

上面这样的问题可以执行下命令 vagrant plugin install vagrant-vbguest ,然后重启vagrant reload来解决。

问题2:

vagrant up的时候出现 “rsync” could not be found on your PATH. Make sure that rsync is properly installed on your system and available on the PATH. 出现这样的错误

找到C:Usersadmin.vagrant.dboxescentos7virtualbox类似这样的目录下面的Vagrantfile文件

修改type配置项: config.vm.synced_folder “.”, “/vagrant”, type: “virtualbox”

Centos 7 JDK、Tomcat9 安装并配置

一、JDK 安装

1、安装wget

yum -y install wget

2、下载,输入指令

wget --no-check-certificate --no-cookies --header "Cookie: oraclelicense=accept-securebackup-cookie" http://download.oracle.com/otn-pub/java/jdk/8u144-b01/090f390dda5b47b9b721c7dfaa008135/jdk-8u144-linux-x64.rpm

3、执行npm安装包,等待安装完成

rpm -ivh jdk-8u112-linux-x64.rpm

4、验证安装是否成功

//输入指令

java -version
//输出版本
java version “1.8.0_112”
Java(TM) SE Runtime Environment (build 1.8.0_112-b15)
Java HotSpot(TM) 64-Bit Server VM (build 25.112-b15, mixed mode)

二、Tomcat 安装

1、下载,切换至任意目录执行

wget http://archive.apache.org/dist/tomcat/tomcat-9/v9.0.0.M18/bin/apache-tomcat-9.0.0.M18.tar.gz

2、解压 ,执行以下命令

tar -zxvf apache-tomcat-9.0.0.M18.tar.gz

3、移动至想放置的目录

mv apache-tomcat-9.0.0.M18 /usr/local/

4、配置自启动

切换至Tomcat的bin目录执行vi setenv.sh,并按i进入编辑模式,拷贝以下代码粘贴

#add tomcat pid
CATALINA_PID=”$CATALINA_BASE/tomcat.pid”
#add java opts
JAVA_OPTS=”-server -XX:PermSize=256M -XX:MaxPermSize=1024m -Xms512M -Xmx1024M -XX:MaxNewSize=256m”

之后按esc键,在按shift+:(左下角出现会出现“:”),然后输入wq保存退出,最后执行 chmod +x setenv.sh,确保文件setenv.sh可执行。

5、配置service

执行cd /usr/lib/systemd/system切换至目录 并执行vi tomcat.service(也可以直接vi /usr/lib/systemd/system/tomcat.service),拷贝以下代码粘贴(注意将第6和7行的Tomcat路径/usr/local/apache-tomcat-9.0.0.M18 换成你自己的Tomcat的绝对路径)

[Unit]
Description=Tomcat
After=syslog.target network.target remote-fs.target nss-lookup.target
[Service]
Type=forking
PIDFile=/usr/local/apache-tomcat-9.0.0.M18/tomcat.pid
ExecStart=/usr/local/apache-tomcat-9.0.0.M18/bin/startup.sh
ExecReload=/bin/kill -s HUP $MAINPID
ExecStop=/bin/kill -s QUIT $MAINPID
PrivateTmp=true
[Install]
WantedBy=multi-user.target

之后按esc键,在按shift+:(左下角出现会出现“:”),然后输入wq保存退出。执行以下指令将tomcat.service添加开机至开机启动

//配置开机启动
systemctl enable tomcat
//启动tomcat
systemctl start tomcat
//停止tomcat
systemctl stop tomcat
//重启tomcat
systemctl restart tomcat

配置完成,建议重启服务器,即输入命令 reboot(或者sudo reboot)即可在浏览器里输入你的服务器地址+8080端口(例如:192.168.1.161:8080),如果看到小猫咪表示成功,否则请检查以上所有步骤是否全都执行正确了。

6、修改端口

切换至Tomcat conf目录

cd /usr/local/apache-tomcat-9.0.0.M18/conf
//输入指令打开文件
vi server.xml
//输入 /8080 并回车搜索8080 字符串,找到如下两处地方
<<Connector port="8080" protocol="HTTP/1.1"
               connectionTimeout="20000"
               redirectPort="8443" />
    <!-- A "Connector" using the shared thread pool-->
    <!--
    <Connector executor="tomcatThreadPool"
               port="8080" protocol="HTTP/1.1"
               connectionTimeout="20000"
               redirectPort="8443" />
//按“i”进入编辑模式,将port="8080"改成port="80"
<Connector port="80" protocol="HTTP/1.1"
               connectionTimeout="20000"
               redirectPort="8443" />
    <!-- A "Connector" using the shared thread pool-->
    <!--
    <Connector executor="tomcatThreadPool"
               port="80" protocol="HTTP/1.1"
               connectionTimeout="20000"
               redirectPort="8443" />

之后按esc键,在按shift+:(左下角出现会出现“:”),然后输入wq保存退出。

7、配置gui-manager项目部署方式

切换至Tomcat conf目录,输入vi tomcat-users.xml打开文件,按“i”进入编辑模式,拷贝以下代码放置标签之间(注意将password和username换成你自己的)

 <role rolename="manager"/>     
  <role rolename="admin"/> 
  <role rolename="admin-gui"/>
  <role rolename="manager-gui"/>
  <user username="xxx" password="***" roles="admin-gui,manager-gui"/>

之后按esc键,在按shift+:(左下角出现会出现“:”),然后输入wq保存退出。

输入 cd webapps/manager/META-INF/ 切换至目录,输入vi context.xml打开文件,按i进入编辑模式,将 标签下的 标签注释掉

<Context antiResourceLocking="false" privileged="true" >
<!--注释掉此标签
 <Valve className="org.apache.catalina.valves.RemoteAddrValve"
         allow="127.d+.d+.d+|::1|0:0:0:0:0:0:0:1" />
-->
</Context>

之后按esc键,在按shift+:(左下角出现会出现“:”),然后输入wq保存退出。

8、重启Tomcat

systemctl restart tomcat

浏览器中直接输入你的服务器地址,例如192.168.1.161(不用输端口号了),看见小猫咪,点击manager 输入账号密码即可部署你的项目了。

Tomcat manager无法访问

百度类似文档一大堆,能用的不多。

问题截图

访问tomcat manager页面时提示403拒绝

未分类

解决方法

1、修改权限

[root@192-168-10-51 tomcat]# vim webapps/manager/META-INF/context.xml

将下图中的两行使用屏蔽

未分类

2、配置用户

[root@192-168-10-51 tomcat]# vim conf/tomcat-users.xml

在最后一行之前,加入

<user username="tomcat" password="123com" roles="manager-gui,manager-jmx,manager-script,manager-status"/>

用户名,密码,角色(权限)

未分类

重启tomcat

未分类

测试

未分类

未分类

未分类

tcpdump使用技巧

一般情况下,非HTTP协议的网络分析,在服务器端用tcpdump比较多,在客户端用wireshark比较多,两个抓包软件的语法是一样的。

一、基本语法

1、过滤主机

  • 抓取所有经过eth1,目的或源地址是192.168.1.1的网络数据
tcpdump -i eth1 host 192.168.1.1
  • 指定源地址
tcpdump -i eth1 src host 192.168.1.1
  • 指定目的地址
tcpdump -i eth1 dst host 192.168.1.1

2、过滤端口

  • 抓取所有经过eth1,目的或源端口是25的网络数据
tcpdump -i eth1 port 25
  • 指定源端口
tcpdump -i eth1 src port 25

指定目的端口

tcpdump -i eth1 dst port 25

3、网络过滤

tcpdump -i eth1 net 192.168
tcpdump -i eth1 src net 192.168
tcpdump -i eth1 dst net 192.168

4、协议过滤

tcpdump -i eth1 arp
tcpdump -i eth1 ip
tcpdump -i eth1 tcp
tcpdump -i eth1 udp
tcpdump -i eth1 icmp

5、常用表达式

非 : ! or "not" (去掉双引号)  且 : && or "and"  或 : || or "or"
  • 抓取所有经过eth1,目的地址是192.168.1.254或192.168.1.200端口是80的TCP数据
tcpdump -i eth1 '((tcp) and (port 80) and ((dst host 192.168.1.254) or (dst host 192.168.1.200)))'
  • 抓取所有经过eth1,目标MAC地址是00:01:02:03:04:05的ICMP数据
tcpdump -i eth1 '((icmp) and ((ether dst host 00:01:02:03:04:05)))'
  • 抓取所有经过eth1,目的网络是192.168,但目的主机不是192.168.1.200的TCP数据
tcpdump -i eth1 '((tcp) and ((dst net 192.168) and (not dst host 192.168.1.200)))'

二、高级包头过滤

首先了解如何从包头过滤信息

proto[x:y]          : 过滤从x字节开始的y字节数。比如ip[2:2]过滤出3、4字节(第一字节从0开始排)proto[x:y] & z = 0  : proto[x:y]和z的与操作为0proto[x:y] & z !=0  : proto[x:y]和z的与操作不为0proto[x:y] & z = z  : proto[x:y]和z的与操作为zproto[x:y] = z      : proto[x:y]等于z

操作符 : >, <, >=, <=, =, !=

1、IP头

 0                   1                   2                   3
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 |Version|  IHL  |Type of Service|          Total Length         |
 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 |         Identification        |Flags|      Fragment Offset    |
 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 |  Time to Live |    Protocol   |         Header Checksum       |
 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 |                       Source Address                          |
 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 |                    Destination Address                        |
 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 |                    Options                    |    Padding    | <-- optional +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 |                            DATA ...                           |
 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

本文只针对IPv4。

2、IP选项设置了吗?

“一般”的IP头是20字节,但IP头有选项设置,不能直接从偏移21字节处读取数据。IP头有个长度字段可以知道头长度是否大于20字节。

 +-+-+-+-+-+-+-+-+
 |Version|  IHL  |
 +-+-+-+-+-+-+-+-+

通常第一个字节的二进制值是:01000101,分成两个部分:

0100 = 4 表示IP版本 0101 = 5 表示IP头32 bit的块数,5 x 32 bits = 160 bits or 20 bytes

如果第一字节第二部分的值大于5,那么表示头有IP选项。

下面介绍两种过滤方法(第一种方法比较操蛋,可忽略):

a. 比较第一字节的值是否大于01000101,这可以判断IPv4带IP选项的数据和IPv6的数据。

01000101十进制等于69,计算方法如下(小提示:用计算器更方便)

0 : 0  1 : 2^6 = 64  第一部分 (IP版本)0 : 0   /0 : 0  /-0 : 0  1 : 2^2 = 4   第二部分 (头长度)0 : 0   /1 : 2^0 = 1 /

64 + 4 + 1 = 69

如果设置了IP选项,那么第一自己是01000110(十进制70),过滤规则:

tcpdump -i eth1 'ip[0] > 69'

IPv6的数据也会匹配,看看第二种方法。

b. 位操作

0100 0101 : 第一字节的二进制
0000 1111 : 与操作
<=========
0000 0101 : 结果

正确的过滤方法

tcpdump -i eth1 'ip[0] & 15 > 5'

或者

tcpdump -i eth1 'ip[0] & 0x0f > 5'

3、分片标记

当发送端的MTU大于到目的路径链路上的MTU时就会被分片,这段话有点拗口,权威的请参考《TCP/IP详解》。唉,32借我的书没还,只能凑合写,大家记得看书啊。

分片信息在IP头的第七和第八字节:

 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 |Flags|      Fragment Offset    |
 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

Bit 0: 保留,必须是0
Bit 1: (DF) 0 = 可能分片, 1 = 不分片
Bit 2: (MF) 0 = 最后的分片, 1 = 还有分片

Fragment Offset字段只有在分片的时候才使用。

要抓带DF位标记的不分片的包,第七字节的值应该是:

01000000 = 64

tcpdump -i eth1 'ip[6] = 64'

4、抓分片包

  • 匹配MF,分片包
tcpdump -i eth1 'ip[6] = 32'

最后分片包的开始3位是0,但是有Fragment Offset字段。

  • 匹配分片和最后分片
tcpdump -i eth1 '((ip[6:2] > 0) and (not ip[6] = 64))'

测试分片可以用下面的命令:

ping -M want -s 3000 192.168.1.1

5、匹配小TTL

TTL字段在第九字节,并且正好是完整的一个字节,TTL最大值是255,二进制为11111111。

可以用下面的命令验证一下:

$ ping -M want -s 3000 -t 256 192.168.1.200
ping: ttl 256 out of range
 +-+-+-+-+-+-+-+-+
 |  Time to Live |
 +-+-+-+-+-+-+-+-+
  • 在网关可以用下面的命令看看网络中谁在使用traceroute
tcpdump -i eth1 'ip[8] < 5'

6、抓大于X字节的包

  • 大于600字节
tcpdump -i eth1 'ip[2:2] > 600'

7、更多的IP过滤

首先还是需要知道TCP基本结构,再次推荐《TCP/IP详解》,卷一就够看的了,避免走火入魔。

  • TCP头
 0                   1                   2                   3
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 |          Source Port          |       Destination Port        |
 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 |                        Sequence Number                        |
 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 |                    Acknowledgment Number                      |
 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 |  Data |       |C|E|U|A|P|R|S|F|                               |
 | Offset|  Res. |W|C|R|C|S|S|Y|I|            Window             |
 |       |       |R|E|G|K|H|T|N|N|                               |
 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 |           Checksum            |         Urgent Pointer        |
 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 |                    Options                    |    Padding    |
 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 |                             data                              |
 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  • 抓取源端口大于1024的TCP数据包
tcpdump -i eth1 'tcp[0:2] > 1024'
  • 匹配TCP数据包的特殊标记

TCP标记定义在TCP头的第十四个字节

 +-+-+-+-+-+-+-+-+
 |C|E|U|A|P|R|S|F|
 |W|C|R|C|S|S|Y|I|
 |R|E|G|K|H|T|N|N|
 +-+-+-+-+-+-+-+-+

重复一下TCP三次握手,两个主机是如何勾搭的:

  1. 源发送SYN
  2. 目标回答SYN, ACK
  3. 源发送ACK

没女朋友的童鞋要学习一下:

  1. MM,你的手有空吗?–
  2. 有空,你呢?~~
  3. 我也有空 _

失败的loser是酱紫的:

  1. MM,这是你掉的板砖吗?(SYN)  ̄▽ ̄
  2. 不是,找拍啊?(RST-ACK) ˋ﹏ˊ
  • 只抓SYN包,第十四字节是二进制的00000010,也就是十进制的2
tcpdump -i eth1 'tcp[13] = 2'
  • 抓SYN, ACK (00010010 or 18)
tcpdump -i eth1 'tcp[13] = 18'
  • 抓SYN或者SYN-ACK
tcpdump -i eth1 'tcp[13] & 2 = 2'

用到了位操作,就是不管ACK位是啥。

  • 抓PSH-ACK
tcpdump -i eth1 'tcp[13] = 24'
  • 抓所有包含FIN标记的包(FIN通常和ACK一起,表示幽会完了,回见)
tcpdump -i eth1 'tcp[13] & 1 = 1'
  • 抓RST(勾搭没成功,伟大的greatwall对她认为有敏感信息的连接发RST包,典型的棒打鸳鸯)
tcpdump -i eth1 'tcp[13] & 4 = 4'

8、大叔注

tcpdump考虑了一些数字恐惧症者的需求,提供了部分常用的字段偏移名字:

icmptype (ICMP类型字段)
icmpcode (ICMP符号字段)
tcpflags (TCP标记字段)

ICMP类型值有:

icmp-echoreply, icmp-unreach, icmp-sourcequench, icmp-redirect, icmp-echo, icmp-routeradvert, icmp-routersolicit, icmp-timxceed, icmp-paramprob, icmp-tstamp, icmp-tstampreply, icmp-ireq, icmp-ireqreply, icmp-maskreq, icmp-maskreply

TCP标记值:

tcp-fin, tcp-syn, tcp-rst, tcp-push, tcp-push, tcp-ack, tcp-urg

这样上面按照TCP标记位抓包的就可以写直观的表达式了:

  • 只抓SYN包
tcpdump -i eth1 'tcp[tcpflags] = tcp-syn'
  • 抓SYN, ACK
tcpdump -i eth1 'tcp[tcpflags] & tcp-syn != 0 and tcp[tcpflags] & tcp-ack != 0'

9、抓SMTP数据

tcpdump -i eth1 '((port 25) and (tcp[(tcp[12]>>2):4] = 0x4d41494c))'

抓取数据区开始为”MAIL”的包,”MAIL”的十六进制为0x4d41494c。

10、抓HTTP GET数据

tcpdump -i eth1 'tcp[(tcp[12]>>2):4] = 0x47455420'

“GET “的十六进制是47455420

11、抓SSH返回

tcpdump -i eth1 'tcp[(tcp[12]>>2):4] = 0x5353482D'

“SSH-“的十六进制是0x5353482D

tcpdump -i eth1 '(tcp[(tcp[12]>>2):4] = 0x5353482D) and (tcp[((tcp[12]>>2)+4):2] = 0x312E)'

抓老版本的SSH返回信息,如”SSH-1.99..”

三、大叔注

如果是为了查看数据内容,建议用tcpdump -s 0 -w filename把数据包都保存下来,然后用wireshark的Follow TCP Stream/Follow UDP Stream来查看整个会话的内容。

-s 0是抓取完整数据包,否则默认只抓68字节。

另外,用tcpflow也可以方便的获取TCP会话内容,支持tcpdump的各种表达式。

1、UDP头

  0      7 8     15 16    23 24    31
 +--------+--------+--------+--------+
 |     Source      |   Destination   |
 |      Port       |      Port       |
 +--------+--------+--------+--------+
 |                 |                 |
 |     Length      |    Checksum     |
 +--------+--------+--------+--------+
 |                                   |
 |              DATA ...             |
 +-----------------------------------+
  • 抓DNS请求数据
tcpdump -i eth1 udp dst port 53

2、其他

-c参数对于运维人员来说也比较常用,因为流量比较大的服务器,靠人工CTRL+C还是抓的太多,甚至导致服务器宕机,于是可以用-c参数指定抓多少个包。

time tcpdump -nn -i eth0 'tcp[tcpflags] = tcp-syn' -c 10000 > /dev/null

上面的命令计算抓10000个SYN包花费多少时间,可以判断访问量大概是多少。

Linux VPS上DenyHosts阻止SSH暴力攻击

现在的互联网非常不安全,很多人没事就拿一些扫描机扫描ssh端口,然后试图连接ssh端口进行暴力破解(穷举扫描),所以建议vps主机的空间,尽量设置复杂的ssh登录密码,虽然在前段时间曾经介绍过Linux VPS禁止某个IP访问使用hosts.deny禁止某些IP访问,但是功能方面欠缺,如:不能自动屏蔽,那么有什么更好的办法吗,就可以使用denyhosts这款软件了,它会分析/var/log/secure(redhat,Fedora Core)等日志文件,当发现同一IP在进行多次SSH密码尝试时就会记录IP到/etc/hosts.deny文件,从而达到自动屏蔽该IP的目的。

DenyHosts官方网站为:http://denyhosts.sourceforge.net/

LNMP一件安装包中自带该软件可以一键安装,命令:

wget http://soft.vpser.net/lnmp/lnmp1.4beta.tar.gz && tar zxf lnmp1.4beta.tar.gz && cd lnmp1.4/tools/ && ./denyhosts.sh 

回车确认即可开始安装配置,不需要下面的步骤进行安装配置。(该tools目录下也有denyhosts相似的工具fail2ban的一键安装工具 ./fail2ban.sh 安装即可)

1、下载DenyHosts 并解压

# wget http://soft.vpser.net/security/denyhosts/DenyHosts-2.6.tar.gz
# tar zxvf DenyHosts-2.6.tar.gz
# cd DenyHosts-2.6

2、安装、配置和启动

安装前建议执行:echo “” > /var/log/secure && service rsyslog restart 清空以前的日志并重启一下rsyslog

# python setup.py install

因为DenyHosts是基于python的,所以要已安装python,大部分Linux发行版一般都有。默认是安装到/usr/share/denyhosts/目录的,进入相应的目录修改配置文件

# cd /usr/share/denyhosts/
# cp denyhosts.cfg-dist denyhosts.cfg
# cp daemon-control-dist daemon-control

默认的设置已经可以适合centos系统环境,你们可以使用vi命令查看一下denyhosts.cfg和daemon-control,里面有详细的解释

接着使用下面命令启动denyhosts程序

# chown root daemon-control
# chmod 700 daemon-control
# ./daemon-control start

如果要使DenyHosts每次重起后自动启动还需做如下设置:

# ln -sf /usr/share/denyhosts/daemon-control /etc/init.d/denyhosts
# chkconfig –add denyhosts
# chkconfig –level 2345 denyhosts on

或者执行下面的命令加入开机启动,将会修改/etc/rc.local文件:

# echo “/usr/share/denyhosts/daemon-control start” >> /etc/rc.local

DenyHosts配置文件/usr/share/denyhosts/denyhosts.cfg说明:

SECURE_LOG = /var/log/secure
#sshd日志文件,它是根据这个文件来判断的,不同的操作系统,文件名稍有不同。

HOSTS_DENY = /etc/hosts.deny
#控制用户登陆的文件

PURGE_DENY = 5m
DAEMON_PURGE = 5m
#过多久后清除已经禁止的IP,如5m(5分钟)、5h(5小时)、5d(5天)、5w(5周)、1y(一年)

BLOCK_SERVICE  = sshd
#禁止的服务名,可以只限制不允许访问ssh服务,也可以选择ALL

DENY_THRESHOLD_INVALID = 5
#允许无效用户失败的次数

DENY_THRESHOLD_VALID = 10
#允许普通用户登陆失败的次数

DENY_THRESHOLD_ROOT = 5
#允许root登陆失败的次数

HOSTNAME_LOOKUP=NO
#是否做域名反解

DAEMON_LOG = /var/log/denyhosts

为防止自己的IP被屏蔽,可以:echo “你的IP” >> /usr/share/denyhosts/allowed-hosts 将你的IP加入白名单,再重启DenyHosts:/etc/init.d/denyhosts ,如果已经被封,需要先按下面的命令删除被封IP后再加白名单。

如有IP被误封,可以执行下面的命令解封:

wget http://soft.vpser.net/security/denyhosts/denyhosts_removeip.sh && bash denyhost_removeip.sh 要解封的IP

更多的说明请查看自带的README文本文件,好了以后维护VPS就会省一些心了,但是各位VPSer们注意了安全都是相对的哦,没有绝对安全,将密码设置的更Strong,并请定期或不定期的检查你的VPS主机,而且要定时备份你的数据哦。

与DenyHosts类似的软件还有fail2ban功能上更多,还可以对ftp进行保护,自己可以搜索看一下。