Git钩子与自动化:让代码质量自动守护

Git钩子与自动化:让代码质量自动守护

前三期我们掌握了Git的基础操作、分支管理和团队协作。现在,让我们把效率提升到下一个层次——自动化。

Git钩子(Hooks)是Git在特定事件发生时自动执行的脚本。比如,每次commit前自动检查代码格式,每次push前自动运行测试,每次merge后自动部署。

这一期,我们深入Git的自动化世界。

Git钩子基础

钩子存放在.git/hooks/目录:

ls -la .git/hooks/

你会看到很多.sample文件,这是示例。去掉.sample后缀就激活了。

钩子类型

客户端钩子(本地执行):

  • pre-commit:commit前,检查代码
  • prepare-commit-msg:commit message生成后,编辑器启动前
  • commit-msg:commit message写完后,检查格式
  • post-commit:commit完成后,发通知
  • pre-push:push前,跑测试
  • post-checkout:切换分支后,安装依赖

服务端钩子(远程执行):

  • pre-receive:push到达服务器时
  • update:每个分支更新时
  • post-receive:push完成后

第一个钩子

创建一个简单的pre-commit钩子,检查是否有console.log

# .git/hooks/pre-commit
#!/bin/bash

# 检查暂存区的JS文件
files=$(git diff --cached --name-only --filter=ACM | grep '\.js$')

if [ -z "$files" ]; then
    exit 0
fi

# 检查是否有console.log
if grep -n "console\.log" $files; then
    echo "❌ 发现console.log,请移除后再提交"
    exit 1
fi

exit 0
chmod +x .git/hooks/pre-commit

现在,如果有console.log,commit会被拒绝。

Husky:现代钩子管理

直接编辑.git/hooks/有几个问题:

  • 钩子不会被Git跟踪,队友无法共享
  • 每次clone后需要手动设置
  • 脚本管理混乱

Husky解决了这些问题。

安装

npm install husky --save-dev

# 初始化(自动创建.husky目录)
npx husky init

配置pre-commit

# 创建pre-commit钩子
echo "npm test" > .husky/pre-commit

现在每次commit前会自动运行测试。测试失败,commit就被拒绝。

配置commit-msg

验证提交信息格式:

# .husky/commit-msg
#!/bin/bash

msg=$(cat $1)

# 检查是否符合约定式提交
if ! echo "$msg" | grep -qE "^(feat|fix|docs|style|refactor|test|chore)(\(.+\))?: .{1,}"; then
    echo "❌ 提交信息格式错误"
    echo "格式: (): "
    echo "示例: feat(auth): 添加OAuth登录"
    exit 1
fi
npx husky add .husky/commit-msg 'npx --no -- commitlint --edit "$1"'

lint-staged:只检查暂存文件

全量检查太慢?lint-staged只检查你改动的文件。

npm install lint-staged --save-dev
// package.json
{
  "lint-staged": {
    "*.js": [
      "eslint --fix",
      "prettier --write"
    ],
    "*.css": [
      "stylelint --fix",
      "prettier --write"
    ],
    "*.{json,md}": [
      "prettier --write"
    ]
  }
}
# .husky/pre-commit
npx lint-staged

流程:

  1. git commit触发pre-commit
  2. lint-staged检查暂存的文件
  3. ESLint/Prettier自动修复
  4. 修复后的文件重新add
  5. commit继续

commitlint:提交信息规范

npm install @commitlint/cli @commitlint/config-conventional --save-dev
// commitlint.config.js
module.exports = {
  extends: ['@commitlint/config-conventional'],
  rules: {
    'type-enum': [
      2,
      'always',
      [
        'feat',
        'fix',
        'docs',
        'style',
        'refactor',
        'perf',
        'test',
        'build',
        'ci',
        'chore',
        'revert'
      ]
    ],
    'subject-case': [2, 'always', 'lower-case']  // 主题小写
  }
};

现在,不符合规范的提交会被拒绝:

git commit -m "添加功能"
# ❌ 提交失败:必须以type开头

git commit -m "feat: 添加用户登录功能"
# ✅ 提交成功

完整工作流配置

一个现代化的前端项目配置:

// package.json
{
  "scripts": {
    "prepare": "husky install",
    "lint": "eslint . --ext .js,.ts,.tsx",
    "format": "prettier --write .",
    "test": "jest"
  },
  "lint-staged": {
    "*.{js,ts,tsx}": [
      "eslint --fix",
      "prettier --write"
    ],
    "*.{css,scss,json,md}": [
      "prettier --write"
    ]
  },
  "devDependencies": {
    "@commitlint/cli": "^18.0.0",
    "@commitlint/config-conventional": "^18.0.0",
    "eslint": "^8.0.0",
    "husky": "^9.0.0",
    "lint-staged": "^15.0.0",
    "prettier": "^3.0.0"
  }
}
# .husky/pre-commit
npx lint-staged

# .husky/commit-msg
npx --no -- commitlint --edit $1

# .husky/pre-push
npm test
// commitlint.config.js
module.exports = { extends: ['@commitlint/config-conventional'] };

一次clone后,所有开发者都会自动拥有相同的检查规则。

Git别名:效率提升

配置常用别名,减少输入:

# 基础别名
git config --global alias.st status
git config --global alias.co checkout
git config --global alias.br branch
git config --global alias.ci commit

# 查看日志
git config --global alias.lg "log --oneline --graph --all"
git config --global alias.last 'log -1 HEAD'

# 撤销
git config --global alias.unstage 'reset HEAD --'
git config --global alias.undo 'checkout HEAD --'

# 有用的别名
git config --global alias.stash-all 'stash save --include-untracked'
git config --global alias.push-force 'push --force-with-lease'

使用:

git st          # = git status
git lg          # 美观的日志图
git unstage file.txt  # 取消暂存

自定义Git命令

创建git-xxx脚本,就能用git xxx调用:

# ~/bin/git-publish
#!/bin/bash
# 发布当前分支到远程

branch=$(git branch --show-current)
git push -u origin $branch
chmod +x ~/bin/git-publish
export PATH=$PATH:~/bin

# 使用
git publish

自动部署

post-receive钩子(服务端)

在服务器上配置自动部署:

# /var/git/project.git/hooks/post-receive
#!/bin/bash

TARGET="/var/www/project"
GIT_DIR="/var/git/project.git"

while read oldrev newrev ref
do
    BRANCH=$(git rev-parse --symbolic --abbrev-ref $ref)

    if [ "$BRANCH" = "main" ]; then
        echo "Deploying main branch..."
        git --work-tree=$TARGET --git-dir=$GIT_DIR checkout -f main
        cd $TARGET
        npm install --production
        pm2 restart project
        echo "Deploy complete."
    fi
