「Docker」- 在测试中使用

#1 测试静态网站(单个容器)
(1)创建Dockerfile并使用该Dockerfile创建镜像。
(2)从该镜像中启动容器。启动时,将本地卷挂载到容器中(通过-v选项)。
(3)修改本地卷中的文件,访问容器来查看。
#2 构建并测试Web应用程序(多个容器)
# 示例一、接收URL参数,并以JSON返回 老路子:使用Dockerfile创建容器。启动一个容器,并使用-v挂载外部卷。访问容器来测试。
# 示例二、连接Redis服务,存储输入的URL参数 创建一个项目,项目中连接Redis服务,Host: db,Post: 6379,并将请求参数写入Redis中。
使用Dockerfile创建一个Redis镜像。从镜像启动容器。使用docker port命令查看端口,使用Redis的客户端工具进行测试。
将应用程序连接到Redis容器,实际上是「组网」,使二者能互相连接。共有三种方法:

使用Docker「内部网络」。不灵活,也不够强大。不推荐使用。
使用Docker「Networing」从Docker 1.9开始,使用docker networking命令。推荐使用的方法。
使用Docker「链接」。是一个抽象层,可以将具体容器链接到一起来进行通讯。在Docker 1.9之前版本推荐使用的方法。

推荐使用「Docker Networking」,而不是「Docker链接」的原因:

「Docker Networking」可以跨宿主机;
「Docker Networking」无需事先创建容器,也不必关心容器的运行顺序;
「Docker Networking」可以在无需更新连接的情况下,对停止、启动或重启容器。而「Docker链接」,则需要更新一些配置,或者重启相应的容器来维护Docker容器之间的链接。

# 内部网络
这属于Docker自身的网络栈。常见的就是把「容器的端口」映射到「宿主机的端口」。还有一种用法就是内部网络。
安装Docker时,会默认创建了docker0网口,它是一个虚拟网桥,连接容器和宿主机,分配私有IP地址,网段172.17.0.0/16,如果被占用,则会在172.16.0.0到172.31.0.0之间选择一个。每个容器都会在这个接口上分配一个IP地址。Docker会为每一个容器创建一个veth*的接口,这个接口一端连接到「容器内的eth0」,一端桥接到「宿主机的docker0」。这样Docker就创建了一个虚拟子网,连通的宿主机器和各个容器,这样它们之间就可以互相操作了。
追踪路由可以发现,流量从「容器内的eth0」到「veth*接口」,到了「docker0」。[……]

READ MORE

「Kubernetes」- 在集群初始化时,如果无法拉取官方镜像怎么办?

问题描述
当使用 kubeadm 命令初始化集群时,会去官方镜像仓库(k8s.gcr.io)拉取镜像。但是国内网络无法访问官方镜像仓库,导致集群初始化失败;
该笔记将记录:在 Kubernetes 集群初始化时,拉取官方镜像的方法;
解决方案
简而言之,我们推荐使用如下方式:
通用场景:crane, gcrane, krane
通过 crane cp 命令,能够将镜像复制到自建仓库中:

crane auth login -u username -p password registry.example.com

crane cp \
registry.k8s.io/ingress-nginx/controller:v1.2.1 \
registry.example.com/ingress-nginx/controller:v1.2.1

# 在 Harbor 中,crane 无法使用多级镜像路径,即 registry.example.com/a/b/c/ingress-nginx/controller:v1.2.1 将失败;

特性特征: 1)能够识别 HTTP_PROXY HTTPS_PROXY NO_PROXY 等等环境变量; 2)无需运行 docker 服务;
复制镜像,并保存摘要(镜像摘要发生变化)
go-containerregistry/crane.md at main · google/go-containerregistry · GitHub
我们现在发现的问题是 1)通过 docker inspect –format='{{index .RepoDigests 0}}’ $IMAGE 会发现多个摘要; 2)当推送镜像后,将仅保留当前仓库的 Digest 信息,而原始仓库的 Digest 信息将不会被推送到当前仓库中;
通过 crane cp 命令,能够解决该问题;
针对 Kubernetes 集群:新版集群(推荐)
在使用 kubeadm v1.14 初始化集群时,我们无意间发现它支持 –image-repository 选项,该选项能够指定镜像仓库地址:

kubeadm init –image-repository registry.aliyuncs.com/google_containers

如果通过配置文件初始化集群,能够使用 imageRepository 字段
针对 Kubernetes 集群:手动拉取镜像
我学到的首个方法是手动拉取镜像,然后在本地打标签。[……]

READ MORE

「VCS」- 版本控制系统

SCCS – Source Code Control System
https://en.wikipedia.org/wiki/Source_Code_Control_System 源代码控制系统(SCCS)是一种版本控制系统,用于在开发软件期间跟踪源代码和其他文本文件的变化。 这允许用户检索原始源代码的任何先前版本,以及已经存储的更改。
于1972年,由Marc Rochkind在贝尔实验室开发,用于运行OS/360的IBM System/370计算机。
RCS – Revision Control System
Revision Control System – Wikipedia
版本控制系统(RCS)是早期版本控制系统(VCS)。可以将其视作一组UNIX命令,允许多个用户开发和维护代码或文档。使用RCS,用户可以自己修改文档、提交更改、合并它们。RCS最初是为程序开发的,但对于经常修改的文本文档或配置文件也很有用。
于1982年首次发布
CVS – Concurrent Versions System
Wikipedia/Concurrent Versions System
并发版本系统(CVS, Concurrent Versions System),也称为并发版本控制系统(Concurrent Versioning System),是软件开发领域中的免费的客户端-服务器版本控制系统。 版本控制系统会跟踪一组文件中的所有工作及更改,并允许多个开发人员进行协作(可能在空间和时间上很分散)。
于1986年7月,Dick Grune将CVS作为一系列shell脚本开发出来。
Git
Git
Bazaar
Bazaar 著名的launchpad.net使用的就是Bazaar进行版本控制。
Subversion
BitKeeper
Mercuial
Mercurial 主命令:hg
参考文献
For the specific software implementation, see Revision Control System Version control system[……]

