分类 博客文章 下的文章

树莓派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=

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

[译]在CentOS7上安装Mumble的服务器端

在CentOS7上安装Mumble的服务器端

前言

最近研究了一下Mumble,使用Mumble能建立加密的语音通信。不敢独享,特翻译官方wiki文档Installation of murmur server on CentOS 7 (RHEL 7) using the static mumble server.如下。


正文:

在CentOS7上安装Mumble的服务器端murmur


在CentOS7(RHEL7)上使用static mumble server安装包配置murmur 服务端

目录

1 安装

2 系统配置

  • 2.1 配置Murmur.ini文件
  • 2.2 允许作为后台进程运行
  • 2.3 配置日志滚动
  • 2.4 防火墙
  • 2.5 SELinux
  • 2.6 完成并启动

安装

下载Static Murmur Server,然后运行以下命令安装:

tar -vxjf ./murmur-static_x86-1.2.8.tar.bz2
sudo mkdir /usr/local/murmur
sudo cp -r ./murmur-static_x86-1.2.8/* /usr/local/murmur/
sudo cp ./murmur-static_x86-1.2.8/murmur.ini /etc/murmur.ini

现在创建murmur用户和组,以及数据目录和日志记录目录:

sudo groupadd -r murmur
sudo useradd -r -g murmur -m -d /var/lib/murmur -s /sbin/nologin murmur
sudo mkdir /var/log/murmur
sudo chown murmur:murmur /var/log/murmur
sudo chmod 0770 /var/log/murmur

系统配置

Murmur.ini

确保在/etc/murmur.ini文件中正确配置了以下设置:

database=/var/lib/murmur/murmur.sqlite
logfile=/var/log/murmur/murmur.log
pidfile=/var/run/murmur/murmur.pid
# Reminder: When changing the port that murmur will listen to you will need to also update the firewall.
# Update the firewall by editing /etc/firewalld/services/murmur.xml
# Then run "sudo firewall-cmd --reload"
port=64738
# Comment out the following setting since the service will already be executing as the correct user:
# uname=murmur

允许作为后台进程运行

创建一个 systemd unit 文件,以便操作系统可以管理murmur服务。 使用您的文本编辑器,创建文件'/etc/systemd/system/murmur.service'(需要root权限)。 复制并粘贴以下内容:

[Unit]
Description=Mumble Server (Murmur)
Requires=network-online.target
After=network-online.target mariadb.service time-sync.target

[Service]
User=murmur
Type=forking
ExecStart=/usr/local/murmur/murmur.x86 -ini /etc/murmur.ini
PIDFile=/var/run/murmur/murmur.pid
ExecReload=/bin/kill -s HUP $MAINPID

[Install]
WantedBy=multi-user.target

在新系统上 /var/run 在重启后被丢弃。 要重新生成murmur的pid目录,请以root身份创建配置文件 “/etc/tmpfiles.d/murmur.conf” 并复制粘贴以下内容:

d /var/run/murmur 775 murmur murmur

配置日志滚动

配置logrotate,以致murmur的日志不填满 /var/log 。 以root身份创建 '/etc/logrotate.d/murmur' 配置文件并复制并粘贴以下内容:

/var/log/murmur/*log {
    su murmur murmur
    dateext
    rotate 4
    missingok
    notifempty
    sharedscripts
    delaycompress
    postrotate
        /bin/systemctl reload murmur.service > /dev/null 2>/dev/null || true
    endscript
}

防火墙

配置firewalld以便它允许服务侦听 TCP/UDP 。如果您修改了murmur.ini以便它侦听非默认端口,那么您在此步骤需要修改对应端口以适配您对murmur.ini的修改。 以root用户身份创建配置文件'/etc/firewalld/services/murmur.xml'并复制粘贴以下内容:

<?xml version="1.0" encoding="utf-8"?>
<service>
        <short>Murmur</short>
        <description>Mumble Server (Murmur)</description>
        <port protocol="tcp" port="64738" /><!-- Reminder: Update /etc/murmur.ini so that it uses the same ports -->
        <port protocol="udp" port="64738" />
</service>

然后运行以下命令将防火墙规则添加到默认区域,并重新加载:

sudo firewall-cmd --permanent --add-service=murmur
sudo firewall-cmd --reload

SELinux

注意:请先尝试在SELinux强制模式下运行murmur。在RHEL或CentOS 7.2以上系统中,SELinux似乎不再阻止murmur的运行 。 如有异常,请在'/var/log/audit/audit.log'中检查与murmur相关的AVC条目。

注意:此处列出的步骤可能会使安全人士感到畏缩。 如果有人有时间和耐心解决SELinux,请考虑使用适当的解决方案更新本文档。

SELinux默认会阻止murmur正常运作。 快速简便的解决方案是简单地禁用它。 要暂时禁用(直到下次重新启动),请运行以下命令:

sudo setenforce 0

要永久禁用(在下次重启后),请编辑 '/etc/sysconfig/selinux' 并将“SELINUX”行更改为:

SELINUX=disabled

完成并运行

更新您的系统配置,以便它可以启动 murmur 服务:

sudo systemd-tmpfiles --create /etc/tmpfiles.d/murmur.conf
sudo systemctl daemon-reload

要暂时启动 murmur 服务(直到下次重启),请运行:

sudo systemctl start murmur.service

告诉系统自动启动murmur服务(这不会立即运行murmur,而是在下次重启时启动):

sudo systemctl enable murmur.service

警告:如果在启动Murmur时遇到僵尸进程(zombie process),则必须安装redhat-lsb-core软件包。

参考链接:

Install CentOS7-wiki.mumble.info

Installing Mumble-wiki.mumble.info

[译]获取Comodo免费邮件证书

[译]获取Comodo免费邮件证书

前言

  最近因需要找一款免费的邮件证书,用来签名word文档,以此保证文档没有被修改。又恰好学习通过Mumble搭建语音聊天服务,在官方wiki中看到这篇名为《Obtaining a Comodo Certificate》的文档。文中提到的Comodo S/MIME email certificate证书可以用来为word文档签名,为邮件加密等。感觉本文非常实用,特翻译。

原文链接
https://www.instantssl.com/ssl-certificate-products/free-email-certificate.html

正文

获取Comodo证书

  本文介绍了获取用户证书的过程。证书将代表用户拥有他指定的电子邮件地址的信任。

  服务端使用不同种类的证书来进行认证。 如果您正在寻找服务器证书,本指南不适合您。

使用Internet Explorer从Comodo(Instantssl)获取Class 1证书

注意:
使用Chrome / Safari(基于webkit)获取证书似乎最初的操作可以正常进行,但最终会得到一个不完整的证书包! 考虑使用其他浏览器替代。

译注:本人使用Internet Explorer11导出的证书也不能正常工作,但是使用Firefox导出的证书可正常使用,推荐使用Firefox浏览器进行操作

Comodo支持通过IE,Firefox,Opera和Flock等浏览器获取证书。

  1:请访问http://www.instantssl.com/ssl-certificate-products/free-email-certificate.html
  2:点击“Free Email Certificate”旁边的“GET NOW”按钮。

  3:填入你的信息。

译注:网页中的First Name项中填入名字,Last Name项内填入姓,Email Address中填入电子邮箱地址(重要信息,证书与电邮地址绑定,必须正确),Country下拉菜单中选择国家,比如选择China。

译注:Private Key Options下方的设置中,Revocation Passwrod处需要设置一个密码,其用于保障在您认为证书失去安全性时,可以通过这个密码保证只有您有权吊销证书。

  4:填写完毕后勾选“ I ACCEPT the terms of this Subscriber Agreement. ”,点击"NEXT>"按钮继续。网页会提醒后续具体的证书获取已经发送到您设置的邮箱中了。

  5:等待确认邮件送达您的邮箱中。

  6:按照邮件中的说明(或转到此链接)。

  7:输入您的电子邮件地址和邮件中提供的Collection Password。

  8:这样证书将被成功收集并安装到浏览器中。

  将证书导出到文件:

  9:导出证书到文件:

导出证书(Internet Explorer 8)

  打开“工具” - >“Internet选项” - >“内容” - >“证书” - >“个人”,然后从列表中找到并选定您的证书。如果这是您的第一个证书,它将以名称“UTN-USERFirst-Client Authentication and Email”的形式列出。单击“导出” - >“下一步” - >“是,导出私钥” - >“下一步” - >“下一步”。设置文件密码,然后单击“下一步”,设置此备份文件的名称并将其保存在已知的位置。

导出证书(Firefox 3.5)

  选择“首选项” - >“高级” - >“加密” - >“查看证书”,选择“您的证书”选项卡,然后从列表中找到您的证书。证书将以“UTN-USERFirst-Client Authentication and Email”作为名称列出。选择证书并单击“备份”,选择此备份文件的名称,提供密码并将其保存在已知位置。

导出证书(Opera 10.10)

  选择“工具” - >“首选项” - >“高级”(选项卡) - >“安全” - >“管理证书”(按钮) - >“个人”(选项卡)选择您的证书并单击“导出”(按钮) 。

译注:导出证书(Firefox 64.0)

  选择“选项” - >“隐私与安全” - >“证书” - >“查看证书”,选择“您的证书”选项卡,然后从列表中找到您的证书。证书将以“UTN-USERFirst-Client Authentication and Email”作为名称列出。选择证书并单击“备份”,选择此备份文件的名称,设置密码并将其保存在已知位置。

将证书从文件导入Mumble

  1:选择 “配置” -> “证书向导”;

  2:选择“导入证书”,点击下一步;

  3:点击“导入自”后的“打开”,找到并选择证书文件。 它应以.p12或.pfx结尾,具体取决于导出证书的浏览器。

  4:输入您导出时设置的证书密码;

  5:现在证书详细信息应该会显示在下方。确认它是正确的证书,点击下一步;

  6:按“下一步”确认您要更换证书;

  7:搞定! 按完成关闭本向导。

安装证书后无法连接服务器

  如果您安装证书后无法连接并且服务器日志中出现以下记录:“SSL Error: The root CA certificate is not trusted for this purpose(SSL错误:根CA CA证书不可信任)”,这通常是由于导出的证书包不完整造成的。

  请尝试使用Firefox浏览器重新获取证书,并导出证书。 已知问题,Chrome和Safari会创建不完整的证书包。

译文结束

参考资料

1:Obtaining a Comodo Certificate

https://wiki.mumble.info/wiki/Obtaining_a_Comodo_Certificate

2:Free Email Certificates

https://www.instantssl.com/ssl-certificate-products/free-email-certificate.html

3:S/MIME

https://zh.wikipedia.org/wiki/S/MIME

DSM系统损坏后通过电脑恢复数据

DSM系统损坏后通过电脑恢复数据

前言

最近几天天冷,大家都开着空调,结果电流过大导致跳闸,群辉异常断电,再次尝试启动,发现无法启动,拆出硬盘挂到Windows下发现磁盘分区正常,判断应该是DSM系统坏。

技能

1:计算机硬件维护技术,硬盘拆装
2:基本Linux操作

处理过程:

群辉中拆出的硬盘挂到Windows系统下是无法直接读取的,像我的这个,群辉的DSM使用的文件系统是Ext4,其在Windows下是不可直接识别的。且其使用了RAID阵列技术,尝试在Windows下读取更是困难。于是我们需要一个Linux环境,手里正有一台运行Ubuntu16的电脑,群辉官网的帮助文档也是使用的Ubuntu。

1:将群辉中拆出的硬盘连接到Ubuntu环境的电脑,如果有多块硬盘组成RAID阵列,需要将所有硬盘挂载,具体硬件连接方案自行确定。
2:打开系统自带的磁盘应用,查看是否有显示插入的硬盘,确认硬盘被识别。
3:此时打开“文件”查看是否有文件系统被直接挂载,可以访问。如有,那就不必继续看下去,直接复制出数据即可。
4:运行终端(英文系统下为Terminal),在终端中使用以下命令安装mdadm:

sudo -i
apt-get install mdadm

5:使用以下命令安装lvm2以保证vgchange正常运作:

apt-get install lvm2

6:运行以下命令覆盖常规检查重建RAID阵列:

mdadm -Asf

7:运行以下命令挂载所有已知的卷到系统:

vgchange -ay

8:此时应能在系统自带的“文件”中看到新挂载的卷,打开便能看到所有文件,接下来就是自行复制出需要的数据了。

结束操作

数据复制完后我们需要移除设备,直接关机,拆出硬盘是最快捷方便的办法。或可按如下操作:
1:在“文件”中点击对应的弹出按钮;或到“磁盘”中选择对应的块设备,点击卸载所选分区。
2:运行以下命令卸载所有的vg卷:

vgchange -an

3:运行以下命令查看所有RAID状态,用以确认我们要卸载的RAID设备名:

cat /proc/mdstat

4:通过以上命令我得知我的RAID设备为md2,运行以下命令可以查看这个RAID设备的状态,通过获取到的信息可以确认是否是要操作的设备:

mdadm -D /dev/md2

5:运行以下命令确认卸载md2:

umount /dev/md2

6:运行以下命令停止这个RAID:

mdadm -S /dev/md2

7:然后我们可以去“磁盘”中选定对应磁盘,点击关闭此硬盘,这时我们便可以安全的拔下硬盘了。

参考:

1:我如何使用计算机来还原存储在 DiskStation 中的数据?
https://www.synology.com/zh-cn/knowledgebase/DSM/tutorial/Storage/How_can_I_recover_data_from_my_DiskStation_using_a_PC
2:如何在Linux 下面挂载LVM2分区
https://wenku.baidu.com/view/119cf83ef5335a8103d22009.html
3:mdadm详细使用手册
https://blog.csdn.net/a7320760/article/details/10442715
4:linux安全移除USB设备
http://blog.sina.com.cn/s/blog_60cbc1700100nsy0.html
5:mdadm彻底删除software RAID
https://blog.csdn.net/chenyouxu/article/details/47415985
6:软RAID管理命令mdadm详解
http://www.toxingwang.com/linux-unix/linux-basic/1048.html

OpenVZ架构VPS安装SoftEtherVPN实现搭建L2TP协议VPN服务

OpenVZ架构VPS安装SoftEtherVPN实现搭建L2TP协议VPN服务

前言:

  在某些情况下,我们可能需要部署一个VPN,来实现某些网络应用。部署VPN的方案有很多种,比较廉价的方案是选择一个运行Linux系统的,OpenVZ架构的虚拟服务器(VPS),然后在上面运行SoftEther VPN Server。
  SoftEther VPN 是日本筑波大学的一个研究项目。其包含服务端,客户端,服务端管理工具等软件。其服务端目前支持包括Windows、Linux,FreeBSD,MAC OS X等多种操作系统,其Linux版本对包括X86、ARM,MIPS等多种硬件架构均有支持,这表明它甚至可以运行在某些路由器上。其支持L2TP over IPsec 协议、 OpenVPN 协议和 MS-SSTP 协议,在Windows、Linux、Android和IOS等系统下都可以连接到SoftEther VPN服务器。SoftEther VPN服务端安装非常方便,且后期配置时可在Windows系统下安装管理工具通过图形界面来进行服务端配置。

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

  1:基本的Windows系统与Linux系统操作技能;

准备:

  1:一台运行Windows系统的计算机;
  2:运行Linux系统的VPS(我的是运行的CentOS);
  3:SSH客户端,我用的是Putty.

操作过程:

登录VPS:

  1,打开SSH客户端,此处以Putty为例;
  2,在HostName(or IP address)下填入VPS的IP地址,在Port填入SSH服务的端口,Connection type下选择SSH;
  3,可在下方的Saved Sessions下的文本框中填入一个友好的名字,点击Save保存,以方便下次连接,下次连接时只需选择对应名字,然后点击Load即可。
  4,点击Open开始连接,连接成功后会提示login as:在此输入VPS提供商提供的用户名,一般为root;按Enter键确认,会出现用户名@IP地址 's password:信息提示输入密码,输入VPS提供商提供的密码,按Enter键确认密码完成登录。需要注意的是Linux系统安全限制,密码输入时不会有任何内容甚至占位符出现。

寻找服务端安装文件并安装:

  1,浏览器访问:https://www.softether-download.com/cn.aspx 地址,产品选项中选择SoftEther VPN(Freeware),组件选项选择SoftEther VPN Server,系统选择Linux,CPU自行根据VPS配置选择,下方会出现可供下载的资料,右键复制需要的Server安装文件包地址,在前面加上wget空格,类似如下格式:

wget https://github.com/SoftEtherVPN/SoftEtherVPN_Stable/releases/download/v4.28-9669-beta/softether-vpnserver-v4.28-9669-beta-2018.09.11-linux-x64-64bit.tar.gz

  2,解压文件,命令为tar zxvf后面接文件名,类似如下格式:

tar zxvf softether-vpnserver-v4.28-9669-beta-2018.09.11-linux-x64-64bit.tar.gz

  3,待所有显示的文件处理完毕,进入刚解压出的vpnserver文件夹,运行make若出现交互信息,请跳至第5条.
  4,若运行make失败,提示命令未找到,应该是没有安装make造成的,尝试运行以下命令安装:

yum -y install gcc automake autoconf libtool make

  待安装完成后,重新运行make命令。
  若出现"grep" command not found.提示,则尝试运行yum install grep,若提示grep已经存在,则尝试使用yum安装wherewhich后再尝试运行make.
  5,首先看到的是询问是否愿意查看许可条款,选择1表示需要;然后会显示出许可条款并要求你选择是否看完并理解条款,选择1表示是;最后询问是否同意,输入1选择同意。然后会开始创建可执行程序。
  6,待创建完成后,可使用以下命令开关服务。

./vpnserver start      //开始服务
./vpuserver stop       //停止服务

下载管理工具完成配置

  1,浏览器访问:https://www.softether-download.com/cn.aspx 地址,产品选项中选择SoftEther VPN(Freeware),组件选项选择SoftEther VPN Server Manager for Windows,系统选择Windows(.zip package with out installers);下方选择需要的文件版本下载。
  2,解压下载的软件包,运行vpnsmgr.exe,在出现的界面选择新设置,填入VPS的IP信息,尝试连接,第一次连接会要求你设置管理密码,自行设置即可。
  3,设置密码后进入管理页面,自动弹出配置向导,可直接跟随设置向导,设置自己喜欢的虚拟HUB名称,选择远程访问VPN Server,然后在自动弹出的L2TP配置页面勾选两种L2TP协议,设置好预共享密钥,点击确认后进入主管理页面。
  4,单击需要管理的HUB选定,单击管理虚拟HUB,会出现虚拟HUB管理页面。点击虚拟NAT和虚拟DHCP服务器按钮。
  5,在出现的设置窗口中点击启用SecureNAT,点击后会出现一个警告框,其提醒内容对于非专业人员过于专业化,容易让人打退堂鼓。但是想要正常连接VPN服务,必须点击确定开启本功能,不打开会导致客户端无法获取IP地址而连接失败。
  6,点击管理用户按钮添加用户帐号,设置用户名和密码,点击确定后正常就可以尝试连接了。

客户端连接

此处以Windows7为例:
  1,打开控制面板,点击网络和共享中心,点击设置新的连接或网络;
  2,在弹出的连接向导中选择“连接到工作区”,点击下一步,选择“否,创建新连接”,点击下一步,选择“使用我的Internet连接(VPN)”,Internet地址中填入VPS的地址,目标名称中自行起一个便于分辨的名字,点击下一步,输入用户名和密码,按需求自行确认是否勾选记住密码,点击连接。
  3,此时正常会提示连接失败,错误代码800,点击仍然设置。
  4,回到网络和共享中心窗口,点击更改适配器设置,在刚才设置的VPN连接上右击,点击属性,选择安全选项卡。
  5,在安全选项卡中,VPN类型改为:使用IPsec的第二层隧道协议,点击高级设置,选择使用预共享的密钥做身份验证,将之前设置的预共享密钥填入密钥框中,点击确定。点击确定关闭属性窗口。点击任务栏通知区域的网络图标,选择刚才设置的VPN连接,点击连接即可正常使用。

参考:

1,Install on Linux and Initial Configurations-softether.org
https://www.softether.org/4-docs/1-manual/7._Installing_SoftEther_VPN_Server/7.3_Install_on_Linux_and_Initial_Configurations
2,SoftEther下载中心
https://www.softether-download.com/cn.aspx

乐视路由器LBA-047-CH免拆机原厂系统开启SSH、备份固件、刷入breed

乐视路由器LBA-047-CH免拆机原厂系统开启SSH、备份固件、刷入breed

前言

这款乐视路由器虽然配置很低,处理器为QCA9531,RAM为128M,ROM为16M,2.4G频段300M无线,没有5G,1WAN口,2LAN口。但是今年双十一,乐视官网活动价19.9元,价格超级低,而且据说买五个可以包邮,看到好多网友们都买了,于是我也买了一只用于研究。虽说经历过斐讯的各位网友可能觉得没什么购买欲,但这个路由器性价比还是蛮高的。本文主要讲该路由器如何开启SSH。

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

1:基本的Windows系统与Linux系统操作;
2:基本的路由器组网知识;

操作警告:

修改路由器的设置,尤其是原厂固件设置界面未显示的设置项,可能会因此损坏您的路由器系统,甚至损坏设备硬件,所以请务必小心操作!学习本文需要您自担风险,本人不对您路由器可能发生的损坏负责。

软件和硬件准备:

学习本文体验这个工具需要做如下准备:
1:LBA-047-CH路由器一台(废话),本人手里这台固件版本为5.0.016S,其他版本未测试,请自行测试。
2:网线*2,不连接上级网络,1根网线就够。机器原包装只有电源适配器,没网线。
3:电脑一台,我的电脑上用的是Windows系统。
4:SSH客户端,我用的是Putty.
5:网页浏览器软件。
6: 可能需要Internet. 其实无Internet也可以。

开启SSH:

1:使用一根网线连接路由器WAN口到上级网络,上级网络要有Internet连接。如果你只是开启SSH,Internet不是必要的,另一根网线连接路由器LAN口与电脑,路由器接通电源。
2:打开浏览器,登陆管理页面,IP地址如果没修改过应该是:192.168.67.1,如果路由器之前没设置过,应该会引导设置路由器。
3:按照引导设置上网方式、无线ID、无线密码与管理密码等信息,进入管理页面后路由器就可以正常使用了。

4:点击‘更多功能’设置按钮,进入更多功能设置页。

008.JPG

此时浏览器地址栏中的地址类似为

http://192.168.67.1/cgi-bin/luci/;stok=********************************/admin/more/

