跳转至

05 高级Git技巧

分支策略(Git Flow, GitHub Flow)

在编程的高级巫术中,有效的分支策略是保持魔法(代码)秩序和高效率的关键。每个团队都需要一个清晰的路线图来指导他们如何编织(合并)和分割(创建)分支,以及如何将新的魔法(功能)安全地引入到主法典(生产代码)中。让我们探讨两种流行的分支策略:Git FlowGitHub Flow

Git Flow: 分支巫术的经典之路

Git Flow
├───特色分支的系统化使用
└───适用于定期发布周期的项目
Git Flow 是一种围绕项目发布管理的复杂分支模型。它定义了一个固定的分支结构,包括:

  • master 分支:稳定的,随时准备发布的代码。
  • develop 分支:用于日常开发的主要分支。
  • feature 分支:用于开发新功能的分支,从 develop 分支出发,完成后合并回去。
  • release 分支:当准备下一个版本发布时创建,用于最终的调试和优化。
  • hotfix 分支:用于从 master 分支紧急修复生产问题。 这种策略非常适合有固定发布周期的大型项目,因为它非常注重维护稳定的生产版本。

GitHub Flow: 更加流畅的魔法之流

GitHub Flow
├───简洁直观的分支模型
└───适用于持续部署和快速迭代的项目
GitHub Flow 是一种更简单、更直观的分支策略。它鼓励团队采用以下流程:

任何新的工作都在基于 master 分支的新分支上进行。 新分支应该有描述性的名称来反映其目的。 提交更改后,及早打开一个拉取请求(pull request),并在团队中进行讨论。 一旦完成讨论并通过测试,就将变更合并到 master 分支。 一旦合并到 master,立即部署到生产环境。 GitHub Flow 的核心在于简化,它支持团队快速迭代和持续集成/持续部署(CI/CD)的实践。

小结

选择合适的分支策略对于保持代码库的清晰和项目的顺利进行至关重要。Git Flow 提供了一个结构化的模型,适合需要严格管理的项目。相比之下,GitHub Flow 则更加灵活、快速,适合持续部署的环境。每种策略都有其魔法之处,但最重要的是选择一种符合你团队特定需求和工作流的策略。掌握这些高级的分支巫术,你将能够更加自信地在编程的世界中导航,无论是平静的河流还是波涛汹涌的大海。

交互式提交(Interactive Rebase)

在巫师的世界里,交互式提交(Interactive Rebase)是一种强大的魔法,允许高级巫师精细地调整他们的魔法历史(提交历史)。这个过程就像是在时间的河流中穿行,悄悄地调整过去的事件,使魔法书(代码库)的叙述更加流畅和有逻辑。

启动交互式提交

git rebase -i <base-commit>
启动交互式提交的咒语是 git rebase -i,其中 -i 表示 interactive。你需要指定一个基础提交,它是你想要开始调整历史的起点。巫师们会被带到一个可以操作历史的特殊工坊(文本编辑器)。

在工坊里重新编排历史

在工坊里,你将看到一系列的提交列表,每个提交前面都有命令选项: - pick:保留该提交(默认操作) - reword:保留提交的更改,但修改提交信息 - edit:在进行该提交后暂停,以便添加新的更改或修正 - squash:将该提交与前一个提交合并 - fixup:与 squash 类似,但会丢弃该提交的日志信息 - drop:完全删除该提交 通过编辑每个提交前的命令,巫师们可以重新编排他们的历史,选择保留、修改、合并或删除某些事件。

实施历史上的变化

一旦完成了历史的重新编排,巫师们将保存并关闭编辑器,魔法就会开始施展。Git 将按照你的指示重新应用提交,这可能会导致时间线上的冲突。

解决时间线冲突

如果在重新应用提交时遇到冲突,Git 会暂停操作并要求你解决这些冲突。你需要手动编辑文件来解决冲突,然后使用以下命令继续魔法:

git add <file>
git rebase --continue
如果你想要取消整个变化过程并返回到开始之前的状态,可以使用:
git rebase --abort

小结

交互式提交是一种强大的工具,让巫师们可以清理他们的魔法历史,使其更加整洁和有序。它特别适用于在公开展示魔法之前整理个人或小团队的工作。然而,对于已经公开的魔法历史,使用这种咒语需要极度谨慎,因为它可以改变时间的本质。正确地使用这种高级魔法,你的魔法书将成为一个光辉历程,清晰地展示了你魔法旅途的每一步。

Cherry-picking

在魔法世界的历史编织中,有时巫师们需要从广阔的时间线上精准地挑选出某些特定的事件,就像在巨大的魔法果园中挑选最甜的果实一样。这种巧妙的技艺被称为 Cherry-picking,在 Git 中,它允许我们选择性地将某个分支上的提交应用到当前分支。

什么是 Cherry-picking

Cherry-picking
├───选择并复制特定的提交到当前分支
└───不影响其他分支的历史
通过 Cherry-picking,巫师们可以将一个分支上的魔法(更改)复制到他们当前所在的分支上,而不必合并整个分支的历史。这是一个非常有用的技能,尤其是当你只想引入一个特定的功能或修复,而不想打乱你当前魔法书的结构时。

如何进行 Cherry-picking

git cherry-pick <commit-hash>
施展这个咒语前,你需要准确知道你想要复制的魔法的唯一标识符——提交的哈希值。一旦你发现了这个魔法果实,使用 git cherry-pick 咒语,Git 将会复制那个特定的提交到你当前的分支上。

