显示 / 隐藏 文章目录 ]

Git

上次更新: 2024-03-15 23:14:48

GIT 最佳实践

GIT 本质是一个数据库,用来存代码的

  • 工作区:一个沙箱环境,GIT 不负责管理,你尽管在沙箱里面对文件进行操作
  • 暂存区:工作区文件变动先不急着提交,暂存到一定数量,在提交到版本库
  • 版本库:

!! Linus 永远的神!

配置用户

git config --global user.name "mozzie"
git config --global user.email himozzie@foxmail.com

alias 别名

解决参数太多,记不住的问题

!! HEAD -> master HEAD 相当于一个指针,指向当前所在分支

# 查看项目分支图,
git config --global alias.lo "log --oneline --decorate --graph --all"

.git 文件结构

  • hooks:提交代码前,检查代码格式……
  • info:包含一个排除性文件
  • logs:保存日志信息,不太需要
  • objects:相当于数据库,存储所有数据内容
  • refs:存放提交对象指针,管理分支的
  • config:配置文件
  • description:仓库描述信息
  • HEAD:指示目前被检出的分支
  • index:文件保存暂存区信息

修改远程仓库

# way 1
git remote set-url origin [url]
# way 2
git remote rm origin
git remote add origin [url]
# way3
修改 config 文件

高层命令

初始化仓库

git init

修改添加到暂存区

git add ./,相当于如下操作:

# 有多少文件改动,就执行多少次
git hash-object -w 文件名
git update-index

!! git add ./ 先把工作区生成 git 对象,放到版本库,然后再放到暂存区

暂存区提交到版本库

git commit -m 'comment',相当于如下操作:

git write-tree
git commit-tree

也可以跳过暂存区提交,git commit -a -m

查看哪些修改没有暂存

git diff:没有暂存

git diff --staged:查看哪些修改以及被暂存了,但没有提交

查看提交历史记录

git log --oneline,打印出hash值是提交对象

分支

本质是一个提交对象,每次git branch name中的name,指针HEAD,就会根据name指向提交对象

如果要开发新功能,就新建一个分支A,写完再合master分支,正常来说master分支不会轻易给修改权限。

如果另一个新功能,和分支A同级、并行的,那就切到master分支,在master分支基础上,开分支B,进行新功能开发

一般来说,master 分支没有权限,需要自己重新写开一个分支,分支名用 nickname

C1              master
|——C2——C3——C4   mozzie

分支列表

git branch

创建分支

git branch 分支名,并不会自动切换到分支

切换分支

!! 最佳实践:每次切换分之前,git status 查一下,当前分支一定要是干净的

git checkout 分支名

合并分支

!! 做任何事情,确保做完了,再合并到 master 分支

场景:需要增加功能feat:#53

# HEAD -> master,新开一个分支
git checkout -b 'feat53'

突然发现 bug,需要修复bug:#52

# HEAD -> feat53,先提交#53分支的工作
git commit -a -m 'feat53 完成50%'
# 切回 master 分支
git checkout master
# HEAD -> master,创建 issue52 分支
git checkout -b 'issue52'
# 改完了issue52
git commit -a -m 'fix:issue52'
# HEAD -> master
git checkout master
# 合
git merge issue52
# 删除 issue52分支(hash还在)
git branch -d issue52

此时,由于issue52是在之前的 master 分支上生成的,故而feat53的分支仍然存在issue52的 bug,所以有可能存在冲突,需要手动解决

# HEAD -> master
git merge feat53
# 此处省略解决冲突
git add ./
git commit -m 'fix:merge conflict'
# 删除 feat53
git branch -d feat53

删除分支

查看哪些分支合并到当前分支,git branch --merged,这个列表中分支名字前没有*号的分支通常可以使用git branch -d 分支名删掉

git branch -D 分支名,强制删除

新建分支并指向指定提交对象

git branch name commitHash,例git log --oneline如下:

* hasfh2asd 1.txt
* 1shfd2zsw 2.txt
* 67rf73has 3.txt
* 03uhr4rug 4.txt

输入git branch CCC 03uhr4rug,那么会创建一个名为CCC的分支,并且CCC分支有4.txt

通常想看原来的某个版本的代码,就可以这样操作,看完,把这个分支删了

远程分支

git clone下来的分支,默认就会建立一个远程跟踪分支(同步关系),例如 master 分支

  • 本地分支

场景一:如果想公开一个share分支 ,与他人共同写作:

# 过程中会生成生成一个远程跟踪分支 origin/share
git push origin share

场景二:创建一个本地分支b1,直接跟踪远程分支orgin/b1

git checkout -b 'b1' 'origin/b1'

场景三:已存在一个本地分支dev,改成远程跟踪分支

# HEAD -> dev,建立 本地分支 dev 与 远程分支 origin/dev 关系
git branch -u origin/dev
# 这样就可以直接
git push / git pull
  • 远程分支

查看远程分支:git remote -v