READ MORE

「Bazaar」

Bazaar,是一个版本控制系统。Bazaar(或bzr)是一个强大,友好和可扩展的分布式版本控制系统。Bazaar是Canonical Ltd的一个项目,也是GNU项目的一部分,旨在开发一个免费的操作系统。Bazaar跟踪软件源代码(或类似信息)的变化;让你看到使谁修改了它、什么时候、为什么;合并并发更改;帮助人们在团队中一起工作。
安装
从发行版的源中安装

# Kali GNU/Linux Rolling
apt-get install bzr

使用源码编译Bazaar并安装
Download Bazaar: http://wiki.bazaar.canonical.com/Download 安装过程可以参考:BLFS/Bazaar-2.5.1:http://www.linuxfromscratch.org/blfs/view/7.6/general/bazaar.html
文档:http://wiki.bazaar.canonical.com/SourceDownloads#Source_Downloads 下载:https://launchpad.net/bzr/2.7/2.7.0/+download/bzr-2.7.0.tar.gz 编译、安装:http://wiki.bazaar.canonical.com/InstallationFaq
安装的可执行程序
bzr 用于访问bzr仓库的命令行的Client程序。
常见错误汇总
ImportError: No module named bzrlib

bzr: ERROR: Couldn’t import bzrlib and dependencies.
Please check the directory containing bzrlib is on your PYTHONPATH.

Traceback (most recent call last):
File “/opt/bazaar/bin/bzr”, line 74, in <module>
import bzrlib
ImportError: No module named bzrlib

原因分析:因为我的安装目录在 /opt/bazaar(python setup.py install –prefix=/opt/bazaar),所以bzrlib在 /opt/bazaar/lib/python2.7/site-packages 下。
解决方案:

# 将bzrlib添加到模块的搜索路径中
export PYTHONPATH=$PYTHONPATH:/opt/bazaar/lib/python2.7/si[……]

READ MORE

「Git」- 杂记

Branching Model(分支模型)
码云中的分支模型
单分支模型 (只创建 master 分支)
生产/开发模型 (支持 master/develop 类型分支)
特性/发布模型 (支持 master/develop/feature 类型分支)
开发/发布分离模型 (支持 master/develop/feature/release 类型分支)
开发/发布/缺陷分离模型 (支持 master/develop/feature/release/bugfix 类型分支)
git-flow [支持自定义]

生产环境分支 master
开发分支 develop
功能分支 feature
发布分支 release
补丁分支 hotfix

Trunk Based Development
Trunk Based Development
master(1)\release(n)
该模型是CI思想所崇尚的工作方式,它由单个master分支和许多release分支组成,每个release分支在特定版本的提交点上从master分支创建出来,用来进行上线部署和热修复。在该模式中,没有显性的feature分支。
Git Flow
Gitflow Workflow
master(1)\develop(1)\feature(n)\release(n)\hotfix(n)
该模型是若干模式的集大成者,包含一个master分支、一个develop分支、许多feature分支、许多release分支、许多hotfix分支,以及许多繁琐的合并规则。

Aone Flow
master(1)\feature(n)\release(n)
三条规则:

规则一:开始工作前,从master创建feature分支

从代表最新已发布版本的master分支上创建一个通常以「feature/」为前缀命名的特性分支,然后在这个分支上提交代码修改。也就是说,每个工作项(可以是一个人完成,或是多个人协作完成)对应一个特性分支,所有的修改都不允许直接提交到master分支。

规则二,通过合并feature分支,形成release分支

从master分支上拉出一条新分支,将所有本次要集成或发布的feature分支依次合并过去,从而得到release分支。release分支通常以「release/」前缀命名。

规则三,发布到线上正式环境后,合并相应的release分支到master分支[……]

READ MORE

「GitLab」- 当前登录网络地址非用户的真实地址(Current sign-in IP)

问题描述
在 GitLab / Admin Area / Users / <Username> / Current sign-in IP 中,显示的网络地址非当前用户的真实地址。
该笔记将记录:如何设置 GitLab 以使 Current sign-in IP 显示真实的网络地址。
解决方案
请求链路:Client => Nginx => Docker => Nginx within the Gitlab Container
第一步、修改 Nginx 配置
目的:使客户端的真实网络地址可以传递到下游,这通过保存在 X-Forwarded-For 字段实现。
为被 Client 请求的 Nginx 设置 X-Forwarded-For 头部:

location / {
….
proxy_set_header X-Forwarded-For $realip_remote_addr;
….
}

第二步、修改 gitlab.rb 配置
目的:1)使在 GitLab 中的 Nginx 读取到上游传递过来的客户端的真实网络地址,2)并传递给 GitLab 后端服务。


# 1)
nginx[‘real_ip_trusted_addresses’] = [‘127.0.0.1′,’172.16.37.0/24’]
nginx[‘real_ip_header’] = ‘X-Forwarded-For’
nginx[‘real_ip_recursive’] = ‘on’


# 2)
nginx[‘proxy_set_headers’] = {
“Host” => “$http_host_with_default”,
“X-Real-IP” => “$remote_addr”,
“X-Forwarded-For” => “$proxy_add_x_forwarded_for”,
“X-Forwarded-Proto” => “https”,
“X-Forwarded-Ssl” => “on”,
“Upgrade” => “$http_upgrade”,
“Connection” => “$connection_upgrade”
}