5:对此进行修改,admin斜杠后面内容删除,添加部分内容。改为类似以下内容并回车进入Openwrt启动脚本设置页面,如下图:

***/admin/system/startup

006.JPG

006-2.JPG

6:对本地启动脚本进行编辑,按其要求将以下命令插入到'exit 0'前面

/usr/sbin/dropbear -p 0.0.0.0:22

点击‘/sbin/letvaccount 6’一行结尾处以将光标置于此,然后按回车键换行,插入一个新行,将上面一行代码填入。如果你想备注,行注以#标示。最后不要忘了点击提交按钮保存。

007.JPG

7:再次点击‘更多功能’设置按钮,进入更多功能设置页,点击重启路由,会询问是否确认重启,确认后路由器开始重启。

008.JPG

大约等待一分钟后确认路由器启动,前置彩色LED指示灯亮蓝色或绿色。尝试使用SSH客户端进行连接,连接成功。
Putty界面参考以下填写:

009.JPG

连接成功

010.JPG

输入用户名root,之前配置页面设置的密码,登陆成功。

012.JPG

至此,成功打开此路由器的SSH。

备份路由器分区

我们折腾路由器,最常做的就是为路由器刷入第三方固件,再刷固件之前,我们一般都会对原厂固件进行备份。一般我们两种备份方式,一种是将存储器拆下使用编程器对整个Flash制作镜像,一种是在打开Telnet或SSH的前提下使用命令行备份分区。