查看当前本地分支的远程跟踪分支:git branch -vv

远程分支删除, 本地更新 –prune

# 不加 --prune,和 fetch 等价, 远程被删除的分支不会同步删除本地origin的分支
git remote update origin --prune

提交规范

type(scope): subject
# 例如
feat(miniprogram): 增加了小程序模板消息相关功能

通常type有如下:

  • feat - 新功能 feature
  • fix - 修复 bug
  • docs - 文档注释
  • style - 代码格式(不影响代码运行的变动)
  • refactor - 重构、优化(既不增加新功能,也不是修复 bug)
  • perf - 性能优化
  • test - 增加测试
  • chore - 构建过程或辅助工具的变动
  • revert - 回退
  • build - 打包

自动生成 Change log

原理:利用 child_process获取 git log内容,处理字符串

const execSync = require("child_process").execSync; //同步子进程
const fs = require("fs");
const process = require("process");
const path = require("path");
const inquirer = require("inquirer");
const dayjs = require("dayjs");
const axios = require("axios");

// env
const isForCommanHuman = process.argv.includes("--common");

// changelog.md生成路径
const outputpath = path.resolve(process.cwd(), "./changelog.md");
// 非空检测
if (!fs.existsSync(outputpath)) fs.writeFile(outputpath, "", (err) => {});
// 华丽的gitlog日志
const perfectGitLog = (startTime, endTime) =>
  isForCommanHuman
    ? `git log --since="${startTime}" --until="${endTime}" --no-merges  --pretty=format:"%cr %C(cyan)%s"`
    : `git log --since="${startTime}" --until="${endTime}" --no-merges  --pretty=format:"%C(yellow)%h %C(green)%cn %C(redz)(%cr:%ci) %C(cyan)%s"`;

const wxrobotHook =
  "https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=be4d4473-c290-4ddd-a089-41df3ed1d601";

// 当前时间
const now = Date.now();
// 2周前
const weeks_2_ago = now - 14 * 24 * 60 * 60 * 1000;

inquirer
  .prompt([
    {
      type: "input",
      name: "startDate",
      message: `起始时间,默认13天前 \n`,
      default: dayjs(weeks_2_ago).format("YYYY.MM.DD"),
      validate: (val) => /\d{4}.\d{2}.\d{2}/.test(val),
    },
    {
      type: "input",
      name: "endDate",
      message: `结束时间,默认今天 \n`,
      default: dayjs(now).format("YYYY.MM.DD"),
      validate: (val) => /\d{4}.\d{2}.\d{2}/.test(val),
    },
    {
      type: "rawlist",
      message: "是否通知到微信机器人:",
      name: "notifyWxrobot",
      choices: ["Y", "N"],
    },
  ])
  .then((answers) => {
    const { startDate, endDate, notifyWxrobot } = answers;
    const rowTemplate = perfectGitLog(startDate, endDate);
    let fmt = execSync(rowTemplate)
      .toString()
      .trim()
      .replace(/feat: /gi, "✅: ")
      .replace(/fix: /gi, "🐛: ")
      .replace(/chore: /gi, "🎨: ")
      .replace(/perf: /gi, "⚡: ")
      .replace(/docs: /gi, "📝: ")
      .replace(/refactor: /gi, "🔨: ")
      .replace(/anno: /gi, "🔖: ")
      .replace(/style: /gi, "👷: ");
    fs.writeFileSync(outputpath, fmt, (err) => {});
    // 通知微信群聊机器人
    if (notifyWxrobot === "Y") {
      axios.post(wxrobotHook, {
        msgtype: "markdown",
        markdown: {
          content: fmt,
        },
      });
    }
  })
  .catch((error) => {
    if (error.isTtyError) {
      // Prompt couldn't be rendered in the current environment
    } else {
      // Something else went wrong
    }
  });

使用 husky+eslint 规范提交

需要配合 eslint

git init后,yarn add husky,在package.json配置

{
  "husky": {
    "hooks": {
      "pre-commit": "npm run lint"
    }
  }
}

生成 ssh key

ssh-keygen -t rsa -C "himozzie@foxmail.com"

查看 ssh 公钥

cat ~/.ssh/id_rsa.pub

git 代理

前提条件是开了扶墙工具

git clone 拉取方式选择 http/https(默认会让你输入账号密码,比较蛋疼),不要选择 ssl 拉取

git config --global http.proxy 'http://127.0.0.1:1081'
git config --global https.proxy 'https://127.0.0.1:1081'
# 清除
git config --global --unset http.proxy
git config --global --unset https.proxy

终端临时代理

# cmd临时代理方案(cmd窗口关闭,则代理失效)
set http_proxy=http://127.0.0.1:50015
set https_proxy=http://127.0.0.1:50015

git 钩子(hooks)

原理:项目 git push 到远程仓库,远程仓库的钩子 post 通知 www/wwwroot 下的站点 pull 远程仓库

