Lexsion 发布的文章

CentOS7新主机初步配置命令

CentOS7新主机初步配置命令

前言

购买自己的Linux主机后第一件事就是安装操作系统,再之后需要自己做一些配置。本文对CentOS7系统下此流程进行整理,主要用于记录备忘,以便于日后查阅。如有遗漏,欢迎大家留言补充。

目录

  1. SSH登陆并修改密码
  2. 修改SSH的登陆端口
  3. 修改系统欢迎信息
  4. 修改启动选择菜单等待时间
  5. 修改主机名(HostName)
  6. 配置Fail2Ban防止SSH爆破

1.SSH登陆并修改密码

将主机IP地址与SSH端口号输入SSH软件使用 用户名和密码登陆服务器,SSH的端口号默认为22端口,用户名一般应为root。如果是购买VPS,商家一般会告知IP地址、端口号以及用户名密码。
登陆一个新的主机时(或主机重装系统后),会对未知的信息进行警告,需选择接受才能正常连接。
通常我们使用root用户登陆后需要修改密码,使用以下命令修改密码,系统会提示要求输入新密码两次以确认修改,如下所示:

# passwd 
Changing password for user root. 
New password: 
Retype new password: 
passwd: all authentication tokens updated successfully.

2.修改SSH的登陆端口

在使用有公网IP的主机时,为了安全考虑,我们需要改掉默认的SSH端口。
使用 cp /etc/ssh/sshd_config /etc/ssh/sshd_config.old 命令备份配置文件 sshd_configsshd_config.old ,使用 vi /etc/ssh/sshd_config 命令打开SSH服务端配置文件,将 #Port 22# 号删除,按格式添加新行,内容为Port空格后跟自定义端口号。如下所示自定义端口为21748:

#
Port 22
Port 21748

使用以下命令重启SSH服务端使配置生效,正常情况此时端口22和端口21748应都能正常访问。

service sshd restart

使用 exit 命令退出SSH客户端,然后使用IP地址加新端口号尝试连接,如不成功,请检查防火墙设置以及是否自定义端口与其他应用冲突。
如果通过新端口连接正常,则记录自己修改的端口号已免忘记,重新使用 vi /etc/ssh/sshd_config 命令打开配置文件,如下所示,在 Port 22 行前添加 # 号注释本行并保存,停用22端口的使用。

#
#Port 22
Port 21748

运行 service sshd restart 使配置生效,这之后,将无法通过22端口连接SSH,此时我们可以删除防火墙规则中的22端口。

3.修改系统欢迎信息

某些系统在我们登陆后会显示一段欢迎信息。我们可以按我们自己的意愿进行修改。这些信息实际来自于文件 /etc/motd ,我们可以使用以下命令通过vim编辑器编辑此文件来修改欢迎信息。

vim /etc/motd

如果系统提示命令未找到,可尝试使用其他编辑器修改。例如: vi , nano 。

  • vim编辑器使用:按i键进入输入模式,编辑完后按ESC键退出编辑模式,输入进入命令模式,输入wq命令保存并退出。若没有vim编辑器或不习惯使用vim编辑器,可用其他编辑器替代,具体使用方法请自行通过搜索引擎查询。

4.修改启动选择菜单等待时间

在使用独立主机或自己的物理主机情况下,可能会遇到开机时的启动选择菜单等待时间较长需要修改的问题,此问题可通过修改 /boot/grub2/grub.cfg 文件解决。与上文类似,找到修改以下代码:

terminal_output console
if [ x$feature_timeout_style = xy ] ; then
  set timeout_style=menu
  set timeout=5(单位为秒,建议修改成1,修改完成下次开机等待时间就会生效)
# Fallback normal timeout code in case the timeout_style feature is
# unavailable.

5.修改主机名(HostName)

在CentOS7中,有三种定义的主机名:静态的(static),瞬态的(transient),和灵活的(pretty)。静态主机名也称为内核主机名,是系统在启动时从/etc/hostname自动初始化的主机名。瞬态主机名是在系统运行时临时分配的主机名,例如,通过DHCP或mDNS服务器分配。静态主机名和瞬态主机名都遵从作为互联网域名同样的字符限制规则。而另一方面,灵活主机名则允许使用自由形式(包括特殊/空白字符)的主机名,以展示给终端用户。
一般情况下主机名默认为 localhost 。但在管理的主机较多时,我们需要修改一个易于识别的主机名来标记每台主机。这样才能方便区分自己操作的主机。
在CentOS 7中,使用 hostnamectl 命令行工具查看或修改与主机名相关的配置。
不带参数输入命令查看主机名相关的设置,如果只查看静态、瞬态或灵活主机名,可分别使用 --static--transient--pretty 选项:

[root@localhost ~]# hostnamectl
Static hostname: localhost.localdomain
Pretty hostname: localhost.localdomain
        Icon name: computer-vm
        Chassis: vm
        Machine ID: b5f3ded389c742h9d3g41s87bt57ng28
        Boot ID: 5aa97h356hjg9v8jhng474m6r6k48w89
    Virtualization: kvm
Operating System: CentOS Linux 7 (Core)
    CPE OS Name: cpe:/o:centos:centos:7
            Kernel: Linux 3.10.0-957.10.1.el7.x86_64
    Architecture: x86-64

[root@localhost ~]# hostnamectl --static
localhost.localdomain

通过以下命令同时修改三个主机名:

hostnamectl set-hostname

如果只想修改特定的主机名(静态,瞬态或灵活),可以使用 --static--transient--pretty 选项。例如:使用以下命令修改灵活主机名为ahost:

[root@localhost ~]# hostnamectl --pretty set-hostname ahost

一旦修改了静态主机名,/etc/hostname 将被自动更新。然而, /etc/hosts 不会自动根据所做的修改自动修改,所以在修改主机名后一定要手动更新 /etc/hosts 。使用 vim /etc/hosts 命令通过vi编辑器打开host文件,在里面加入以下内容保存(此处以主机名为ahost为例):

127.0.0.1       ahost
::1             ahost

6.配置Fail2Ban防止SSH爆破

Fail2Ban是一种入侵防御软件框架,可以保护计算机服务器免受暴力攻击。它可以监视计算机的系统日志,通过匹配日志的错误信息执行相应的屏蔽动作。
CentOS7默认的防火墙管理工具是FirewallD,通过以下命令检查其运行状态,若提示running则表示正常运行。

firewall-cmd --state

如果提示未启动则可通过以下命令启用:

# 启动FirewallD
systemctl start firewalld

# 将FirewallD设置开机启动
systemctl enable firewalld.service

启用FirewallD后会禁止除设置的放行端口外的其他端口连接,因此需设置放行常用的端口,以免自己被防火墙阻挡。使用以下命令查看已经放行的端口:

firewall-cmd --zone=public --list-ports

以下是放行上文设置的SSH端口(21748)示例,供参考:

firewall-cmd --zone=public --add-port=21748/tcp --permanent
firewall-cmd --reload

通过以下命令获取FailedBan:

yum -y install epel-release
yum -y install fail2ban

fail2ban配置文件位于/etc/fail2ban,其中jail.conf为主配置文件,相关的匹配规则位于filter.d目录。我们通过新建jail.local文件来覆盖fail2ban的一些默认规则以实现自定义配置。使用 vi /etc/fail2ban/jail.local 命令新建 jail.local 文件,内容如下。

[DEFAULT]
ignoreip = 127.0.0.1/8
bantime  = 86400
findtime = 600
maxretry = 5
banaction = firewallcmd-ipset
action = %(action_mwl)s

[sshd]
enabled = true
filter  = sshd
port    = 21748
action = %(action_mwl)s
logpath = /var/log/secure
  • ignoreip:IP白名单,可填写多个以 , 分隔
  • bantime:屏蔽时间,单位为秒(s)
  • findtime:时间范围
  • maxretry:最大次数
  • banaction:屏蔽动作,上面使用firewalld屏蔽接口
  • [sshd]:给人看的名称,可随便填写
  • filter:规则名称,必须填写位于filter.d目录里面的规则,sshd是fail2ban内置规则
  • port:对应的端口
  • action:采取的行动
  • logpath:需要监视的日志路径

以上配置意为如果同一个IP,在10分钟内,连续超过5次密码错误,则通过FirewallD接口将此IP ban掉。运行 systemctl start fail2ban 命令启动Fail2Ban。
使用另一台主机不断尝试使用错误密码连接SSH,你会发现连续错误超过5次后直接连不上,说明IP被ban。可以使用命令 fail2ban-client status sshd 查看被ban的IP地址。假设IP:10.0.0.8被sshd规则ban掉,使用命令 fail2ban-client set sshd unbanip 10.0.0.8 可以解除封锁。
确认配置没有问题,使用命令 systemctl enable fail2ban 为Fail2Ban设置开机启动,使用 systemctl status fail2ban 可查看服务状态。若需要停止Fail2Ban,可使用命令 systemctl stop fail2ban 停止其服务,使用命令 systemctl disable fail2ban 可取消开机启动。

参考

CentOS 7安装fail2ban + Firewalld防止爆破与CC攻击
https://www.xiaoz.me/archives/9831

FirewallD入门手册
https://www.linuxprobe.com/centos-firewalld.html

如何在CentOS 7上修改主机名
https://www.jianshu.com/p/39d7000dfa47

将CentOS6自带Python2.6升级到2.7版本

将CentOS6自带Python2.6升级到2.7版本

前言:

最近在自己的服务器上配置ServerStatus中文版,因某些服务器运行的CentOS6系统,发现其自带Python都是2.6版本,而ServerStatus要求使用Python2.7。于是就研究了一下如何手动升级Python版本。

Linux系统没有像Windows那样的注册表,所以软件的安装就非常的简单。Python的调用是通过一个链接实现。因为CentOS6内的yum不支持Python2.7,只能使用Python2.6,所以我们需要将原有的Python2.6保留。

操作步骤:

安装新版Python:

1.使用以下命令查看Python版本(注意V大写),我的回显信息是Python 2.6.6,所以继续。

    python -V

2.下载需要的 Python 版本,访问 Python 官方网站点击 Downloads->Source code 从出现的下载页获取 Python2.7.X 。比如我看到的 Python2.7 最新版本是 Python 2.7.16,下载地址是 https://www.python.org/ftp/python/2.7.16/Python-2.7.16.tgz 。在地址前加上wget运行,以下载源代码。如下:

    wget https://www.python.org/ftp/python/2.7.16/Python-2.7.16.tgz

3.使用以下命令解压下载的源码文件,并进入解压出的文件夹:

    tar  vxf Python-2.7.16.tgz
    cd Python-2.7.16

4.运行以下命令编译源代码,并安装。Python2.7 将会被安装到 /usr/local/bin/ 目录。

    ./configure --prefix=/usr/local
    make && make install

5.运行以下命令让 Python2.7 输出版本信息,以此确认编译安装的 Python2.7 是否能够正常运行。

    /usr/local/bin/python2.7 -V

6.运行以下命令建立软连接,使系统默认的 python 指向 python2.7:

    mv /usr/bin/python /usr/bin/python2.6.6 
    ln -s /usr/local/bin/python2.7 /usr/bin/python

7.再次像最开始那样运行 python -V 命令检查是否配置正确,若配置正确,回显信息应为新版本号。
可运行以下命令安装 pip:

    wget https://bootstrap.pypa.io/get-pip.py -O - | python

至此系统中默认的 Python 已经从 Python2.6 替换为 Python2.7 ,但是这并没有结束,如果此时尝试运行 yum 命令,我们会收到错误提示,其大意为缺少 Python2.6.6 ,为此我们需要单独为 yum 指定使用之前的Python版本。

指定 yum 的 Python 版本:

1.运行以下命令使用vi编辑器打开文件 /usr/bin/yum ,若没有 vi 编辑器,或习惯使用其他编辑器,也可用其他编辑器替代。

    vi /usr/bin/yum

2.将文件最开始部分的:!/usr/bin/python 替换为:!/usr/bin/python2.6.6 ,完成编辑并保存。

  • vi编辑器使用:按i键进入输入模式,编辑完后按ESC键退出编辑模式,输入进入命令模式,输入wq命令保存并退出。

3.这时,我们再次运行 yum 命令即能够正常回显帮助信息。至此,我们便真正完成了 Python 的升级。

使用ServerStatus项目实现多服务器云监控

使用ServerStatus项目实现多服务器云监控

前言

相信很多爱折腾的人手里都有不止一个服务器,或者是VPS,或者是独立服务器。当手里的服务器数量较多时,管理上就会有些麻烦。最常见的需求就是快速的确定服务器的运行状态,比如:是否在线,CPU、内存、网络的占用。手动检查每台服务器获取这些信息是不现实的,所以我们就需要一个方案来实现这个需求。传统的企业方案包括Nagios、zabbix等实现繁琐,本人也不会(流下了没有技术的泪水)。有个方案叫linux-dash挺漂亮,貌似只能给单机做状态页,一台服务器的朋友可以考虑玩一下,但其不在本文讨论范围内。最终,我找到了ServerStatus中文版这个方案。

引用其作者的话:ServerStatus中文版是一个酷炫高逼格的云探针、云监控、服务器云监控、多服务器探针~。ServerStatus监控的数据较多,可提供网络状态、开机时间、负载、实时网速、流量统计、处理器、内存、硬盘、进程数、主机到三网(CU,CT,CM)每小时丢包率等数据,界面酷炫,数据一目了然。其主要由客户端与服务端构成,服务端要求运行在一个有网站空间的Linux系统上。客户端分为两个版本:一个是Linux版本,使用Python实现;一个是跨平台版本,使用Python配合psutil跨平台依赖库实现,该版本客户端可在Windows系统上部署。

读懂实践本文,你可能需要在技能树中点亮以下技能:

  • 会通过搜索引擎尝试解决遇到的问题;
  • 基本的Windows系统与Linux系统操作;
  • 会使用一款SSH客户端;

准备

  • 运行Windows电脑一台(其他系统也可,但具体某些操作可能不同)
  • VPS几台,运行Linux系统或Windows系统。KVM或OpenVZ架构均可;有钱人上独服也行
  • 一台Linux系统VPS(或独服),我使用的CentOS7
  • SSH客户端,我用的是Putty

操作警告:

  • 错误的操作可能导致服务器系统损坏,这意味着潜在的服务停止与数据损失风险,请注意对重要数据做好备份!本人及相关项目的作者等均不会对使用软件造成的损失负责,亦不会对您学习本文的操作负责。继续操作,请自行承担风险!
  • 本方案虽支持监控Windows主机,但本人使用效果并不好,存在频繁掉线问题。这并不能代表您使用时也会遇到此问题,但若您的基本需求为监测Windows主机,请慎重考虑本方案。

步骤

  • 1.统计各被检测主机信息
  • 2.配置服务端
  • 3.配置客户端

1.统计各被检测主机信息

想要做一个多服务器状态监测页,首先应确认自己有多少服务器需要监测,为每台服务器命名,准备好以下信息:

  • 连接用户名:每台客户端唯一的用户名,用于服务器确认是哪一台客户端。
  • 服务器名称:服务器的名称,给人看的名字,在监控页面上会以节点名称显示。
  • 服务器类型:用于标记主机类型,VPS一般填写虚拟化方式。
  • 服务器提供商:这个信息服务端配置文件中有填写位置,但ServerStatus中文版中作者未提供展示。
  • 服务器位置:用户标记服务器所属地理位置。
  • 连接密码:与用户名对应,提供服务端对客户端的认证。