done

现在,push到main分支会自动部署。

GitHub Actions自动部署

# .github/workflows/deploy.yml
name: Deploy

on:
  push:
    branches: [main]

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - uses: actions/setup-node@v4
        with:
          node-version: '20'

      - run: npm ci
      - run: npm run build

      - name: Deploy to server
        uses: appleboy/ssh-action@master
        with:
          host: ${{ secrets.HOST }}
          username: ${{ secrets.USERNAME }}
          key: ${{ secrets.SSH_KEY }}
          script: |
            cd /var/www/project
            git pull
            npm ci --production
            pm2 restart project

Vercel/Netlify自动部署

最简单的方式:连接GitHub仓库,自动部署。

  • push到main → 自动构建 → 自动部署
  • PR预览 → 每个PR都有独立预览链接
  • 回滚 → 点一下就回退

Git bisect:定位问题提交

当项目出现bug,但不知道是哪个提交引入的:

# 开始二分查找
git bisect start

# 标记当前提交有问题
git bisect bad

# 标记某个旧提交是正常的
git bisect good v1.0.0

# Git会自动跳到中间的提交
# 你测试后标记
git bisect good  # 或 git bisect bad

# 重复直到找到问题提交
# Git会告诉你哪个提交有问题

# 结束
git bisect reset

自动化:

# 自动运行测试脚本来判断
git bisect run npm test

Git worktree:多分支并行开发

需要同时在多个分支工作,但不想频繁切换?

# 创建worktree
git worktree add ../project-feature feature-branch

# 现在有两个工作目录
# ../project (main分支)
# ../project-feature (feature-branch)

# 在project-feature中工作
cd ../project-feature
# 修改、提交...

# 完成后删除worktree
git worktree remove ../project-feature

小结

你现在掌握了Git自动化的核心技能:

  • Git钩子原理和常用钩子
  • Husky + lint-staged + commitlint现代工作流
  • 配置Git别名提升效率
  • 服务端自动部署
  • GitHub Actions CI/CD
  • Git bisect定位问题
  • Git worktree多分支并行

下一期,我们将进入实战环节——常见坑与解决方案。你会学到如何处理那些让新手崩溃的场景。


练习任务

  1. 为你的项目配置Husky + lint-staged
  2. 配置commitlint,尝试提交不规范信息(应该被拒绝)
  3. 配置一个Git别名,一键查看美化日志
  4. 用git bisect找一个故意引入的bug

下期预告:《Git实战:常见坑与解决方案》—— 误删分支怎么办?提交到错误分支怎么救?大文件怎么处理?

Views: 19

Git团队协作:让代码审查成为日常

Git团队协作:让代码审查成为日常

前两期我们掌握了Git的基础操作和分支管理。但Git的真正威力在于协作——让一群人同时开发,而不会互相踩脚。

这一期,我们来聊聊团队协作的最佳实践。

Fork vs Clone

Clone:直接克隆仓库,有写权限

git clone git@github.com:myteam/project.git

适用于团队成员,对仓库有直接写权限。

Fork:在你的账号下创建仓库副本

  1. 在GitHub/GitLab页面点击Fork
  2. 克隆你fork的仓库
    git clone git@github.com:yourname/project.git

    适用于开源贡献者,对原仓库没有写权限。

Pull Request工作流

Pull Request(PR)是GitHub的叫法,GitLab叫Merge Request(MR)。本质相同:请求把你的分支合并到目标分支。

流程

graph TB
    A[从main创建feature分支] --> B[开发并提交]
    B --> C[推送到远程]
    C --> D[在GitHub创建PR]
    D --> E[代码审查]
    E --> F{通过?}
    F -->|是| G[合并PR]
    F -->|否| H[修改代码]
    H --> B
    G --> I[删除feature分支]

实战示例

# 1. 确保main是最新的
git checkout main
git pull origin main

# 2. 创建功能分支
git checkout -b feature/add-dark-mode

# 3. 开发...
git add .
git commit -m "feat: 添加暗黑模式支持"

# 4. 推送到远程
git push -u origin feature/add-dark-mode

# 5. 去GitHub/GitLab页面创建PR

创建PR时,填写:

  • 标题:简洁描述改动(如"feat: 添加暗黑模式支持")
  • 描述:详细说明改了什么、为什么改、怎么测试
  • 审查者:指定审查代码的人
  • 标签:如enhancement、bug、documentation

好的PR长什么样?

标题格式(约定式提交):

  • feat::新功能
  • fix::bug修复
  • docs::文档更新
  • refactor::重构
  • test::测试
  • chore::杂务(依赖更新、配置等)

描述模板

## 改动描述
添加了暗黑模式支持,用户可以在设置中切换主题。

## 改动原因
用户反馈夜间使用时太刺眼,需要暗黑模式。

## 如何测试
1. 登录系统
2. 进入设置页面
3. 点击"切换主题"
4. 验证页面颜色变化

## 截图
![暗黑模式效果](screenshot.png)

## 相关Issue
Closes #123

一个PR只做一件事

  • 不要把多个不相关的改动塞进一个PR
  • 小PR更容易审查,更快合并
  • 理想大小:200-400行代码

代码审查

代码审查(Code Review)是团队协作的核心。它不仅能发现bug,还能传播知识、统一风格。

审查者看什么?

  1. 正确性:代码是否实现了需求?
  2. 可读性:变量名、函数名是否清晰?逻辑是否易懂?
  3. 性能:有没有明显的性能问题?
  4. 安全:有没有SQL注入、XSS等安全隐患?
  5. 测试:有没有足够的测试覆盖?
  6. 风格:是否符合团队的编码规范?

审查评论类型

必须修改(Blocking)

🛑 这里有个bug,变量未定义就会使用

建议修改(Non-blocking)

💡 建议:这里用Array.filter会更简洁

提问

❓ 为什么要用递归?迭代是不是更合适?

称赞

👍 这个抽象做得很好!

作为被审查者

  1. 不要抵触批评:审查的是代码,不是你这个人
  2. 解释而非辩解:解释为什么这样写,而不是为错误找借口
  3. 及时响应:不要让PR挂着一周不动
  4. 自己先审查一遍:push前自己diff一下,避免低级错误
# 提交前自查
git diff main...HEAD  # 查看当前分支的所有改动

解决PR冲突

PR期间main可能有了新提交,导致你的PR冲突:

# 方法1:merge
git checkout feature/add-dark-mode
git fetch origin
git merge origin/main
# 解决冲突...
git push

# 方法2:rebase(推荐,保持线性历史)
git checkout feature/add-dark-mode
git fetch origin
git rebase origin/main
# 解决冲突...
git push --force-with-lease  # 注意:需要force push