1:拆下Flash备份

拆下Flash备份需要有足够的焊接技术,要用到编程器,运气不好极易损坏设备。路由器常见的Flash有两种,一种是SPI Flash,另一种是NAND Flash。SPI Flash使用SPI接口存取数据,编程器实现简单,价格较低,大约三十元左右即可搞到;但NAND Flash较复杂,专业的编程器非常昂贵,价格几百到几千,业余玩家是没有财力购买这种设备的。曾有网友自购IC座与某些型号路由器自行DIY编程器,若读者有兴趣具体资料可使用搜索引擎搜索,本文暂不讨论硬件备份技术。

2:SSH登录使用命令行配合WinSCP备份分区

使用SSH登录路由器通过命令行备份分区需要有root权限。当您打开了路由器的SSH登录功能,且获取到了root账号的登录权限,您可以通过cat命令将分区备份到/tmp下,该位置在RAM中,因为路由器的RAM一般情况都是比ROM大的,所以我们可以把RAM的镜像存储在内存中。比如我们这次的乐视超级路由器,RAM大小为128M,ROM为16M。这个机器我已经成功备份了mtd0~mtd6的所有分区,以下是操作步骤。
首先确保网路连接正常,通过SSH终端连接路由器并登录,输入cat /proc/mtd 命令以列出所有分区,不同机型可能分区方案不同,我们看一下乐视这款路由器的分区:

root@OpenWrt:~# cat /proc/mtd
dev:    size   erasesize  name
mtd0: 00040000 00010000 "u-boot"
mtd1: 00010000 00010000 "u-boot-env"
mtd2: 00e30000 00010000 "rootfs"
mtd3: 005b0000 00010000 "rootfs_data"
mtd4: 00170000 00010000 "kernel"
mtd5: 00010000 00010000 "art"
mtd6: 00fa0000 00010000 "firmware"

我们可以看出,名字为"u-boot"的mtd0分区明显是存储Bootloader的,Kernel可能表示的系统内核,art是机器的工厂数据,firmware就表示固件。
假如我们想要备份u-boot的分区数据,我们可以使用cat命令来创建备份并将其存储到/tmp。

root@OpenWrt:~# cat /dev/mtd0 > /tmp/mtd0

这条命令是没有回显信息的,当我们再次看到以下信息时,表示命令已经执行完毕。

root@OpenWrt:~#

这时我们就可以在/tmp目录下看到一个名为mtd0的文件,大小为256KB,我们可以使用WinSCP下载文件到本地,然后删除/tmp下的文件,以释放存储空间。
重复以上步骤,把mtd0改为mtd1,我们尝试运行以下命令,就可以将mtd1的数据备份到/tmp中。

