git指南¶
前言¶
关于版本控制¶
版本控制(version control
),或称为修订控制(revision control
)、源控制(source control
),其作用是保存源代码、配置文件和工程文件的修改历史,保证开发人员能够定位错误、回滚版本
大致经历3
个阶段:
- 保存副本
- 集中式修订控制(
centralized revision control
) - 分布式修订控制(
distributed revision control
)
最简单的版本控制方式就是备份每次修改后的文件,优点在于操作简单,缺点在于占用存储大,在大文件情况下非常耗时,也不利于多人同时开发
第二和第三种方式都是通过保存文件修改记录来进行版本控制
第二种是集中式修订控制,即设立服务器来保存源代码和所有人修改的记录,上传和回滚版本通过服务器进行
优点在于这样可以保证占用的存储大大减小,同时仅需上传和下载修改记录就能够进行版本上传和更新,减小操作时间,并且能够有效协调地理隔离下的多人开发;管理员能控制开发人员权限
缺点在于仅在中央服务器保存了所有的修改记录,一旦损坏无法修复; 无法在同一版本库中同时进行多方向开发
第三种是分布式修订控制,同一个开发库可以进行多分支开发,客户端也保存了所有分支的修改记录
优点:多分支开发;相比于集中式修订控制,仅需在拉取其他开发人员的变更和自己的提交记录时需要连接服务器,所以一些常用操作更加快捷,比如提交记录,浏览历史和回退操作
缺点:增加了客户端开发库的体积;操作较复杂
使用集中式修订控制方式的版本控制系统:svn
使用分布式修订控制方式的版本控制系统:git
基础操作¶
帮助¶
获取命令参数¶
输入命令直接回车即可
zj@zj-ThinkPad-T470p:~$ git config
usage: git config [<options>]
Config file location
--global use global config file
--system use system config file
--local use repository config file
-f, --file <file> use given config file
--blob <blob-id> read config from given blob object
Action
--get get value: name [value-regex]
--get-all get all values: key [value-regex]
--get-regexp get values for regexp: name-regex [value-regex]
--get-urlmatch get value specific for the URL: section[.var] URL
--replace-all replace all matching variables: name value [value_regex]
--add add a new variable: name value
--unset remove a variable: name [value-regex]
--unset-all remove all matches: name [value-regex]
--rename-section rename section: old-name new-name
--remove-section remove a section: name
-l, --list list all
-e, --edit open an editor
--get-color find the color configured: slot [default]
--get-colorbool find the color setting: slot [stdout-is-tty]
Type
--bool value is "true" or "false"
--int value is decimal number
--bool-or-int value is --bool or --int
--path value is a path (file or directory name)
Other
-z, --null terminate values with NUL byte
--name-only show variable names only
--includes respect include directives on lookup
获取使用手册¶
git
包含了许多命令,可以通过命令查找使用手册
git help command-name
# 或
git command-name --help
# 或
man git-<command-name>
比如配置环境变量git config
,获取其使用手册
git help config
# 或
git config --help
# 或
man git-config
git配置¶
命令行操作范围¶
使用命令git config
进行配置,各级别设置需要加上可选参数
# 系统级别
git config --system ...
# 全局级别
git config --global ...
# 仓库级别
git config --local ...
打印配置信息¶
# 打印所有信息
$ git config --list
user.email=505169307@qq.com
user.name=zhujian
core.editor=code
# 打印全局信息
$ git config --global --list
user.email=505169307@qq.com
user.name=zhujian
core.editor=code
常用设置¶
- 设置用户信息
- 设置文本编辑器
- 移除变量
设置用户信息¶
每次提交时都需加上用户名和邮箱地址,可以设置成全局变量
git config --global user.name user-name
git config --global user.email email-address
设置节点为user
,设置属性为name
和email
设置文本编辑器¶
git
使用系统默认的编辑器,可以设置指定编辑器
# 未设置
git config --global core.editor vim
# 已设置,先删除再添加
git config --global --unset core.editor
git config --global core.editor vim
移除变量¶
# 移除单个变量
git config --global --unset 属性名
# 移除所有变量
git config --global --unset-all 属性名
配置文件地址¶
git
有3
个级别的配置文件:
local
:本地文件存放在仓库中(.git/config
),只针对当前仓库global
:全局文件存放为~/.gitconfig
或~/.config/git/config
,作用于当前用户的所有仓库system
:系统文件存放为/etc/gitconfig
,作用于系统的每个用户
其优先级为local > global > system
windows
环境下的全局配置文件存放为C:\\User\\$USER\\.gitconfig
编写格式¶
所有配置文件的编写格式都一样,可参考仓库级别的config
文件,按照section和key进行配置
# 仓库级别
$ cat config
[core]
repositoryformatversion = 0
filemode = true
bare = false
logallrefupdates = true
[remote "origin"]
url = git@github.com:zjZSTU/linux-guide.git
fetch = +refs/heads/*:refs/remotes/origin/*
[branch "master"]
remote = origin
merge = refs/heads/master
# 全局级别
$ cat .gitconfig
[user]
name = zxxx
email = 50xxxxx.com
获取git仓库¶
远程拉取¶
从远程服务器(github/gitee等)获取地址后拉取到本地
git clone <repo> [<dir>]
<repo>
表示输入地址
git clone https://github.com/zjZSTU/git-guide.git
也可制定路径
git clone https://github.com/zjZSTU/git-guide.git ../git-repo/
或文件夹
git clone https://github.com/zjZSTU/git-guide.git guide
下载并绑定指定分支
git clone --branch [标签名/分支名] [git地址]
提交新版本¶
在本地创建git仓库后,就可以对文件进行版本控制.文件分为2种状态:已追踪(tracked)和未追踪(untracked)
未追踪(untracked)文件就是未添加到版本控制的文件
已追踪的文件可分为已修改(modified),已暂存(staged)和未修改(unmodified)文件
基本的git工作流程如下:
- 在工作目录下添加文件,修改文件或删除文件
- 保存文件状态到暂存区域
- 提交修改记录到仓库
查看文件状态¶
使用命令git status查看文件状态,同时会给出相应文件状态下的命令
$ git status
On branch master
Your branch is up-to-date with 'origin/master'.
nothing to commit, working directory clean
$ 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: docs/source/index.rst
Untracked files:
(use "git add <file>..." to include in what will be committed)
.vscode/
docs/source/git/
no changes added to commit (use "git add" and/or "git commit -a")
仅需查看文件状态
$ git status -s
A .vscode/settings.json
M docs/source/index.rst
?? docs/source/git/
符号A
表示已暂存,符号M
表示已修改,符号??
表示未追踪
其中已修改文件有如下3种状态
$ git status -s
M README
MM Rakefile
M lib/simplegit.rb
符号_M
表示已修改还未加入暂存区域,符号MM
表示已加入暂存区域的已修改文件又被修改了,符号M_
表示添加到暂存区域的已修改文件
添加修改文件¶
使用命令git add将未追踪文件或已修改文件添加到暂存区域
git add name1 name2 ...
# 添加所有文件
git add *
忽略文件¶
编辑.gitignore文件,将整个工程文件中不想添加版本控制的文件加入进去
所有空行或者以 # 开头的行都会被 Git 忽略。
可以使用标准的 glob 模式匹配。
匹配模式可以以(/)开头防止递归。
匹配模式可以以(/)结尾指定目录。
要忽略指定模式以外的文件或目录,可以在模式前加上惊叹号(!)取反。
可参考github/gitignore,上面包含了很多不同开发环境下的.gitignore文件
如果git add添加了忽略文件会报错,可以使用-f强制添加
git add -f name1 name2 ...
标签设置¶
git
在log
设置的基础上添加了标签设置,其目的是标识重要的提交记录(比如标识发布版本)
下面以opencv版本库为例
标签分类¶
标签分为两种
- 注解标签(
annotated tag
) - 命名标签(
named tag
)
注解标签用于版本管理,命名标签用于私有或者临时标注
注解标签包含创建日期、标签名、e-mail
、标签信息和可选的GPG
签名
命名标签仅包含标签名,所以称为轻量级标签(lightweight tag
)
创建标签¶
常用参数如下:
-a, --annotate
:生成一个未签名的注解标签对象-s, --sign
:生成一个GPG签名的标签,使用默认e-mail
地址作为键-u <keyid>, --local-user=<keyid>
:生成一个GPG
签名的标签,使用给定的键-m <msg>, --message=<msg>
:添加标签消息-F <file>, --file=<file>
:带有标签消息的文件
注解标签¶
使用上述参数-a
/-s
/-u
生成的标签称.git/refs/tags标签,注解标签必须添加消息,可以使用参数-m
或者-F
,否则会打开一个编辑器
$ git tag -a v1.1 -m "添加一个注解标签"
给过去提交记录创建标签¶
默认给当前记录创建标签,还可以给过去记录创建标签
查看记录
$ git log --pretty=oneline
9e1b1e5389237c2b9f6c7b9d7715d9836c0a5de1 OpenCV 3.4.2
a0baae8a559d31c22ae08976b41cc99e046ba52b Merge pull request #11875 from dkurt:dnn_fix_reshape
9a66331984c5b0f0a71d6208a8237fc410ae923e Merge pull request #11882 from alalek:videoio_vfw_lower_priority
...
...
打标签时指定提交签名(头几位就行了)
$ git tag v0.3 0660c1108f969a -a -m "给过去提交记录打标签"
查看标签¶
查看所有标签
$ git tag
2.2
...
...
4.0.1
4.0.1-openvino
查看指定系列标签,使用参数-l
# 列出4.x版本
$ git tag -l 4.*
4.0.0
4.0.0-alpha
4.0.0-beta
4.0.0-openvino
4.0.0-rc
4.0.1
4.0.1-openvino
查看某一标签信息
$ git show 标签名
# 对于注解标签而言
$ git show 4.0.0
tag 4.0.0 # 标签名
Tagger: Alexander Alekhin <alexander.a.alekhin@gmail.com> # 标签者
Date: Sun Nov 18 09:19:48 2018 +0000 # 标签日期
OpenCV 4.0.0 # 标签信息
...
...
# 对于命名标签而言
$ git show v1.1 # 仅显示提交记录
commit a92571f31ddc7ea959b99e129f6c4705a404c36b
Author: zhujian <505169307@qq.com>
Date: Thu Feb 28 20:37:01 2019 +0800
共享标签¶
github
利用标签进行github release
的发布
但是默认情况下不会传输标签到远程托管服务器,需要单独显式推送
$ git push origin v1.0
# 或者全部推送
$ git push origin --tags
文件解析¶
创建的标签在.git/refs/tags
文件夹下
删除标签¶
子模块¶
开发个人网站的过程中需要用到主题仓库,所以会在一个仓库的里面嵌套另一个仓库,如果直接将子仓库加入版本管理,很多文件无法进行版本化,所以想到了子模块的操作
创建子模块¶
使用git submodule
命令添加子模块
$ git submodule add git@github.com:zjZSTU/hexo-theme-next.git blogs/themes/next
Cloning into 'blogs/themes/next'...
remote: Enumerating objects: 1, done.
remote: Counting objects: 100% (1/1), done.
remote: Total 5402 (delta 0), reused 0 (delta 0), pack-reused 5401
Receiving objects: 100% (5402/5402), 5.29 MiB | 1.03 MiB/s, done.
Resolving deltas: 100% (3294/3294), done.
Checking connectivity... done.
除了添加子仓库之外,还生成了一个配置文件.gitmodules
$ git status
On branch dev
Your branch is ahead of 'origin/dev' by 1 commit.
(use "git push" to publish your local commits)
Changes to be committed:
(use "git reset HEAD <file>..." to unstage)
new file: .gitmodules
new file: blogs/themes/next
.gitmodules
里面保存了子模块的地址和远程仓库链接
$ cat .gitmodules
[submodule "blogs/themes/next"]
path = blogs/themes/next
url = git@github.com:zjZSTU/hexo-theme-next.git
管理子模块¶
主仓库只能提示子模块中的文件修改,必须子模块自己进行添加和上传
比如在next
文件夹内新建文件hellogit
# 对于主模块而言
$ git status
On branch dev
Your branch is up-to-date with 'origin/dev'.
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)
(commit or discard the untracked or modified content in submodules)
modified: next (untracked content)
no changes added to commit (use "git add" and/or "git commit -a")
# 对于子模块而言
$ git status
HEAD detached at 0c5ed6f
Untracked files:
(use "git add <file>..." to include in what will be committed)
hellogit
nothing added to commit but untracked files present (use "git add" to track)
克隆子模块¶
克隆主仓库后子模块的文件夹在但是没有文件,还需要进一步克隆子仓库
# 初始化本地配置文件
$ git submodule init
# 拉取远程仓库
$ git submodule update
集成代码如下:
$ git submodule update --init --recursive
更新子模块¶
如果子模块有更新,可以进入子模块路径进行更新
$ git pull
或者在主仓库更新所有子模块
$ git submodule foreach git pull
可能会遇到如下错误:
Entering 'blogs/themes/next'
You are not currently on a branch.
Please specify which branch you want to merge with.
See git-pull(1) for details.
git pull <remote> <branch>
Stopping at 'blogs/themes/next'; script returned non-zero status.
The command "git submodule foreach git pull" failed and exited with 1 during .
需要指定哪个分支,要么修改更新语句如下:
$ git submodule foreach git pull origin master
要么设置远程关联分支
$ git branch --set-upstream-to=origin/remote_branch your_branch
# 或
git branch --set-upstream your_branch origin/remote_branch
忽略子模块¶
当在子模块执行完成修改提交后,在主模块仍会显示子模块待提交
$ git status
On branch dev
Your branch is up-to-date with 'origin/dev'.
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: blogs/themes/next (new commits)
需要修改.gitmodule
的ignore
属性,用于定义何种情况下使用git status
或者diff
命令会显示子模块的修改状况
有4
个可选的属性值
all
:子模块永远不会被认为是已修改的(但是当它处于暂存阶段时仍旧会在状态和提交命令的输出中)dirty
:子模块工作树上的所有改变都会被忽略,只考虑子模块的HEAD
与其在父项目中记录的状态之间的差异untracked
:仅仅子模块未追踪的文件会被忽略。对于已追踪文件的提交差异和修改会显示none
:默认选项。不会忽略所有对于子模块的修改,会显示所有的对于提交差异以及对于已追踪或未追踪的文件修改
所以设置属性ignore
为all
就能忽略子模块变化
[submodule "blogs/themes/next"]
path = blogs/themes/next
url = https://github.com/zjZSTU/hexo-theme-next.git
ignore = all
[github][gitee]SSH公钥设置¶
[github]公钥设置¶
参考:Adding a new SSH key to your GitHub account
登录github
,进入个人主页,选择Settings->SSH and GPG keys->New SSH key
填写title
,并复制个人主机中的公钥到key
$ cat github_id_rsa.pub
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQDIUsnRNu/+Zeurm2Ty/Xac+q+0y87aHWr0N7fb+gygQK7xRux9UAI7UK3GwP7dwxYT8KTOrxf0tPnI4d/bCtETHcoj0D2UlwMO20FWFaoOocteccJLbmQ9XXsrt05KlJcDGr9L8e9eMyWKj5ZXMOxSwravv+e64XGkFaAmNX4XkCkENlZcIq6w+Fo/xtyPZA0W/oYnBWAvKd937GbKEA1m1rARzo/xGCn8uf76PUlNy2UscujnWbMUYGeLxf5jRCgWD0KZLJsJAsOCxczeRn0EAczgNcgyBbjotDnpTKbP6Xtqvf3TtVty9fgQgs7/oLNb8K+v0XVVR9XsX+DZkqF+JCzIOf+0dpnJiery187rw4MuRIlct+vGM1P+FaiPphh2vMhe5YEaFErrHNTDZiw+LbHCE3Eo9wK9t0wb/yFiHELempoZI+K3Zjv6cnUnl3urXQFHV/RJCj/JHOEA1Q3jvVLa3nETRMfBBEiDuK0YPH6OUac+GSg+ldCVwDydeCa2Z4/OdgZqsoyTU5o4vewbT3vKwmQGfu7BNOmHgnIzMZQsg0JWScDX9/c/DoCaGW95ej68niZ3ICtUWnlYKZVlzg+cyIRzuzSmaa5ecOgzxZ6moW4wRGrvMM94X0HMmWWXXV/WLXiUG2KN1upz7m78zwJ6ZXvh2sWmCe+q+YhJIw== github.com
github
上设置的公钥同时具备推送/拉取
的权限
测试¶
参考:Testing your SSH connection
在github
上设置好公钥之后
SSH
zj-github
d9:fc:d8:02:ee:6c:75:68:a1xxx Added on Feb 4, 2019 Last used within the last week — Read/write
在本地测试是否成功
$ ssh -T git@github.com
Hi zjZSTU! You've successfully authenticated, but GitHub does not provide shell access.
$ ssh -T git@gitee.com
Hi zjZSTU! You've successfully authenticated, but GITEE.COM does not provide shell access.
下载代码¶
选择仓库,以ssh
协议下载
$ git clone git@github.com:zjZSTU/git-guide.git
这一次会要求你输入设置好的密码(passphrase
),之后的拉取代码操作都可以自动认证完成
[ssh][http]传输方式切换¶
通过修改本地文件,切换代码传输方式
命令修改¶
查看当前使用SSH
还是HTTP
$ git remote -v
origin git@gitee.com:zjZSTU/zjzstu.gitee.io.git (fetch)
origin git@gitee.com:zjZSTU/zjzstu.gitee.io.git (push)
当前使用SSH
协议进行代码拉取和推送
方式一:仅修改拉取协议为HTTP
$ git remote set-url --push origin https://gitee.com/zjZSTU/zjzstu.gitee.io.git
$ git remote -v
origin git@gitee.com:zjZSTU/zjzstu.gitee.io.git (fetch)
origin https://gitee.com/zjZSTU/zjzstu.gitee.io.git (push)
方式二:同时修改拉取和推送协议为HTTP
# 先增加HTTP
$ git remote set-url --add origin https://gitee.com/zjZSTU/zjzstu.gitee.io.git
$ git remote -v
origin git@gitee.com:zjZSTU/zjzstu.gitee.io.git (fetch)
origin https://gitee.com/zjZSTU/zjzstu.gitee.io.git (push)
# 再删除SSH
$ git remote set-url --delete origin git@gitee.com:zjZSTU/zjzstu.gitee.io.git
$ git remote -v
origin https://gitee.com/zjZSTU/zjzstu.gitee.io.git (fetch)
origin https://gitee.com/zjZSTU/zjzstu.gitee.io.git (push)
文件修改¶
修改文件.git/config
的remote
小节
[core]
repositoryformatversion = 0
filemode = true
bare = false
logallrefupdates = true
[remote "origin"]
fetch = +refs/heads/*:refs/remotes/origin/*
url = git@gitee.com:zjZSTU/zjzstu.gitee.io.git
[branch "master"]
remote = origin
merge = refs/heads/master
[branch "dev"]
remote = origin
merge = refs/heads/dev
方式一:仅修改拉取协议为HTTP
添加pushurl = ...
到remote
小节
...
[remote "origin"]
fetch = +refs/heads/*:refs/remotes/origin/*
url = git@gitee.com:zjZSTU/zjzstu.gitee.io.git
pushurl = https://gitee.com/zjZSTU/zjzstu.gitee.io.git
[branch "master"]
...
方式二:同时修改拉取和推送协议为HTTP
修改url
为HTTP
即可
...
[remote "origin"]
fetch = +refs/heads/*:refs/remotes/origin/*
url = https://gitee.com/zjZSTU/zjzstu.gitee.io.git
...
进阶操作¶
工作目录和裸仓库分离¶
参考:
GIT_DIR和GIT_WORK_TREE的妙用,工作区和仓储可隔离
裸仓库指.git
文件夹,工作目录指除.git
文件夹外的其他文件
使用场景之一如下:
- 本地将修改好的代码上传到远程裸仓库
- 裸仓库获取到代码后,通过钩子生成工作目录,放置在其他路径下
- 服务器再对工作目录进行操作,比如
nginx
对静态文件进行托管
在.git/hooks
文件夹下新建post-receive
文件
$ vim post-receive
添加如下内容
#!/bin/sh
git --work-tree=工作目录 --git-dir=裸仓库 checkout -f
授予执行权限
$ sudo chmod +x post-receive
自建服务器¶
参考:
在云服务器上自建git
服务器,最简单的方式就是创建裸仓库然后用ssh
的方式进行代码的拉取和推送,参考创建裸仓库
下面实现一个规范的git
服务器,类似第三方服务器(github、coding、gitlab
等),其支持ssh
和http
协议的仓库操作,但不允许进行远程登录
第三方仓库名如下:
https://<domain-name>/<user-name>/<repo-name>.git
git@<domain-name>:<user-name>/<repo-name>.git
操作步骤如下:
- 创建用户
git
ssh
设置- 下载仓库
创建用户git
¶
$ sudo adduser git
正在添加用户"git"...
正在添加新组"git" (1000)...
正在添加新用户"git" (1000) 到组"git"...
创建主目录"/home/git"...
正在从"/etc/skel"复制文件...
输入新的 UNIX 密码:
重新输入新的 UNIX 密码:
passwd: password updated successfully
Changing the user information for git
Enter the new value, or press ENTER for the default
Full Name []:
Room Number []:
Work Phone []:
Home Phone []:
Other []:
这些信息是否正确? [Y/n]
在/data
目录下创建目录repositories
,然后在里面创建一个裸仓库
# 创建目录
$ sudo mkdir -p /data/repositories
# 设置用户和组
$ sudo chown -R git:git /data/repositories
# 设置可访问权限
$ sudo chmod 755 /data/repositories/
# 创建裸仓库
$ git init --bare hello.git
Initialized empty Git repository in /data/repositories/hello.git/
perl: warning: Falling back to a fallback locale ("en_US.utf8").
¶
$ sudo adduser zhujian
perl: warning: Setting locale failed.
perl: warning: Please check that your locale settings:
LANGUAGE = (unset),
LC_ALL = (unset),
LC_MEASUREMENT = "zh_CN.UTF-8",
LC_PAPER = "zh_CN.UTF-8",
LC_MONETARY = "zh_CN.UTF-8",
LC_NAME = "zh_CN.UTF-8",
LC_ADDRESS = "zh_CN.UTF-8",
LC_NUMERIC = "zh_CN.UTF-8",
LC_TELEPHONE = "zh_CN.UTF-8",
LC_IDENTIFICATION = "zh_CN.UTF-8",
LC_TIME = "zh_CN.UTF-8",
LANG = "en_US.utf8"
are supported and installed on your system.
perl: warning: Falling back to a fallback locale ("en_US.utf8").
Adding user `zhujian'ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC+VVpw5kOZBmzJYz/vngYpAAV61Fq9oChSflQFkfzr1sKHRqq2/sqeZD3gzPQZbrKWcHbuGCWyQOvm1gH+67gW+TpUO9DWeeHqo3h5rlCW+ElJcL/q4b+ZBVEmGDjzE+Sg+6wM+izBl5xzHDFeLhN3Yw1OVc2rwQFQ/CD6FSKdL4b5bt0/5rpu65sv7haXjfDMSEsIVgPY5behLzZzoXy81iN4/tPF3cjDsn/x5Yywc60LdslJ5hW5wlozhq1LibUXk9JQu/+5DDZKi8ytMEoe1S7yROvaC/ofJQR22hINnFoLNBC8gSFM2YR+t9oBF0eiAaVwfgddA0+ScYrWA5Yr zj@zj-ThinkPad-T470p ...
Adding new group `zhujian' (1000) ...
Adding new user `zhujian' (1000) with group `zhujian' ...
Creating home directory `/home/zhujian' ...
...
...
提示语言包问题,参考perl: warning: Falling back to a fallback locale (“en_US.UTF-8”)
$ sudo apt install locales-all
git is not in the sudoers file. This incident will be reported.
¶
是因为git
没有添加到sudo
权限,参考xxx is not in the sudoers file.This incident will be reported.的解决方法
先切换到
ubuntu
用户$ su ubuntu
赋予
sudo
文件写权限$ sudo chmod u+w /etc/sudoers
修改文件
/etc/sudoers
$ sudo vim /etc/sudoers # 添加 youuser ALL=(ALL) ALL
表示允许用户
youuser
执行sudo
命令(需要输入密码)撤销
sudo
文件写权限$ sudo chmod u-w /etc/sudoers
重新切换回原来用户
$ su git
设置ssh
连接¶
将客户端的ssh
公钥添加到用户git
的.ssh/authorized_keys
文件中,即可实现ssh
连接
$ mkdir .ssh && chmod 700 .ssh
$ touch .ssh/authorized_keys && chmod 600 .ssh/authorized_keys
设置git-shell
连接¶
设置用户git
仅能操作git
相关内容,可以将用户git
的登录shell
设置为git-shell
#查看用户git登录shell
$ cat /etc/passwd | grep git
git:x:1000:1000:,,,:/home/git:/bin/bash
修改为git-shell
# 查找
$ which git-shell
/usr/bin/git-shell
# 修改
$ sudo vim /etc/passwd
# 修改后
$ cat /etc/passwd | grep git
git:x:1000:1000:,,,:/home/git:/usr/bin/git-shell
publickey denied
¶
ssh
连接失败,这个问题很迷,耗了1
天时间,网上找了很多资料没有结果,有一个博客主也遇到了同样的问题,他最后解决是因为突然就可以了,我也一样
下载仓库¶
下载仓库hello.git
到本地
$ git clone git@132.232.142.219:/data/repositories/hello.git
Cloning into 'hello'...
warning: You appear to have cloned an empty repository.
Checking connectivity... done.
$ cd hello/
$ ls -al
total 12
drwxrwxr-x 3 zj zj 4096 3月 9 16:29 .
drwxr-xr-x 4 zj zj 4096 3月 9 16:29 ..
drwxrwxr-x 7 zj zj 4096 3月 9 16:29 .git
添加文件hello.txt
,加入版本管理并上传
$ touch hello.txt
$ ls
hello.txt
$ git add hello.txt
$ git commit -m "hello git"
[master (root-commit) 24265ed] hello git
1 file changed, 0 insertions(+), 0 deletions(-)
create mode 100644 hello.txt
$ git push -u origin master
Counting objects: 3, done.
Writing objects: 100% (3/3), 207 bytes | 0 bytes/s, done.
Total 3 (delta 0), reused 0 (delta 0)
To git@132.232.142.219:/data/repositories/hello.git
* [new branch] master -> master
Branch master set up to track remote branch master from origin.
配置config
¶
使用config
文件可以简易仓库下载地址,在本地~/.ssh
文件夹下新建配置文件config
,添加如下
$ cat config
host git-server
user server
hostname 132.232.142.219
port 22
identityfile ~/.ssh/tencent_id_rsa
# 设置访问权限
$ sudo chmod 600 config
注意:用tab
键保持文档格式
config
文件指定了主机名git-server
配置的用户名、ip
地址、端口号和私钥地址
添加配置文件后下载仓库地址如下
$ git clone git-server:/data/repositories/hello.git
Cloning into 'hello'...
remote: Counting objects: 3, done.
Receiving objects: 100% (3/3), done.
remote: Total 3 (delta 0), reused 0 (delta 0)
Checking connectivity... done.
推送到多个远程托管服务器¶
参考:Git - Pushing code to two remotes [duplicate]
将代码推送到多个远程托管服务器,多重备份保证安全性,比如推送到github
和coding
有两种情况
- 同时推送代码到多个仓库
- 指定推送的地址,比如本次操作仅推送到
github
,不推送到coding
首先查看当前已追踪的远程仓库地址
$ git remote -v
origin https://git.dev.tencent.com/zjZSTU/TEST.git (fetch)
origin https://git.dev.tencent.com/zjZSTU/TEST.git (push)
当前已追踪了coding
服务器上的仓库,需要加入github
仓库
针对多个远程仓库的推送,使用SSH
传输协议可以提高操作便捷性
同时推送¶
命令行操作¶
添加github
仓库地址
$ git remote set-url --add --push origin https://github.com/zjZSTU/TEST.git
$ git remote -v
origin https://git.dev.tencent.com/zjZSTU/TEST.git (fetch)
origin https://github.com/zjZSTU/TEST.git (push)
再重新添加coding
的仓库地址
$ git remote set-url --add --push origin https://git.dev.tencent.com/zjZSTU/TEST.git
$ git remote -v
origin https://git.dev.tencent.com/zjZSTU/TEST.git (fetch)
origin https://github.com/zjZSTU/TEST.git (push)
origin https://git.dev.tencent.com/zjZSTU/TEST.git (push)
这样就可以同时推送到多个远程仓库
$ git push -u origin master
Username for 'https://github.com': zjZSTU
Password for 'https://zjZSTU@github.com':
...
...
To https://github.com/zjZSTU/TEST.git
d19a01e..4b76b5d master -> master
Branch master set up to track remote branch master from origin.
Username for 'https://git.dev.tencent.com': zjZSTU
Password for 'https://zjZSTU@git.dev.tencent.com':
...
...
To https://git.dev.tencent.com/zjZSTU/TEST.git
d19a01e..4b76b5d master -> master
Branch master set up to track remote branch master from origin.
文件操作¶
修改.git
文件夹下的CONFIG
文件
# 原先
[remote "origin"]
fetch = +refs/heads/*:refs/remotes/origin/*
url = https://git.dev.tencent.com/zjZSTU/TEST.git
# 修改为
[remote "origin"]
fetch = +refs/heads/*:refs/remotes/origin/*
url = https://git.dev.tencent.com/zjZSTU/TEST.git
pushurl = https://github.com/zjZSTU/TEST.git
pushurl = https://git.dev.tencent.com/zjZSTU/TEST.git
在origin
小节中添加属性pushurl
,设置多个远程仓库地址
指定推送¶
指定推送操作和同时推送操作能够同时并存在同一个仓库中
默认情况下使用origin
作为远程仓库名,可以添加另外的名字,在旗下指定新的远程仓库
当前操作如下:默认origin
指向coding
,添加github
指向github
仓库,添加all
指向github
和coding
命令行操作¶
添加github
远程
$ git remote add github https://github.com/zjZSTU/TEST.git
$ git remote -v
github https://github.com/zjZSTU/TEST.git (fetch)
github https://github.com/zjZSTU/TEST.git (push)
origin https://git.dev.tencent.com/zjZSTU/TEST.git (fetch)
origin https://git.dev.tencent.com/zjZSTU/TEST.git (push)
添加all
远程
$ git remote add all https://github.com/zjZSTU/TEST.git
$ git remote set-url --add --push all https://git.dev.tencent.com/zjZSTU/TEST.git
$ git remote set-url --add --push all https://github.com/zjZSTU/TEST.git
$ git remote -v
all https://github.com/zjZSTU/TEST.git (fetch)
all https://git.dev.tencent.com/zjZSTU/TEST.git (push)
all https://github.com/zjZSTU/TEST.git (push)
github https://github.com/zjZSTU/TEST.git (fetch)
github https://github.com/zjZSTU/TEST.git (push)
origin https://git.dev.tencent.com/zjZSTU/TEST.git (fetch)
origin https://git.dev.tencent.com/zjZSTU/TEST.git (push)
上传代码
# 上传到coding
git push -u origin master
# 上传到github
git push -u github master
# 同时上传
git push -u all master
文件操作¶
修改.git
文件夹下的CONFIG
文件,添加github
和all
小节
[remote "github"]
url = https://github.com/zjZSTU/TEST.git
fetch = +refs/heads/*:refs/remotes/github/*
[remote "all"]
url = https://github.com/zjZSTU/TEST.git
fetch = +refs/heads/*:refs/remotes/all/*
pushurl = https://git.dev.tencent.com/zjZSTU/TEST.git
pushurl = https://github.com/zjZSTU/TEST.git
创建裸仓库¶
参考:4.2 服务器上的 Git - 在服务器上搭建 Git
裸仓库,也就是不包含当前工作目录的仓库,即.git
文件夹,可作为服务器git
仓库
有两种方式,一是使用本地已存在的仓库,二是新建远程裸仓库
本地导出¶
从已有仓库中导出.git
文件夹,有两种方式
使用
git
命令git clone --bare my_project my_project.git $ git clone --bare TEST TEST.git Cloning into bare repository 'TEST.git'... done.
使用
cp
命令cp -rf my_project/.git my_project.git
放置在远程服务器¶
在服务器上新建文件夹git
$ pwd
/home/ubuntu/git
复制本地裸仓库到服务器
$ scp -r TEST.git ubuntu@132.232.142.219:/home/ubuntu/git/TEST.git
这样在git
文件夹下就有了裸仓库TEST.git
$ pwd
/home/ubuntu/git/TEST.git
远程新建¶
在远程服务器新建文件夹,并在其中初始化为裸仓库
$ mkdir TE.git
$ cd TE.git
$ git init --bare
Initialized empty Git repository in /home/ubuntu/git/TE.git/
# 如果想要同一组内的其他用户也可访问该仓库,添加参数--shared来修改仓库权限
$ git init --bare --shared
Initialized empty shared Git repository in /home/ubuntu/git/TE.git/
本地分支操作¶
参考:
主要学习内容:
- 分支显示、创建和切换
- 分支暂存
- 分支删除
- 分支合并
使用命令
分支显示、创建和切换¶
显示所有分支以及当前所处分支
$ git branch
创建新分支testing
$ git branch testing
切换到新分支testing
$ git checkout testing
创建新分支aa
并自动切换
$ git checkout -b aa
分支暂存¶
在切换分支之前最好先保存当前在暂存区域的内容,使用git stash
命令将其保存在一个脏目录中
暂存当前工作状态
$ git stash
可进行多次暂存操作,查看暂存列表
$ git stash list
重新释放最新的暂存内容
$ git stash apply
指定暂存节点进行释放
$ git stash apply 节点名
清除所有的暂存节点
$ git stash clear
分支合并¶
合并指定分支到当前分支
$ git merge 分支名
在分支合并出现冲突时可以使用命令回复到之前为合并状态
$ git merge --abort
不合并其他分支的提交历史
# 仅添加文件,不进行提交
$ git merge --squash
# 添加文件并进行提交
$ git merge --no-squash
使用参数--merged
和--no-merged
过滤已合并和未合并到当前分支的分支
远程分支操作¶
学习本地分支与远程分支的交互
- 分支显示
- 分支同步
- 分支推送
- 分支跟踪
- 分支删除
使用命令
分支同步¶
获取远程分支数据
$ git fetch 远程仓库 # origin是默认的远程仓库
使用git fetch
不会合并远程分支,需要再显式使用git merge
命令
使用git pull
可实现拉取远程分支数据并合并
$ git pull 远程仓库 本地分支名
分支推送¶
推送本地分支内容到远程分支
$ git push 远程仓库 本地分支名/远程分支名
如果需要本地分支和远程分支名一致,实现如下:
$ git push 远程仓库 本地分支名
使用参数-u
设置要推送的远程分支为本地待跟踪,方便后续拉取代码操作
$ git push -u 远程仓库 本地分支
分支跟踪¶
设置本地分支想要跟踪的远程分支
$ git checkout -b [branch] [remotename]/[branch]
如果远程分支和本地分支一致,那么使用简易方式
$ git checkout --track [remotename]/[branch]
修改要跟踪的远程分支,使用参数-u
或--set-upstream-to
$ git branch -u [branch] [remotename]/[branch]
# 同样的分支名
$ git branch -u [remotename]/[branch]
分支删除¶
删除远程分支
$ git push 远程仓库 --delete 远程分支名
如果远程分支已在本地分支之后,可以不删除远程分支而使用强制方式推送到远程分支,参考[Git高级教程(二)] 远程仓库版本回退方法
$ git push -f
拉取指定远程分支到本地¶
由于git
去中心化的特性,下载远程仓库时会将所有分支都下载下来,不仅耗时而且占用本地磁盘容量
参考git 拉取远程分支到本地,拉取指定远程分支到本地
思路¶
首先在本地新建git
仓库,然后下载指定远程分支,最后创建本地分支并关联到指定远程分支即可
实现¶
新建仓库
$ mkdir gitrepo
$ cd giterpo
$ git init
拉取远程指定分支
$ git remote add origin https://github.com/zjZSTU/zjzstu.github.com.git
$ git fetch origin dev
新建本地分支并关联到指定远程分支
$ git checkout -b dev origin/dev
remote: error: cannot lock ref ‘refs/heads/master’: ref refs/heads/master¶
在Travis CI
上上传文件到远程仓库,出现如下问题
remote: error: cannot lock ref 'refs/heads/master': ref refs/heads/master
起因¶
我在上传提交时中间中断了
$ git push -u origin dev
Counting objects: 6, done.
Delta compression using up to 8 threads.
Compressing objects: 100% (6/6), done.
Writing objects: 100% (6/6), 556 bytes | 0 bytes/s, done.
Total 6 (delta 5), reused 0 (delta 0)
remote: Resolving deltas: 100% (5/5), completed with 5 local objects.
^C
然后再更新文章后再一次提交,就出现了远程仓库锁定的问题
解决¶
参考:git: error: cannot lock ref, error: cannot lock ref
将远程仓库下载到本地,然后执行如下命令
git remote prune origin
其作用是同步本地远程分支,删除本地已过时的远程分支
重新触发Travis CI执行,能够成功更新了。
远程仓库¶
[GitLab]安装¶
安装¶
进入gitlab/gitlab-ce查询
首先安装依赖项
$ curl -s https://packages.gitlab.com/install/repositories/gitlab/gitlab-ce/script.deb.sh | sudo bash
Detected operating system as Ubuntu/xenial.
Checking for curl...
Detected curl...
Checking for gpg...
Detected gpg...
Running apt-get update... done.
Installing apt-transport-https... done.
Installing /etc/apt/sources.list.d/gitlab_gitlab-ce.list...done.
Importing packagecloud gpg key... done.
Running apt-get update... done.
The repository is setup! You can now install packages.
然后安装gitlab-ce
# 当前是ubuntu 16.04
$ sudo apt-get install gitlab-ce
也可以下载.deb包后安装
$ sudo dpkg -i gitlab-ce_12.3.5-ce.0_amd64.deb
Selecting previously unselected package gitlab-ce.
(Reading database ... 368157 files and directories currently installed.)
Preparing to unpack gitlab-ce_12.3.5-ce.0_amd64.deb ...
Unpacking gitlab-ce (12.3.5-ce.0) ...
Setting up gitlab-ce (12.3.5-ce.0) ...
It looks like GitLab has not been configured yet; skipping the upgrade script.
*. *.
*** ***
***** *****
.****** *******
******** ********
,,,,,,,,,***********,,,,,,,,,
,,,,,,,,,,,*********,,,,,,,,,,,
.,,,,,,,,,,,*******,,,,,,,,,,,,
,,,,,,,,,*****,,,,,,,,,.
,,,,,,,****,,,,,,
.,,,***,,,,
,*,.
_______ __ __ __
/ ____(_) /_/ / ____ _/ /_
/ / __/ / __/ / / __ `/ __ \
/ /_/ / / /_/ /___/ /_/ / /_/ /
\____/_/\__/_____/\__,_/_.___/
Thank you for installing GitLab!
GitLab was unable to detect a valid hostname for your instance.
Please configure a URL for your GitLab instance by setting `external_url`
configuration in /etc/gitlab/gitlab.rb file.
Then, you can start your GitLab instance by running the following command:
sudo gitlab-ctl reconfigure
For a comprehensive list of configuration options please see the Omnibus GitLab readme
https://gitlab.com/gitlab-org/omnibus-gitlab/blob/master/README.md
系统配置¶
打开文件/etc/gitlab/gitlab.rb
,修改external_url为自己的地址
$ sudo cat /etc/gitlab/gitlab.rb | grep external_url
[sudo] password for zj:
Sorry, try again.
[sudo] password for zj:
##! For more details on configuring external_url see:
##external_url 'http://gitlab.example.com'
external_url 'http://localhost:8800'
...
...
重新进行gitlab配置
$ sudo gitlab-ctl reconfigure
Starting Chef Client, version 14.13.11
resolving cookbooks for run list: ["gitlab"]
Synchronizing Cookbooks:
- gitlab (0.0.1)
- package (0.1.0)
- redis (0.1.0)
- postgresql (0.1.0)
- monitoring (0.1.0)
- registry (0.1.0)
- mattermost (0.1.0)
- consul (0.1.0)
- gitaly (0.1.0)
- letsencrypt (0.1.0)
- nginx (0.1.0)
- runit (4.3.0)
- crond (0.1.0)
- acme (4.0.0)
Installing Cookbook Gems:
Compiling Cookbooks...
...
...
Running handlers:
Running handlers complete
Chef Client finished, 526/1417 resources updated in 02 minutes 32 seconds
gitlab Reconfigured!
登录修改后的网址:http://localhost:8800
管理员root
的密码设置完成后就自动跳转到登录页面
可以直接使用root
用户登录,也可以注册一个新帐号
[GitLab]命令行启动、停止和重启¶
启动
sudo gitlab-ctl start
停止
sudo gitlab-ctl stop
重启
sudo gitlab-ctl restart
GitLab导致8080端口冲突¶
问题复现¶
安装完GitLab
后,修改配置文件/etc/gitlab/gitlab.rb
##external_url 'http://gitlab.example.com'
external_url 'http://localhost:8800'
本以为这样就能修改GitLab
端口号为8800
了,没想到再次登录8080
仍旧出现了GitLab
页面
问题解析¶
查询哪个程序监听了8080
端口
# netstat -lnp | grep 8080
tcp 0 0 127.0.0.1:8080 0.0.0.0:* LISTEN 26436/config.ru
查询相应的进程
# netstat -lnp | grep 26436
tcp 0 0 127.0.0.1:8080 0.0.0.0:* LISTEN 26436/config.ru
unix 2 [ ACC ] STREAM LISTENING 343538 26436/config.ru /var/opt/gitlab/gitlab-rails/sockets/gitlab.socket
仍然是GitLab
在监听8080
端口,参考gitlab 8.13 80 8080端口冲突问题,查看配置文件unicorn.rb
# This file is managed by gitlab-ctl. Manual changes will be
# erased! To change the contents below, edit /etc/gitlab/gitlab.rb
# and run `sudo gitlab-ctl reconfigure`.
# What ports/sockets to listen on, and what options for them.
listen "127.0.0.1:8080", :tcp_nopush => true
默认情况下unicorn
同样监听8080
端口,查询/etc/gitlab/gitlab.rb
中相应的设置
# cat gitlab.rb | grep unicorn
#unicorn['port'] = 8800
解决方案¶
需要在gitlab.rb
上同时修改unicorn
监听端口号,修改配置文件/etc/gitlab/gitlab.rb
如下
##external_url 'http://gitlab.example.com'
external_url 'http://localhost:8800'
unicorn['port'] = 8801
重新启动GitLab
# gitlab-ctl reconfigure
# gitlab-ctl restart
查询配置文件/var/opt/gitlab/gitlab-rails/etc/unicorn.rb
# cat unicorn.rb | grep listen
# What ports/sockets to listen on, and what options for them.
listen "127.0.0.1:8801", :tcp_nopush => true
测试端口号
$ curl localhost:8080
curl: (7) Failed to connect to localhost port 8080: Connection refused
$ curl localhost:8800
<!DOCTYPE html>
<html>
<head>
<meta content="width=device-width, initial-scale=1, maximum-scale=1" name="viewport">
...
...
# curl localhost:8801
<html><body>You are being <a href="http://localhost:8801/users/sign_in">redirected</a>.</body></html>
[GitLab][nginx]反向代理¶
当前gitlab
登录路径是localhost:8080
$ curl localhost:8800
<html><body>You are being <a href="http://localhost:8800/users/sign_in">redirected</a>.</body></html>
地址会跳转到http://localhost:8800/users/sign_i
,下面通过反向代理简化登录地址
调整gitlab登录地址¶
修改gitlab
配置文件/etc/gitlab/gitlab.rb
,修改external_url
访问路径
external_url 'http://localhost:8800/gitlabs/'
更新gitlab
配置
$ gitlab-ctl reconfigure
$ gitlab-ctl restart
nginx配置¶
修改nginx
配置文件/etc/nginx/conf.d/default.conf
,新增location
$ cat gitlab.conf
server {
...
...
location /gitlabs/ {
proxy_pass http://localhost:8800;
}
...
...
}
刷新nginx
$ sudo nginx -t
$ sudo nginx -s reload
之后输入localhost/gitlabs/
即可登录gitlab
[Docker]GitLab使用¶
参考:
gitlab docker Web界面打开反应迟钝的解决办法
gitlab
提供了官方镜像 - gitlab/gitlab-ce
启动容器¶
运行以下命令启动容器
$ docker run --detach \
--publish 7010:7010 \
--publish 7020:22 \
--name gitlab \
--restart always \
--volume /srv/gitlab/config:/etc/gitlab \
--volume /srv/gitlab/logs:/var/log/gitlab \
--volume /srv/gitlab/data:/var/opt/gitlab \
gitlab/gitlab-ce:latest
等待容器状态从Up 1 second (health: starting)
变为Up 3 minutes (healthy)
- 绑定
7010
端口(作用于后续的external_url
) - 绑定主机
7020
端口到容器22
端口 - 挂载主机
/srv/gitlab
文件夹到容器/etc/gitlab:Gitlab
配置文件/var/log/gitlab
:日志/var/opt/gitlab
:应用数据
设置external_url¶
进入gitlab
容器
$ docker exec -it COMTAINER_ID bash
修改配置文件/etc/gitlab/gitlab.rb
,添加external_url
属性
external_url 'http://IP_ADDRESS:7010' # 指定IP地址,设置访问地址
nginx['listen_port'] = 7010
gitlab_rails['gitlab_shell_ssh_port'] = 7020
在容器内部重启gitlab
服务
$ gitlab-ctl reconfigure
$ gitlab-ctl restart
也可以退出系统后,重新启动容器
$ docker restart CONTAINER_ID
等待容器状态从Restarting (1) 19 seconds ago
到Up 18 minutes (healthy)
启动浏览器登录http://localhost:7010
[问题]容器一直重启¶
使用docker logs
命令查询
$ docker log CONTAINER_ID
...
...
System Info:
------------
chef_version=14.13.11
platform=ubuntu
platform_version=16.04
ruby=ruby 2.6.3p62 (2019-04-16 revision 67580) [x86_64-linux]
program_name=/opt/gitlab/embedded/bin/chef-client
executable=/opt/gitlab/embedded/bin/chef-client
Running handlers:
There was an error running gitlab-ctl reconfigure:
/etc/gitlab/gitlab.rb:1: unexpected fraction part after numeric literal
external_url = 192.168.0.144:7002
^~~~~~~
/etc/gitlab/gitlab.rb:1: syntax error, unexpected tINTEGER, expecting end-of-input
external_url = 192.168.0.144:7002
^~~
Running handlers complete
Chef Client failed. 0 resources updated in 01 seconds
发现是external_url
配置失误导致。解决方法如下:
- 停止
gitlab
容器 - 修改配置文件(在主机中)
/srv/gitlab/config/gitlab.rb
- 重新启动容器
[GitLab][Webhook]不允许本地连接¶
在gitlab
仓库中设置Webhook
,使用本地连接出现如下错误:
Url is blocked: Requests to the local network are not allowed
参考:gitlab使用webhook向jenkins发送请求,报错 Requests to the local network are not allowed
登录root账户,点击Configure Gitlab
选项
进入Settings -> Network
,展开Outbound requests
,选中Allow requests to the local network from web hooks and services
[GitLab]重置密码¶
昨天新建的账户,今天突然等不上去了,参考以下文章重置密码
进入gitlab
管理后台。当前使用docker
版本gitlab
,所以先进入容器
$ docker exec -it CONTIANINER_ID bash
切换到git
用户
$ su git
登录gitlab-rails
$ gitlab-rails console production
DEPRECATION WARNING: Passing the environment's name as a regular argument is deprecated and will be removed in the next Rails version. Please, use the -e option instead. (called from require at bin/rails:4)
--------------------------------------------------------------------------------
GitLab: 12.4.2 (393a5bdafa2)
GitLab Shell: 10.2.0
PostgreSQL: 10.9
--------------------------------------------------------------------------------
Loading production environment (Rails 5.2.3)
irb(main):001:0>
(上面这一步有点慢),查询用户是否存在
irb(main):001:0> user=User.where(name: "zxxU").first
=> nil
irb(main):002:0> user=User.where(name: "zxxu").first
=> nil
irb(main):003:0> user=User.where(name: "zxxxn").first
=> #<User id:2 @zxxxU>
充值密码并确认
irb(main):005:0> user.password=12345678
=> 12345678
irb(main):006:0> user.password_confirmation=12345678
=> 12345678
保存并退出
irb(main):007:0> user.save
Enqueued ActionMailer::DeliveryJob (Job ID: 2b220e18-d0ac-415e-a1cc-52f31069d3be) to Sidekiq(mailers) with arguments: "DeviseMailer", "password_change", "deliver_now", #<GlobalID:0x00007f4e84a25510 @uri=#<URI::GID gid://gitlab/User/2>>
=> true
irb(main):008:0> quit
[GitLab]受保护分支¶
强制上传代码到Gitlab
仓库的dev
分支出错,提示如下:
GitLab: You are not allowed to force push code to a protected branch on this project
参考:解决 GitLab: You are not allowed to force push code to a protected branch on this project问题
是由于分支保护的原因,需要进入仓库setting -> Repository -> Protected Branches
允许dev
分支能够强制推送
unicorn出错¶
问题描述¶
通过docker
部署gitlab
一段时间后,突然出现502
错误
查看容器状态,显示不健康
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
89481faa2ed1 gitlab/gitlab-ce:latest "/assets/wrapper" 2 weeks ago Up 7 hours (unhealthy)
浏览容器日志,发现如下错误:
==> /var/log/gitlab/unicorn/unicorn_stdout.log <==
bundler: failed to load command: unicorn (/opt/gitlab/embedded/bin/unicorn)
==> /var/log/gitlab/unicorn/unicorn_stderr.log <==
ArgumentError: Already running on PID:460 (or pid=/opt/gitlab/var/unicorn/unicorn.pid is stale)
/opt/gitlab/embedded/lib/ruby/gems/2.6.0/gems/unicorn-5.4.1/lib/unicorn/http_server.rb:205:in `pid='
/opt/gitlab/embedded/lib/ruby/gems/2.6.0/gems/unicorn-5.4.1/lib/unicorn/http_server.rb:137:in `start'
/opt/gitlab/embedded/lib/ruby/gems/2.6.0/gems/unicorn-5.4.1/bin/unicorn:126:in `<top (required)>'
/opt/gitlab/embedded/bin/unicorn:23:in `load'
/opt/gitlab/embedded/bin/unicorn:23:in `<top (required)>'
==> /var/log/gitlab/unicorn/current <==
2019-12-18_12:27:47.34406 failed to start a new unicorn master
2019-12-18_12:27:47.35882 starting new unicorn master
2019-12-18_12:27:47.91735 master failed to start, check stderr log for details
问题解析¶
看样子是unicorn
的问题,参考:
gitlab docker Web界面打开反应迟钝的解决办法
进入容器内部,查看unicorn
状态
$ docker exec -it xxxx bash
# gitlab-ctl tail unicorn
发现每次unicorn
显示的PID
都不同,修改/etc/gitlab/gitlab.rb
,添加
unicorn['listen'] = 'localhost'
unicorn['port'] = 8999
更新并重启后,gitlab
服务恢复正常
# gitlab-ctl reconfigure
# gitlab-ctl restart
[GitHub]版本发布¶
之前通过本地进行版本标记,然后上传到github
,在release
页面能够查询到相应的版本。参考标签设置
但是查看其他的github
项目的release
页面,发现发布的版本中还包含了多个压缩文件(比如Windows/Linux/MacOS
),可以单独下载
学习GitHub
文档About releases和Creating releases后发现必须通过在线标签设置的方式才能额外上传单独的压缩文件
提交信息规范¶
引言¶
参考:
Commit message 和 Change log 编写指南
每次进行git提交时,需要写提交说明,规范提交说明的好处如下
- 更加结构化的提交历史
- 保证每次信息都有确切的含义
- 方便直接生成changelog
- 方便信息搜索和过滤
- 提交日志规范
- 提交日志工具
- 检查日志工具
- 版本化工具
- 如何利用git hooks自制工具
Angular消息准则¶
目前最受开发人员肯定的规范是前端框架Angular
提出的提交消息准则
提交格式如下:
<type>(<scope>): <subject>
<BLANK LINE>
<body>
<BLANK LINE>
<footer>
每次提交可以包含页眉(header
)、正文(body
)和页脚(footer
),每次提交必须包含页眉内容
每次提交的信息不超过100
个字符
详细文档:AngularJS Git Commit Message Conventions
页眉设置¶
页眉的格式指定为提交类型(type
)、作用域(scope
,可选)和主题(subject
)
提交类型¶
提交类型指定为下面其中一个:
build
:对构建系统或者外部依赖项进行了修改ci
:对CI配置文件或脚本进行了修改docs
:对文档进行了修改feat
:增加新的特征fix
:修复bug
pref
:提高性能的代码更改refactor
:既不是修复bug
也不是添加特征的代码重构style
:不影响代码含义的修改,比如空格、格式化、缺失的分号等test
:增加确实的测试或者矫正已存在的测试
作用域¶
范围可以是任何指定提交更改位置的内容
页脚设置¶
Breaking changes
¶
不兼容修改指的是本次提交修改了不兼容之前版本的API或者环境变量
所有不兼容修改都必须在页脚中作为中断更改块提到,以BREAKING CHANGE
:开头,后跟一个空格或者两个换行符,其余的信息就是对此次修改的描述,修改的理由和修改注释
BREAKING CHANGE: isolate scope bindings definition has changed and
the inject option for the directive controller injection was removed.
To migrate the code follow the example below:
Before:
。。。
。。。
After:
。。。
。。。
The removed `inject` wasn't generaly useful for directives so there should be no code using it.
引用提交的问题¶
如果本次提交目的是修改issue
的话,需要在页脚引用该issue
以关键字Closes
开头,比如
Closes #234
如果修改了多个bug
,以逗号隔开
Closes #123, #245, #992
回滚设置¶
当此次提交包含回滚(revert
)操作,那么页眉以"revert:"
开头,同时在正文中添加"This reverts commit hash"
,其中hash
值表示被回滚前的提交
revert:<type>(<scope>): <subject>
<BLANK LINE>
This reverts commit hash
<other-body>
<BLANK LINE>
<footer>
Conventional提交规范¶
Conventional Commits(约定式提交)脱胎于Angular
提交信息准则,提供了更加通用、简洁和灵活的提交规范
提交格式如下:
<类型>[可选的作用域]: <描述>
# 空一行
[可选的正文]
# 空一行
[可选的脚注]
页尾设置¶
强制支持在页脚使用BREAKING CHANGES
提交规范¶
结合RFC2019,在下面规范中使用关键字来指示需求级别
MUST
(必须)MUST NOT
(禁止)REQUIRED
(需要)SHALL
(应当)SHALL NOT
(不应当)SHOULD
(应该)SHOULD NOT
(不应该)RECOMMENDED
(推荐)MAY
(可以)OPTIONAL
(可选)
- 每次提交必须添加类型名为前缀。类型名是一个名词,比如
feat、fix
,后跟冒号和一个空格 - 类型
feat
必须在提交新特征时使用 - 类型
fix
必须用于修复bug
的提交 - 类型后面可以添加一个可选的作用域。作用域名是一个短语,表示代码库中的一个小节,比如
fix(parser)
- 在类型/作用域前缀后面必须跟上一个简短描述,关于本次提交的代码修改,比如
fix: 字符串中包含多个空格时的数组分析问题
- 可以在描述后面添加一个长的正文,用于提供额外的上下文信息。正文内容必须在短描述后空一行开始
- 可以在正文后空一行开始页脚,页脚应该包含这次代码修改的相关问题,比如
Fixes #13
- 不兼容修改(
breaking change
)必须放置在提交的页脚或正文部分的最开始处,必须使用大写文本BREAKING CHANGE
作为前缀,后跟冒号和一个空格 - 在
BREAKING CHANGE:
后面必须提供一个描述,关于API
的修改,比如BREAKING CHANGE: 环境变量目前优先于配置文件
- 页脚必须包含不兼容修改、额外链接、问题引用和其他元信息
- 除了
feat
和fix
以外的类型可以在提交信息中使用
徽章¶
使用了常规提交规范可以添加徽章在README
[](https://conventionalcommits.org)
实现示例¶
只有页眉和页尾
feat: allow provided config object to extend other configs
BREAKING CHANGE: `extends` key in config file is now used for extending other config files
只有页眉
docs: correct spelling of CHANGELOG
使用了作用域
feat(lang): added polish language
修复了bug
fix: minor typos in code
see the issue for details on the typos fixed
fixes issue #12
FAQ
¶
问:在最初开发阶段如何处理提交信息?
建议像已发布产品一样处理。即使是你的软件开发伙伴在使用软件过程中,也想知道那些被修复了,那些是不兼容修改。
问:提交头的类型名是大写还是小写?
无所谓,不过最好保持一致(一直大写或一直小写)
问:如果提交内容适用于多个类型怎么办?
尽可能返回并进行多次提交。常规提交准则的优势在于它有能力驱动我们进行更加组织化的提交和PR
问:这是否是不鼓励快速开发和快速迭代?
它不鼓励以无序的方式快速开发。它帮助你在有多个开发者的多个项目中进行长期开发
问:常规提交准则是否会限制提交的类型?
常规提交准则鼓励开发者使用更多有确切含义的类型。除此以外,准则的灵活性允许开发组提出更多适用于自己的类型,并随着时间的推移更改这些类型
问:这个准则和SemVer的联系?
fix
类型应该翻译成PATCH
版本。feat
类型应该翻译成MINOR
版本。如果提交信息中包含不兼容修改
,不管哪种类型,都应该翻译成MAJOR
版本
问:如何将扩展版本转换为常规提交规范?
我们建议使用SemVer
发布您自己对本规范的扩展(并鼓励您进行这些扩展!)
问:如果我不小心使用了错误的提交类型,该怎么办?
- 使用了规范中的类型但是没有使用正确的类型,比如使用
fix
替代了feat
在合并或者发布这个错误之前,推荐使用git rebase -i
进行提交历史编辑。发布之后,依据使用的工具或流程进行清理
- 当使用了规范外的类型,比如使用了
feet
替代了feat
如果提交不符合常规提交规范,它只是意味着基于规范的工具将错过这次提交
问:是否我的所有贡献者都需要使用常规提交规范?
如果使用基于squash
的Git
工作流,主管维护者可以在合并时清理提交信息——这不会对普通提交者产生额外的负担。常见的工作流程是让git
系统自动从pull request
中squash
出提交,并向主维护者提供一份表单,用以在合并时输入适合的git
提交信息。
添加提交模板¶
默认模板¶
在提交时打开编译器,默认会出现一段模板信息,提示你编辑提交信息,同时会提示当前修改的文件
$ git commit
# Please enter the commit message for your changes. Lines starting
# with '#' will be ignored, and an empty message aborts the commit.
# On branch master
# Your branch is ahead of 'origin/master' by 1 commit.
# (use "git push" to publish your local commits)
#
# Changes to be committed:
# modified: ...
# deleted: ...
#
自定义模板¶
可以自己编辑一个模板文件,比如新建~/.gitmessage
,编辑一段关于提交规范的注释
$ vim ~/.gitmessage
# head: <type>(<scope>): <subject>
# - type: feat, fix, docs, style, refactor, test, chore
# - scope: can be empty (eg. if the change is a global or difficult to assign to a single component)
# - subject: start with verb (such as 'change'), 50-character line
#
# body: 72-character wrapped. This should answer:
# * Why was this change necessary?
# * How does it address the problem?
# * Are there any side effects?
#
# footer:
# - Include a link to the ticket, if any.
# - BREAKING CHANGE
#
修改全局配置文件~/.gitconfig
,添加
[commit]
template = ~/.gitmessage
再次提交时显示的模板如下
# head: <type>(<scope>): <subject>
# - type: feat, fix, docs, style, refactor, test, chore
# - scope: can be empty (eg. if the change is a global or difficult to assign to a single component)
# - subject: start with verb (such as 'change'), 50-character line
#
# body: 72-character wrapped. This should answer:
# * Why was this change necessary?
# * How does it address the problem?
# * Are there any side effects?
#
# footer:
# - Include a link to the ticket, if any.
# - BREAKING CHANGE
#
# Please enter the commit message for your changes. Lines starting
# with '#' will be ignored, and an empty message aborts the commit.
# On branch master
# Your branch is ahead of 'all/master' by 2 commits.
# (use "git push" to publish your local commits)
#
# Changes to be committed:
# new file: .gitignore
#
# Untracked files:
# package.json
#
文件解析¶
在仓库内的.git/COMMIT_EDITMSG
文件中保存了最近一次提交的日志(包括模板信息)
提交信息交互工具Commitizen¶
Commitizen是一个提交日志工具,辅助开发者使用提交规则
安装Commitizen
¶
# 全局安装
$ npm install -g commitizen
安装Adapter
¶
Commitizen
支持多种不同的提交规范,可以安装和配置不同的适配器实现
以Conventional Commit
规范为例
全局配置(推荐)¶
# 安装
$ npm install -g cz-conventional-changelog
# 配置
$ echo '{ "path": "cz-conventional-changelog" }' > ~/.czrc
本地配置¶
# 安装
commitizen init cz-conventional-changelog --save-dev --save-exact
安装完成后,查看是否在package.json
中已加入cz-conventional-changelog
信息:
...
...
"devDependencies": {
"cz-conventional-changelog": "^3.0.2"
},
"config": {
"commitizen": {
"path": "./node_modules/cz-conventional-changelog"
}
}
}
测试¶
安装完成后,使用git-cz
替代git commit
完成提交操作,
$ git cz
cz-cli@4.0.3, cz-conventional-changelog@3.0.2
? Select the type of change that you're committing: (Use arrow keys)
❯ feat: A new feature
fix: A bug fix
docs: Documentation only changes
style: Changes that do not affect the meaning of the code (white-space, formatting, missing semi-colons, etc)
refactor: A code change that neither fixes a bug nor adds a feature
perf: A code change that improves performance
test: Adding missing tests or correcting existing tests
(Move up and down to reveal more choices)
通过提示信息辅助你完成标准化的提交日志
git-cz
支持git commit
所有的参数设置
正文换行使用\n
操作,比如正文内容如下:新增事项:\n1. 测试1\n2. 测试2\n3. 测试
build(npm): 加入package.json
新增事项:
1. 测试1
2. 测试2
3. 测试
校验消息工具commitlint+husky¶
参考:commitlint
使用commitizen
可以规范化提交信息,同样的,可以设置工具来检查提交信息是否符合格式要求
commitlint用于检查提交信息
husky是hook
工具,作用于git-commit
和git-push
阶段
使用场景:
- 本地信息检查
CI
信息检查
commitlint
¶
全局安装¶
$ npm install -g @commitlint/cli @commitlint/config-conventional
本地安装¶
$ npm install --save-dev @commitlint/{cli,config-conventional}
配置规范¶
# 使用conventional规范
$ echo "module.exports = {extends: ['@commitlint/config-conventional']};" > commitlint.config.js
测试¶
需要全局安装才能在命令行使用commitlint
# 错误示例,类型后跟一个冒号和一个空格
$ echo "docs:添加新的文档" | commitlint
⧗ input: docs:添加新的文档
✖ subject may not be empty [subject-empty]
✖ type may not be empty [type-empty]
✖ found 2 problems, 0 warnings
(Need help? -> https://github.com/conventional-changelog/commitlint#what-is-commitlint )
# 正确示例
$ echo "docs: 添加新的文档" | commitlint
⧗ input: docs: 添加新的文档
✔ found 0 problems, 0 warnings
(Need help? -> https://github.com/conventional-changelog/commitlint#what-is-commitlint )
# 或者
$ commitlint "docs: asdf"
⧗ input: build(npm): 添加package.json
✔ found 0 problems, 0 warnings
(Need help? -> https://github.com/conventional-changelog/commitlint#what-is-commitlint )
husky
¶
安装¶
# 本地
$ npm install --save-dev husky
配置¶
在package.json
中添加
// package.json
{
"husky": {
"hooks": {
"commit-msg": "commitlint -E HUSKY_GIT_PARAMS"
}
}
}
当
git提交信息提交
commitlint检查,参数
-E默认将
.git/COMMIT_EDITMSG数据添加到
HUSKY_GIT_PARAMS`
测试¶
# 错误提交提交
$ git commit -m "忽略node_modules"
husky > commit-msg (node v10.15.3)
⧗ input: 忽略node_modules
✖ subject may not be empty [subject-empty]
✖ type may not be empty [type-empty]
✖ found 2 problems, 0 warnings
(Need help? -> https://github.com/conventional-changelog/commitlint#what-is-commitlint )
husky > commit-msg hook failed (add --no-verify to bypass)
# 正确提交
$ git commit -m "build(npm): 忽略node_modules"
husky > commit-msg (node v10.15.3)
⧗ input: build(npm): 忽略node_modules
✔ found 0 problems, 0 warnings
(Need help? -> https://github.com/conventional-changelog/commitlint#what-is-commitlint )
[master 8728336] build(npm): 忽略node_modules
1 file changed, 1 insertion(+)
create mode 100644 .gitignore
CI
设置¶
以Travis CI
为例
在本地安装
$ npm install --save-dev @commitlint/travis-cli
修改travis.yml
language: node_js
script:
- commitlint-travis
语义版本规范¶
semver/semver.org提出一个语义版本规范,用于规范版本的生成和设置
中文版:语义化版本 2.0.0
优势¶
- 标识当前应用版本信息
- 管理代码仓库
- 管理外部依赖
版本格式¶
版本号命名如下:
# 英文版
MAJOR.MINOR.PATCH
# 中文版
主版本号.次版本号.修订号
版本号递增规则:
- 主版本号(
MAJOR version
):出现不兼容的API
变化 - 次版本号(
MINOR version
):新增向后兼容的功能 - 修订号(补丁版本号,
PATCH version
):修复向后兼容的bug
规范¶
- 使用语义版本控制的软件**必须(MUST)**声明公共
API
。API
可以在代码本身中声明,或者严格存在于文档中。不管怎样,它都应该是精确和全面的 - 正常版本号**必须(MUST)采用
X.Y.Z
格式,其中X、Y
和Z
是非负整数,并且必须不(MUST NOT)包含前导零。X
是主版本,Y
是次版本,Z
是补丁版本。每个元素必须(MUST)**以数字形式增加。例如:1.9.0 -> 1.10.0 -> 1.11.0
- 一旦发布了版本化的包,就**不能再(MUST NOT)**修改该版本的内容。任何修改都必须作为新版本重新发布
- 主版本号为
0(0.y.z)
表示初始开发阶段,可以执行任意的修改。这个阶段的公共API
**不应该(SHOULD NOT)**被视为稳定版。 - 从版本
1.0.0
定义的公共API
开始,之后版本号的递增方式依赖于此公共API
的更改方式 - 只要有向后兼容的
bug
被修复,就**必须(MUST)**递增补丁版本号Z(x.y.Z | x>0)
。错误修复被定义为修复错误行为的内部更改 - 只要有向后兼容的功能被引入公共
API
,就**必须(MUST)递增次版本号Y(x.Y.z | x>0)
。只要有任何公共API
被标记为舍弃(deprecated
),就必须(MUST)递增次版本号。如果在私有代码中引入了大量新功能或改进,其中可以(MAY)包括补丁级别的改变,那么可以(MAY)递增次版本号。当次版本号递增时必须(MUST)**设置补丁版本号为0
- 只要有不向后兼容的改变被引入公共
API
,就**必须(MUST)递增主版本号X(X.y.z | x>0)
,其中可以(MAY)**包括次版本和补丁级别的修改。当主版本号递增时,**必须(MUST)**设置次版本号和补丁版本号为0
- 预发布版本**可以(MAY)通过在补丁版本之后附加连字符(
-
)和一系列点(.
)分隔的标识符来表示。标识符必须(MUST)只包含ASCII
字母数字和连字符[0-9a-za-z-]
。标识符必须不(MUST NOT)为空。数字标识符必须不(MUST NOT)**包含前导0
。预发布版本的优先级低于相关的正常版本。预发布版本表示该版本尚不稳定,可能不满足与其关联的正常版本预期的兼容性要求。比如,1.0.0-alpha、1.0.0-alpha.1、1.0.0-0.3.7、1.0.0-x.7.z.92
- 构建元数据**可以(MAY)通过在补丁或预发布版本之后立即附加一个加号和一系列点分隔的标识符来表示。标识符必须(MUST)只包含
ASCII
字母数字和连字符[0-9a-za-z-]
。标识符必须不(MUST NOT)为空。在确定版本优先级时应该(SHOULD)**忽略构建元数据。因此如果有两个版本仅在构建元数据上有区别,那么这两个版本优先级相同。比如,1.0.0-alpha+001、1.0.0+20130313144700、1.0.0-beta+exp.sha.5114f85
- 优先级是指在排序时版本之间如何进行比较。**必须(MUST)按顺序将版本分离为主、次、补丁和预发布标识符来计算优先级(构建元数据不包含在优先级中)。当从左到右比较每个标识符时,优先级由第一个差异决定,如下所示:主、次和补丁版本总是用数字进行比较。比如,
1.0.0 < 2.0.0 < 2.1.0 < 2.1.1
。当主、次和补丁的大小相同时,预编译版本的优先级低于正常版本。比如,1.0.0-alpha < 1.0.0
。具有相同主版本、次版本和补丁版本的两个预发布版本的优先级必须(MUST)**通过从左到右比较每个点分隔的标识符来确定,直到发现以下差异:仅由数字组成的标识符用数字进行比较,带字母或连字符的标识符按ASCII
排序顺序在词法上进行比较。数字标识符总是优先级低于非数字标识符。如果前面的所有标识符都相同,则拥有更长字段集的预发布版本的优先级高于较小字段集的预发布版本。比如,1.0.0-alpha < 1.0.0-alpha.1 < 1.0.0-alpha.beta < 1.0.0-beta < 1.0.0-beta.2 < 1.0.0-beta.11 < 1.0.0-rc.1 < 1.0.0
FAQ
¶
问:应该如何处理0.y.z
初始开发阶段的修订?
最简单的方式是初始开发版本从0.1.0
开始,然后在每一个后续的阶段递增次版本号
问:什么时候发布1.0.0
版本?
下列情况可用于发布1.0.0
版本
- 软件已经在生产中使用
- 已经有用户依赖于稳定的
API
- 开发过程中非常担心向后兼容性
问:是否语义化规范不鼓励快速开发和快速迭代?
主版本为0
的初始开发阶段就是用于快速开发的。如果每天都在改变API
,那么软件应该仍旧停留在0.y.z
阶段或者在一个单独的开发分支上处理下一个主版本
问:是否对公共API
小小的不兼容修改都要递增主版本,那这样的话很快就能达到42.0.0
?
这就要考验你的开发经验和开发远见。不应将不兼容的更改轻易地引入具有大量依赖代码的软件中,升级所需的成本可能很高。必须推出主版本以发布不兼容的更改意味着你已经考虑了更改的影响,并评估所涉及的成本/效益比
问:为全部公共API
生成文档需要做太多的工作了!
为了其他人的使用而去文档化软件,这是作为职业开发者的责任。管理软件复杂性是保持项目高效的一个非常重要的部分,如果没有人知道如何使用您的软件,或者可以安全地调用哪些方法,这很难做到。从长远来看,语义版本控制以及对定义良好的公共API
的坚持可以使每个人都能顺利运行
问:如果不小心在次版本发布了一个不兼容改变该怎么办?
一旦意识到已经破坏了语义化版本规范,修复问题并发布一个新的次要版本,以纠正问题并恢复向后兼容性。**即使在这种情况下,修改已发行的版本也是不可接受的。**如果合适,记录违规版本并告知用户该问题,以便他们了解有问题的版本。
问:如果我更新了依赖,但是没有改变公共API
,应该怎么做?
这种方式是兼容的,因为它没有影响公共API
。明确依赖于你的包的软件应该有它们自己的依赖规范,作者也会注意到任何冲突。决定是否这个修改是补丁级别还是次版本级别依赖于你更新你的依赖是为了修复bug
还是添加新功能。我通常期待额外的代码是为了后一种,这种情况下明显是一个次版本级别递增
问:如果我不小心修改了公共API
,但是不兼容于版本号的改变(比如在补丁版本中错误的引入了主版本级别的不兼容修改)?
运用你最好的判断。如果有大量的用户会因为这个公共API
的返回而受到影响,那么最好的策略是执行一次主版本发布,即使这次修复严格上被视为是补丁发布。记住,语义版本化就是通过版本号的变化来传达意义。如果这些更改对您的用户很重要,请使用版本号通知他们
问:应该如何处理待舍弃的功能?
舍弃已存在的功能是软件开发的常规动作,也是为了进一步发展所必须的。当你舍弃部分公共API
,应该做两件事情:(1)更新文档让用户知道这次改变,(2)发布一个新的次版本,仍旧包含这个舍弃功能。在新的主版本发布中完全移除这些功能之前,应该至少发布一个包含这些舍弃功能的次版本,其目的是让用户能够平滑的迁移到新的API
问:语义规范对版本字符串有大小限制吗?
没有限制,但是255
个字符的版本号也太长了一点。此外,特定系统可能会对字符串的大小有限制
自动版本化和生成CHANGELOG工具standard-version¶
参考:
conventional-changelog/standard-version
conventioanl-changelog¶
参考:
使用工具conventional-changelog进行CHANGELOG文件的自动生成
使用¶
基本使用命令如下:
$ conventional-changelog -p angular -i CHANGELOG.md -s
- 参数
-p
指定提交信息的规范,有以下选择:angular, atom, codemirror, ember, eslint, express, jquery, jscs or jshint
- 参数
-i
指定读取CHANGELOG
内容的文件 - 参数
-s
表示将新生成的CHANGELOG
输出到-i
指定的文件中
上述命令将基于上次tag
版本后的变更内容添加到CHANGELOG.md
文件中,CHANGELOG.md
之前的内容不会消失
如果想要重新生成所有版本完整的CHANGELOG
内容,使用以下命令:
$ conventional-changelog -p angular -i CHANGELOG.md -s -r 0
- 参数
-r
默认为1
,设为0
将重新生成所有版本的变更信息
快捷方式¶
在工程package.json
中加入以下脚本
{
"scripts": {
"changelog": "conventional-changelog -p angular -i CHANGELOG.md -s -r 0"
}
}
运行如下命令即可生成1CHANGELOG
$ npm run changelog
README¶
如何写好README¶
README
常常是工程的第一个入口,经常不知道写些什么,如何介绍工程的内容。在网上找了资料,发现这是很多人遇到的问题,也有很多热心人士发表了自己的意见
主要参考RichardLitt/standard-readme,里面提出了一整套REAMDE
规范,包括编写规范、linter
、生成器、徽章以及示例
另外kylelobo/The-Documentation-Compendium和如何写好Github中的readme?也给出了很多建议
[译]规范¶
README
必须满足下面列出的所有要求
注意:标准自述文件是为开源库设计的。尽管它在历史上是为node
和npm
项目创建的,但它也适用于其他语言的库和包管理器
要求:
- 称为
README.md
(大写) - 如果项目支持i18n,则必须相应地命名该文件:
README.de.md
,其中de
是BCP 47语言标记。对于命名,请优先考虑语言的非区域子标记。如果只有一个README
且语言不是英语,则允许文本中使用不同的语言而无需指定BCP
标记:例如README.md可以是德语。在包含多种语言版本的情况下,README.md
固定为英语 - 是一个有效的
Markdown
文件 - 章节必须按下面给出的顺序出现。可省略可选部分
- 除非另有说明,否则每个章节必须具有下面列出的标题。如果
README
是另一种语言,则必须将标题翻译成该语言 - 不能包含无法访问链接
- 如果有代码示例,则应该像在项目的其余部分中对代码进行
linted
一样对它们进行linted
内容列表¶
注意:这只是规范的导航指南,并不是任何符合规范的文档定义或强制使用术语
- 章节
- 标题(
Title
) - 横幅(
Banner
) - 徽章(
Badges
) - 简短说明(
Short Description
) - 详细描述(
Long Description
) - 内容列表(
Table of Contents
) - 安全(
Security
) - 背景(
Background
) - 安装(
Install
) - 用法(
Usage
) - 附加内容(
Extra Sections
) - 应用编程接口(
API
) - 主要维护人员(
Maintainers
) - 致谢(
Thanks
) - 参与贡献方式(
Contributing
) - 许可证(
License
)
- 标题(
- 定义
章节¶
标题¶
状态(
status
):必须必要条件(
requirements
):标题必须与
repository、folder
和package manager
名称匹配,或者它可以有另一个相关的标题,旁边的repository、folder
和package manager
标题用斜体字和括号括起来。例如:# Standard Readme Style _(standard-readme)_
如果任何文件夹、存储库或包管理器名称不匹配,则在详细描述中必须有一条说明原因
建议(
suggestions
):符合内容要求,做到显而易见
横幅¶
- 状态:可选
- 必要条件:
- 不能有自己的标题
- 必须链接到当前存储库中的本地图像
- 必须直接出现在标题后面
徽章¶
- 状态:可选
- 必要条件:
- 不能有自己的标题
- 必须用换行符分隔
- 建议:使用http://shields.io或类似服务创建和托管图像
简短说明¶
- 状态:必须
- 必要条件:
- 不能有自己的标题
- 小于
120
个字符 - 以
>
开始 - 一定是单独一行
- 必须与包装管理器
说明
字段中的描述匹配 - 必须匹配
github
的描述(如果在github
上)
- 建议(
js
相关):- 使用
gh description
设置并获取github
描述 - 使用
npm show . description
显示本地npm
包中的描述
- 使用
详细描述¶
状态:可选
必要条件:
- 不能有自己的标题
- 如果任何文件夹、存储库或包管理器名称不匹配,必须在此处说明原因。参考标题
建议:
如果太长,考虑移动到背景章节
介绍构建存储库的主要原因
应该用宽泛的术语来描述模块,一般只在几段中;模块的例程或方法、冗长的代码示例或其他深入的材料的更多细节应该在后面的章节中给出。
理想情况下,稍微熟悉模块的人应该能够刷新他们的内存,而不必点击“向下翻页”。当读者继续阅读文档时,他们应该会逐渐获得更多的知识。
内容列表¶
- 状态:必须;对于小于
100
行的README
是可选的 - 必要条件:
- 必须链接到文件中的所有markdown章节
- 必须从第二节开始;不要包含标题或目录标题
- 必须至少有一个深度:必须捕获所有二级标题(
##
)
- 建议:
- 可以捕获三级(
###
)和四级(####
)深度的标题。如果是长目录,这些是可选的
- 可以捕获三级(
安全¶
- 状态:可选
- 必要条件:
- 如果有必要强调安全问题,则说明。否则,它应该在
Extra Sections
- 如果有必要强调安全问题,则说明。否则,它应该在
背景¶
- 状态:可选
- 必要条件:
- 涵盖动机
- 覆盖抽象依赖项
- 涵盖知识来源:
see also
也很合适
安装¶
用法¶
- 状态:默认是必须的,对于文档仓库而言是可选的
- 必要条件:
- 使用代码块说明常见用法
- 如果兼容于
cli
,用代码块说明其用法 - 如果可导入,用代码块表示导入功能和用法
- 子章节:
CLI
:如果命令行功能存在则是必要的
- 建议:
- 覆盖可能影响使用的基本选项:例如,如果是
javascript
,则覆盖promises/callbacks
(对ES6
而言) - 可以指向示例代码的可执行文件
- 覆盖可能影响使用的基本选项:例如,如果是
附加内容¶
- 状态:可选
- 必要条件:
- 无
- 建议:
- 这不应称为附加内容。可容纳
0
个或多个章节,每个章节必须有其标题 - 这应该包含任何其他相关的内容,放在用法之后,应用程序接口之前
- 具体来说,如果安全章节不够重要,不需要放在上面的话,可以放在这里
- 这不应称为附加内容。可容纳
应用编程接口¶
- 状态:可选
- 必要条件:
- 描述开放的函数和对象
- 建议:
- 描述签名、返回类型、回调和事件
- 覆盖类型不明显的地方
- 描述注意事项
- 如果使用外部
api
生成器(如go-doc、js-doc
等),那么指向外部api.md
文件即可
主要维护人员¶
- 状态:可选
- 必要条件:
- 列出存储库的维护人员,以及联系他们的一种方式(例如
github
链接或电子邮件)
- 列出存储库的维护人员,以及联系他们的一种方式(例如
- 建议:
- 这应该是一个负责这个仓库人员的小名单。这不应该是所有拥有访问权限的人,例如整个组织,而是应该
ping
并负责管理和维护存储库的人 - 列出过去的维护者是友好的
- 这应该是一个负责这个仓库人员的小名单。这不应该是所有拥有访问权限的人,例如整个组织,而是应该
致谢¶
- 状态:可选
- 必要条件:
- 必须称为
Thanks, Credits
和Acknowledgements
的其中一种
- 必须称为
- 建议:
- 陈述任何对项目开发有重大帮助的人或事
- 列出公共联系人的超链接(如果可以的话)
参与贡献方式¶
- 状态:必须
- 必要条件:
- 说明用户可在哪里提问
- 说明是否接受
PR
- 列出参与的任何要求;例如,对提交进行审核
- 建议:
- 如果有的话,链接到
CONTRIBUTING
文件 - 尽可能友好
- 链接到
github
问题库 - 链接到行为准则(
Code of Conduct
)。Coc
通常位于贡献部分或文档中,或者设置在整个组织的其他位置,因此可能不需要在每个存储库中包含整个文件。但是,强烈建议始终链接到代码,无论它位于何处 - 也可以在这里增加一个小节,列出贡献者
- 如果有的话,链接到
README生成器¶
RichardLitt/generator-standard-readme提供了一个npm
命令行工具,用于生成README
文件
安装¶
npm install --global yo generator-standard-readme
使用¶
命令行输入
$ yo standard-readme
接下来会提出很多问题,然后生成一个README文件。所有问题如下:
What do you want to name your module?
What is the description of this module?
Do have a banner image?
Where is the banner image? Ex: 'img/banner.png'
Do you want a TODO dropped where your badges should be?
Do you want a TODO dropped where your long description should be?
Do you need a prioritized security section?
Do you need a background section?
Do you need an API section?
What is the GitHub handle of the main maintainer?
Do you have a CONTRIBUTING.md file?
Are PRs accepted?
Is an MIT license OK?
What is your license?
Who is the License holder (probably your name)?
Use the current year?
What years would you like to specify?
示例¶
$ yo standard-readme
? ==========================================================================
We're constantly looking for ways to make yo better!
May we anonymously report usage statistics to improve the tool over time?
More info: https://github.com/yeoman/insight & http://yeoman.io
========================================================================== Yes
? What is the name of your module? zj
? What is the description of this module? yo使用示例
? Do have a banner image? No
? Do you want a standard-readme compliant badge? Yes
? Do you want a TODO dropped where more badges should be? Yes
? Do you want a TODO dropped where your long description should be? Yes
? Do you need a prioritized security section? No
? Do you need a background section? Yes
? Do you need an API section? No
? What is the GitHub handle of the main maintainer? zjZSTU
? Do you have a CONTRIBUTING.md file? No
? Are PRs accepted? Yes
? Is an MIT license OK? Yes
? Who is the License holder (probably your name)? zjZSTU
? Use the current year? Yes
create README.md
生成文件如下:
# zj // 标题
[](https://github.com/RichardLitt/standard-readme) // 徽章
TODO: Put more badges here. // 可以添加更多徽章
> yo使用示例 // 简短说明
TODO: Fill out this long description. // 详细说明
## Table of Contents // 下面的章节列表,每个章节都可以点击跳转
- [Background](#background)
- [Install](#install)
- [Usage](#usage)
- [Maintainers](#maintainers)
- [Contributing](#contributing)
- [License](#license)
## Background // 背景
## Install // 安装
```
```
## Usage // 用法
```
```
## Maintainers // 主要维护人员
[@zjZSTU](https://github.com/zjZSTU)
## Contributing // 参与贡献方式
PRs accepted.
Small note: If editing the README, please conform to the [standard-readme](https://github.com/RichardLitt/standard-readme) specification.
## License // 许可证
MIT © 2019 zjZSTU
自定义徽章¶
经常在README
文件中发现许多徽章,很多都是使用http://shields.io或类似服务创建和托管的
添加链接¶
在徽章图像上添加链接,点击图像跳转到仓库
[](https://shields.io)