在 gitlab.rb 中,配置 nginx[”] 用于控制在 GitLab 中的 Nginx 的配置: 1)nginx[‘real_ip_header’],指示从 X-Forwarded-For 中读取客户端真实网络地址; 2)nginx[‘proxy_set_headers'[……]

READ MORE

「GitLab」- 维护,管理

修改 ROOT 密码(忘记密码)
How to reset your root password | GitLab

gitlab-rails console -e production

user = User.find_by(email: ‘admin@example.com’)

user.password = ‘secret_pass’
user.password_confirmation = ‘secret_pass’

user.save!

最后,使用 admin@example.com / secret_pass 登录。[……]

READ MORE

「GitLab」- 配置 Nginx 反向代理 GitLab 服务

问题描述
在 GitLab 中,内置 Nginx 服务,但是在部分场景下,部署 GitLab 的主机还会部署 Web 服务,所以就会形成如下架构:

Client –>> Nginx –>> Nginx within GitLab –>> GitLab Backend
\
`–>> Other Web Service

再比如,我们使用 GitLab Omnibus 部署 GitLab 服务,而外部使用 Nginx 反向代理,而非主机网络。所以就会形成如下架构:

Client –>> Nginx –>> Nginx within GitLab Omnibus –>> GitLab Backend

该笔记将记录:配置 Nginx 反响代理 GitLab 服务,以及其中可能会遇到的问题。
注意事项
1)当我们提到“Nginx”时,是专指 Client 请求的 Nginx,而不是 GitLab 内置的 Nginx; 2)我们将使用“Nginx within GitLab”来表示 GitLab 内置的 Nginx(包括 GitLab Omnibus 的 Nginx);
场景一、Nginx –>> GitLab Omnibus
Nginx 提供 HTTPS 服务,而以 HTTP 来请求后端的 GitLab 服务。
使用如下 Nginx 配置即可:

server {
listen 443 ssl;
server_name gitlab.example.com;

ssl_certificate /path/to/fullchain.pem;
ssl_certificate_key /path/to/privkey.pem;

location / {
proxy_pass http://127.0.0.1:8080;
}
}

后端 GitLab 使用如下 gitlab.rb 配置:


external_url ‘https://git.example.com’
gitlab_rails[‘gitlab_shell_ssh_port’] = 22

nginx[‘listen_port’] = 80
nginx[‘listen_https’] = false

参数 external_url 指定外部地址。当 GitLab 创建地址时(比如,[……]

READ MORE

「GitLab」- 常见问题处理

镜像(复制)远程仓库
Pulling from a remote repository[……]

READ MORE

「GitLab」- Requests to the local network are not allowed

Requests to the local network are not allowed
gitlab使用webhook向jenkins发送请求,报错 Requests to the local network are not allowed Webhooks and insecure internal web services
在添加 Webhook 地址时,产生类似如下错误提示:

Requests to the local network are not allowed

原因分析
原因在官方「Webhooks and insecure internal web services」文章已经解释,是为了防止内部无认证的服务被恶意请求。
解决方案
如果要解决这个问题,在管理员后台设置即可。以管理员帐号登录:

Admin Area

-> Settings

-> Network

-> Outbound requests

-> Allow requests to the local network from hooks and services

勾选「Allow requests to the local network from hooks and services」即可。
Url is blocked: Requests to the local network are not allowed
gitlab Import url is blocked: “Requests to the local network are not allowed” (#26845) · Issues · GitLab.org / GitLab · GitLab
在添加 Webhook 地址时,产生类似如下错误提示:

Url is blocked: Requests to the local network are not allowed

原因分析
参考 gitlab Import url is blocked: “Requests to the local network are not allowed” (#26845) 页面;
解决方案
Admin -> Settings -> Network -> Outbound Requests -> Allow requests to the local network from hooks and services[……]

READ MORE

「GitLab」- 常见问题整理

remote: The project you were looking for could not be found
GitLab: The project you were looking for could not be found issue
问题描述: 项目存在,但是在提交时提示项目不存在。
问题原因: 不详。
解决办法: 将 https://gitlab.com/{gitlab_user}/project_repo.git 修改为 https://{gitlab_user}@gitlab.com/gitlab_user/project_repo.git 即可。即添加用户名。[……]

READ MORE

「Git」- 分布式版本控制系统

关于Git,我写不出来更好的文章,也轮不到我写。因为我只是一个Git用户,有些东西在书里和手册里写的已经很明白了,我只能做一些简单的杂记。
相关手册和文档
执行命令 git help <cmd> 用于查看帮助手册,比如 git help add 用于查看 git add 命令的手册。
或者使用子命令的形式在Man手册页面中查找。比如man git-add,用于查看git add命令的手册。
或者可以查看Git文档主页:https://git-scm.com/doc
当然,常用的做法还是”百度一下“,用的时候现查嘛。。。
相关书籍
《Git版本控制管理(第2版)》 《Pro Git》:https://git-scm.com/book/en/v2
相关的GUI工具
参考官方页面中的工具列表:https://git-scm.com/download/gui/linux
不用Git的GUI工具。命令行虽然操作繁琐,但是也没有繁琐到哪里去,处在一个可接收的范围内。当配合命令行工具进行仓库管理、过滤、检查、筛选操作的时候,使用命令行非常方便。GUI提供的功能通常都非常的基础,不是非常适用于复杂Git操作。不过,我的笔记本上还是安装了一个GUI工具,之所以安装就是为了丰富一下自己的工具包。我能用到的GUI工具屈指可数,大部分日常操作都是在命令行中完成的。
额,我安装的是Git内置的GUI工具,通过git gui命令启动。
参考文献
Home Page:https://git-scm.com/ Installion: https://git-scm.com/download/linux Souece Code: https://github.com/git/git[……]

READ MORE

「Git」- 概念及原理

概念(学习笔记)
对象库:原始文件,日志消息,作者信息,日期,以及其他的版本或者分支的信息。
索引
对象类型
# 块:BLOB 文件的每一个版本表示为一个「块」。二进制大对象,可以包含任意数据的变量或者文件。
# 目录树:TREE 一个「目录树」对象代表一层目录信息。它记录BLOB标识符,路径名,和在一个目录里所有文件的一些元数据。它可以递归引用其他「目录树」,从而建立一个包含目录和子目录的完整的目录层次结构。
# 提交:COMMIT 一个「提交」对象保存版本库中每次变化的元数据,包括作者、提交者、提交日期、日志消息。每个提交都指向一个「目录树」对象。这个目录树对象在一张完整的快照中捕获提交时版本库的状态。
# 标签:TAG 为特定对象分配可读的名称。通常是一个「提交」对象。
索引
索引是一个临时的、动态的二进制文件,它描述整个版本库的目录结构。索引捕获项目的某以时刻的整体结构的一个版本。[……]

READ MORE

「Git」- 安装(Ubuntu、Debian、CentOS、源码编译)

on Ubuntu 18.04.5 LTS
How to Install the Latest Git Version on Ubuntu Git/Download for Linux and Unix

# 仓库版本的安装
apt-get install git

# 最新版本的安装,for Ubuntu
add-apt-repository ppa:git-core/ppa
apt update
apt install git

on CentOS 7.x(安装新版本)
IUS/Setup Update Git to the latest (help) How to install latest version of git on CentOS 7.x/6.x

# 安装新版本 Git
yum install -y \
https://repo.ius.io/ius-release-el7.rpm \
https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm
yum makecache
yum install git2u-all.noarch # 全家桶(11/20/2019 git version 2.16.5)

# 安装更新的版本
# yum install http://opensource.wandisco.com/centos/6/git/x86_64/wandisco-git-release-6-1.noarch.rpm
# yum install http://opensource.wandisco.com/centos/7/git/x86_64/wandisco-git-release-7-1.noarch.rpm
yum install -y http://opensource.wandisco.com/centos/7/git/x86_64/wandisco-git-release-7-2.noarch.rpm
yum makecache
yum install -y git #(11/20/2019 git version 2.22.0)

on Windows
Git – Downloading Package/Download for Windows
安装下载即可
通过源码安装
对于 Git 的编译安装,建议参考 BLFS 文档;
建议安装依赖
cURL-7.50.1 (needed to use Git over http, https, ftp or ftps), OpenSSL-1.0.2h, Python-2.7.12[……]

READ MORE

「Git」- 快速开始、常用操作、基本配置

第一步、创建仓库(git init, git clone)
xcode – ‘git init -b <branch name>’ command in terminal is throwing an ‘unknown switch’ error
创建本地仓库,并添加远程地址:

git init
git init –initial-branch=master # 初始化,并指定初始化分支,需要 git 2.28+ 版本

git remote add origin “protocol://path/to/repo”

克隆远程仓库到本地:

git clone “protocol://path/to/repo”

git clone “protocol://path/to/repo” “/path/to/local/folder” # 检出到特定目录

检查到本地非空目录(git – How do I clone into a non-empty directory?):

// fatal: destination path ‘.’ already exists and is not an empty directory

git init
git remote add origin PATH/TO/REPO
git fetch
git reset origin/master # Required when the versioned files existed in path before “git init” of this repo.

# 如果本地不存在,则重置文件
git reset –hard

# 清理已经版本控制的本地文件
git checkout -t origin/master

在命令行中,无密码检出(How to give username/password to git clone in a script, but not store credentials in .git/config):

# 方法一、直接指定密码

git clone https://user:password@github.com/name/repo.git

# 方法二、自定义密码程序

cat > /tmp/git-ask-pass.sh <<EOF
#!/bin/sh
exec echo “$GIT_PASSWORD”
EOF

GIT_ASKPASS=/tmp/git-askpass-helper.sh GIT_PASSW[……]

READ MORE

「Git」- 提示和技巧

Gitosis
.7 Git on the Server – Gitosis gitosis 使用笔记
权限管理工具,通过一个特殊的仓库(gitosis-admin.git)对 Git 权限进行管理;
# git stash
git-stash,暂存当前工作目录中的修改;
当切换分支时,提示 error Your local changes to the following files would be overwritten by checkout …

git stash
git checkout mBranch
git stash pop

只暂存部分文件
Stash only one file out of multiple files that have changed with Git? – Stack Overflow

# 1) 将无需暂存的文件保存到索引中
git add ‘file1’

# 2)执行 stash 命令,并保存索引
git stash –keep-index

# git merge
分支与合并
Why does pulling sometimes make me create a commit? Git Merge Strategy Options and Examples
git pull = git fetch + git merge,如果无法 fast-forwarding,则进行传统合并(提交具有两个父提交),此时则会要去输入合并说明;
处理 Git 冲突
日常处理冲突的办法是手动修改冲突文件,Git/Resolve Merge Conflicts 解释了如何处理大批量的冲突问题;
合并:两个无关分支的合并
Git refusing to merge unrelated histories on rebase – Stack Overflow
使用 –allow-unrelated-histories 选项,可以合并两个无关分支;
# git rebase
reorder commits with rebase
很并多个提交为单个提交(以简化变更历史)
rebase – Squash my last X commits together using Git – Stack Overflow

git rebase -i ‘<after-this-commit>’
# <after-this-commit> is commit X+1 i.e. parent of the oldest commit you want[……]

READ MORE

「Git」- 分支(Branch)

git-branch,查看、创建、删除分支。
创建分支(增)
How To Create a Git Branch How do I create a new branch in Git? | Learn Version Control with Git

git branch <new-branch> # 基于当前分支
git branch <new-branch> v1.2 # 基于特定 Tag 来创建
git branch <new-branch> <base-branch> # 基于特定 Branch 来创建
git branch <new-branch> f71ac24d # 基于特定 CommitID 来创建

从 Tag 创建分支(What is git tag, How to create tags & How to checkout git remote tag(s)):

git fetch –all –tags –prune
git checkout tags/<tag_name> -b <branch_name>

# 先 git clone 整个仓库,然后 git checkout tag_name 就可以取得 tag 对应的代码了。
# 但是这时候 git 可能会提示你当前处于一个“detached HEAD” 状态,因为 tag 相当于是一个快照,是不能更改它的代码的,如果要在 tag 代码的基础上做修改,需要分支:
# 检出某个tag
git checkout -b <new-branch-name> <tag-name>

创建空分支,并切换到该空分支(Git create a empty branch from existing repository):

git checkout –orphan “<your branch name>”

删除分支(删)
-d, –delete,删除一个分支。 The branch must be fully merged in its upstream branch, or in HEAD if no upstream was set with –track or –set-upstream.
-D,–delete –f[……]

READ MORE

「Git」- Clean(清理)

git-clean,从工作树中删除未跟踪的文件。
命令支持的选项及含义(OPTIONS)
-d 删除未跟踪的目录以及未跟踪的文件。 如果未跟踪的目录由不同的Git仓库管理,则默认情况下不会删除它。如果要删除这样的目录,使用两次-f选项。
-f, –force 如果Git中,未配置变量clean.requireForce为false,git clean将拒绝删除文件或目录,除非给出了-f、-n、-i。 Git将拒绝删除具有.git子目录或文件的目录,除非给出了第二个-f选项。
-i, –interactive 以交互方式显示将要执行的动作和清除的文件。参阅“INTERACTIVE MODE”。
-n, –dry-run 不进行实际的删除动作,只是显示将会执行的动作。
-q, –quiet 安静模式,只报告错误,但不是成功删除的文件。
-e <pattern>, –exclude=<pattern> 除了在每个目录中的.gitignore和$GIT_DIR/info/exclude外,对<pattern>规则指定的文件或者目录也进行忽略。
-x 不要使用从.gitignore(每个目录)和$GIT_DIR/info/exclude读取的忽略规则,但仍然使用-e选项给出的忽略规则。 这允许删除所有未跟踪的文件,包括构建时的输出。这可以使用(可能与git reset一起)来创建一个原始的工作目录来测试一次“干净的构建”。
-X Remove only files ignored by Git. This may be useful to rebuild everything from scratch, but keep manually created files.[……]

READ MORE

「Git」- Clone(克隆)

git-clone,将一个仓库克隆到新的目录。
命令行语法格式(SYNOPSIS)

git clone [–template=<template_directory>]
[-l] [-s] [–no-hardlinks] [-q] [-n] [–bare] [–mirror]
[-o <name>] [-b <name>] [-u <upload-pack>] [–reference <repository>]
[–dissociate] [–separate-git-dir <git dir>]
[–depth <depth>] [–[no-]single-branch]
[–recurse-submodules] [–[no-]shallow-submodules]
[–jobs <n>] [–] <repository> [<directory>]

命令简述(DESCRIPTION)
将仓库克隆到新创建的目录中,为仓库中克隆的每个分支创建远程跟踪分支(使用git branch -r查看),然后创建并检出初始分支,该初始分支是所克隆的仓库中的当前活动的分支。
在克隆之后,没有参数的普通git fetch将更新所有远程跟踪分支,而没有参数的git pull将另外将远程master分支合并到当前master分支(如果有的话)(当指定“–single-branch“另说,见下文)。
此默认配置通过在refs/remotes/origin下创建对远程分支头的引用,并通过初始化remote.origin.url和remote.origin.fetch配置变量来实现。
命令支持的选项及含义(OPTIONS)
–local, -l 当克隆的仓库在本地机器上时,-l使git绕过正常的“Git aware”传输机制,并通过创建「HEAD副本」和「对象和引用目录下的所有内容」来克隆仓库。.git/objects/目录下的文件是硬链接的,以尽可能节省空间。
如果仓库被指定为本地路径(例如,/path/to/repo),则该选项是默认值,而–local本质上是一个no-op。如果仓库被指定为URL,则-l被忽略(我们从不使用本地优化)。如果给出了/path/to/repo,指定–no-local将覆盖默认值,使用正常的Git传输。
–no-hardlinks 强制从本地文件系统上的仓库复制.git/objects目录下的文件,而不是使用硬链接。 如果尝试备份仓库,可以这么做。
–shared, -s[……]

READ MORE

「Git」- Config(配置)

git config,用于获取或设置仓库或全局的选项。
-f config-file / –file config-file 使用指定的配置文件。如果未指定该选项则默认使用GIT_CONFIG中指定的。
git-credential-store
帮助在磁盘上存储凭据。
命令行语法格式
git config credential.helper ‘store [options]’
命令简述
注意 密码以无加密的方式存储在硬盘的文件中。只能通过文件系统的权限进行保护。如果这种做法不可接受,那么可以使用git-credential-cache,或者系统提供的安全存储工具。
此命令,将凭证无限期的存储在磁盘上,供未来的Git程序使用。
你可能不想直接调用这个命令;它被用作git的其他部分的凭据助手。请参见gitcredentials或下面的Examples。
命令支持的选项及含义
–file=<path> 使用<path>来查找和存储凭据。该文件将设置成其文件系统权限,以防止系统上的其他用户读取它,但不会被加密或以其他方式保护。 如果未指定<path>,将从~/.git-credentials和$XDG_CONFIG_HOME/git/credentials中搜索凭据。如果存在~/.git-credentials,则将将凭据写入~/.git-credentials;如果前者没有,存在$XDG_CONFIG_HOME/git/credentials,则为$XDG_CONFIG_HOME/git/credentials。查看下面的FILES章节。
相关文件(FILES)
如果没有指定–file,将会按顺序搜索一下两个凭据文件:

~/.git-credentials: 用户特定的凭据文件。
$XDG_CONFIG_HOME/git/credentials: 第二个用户特定的凭据文件。如果$XDG_CONFIG_HOME为空或者未设置,使用$HOME/.config/git/credentials。如果~/.git-credentials也具有匹配的凭据,则不会使用存储在此文件中的任何凭据。如果使用不支持的Git的旧版本,那么不要创建此文件是个好主意。

对于凭据查找,文件按照上面给出的顺序读取,最先读取的凭证的优先级高于后读取的。
凭证存储将默认写入列表中的第一个文件。如果没有这些文件存在,将会创建~/.git-credentials来写入。
删除凭据时,匹配凭证将从所有文件中删除。
简单示例(EXAMPLES)

$ git config credential.helper[……]

READ MORE

「Git」- 钩子

钩子是什么?
和其它版本控制系统一样,在特定的动作发生时,Git能触发自定义的脚本,以此来完成Git无法完成的某些工作。这些脚本就是“钩子”。
钩子分为两种: 1)运行于客户端的钩子。在进行诸如提交、合并这样的操作时,会触发客户端钩子。 2)运行于服务端的钩子。在诸如接收到推送的提交这样的操作时,则会触发服务端钩子。
我们能够根据自己的需要使用这些钩子。
如何设置钩子?
在客户端中,钩子被存储在项目中的.git/hooks目录中。在远程仓库中,钩子存储在仓库的hooks目录下。当发生特定的Git动作时,Git会调用该目录中特定名字的脚本。这些脚本就是“钩子”。
当我们用git init初始化一个新仓库时,Git默认会在这个目录中放置一些示例钩子。这些脚本除了本身可以被调用外,它们还透露了被触发时所传入的参数。所有的示例钩子都是Shell脚本,其中一些还混杂了Perl代码,不过,任何正确命名的可执行脚本都可以正常使用,我们可以用Ruby或Python,或其它语言编写它们。这些示例钩子的名字都是以.sample结尾,如果我们想启用它们,得先移除这个后缀。
把一个正确命名且可执行的钩子文件放入.git/hooks目录中,即可激活该钩子脚本。这样一来,它就能在发生特定动作时被Git调用。接下来,我们会讲解常用的钩子脚本类型。
客户端中的钩子
客户端钩子主要存在于本地仓库中,通常在.git/hooks目录中,分为很多种。下面把它们分为三类进行介绍,分别是:提交工作流钩子、电子邮件工作流钩子、其它钩子。
提交工作流中的钩子
pre-commit,在输入提交信息前运行。它用于检查即将提交的快照,例如,检查是否有所遗漏、确保测试运行、以及核查代码。 如果该钩子以非零值退出,Git将放弃此次提交,不过我们可以用git commit –no-verify来绕过这个环节。我们可以利用该钩子,来检查代码风格是否一致(运行类似lint的程序)、尾随空白字符是否存在(自带的钩子就是这么做的)、或新方法的文档是否适当。
有的人可能不理解“在输入提交信息前运行”这句话什么意思,大概是我们用了太多的git commit -m “New Commit”的缘故,该命令将提交和提交的输入信息一步化,淡化了二者中间的一个过程。实际情况是执行提交命令git commit后会启动一个编辑器。
prepare-commit-msg,该钩子在启动提交信息编辑器之前,默认信息被创建之后运行。它允许我们编辑提交者所看到的默认信息。该钩子会接收一些参上:存有当前提交信息的文件的路径、提交类型、修补提交的提交SHA-1校验。它对一般的提交来说并没有什么用;然而对那些会自动产生默认信息的提交非常有用,如提交信息模板、合并提交、[……]

READ MORE

「Git」- 对大文件进行版本控制(LFS, Large File Storage)

问题描述
在我们的某个仓库中,存在大量 PDF 文件,我们会频繁操作这些文件。
在提交时,Git 会进行系列操作(比如创建对应的 BLOG 文件),都会消耗很多系统资源。
在笔记将记录:在 Git 中,如何管理大文件,以及常见问题解决方案。
解决方案
GitHub 开发 Git LFS 插件来管理大文件,所以我们使用 git-lfs 来管理这些大文件。
安装插件

# Ubuntu 21.04 TLS
apt-get install git-lfs

参考 Installation · git-lfs/git-lfs Wiki 文档,获取其他系统的安装方法。
简单示例

#1 You only need to run this once per user account.
git lfs install

#2
git lfs track “*.psd”
git add .gitattributes

#3
git add file.psd
git commit -m “Add design file”
git push origin main

常见问题处理
GitLab: LFS objects are missing. Ensure LFS is properly set up or try a manual “git lfs push –all”.
! [remote rejected] master -> master (pre-receive hook declined) Error: remote: GitLab: LFS objects are missing. Ensure LFS is properly set up or try a manual “git lfs push –all” · Issue #2744
问题描述:

# git push origin main
Enumerating objects: 1035, done.35), 880 MB | 0 B/s
Counting objects: 100% (1035/1035), done.
Delta compression[……]

READ MORE

「Git」- for-each-ref

git-for-each-ref,输出每个ref的信息。
命令行语法格式

git for-each-ref [–count=<count>] [–shell|–perl|–python|–tcl]
[(–sort=<key>)…] [–format=<format>] [<pattern>…]
[–points-at <object>] [(–merged | –no-merged) [<object>]]
[–contains [<object>]] [–no-contains [<object>]]

简单示例
下面的示例直接格式化输出文本来显示最近3个打标签的提交:

git for-each-ref –count=3 –sort=’-*authordate’ \
–format=’From: %(*authorname) %(*authoremail)
Subject: %(*subject)
Date: %(*authordate)
Ref: %(*refname)

%(*body)
‘ ‘refs/tags’

下面的例子显示了对输出结果使用shell eval,展示了–shell选项的使用,列出所有头的前缀:

#!/bin/sh

git for-each-ref –shell –format=”ref=%(refname)” refs/heads | \
while read entry
do
eval “$entry”
echo `dirname $ref`
done

下面的示例演示了更详细的tag报告,说明格式可能是一个完整的脚本:

#!/bin/sh

fmt=’
r=%(refname)
t=%(*objecttype)
T=${r#refs/tags/}

o=%(*objectname)
n=%(*authorname)
e=%(*authoremail)
s=%(*subject)
d=%(*authordate)
b=%(*body)

kind=Tag
if test “z$t” = z
then
# could be a lightweight tag
t=%(objecttype)
kind=”Lightweight tag”
o=%(objectna[……]

READ MORE

「Git」- rm

git-rm,从工作树和索引中删除文件;
命令行语法格式(SYNOPSIS)
git rm [-f | –force] [-n] [-r] [–cached] [–ignore-unmatch] [–quiet] [–] <file>…
命令简介(DESCRIPTION)
从索引中删除文件、或从工作树和索引中删除文件。git rm 不会值删除工作目录中的文件;
没有选项支持只能从工作树中删除文件而文件依旧保留在索引中;如果要这样做,请使用 /bin/rm。但可以工作目录的文件,而删除索引中的文件;
要删除的文件必须与分支的提示相同,并且在索引中不能对其内容进行更新,尽管可以使用-f 选项覆盖默认行为;
当给出–cached 时,暂存的内容必须与分支的尖端或磁盘上的文件相匹配,从而仅将该文件从索引中删除;
命令支持的选项及含义(OPTIONS)
<file>… 要删除的文件; 支持全局字符,比如:*.c,删除所有匹配的文件。SHELL 中某些字符需要转义,防止被 SHELL 解释; 如果指定了文件夹的名字,会删除整个目录下及递归子目录下的文件。递归删除时,需要执行-r 选项;
-f, –force 覆盖最新的检查;
-n, –dry-run 实际上不会删除任何文件。相反,只显示它们是否存在于索引中,否则将被命令删除;
-r 当给出了前导目录时,只有使用该选项才能允许递归删除;
— 此选项可用于将命令行选项从文件列表中分离(当文件名可能被误认为命令行选项时,此选项很有用);
–cached 只删除索引中的文件,而保留工作目录中的文件;
–ignore-unmatch 即使没有文件匹配,依旧返回 0 状态码;
-q, –quiet 默认删除时会显示日志信息。使用该选项,抑制输出信息;
讨论(DISCUSSION)
<file>… 可以是精确的路径名、文件 glob 模式、目录名称;
该命令仅删除 Git 已知的文件。Git 不会删除不在仓库中的文件。如果给出的文件是 Git 未知的,则 git rm 会返回:fatal: pathspec ‘./path/to/file’ did not match any files
文件通配匹配目录边界。因此,给定两个目录 d 和 d2,使用 git rm ‘d*’和 git rm ‘d/*’之间存在差异,因为前者还将删除所有目录 d2;
删除文件系统中已不存在的文件(REMOVING FILES THAT HAVE DISAPPEARED FROM THE FILESYSTEM)
git rm 不能从[……]

READ MORE

「Git」- submodule,引用其他仓库

git-submodule – Initialize, update or inspect submodules
添加子模块(增)
git – How do I add a submodule to a sub-directory? – Stack Overflow How can I specify a branch/tag when adding a Git submodule? – Stack Overflow

# 添加子模块
git submodule add “<git@github …>”

# 添加子模块到子目录
git submodule add “<repo>” “path/to/folder”

# 注意事项,-b 选项不支持指定 Tag,否则会提示:
# git submodule fatal: ‘origin/xxx’ is not a commit and a branch ‘xxx’ cannot be created from it
git submodule add -b “<branch>” “<repo>” “path/to/folder”

#######################################
## 如果需要添加特定分支,可以使用如下命令:
#######################################
git submodule add “<your repo>” path/to/folder
cd path/to/folder
git checkout v1.0.2
cd –
git add path/to/folder
git commit -m “moved submodule to v1.0.2”
git push

删除子模块(删)
How effectively delete a git submodule.
从仓库中删除子模块,有很多不同的方法,似乎没有统一的做法
或:

mv path/to/module path/to/module.backup

git submoduel deinit –force — path/to/module
rm -rf .git/modules/path/to/module
git rm –force path/to/module
# Note: path/to/module (no trailing slash)

或:

git submodule deinit “<path_to_submodule>”
git rm -f “<path_to_[……]

READ MORE

「Git」- .gitignore,忽略文件,控制需要提交的文件

问题描述
gitignore,指定有意的未跟踪的文件,并忽略;
通过 .gitignore 文件,我们能够通过那些哪些文件需要提交,哪些文件应该被忽略;
该笔记将记录:在 Git 中,如何使用 .gitignore 文件,以及常见问题的解决方法;
文件概要(SYNOPSIS)
$HOME/.config/git/ignore $GIT_DIR/info/exclude .gitignore
描述(DESCRIPTION)
在 gitignore 文件中,指定了有意未跟踪的、需要 Git 忽略的文件。已经追踪的文件不受影响。参见下面的 NOTES 部分;
在 gitignore 文件中,每一行都指定一个 Pattern。在决定是否忽略某个路径时,Git 通常会从多个地方读取 gitignore 文件,按照以下从最高到最低的顺序读取(在一个优先级中,最后一个 Pattern 决定结果):

对于支持它们的那些命令,可以从命令行读取 Pattern;
从同级目录(或者父级目录)中的.gitignore 文件中读取的 Pattern 及任何父目录中读取的 Pattern(工作树的最顶层,即项目的根目录),会一起被下层文件中的.gitignore 文件覆盖,直到到包含.gitignore 文件的目录。这些 Pattern 相对于.gitignore 文件的位置开始匹配。一个项目通常会在其存储库中包含.gitignore 文件,其中包含作为项目构建一部分生成的文件的 Pattern;
$GIT_DIR/info/exclude.
由配置变量 core.excludesFile 指定的 Pattern 读取文件;

放置 Pattern 的文件取决于 Pattern 的使用方式;
不应该版本控制和通过克隆分发到其他存储库的 Pattern,应该进入.gitignore 文件;
某个存储库特定的,而且不需要与其他相关存储库共享的 Pattern(例如,存储在存储库中,但是特定于一个用户工作流程的辅助文件)应该进入$GIT_DIR/info/exclude 文件;
用户希望 Git 在所有情况下忽略的 Pattern(例如,由编辑器生成的备份或临时文件)通常会转到由用户的~/.gitconfig 中的 core.excludesFile 指定的文件中。其默认值为$ XDG_CONFIG_HOME/git/ignore。如果$ XDG_CONFIG_HOME 未设置或为空,则使用$ HOME/.config/git/ignore;
底层的 Git 管道工具(如 git ls-files 和 git read-tree)读取由命令行选项指定的[……]

READ MORE

「Git」- 常用工具

# 在多个仓库同时执行Git命令

###########################################################
# git-mult-exec.sh
###########################################################
#!/bin/bash

###########################################################
# 在多个Git仓库同时执行相同的命令嗯
# @author wangpengfei
# @date Wed Aug 16 08:55:42 CST 2017
# @version 0.0.1
#
# 已知BUG:
# 1). 该脚本暂时不支持批量clone,执行前仓库必须使已经存在的
# 2). 由于使并行处理,仓库操作时需要输入密码时,会出现问题
# 3). SHELL中的通配符需要转义
#
###########################################################

tmp=/tmp/gitforest.$$
rm -rf ${tmp}
mkdir -p ${tmp}

trap ‘rm -rf ${tmp}’ EXIT
trap ‘rm -rf ${tmp}’ KILL

###########################################################
# 获取所有的仓库
###########################################################

repo_perhaps=$(/bin/ls -d ./.git ./*/.git ./*/*/.git ./*/*/*/.git ./*/*/*/*/.git 2>/dev/null)
echo ‘———————‘

repo_dir=””
for item in ${repo_perhaps}
do
repo_dir=”${repo_dir} $(dirname ${item})”
done

###########################################################
# 检查是否有仓库需要处理
###########################################################

if [ “{$repo}” = “” ]
then
echo “Idiot! No repo to process.”
exit
fi

#######################[……]

READ MORE

「Git」- 文件权限、所有者

在检出时,保持原文件的所属用户及组
Is there a way to trigger a hook after a new branch has been checked out in Git?
在 git checkout 时,如果分支里的文件和硬盘中的文件不同,git会创建新文件,并且新文件的用户和组为当前用户及其组。
现象如下:

# ll Config.php
-rwxr-xr-x 1 www www 2165 Feb 26 17:45 Config.php*

# git checkout master
Switched to branch ‘master’
Your branch is behind ‘origin/master’ by 11 commits, and can be fast-forwarded.
(use “git pull” to update your local branch)

# ll Config.php
-rw-r–r– 1 root root 2162 Feb 26 17:45 Config.php

原文件的用户及组为www:www,我使用的root用户检出后成为了root:root。这就比较麻烦了,比如用Samba共享之后,由于Samba的匿名用户为默认的www,而checkout出的文件为root:root,这会导致访问Samba的用户无法保存该文件。
当然可以每次手动执行chown www:www . -R,但这不程序。
方法一、使用 git hook
在本地仓库的 .git/hooks 下创建 post-checkout 文件,文件的内容如下:

#!/bin/sh
chown www:www . -R

并赋予执行权限:chmod u+x post-checkout
如果是执行git pull(等价于git fetch; git merge操作)操作,需要创建post-update文件,文件内容与post-checkout相同。
方法二、使用www账户
即使用 www 账户来执行 git 相关操作。
忽略文件权限的变化
How do I make Git ignore file mode (chmod) changes? – Stack Overflow
问题描述: 当文件权限发生变化后,Git 也会将其视为变化。当这些文件被两个文件系统工具共享时,文件权限经常被工具改变,我们希望 Git 能够忽略这种变化,
解决方案:

git config core.fileMode false

注意事项: 1)这种方式并非最佳实践,仅作为某[……]

READ MORE

「Git」- 提交空目录

问题描述
在我们项目中,存在数据目录,在程序运行之前,这些目录为空目录。当提交到 Git 仓库时,这些空目录会被忽略。
但是,我们希望保存这些空目录,以体现项目目录结构。
该笔记将记录:在 git 中,如何保留空目录。
解决方案
在空目录中创建 .gitignore 文件,并填入如下内容:

# Ignore everything in this directory
*
# Except this file
!.gitignore

或者,在空目录中创建 .placeholder 文件,在根目录的 .gitignore 填入如下内容:

# Ignore everything in this directory
data/*
# Except this file
!.placeholder

# 如果是多级的子目录,使用
**/data/*

参考文献
How can I add an empty directory to a Git repository? – Stack Overflow[……]

READ MORE

「Git」- 仓库代码统计

问题描述
在绩效考核中,某项指标名为「千行代码BUG数」,即根据“总BUG数”与“代码行数”来计算“千行代码BUG数”。因此需要计算代码总行数。
本文将整理用于计算代码行数的工具。
# 使用GitStats工具
-「git代码统计工具git_stats」 -「GitHub/tomgi/git_stats」
这是我们目前正在使用的工具。
# 使用Gitinspector工具
https://github.com/ejwa/gitinspector
# 使用git-stats工具
https://github.com/IonicaBizau/git-stats
# 在GitLab中统计
「Count lines added by a developer」 「Commits API」
# 统计代码提交行数
「How can I calculate the number of lines changed between two commits in git?」 「How to count total lines changed by a specific author in a Git repository?」 git log –author=”<authorname>” –pretty=tformat: –numstat[……]

READ MORE