root@OpenWrt:~# cat /dev/mtd1 > /tmp/mtd1

我们依然可以使用SCP客户端将文件下载到本地,然后删除/tmp下的mtd1文件。
如果我们需要,如此重复操作,可将mtd0~mtd6全部备份。我们发现,所有的文件的总大小超过了Flash的大小16M,分析文件大小可知,mtd3:rootfs_data是属于mtd2:rootfs的,mtd2:rootfs和mtd4:kernel构成了mtd6:firmware最终我们会发现,Firmware + u-boot + u-boot-env + art合起来正好是16384KB等于16M。如此看来,其实我们备份mtd0,1,5,6,即可对整个Flash空间进行了备份。

为机器刷入新的Bootloader

将机器原厂系统备份后我们就可以随意刷固件了么?别急,我们在开始随意刷入固件之前可以先为其刷入一个称之为Breed的Bootloader,通过这个Bootloader我们可以更方便安全的为路由器刷入新的固件。
看到这可能有人会问,什么是Bootloader?简单地说,Boot Loader 就是在操作系统内核运行之前运行的一段小程序。通过这段小程序,我们可以初始化硬件设备、建立内存空间的映射图,从而将系统的软硬件环境带到一个合适的状态,以便为最终调用操作系统内核准备好正确的环境。如果想详细了解相关知识,具体参考:嵌入式系统 Boot Loader 技术内幕
为本机刷入Breed,我们需要找到与本机对应的Breed,我们可以访问作者提供的下载网站查找下载对应机器型号的的breed,下载后将文件改名为breed.bin后使用WinSCP上传至路由器/tmp目录,然后我们尝试运行mtd write /tmp/breed.bin u-boot,这时我们会发现如下提示:

root@OpenWrt:/tmp# mtd write breed.bin u-boot
Could not open mtd device: u-boot
Can't open device for writing!

这是因为当前运行的原厂固件不支持对Bootloader区写入,不仅如此,Openwrt编译时默认的配置都是不支持写Bootloader区的,如果需要Openwrt正常运行此命令,需要在编译openwrt时设置好配置文件,Openwrt的编译不在本文讨论范围。幸运的是,我在网上找到了其他网友分享的解锁u-boot临时固件,我们将此固件刷入,然后就可以正常运行写入命令了。
首先,我们下载这个临时固件ap147.bin,将其通过WinSCP上传至路由器/tmp目录,只保留与电脑连接的LAN口网线,断开路由器其他网线。然后使用sysupgrade命令刷入固件。

root@OpenWrt:/tmp# sysupgrade -F -n ap147.bin
Sending TERM to remaining processes ... netifd sleep sleep mcproxy miniupnpd zebra watchquagga ifplugd led-monitor nginx uhttpd dnsmasq monit letvremotecontr xl2tpd privoxy letvreport letvlogreport ntpd crond rcS logger syslogd klogd hotplug2 ubusd log_monitor
Sending KILL to remaining processes ... sleep sleep uhttpd letvlogreport crond
killall: led-monitor: no process killed
killall: wan_probe: no process killed
setting up led super_router:blue:wan
setting up led super_router:red:wan
setting up led super_router:green:wan
Switching to ramdisk...
Performing system upgrade...
Warning: Bad CRC, using default environment
ash: invalid number 'bootcmd=bootp;'
ash: invalid number 'setenv'
ash: invalid number 'bootargs'
ash: invalid number 'root=/dev/nfs'
ash: invalid number 'nfsroot=${serverip}:${rootpath}'
ash: invalid number 'ip=${ipaddr}:${serverip}:${gatewayip}:${netmask}:${hostname}::off;'
ash: invalid number 'bootm'
ash: 0x0: unknown operand
Unlocking firmware ...