处理合并冲突

就像在果园中一样,有时候你会发现你挑选的果实(提交)可能不完全适合你的篮子(分支)。这时候,可能会出现冲突。如果在 Cherry-picking 的过程中遇到冲突,Git 会暂停操作,等待你解决这些冲突。

## 解决冲突后
git add <file>
git cherry-pick --continue
解决完冲突并添加了修正后,使用 --continue 选项可以完成 Cherry-picking 的过程。

小结

Cherry-picking 是一种高级且强大的 Git 工具,它提供了极大的灵活性,让你能够精确地控制哪些魔法(更改)被引入到你的魔法书(代码库)中。但是,这种力量也需要谨慎使用,因为它可能会导致分支间的历史出现差异。当正确使用时,Cherry-picking 能够帮助你优雅地维护你的魔法历史,保持故事的连贯性,同时添加必要的魔法改进。

子模块和子树

在巫师的编程领域,有时一个庞大的魔法项目(代码库)需要借用其他项目的力量。这时,巫师们会使用两种古老的魔法——子模块(Submodules)和子树(Subtrees)。这些魔法使得整合外部的魔法书籍(库)变得可能,同时保持主项目的独立性和纯净性。

子模块:独立的魔法书籍

子模块
├───一个独立的项目嵌入到你的主项目中
└───每个子模块都有自己的历史和提交记录
子模块就像是一本独立的魔法书,被放置在你的巨大图书馆(项目)中的一个特殊架子上。这本书有它自己的魔法历史(版本控制历史),而且可以在需要的时候更新它。

添加子模块

git submodule add <repository> <path>
这个咒语将一个外部仓库作为子模块添加到你的项目中。它将克隆外部仓库到指定的路径,并将其作为你的项目的一部分进行跟踪。

更新子模块

git submodule update --remote --merge
当外部仓库有新的魔法(更改)时,你可以使用这个咒语来更新你的子模块。这会拉取最新的更改,并尝试合并它们到当前的子模块中。

子树:合并的魔法枝条

子树
├───将一个项目作为一个分支合并到你的项目中
└───可以选择性地合并外部项目的更改
子树则更像是你的魔法树(项目)上的一个枝条,它和主树共享同一个魔法历史。当你想要合并外部的魔法而不是单纯地链接时,子树是一个很好的选择。

添加子树

git subtree add --prefix=<path> <repository> <branch>
这个咒语将外部项目的特定分支添加到你的项目中的指定路径。它不仅克隆外部项目,还将其历史合并到你的项目中。

拉取子树更改

git subtree pull --prefix=<path> <repository> <branch>
如果外部的魔法书有了更新,你可以使用这个咒语来合并这些新的魔法到你的项目中的子树里。

小结

无论是子模块还是子树,每种方法都有其特定的使用场景。子模块适用于需要保持外部仓库独立性的情况,而子树则适用于希望将外部仓库和主项目更紧密地集成的情况。巫师们必须谨慎选择,因为每种魔法都有其力量和局限性。正确地使用这些高级的魔法,你将能够有效地管理你的魔法组件(代码依赖),并在巨大的魔法项目中保持秩序和谐。

钩子(Hooks)

在魔法世界中,钩子(Hooks)就像是一系列神秘的符咒,它们在特定的魔法仪式(Git 事件)发生时自动触发,执行预先设定的魔法任务。这些自动化的魔法能够在你的编程工作流中起到关键作用,帮助你自动化执行测试、代码检查、通知创建和其他重要的任务。

Git 钩子的种类

Git 钩子分为客户端钩子和服务器端钩子,下面是一些常见的钩子类型:

  • pre-commit:在提交前运行,用于检查即将提交的快照,例如运行测试或代码风格检查。
  • commit-msg:在提交信息被提交前运行,用于验证或格式化提交信息。
  • post-commit:在提交完成后运行,可以用来通知或其他后续操作。
  • pre-push:在 git push 执行前运行,用于运行测试以确保不会推送坏代码。
  • pre-receive:在服务器端接收到推送前运行,用于检查即将进入仓库的提交。

设置和使用钩子

钩子脚本存放在 Git 仓库的 .git/hooks 目录中。启用钩子的一般步骤如下:

  1. 进入 .git/hooks 目录。
  2. 创建或修改你想要设置的钩子脚本。
  3. 确保钩子脚本有执行权限。

示例:设置一个 pre-commit 钩子

cd .git/hooks
touch pre-commit  ## 创建 pre-commit 钩子文件
chmod +x pre-commit  ## 给钩子文件添加执行权限
编辑 pre-commit 文件,输入你的自动化脚本。例如,你可以使用下面的简单 Bash 脚本来检查 Python 代码风格:
#!/bin/sh
## pre-commit

## 检查 Python 代码风格
flake8 .
if [ $? -ne 0 ]; then
    echo "代码风格检查未通过,提交被阻止。"
    exit 1
fi
当你尝试提交时,这个钩子会自动运行 flake8 来检查你的代码风格。如果检查未通过,提交将会被阻止。

小结

钩子是 Git 魔法中的自动化工具,可以显著提高你的开发效率和代码质量。通过合理利用钩子,在适当的时机自动执行重要任务,你可以确保你的魔法仓库(代码库)始终保持在最佳状态。但记住,像任何强大的魔法一样,正确配置和使用钩子是至关重要的,它需要细心的计划和测试,以确保它们正常工作并且对你的工作流产生积极影响。