注意--force-with-lease--force更安全,它会在远程有新提交时拒绝push。

Code Owner

大项目可以配置CODEOWNERS文件,自动指定审查者:

# .github/CODEOWNERS

# 前端代码由前端组审查
/frontend/ @myteam/frontend

# API代码由后端组审查
/api/ @myteam/backend

# 安全相关由安全组审查
**/auth* @myteam/security

保护分支

防止直接push到main分支,强制走PR流程:

GitHub设置:

  1. Settings → Branches → Add rule
  2. Branch name pattern: main
  3. 勾选:
    • Require a pull request before merging
    • Require approvals(需要几个人审批)
    • Require status checks to pass before merging(CI必须通过)

这样,任何人(包括管理员)都不能直接push到main,必须通过PR。

CI/CD集成

PR可以触发自动测试,只有测试通过才能合并:

# .github/workflows/test.yml
name: Test

on:
  pull_request:
    branches: [main]

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: '20'
      - run: npm ci
      - run: npm test
      - run: npm run lint

这样每次PR都会自动跑测试,测试失败就无法合并。

多人协作常见问题

问题1:Push被拒绝

! [rejected] main -> main (non-fast-forward)

原因:远程有新提交,你本地没有。

解决

git pull --rebase origin main
git push origin main

问题2:别人的分支怎么更新?

# 获取所有远程分支
git fetch --all

# 查看同事的分支
git branch -r

# 基于同事的分支创建本地分支
git checkout -b feature-xxx origin/feature-xxx

问题3:如何同步Fork?

# 1. 添加上游仓库
git remote add upstream git@github.com:original-owner/project.git

# 2. 获取上游更新
git fetch upstream

# 3. 合并到本地main
git checkout main
git merge upstream/main

# 4. 推送到你的fork
git push origin main

问题4:不小心push了敏感信息!

# 立即删除敏感文件
git rm --cached config/secrets.yml
git commit -m "chore: 移除敏感文件"
git push

# 历史中还有!需要彻底清除
# 使用BFG Repo-Cleaner(推荐)
bfg --delete-files secrets.yml
git push --force

# 或用git filter-branch(慢)
git filter-branch --force --index-filter \
  'git rm --cached --ignore-unmatch config/secrets.yml' \
  --prune-empty --tag-name-filter cat -- --all
git push --force

重要:改写历史后,所有协作者需要重新clone仓库!

协作规范

Git提交规范

使用约定式提交(Conventional Commits):

(): 

<footer>

示例:

feat(auth): 添加OAuth2.0登录支持

- 支持Google登录
- 支持GitHub登录
- 添加登录状态持久化

Closes #456

好处:

  • 自动生成changelog
  • 自动决定版本号(feat是minor,fix是patch)
  • 清晰的历史记录

提交信息模板

配置提交模板:

git config commit.template ~/.gitmessage

~/.gitmessage内容:

# :  (50 chars)
# |- - - - - - - - - - - - - - - - - - - - - ->|

#  (72 chars)
# |- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ->|

# Type:
#   feat     新功能
#   fix      Bug修复
#   docs     文档
#   style    格式(不影响代码运行)
#   refactor 重构
#   test     测试
#   chore    构建/工具

分支保护策略

graph LR
    A[feature分支] -->|PR| B[develop分支]
    C[bugfix分支] -->|PR| B
    B -->|PR| D[release分支]
    D -->|测试通过| E[main分支]
    F[hotfix分支] -->|PR| E
    E -->|backport| B

小结

你现在掌握了团队协作的核心技能:

  • Fork vs Clone的使用场景
  • Pull Request完整流程
  • 代码审查的最佳实践
  • 解决PR冲突
  • 配置分支保护和CI/CD
  • 多人协作常见问题解决

下一期,我们将进入高级主题——Git钩子和自动化。你会学到如何在commit/push时自动检查代码、运行测试、部署应用。


练习任务

  1. 在GitHub创建一个测试仓库,尝试完整的PR流程
  2. 邀请朋友审查你的PR,练习代码审查对话
  3. 配置一个简单的GitHub Actions,自动运行测试
  4. 尝试在PR中制造冲突并解决

下期预告:《Git高级:钩子与自动化》—— pre-commit怎么配置?如何自动部署?Husky和lint-staged怎么用?

Views: 28

Git分支管理:在平行宇宙中优雅开发

Git分支管理:在平行宇宙中优雅开发

在上一期,我们学会了Git的基本操作。你可能会想:不就是存代码历史嘛,为什么要搞得这么复杂?

答案就在于分支。分支是Git最强大的特性,它允许你在不影响主线的情况下,创建一个平行的开发线,自由实验、开发新功能、修复bug。当你完成工作后,再把分支合并回去。

这就像在写小说时,你想尝试一个大胆的剧情转折。你不需要直接改原文,而是复制一份,在新文件里尽情发挥。如果写得好,就把新版本作为正式版;如果写得烂,直接删掉,原文丝毫不受影响。

分支的本质

在深入之前,先理解分支的本质。

Git的提交不是孤立的,每个提交都包含一个指针,指向上一个提交(父提交)。这样一串提交就形成了一条链。

graph LR
    A[提交1] --> B[提交2] --> C[提交3] --> D[提交4]

分支本质上只是一个指向某个提交的可移动指针。默认分支叫main(以前叫master)。

HEAD是一个特殊指针,指向当前所在的分支。

graph TB
    HEAD --> main
    main --> D[提交4]
    D --> C[提交3] --> B[提交2] --> A[提交1]

当你创建新分支时,Git只是创建了一个新指针,指向当前提交。仓库本身没有变化,快到飞起。

graph TB
    HEAD --> main
    main --> D[提交4]
    feature --> D
    D --> C[提交3] --> B[提交2] --> A[提交1]

分支基本操作

创建分支

# 创建分支(停留在当前分支)
git branch feature-login

# 创建并切换
git checkout -b feature-login

# 新语法(推荐)
git switch -c feature-login

切换分支

# 老语法
git checkout feature-login

# 新语法(推荐)
git switch feature-login

查看分支

# 查看本地分支
git branch

# 查看所有分支(包括远程)
git branch -a

# 查看分支及其最后一次提交
git branch -v

删除分支

# 删除已合并的分支
git branch -d feature-login

# 强制删除(未合并也删)
git branch -D feature-login

重命名分支

# 重命名当前分支
git branch -m new-name

# 重命名指定分支
git branch -m old-name new-name

分支工作流

Feature Branch工作流

这是最常用的分支策略。每开发一个新功能,就创建一个分支,开发完成后合并回主线。

# 1. 从main创建功能分支
git checkout main
git pull
git checkout -b feature-user-profile