Writing from <stdin> to firmware ...
Upgrade completed
Rebooting system...

显示Rebooting后,我们会发现路由器的IP地址变成了192.168.1.20,我们登录管理页面,使用密码password登录路由器,修改密码。然后WinSCP和SSH终端使用修改后的密码通过IP192.168.1.20登录。将之前下载的breed文件改名为breed.bin后使用WinSCP上传至路由器/tmp目录,输入以下命令成功刷入。

root@Gargoyle:/tmp# mtd write /tmp/breed.bin u-boot
Unlocking u-boot ...

Writing from /tmp/breed.bin to u-boot ...
root@Gargoyle:/tmp#

然后我们输入reboot命令重启路由器。
按住复位键接通电源大约10秒左右,机器指示灯会不断闪烁,浏览器访问192.168.1.1进入Breed界面。然后我们就可以愉快的刷入固件了。

参考:

本文思路参考自:

1:(更新)解锁uboot,刷入breed,乐视路由已破解(非拆机)附官方固件+art备份64k文件
https://www.right.com.cn/forum/thread-172877-1-1.html

其他搞机参考资料:

1:乐视路由器抢先全网开箱+首拆+评价 多图(增补润色版)
http://bbs.mydigit.cn/read.php?tid=1327297
2:乐视路由器刷OpenWrt(LEDE)教程
https://www.right.com.cn/forum/thread-195788-1-1.html
3:[10-09更新]LETV 路由器刷openwrt固件---QCA高通原厂无线驱动
https://www.right.com.cn/forum/thread-194485-1-1.html
4:乐视超级路由器刷LEDE,安装SS插件
https://www.right.com.cn/forum/thread-261787-1-1.html
5:嵌入式系统 Boot Loader 技术内幕
https://www.ibm.com/developerworks/cn/linux/l-btloader/index.html
6:Breed下载页
https://breed.hackpascal.net/