git 钩子需要 git 服务和 pull 在同一环境中

  • 创建远程仓库,配置钩子,git post-receive 钩子
#!/bin/bash
unset $(git rev-parse --local-env-vars);
# post-receive接收到pull指令后,执行bash命令
cd /www/wwwroot/doc.mozzie.cn/  &&  git pull origin master

web 目录下 doc.mozzie.cn 是网站目录,本地项目编译打包后,直接 git push 的目录

web 钩子

待耍

项目

统计项目代码行数

统计所有人代码增删量,拷贝如下命令, git bash 终端,git 项目某分支下执行

git log --format='%aN' | sort -u | while read name; do echo -en "$name\t"; git log --author="$name" --pretty=tformat: --numstat | awk '{ add += $1; subs += $2; loc += $1 - $2 } END { printf "added lines: %s, removed lines: %s, total lines: %s\n", add, subs, loc }' -; done

统计制定提交者代码量

替换username为提交者的名称

git log --author="username" --pretty=tformat: --numstat | awk '{ add += $1; subs += $2; loc += $1 - $2 } END { printf "added lines: %s, removed lines: %s, total lines: %s\n", add, subs, loc }' -

搭建 gogs

gogs 官网下载,压缩包解压到www/wwwroot/

cd /www/wwwroot/gogs
# 启服务,默认3000的端口,被占用则 ./gogs web -port 3001
./gogs web

浏览器访问http://yourip:3000/install,注意服务器安全组放行 3000 端口

  • 为 gogs 添加 mysql 数据库
  • 配置 mysql
  • 配置 gogs 相关信息
  • 配置其他信息

停掉./gogs web

在刚安装的 gogs 路径下,找到/gogs/scripts/systemd/gogs.service 文件复制一份

User=root
Group=root
WorkingDirectory=/www/wwwroot/git.mozzie.cn
ExecStart=/www/wwwroot/git.mozzie.cn/gogs web
Restart=always
Environment=USER=root HOME=/www/wwwroot/git.mozzie.cn

将修改好的gogs.service文件上传到/etc/systemd/system下,并执行以下命令来激活 gogs

sudo systemctl enable gogs
# 启动gogs
sudo systemctl start gogs

/gogs/custom/conf/app.ini,修改该文件可以自定义配置,安装步骤填错了,可以这里修改,重启 gogs 服务即可

配置 gogs GIT 钩子

场景:以 Gogs 为例,先 git push A项目 到远程仓库 REPO,服务端 web 目录webB文件夹触发钩子执行 git pull

1、gogs 初始化一个仓库REPO,仓库设置=>管理 GIT 钩子=>post-receive,填入

#!/bin/sh
export GIT_WORK_TREE=/www/wwwroot/webB
export GIT_DIR=${GIT_WORK_TREE}/.git
cd ${GIT_WORK_TREE}
git pull

2、利用 ssh 工具登录服务器

ssh root@mozzie.cn

3、生成 ssh key

ssh-keygen -t rsa -C "himozzie@foxmail.com"

4、配置公钥到 gogs

cat ~/.ssh/id_rsa.pub

把打印出的公钥,配置到 ssh 密钥

5、最后一步

配置好服务端的公钥后,就可以无需用户名密码,cd /webB目录下,执行git pull,此后每次git push A项目,服务端都会触发GIT钩子,自动从REPO拉取最新的仓库文件

重拾纯粹的写作

<<<<<<< HEAD

目录

  1. 1. GIT 最佳实践
    1. 1.1. 配置用户
    2. 1.2. alias 别名
    3. 1.3. .git 文件结构
    4. 1.4. 修改远程仓库
    5. 1.5. 高层命令
      1. 1.5.1. 初始化仓库
      2. 1.5.2. 修改添加到暂存区
      3. 1.5.3. 暂存区提交到版本库
      4. 1.5.4. 查看哪些修改没有暂存
      5. 1.5.5. 查看提交历史记录
    6. 1.6. 分支
      1. 1.6.1. 分支列表
      2. 1.6.2. 创建分支
      3. 1.6.3. 切换分支
      4. 1.6.4. 合并分支
      5. 1.6.5. 删除分支
      6. 1.6.6. 新建分支并指向指定提交对象
      7. 1.6.7. 远程分支
    7. 1.7. 远程分支删除, 本地更新 –prune
  2. 2. 提交规范
    1. 2.1. 自动生成 Change log
    2. 2.2. 使用 husky+eslint 规范提交
    3. 2.3. 生成 ssh key
    4. 2.4. 查看 ssh 公钥
  3. 3. git 代理
  4. 4. 终端临时代理
  5. 5. git 钩子(hooks)
    1. 5.1. web 钩子
  6. 6. 项目
    1. 6.1. 统计项目代码行数
    2. 6.2. 统计制定提交者代码量
  7. 7. 搭建 gogs
    1. 7.1. 配置 gogs GIT 钩子
=======