# 2. 开发中...频繁提交
git add .
git commit -m "feat: 添加用户头像上传"

git add .
git commit -m "feat: 添加用户简介编辑"

# 3. 开发完成,合并回main
git checkout main
git pull  # 先更新main
git merge feature-user-profile

# 4. 删除功能分支
git branch -d feature-user-profile

Git Flow工作流

更复杂的团队协作模型,定义了几种分支类型:

  • main:生产环境代码,永远是稳定的
  • develop:开发分支,集成各个功能
  • **feature/***:功能分支,从develop分出,合并回develop
  • **release/***:发布分支,从develop分出,准备发布
  • **hotfix/***:紧急修复分支,从main分出,合并回main和develop
gitGraph
    commit id: "init"
    branch develop
    checkout develop
    commit id: "dev1"
    branch feature-A
    checkout feature-A
    commit id: "feat1"
    commit id: "feat2"
    checkout develop
    merge feature-A id: "merge-A"
    checkout main
    branch hotfix
    checkout hotfix
    commit id: "fix"
    checkout main
    merge hotfix id: "hotfix-merge"
    checkout develop
    merge hotfix

小团队不需要这么复杂,Feature Branch足够用了。

合并分支

快进合并(Fast-forward)

如果main分支在你分出feature后没有任何新提交,Git会直接把main指针移到feature的最新提交。

git checkout main
git merge feature-login
# 输出:Fast-forward

这种合并不产生新的提交节点,历史是线性的。

三方合并(Three-way merge)

如果main分支有了新提交,Git会找到两个分支的共同祖先,做一个三方合并,产生一个新的合并提交。

git checkout main
git merge feature-login
# 输出:Merge made by the 'recursive' strategy.
graph TB
    subgraph 合并前
    A[共同祖先] --> B[main新提交]
    A --> C[feature提交]
    end
graph TB
    subgraph 合并后
    A[共同祖先] --> B[main新提交]
    A --> C[feature提交]
    B --> D[合并提交]
    C --> D
    end

禁用快进合并

有时候你想保留分支历史,即使是快进合并也产生一个合并节点:

git merge --no-ff feature-login

这样历史会更清晰地显示"这里曾经有个分支"。

冲突解决

这是新手最害怕的部分。当两个分支修改了同一文件的同一行,Git无法自动合并,就会产生冲突。

模拟冲突

# 分支1修改readme.md第一行
echo "Version A" > readme.md
git add readme.md
git commit -m "Version A"

# 切回main,也修改第一行
git checkout main
echo "Version B" > readme.md
git add readme.md
git commit -m "Version B"

# 尝试合并
git merge feature-xxx
# 冲突!

Git会告诉你哪些文件冲突了:

CONFLICT (content): Merge conflict in readme.md
Automatic merge failed; fix conflicts and then commit the result.

打开冲突文件,你会看到:

<<<<<<>>>>>> feature-xxx
  • <<<<<<>>>>>> feature-xxx:要合并的分支内容

手动解决冲突

  1. 删除标记符号
  2. 保留正确的内容(或两者都保留)
  3. 保存文件
  4. git add + git commit
# 解决后
echo "Version A and B combined" > readme.md
git add readme.md
git commit -m "merge: 解决readme冲突"

使用合并工具

# 使用配置的合并工具(如VSCode)
git mergetool

放弃合并

git merge --abort

变基(Rebase)

merge会产生分叉的历史,有些人喜欢线性的历史。这时候可以用rebase。

merge vs rebase

gitGraph
    commit id: "A"
    commit id: "B"
    branch feature
    checkout feature
    commit id: "C"
    commit id: "D"
    checkout main
    commit id: "E"

用merge

gitGraph
    commit id: "A"
    commit id: "B"
    branch feature
    checkout feature
    commit id: "C"
    commit id: "D"
    checkout main
    commit id: "E"
    merge feature id: "M"

用rebase

gitGraph
    commit id: "A"
    commit id: "B"
    commit id: "E"
    commit id: "C'"
    commit id: "D'"
# 在feature分支上执行
git checkout feature
git rebase main

rebase会把feature上的提交"移到"main的最新提交之后,历史变成线性的。

黄金法则永远不要rebase已经push到远程的提交。因为这会改写历史,给队友带来灾难。

交互式rebase

# 修改最近3个提交
git rebase -i HEAD~3

这会打开编辑器,你可以:

  • pick:保留提交
  • squash:合并到前一个提交
  • reword:修改提交信息
  • drop:删除提交
  • edit:暂停以便修改这个提交

Stash:临时保存

开发到一半,突然需要切换分支处理紧急事务,但当前工作还没完成,不想commit怎么办?

# 保存当前工作
git stash

# 带描述保存
git stash save "WIP: 用户登录功能"

# 查看stash列表
git stash list

# 恢复最近的stash
git stash pop

# 恢复但不删除
git stash apply

# 恢复指定stash
git stash apply stash@{2}

# 删除stash
git stash drop stash@{0}

# 清空所有stash
git stash clear

Cherry-pick:选择性合并

只想合并某个分支的一个特定提交?用cherry-pick:

# 先在目标分支找到提交hash
git checkout feature-A
git log --oneline
# 假设要合并的提交是 a1b2c3d

# 切回main,cherry-pick
git checkout main
git cherry-pick a1b2c3d

这会把那个提交的改动复制到当前分支,产生一个新的提交。

分支最佳实践

  1. 分支命名规范

    • feature/xxx:新功能
    • bugfix/xxx:bug修复
    • hotfix/xxx:紧急修复
    • release/x.x.x:发布准备
    • experiment/xxx:实验性功能
  2. 及时删除已合并分支

    # 删除本地
    git branch -d feature-xxx
    
    # 删除远程
    git push origin --delete feature-xxx
  3. 保持分支短小

    • 一个分支只做一件事
    • 频繁合并回主线,避免长寿命分支
  4. 提交前先pull

    git checkout main
    git pull --rebase  # 用rebase避免不必要的merge提交
  5. 使用Pull Request / Merge Request
    不要直接在本地合并,通过PR让代码经过review再合并。

小结

你现在掌握了Git分支的核心技能:

  • 理解分支的本质(可移动指针)
  • 创建、切换、删除分支
  • 合并分支(快进和三方合并)
  • 解决合并冲突
  • 使用rebase保持线性历史
  • stash临时保存工作
  • cherry-pick选择性合并

下一期,我们将进入团队协作。你会学到如何用Git在团队中高效工作,包括Pull Request流程、代码审查、多人协作的最佳实践。


练习任务

  1. 创建一个feature分支,提交几次后合并回main
  2. 制造一个冲突并手动解决
  3. 尝试git rebase -i合并最近2个提交
  4. 用stash保存当前工作,切换分支后再恢复

下期预告:《Git协作:团队开发流程》—— Pull Request怎么做?代码审查看什么?多人协作怎么避免灾难?

Views: 14

Git入门指南:从零开始掌握版本控制

Git入门指南:从零开始掌握版本控制

Git Logo

你有没有经历过这样的噩梦?项目文件夹里到处是 最终版.doc最终版2.doc打死不改版.doc真的最后版.doc...每次回滚代码都要手动复制备份,团队协作时互相覆盖文件,谁改了什么完全不知道。

这就是没有版本控制的痛。而Git,就是终结这一切的利器。

什么是版本控制?

想象你在写一本小说,每写完一章就保存一个副本。突然你发现第三章的情节有问题,想回到第二章重新写。如果没有版本控制,你只能手动翻备份文件夹,祈祷自己当时保存了。

版本控制系统就像是给项目装了一个时光机。它记录了每次修改的快照,你可以随时回到任意历史版本,查看谁在什么时候改了什么,甚至可以创建平行世界(分支)来尝试不同的剧情走向。

为什么是Git?

2005年,Linux内核开发社区遭遇了一场危机:他们使用的专有版本控制系统BitKeeper不再免费提供。Linux之父Linus Torvalds在短短两周内开发出了Git的初始版本。

Git的设计哲学很简单:快、简单、支持非线性开发(成千上万个并行分支)、完全分布式。这些特性让它迅速成为全球最流行的版本控制系统。今天,从Google到Microsoft,从Facebook到阿里巴巴,几乎每家科技公司都在用Git。

安装Git

Windows用户
从官网下载安装包(https://git-scm.com/download/win),一路下一步即可。安装完成后,右键菜单会多出"Git Bash Here"选项,这就是你的Git命令行工具。

Mac用户
最简单的方式是安装Xcode Command Line Tools:

xcode-select --install

或者用Homebrew:

brew install git

Linux用户
Debian/Ubuntu:

sudo apt-get install git

CentOS/RHEL:

sudo yum install git

安装完成后,验证一下:

git --version

看到版本号就说明安装成功了。

第一次配置

Git需要知道你是谁,因为每次提交都会记录作者信息。打开终端,运行:

git config --global user.name "你的名字"
git config --global user.email "你的邮箱"

这里的名字和邮箱最好和你的GitHub/GitLab账号一致,这样后续协作会更方便。

查看配置:

git config --list

创建你的第一个仓库

方式一:初始化新仓库

创建一个新项目文件夹,进入后执行:

mkdir my-first-project
cd my-first-project
git init

这时候Git会在当前目录创建一个隐藏的.git文件夹,所有版本信息都存在这里。

方式二:克隆已有仓库

如果项目已经存在于远程(比如GitHub),直接克隆:

git clone https://github.com/username/repo.git

理解Git的三个区域

这是理解Git最关键的概念。Git有三个逻辑区域:

  1. 工作区(Working Directory):你看到的文件,正在编辑的地方
  2. 暂存区(Staging Area/Index):准备提交的修改,像购物车
  3. 版本库(Repository):已提交的历史记录,像仓库
graph LR
    A[工作区] -->|git add| B[暂存区]
    B -->|git commit| C[版本库]
    C -->|git checkout| A

为什么需要暂存区?

假设你修改了三个文件:A、B、C。其中A和B是同一个功能,C是另一个功能。你可以把A和B先add到暂存区,commit成一个提交;然后再add C,commit成另一个提交。这样提交历史就很清晰,而不是把所有修改混在一起。

日常操作流程

1. 查看状态

git status

这是最常用的命令,告诉你哪些文件被修改了,哪些在暂存区,哪些还没被跟踪。

2. 添加到暂存区

# 添加单个文件
git add filename.txt

# 添加所有修改
git add .

# 添加所有修改(包括删除)
git add -A

3. 提交到版本库

git commit -m "简洁的提交信息"

提交信息很重要!好的提交信息应该回答:做了什么修改?为什么这样修改?

4. 查看历史

# 完整历史
git log

# 简洁版(一行一个提交)
git log --oneline

# 图形化显示分支
git log --oneline --graph --all

5. 查看差异

# 工作区 vs 暂存区
git diff

# 暂存区 vs 最新提交
git diff --staged

# 两个提交之间
git diff commit1 commit2

撤销操作(救你于水火)

撤销工作区修改

# 丢弃单个文件的修改(危险操作!)
git checkout -- filename.txt

# 或者用新语法
git restore filename.txt

撤销暂存

# 把文件从暂存区移回工作区
git reset HEAD filename.txt

# 或者用新语法
git restore --staged filename.txt

修改最后一次提交

# 还没push,发现提交信息写错了
git commit --amend -m "正确的提交信息"

# 还没push,漏了一个文件
git add forgotten-file.txt
git commit --amend --no-edit

注意--amend会改写历史,如果已经push了就不要用,否则会给队友带来麻烦。

忽略文件

有些文件不需要纳入版本控制,比如编译产物、日志文件、IDE配置等。在项目根目录创建.gitignore文件:

# 编译产物
*.o
*.exe
build/

# 日志
*.log

# IDE配置
.idea/
.vscode/

# 系统文件
.DS_Store
Thumbs.db

# 依赖目录
node_modules/
.venv/

GitHub有个awesome-gitignore仓库,收集了各种项目的.gitignore模板,值得收藏。

远程仓库

关联远程仓库

# 添加远程仓库
git remote add origin https://github.com/username/repo.git

# 查看远程仓库
git remote -v

推送代码

# 第一次推送(设置上游分支)
git push -u origin main

# 之后推送
git push

拉取代码

# 拉取并合并
git pull

# 只拉取不合并
git fetch

git pull = git fetch + git merge。建议先fetch看看有什么变化,再决定要不要merge。

SSH配置(告别密码)

每次push都要输入密码很烦?配置SSH密钥:

# 生成密钥对
ssh-keygen -t ed25519 -C "你的邮箱"

# 查看公钥
cat ~/.ssh/id_ed25519.pub

把公钥复制到GitHub的Settings → SSH Keys。然后把远程地址改成SSH格式:

git remote set-url origin git@github.com:username/repo.git

现在push再也不用输密码了。

小结

恭喜你,掌握了Git的基础用法。你现在可以:

  • 创建和管理仓库
  • 理解工作区、暂存区、版本库
  • 进行日常的add、commit、push、pull操作
  • 撤销误操作
  • 配置.gitignore和SSH

但这只是Git冰山一角。下一期,我们将深入分支管理——Git最强大的功能之一。你会学会如何创建平行宇宙,在不同的开发线之间自由穿梭,最后把它们完美合并。


练习任务

  1. 创建一个新仓库,提交至少3次
  2. 尝试修改文件后用git checkout撤销
  3. 故意add一个文件,然后用git reset HEAD撤销暂存
  4. 在GitHub创建仓库,把本地代码push上去

做完这些,你就真正入门Git了。


下期预告:《Git进阶:分支管理艺术》—— 什么时候该开分支?如何优雅地合并?冲突了怎么办?

Views: 26

RHEL9 系统中 Apache HTTP 服务器入门实战指南

写在前面

🚀 RHEL9 Apache 入门实战

从零开始搭建企业级 Web 服务器

如果你是第一次接触 Web 服务器,不用担心!这篇文章会像教朋友一样,一步一步带你完成 Apache 的安装和配置。每一步都有详细说明,遇到问题也有解决方案。

你需要准备的东西:

  • 一台安装了 RHEL9(或 Rocky Linux 9、AlmaLinux 9)的服务器
  • 有 root 权限(或者能用 sudo)
  • 能联网(需要下载软件包)

学完你能做到:

  • 搭建一个可以访问的网站
  • 配置多个网站在同一台服务器上
  • 让网站支持 HTTPS 安全访问
  • 知道出了问题怎么排查

一、什么是 Apache?为什么选它?

Apache 就像是一个"网站管家",当有人在浏览器输入你的网址时,Apache 会把网页内容发送给他们。

为什么企业都喜欢用 Apache?

  • 稳定可靠:运行 20+ 年的老牌软件,久经考验
  • 免费开源:不用花一分钱
  • 功能强大:支持虚拟主机、HTTPS、反向代理等
  • 文档齐全:遇到问题很容易找到解决方案

RHEL9 是什么?
RHEL9(Red Hat Enterprise Linux 9)是红帽公司推出的企业级 Linux 系统,Rocky Linux 9 和 AlmaLinux 9 都是它的免费替代版本,操作方法完全一样。

  • 有 root 权限(或者能用 sudo)
  • 能联网(需要下载软件包)

学完你能做到:

  • 搭建一个可以访问的网站
  • 配置多个网站在同一台服务器上
  • 让网站支持 HTTPS 安全访问
  • 知道出了问题怎么排查

一、什么是 Apache?为什么选它?

Apache 就像是一个"网站管家",当有人在浏览器输入你的网址时,Apache 会把网页内容发送给他们。

为什么企业都喜欢用 Apache?

  • 稳定可靠:运行 20+ 年的老牌软件,久经考验
  • 免费开源:不用花一分钱
  • 功能强大:支持虚拟主机、HTTPS、反向代理等
  • 文档齐全:遇到问题很容易找到解决方案

RHEL9 是什么?
RHEL9(Red Hat Enterprise Linux 9)是红帽公司推出的企业级 Linux 系统,Rocky Linux 9 和 AlmaLinux 9 都是它的免费替代版本,操作方法完全一样。


二、安装 Apache

2.1 先检查系统版本

打开终端,输入这个命令:

cat /etc/redhat-release

你会看到类似这样的输出:

Red Hat Enterprise Linux release 9.3 (Plow)

💡 小提示:如果你看到的是 Rocky Linux 或 AlmaLinux,完全没问题,步骤一模一样!

2.2 安装 httpd 软件包

在 RHEL9 中,Apache 的软件包名字叫 httpd。用这个命令安装:

# 使用 dnf 包管理器安装
sudo dnf install -y httpd

命令解释:

  • sudo:用管理员权限运行
  • dnf:RHEL9 的包管理器(类似手机的应用商店)
  • install:安装
  • -y:自动回答"是",不用手动确认
  • httpd:Apache 的软件包名

安装完成后,检查版本:

httpd -v

你会看到:

Server version: Apache/2.4.xx (Red Hat Enterprise Linux)

✅ 恭喜!Apache 已经安装好了!

2.3 启动 Apache 服务

安装好了还不够,要"启动"它才能工作:

# 启动 Apache 服务
sudo systemctl start httpd

# 设置开机自动启动
sudo systemctl enable httpd

# 查看服务状态
sudo systemctl status httpd

你会看到这样的输出:

● httpd.service - The Apache HTTP Server
   Loaded: loaded (/usr/lib/systemd/system/httpd.service; enabled)
   Active: active (running) since Thu 2026-02-27 15:00:00 CST; 10s ago

重点看这里:

  • Active: active (running) - 说明服务正在运行 ✅
  • enabled - 说明开机后会自动启动 ✅

💡 如果看到 inactive (dead)failed,往下看"常见问题"部分。


三、配置防火墙(让外网能访问)

3.1 为什么需要配置防火墙?

想象你的服务器是一栋楼,防火墙就是门卫。默认情况下,门卫会拦住所有陌生人。你需要告诉门卫:"HTTP(80端口)和 HTTPS(443端口)的客人可以进来。"

3.2 开放 HTTP 和 HTTPS 端口

# 检查防火墙状态
sudo firewall-cmd --state
# 应该看到:running

# 开放 HTTP(网站默认端口)
sudo firewall-cmd --permanent --add-service=http

# 开放 HTTPS(安全端口,后面会用到)
sudo firewall-cmd --permanent --add-service=https

# 重载防火墙配置(让设置生效)
sudo firewall-cmd --reload

# 验证规则是否生效
sudo firewall-cmd --list-services

你会看到:

ssh http https

命令解释:

  • --permanent:永久生效,重启后不会丢
  • --add-service=http:添加 HTTP 服务规则
  • --reload:重新加载配置

✅ 现在外网可以访问你的网站了!


四、创建你的第一个网页

4.1 Apache 的网站目录

Apache 默认把网站文件放在 /var/www/html/ 目录下。这就像你的"网站仓库",所有网页都要放这里。

# 查看 Apache 的默认目录
ls -la /var/www/html/

💡 刚安装完,这个目录是空的,没关系!

4.2 创建一个简单的测试页面

# 创建首页文件
echo "<h1>我的第一个网站!</h1>" | sudo tee /var/www/html/index.html

# 设置正确的权限(重要!)
sudo chown apache:apache /var/www/html/index.html
sudo chmod 644 /var/www/html/index.html

命令解释:

  • chown apache:apache:把文件所有者改为 apache 用户
  • chmod 644:设置文件权限(所有者可读写,其他人只读)

4.3 测试访问

现在打开浏览器,输入你的服务器 IP 地址:

http://你的服务器IP/

你会看到:

我的第一个网站!

✅ 恭喜!你的网站已经上线了!

💡 如果看不到这个页面,检查:

  1. 防火墙是否开放了 80 端口
  2. Apache 服务是否在运行
  3. 云服务商的安全组是否开放了 80 端口

五、配置 SELinux(企业级安全)

5.1 什么是 SELinux?

SELinux 是 RHEL9 的安全增强系统,它像一个严格的安检员,会检查每个操作是否合法。

为什么要学 SELinux?

  • 企业环境必须开启 SELinux
  • 配置错误会导致网站无法访问
  • 掌握 SELinux 是运维工程师的必备技能

5.2 检查 SELinux 状态

# 查看 SELinux 是否开启
getenforce

可能的输出:

  • Enforcing:开启状态(推荐)✅
  • Permissive:宽容模式(只记录不阻止)
  • Disabled:关闭状态(不推荐)❌

⚠️ 不要关闭 SELinux!学会正确配置才是正道。

5.3 配置 Apache 的 SELinux 权限

# 查看 Apache 相关的 SELinux 布尔值
getsebool -a | grep httpd

常用设置:

# 允许 Apache 连接网络(反向代理需要)
sudo setsebool -P httpd_can_network_connect 1

# 允许 Apache 发送邮件
sudo setsebool -P httpd_can_sendmail 1

# 允许 Apache 访问用户主目录
sudo setsebool -P httpd_enable_homedirs 1

5.4 设置网站目录的 SELinux 上下文

这是最容易出错的地方!

# 为网站目录设置正确的上下文
sudo semanage fcontext -a -t httpd_sys_content_t "/var/www/html(/.*)?"
sudo restorecon -Rv /var/www/html

命令解释:

  • httpd_sys_content_t:Apache 可以读取的文件类型
  • restorecon:重新应用 SELinux 上下文

💡 记住这个命令,每次创建新网站目录都要执行!

5.5 SELinux 排错技巧

如果网站访问不了,这样查:

# 查看 SELinux 拒绝日志
sudo ausearch -m avc -ts recent | grep httpd

# 如果看到很多拒绝记录,可以用这个工具生成策略
sudo ausearch -c 'httpd' --raw | audit2allow -M my-httpd
sudo semodule -i my-httpd.pp

⚠️ 注意:只在测试环境用 audit2allow,生产环境要分析具体原因。


六、虚拟主机配置(一台服务器托管多个网站)

6.1 什么是虚拟主机?

虚拟主机就像一栋楼里有多个房间,每个房间(网站)都有独立的门牌号(域名),但都共用同一栋楼(服务器)。

应用场景:

  • 公司有多个网站,但只有一台服务器
  • 开发环境和测试环境分开
  • 节省服务器成本

6.2 创建网站目录

假设你要托管 example.com 这个网站:

# 创建网站目录结构
sudo mkdir -p /var/www/example.com/public_html
sudo mkdir -p /var/www/example.com/logs

# 创建测试页面
echo "<h1>欢迎访问 example.com</h1>" | sudo tee /var/www/example.com/public_html/index.html

# 设置权限
sudo chown -R apache:apache /var/www/example.com
sudo chmod -R 755 /var/www/example.com

目录结构说明:

/var/www/example.com/
├── public_html/    # 网站文件目录
└── logs/           # 日志目录

6.3 创建虚拟主机配置文件

# 创建配置文件
sudo vim /etc/httpd/conf.d/example.com.conf

粘贴以下内容:


    # 管理员邮箱
    ServerAdmin webmaster@example.com

    # 网站域名
    ServerName example.com
    ServerAlias www.example.com

    # 网站文件目录
    DocumentRoot /var/www/example.com/public_html

    # 日志配置
    ErrorLog /var/www/example.com/logs/error.log
    CustomLog /var/www/example.com/logs/access.log combined

    # 目录权限配置
    
        Options -Indexes +FollowSymLinks
        AllowOverride All
        Require all granted
    

配置解释:

  • ServerName:主域名
  • ServerAlias:别名(可以多个)
  • DocumentRoot:网站文件位置
  • Options -Indexes:禁止目录列表(安全)
  • AllowOverride All:允许 .htaccess 文件

6.4 测试配置并重启

# 测试配置语法(重要!)
sudo apachectl configtest

看到 Syntax OK 才能继续!

# 重启 Apache
sudo systemctl restart httpd

6.5 配置 SELinux 上下文

这一步不能少,否则网站无法访问!

# 为新网站设置 SELinux 上下文
sudo semanage fcontext -a -t httpd_sys_content_t "/var/www/example.com/public_html(/.*)?"
sudo semanage fcontext -a -t httpd_log_t "/var/www/example.com/logs(/.*)?"
sudo restorecon -Rv /var/www/example.com

✅ 现在你可以用 example.com 访问这个网站了!

💡 要添加更多网站,重复 6.2-6.5 步骤即可。


七、配置 HTTPS(安全访问)

7.1 为什么需要 HTTPS?

  • 安全:加密传输,防止数据被窃取
  • 信任:浏览器显示小锁图标
  • SEO:搜索引擎更喜欢 HTTPS 网站
  • 必须:很多功能(如 PWA)要求 HTTPS

7.2 安装 SSL 模块

# 安装 mod_ssl
sudo dnf install -y mod_ssl

7.3 生成自签名证书(测试用)

⚠️ 测试环境用自签名证书,生产环境要用正式证书(如 Let's Encrypt)。

# 生成私钥和证书
sudo openssl req -x509 -nodes -days 365 -newkey rsa:2048 \
  -keyout /etc/pki/tls/private/example.com.key \
  -out /etc/pki/tls/certs/example.com.crt

按提示填写信息:

Country Name: CN
State: Beijing
Locality: Beijing
Organization: Example Company
Organizational Unit: IT
Common Name: example.com
Email: webmaster@example.com

💡 Common Name 一定要填你的域名!

7.4 配置 HTTPS 虚拟主机

编辑配置文件:

sudo vim /etc/httpd/conf.d/ssl.conf

找到 `` 部分,修改为:


    ServerName example.com
    DocumentRoot /var/www/example.com/public_html

    SSLEngine on
    SSLCertificateFile /etc/pki/tls/certs/example.com.crt
    SSLCertificateKeyFile /etc/pki/tls/private/example.com.key

    ErrorLog /var/www/example.com/logs/ssl_error.log
    CustomLog /var/www/example.com/logs/ssl_access.log combined

7.5 重启并测试

# 测试配置
sudo apachectl configtest

# 重启服务
sudo systemctl restart httpd

现在访问:

https://example.com/

💡 浏览器会提示"证书不安全",这是因为自签名证书。生产环境用 Let's Encrypt 就不会有这个提示。

7.6 HTTP 自动跳转到 HTTPS

让用户访问 HTTP 自动跳转到 HTTPS:

sudo vim /etc/httpd/conf.d/example.com.conf

在文件开头添加:


    ServerName example.com
    Redirect permanent / https://example.com/

重启服务:

sudo systemctl restart httpd

✅ 现在访问 http://example.com 会自动跳转到 https://example.com


八、常见问题排查

问题 1:网站打不开(403 Forbidden)

可能原因:

  1. 文件权限不对
  2. SELinux 阻止
  3. Apache 配置限制

排查步骤:

# 1. 检查文件权限
ls -la /var/www/html/

# 2. 检查 SELinux 上下文
ls -laZ /var/www/html/

# 3. 查看 Apache 错误日志
sudo tail -f /var/log/httpd/error_log

解决方法:

# 修复权限
sudo chown -R apache:apache /var/www/html
sudo chmod -R 755 /var/www/html

# 修复 SELinux
sudo restorecon -Rv /var/www/html

问题 2:Apache 服务无法启动

排查步骤:

# 检查配置语法
sudo apachectl configtest

# 查看详细错误
sudo journalctl -xeu httpd

# 检查端口占用
sudo netstat -tlnp | grep :80

常见错误:

  • Syntax error:配置文件写错了
  • Address already in use:80 端口被占用
  • Permission denied:权限不足

问题 3:SELinux 阻止访问

症状:

  • 网站文件存在,但访问 403
  • 日志显示 Permission denied
  • 关闭 SELinux 后正常

正确做法:

# 1. 查看 SELinux 拒绝日志
sudo ausearch -m avc -ts recent | grep httpd

# 2. 查看 Apache 的 SELinux 布尔值
getsebool -a | grep httpd

# 3. 检查文件上下文
ls -laZ /var/www/html/

# 4. 修复上下文
sudo semanage fcontext -a -t httpd_sys_content_t "/var/www/html(/.*)?"
sudo restorecon -Rv /var/www/html

⚠️ 不要简单地 setenforce 0,这是逃避问题!

问题 4:防火墙阻止访问

症状:

  • 本地可以访问(curl localhost
  • 外网无法访问
  • 浏览器一直转圈

排查步骤:

# 查看防火墙规则
sudo firewall-cmd --list-all

# 检查端口是否开放
sudo firewall-cmd --query-service=http

# 查看端口监听
sudo netstat -tlnp | grep :80

解决方法:

# 开放 HTTP
sudo firewall-cmd --permanent --add-service=http
sudo firewall-cmd --reload

💡 云服务器还要检查安全组规则!


九、性能优化建议

9.1 调整 MPM(多进程模块)

RHEL9 的 Apache 默认使用 event MPM,性能更好:

# 查看当前 MPM
sudo apachectl -V | grep MPM

编辑配置:

sudo vim /etc/httpd/conf.modules.d/00-mpm.conf

调整参数:


    ServerLimit             16
    StartServer             2
    MaxRequestWorkers      150
    MinSpareThreads         25
    MaxSpareThreads         75
    ThreadsPerChild         25
    MaxConnectionsPerChild   0

参数说明:

  • MaxRequestWorkers:最大并发连接数
  • ThreadsPerChild:每个进程的线程数
  • ServerLimit:最大进程数

9.2 启用压缩

sudo vim /etc/httpd/conf.d/compression.conf

    AddOutputFilterByType DEFLATE text/html text/plain text/xml
    AddOutputFilterByType DEFLATE text/css text/javascript
    AddOutputFilterByType DEFLATE application/javascript application/json

好处: 减少传输数据量,加快加载速度。

9.3 启用缓存


    CacheQuickHandler off
    CacheLock on
    CacheLockPath /tmp/cachelock
    CacheLockMaxAge 5

十、安全加固

10.1 隐藏版本信息

sudo vim /etc/httpd/conf/httpd.conf

添加:

ServerTokens Prod
ServerSignature Off

效果: HTTP 响应头只显示 Server: Apache,不显示版本号。

10.2 限制请求大小

防止恶意的大文件上传:

LimitRequestBody 10485760
LimitRequestFields 50
LimitRequestFieldSize 8190
LimitRequestLine 8190

10.3 使用 ModSecurity(Web 应用防火墙)

# 安装 ModSecurity
sudo dnf install -y mod_security mod_security_crs

# 启用规则
sudo mv /etc/httpd/modsecurity.d/activated_rules/modsecurity_crs_10_setup.conf.example \
       /etc/httpd/modsecurity.d/activated_rules/modsecurity_crs_10_setup.conf

# 重启服务
sudo systemctl restart httpd

功能: 自动防御 SQL 注入、XSS 等攻击。


十一、实用命令速查表

# ========== 服务管理 ==========
sudo systemctl start httpd      # 启动
sudo systemctl stop httpd       # 停止
sudo systemctl restart httpd    # 重启
sudo systemctl reload httpd     # 优雅重启(不中断连接)
sudo systemctl status httpd     # 查看状态

# ========== 配置测试 ==========
sudo apachectl configtest       # 测试配置语法
sudo apachectl -S               # 查看虚拟主机配置
sudo apachectl -M               # 查看已加载模块
sudo apachectl -V               # 查看编译参数

# ========== 日志查看 ==========
sudo tail -f /var/log/httpd/access_log   # 访问日志
sudo tail -f /var/log/httpd/error_log    # 错误日志

# ========== SELinux ==========
getenforce                     # 查看状态
getsebool -a | grep httpd      # 查看布尔值
sudo restorecon -Rv /var/www   # 恢复上下文

# ========== 防火墙 ==========
sudo firewall-cmd --list-all   # 查看规则
sudo firewall-cmd --reload     # 重载配置

# ========== 性能测试 ==========
ab -n 1000 -c 10 http://localhost/   # 压力测试

十二、总结

恭喜你完成了 Apache 的完整学习!让我们回顾一下学到了什么:

核心知识点

  1. 安装配置 - dnf install、systemctl start/enable
  2. 防火墙 - firewall-cmd 开放端口
  3. SELinux - 上下文配置、布尔值设置
  4. 虚拟主机 - 一台服务器托管多个网站
  5. HTTPS - SSL 证书配置、自动跳转
  6. 性能优化 - MPM 调整、压缩、缓存
  7. 安全加固 - 版本隐藏、ModSecurity

学习建议

  • 多动手:实践是最好的老师
  • 看日志:出问题先看 /var/log/httpd/error_log
  • 别怕错:SELinux 和防火墙确实复杂,慢慢就熟练了
  • 记笔记:把常用命令和踩过的坑记下来

进阶方向

  • Let's Encrypt:免费 SSL 证书
  • 反向代理:配合 Nginx 使用
  • 负载均衡:多服务器集群
  • 容器化:Docker + Kubernetes

参考资源


遇到问题? 欢迎在评论区留言,我会尽力帮你解决!

觉得有用? 点个赞,让更多人看到!

Views: 13