2.配置服务端

选择一台Linux服务器作为服务端,一般要求网络较好,稳定性好,否则状态页挂了也是蛮丢人的。我使用的CentOS7系统,其他Linux系统应该也是可以的,但操作可能不一样,具体可以参考Github项目页Readme。

  1. 使用SSH客户端登陆服务器,并使用以下命令检查更新,期间出现y/n请输入y确认:

    yum update
    
  2. 使用以下命令检查Python版本(注意V为大写):

    python -V
    
    • 查看回显的版本信息是否为Python2.7或以上,若为Python2.6或更低,则需要升级Python版本。具体可使用搜索引擎搜索,本文暂不讨论。
    • 若提示命令不存在,则可能未安装Python或安装的Python已损坏,请尝试安装Python2.7。具体操作请自行搜索。
  3. 配置Web环境,使用LNMP,一般大家可以使用LNMP一键脚本实现,网上找一下很多。我因服务器还有它用,使用的宝塔面板,其一键安装脚本简单易用,安装宝塔后按照提示登陆管理页面,直接在图形界面下完成LNMP的配置。安装时间由服务器性能决定,一般时间较长,建议考虑冲杯咖啡,或可再开个SSH页面先去学习配置客户端。以下为宝塔面板一键脚本:

    yum install -y wget && wget -O install.sh http://download.bt.cn/install/install_6.0.sh && sh install.sh
    
  4. 宝塔面板下,LNMP配置完成后,打开网站选项,点击添加站点,如果有域名就填写域名(比如:uptime.xx.com),使用域名勿忘去服务商那里添加解析记录;没有就填写ip:端口,然后可将根目录改个好记的名字(比如:uptime),其他保持默认,点击创建。
    如使用一键LNMP方案,请参考其作者提供的使用说明添加网站。
  5. 使用git命令拉取项目代码,命令如下:

    git clone https://github.com/cppla/ServerStatus.git
    

    若提示-bash: git: command not found,则表示没有安装git,可尝试运行yum –y install git命令安装git。

  6. 使用cd ServerStatus命令进入文件夹。将 web 文件夹内的内容放到网站目录,不同 LNMP 方案可能不同,假设我的文件夹是/www/wwwroot/uptime,我使用命令 cp -r /web/* /www/wwwroot/uptime将 web 文件夹内的文件复制到/www/wwwroot/uptime内,如有提示是否覆盖,则输入y确定。
  7. 此时正常的话我们打开网站就能看到页面了,因为我们服务端没有运行,网页上有相关错误提示,无需理会。
  8. 使用cd server命令进入server文件夹,然后运行make命令编译,等待其编译成功。使用./sergate命令测试是否有错误,没有错误按Ctrl+C结束即可。有错误请检查35601端口是否被占用,若端口被占用请排除或使用参数--port=<端口号>更改端口号运行。
  9. 使用 vi config.json 命令修改config.json文件,需要注意username, password的值需要和对应的客户端对应一致。

    {"servers":
        [
            {
                "username": "连接用户名",
                "name": "服务器名称",
                "type": "主机类型",
                "host": "主机服务商",
                "location": "主机地理位置",
                "password": "与用户名对应的一个难被猜到的密码"
            },
        ]
    }       
    • vi编辑器使用:按i键进入输入模式,编辑完后按ESC键退出编辑模式,输入进入命令模式,输入wq命令保存并退出。若没有vi编辑器或不习惯使用vi编辑器,可用其他编辑器替代,具体使用方法请自行通过搜索引擎查询。

    创建/usr/local/share/ServerStaus/目录,将以上 server 文件夹放到此目录下。

  10. 使用以下格式命令尝试运行服务端,并打开网页看是否正常,若正常请按Ctrl+C退出:

    ./sergate --port=35601 --config=config.json --web-dir=/www/wwwroot/uptime

    以下为各参数对应功能:

    -h, --help            显示此帮助信息并退出
    -v, --verbose         详细输出模式
    -c, --config=<str>    指定配置文件
    -d, --web-dir=<str>   填写Web文件夹位置
    -b, --bind=<str>      Bind to address(看不懂,哪位大佬若看得懂请留言,谢)
    -p, --port=<int>      指定侦听的端口
    
  11. 使用vi /etc/systemd/system/sergate.service命令创建文件 /etc/systemd/system/sergate.service 填入以下内容保存并退出,需注意,ExecStart项目需要参考操作10自行确认:

    # /etc/systemd/system/sergate.service
    
    [Unit]
    Description=ServerStatus Master Server
    After=syslog.target
    After=network.target
    
    [Service]
    Type=simple
    WorkingDirectory=/usr/local/share/ServerStatus/server
    ExecStart=/usr/local/share/ServerStatus/server/sergate --config=config.json --port=35601 --web-dir=/www/wwwroot/uptime
    StandardOutput=syslog
    StandardError=syslog
    SyslogIdentifier=sergate
    
    [Install]
    WantedBy=multi-user.target
    
    • vi编辑器使用:按i键进入输入模式,编辑完后按ESC键退出编辑模式,输入进入命令模式,输入wq命令保存并退出。若没有vi编辑器或不习惯使用vi编辑器,可用其他编辑器替代,具体使用方法请自行通过搜索引擎查询。
  12. 创建sergate.service文件后,可使用systemctl start sergate运行服务,使用systemctl enable sergate命令将其加入开机启动。若有需要增减客户端,或其他原因需要停止服务,可使用systemctl stop sergate命令停止服务。如需要检查服务运行状态,可使用systemctl status sergate命令输出状态信息。

    请注意,此为Systemd启动方式,CentOS6不支持此方式,若您的系统不支持,请自行查找可用的方式启动。

3.配置客户端

服务端就绪后能看到监控页满屏的红色,不要慌,接下来配置客户端。客户端程序是用Python实现,在ServerStatus/clients目录下,它有两个版本,client-linux为普通Linux版,client-psutil为跨平台版,普通版不成功,请尝试换用跨平台版,Windows需要使用跨平台版。

使用Linux版本:

此处依然以CentOS7为例,其他系统会有不同,请自行摸索。

  1. 使用SSH客户端登陆服务器,并使用以下命令检查更新,期间出现y/n请输入y确认:

    yum update
    
  2. 使用以下命令检查Python版本(注意V为大写):

    python -V
    
    • 查看回显的版本信息是否为Python2.7或以上,若为Python2.6或更低,则需要升级Python版本。具体可使用搜索引擎搜索,本文暂不讨论。
    • 若提示命令不存在,则可能未安装Python或安装的Python已损坏,请尝试安装Python2.7。具体操作请自行搜索。
  3. 运行以下命令创建/usr/local/share/ServerStatus目录并进入该目录,直接从Github下载 client-linux.py 文件到此目录中。

    mkdir /usr/local/share/ServerStatus
    cd /usr/local/share/ServerStatus
    wget https://github.com/cppla/ServerStatus/raw/master/clients/client-linux.py
    
  4. 运行 vi client-linux.py 命令使用vi编辑器打开client-linux.py文件,根据自己需求修改以下部分内容并保存:

    SERVER = "<服务端地址>"
    PORT = <服务端设置的端口号>
    USER = "之前为本机定义的连接用户名"
    PASSWORD = "之前为本机定义的与用户名对应的一个难被猜到的密码"
    
    • vi编辑器使用:按i键进入输入模式,编辑完后按ESC键退出编辑模式,输入进入命令模式,输入wq命令保存并退出。若没有vi编辑器或不习惯使用vi编辑器,可用其他编辑器替代,具体使用方法请自行通过搜索引擎查询。
  5. 运行 chmod +x client-linux.py 命令为文件 client-linux.py 赋予可执行权限。使用以下命令运行客户端,检查状态页显示是否正常,若正常按Ctrl+C退出。

    ./client-linux.py
    
  6. 运行 vi /etc/systemd/system/serverstatus.service 命令使用vi编辑器在目录/etc/systemd/system/创建文件 serverstatus.service。填入以下内容保存并退出:

    #/etc/systemd/system/serverstatus.service
    
    [Unit]
    Description=ServerStatus Client
    Documentation=https://github.com/LexsionLee/ServerStatus
    After=network.target
    
    [Service]
    Type=simple
    IgnoreSIGPIPE=no
    ExecStart=/usr/local/share/ServerStatus/client-linux.py
    Restart=on-failure
    
    [Install]
    WantedBy=multi-user.target
    
  7. 创建serverstatus.service文件后,可使用systemctl start serverstatus.service命令运行服务,使用systemctl enable serverstatus.service命令将其加入开机启动。若要停止服务,可使用systemctl stop serverstatus.service命令停止服务。如需要检查服务运行状态,可使用systemctl status serverstatus.service命令输出状态信息。

至此,在CentOS7上配置客户端就完成了,若一切正常,我们就能在监控页面看到我们的客户端主机状态信息了。

使用psutil跨平台版本(For Windows)

此处以 Windows 7 为例讲述如何在 Windows 下配置ServerStatus的psutil跨平台版本客户端。

  1. 访问Python官方网站点击Downloads->Windows从出现的下载页获取Python2.7.X。请自行选择下载32位或64位版本。有网帖表示Python3可能不行,本人未作测试。
  2. 双击下载的.msi文件运行安装程序,安照提示安装,在功能自定义页面的 Add pytnon.exe to Path 处选择 Will installed on local hard drive ,点击Next安装,若出现UAC提醒请允许。安装完成后点击Finish退出安装程序。
  3. 按 Windows徽标键+R键 打开 “运行” 对话框,输入 cmd 按 Enter键 打开命令提示符。在命令提示符中输入以下命令安装psutil跨平台软件包:

    pip install psutil
    
  4. 访问ServerStatus中文版GitHub项目页,从
    clients目录下找到client-psutil.py文件页,点击Raw按钮直接下载文件。
  5. 将下载的client-psutil.py文件放到一个合适的目录。比如我在C盘下创建了一个文件夹 ServerStatus ,将其存在此。在此文件上右击,点击Edit with IDLE(亦可使用其他编辑器打开)。参考Linux版本配置小节中的说明填写配置信息保存并退出编辑器。
  6. 双击client-psutil.py文件运行,检查监控页是否正常显示,然后关闭窗口停止。
  7. 点击开始->所有程序->启动->右击->打开,创建一个ServerStatusClient.bat文件,填写运行client-psutil.py的代码,我的文件在C:\ServerStatus\下,参考如下:

    python C:\ServerStatus\client-psutil.py
    • 注意该操作可能被安全软件拦截,请在安全软件中设置例外。

此方法配置的客户端在启动时会一直显示一个终端窗口,关闭窗口后客户端即停止工作。强迫症患者慎用!如果希望没有窗口显示,请自行研究解决。

参考:

1:Cppla 大佬的 ServerStatus GitHub 页

2:BotoX 大佬的 ServerStatus GitHub 页

IPROUTE2之IP工具的学习笔记-替代net-tools实现常用网络命令

IPROUTE2之IP工具的学习笔记-替代net-tools实现常用网络命令

前言:

在Linux系统下,我们可能经常会使用ifconfig执行一些网络管理任务,该命令属于net-tools工具组,这是一个很多年前就停止维护的项目,已经有越来越多的人认识到,ifconfig在现代网络环境中已经不再是一个好的工具了,有些发行版的Linux系统已经默认不在包含它,当我们在没有net-tools工具的系统上尝试运行ifconfig时,会提示command not found。这中情况我们可以尝试安装net-tools以可以再次运行ifconfig,或者我们可以考虑学习一个新的工具。iproute2通常以一个名为iproute或iproute2的包形式发放,它由多个工具组成,其中最重要的工具是iptc,IP控制IPv4和IPv6配置,TC代表流量控制。本文即针对ip工具进行学习。该项目目前由Stephen Hemminger负责维护,其原始作者为 Alexey Kuznetsov,,他以在Linux内核中实现QoS而闻名。

获取工具:

与net-tools相反,iprouter2工具在越来越多的Linux发行版本中集成,我们尝试运行以下命令(注意大小写)查看ip实用程序的版本以此检查是否配置了该实用程序:

ip -V

正常回显信息为:

ip utility, iproute2-*******

若回显信息为:command not found,则表示没有配置该工具,如果需要,您可以安装该工具。使用以下命令可以在CentOS下安装iproute2.

yum install -y iproute

使用以下命令可以在Ubuntu下安装iproute2:

sudo apt-get update
sudo apt-get install iproute2

其他系统的配置方法大家可自行搜索相关资料。

命令语法:

我们常使用ifconfig命令大多由IP命令集取代,以下是其命令通用形式:

ip [OPTIONS] OBJECT [COMMAND [ARGUMENTS]]

OPTIONS:

OPTIONS(选项)是一组多值修饰符,它们影响ip实用程序的一般行为和输出。所有选项均以“ - ”字符开头,可以通过输入完整形式或其缩略形式实现。目前可以使用以下选项:

-V,-Version ---输出ip实用程序的版本号并退出。

-s,-stats,-statistics ---输出更多信息。
可以重复此选项以增加输出的详细级别。比如,我们可以观察ip -4 a , ip -4 -s a , ip -4 -s -s a 这三条命令输出信息的区别。通常,附加信息是设备或功能统计或值。在许多情况下,值输出应该与 /proc/ 目录的输出相同,其中值的名称与值本身没有直接关系。

-f[amily] { inet | inet6 | ipx | dnet | bridge | link } ---强制使用哪个协议族。
如果此选项不存在,则使用的协议族输出将从其他命令行参数中猜出。如果命令行的其余部分没有提供足够的信息来猜测协议族,则ip命令会回退到默认的inet协议族。链接是一个特殊的系列标识符,意味着不涉及网络协议。此选项有几个快捷方式,如下所示:
-4 | -6 | -I | -D | -B | -0 | 常用如下:
-4 ---IPv4快捷方式。
-6 ----IPv6快捷方式。
-0 ----链接的快捷方式。
例如,我们使用 ip -6 a 命令输出所有IPv6地址。

-o,-oneline ---通过用“”字符替换任何换行符将输出内容格式化为单行。

OBJECT:

OBJECT(对象)是您希望操作或获取有关信息的对象类型。其包含:

{ link | address | addrlabel | route | rule | neighbour | ntable | tunnel | tuntap | maddress | mroute | mrule | monitor | xfrm |netns | l2tp | tcp_metrics | token }  

以下对其进行介绍:
link---物理或逻辑网络设备,亦可使用 l
address ---设备上的协议(IPv4或IPv6)地址,亦可使用 a , addr
addrlabel ---协议地址选择的标签配置。
route ---路由表条目。
rule---路由策略数据库中的规则。
neighbour --- ARP或NDISC缓存条目,亦可使用n
ntable --- neighbour缓存的操作。
tunnel--- IP隧道。
tuntap ---管理TUN/TAP设备。
maddress --- 多播地址。
mroute ---组播路由缓存条目。
mrule ---多播路由策略数据库中的规则。
monitor ---监视netlink信息。
xfrm ---管理IPSec策略。
netns ---管理网络命名空间。
l2tp ---通过IP隧道传输以太网(L2TPv3)。
tcp_metrics ---管理TCP Metrics。
token ---管理标记化的接口标识符。

所有对象的名称可以全部或缩写形式书写。例如: address 可以缩写为 addr 或只是 a 。但是,如果您在脚本中使用这些命令,则应该养成始终使用操作的完整规范的习惯。使用缩写使其易于在命令行上使用,但很难理解脚本中的逻辑。由于您可能不是唯一需要处理脚本的人,因此您应该努力使它们尽可能完整。

COMMAND:

COMMAND(命令)指定要对对象执行的操作。可能的操作集取决于对象类型。通常,可以是 adddeleteshowlist )对象。但某些对象不允许所有的这些操作或具有一些其他命令,help 命令适用于所有的 OBJECT,它可以打印出可用命令和参数语法约定的列表。
即我们可以使用以下命令列出address的命令语法:

ip address help

如果没有给出命令,则假定一些默认命令。通常它是 showlist ), 或者,如果无法列出此类的对象,则默认输出 help

ARGUMENTS:

ARGUMENTS(参数)是具体化命令的命令选项列表。参数取决于命令和对象。可以发出以下两种类型的参数:
--- flags - 缩写为单个关键字。
--- parameters - consisting of a keyword followed by a value.
每个命令都有一个默认参数,如果省略参数,则使用默认参数。例如:dev参数是ip link命令的默认值,因此ip link list eth0相当于ip link list dev eth0
正如我们上面提到的对象名称,所有关键字都可以用第一个或前几个唯一字母缩写。当交互式使用ip时,这些快捷方式很方便,但不建议在脚本中使用它们,请不要在报告错误或寻求帮助时使用它们。

退出状态

如果命令成功,则退出状态为0;如果存在语法错误,则退出状态为1。如果内核报告错误,则退出状态为2。

常用命令:

ip link-网络设备配置

ip link show ---查看设备属性。

此语句中,show可写为:list,lst,sh,ls,l 。其后可跟以下参数:
* dev NAME(默认值)--- NAME指定要显示的网络设备。
如果省略此参数,则该命令将列出所有设备。

* up ---仅显示正在运行的接口。
例如,使用以下命令列出lo的信息:

ip link show dev lo
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00

冒号前面的数字是接口索引或ifindex,此编号唯一标识接口。如果查看cat / proc / net / dev的输出,您将看到网络设备的列出顺序与您在此处看到的编号相同。ifindex之后是接口名称(lo,eth0,venet0,sit0等)。接口名称在任何给定时刻也是唯一的,但接口可能会从列表中消失,例如卸载相应的驱动程序模块时,稍后将创建另一个具有相同名称的接口。此外,使用ip link set DEVICE name NEWNAME命令,系统管理员可以更改设备名称。
接口名称也可以有另一个名称或在“@”符号后附加关键字NONE。这表示此设备绑定到主/从设备关系中的另一个设备。因此,通过该设备发送的数据包被封装并通过主设备转发。如果名称为NONE,则主设备未知。
在接口名称之后,我们看到接口mtu(最大传输单元),它确定数据包的最大大小,该数据包可以通过该接口作为单个包发送。
qdisc(排队规则)显示在接口上使用哪种排队算法。特别的是,关键字noqueue意味着此接口不排队任何内容。关键字noop表示接口处于黑洞模式,其会立即丢弃送达的所有数据包。

以下这些信息都是尖括号内的选项。在尖括号内是汇总接口标志的位置。最常用的标志如下:

  • UP ---此设备已打开,准备接受数据包以传输到网络上,并且可能会从网络上的其他节点接收数据包。
  • LOOPBACK ---接口不与其他主机通信。通过它发送的所有数据包都将返回给发送方,并且可以接收退回的数据包。
  • BROADCAST ---此设备可以将数据包发送到共享相同物理链路的所有其他主机。示例:以太网
  • POINTOPOINT ---网络只有两端连接两个节点。发送到链路的所有数据包都将到达对等链路,并且所有收到的数据包都是由对等体发起的。
    如果既未设置LOOPBACK也未设置BROADCAST或POINTOPOINT,则假定接口是NBMA(非广播多路访问)链路。NBMA是最通用的设备类型,也是最复杂的设备类型,因为连接到NBMA链路的主机无法在没有其他手动提供的配置信息的情况下向任何其他主机发送信息。
  • MULTICAST ---一个标记接口多播的标志。广播是多播的一个特殊情况,其中多播组包含链路上的所有节点作为成员。请注意,软件不得将此标志的缺失解释为接口无法进行多播。根据定义,任何POINTOPOINT和BROADCAST链接都是多播的,因为我们可以直接访问所有链接邻居,从而直接访问它们的任何特定组。由于与传输相关的高成本,不建议在仅广播网络上使用高带宽多播传输,但不严格禁止这种使用。
  • PROMISC ---设备监听并向内核提供链路上的所有流量。这包括网络上通过收发器的每个数据包。通常,此模式仅存在于广播链路上,并由网桥和网络监控设备使用。
  • ALLMULTI ---设备接收在链路上漫游的所有多播数据包。组播路由器使用此模式。
  • NOARP ---这个标志与其他标志不同。它没有不变的值,其解释取决于所涉及的网络协议。通常,它表示设备不需要任何地址解析,并且软件或硬件知道如何在没有协议栈帮助的情况下传送数据包。
  • DYNAMIC ---是一个建议标志,将此接口标记为动态创建和销毁。
  • SLAVE ---此接口与其他接口绑定,以共享链路容量。

示例输出的第二行包含有关与设备关联的链路层地址的信息。第一个字定义接口硬件类型,然后确定地址的格式和语义,因此逻辑上是地址本身的一部分。站点和广播地址的默认格式(或点对点链接的对等地址)是由冒号分隔的十六进制字节序列。但是,某些链接类型可能会有自己的自然地址格式,这些格式在演示文稿中使用。IE:IP隧道的地址打印为点分四IP地址。虽然NBMA链路没有明确定义的广播或对等地址,但该字段可能包含有用的信息,例如广播中继的地址或ARP服务器的地址。

ip link set ---更改设备属性。

您可以使用ip link set 请求多个参数更改。如果您请求多个参数更改并且任何一个更改失败,则ip会在失败后立即中止,因此失败之前的参数更改已完成,并且不会在中止时撤消。这是使用ip命令使系统处于不可预测状态的唯一情况。解决方案是避免使用一个ip link set调用更改多个参数。根据需要使用尽可能多的单独 ip link set 命令来执行所需的操作。

参数:

  • dev NAME (default) --- NAME 指定操作的网络设备。
  • up / down --- 将设备状态更改为UP或DOWN。
  • arp on / arp off --- 更改设备上的NOARP标志状态。
    注意,如果设备已处于UP状态,则不允许此操作。由于ip utility和内核都不检查此情况,因此在设备运行时更改标志会产生非常不可预测的结果。最好将设备设置为关闭然后发出此命令。
  • multicast on / multicast off --- 更改设备上的MULTICAST标志。
  • dynamic on / dynamic off --- 更改设备上的DYNAMIC标志。
  • name NAME --- 更改设备名称。
    注意,如果设备正在运行或已配置某些地址,则不建议执行此操作。您会因在设备运行或已分配寻址时更改设备名称而导致破坏系统安全性并搞砸其他网络守护进程或程序。
  • txqueuelen NUMBER / txqlen NUMBER --- 更改设备的传输队列长度。
  • mtu NUMBER --- 更改设备的MTU。
  • address LLADDRESS --- 更改接口的站地址。
  • broadcast LLADDRESS, brd LLADDRESS or peer LLADDRESS --- 在POINTOPOINT接口的情况下更改链路层广播地址或对等地址。
    注意,对于大多数物理网络设备(以太网,令牌环等),更改链路层广播地址将破坏网络。如果你不明白这个操作到底做了什么,请不要使用这个参数。
  • ip命令不允许更改PROMISC或ALLMULTI标志,因为这些标志被认为是过时的,不应在管理上进行更改。

例子:
ip link set venet1 address 000000000001 --- 更改接口venet1的站地址(MAC地址)为000000000001。
ip link set venet1 up ---启动接口venet1。

ip link的其他命令还有ip link add (用于添加虚拟Link), ip link delete (用户删除虚拟Link),本文暂不讲述。具体可参考命令:ip link help,或可参考:IP Link - Linux Man Pages

ip address - 协议地址管理

缩略词: address, addr, a
可用命令: add, delete, flush, show (list)
地址是指连接到网络设备的协议(IP或IPv6)地址。每个设备必须至少有一个地址才能使用相应的协议。可以将多个不同的地址连接到一个设备。
ip addr命令允许您查看接口上的地址及其属性。您可以添加新地址并删除旧地址,而无需考虑任何排序。

ip address add ---添加新的协议地址。

参数:

  • dev NAME --- 我们添加地址的设备的名称。
  • local ADDRESS (default) --- 接口的地址。
    地址格式取决于协议。IPv4使用点分四组,IPv6使用由冒号分隔的十六进制半字序列。 ADDRESS后面可以跟一个斜杠和一个十进制数字,它以CIDR表示法编码网络前缀(子网掩码)长度。 如果未指定CIDR子网掩码表示法,则该命令假定指定了主机(/ 32掩码)地址。
  • peer ADDRESS--- pointopoint接口的远程端点的地址。同样,ADDRESS后面可能跟一个斜杠和十进制数字,编码网络前缀长度。如果指定了对等体地址则本地地址不能具有的网络前缀长度中的网络前缀与所述对等体相关联,而不是与本地地址。换句话说,在指定对等地址和本地地址时,只能将网络掩码分配给对等地址。
  • broadcast ADDRESS --- 接口上广播地址。
    可以使用特殊符号“+”和“ - ”代替指定广播地址。在这种情况下,广播地址由或设置所有接口主机位衍生的一个(+)或由所有接口主机位设置为零( - )。在IPv4网络的大多数现代实现中,您将需要使用(+)设置。与ifconfig不同,除非明确请求,否则ip命令不会设置广播地址。
  • label NAME --- 每个地址都可以用标签字符串标记。
    为了保持使用Linux-2.0净别名兼容性,这个字符串必须与设备的名称一致或必须用的设备名,后跟一个冒号前缀。(eth0:duh)
  • scope SCOPE_VALUE --- 此地址有效的区域范围。
    可用范围在以下文件中列出 /etc/iproute2/rt_scopes 。预定义的范围值为:
  • global --- 地址全局有效。
  • site --- (仅限IPv6)地址是本地站点,仅在此站点内有效。
  • link --- 地址是本地链接,仅在此设备上有效。
  • host --- 该地址仅在此主机内有效。

示例:
ip addr add 127.0.0.1/8 dev lo brd + scope host
--- 将通常的环回地址添加到环回设备。必须先启用该设备,然后才能显示此地址。

ip addr add 10.0.0.1/24 brd + dev eth0
--- 将地址长度为24(网络掩码255.255.255.0)的地址10.0.0.1和标准广播添加到接口eth0

ip address delete ---删除协议地址。

缩略:delete,del,d
参数:
参数与 ip addr add 的参数一致。设备名称是必需参数,其余是可选的。如果没有给出参数,则删除列出的第一个地址。

示例:
ip addr del 127.0.0.1/8 dev lo
--- 从loopback设备中删除环回地址。

Alexey states说:
"最好不要尝试重复这个实验 8-}"
删除接口eth0上的所有IPv4地址:

while ip -f inet addr del dev eth0; do
nothing
done

ip address show ---查看协议地址。

缩略:show,list,lst,sh,ls,l
参数:

  • dev NAME (default) --- 设备名称。
  • scope SCOPE_VAL --- 仅列出具有此范围的地址。
  • to PREFIX --- 仅列出与此前缀匹配的地址。
  • label PATTERN --- 仅列出标签与PATTERN匹配的地址。
    PATTERN是通常的shell regexp样式模式。
  • dynamic / permanent ---(仅限IPv6)仅列出stateless address configuration配置的地址,或仅列出永久(非动态)地址。
  • tentative --- (仅限IPv6)仅列出地址,但未通过重复地址检测。
  • deprecated --- 仅限IPv6)仅列出弃用的地址。
  • primary / secondary --- 仅列出主要(或次要)地址。
    示例:

ip -4 a ls eth0 ---列出eth0上的IPv4地址。

ip address flush ---刷新协议地址。

参数:
此命令刷新由某些条件筛选的协议地址。此命令与show具有相同的参数。主要区别在于,如果没有给出参数,则此命令不会运行。否则你可能会错误地删除所有地址。此命令(以及下面描述的其他刷新命令)非常危险。如果你犯了一个错误,命令不会请求确认或跳过,它真的会完全的地清除你的所有地址。一定要注意!

使用选项-statistics,命令变得详细,并打印出已删除的地址数和处理轮数以刷新地址列表。如果给出-statistics选项两次,那么ip addr flush也会以完整格式转储所有已删除的地址,如ip addr list部分所述。

ip neighbor --- neighbor/arp 表管理。

neighbour table对象在共享相同物理链路的主机的协议地址和链路层地址之间建立绑定。 Neighbour对象条目组织成表。IPv4 Neighbour对象表在另一个名称下称为ARP table。这些命令允许您查看neighbour table绑定及其属性,添加新neighbour table条目以及删除旧neighbour table条目。
参数:add, change, replace, delete, flush and show (list)

ip neighbor add ---添加新neighbor条目

ip neighbor change ---改变现有条目

ip neighbor replace ---添加新的或更改现有条目

缩略:add, a; change, chg; replace, repl
这些命令可创建新neighbor记录或更新现有neighbor记录。

  • to ADDRESS (default) --- 邻居的协议地址。它是IPv4或IPv6地址。
  • dev NAME --- 此邻居所连接的接口。
  • lladdr LLADDRESS --- 邻居的链路层地址。LLADDRESS可以为null。
  • nud NUD_STATE --- 邻居条目的状态。nud是“Neighbor Unreachability Detection”的缩写。

此状态可以采用以下值之一:

  • permanent --- 邻居条目永远有效,只能通过管理方式删除。
  • noarp --- 邻居条目有效,不会尝试验证此条目,但可以在其生命周期到期时删除。
  • reachable --- 邻居条目有效,直到可达性超时到期。
  • stale --- 邻居条目有效,但可疑。如果条目有效且此命令未更改地址,则ip neighbor的此选项不会更改邻居状态。

示例:
ip neigh add 10.0.0.3 lladdr 000001 dev eth0 nud perm
---在设备eth0上为邻居10.0.0.3添加永久ARP条目。
ip neigh chg 10.0.0.3 dev eth0 nud reachable
---将其状态更改为可达。

ip neighbor delete ---删除neighbor条目。

缩略:delete,del,d。
此命令使neighbor条目失效。参数与ip neigh add相同,只有lladdr和nud被忽略。
示例:
ip neigh del 10.0.0.3 dev eth0
---在设备eth0上使邻居10.0.0.3的ARP条目无效。
删除的neighbor条目不会立即从表中消失; 如果它正在使用中,则它在最后一个客户端释放它之前不会被删除,否则它将在下一次垃圾收集期间被销毁。
警告!尝试删除或手动更改内核创建的noarp条目可能会导致不可预测的行为。更具体地说,即使在NOARP接口上,内核也可能开始尝试解析该地址,或者将地址更改为多播或广播。

ip neighbor show ---列出邻居条目。

缩略:show,list,sh,ls。
此命令显示neighbor表。
参数:

  • to ADDRESS (default) --- 前缀选择要列出的neighbours。
  • dev NAME --- 仅列出连接到此设备的邻居。
  • unused --- 仅列出邻居,现在没有使用。
  • nud NUD_STATE --- 仅列出此状态中的邻居条目。 NUD_STATE takes values listed below after the example or the special value all, which means all the states. 此选项可能不止一次出现。如果没有此选项,ip将列出除none和noarp之外的所有条目。

ip neighbor flush ---刷新邻居条目。

此命令刷新邻居表。可以选择条目以通过各种标准进行刷新。
此命令与show具有相同的参数。请注意,在没有给出参数时它将不会运行,并且要刷新的默认邻居状态不包括permanent或noarp。
使用选项-statistics,命令输出变得详细,并打印出删除的邻居数和刷新邻居表时的轮数。如果选项被给出两次,ip neigh flush也会以前一小节中描述的格式转储所有已删除的邻居。

ip route - 路由表管理。

缩写:route,ro,r。
此命令管理内核路由表中的路由条目。内核路由表将有关协议路径的信息保存到其他网络节点。
因本人才疏学浅,暂只列出相关命令。

ip route add ---添加新路由。

ip route change ---改变路线。

ip route replace ---更改路由或添加新路由。

ip route delete ----删除路由。

ip route show ---此命令格式允许查看路由表内容并查看由某些条件选择的路由。

ip route flush --- 允许组删除路由,此命令允许按某些条件选择刷新路由。

ip route get --- 获取路由路径。此命令获取到目标的单个路径,并在内核看到时准确打印其内容。

ip rule ---路由策略数据库管理。

缩写:rule,ru。
路由策略数据库控制路由选择算法的规则。
因特网中使用的经典路由算法仅基于分组的目的地地址做出路由决定,并且在理论上,但在实践中不在TOS字段上。在某些情况下,我们希望以不同方式路由数据包,这不仅取决于目标地址,还取决于其他数据包字段,例如源地址,IP协议,传输协议端口甚至数据包有效负载。此任务称为“策略路由(policy routing)”。
"policy routing" != "routing policy" (“策略路由”!=“路由策略”)
"policy routing" = "cunning routing" (“策略路由” = “灵活路由”)
"routing policy" = "routing tactics" or "routing plan" (“路由策略”=“路由策略”或“路由计划”)
因本人才疏学浅,暂只列出相关命令。

ip rule add ---插入新规则。

ip rule show --- 列出策略规则。

ip tunnel - ip隧道配置。

ip tunnel add - 创建隧道。

ip tunnel show - 列出隧道属性。

ip monitor和rtmon ---路由状态监控。

ip实用程序允许连续监视设备,地址和路由的状态。此选项具有不同的格式,因为命令监视器首先在命令行上,后跟对象列表。
ip monitor [ file FILE ] [ all OBJECT-LIST ]
OBJECT-LIST是我们要监视的对象类型列表。它可能包含链接,地址和路由。如果没有给出文件参数,则ip打开RTNETLINK,监听它并以前面部分中描述的格式转储状态更改。
如果给出了文件名,则ip不会侦听RTNETLINK,而是打开假定包含以二进制格式保存的RTNETLINK消息的文件并将其转储。可以使用实用程序rtmon生成此类历史文件。此实用程序具有类似于ip monitor的命令行语法。理想情况下,应在发出第一个网络配置命令之前启动rtmon。可以随时启动rtmon,因为它使用在启动时转储的系统状态快照预先填充历史记录。


正是如此,IPROUTE2的IP实用程序是Linux下用于执行高级IP网络操作的ifconfig和路由实用程序的替代品。虽然标准实用程序足以满足简单设置,但仍建议学习使用ip实用程序,以便熟悉其用法并能够充分利用此实用程序的强大功能。

参考:

  1. Wiki页
    https://wiki.linuxfoundation.org/networking/iproute2
  2. Linux手册页-systutorials
    https://www.systutorials.com/docs/linux/man/8-ip/
  3. IPROUTE2 Utility Suite Howto
    http://www.policyrouting.org/iproute2.doc.html
  4. IP Link - Linux Man Pages
    https://www.systutorials.com/docs/linux/man/8-ip-link/
  5. 试试Linux下的ip命令,ifconfig已经过时了
    https://linux.cn/article-3144-1.html
  6. linux网络工具iproute2的使用简介
    https://blog.csdn.net/astrotycoon/article/details/52317288
  7. 新的网络管理工具 ip 替代 ifconfig 零压力
    https://linuxstory.org/replacing-ifconfig-with-ip/

使用Cloudflare的Page Rules实现支持通配符的301跳转

使用Cloudflare的Page Rules实现支持通配符的301跳转

前言:

  有些时候,比如我们网站更换域名时,我们需要使发布于各处的原始域名链接指向新的域名,以避免其变成死链。这种情况我们就需要使用301永久重定向(301 - Permanent Redirect)使原始域名链接指向新的域名。301重定向处于HTTP协议层,所以我们可能需要架设一个Web服务器来做301重定向;或者一些具有中国特色的域名解析服务商会提供一种叫做“显性URL”的功能(虽然301重定向不属于域名解析),这种情况是借助它们的服务器做了一个301跳转,但是据了解,国内域名解析服务商可能会要求域名有备案。这里有一个简单的解决方法,我们可以使用Cloudflare的Page Rules实现这个需求。

操作:

  首先要把源域名的DNS解析服务转到Cloudflare下,这样就要求你的源域名注册商是支持修改源域名的解析服务提供商的。否则本文就不适用了。
  打开 CloudFlare 网站:https://www.cloudflare.com 。注册账号并登录,点击 Add Websites,输入你要跳转的源域名所属的顶级域名,点击 Begin Scan,CloudFlare 会扫描你源域名当前的 DNS 记录,扫描完成后点击 Continue Setup。
  在Cloudflare给出的 DNS 列表中检查是否包含源域名的所有 DNS 记录,有缺就手动补上。然后点击 Continue。选择 Free Website 项,点击 Continue。
  Cloudflare 提示需要修改源域名的域名服务器,在源域名注册商处修改域名服务器到Cloudflare提示的服务器。修改后点击 Continue,等待域名服务器的修改生效,一般可能需要一定的时间。在 Cloudflare 主页上显示域名对应的状态(Status)为Active即表示已经域名服务器的变更已经生效了。
  在 DNS 选项卡下查看 DNS 记录。将你要跳转的域名解析到一个有效的 IP,比如 8.8.8.8,Status处选择通过 Cloudflare 。
  此处举例我要将test.lexsion.ml重定向到test.lexsion.com/old/
  我们选择 Page Rules 选项卡,点击Create Page Rule ,在 If the URL matches: 内填入源域名,需后跟通配符 /* 使所有页面均重定向,像这样:test.lexsion.ml/*,然后点击 Add a Setting ,选择 Forwarding URL ,在 Select Status Code 中选择 301 - Permanent Redirect ,然后在下方的Enter destination URL中输入要重定向到的网址,比如我想跳转到 test.lexsion.com/old/ ,并希望能使用通配符将请求的目录和文件结构带过来。那我需要输入 https://test.lexsion.com/old/$1 ,然后点击 Save and Deploy ,等待一段时间让Cloudflare规则生效就完成了。

  这时我们输入 http://test.lexsion.ml/XXXX.html 就会跳转到 https://test.lexsion.com/old/XXXX.html 。当然本文所写链接仅为举栗子,实际没有跳转效果。

树莓派ZeroW搭建PHP环境运行BiliHelper实现BiliBliLive自动捡辣条

树莓派ZeroW搭建PHP环境运行BiliHelper实现BiliBliLive自动捡辣条

前言

树莓派(RaspberryPi)是一类卡片型计算机,其有一枚博通的ARM处理器,可以运行基于Debian的Raspbian系统。其具有低价的硬件,较低的功耗,小巧的外观。而树莓派ZeroW拥有更小的外观,具有2.4GWIFI功能,且价格不到百元。
BiliBili是是一个弹幕视频网站,后期发展了直播业务BiliBiliLive,目前其有设计某些礼物赠送时会触发全网通告抽奖任务,然后大家蜂拥而上,来到这个直播房间抽奖。奖品目前基本为辣条或粉丝亲密度,这个虽不涉及财物,但涉及粉丝勋章升级,其亦乃兵家必争之地(货?)。
既然这个抽奖对我们有用,那便可以加以利用。正常情况下,我们手动操作Web网页端或APP端效率低下,于是考虑可以使用一些辅助脚本等实现自动化领取。于是就出现某些网友分享实现方式,比如 metowolf的BilibiliHelper ,然后就有基于该项目的 lkeme的BiliHelper 。感谢以上两位大佬的付出。本文所讲述的就是使用这个脚本,我们将在树莓派ZeroW上配置一个PHP环境,然后运行这个脚本。

读懂实践本文,你可能需要在技能树中点亮以下技能:

  • 树莓派装配、启动操作;
  • 基本的Windows系统与Linux系统操作;

准备

  • 运行Windows电脑一台(其他系统也可,但具体某些操作可能不同)
  • 树莓派ZeroW一套(包含主板卡、8G或以上的MicroSD卡、电源)
  • MicroSD卡读卡器
  • SSH客户端,我用的是Putty

操作警告:
使用外部程序完成原本应手动完成操作的行为,可能导致您的BiliBili账号被封禁!本人及相关项目的作者等均不会对使用脚本产生的损失负责,亦不会对您学习本文的操作负责。继续操作,请自行承担风险!

步骤

  • 1.写入映像到MicroSD卡并启动
  • 2.Raspbian系统配置
  • 3.配置PHP环境
  • 4.配置脚本并运行脚本
  • 5.脚本任务的自动化配置

1.写入映像到MicroSD卡并启动

打开树莓派官网选择合适的方法下载合适的映像文件。因为本文实现的功能都是在命令行终端下完成的,不需要桌面系统,所以我选的是Raspbian Stretch Lite这个版本。
Torrent下载
ZIP
我们下载回来的是压缩包文件,解压后里面的img文件便是系统映像。

Etcher是一种图形化SD卡写入工具,适用于Mac OS,Linux和Windows,是RaspberryPi官网推荐的最简单的映像写入工具。Etcher还支持直接从zip文件中读取映像并开始写入,无需任何解压缩。用Etcher实现写入映像:
1.下载Etcher并安装它。
2.将SD卡插入SD卡读卡器并连接电脑。
3.打开Etcher并从磁盘驱动器中选择要写入SD卡的.img或.zip文件。
4.选择要写入映像的SD卡,注意确认不要选错,错误的选择会导致损坏您所选存储设备的资料
5.检查您的选择,然后点击“Flash!/”开始将数据写入SD卡,写入完成后软件会自动安全移除并告知您操作完成。
6.完成后便可以关闭软件,拔下存储卡了。
(其他操作系统与软件操作方法可以查阅官网此页下方的更多链接)

2.Raspbian系统配置

连接WIFI并开启SSH:

将SD卡插入SD卡读卡器并连接电脑。
在电脑显示的/boot下创建文件"wpa_supplicant.conf"。
编辑文件内容如下格式所示,SSID与PSK等对应选项请自行调整:

country=CN
ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev
update_config=1

network={
ssid="我是WIFI名字"
psk="WIFI密码"
key_mgmt=WPA-PSK
priority=1
}

以上是WiFi 配置示例。具体含义:

ssid:网络的ssid
psk:网路的密码
priority:连接优先级,数字越大优先级越高(不可以是负数)
scan_ssid:连接隐藏WiFi时需要指定该值为1

然后在/boot下创建空文件“ssh”,注意全小写。

完成操作后安全移除硬件,将MicroSD卡插入树莓派中。

以上操作可具体参考以下链接:
无屏幕和键盘配置树莓派WiFi和SSH
Setting up a Raspberry Pi headless
Setting WiFi up via the command line

启动并连接树莓派

将树莓派通电,等待至树莓派指示灯不再快速闪烁(建议通电后先等待90秒)。
查找树莓派的IP地址,我在Windows命令提示符下尝试运行Ping树莓派默认主机名:

ping raspberrypi

从回显的信息中我得到了一个IP地址,观察此IP地址与我的电脑在一个子网内,判断这应该是正确的IP。
(获取IP的方式不只一种,你可以从路由器的管理页面获取,或者尝试在电脑或手机上安装局域网扫描软件来查找树莓派IP地址。可参考本文:IP Address

使用SSH客户端通过填入IP地址连接树莓派,我使用的Putty。该软件使用方法不再赘述,不会可参考本文

使用用户名“pi”,密码:raspberry登陆到树莓派。

修改软件源为国内源

由于一些“未知”的原因,我们连接官方的软件源时速度慢,经常断开,所以我们需要将其修改为国内镜像源。比如我改为清华源。需要编辑 /etc/apt/sources.list 文件,参考命令如下:

pi@raspberrypi ~ $ sudo nano /etc/apt/sources.list

用以下内容替代原文内容:

deb http://mirrors.tuna.tsinghua.edu.cn/raspbian/raspbian/ stretch main non-free contrib
deb-src http://mirrors.tuna.tsinghua.edu.cn/raspbian/raspbian/ stretch main non-free contrib

nano编辑器中按F3,提示编辑保存的文件名,直接保持原始文件名,Enter键确认。再按Ctrl+“X”键退出nano编辑器。
编辑镜像站后,请使用 sudo apt-get update 命令,更新软件源列表,同时检查您的编辑是否正确。
然后运行 sudo apt-get upgrade 命令将所有已经安装在系统内的包升级为最新版本。
具体参考:Raspbian 镜像使用帮助

或可使用中科大源,参考http://mirrors.ustc.edu.cn/help/raspbian.html

本地化设置

使用以下命令通过APT安装中文字体:

sudo apt-get install ttf-wqy-zenhei

安装过程中如果碰到(Y/n),请输入Y并回车。

运行以下命令打开Raspbian的软件配置工具:

sudo raspi-config

上下键移动光标到 Localisation Options 选项,按Enter键进入设置项,在 Change Locale 选项中可以调整系统语言和地区,我这就不修改了。选择 Change Timezone -> Asia ,通过按Pagedown键、Pageup键与方向键调整光标到 Shanghai 并使用Enter键确定,将时区设置为上海。按Tab键调整光标所处区域,通过方向键选择 Finish 退出配置工具。

3.配置PHP环境

我使用oneinstack提供的LNMP一键包来配置PHP环境。这需要漫长的时间,为保证不会因网络问题中断安装进程,我们使用Screen来操作。使用以下命令安装Screen。

sudo apt-get -y install screen

使用以下命令获取LNMP的安装包:

wget http://mirrors.linuxeye.com/oneinstack-full.tar.gz

下载完成后使用以下命令解压文件:

tar xzf oneinstack-full.tar.gz

使用 cd oneinstack 命令进入oneinstack目录.

使用以下命令创建一个名为oneinstack的会话窗口:

screen -S oneinstack

如果网路出现中断,可以执行命令screen -R oneinstack重新连接安装窗口。
运行 sudo ./install.sh 开始安装脚本,按照自己需求选择要安装的模块,比如我选择了安装Web server和PHP,具体过程如下:

Please input SSH port(Default: 22): 22

Do you want to enable iptables? [y/n]: y

Do you want to install Web server? [y/n]: y

Please select Nginx server:
        1. Install Nginx
        2. Install Tengine
        3. Install OpenResty
        4. Do not install
Please input a number:(Default 1 press Enter) 1

Please select Apache server:
        1. Install Apache-2.4
        2. Install Apache-2.2
        3. Do not install
Please input a number:(Default 3 press Enter) 3

Please select tomcat server:
        1. Install Tomcat-9
        2. Install Tomcat-8
        3. Install Tomcat-7
        4. Install Tomcat-6
        5. Do not install
Please input a number:(Default 5 press Enter) 5


Do you want to install Database? [y/n]: n

Do you want to install PHP? [y/n]: y

Please select a version of the PHP:
        1. Install php-5.3
        2. Install php-5.4
        3. Install php-5.5
        4. Install php-5.6
        5. Install php-7.0
        6. Install php-7.1
        7. Install php-7.2
        8. Install php-7.3
Please input a number:(Default 5 press Enter) 7

Do you want to install opcode cache of the PHP? [y/n]: n

Please select PHP extensions:
        0. Do not install
        1. Install zendguardloader(PHP<=5.6)
        2. Install ioncube
        3. Install sourceguardian(PHP<=7.2)
        4. Install imagick
        5. Install gmagick
        6. Install fileinfo
        7. Install imap
        8. Install ldap
        9. Install phalcon(PHP>=5.5)
        10. Install redis
        11. Install memcached
        12. Install memcache
        13. Install mongodb
        14. Install swoole
        15. Install xdebug(PHP>=5.5)
Please input numbers:(Default '4 10 11' press Enter) 0

Do you want to install Pure-FTPd? [y/n]: n

Do you want to install phpMyAdmin? [y/n]: n

Do you want to install redis-server? [y/n]: n

Do you want to install memcached-server? [y/n]: n

Do you want to install HHVM? [y/n]: n

然后就是漫长的等待了,安装成功后会提示成功,并询问是否重新启动,选择重新启动,待启动后重新连接终端。

使用以下命令进入LNMP包目录,运行以下命令添加组件,我们这里添加 PHP Composer :

pi@raspberrypi:~ $ cd oneinstack/

pi@raspberrypi:~/oneinstack $ sudo ./addons.sh

What Are You Doing?
        1. Install/Uninstall PHP Composer
        2. Install/Uninstall fail2ban
        3. Install/Uninstall ngx_lua_waf
        4. Install/Uninstall Python3.6
        q. Exit
Please input the correct option:1
    
Please select an action:
        1. install
        2. uninstall
Please input a number:(Default 1 press Enter) 1

PHP Composer installed successfully!

What Are You Doing?
    1. Install/Uninstall PHP Composer
    2. Install/Uninstall fail2ban
    3. Install/Uninstall ngx_lua_waf
    4. Install/Uninstall Python3.6
    q. Exit

Please input the correct option: q

关于这个脚本的具体使用,可以参考安装步骤-Oneinstack

4.配置脚本并运行脚本

因相关代码作者开源在GitHub,我们需要使用Git工具拉取项目文件。使用以下命令通过APT安装Git:

sudo apt-get install git

如已经安装APT会提示已经安装了,如果提示Y/n,输入Y回车即可。

回到用户目录,拉取项目文件到本地:

cd
git clone https://github.com/lkeme/BiliHelper.git

关于Git的使用可以参考此书:Pro Git
PDF文件直链:progit_v2.1.17

进入配置目录,从 user.conf.example 创建 user.conf,并使用nano编辑器修改配置:

cd BiliHelper/conf
cp user.conf.example user.conf
nano user.conf

在出现的界面中填入B站用户名和密码(用户名为注册邮箱或注册手机号),完成后F3保存,Ctrl+X退出。

使用 composer 工具进行安装:

composer install

若提示(Y/n)请输入y回车。

这时,我们可以返回上层目录中,运行index.php开始脚本了:

cd ..
php index.php

如果一切正常,脚本现在已经能够捡辣条了。只要树莓派不关机,电脑上的终端不关闭。
(脚本默认加载user.conf,如果需要多账户,可复制配置文件修改账号密码,使用php index.php example.conf指定配置文件运行)

这种情况如果我们关闭终端窗口,BiliHelper 就停止了,这样肯定是非常麻烦。我们可以借助Screen来实现后台运行。
GNU Screen是一款由GNU计划开发的用于命令行终端切换的自由软件。用户可以通过该软件同时连接多个本地或远程的命令行会话,并在其间自由切换。其可以看作是窗口管理器的命令行界面版本。它提供了统一的管理多个会话的界面和相应的功能。

首先Ctrl+C停止BiliHelper,使用以下命令创建一个名为Bili的的session:

screen -S Bili

在终端中使用 php index.php 运行BiliHelper,然后使用 Ctrl+a+d 组合键便可以分离这个Session,这时我们就可以安全的使用 exit 命令断开终端与树莓派的连接了,如果我们需要再次连接到这个Session,可以在终端中运行: screen -r Bili ,若Session处于分离状态,便会重新连接。

Screen 官方文档在此,关于Screen的使用可参考本文:linux screen 命令详解

5.脚本任务的自动化配置

systemd是Linux计算机操作系统之下的一套中央化系统及设置管理程序(init),包括有守护进程、程序库以及应用软件,由Lennart Poettering带头开发。其开发目标是提供更优秀的框架以表示系统服务间的依赖关系,并依此实现系统初始化时服务的并行启动,同时达到降低Shell的系统开销的效果,最终代替现在常用的System V与BSD风格init程序。
由此看来,使用systemd管理我们的脚本是一种比较迎合系统的方法。

在以下位置 /etc/systemd/system/ 创建文件 bilibili.service 文件内容如下:

                                                                                 
# /etc/systemd/system/bilibili.service

[Unit]
Description=BiliHelper Manager
Documentation=https://github.com/lkeme/BiliHelper
After=network.target

[Service]
ExecStart=/usr/local/php/bin/php /home/pi/BiliHelper/index.php
Restart=always

[Install]
WantedBy=multi-user.target

这个文件的创建可参考本文替换软件源小节内容,使用nano编辑器创建。

这样我们就创建了一个Service单元配置文件,可见其信息包含三大部分:Unit-主要包含一些基本描述信息与依赖关系;Service-主要描述这个SService运行的内容;Install-安装信息。以下详细介绍每行内容含义:

[Unit]
Description=BiliHelper Manager     //这个Unit的描述,写给人看的。
Documentation=https://github.com/lkeme/BiliHelper       //这个服务的文档,给人看的。
After=network.target   //表示network.target完成后,才会开始启动这个服务。

[Service]
ExecStart=/usr/local/php/bin/php /home/pi/BiliHelper/index.php   //指定服务启动的主要命令
Restart=always     //让服务在退出时能自动重启
#Restart值用于指定在什么情况下需要重启服务进程。常用的值有 no,on-success,on-failure,on-abnormal,on-abort 和 always。默认值为 no,即不会自动重启服务。这些不同的值分别表示了在哪些情况下,服务会被重新启动,参见下方表。

[Install]
WantedBy=multi-user.target  
# 表明当系统以多用户方式(默认的运行级别)启动时,这个服务需要被自动运行。
# 当然,这还需要 systemctl enable 激活这个服务以后自动运行才会生效。

Restart配置为不同值时分别会在哪些情况下重启服务(表格解析异常):

服务退出原因noalwayson-failureon-abnormalon-abortno-success
正常退出
异常退出
启动/停止超时
被异常KILL

Install 段中的配置与 Unit 有几分相似,但是这部分的配置需要通过 systemctl enable 命令来激活,并且可以通过 systemctl disable 命令禁用。另外这部分配置的目标模块通常是特定启动级别的 .target 文件,用来使得服务在系统启动时自动运行。所以我们把服务添加上【当系统以多用户方式(默认的运行级别)启动时,这个服务需要被自动运行。】这个配置信息后,使用 systemctl enable 激活后就可以实现让这个服务在开机时自动运行。
Unit文件的详细解析可参考此文:Systemd的Unit文件; systemctl增加服务详细介绍

创建bilibili.service文件后使用以下命令将其添加到开机自动启动:

sudo systemctl enable bilibili.service

使用以下命令立即启动:

sudo systemctl start  bilibili.service

使用以下命令输出运行状态:

systemctl status  bilibili.service

如果你学习到此,且一切正常,你应该已经成功开始了自动捡辣条之路。恭喜您距离封号又近了一步。

若您后期需要某些调整,以下命令可能有用:

使用以下命令可删除其开机自动启动:

sudo systemctl disable bilibili.service

使用以下命令可检查单元是否配置为自动启动:

sudo systemctl is-enabled bilibili.service

使用以下命令立即停止:

sudo systemctl stop bilibili.service

使用以下命令立即重启:

sudo systemctl restart  bilibili.service

使用以下命令重载配置:

sudo systemctl reload  bilibili.service

如果修改了bilibili.service文件,需使用以下命令重载systemd 系统配置:

systemctl daemon-reload

使用此命令显示系统状态:

systemctl status

使用以下命令输出激活的单元:

systemctl

使用以下命令输出运行失败的单元:

systemctl --failed

*具体命令参考:[systemd (简体中文)]
https://wiki.archlinux.org/index.php/systemd_(%E7%AE%80%E4%BD%93%E4%B8%AD%E6%96%87)#%E7%BC%96%E5%86%99%E5%8D%95%E5%85%83%E6%96%87%E4%BB%B6*


表格解析异常,提供本文Markdown原始文件:树莓派ZeroW搭建PHP环境运行BiliHelper实现BiliBliLive自动捡辣条.zip

参考:

Installing operating system images
https://www.raspberrypi.org/documentation/installation/installing-images/README.md

Setting up a Raspberry Pi headless
https://www.raspberrypi.org/documentation/configuration/wireless/headless.md

Setting WiFi up via the command line
https://www.raspberrypi.org/documentation/configuration/wireless/wireless-cli.md

无屏幕和键盘配置树莓派WiFi和SSH
http://shumeipai.nxez.com/2017/09/13/raspberry-pi-network-configuration-before-boot.html

IP Address
https://www.raspberrypi.org/documentation/remote-access/ip-address.md

Raspbian 镜像使用帮助
https://mirror.tuna.tsinghua.edu.cn/help/raspbian/

安装步骤-Oneinstack
https://oneinstack.com/install/

Systemd的Unit文件; systemctl增加服务详细介绍
https://blog.csdn.net/shuaixingi/article/details/49641721

systemd (简体中文)
https://wiki.archlinux.org/index.php/systemd_(%E7%AE%80%E4%BD%93%E4%B8%AD%E6%96%87)#%E7%BC%96%E5%86%99%E5%8D%95%E5%85%83%E6%96%87%E4%BB%B6

Git学习笔记

Git学习笔记

目录

1.什么是Git?

生活工作或学习中我们有时需要保存一个文件不同时间的多个版本,以便在未来时间我们可以再次查阅。一般情况我们都会复制一份文件,在文件名中加入能够表示时间的文字,以此保证日后查阅时能按照时间找到需要的文件,这样修改的次数多了就会非常麻烦。还有一种情况,我们有时需要多个人编辑同一个文件,我们可以使用文件共享或搭建FTP服务器共享。这种方式如果需要确定文件是谁什么时间编辑的,那就会非常的麻烦。而且如果某人失误损坏了文件,那将是灾难性的。
而Git这个版本控制软件就是为解决这种问题而被设计的。它是一个分布式的版本控制系统,是一个软件。最初由林纳斯·托瓦兹创作,最初的目的是为更好地管理Linux内核开发而设计。Git易于使用,效率高,它支持非线性分支管理文件。
Git的实现是直接记录快照,而不是记录文件的差异对比。其像是把数据看作一组文件快照,每次修改完提交后,就会记一次版本,如果文件没有修改,就会通过链接指向文件,它对待数据就像是一个快照流,我们所有的操作几乎都可以在本地完成。Git有校验文件完整的机制,所有数据在存储之前都会计算校验和,其使用Hash算法通过文件目录和内容来计算校验和。
Git的仓库(.git文件夹),英文名:Repository,仓库用来保存项目的原始数据和对象数据。Git的工作目录,英文名:Working Directory,工作目录是对项目的某个版本提取出来的内容,这些内容供我们使用或修改。当我们修改了某些文件后,对应被修改的文件会在暂存区生成一个列表,用于标记下次提交时要提交的文件。一般的使用流程就是文件在工作目录中修改,被标记在暂存区,执行提交后会提交到仓库中记录一次版本。
区别于我们在本地创建的本地仓库,当然就有存于远程服务器上的远程仓库。其是为多人共享而建立,亦可以看作安全考虑而设置的本地文件的备份。

2.Git的基本操作

本节内容包含Git的安装和基本命令。其基本命令包含初始化仓库、查看仓库状态、暂存操作、本地提交操作、提交本地仓库到远端仓库、从远端仓库拉取仓库数据到本地。

安装Git

CentOS上安装:

yum -y install git

Ubuntu安装:

apt-get install git-all

Windows系统可以去Github项目:Git for Windows/git 的Release下下载对应版本的文件并安装。

安装完Git后我们需要对其进行一些简单的配置,比如配置用户名和邮箱。

git config --global user.name "You Name"
git config --global user.email "youmail@XXX.XX"

Git基本命令

Git命令行的操作类似于Linux shell,首先我们先创建一个Git仓库,比如,我将其创建在E:/git_repos/Git-Tutorial。
使用以下命令创建目录:

cd E:
mkdir git_repos
cd git_repos
mkdir Git-Tutorial
cd Git-Tutorial

以上步骤操作完成后就创建了一个普通的目录,此时这是一个普通的文件夹。使用以下命令初始化Git仓库:

git init

此时系统回显以下信息:

User@PC MINGW64 /e/git_repos/Git-Tutorial
$ git init
Initialized empty Git repository in E:/git_repos/Git-Tutorial/.git/
User@PC MINGW64 /e/git_repos/Git-Tutorial (master)

这时可以看到,终端里面看到的是显示一个Master分支;默认状态下Git会自动为我们初始化一个名为Master的分支。
使用以下命令查看目录下的文件:

ll

出现如下提示,表示目录下没有内容,是空的。

total 0

我们可以使用touch命令创建一个文件README.md,然后使用git status命令查看当前Git仓库状态。

touch README.md

User@PC MINGW64 /e/git_repos/Git-Tutorial (master)
$ git status
On branch master

No commits yet

Untracked files:
  (use "git add <file>..." to include in what will be committed)

        README.md

nothing added to commit but untracked files present (use "git add" to track)

从Git仓库状态信息里可以看出,当前所在分支为Master分支,没有任何的commits(提交)。另外,其下方显示一个未跟踪的文件列表,其中列出所有的存在目录中但是没有被跟踪的文件,并且Git会提示如何将其包含到暂存中(待提交的列表中)。
我们使用git add README.md命令将文件暂存,再通过git status命令查看状态:

User@PC MINGW64 /e/git_repos/Git-Tutorial (master)
$ git add README.md

User@PC MINGW64 /e/git_repos/Git-Tutorial (master)
$ git status
On branch master

No commits yet

Changes to be committed:
  (use "git rm --cached <file>..." to unstage)

        new file:   README.md

这时我们可以看到提示,在Master分支中,暂存中有新增一个文件,README.md,并且提示了,使用git rm --cached <file>...可以将文件返回上一状态。我们可以试一下:

User@PC MINGW64 /e/git_repos/Git-Tutorial (master)
$ git rm --cached README.md
rm 'README.md'

User@PC MINGW64 /e/git_repos/Git-Tutorial (master)
$ git status
On branch master

No commits yet

Untracked files:
  (use "git add <file>..." to include in what will be committed)

        README.md

nothing added to commit but untracked files present (use "git add" to track)

我们还可以使用git add -A命令实现将目录下所有文件加入到暂存区中:

User@PC MINGW64 /e/git_repos/Git-Tutorial (master)
$ git add -A

User@PC MINGW64 /e/git_repos/Git-Tutorial (master)
$ git status
On branch master

No commits yet

Changes to be committed:
  (use "git rm --cached <file>..." to unstage)

        new file:   README.md

目前我们做到了将README.md 文件存于暂存区。当我们需要记录一个版本时,我们便需要做一次提交。使用git commit进行提交,建议其后跟随-m参数,用于备注这次提交的说明。当我们提交后,再次使用git status查看状态:

User@PC MINGW64 /e/git_repos/Git-Tutorial (master)
$ git commit -m "add README.md"
[master (root-commit) dfaaa0b] add README.md
 1 file changed, 0 insertions(+), 0 deletions(-)
 create mode 100644 README.md

User@PC MINGW64 /e/git_repos/Git-Tutorial (master)
$ git status
On branch master
nothing to commit, working tree clean

提交到GitHub

首先需要注册一个Github账号,然后新建一个仓库,填入自己需要的名字,然后创建。
创建后使用以下命令添加,并将代码push到Github。这期间可能需要输入用户名和密码,将Github账号密码输入即可:

User@PC MINGW64 /e/git_repos/Git-Tutorial (master)
$ git remote add origin https://github.com/<用户名>.../<仓库名>.git

User@PC MINGW64 /e/git_repos/Git-Tutorial (master)
$ git push -u origin master
Enumerating objects: 3, done.
Counting objects: 100% (3/3), done.
Writing objects: 100% (3/3), 218 bytes | 109.00 KiB/s, done.
Total 3 (delta 0), reused 0 (delta 0)
To https://github.com/<用户名>.../<仓库名>.git
 * [new branch]      master -> master
Branch 'master' set up to track remote branch 'master' from 'origin'.

既然有将代码提交到Github,那就需要克隆远程仓库到本地,使用如下命令将仓库git-test克隆到本地,并命名为git-demo:

git clone <远端仓库> <本地名称>
User@PC MINGW64 /e/git_repos/Git-Tutorial (master)
$ cd ..

User@PC MINGW64 /e/git_repos
$ git clone https://github.com/<用户名>.../git-test.git git-demo
Cloning into 'git-demo'...
remote: Enumerating objects: 3, done.
remote: Counting objects: 100% (3/3), done.
remote: Total 3 (delta 0), reused 3 (delta 0), pack-reused 0
Unpacking objects: 100% (3/3), done.

仓库克隆到本地后,我们便可以对里面的文件进行修改,修改后的文件自然也可以提交到Github。首先我们使用cd git-demo进入这个仓库,使用文本编辑器(比如vi)修改README.md文件内容为自定义内容,比如:

# Hello Word
This is a file for Test/Study.

然后我们使用 git status 查看 git-demo 这个本地仓库的状态,会提示 README.md 文件的状态是 modified ,意思是被修改了。按照提示,我们尝试运行 git add README.md 命令,或使用 git add -A 命令全部添加到暂存区。最后我们运行 git status 确认一下状态(可选),使用 git-commit 提交修改(建议使用-m "说明文本"添加提交说明)。过程如下:

User@PC MINGW64 /e/git_repos/git-demo (master)
$ vi README.md

User@PC MINGW64 /e/git_repos/git-demo (master)
$ git status
On branch master
Your branch is up to date with 'origin/master'.

Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

        modified:   README.md

no changes added to commit (use "git add" and/or "git commit -a")

User@PC MINGW64 /e/git_repos/git-demo (master)
$ git add -A
warning: LF will be replaced by CRLF in README.md.
The file will have its original line endings in your working directory

User@PC MINGW64 /e/git_repos/git-demo (master)
$ git status
On branch master
Your branch is up to date with 'origin/master'.

Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

        modified:   README.md


User@PC MINGW64 /e/git_repos/git-demo (master)
$ git commit -m "Modified README.md"
[master 935539d] Modified README.md
 1 file changed, 2 insertions(+)

我们在本地完成了git-demo的提交,接下来便可以使用 git push 命令将仓库同步到Github的远端仓库git-test。然后我们也可以在git-tutorial中使用git-pull拉取新的代码,git pull 后面可以跟随仓库链接和分支名称。需要注意的是,在拉取之前git-tutorial中的数据是旧的,我们可以使用cat命令验证。操作如下:

User@PC MINGW64 /e/git_repos/git-demo (master)
$ git push
Enumerating objects: 5, done.
Counting objects: 100% (5/5), done.
Writing objects: 100% (3/3), 293 bytes | 97.00 KiB/s, done.
Total 3 (delta 0), reused 0 (delta 0)
To https://github.com/<用户名>/git-test.git
   dfaaa0b..935539d  master -> master

User@PC MINGW64 /e/git_repos/git-demo (master)
$ cd ..

User@PC MINGW64 /e/git_repos
$ ll
total 0
drwxr-xr-x 1 Lexsion 197609 0 1月  13 23:28 git-demo/
drwxr-xr-x 1 Lexsion 197609 0 1月  13 00:15 Git-Tutorial/

User@PC MINGW64 /e/git_repos
$ cd Git-Tutorial

User@PC MINGW64 /e/git_repos/Git-Tutorial (master)
$ ll
total 0
-rw-r--r-- 1 Lexsion 197609 0 1月  13 00:15 README.md

User@PC MINGW64 /e/git_repos/Git-Tutorial (master)
$ cat README.md

User@PC MINGW64 /e/git_repos/Git-Tutorial (master)
$ git pull
remote: Enumerating objects: 5, done.
remote: Counting objects: 100% (5/5), done.
remote: Total 3 (delta 0), reused 3 (delta 0), pack-reused 0
Unpacking objects: 100% (3/3), done.
From https://github.com/<用户名>/git-test
   dfaaa0b..935539d  master     -> origin/master
Updating dfaaa0b..935539d
Fast-forward
 README.md | 2 ++
 1 file changed, 2 insertions(+)

User@PC MINGW64 /e/git_repos/Git-Tutorial (master)
$ cat README.md
# Hello Word
This is a file for Test/Study.

3.Git的分支

软件开发过程中,我们会有新增功能也有修复BUG,这两者可能是同时存在又独立的。在Git中,为我们提供了一个叫做分支(Branch)的东西来处理这种情况,以此保证BUG的修复与新功能的增加不会互相干扰,不同的人处理不同的分支,不必担心其他人破坏了环境。分支是为了将修改记录的整个流程做一个分岔的保存,分支亦可以在未来合并。
我们在创建仓库时,Git会默认创建一个master分支。在此之后的提交,在切换分支之前,都会提交到这个master分支中。Git分支中有一个概念叫做HEAD,它指向当前在使用的分支中的最后一次更新,通常其指向master分支的最后一次提交。我们可以通过移动这个指针来变更当前分支。
我们可以使用 git branch <新分支名字> 来创建新的分支,通过git branch命令查看当前仓库有哪些分支,使用git checkout <分支名> 来选择当前操作的分支,比如我们新建feature1分支并切换到这个分支。

User@PC MINGW64 /e/git_repos/Git-Tutorial (master)
$ git branch feature1

User@PC MINGW64 /e/git_repos/Git-Tutorial (master)
$ git branch
  feature1
* master

User@PC MINGW64 /e/git_repos/Git-Tutorial (master)
$ git checkout feature1
Switched to branch 'feature1'

User@PC MINGW64 /e/git_repos/Git-Tutorial (feature1)

切换到feature1后,可以看到后面括号中的分支名称已经变成了feature1。接下来就可以编辑这个分支,而不必担心影响其他分支。比如我想在里面新建一个a.txt,编辑一下,加入到仓库并提交。如下:

User@PC MINGW64 /e/git_repos/Git-Tutorial (feature1)
$ touch a.txt

User@PC MINGW64 /e/git_repos/Git-Tutorial (feature1)
$ vi a.txt

User@PC MINGW64 /e/git_repos/Git-Tutorial (feature1)
$ git add a.txt
warning: LF will be replaced by CRLF in a.txt.
The file will have its original line endings in your working directory

User@PC MINGW64 /e/git_repos/Git-Tutorial (feature1)
$ git commit -m "Add a.txt"
[feature1 fcf80e7] Add a.txt
 1 file changed, 3 insertions(+)
 create mode 100644 a.txt

这时,我们的feature1就成功提交到本地仓库了。如果我们需要再基于feature1建立一个分支feature2,那么就输入git branch <分支名称>命令创建新分支,然后使用git check out <分支名> 切换到这个分支。

User@PC MINGW64 /e/git_repos/Git-Tutorial (feature1)
$ git branch feature2

User@PC MINGW64 /e/git_repos/Git-Tutorial (feature1)
$ git checkout feature2
Switched to branch 'feature2'

我们亦可以使用一条命令完成这个过程,比如我们创建feature3并切换到该分支:

User@PC MINGW64 /e/git_repos/Git-Tutorial (feature2)
$ git checkout -b feature3
Switched to a new branch 'feature3'

User@PC MINGW64 /e/git_repos/Git-Tutorial (feature3)

若要删除一个分支,需要执行git branch -d <分支名> 。如下删除feature2分支:

User@PC MINGW64 /e/git_repos/Git-Tutorial (feature3)
$ git branch -d feature2
Deleted branch feature2 (was fcf80e7).

我们在feature3下检查里面的文件,可以看到继承自feature2的文件都还在。尝试建立一个b.txt文件,编辑一下,加入仓库并提交。然后我们切换到master分支,通过命令 git branch -d <分支名> 删除分支feature3,会发现无法删除。系统会提示我们这个分支其中的更改没有合并到其他分支,如果需要强制删除可以使用 git branch -D <分支名> 强行删除,或考虑合并到其他分支。 如下:

User@PC MINGW64 /e/git_repos/Git-Tutorial (feature3)
$ ll
total 2
-rw-r--r-- 1 Lexsion 197609 33 1月  14 01:22 a.txt
-rw-r--r-- 1 Lexsion 197609 46 1月  14 00:03 README.md

User@PC MINGW64 /e/git_repos/Git-Tutorial (feature3)
$ touch b.txt

User@PC MINGW64 /e/git_repos/Git-Tutorial (feature3)
$ vi b.txt

User@PC MINGW64 /e/git_repos/Git-Tutorial (feature3)
$ git add b.txt
warning: LF will be replaced by CRLF in b.txt.
The file will have its original line endings in your working directory

User@PC MINGW64 /e/git_repos/Git-Tutorial (feature3)
$ git commit -m "add b.txt"
[feature3 a03ddaa] add b.txt
 1 file changed, 1 insertion(+)
 create mode 100644 b.txt

User@PC MINGW64 /e/git_repos/Git-Tutorial (feature3)
$ git checkout master
Switched to branch 'master'
Your branch is up to date with 'origin/master'.

User@PC MINGW64 /e/git_repos/Git-Tutorial (master)
$ git branch -d feature3
error: The branch 'feature3' is not fully merged.
If you are sure you want to delete it, run 'git branch -D feature3'.

如果我们需要操作合并分支,比如将feature3分支中的代码合并到master分支,我们可以在master分支下运行git merge <分支名>将某个分支合并到当前分支,因为我们本文案例没有代码冲突,系统自动使用Fast-forward方式自动完成了合并,不需要处理冲突。如下:

User@PC MINGW64 /e/git_repos/Git-Tutorial (master)
$ git merge feature3
Updating 935539d..a03ddaa
Fast-forward
 a.txt | 3 +++
 b.txt | 1 +
 2 files changed, 4 insertions(+)
 create mode 100644 a.txt
 create mode 100644 b.txt

然后我们运行git push将master的修改提交到远程仓库Github。这时我们在本地使用git branch 可以看到有三个分支,但是在远端仓库中只有一个分支,master分支。此时如果我们需要将其他分支提交到远程仓库,首先可以使用git checkout <分支名>切换到要操作的分支(不切换也可以),使用git push origin <本地分支名称>:<远端分支名称> 将分支提交到远端,冒号与后面的远端分支名可不填,远端的分支会使用一样的名字。如果需要将远端分支删除,使用git push origin :<远端分支名称>删除。如下:

User@PC MINGW64 /e/git_repos/Git-Tutorial (master)
$ git branch
  feature1
  feature3
* master

User@PC MINGW64 /e/git_repos/Git-Tutorial (master)
$ git checkout feature1
Switched to branch 'feature1'

User@PC MINGW64 /e/git_repos/Git-Tutorial (feature1)
$ git push origin feature1:TestF1
Total 0 (delta 0), reused 0 (delta 0)
remote:
remote: Create a pull request for 'TestF1' on GitHub by visiting:
remote:      https://github.com/<用户名>/git-test/pull/new/TestF1
remote:
To https://github.com/<用户名>/git-test.git
 * [new branch]      feature1 -> TestF1

User@PC MINGW64 /e/git_repos/Git-Tutorial (feature1)
$ git push origin :TestF1
To https://github.com/<用户名>/git-test.git
 - [deleted]         TestF1

4.Git的合并

在本节开始时,老师表示他把之前的几个分支都删除了,只保留了master这个分支,所以开始之前,我们也去删一下。如果不会的话,那应该复习一下了。

查看日志和创建别名

在学习Git的合并之前,先了解一下如何查看日志,查看日志的命令是git log,日志中靠近上方的是最近的提交,往下则是较早的一些提交。

User@PC MINGW64 /e/git_repos/Git-Tutorial (master)
$ git log
commit a03ddaac380207be15724e1cb21546ff73ea4a93 (HEAD -> master, origin/master)
Author: 用户名<邮箱>
Date:   Tue Jan 15 00:52:06 2019 +0800

    add b.txt

commit fcf80e78461f6d2b66597097ae459254c1d46b9e
Author: 用户名<邮箱>
Date:   Mon Jan 14 01:23:25 2019 +0800

    Add a.txt

commit 935539d80a47a0b5dc86afa9791e9919f6830632
Author: 用户名<邮箱>
Date:   Sun Jan 13 23:30:52 2019 +0800

    Modified README.md

commit dfaaa0b793060603217561b3d7b0e3444c7b198a
Author: 用户名<邮箱>
Date:   Sun Jan 13 01:04:07 2019 +0800

    add README.md

这种看日志的方式并不方便,我们可以使用git log --oneline 使其以单行的方式显示,这样可能会更加直观一些。每行前面的ID是这次提交的Hash码的一部分,此码可唯一的标示出这次提交。如果提交记录较多,可是后缀 -<数量>来表示自己只取最近的几次提交日志。

User@PC MINGW64 /e/git_repos/Git-Tutorial (master)
$ git log --oneline
a03ddaa (HEAD -> master, origin/master) add b.txt
fcf80e7 Add a.txt
935539d Modified README.md
dfaaa0b add README.md

如果想看某次提交具体信息,可以使用git show <ID>这个命令来查看。

User@PC MINGW64 /e/git_repos/Git-Tutorial (master)
$ git show a03ddaa
commit a03ddaac380207be15724e1cb21546ff73ea4a93 (HEAD -> master, origin/master)
Author: 用户名<邮箱>
Date:   Tue Jan 15 00:52:06 2019 +0800

    add b.txt

diff --git a/b.txt b/b.txt
new file mode 100644
index 0000000..63ace0e
--- /dev/null
+++ b/b.txt
@@ -0,0 +1 @@
+Hello word

在Stack overflow上有人提炼了一些好看的指令。比如我们可以使用 git log --all --decorate --oneline --graph 命令来输出一个好看的格式。

User@PC MINGW64 /e/git_repos/Git-Tutorial (master)
$ git log --all --decorate --oneline --graph
* a03ddaa (HEAD -> master, origin/master) add b.txt
* fcf80e7 Add a.txt
* 935539d Modified README.md
* dfaaa0b add README.md

通过上面的命令我们发现,某些时候需要输入的命令会很长,难以记住。这时我们就要提到git的别名功能。使用这个功能我们可以给长命令定义别名,使用文本编辑器编辑 ~/.gitconfig文件,在里面添加以下内容并保存。

[alias]
        dog = log --all --decorate --oneline --graph

这时,我们可以使用git dog 来调用这串长命令。我们在输出的信息中可以看到,最近的一次提交(commit)中,HEAD这个指针指向了master,而括号中逗号右侧的是我们的远程分支。

User@PC MINGW64 /e/git_repos/Git-Tutorial (master)
$ git dog
* a03ddaa (HEAD -> master, origin/master) add b.txt
* fcf80e7 Add a.txt
* 935539d Modified README.md
* dfaaa0b add README.md

通常的合并操作

了解了日志,我们就可以开始学习Git的合并操作。

首先我们基于master分支创建一个分支,命名f1:

git checkout -b f1

使用 ll 命令查看一下分支下有哪些文件:

User@PC MINGW64 /e/git_repos/Git-Tutorial (f1)
$ ll
total 3
-rw-r--r-- 1 Lexsion 197609 36 1月  15 01:59 a.txt
-rw-r--r-- 1 Lexsion 197609 12 1月  15 21:38 b.txt
-rw-r--r-- 1 Lexsion 197609 46 1月  14 00:03 README.md

创建一个 fa.txt 并将其加入暂存区,然后提交一下:

touch fa.txt
git add fa.txt
git commit -m "add fa.txt"

这时我们查看一下日志,发现HRAD指针指向了f1,在master分支下最后的一次提交是 add b.txt :

User@PC MINGW64 /e/git_repos/Git-Tutorial (f1)
$ git dog
* 86b7648 (HEAD -> f1) add fa.txt
* a03ddaa (origin/master, master) add b.txt
* fcf80e7 Add a.txt
* 935539d Modified README.md
* dfaaa0b add README.md

我们现在模拟的是在f1这个分支上相对于master分支添加了新的内容(fa.txt),然后我们需要将其重新合并到master分支。一般的做法是先切换到master分支,master分支下现在是没有fa.txt这个文件的,然后使用git merge f1 命令将F1合并进来。合并后显示的日志中可以看到使用的合并策略是Fast-forward,这种合并方式不会创建新的提交(commit)默认情况下Git会使用这种方式合并,前提是没有冲突。

User@PC MINGW64 /e/git_repos/Git-Tutorial (f1)
$ git checkout master
Switched to branch 'master'
Your branch is up to date with 'origin/master'.

User@PC MINGW64 /e/git_repos/Git-Tutorial (master)
$ ll
total 3
-rw-r--r-- 1 Lexsion 197609 36 1月  15 01:59 a.txt
-rw-r--r-- 1 Lexsion 197609 12 1月  15 21:38 b.txt
-rw-r--r-- 1 Lexsion 197609 46 1月  14 00:03 README.md

User@PC MINGW64 /e/git_repos/Git-Tutorial (master)
$ git merge f1
Updating a03ddaa..86b7648
Fast-forward
 fa.txt | 0
 1 file changed, 0 insertions(+), 0 deletions(-)
 create mode 100644 fa.txt

查看日志,我们看到master的最后一次提交是 add b.txt ,在他上面一行变成了HEAD指向master的的信息依然是add fa.txt的信息。没有创建新的提交,信息左侧的*标记也是竖直向下的,没有分叉出现。

User@PC MINGW64 /e/git_repos/Git-Tutorial (master)
$ git dog
* 86b7648 (HEAD -> master, f1) add fa.txt
* a03ddaa (origin/master) add b.txt
* fcf80e7 Add a.txt
* 935539d Modified README.md
* dfaaa0b add README.md

除了Fast-forward这个模式,我们还有其他的模式,可以使用以下命令查看merge的帮助文档了解。

git merge --help

从帮助文档中可以发现,默认的合并策略就是文档中的 --ff,只移动HEAD指针,不产生新的commit。除了这种策略,还有一个 --no-ff的策略。使用no-ff策略时,即使是可以使用Fast-forward方式,Git依然会创建一个合并节点(即会创建一次commit)。帮助文档中提到,如果合并标签,该策略是默认方式。Git在合并时,使用--no-ff策略是一个很好的实践,这种在Fast-forward方式下产生新commit的功能,让我们可以保持原有开发分支整个提交链的完整性。

我们知道 add fa.txt 这项操作实际是在f1分支完成的,但是merge操作后,我们在master分支下,通过log并不能完全看出这次提交是在哪个分支完成的。

接下来我们切换到f1分支,创建一个fb.txt文件:

git checkout f1
touch fb.txt
git add fb.txt
git commit -m "add fb.txt"

然后我们切换回master分支,再次将f1合并到master,这次我们使用 --no-ff 策略,过程中自动弹出一个编辑器,让我们编辑信息,我们可以在里面填写一些需要的信息,这里我保持默认。我们可以在回显的信息中看到合并的策略已经有了变化。

User@PC MINGW64 /e/git_repos/Git-Tutorial (f1)
$ git checkout master
Switched to branch 'master'
Your branch is ahead of 'origin/master' by 1 commit.
  (use "git push" to publish your local commits)

User@PC MINGW64 /e/git_repos/Git-Tutorial (master)
$ git merge f1 --no-ff
Merge made by the 'recursive' strategy.
 fb.txt | 0
 1 file changed, 0 insertions(+), 0 deletions(-)
 create mode 100644 fb.txt

我们查看一下日志,日志中可以看出,产生了一条新的提交,信息为Merge branch 'f1',并且左边的线条发生了变化。我们之前master最后一次提交是add b.txt,然后在f1这个分支上,做了一个add fa.txt的提交,然后在master分支下做了一次merge操作。之后我们去f1分支添加了fb.txt做了一次提交,最后又到master做了merge。这种方式我们便在日志中看到了其他分支的操作。

User@PC MINGW64 /e/git_repos/Git-Tutorial (master)
$ git dog
*   bf497d9 (HEAD -> master) Merge branch 'f1'
|\
| * af03df4 (f1) add fb.txt
|/
* 86b7648 add fa.txt
* a03ddaa (origin/master) add b.txt
* fcf80e7 Add a.txt
* 935539d Modified README.md
* dfaaa0b add README.md

接下来我们使用以下命令将master和f1两个分支都提交到Github。

git push
git push origin f1:f1

在Github上修改master分支下面的a.txt(添加一行内容update),以此模拟多人协作中其他人修改了文件。现在远端就会有一个新的版本,本地就会是一个相对旧的版本。于是我们本地执行pull操作拉取代码。

git pull

此时,本地的master分支已经拉取到最新版本,此时若f1分支需要同步master分支的变化,就需要切换到f1分支,执行merge master命令。

git checkout f1
git merge master

查看日志,可见以下内容:

User@PC MINGW64 /e/git_repos/Git-Tutorial (f1)
$ git dog
* 40f3061 (HEAD -> f1, origin/master, master) Update a.txt
*   bf497d9 Merge branch 'f1'
|\
| * af03df4 (origin/f1) add fb.txt
|/
* 86b7648 add fa.txt
* a03ddaa add b.txt
* fcf80e7 Add a.txt
* 935539d Modified README.md
* dfaaa0b add README.md

接下来尝试在master做出修改,添加一个m1.txt:

git checkout master
touch m1.txt
git add m1.txt
git commit -m "add m1.txt"

现在master分支有了一些变化,我们切换到f1分支。如果我们需要将master的分支同步到f1分支,我们可以像之前一样,在f1分支下merge master。这样的话。日志中就会产生一条merge的记录。而git还提供了一个命令叫rebase,此命令会把当前分支移动到指定分支的最后一次的提交。运行以下命令,将master分支的提交并入f1分支:

git checkout f1
git rebase master

然后我们查看日志。可以发现f1产生了新的提交信息,“add m1.txt”。此命令重写了项目的历史,并且不会带来merge commit信息。使用rebase可以让项目历史相对变得简洁,不会出现分岔。这个命令不会产生合并提交,如果这个提交不是必要的,我们便可以选择这种方式。但是这种简洁却会给我们项目的安全和可跟踪性带来不良的后果。如果违法了rebase的黄金法则:绝不在公共分支(一般为master)使用rebase,则会因重写项目历史给工作流带来危险的影响。

User@PC MINGW64 /e/git_repos/Git-Tutorial (f1)
$ git dog
* 6f3cfec (HEAD -> f1, master) add m1.txt
* 40f3061 (origin/master) Update a.txt
*   bf497d9 Merge branch 'f1'
|\
| * af03df4 (origin/f1) add fb.txt
|/
* 86b7648 add fa.txt
* a03ddaa add b.txt
* fcf80e7 Add a.txt
* 935539d Modified README.md
* dfaaa0b add README.md

关于我们对两种操作使用的选择。
merge是一个合并操作,其能将两个分支的修改合并到一起,默认情况不提交合并中修改的内容。merge提交历史会记录发生了什么,其关注点在真实的提交历史记录上。
rebase没有合并操作,其是将一个分支的最后一次修改,复制到了一个分支的最后一次提交上。rebase的提交历史能够反映这个项目的过程发生了什么,其关注点在开发的过程上。
两个命令都是分支整合工具,无优劣之分,只是功能有所不同,具体的选择需要根据开发需求决定。

分支冲突

首先我们从f1创建分支f2,并在分支f2下修改a.txt文件。将里面原来的update改为“Upgeade”,然后运行git commit提交。此时f1和f2两个分支可以理解为是在做不同方向的修改,两个分支中的a.txt也是不一样的。然后回到f1,修改其中的a.txt(改为Downgrade),这时,f1也有了新的修改。

git checkout -b f2
vim a.txt
git add a.txt
git commit -m "modified a.txt UG"
git checkout f1
vim a.txt
git add a.txt
git commit -m "modified a.txt DG"

然后切换到f2分支,假定f2分支的人需要拉取f1的修改,然后自己再继续修改。f2分支的人运行git merge就会发现有冲突提示。内容表示:自动合并失败,a.txt发生了冲突。

User@PC MINGW64 /e/git_repos/Git-Tutorial (f1)
$ git checkout f2
Switched to branch 'f2'

User@PC MINGW64 /e/git_repos/Git-Tutorial (f2)
$ git merge f1
Auto-merging a.txt
CONFLICT (content): Merge conflict in a.txt
Automatic merge failed; fix conflicts and then commit the result.

User@PC MINGW64 /e/git_repos/Git-Tutorial (f2|MERGING)
$

此时查看a.txt这个文件,发现文件中正文变成了上下两部分,分别是两个不同分支中此文件的的内容。可以使用vi编辑器或其他编辑工具修改文件保留自己需要的部分,或者可以使用git mergetool来处理。

User@PC MINGW64 /e/git_repos/Git-Tutorial (f2|MERGING)
$ cat a.txt
# a.txt
This is a.txt
Test files
<<<<<<< HEAD
Upgrade
=======
Downgrade
>>>>>>> f1

User@PC MINGW64 /e/git_repos/Git-Tutorial (f2|MERGING)
$ git mergetool

This message is displayed because 'merge.tool' is not configured.
See 'git mergetool --tool-help' or 'git help config' for more details.
'git mergetool' will now attempt to use one of the following tools:
opendiff kdiff3 tkdiff xxdiff meld tortoisemerge gvimdiff diffuse diffmerge ecmerge p4merge araxis bc codecompare emerge vimdiff
Merging:
a.txt

Normal merge conflict for 'a.txt':
  {local}: modified file
  {remote}: modified file
Hit return to start merge resolution tool (vimdiff):
还有 4 个文件等待编辑

User@PC MINGW64 /e/git_repos/Git-Tutorial (f2|MERGING)
$ cat a.txt
# a.txt
This is a.txt
Test files
Upgrade

这个问题的处理过程中会生成一个.orig文件,此为冲突现场,没有用可以使用rm命令删除了:

User@PC MINGW64 /e/git_repos/Git-Tutorial (f2|MERGING)
$ ll
total 4
-rw-r--r-- 1 Lexsion 197609 45 1月  21 00:33 a.txt
-rw-r--r-- 1 Lexsion 197609 91 1月  20 23:35 a.txt.orig
-rw-r--r-- 1 Lexsion 197609 12 1月  15 21:38 b.txt
-rw-r--r-- 1 Lexsion 197609  0 1月  15 23:46 fa.txt
-rw-r--r-- 1 Lexsion 197609  0 1月  16 00:39 fb.txt
-rw-r--r-- 1 Lexsion 197609  0 1月  20 22:27 m1.txt
-rw-r--r-- 1 Lexsion 197609 46 1月  14 00:03 README.md

User@PC MINGW64 /e/git_repos/Git-Tutorial (f2|MERGING)
$ rm a.txt.orig

然后git commit提交,查看日志,日志中可以看到明显的分支变化:

User@PC MINGW64 /e/git_repos/Git-Tutorial (f2|MERGING)
$ git commit -m "update a.txt with f2"
[f2 b3012b6] update a.txt with f2

User@PC MINGW64 /e/git_repos/Git-Tutorial (f2)
$ git dog
*   b3012b6 (HEAD -> f2) update a.txt with f2
|\
| * 5607205 (f1) Modified a.txt DG
* | 84e558c modified a.txt UG
|/
* 6f3cfec (master) add m1.txt
* 40f3061 (origin/master) Update a.txt
*   bf497d9 Merge branch 'f1'
|\
| * af03df4 (origin/f1) add fb.txt
|/
* 86b7648 add fa.txt
* a03ddaa add b.txt
* fcf80e7 Add a.txt
* 935539d Modified README.md
* dfaaa0b add README.md

5.Git的回滚与撤销

git reset命令

使用git reset命令可以回退git分支的的版本,reset的中文翻译是重置,但是Git中的reset命令用中文表示像是前往的意思,类似程序设计中的goto。使用reset命令类似于将最后一次提交的指针指向了之前的某一次提交。

要回退master到上一个版本,使用命令git reset空格后接要回退的版本,master后接的“^”标志表示上一版本,如要回退两个版本就添加两个“^”,以此类推:

git reset master^

若回退的版本较远,比如5次提交之前,可以使用:

git reset master~5

以上是一种相对撤销的操作,我们亦可以通过后接提交id来回退指定版本。比如回退到id为b3012b6的那次提交:

git reset b3012b6

git reset命令有多个模式,具体我们可以在help信息中看到。其中常用的模式为:soft、mixed、hard。其默认使用mixed模式,此模式会丢弃暂存区的文件,但是工作目录的文件不动。soft模式工作目录和暂存区的文件都不会丢弃,这看起来像是移动了HEAD的指针。而hard模式会丢弃工作目录和暂存区的文件。


git reset --help

git reset [-q] [<tree-ish>] [--] <paths>…​
git reset (--patch | -p) [<tree-ish>] [--] [<paths>…​]
EXPERIMENTAL: git reset [-q] [--stdin [-z]] [<tree-ish>]
git reset [--soft | --mixed [-N] | --hard | --merge | --keep] [-q] [<commit>]

以下为使用hard模式的操作,很明显工作目录文件的数量减少了:

User@PC MINGW64 /e/git_repos/Git-Tutorial (master)
$ ll
total 3
-rw-r--r-- 1 Lexsion 197609 44 1月  21 23:30 a.txt
-rw-r--r-- 1 Lexsion 197609 12 1月  21 23:30 b.txt
-rw-r--r-- 1 Lexsion 197609  0 1月  21 23:30 fa.txt
-rw-r--r-- 1 Lexsion 197609  0 1月  21 23:30 fb.txt
-rw-r--r-- 1 Lexsion 197609  0 1月  21 23:30 m1.txt
-rw-r--r-- 1 Lexsion 197609 46 1月  14 00:03 README.md

User@PC MINGW64 /e/git_repos/Git-Tutorial (master)
$ git dog
*   b3012b6 (f2) update a.txt with f2
|\
| * 5607205 (f1) Modified a.txt DG
* | 84e558c modified a.txt UG
|/
* 6f3cfec (HEAD -> master) add m1.txt
* 40f3061 (origin/master) Update a.txt
*   bf497d9 Merge branch 'f1'
|\
| * af03df4 (origin/f1) add fb.txt
|/
* 86b7648 add fa.txt
* a03ddaa add b.txt
* fcf80e7 Add a.txt
* 935539d Modified README.md
* dfaaa0b add README.md

User@PC MINGW64 /e/git_repos/Git-Tutorial (master)
$ git reset --hard 935539d
HEAD is now at 935539d Modified README.md

User@PC MINGW64 /e/git_repos/Git-Tutorial (master)
$ ll
total 1
-rw-r--r-- 1 Lexsion 197609 46 1月  14 00:03 README.md

以下为使用soft模式,可以看出commit被回退了,但是添加到暂存区的文件还是存在的。

User@PC MINGW64 /e/git_repos/Git-Tutorial (master)
$ touch test.txt

User@PC MINGW64 /e/git_repos/Git-Tutorial (master)
$ git add test.txt

User@PC MINGW64 /e/git_repos/Git-Tutorial (master)
$ git commit -m "add test.txt"
[master 29e4eac] add test.txt
 1 file changed, 0 insertions(+), 0 deletions(-)
 create mode 100644 test.txt

User@PC MINGW64 /e/git_repos/Git-Tutorial (master)
$ git dog
* 29e4eac (HEAD -> master) add test.txt
| *   b3012b6 (f2) update a.txt with f2
| |\
| | * 5607205 (f1) Modified a.txt DG
| * | 84e558c modified a.txt UG
| |/
| * 6f3cfec add m1.txt
| * 40f3061 (origin/master) Update a.txt
| *   bf497d9 Merge branch 'f1'
| |\
| | * af03df4 (origin/f1) add fb.txt
| |/
| * 86b7648 add fa.txt
| * a03ddaa add b.txt
| * fcf80e7 Add a.txt
|/
* 935539d Modified README.md
* dfaaa0b add README.md

User@PC MINGW64 /e/git_repos/Git-Tutorial (master)
$ git reset --soft 935539d

User@PC MINGW64 /e/git_repos/Git-Tutorial (master)
$ git status
On branch master
Your branch is behind 'origin/master' by 6 commits, and can be fast-forwarded.
  (use "git pull" to update your local branch)

Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

        new file:   test.txt


User@PC MINGW64 /e/git_repos/Git-Tutorial (master)
$ ll
total 1
-rw-r--r-- 1 Lexsion 197609 46 1月  14 00:03 README.md
-rw-r--r-- 1 Lexsion 197609  0 1月  21 23:38 test.txt

git rest命令类似移动了HEAD的指针,而具体的参数是决定了暂存区和工作目录文件的处理方式。它不是重新设置或删除了提交,只是前往了某次提交之上。也就是说,哪怕我们回退了如此多个版本,在工作目录中文件都删除了,我们依然可以再将其找回来。

使用git reflog命令查看相关的日志,找到本节例程最开始的切换分支操作的记录,使用以下命令回退到本节例程最开始的状态。可以看到,文件全部回来了。

User@PC MINGW64 /e/git_repos/Git-Tutorial (master)
$ git reflog
935539d (HEAD -> master) HEAD@{0}: reset: moving to 935539d
29e4eac HEAD@{1}: commit: add test.txt
935539d (HEAD -> master) HEAD@{2}: reset: moving to 935539d
...
6f3cfec HEAD@{9}: checkout: moving from f2 to master

User@PC MINGW64 /e/git_repos/Git-Tutorial (master)
$ git reset --hard 6f3cfec
HEAD is now at 6f3cfec add m1.txt

User@PC MINGW64 /e/git_repos/Git-Tutorial (master)
$ ll
total 3
-rw-r--r-- 1 Lexsion 197609 44 1月  22 00:12 a.txt
-rw-r--r-- 1 Lexsion 197609 12 1月  22 00:12 b.txt
-rw-r--r-- 1 Lexsion 197609  0 1月  22 00:12 fa.txt
-rw-r--r-- 1 Lexsion 197609  0 1月  22 00:12 fb.txt
-rw-r--r-- 1 Lexsion 197609  0 1月  22 00:12 m1.txt
-rw-r--r-- 1 Lexsion 197609 46 1月  14 00:03 README.md

git revert

撤销某次操作,此次操作之前与之后的commit和history都会保留,并且这次撤销作为一次新的提交。
先运行以下命令新增一个test.c文件并commit:

touch test.c
git add test.c
git commit -m "add test.c"

然后接下来验证操作:

User@PC MINGW64 /e/git_repos/Git-Tutorial (master)
$ ll
total 3
-rw-r--r-- 1 Lexsion 197609 44 1月  22 00:12 a.txt
-rw-r--r-- 1 Lexsion 197609 12 1月  22 00:12 b.txt
-rw-r--r-- 1 Lexsion 197609  0 1月  22 00:12 fa.txt
-rw-r--r-- 1 Lexsion 197609  0 1月  22 00:12 fb.txt
-rw-r--r-- 1 Lexsion 197609  0 1月  22 00:55 m1.txt
-rw-r--r-- 1 Lexsion 197609 46 1月  14 00:03 README.md
-rw-r--r-- 1 Lexsion 197609  0 1月  22 00:56 test.c

User@PC MINGW64 /e/git_repos/Git-Tutorial (master)
$ git dog
* 8d08f74 (HEAD -> master) add test.c
| *   b3012b6 (f2) update a.txt with f2
| |\
| | * 5607205 (f1) Modified a.txt DG
| |/
|/|
| * 84e558c modified a.txt UG
|/
* 6f3cfec add m1.txt
* 40f3061 (origin/master) Update a.txt
*   bf497d9 Merge branch 'f1'
|\
| * af03df4 (origin/f1) add fb.txt
|/
* 86b7648 add fa.txt
* a03ddaa add b.txt
* fcf80e7 Add a.txt
* 935539d Modified README.md
* dfaaa0b add README.md

User@PC MINGW64 /e/git_repos/Git-Tutorial (master)
$ git revert 8d08f74
[master c7654d5] Revert "add test.c"
 1 file changed, 0 insertions(+), 0 deletions(-)
 delete mode 100644 test.c

User@PC MINGW64 /e/git_repos/Git-Tutorial (master)
$ git dog
* c7654d5 (HEAD -> master) Revert "add test.c"
* 8d08f74 add test.c
| *   b3012b6 (f2) update a.txt with f2
| |\
| | * 5607205 (f1) Modified a.txt DG
| |/
|/|
| * 84e558c modified a.txt UG
|/
* 6f3cfec add m1.txt
* 40f3061 (origin/master) Update a.txt
*   bf497d9 Merge branch 'f1'
|\
| * af03df4 (origin/f1) add fb.txt
|/
* 86b7648 add fa.txt
* a03ddaa add b.txt
* fcf80e7 Add a.txt
* 935539d Modified README.md
* dfaaa0b add README.md

User@PC MINGW64 /e/git_repos/Git-Tutorial (master)
$ ll
total 3
-rw-r--r-- 1 Lexsion 197609 44 1月  22 00:12 a.txt
-rw-r--r-- 1 Lexsion 197609 12 1月  22 00:12 b.txt
-rw-r--r-- 1 Lexsion 197609  0 1月  22 00:12 fa.txt
-rw-r--r-- 1 Lexsion 197609  0 1月  22 00:12 fb.txt
-rw-r--r-- 1 Lexsion 197609  0 1月  22 00:55 m1.txt
-rw-r--r-- 1 Lexsion 197609 46 1月  14 00:03 README.md

此命令的格式为git revert 后接版本id,与git reset类似,亦可以后接HEAD^和HEAD~5这种格式,执行命令后会自动产生一次提交,所以需要编辑一下提交信息。命令回显的信息中表示已删除了test.c,我们可以在日志中可以看到有一次新的commit,以前的提交历史都完全存在。

综上所述,我们应该在公共分支上使用revert,避免使用reset,这样日志中就会有信息可供回溯,以此保证良好的可跟踪性。而私人的分支上,就没有什么限制了。revert是用一次新的提交回滚之前的提交,而reset是移动了HEAD指针,使用时应根据需求注意选择。

6.gitignore和fork的同步

gitignore

我们在使用IDE创建工程时,IDE会产生一些配置文件。这些文件并不属于源代码,文件中包含的配置信息可能在另一台计算机上出现错误。或者配置文件中可能存在某些隐私信息不能共享出去。亦或者编译过程中产生的中间文件我们也需要忽略。在Git中,通过gitignore实现了文件忽略。

使用这个功能,需要在工作目录下新建一个名为“ .gitignore ”的文件并将其添加到托管中。然后在文件中添加规则。常用的规则编辑语法举例:

# 忽略一个文件名确定的文件:
666.txt
# 忽略某个扩展名的文件:
*.xx
# 忽略某个目录:
Floder/
# 不忽略某个扩展名的文件:
!*.txt
# 忽略某个目录下的某个扩展名:
/Floder/*.class

通过此方法忽略的前提是新添加的文件还没有被Git托管,添加了“.gitignore”文件后,运行git add -A时会自动按照规则忽略。
如果觉得自己写gitignore文件比较麻烦,可以通过如下网站自动生成。
在线生成忽略文件:https://www.gitignore.io/

fork的同步

有时我们看到好的项目会把仓库fork到自己这里。但是后期原始仓库中的代码更新了,我们fork的仓库还是旧的。我们可能就需要更新一下。
使用以下命令可以看到git 的远程连接:

git remote -v

可以看到默认是一个名为origin的源,我们需要将上游仓库的连接添加进来,名称为upstream,命令格式如下:

git remote add upstream [仓库链接]

fetch命令可以将某个远程仓库拉取到本地,使用fetch命令将上游仓库master分支拉取到本地:

git fetch upstream master

这时使用以下命令便可以查看到远程分支:

git branch -r

然后在我们本地的master分支下运行rebase命令将拉取的上游仓库master分支与其合并,然后使用push命令推送到我们自己的远程仓库:

git rebase upstream/master
git push

需要注意的是,如果我们是做了一些代码共享的情况下,不应该使用rebase,而应该使用merge命令进行合并。push完成后,我们可以使用git log命令查看log确认已经修改。

以上便是本人在学习Git时的笔记,因初学水平有限,如有错误还请各位指正。

LANG=C导致CentOS7中文乱码的处理方法

LANG=C导致CentOS7中文乱码的处理方法

前言

  配置新购的VPS过程中发现中文显示是乱码,因是国外服务商,怀疑系统没有中文字符导致,网上查资料发现确实如此,特将解决方法记录。  

处理过程

1:执行locale命令,查看系统当前的语言环境,看到如下回显信息:

LANG=C

由此判断当前语言环境是C,是ASCII码环境,我们要把语言环境设置成中文中国。

2:执行以下命令查看当前系统是否有中文语言包:

locale -a | grep zh_CN*

如果有显示以下内容,表示系统已经包含了中文语言包。

zh_CN
zh_CN.gb18030
zh_CN.gb2312
zh_CN.gbk
zh_CN.utf8

若没有以上信息回显,可以运行以下命令安装中文语言包:

yum install kde-l10n-Chinese

3:运行以下命令使用vi打开locale.conf文件:

vi /etc/locale.conf

vi编辑器的使用方法:打开后按i键进入插入输入模式,使用上下左右键移动光标到需要修改的位置后面,按Backspace键删除前面要删除的内容。然后使用键盘输入新的内容。内容输入完毕后按ESC退出输入模式,使用键盘组合键输入":"符号,后跟字母"wq",按Enter保存文件并退出vi编辑器。

将打开的文件中LANG=C修改为:

LANG="zh_CN.UTF-8"

然后退出vi编辑器。

4:执行以下命令应用配置文件:

source /etc/locale.conf

5:再次执行locale命令查看当前语言环境:

[root@Test]# locale
LANG=zh_CN.UTF-8
LC_CTYPE="zh_CN.UTF-8"
LC_NUMERIC="zh_CN.UTF-8"
LC_TIME="zh_CN.UTF-8"
LC_COLLATE="zh_CN.UTF-8"
LC_MONETARY="zh_CN.UTF-8"
LC_MESSAGES="zh_CN.UTF-8"
LC_PAPER="zh_CN.UTF-8"
LC_NAME="zh_CN.UTF-8"
LC_ADDRESS="zh_CN.UTF-8"
LC_TELEPHONE="zh_CN.UTF-8"
LC_MEASUREMENT="zh_CN.UTF-8"
LC_IDENTIFICATION="zh_CN.UTF-8"
LC_ALL=

回显信息如上所示,即表示语言环境修改成功。