Git 成长之路:新手到进阶的实用指南

前言

万字长文,全是干货,不看后悔系列。

循序渐进,由表及里,由内而外,给出大量示例,从游戏到魔法,从生活到书本,带你从全新的视角感受Git的暴力美学。

希望通过这篇文章,能够帮你逐步掌握 Git。

耐心看完,你一定有所收获。

正文

1. 确保基础扎实:

1.1 了解 Git 的历史和其设计哲学

学习资料: Git 官方网站 的历史页面,这里提供了 Git 的发展简史

历史:

Git 被创立于 2005 年,由 Linux 的创始人 Linus Torvalds 开发。

当时,Linux 内核开发团队使用的一个专有的版本控制系统与开发者发生了冲突,因此 Linus 决定开发一个新的版本控制系统来替代它。

他的目标是创建一个快速、高效、安全且对非线性开发流程友好的系统,这就是 Git。

设计哲学:

  1. 分布式:与集中式版本控制系统不同,Git 是一个分布式版本控制系统。每个开发者的工作副本都是一个完整的仓库,含有完整的历史记录和版本跟踪能力,不依赖于网络访问或中央服务器。
  2. 完整性:每次提交都有一个唯一的 SHA-1 校验和,确保代码的完整性和一致性。
  3. 速度:Git 设计为高效和速度优先,无论是本地还是网络操作,它都非常快。
  4. 灵活性:Git 支持快速的分支创建和合并,并鼓励用户进行频繁的提交和分支,以保持流动性和协作性。
  5. 安全:使用 SHA-1 来识别和检查对象完整性。
  6. 强调数据的完整性:Git 的设计理念是围绕着保证数据的完整性展开的。它始终确保在任何时候,一旦数据被存入 Git 数据库中,就不会丢失。

这种设计使得 Git 成为一个强大、快速且高效的工具,它能够满足大型和复杂项目的需求。

1.2 确认你理解什么是版本控制,以及为什么我们需要版本控制。

版本控制定义:

版本控制,也被称为源代码管理或者版本管理,是一种记录和管理文件或代码变化的系统,以便在任何时候都可以回到某一个特定的时间点的版本。

这意味着人们可以修改文件或代码,并随时返回到任何之前的状态。

版本控制的重要性:

  1. 追溯历史:版本控制系统允许开发者查看项目历史,了解何时、由谁以及为什么进行的每一次更改。这有助于理解项目的发展脉络和决策背后的原因。
  2. 团队协作:当多人在同一个项目中工作时,版本控制系统确保每个人都可以平稳、无冲突地进行工作。多人对同一个文件的修改会被有效地合并,而不是覆盖。
  3. 版本管理:版本控制允许开发者给软件标记特定的版本号,这样用户和其他开发者可以轻松跟踪和使用软件的不同版本。
  4. 错误恢复:如果新的代码引入了问题或者错误,版本控制系统可以快速地回滚到之前的工作状态,从而进行修复。
  5. 实验与分支:版本控制提供了一个安全的环境,开发者可以在不影响主线开发的基础上进行实验和测试新的想法。
  6. 备份:尽管版本控制的主要目的不是备份,但它为代码和文件提供了多个版本的备份。即使工作副本遭受损坏,开发者仍可以从仓库中恢复工作。

简而言之,版本控制是软件开发的基石。

无论是独立开发者还是大型团队,都依赖于版本控制系统来确保代码的安全、整洁和协作性。

1.3 确保你熟悉 Git 的基本工作流程: init, add, commit, push, pull

这五个命令是 Git 工作流程的核心,它们涵盖了日常开发中的大多数需求。

通过熟练掌握它们,开发者可以高效地进行版本控制和团队协作。

  1. git init:

    • 描述 :这个命令用于在当前目录下初始化一个新的 Git 仓库。它会创建一个名为 .git 的目录来存放所有的仓库数据。
    • 场景:当你开始一个新项目,并决定使用 Git 进行版本控制时,你会首先执行这个命令。
  2. git add:

    • 描述:此命令用于将更改添加到暂存区(也被称为索引)。这是提交更改之前的一个中间步骤,它允许你选择哪些更改(可以是整个文件,也可以是文件的一部分)将被包含在下一次提交中。
    • 场景 :当你修改了文件并准备提交它们时,首先需要执行 git add。例如:git add filename.txt 或者 git add . 来添加所有更改。
  3. git commit:

    • 描述:此命令用于提交暂存区中的更改到仓库。提交后,你的更改就会被永久记录在 Git 的历史中,并附带一个唯一的标识符。
    • 场景 :一旦你已经用 git add 添加了所有想要的更改,你可以使用 git commit -m "描述性的提交信息" 来进行提交。
  4. git push:

    • 描述:此命令用于将你的本地仓库的更改推送到远程仓库。这样,其他协作的开发者也可以看到你的更改。
    • 场景 :当你在本地完成了一系列更改,并想将它们分享给其他开发者或存储在远程服务器上时,你会执行 git push。
  5. git pull:

    • 描述:这个命令用于从远程仓库获取最新的更改并合并到你的本地分支。
    • 场景 :在与其他开发者协作时,为了保持你的工作与他们的同步,你会定期执行 git pull 来获取并合并远程的最新更改。

2. 理解 Git 的机制:

如果你只是机械地记住命令,而不知道它们背后的原理,那么当出现问题时,你可能会感到很迷茫。但如果你理解了 Git 的内部机制,那么即使遇到了不熟悉的问题,你也可以轻松地推理出问题的原因,并找到解决方案。

其实理解 Git 的机制就像是了解汽车引擎是如何运作的。即使你不打算成为专业的汽修师傅,这些知识也会给你成就感,因为一旦当车子出问题时,你知道是怎么回事,也能够第一时间想到最佳的解决方案。

这节可能比较复杂,所以我举了很多例子和比喻帮助你理解,希望能对你起到作用,如果没有效果,欢迎在评论区斧正。

2.1 学习 Git 的对象模型: blobs, trees, commits, tags

  1. Blobs:

    想象你有一个大盒子,这个大盒子就是 Git ,里面放着你所有的玩具,这些玩具可以是积木、玩偶、小车等。

    每一个玩具可以看作是一个 blob。

    在 Git 里,当你创建或者修改一个文件,Git 就会把这个文件内容存储成一个 blob,并给它一个独一无二的编号。

  2. Trees:

    现在,你决定把这些玩具分类放置:积木放一个小盒子,玩偶放另一个小盒子,小车也放在一个专属的小盒子里。

    这些分类的盒子就像 Git 里的 trees。

    一个 tree 记录了多个 blobs(你的玩具)和其他 trees(小盒子)及它们的名称和位置。

  3. Commits:

    假设每次你玩完玩具后,你都拍一张照片,来纪念你的玩具摆放的状态。

    这些照片会告诉你,某一天你的玩具是怎样被放置的,哪些是新增的,哪些可能被放回了盒子里。

    在 Git 中,每次你决定保存你的项目状态时,你就创建了一个 commit。这个 commit 就像那张照片,记录了你的项目在某一时刻的完整状态。

  4. Tags:

    某一天你觉得你的玩具摆得特别好,于是在那张照片后面贴了一个星星贴纸来标记。

    这样,你以后就能快速找到那张你特别喜欢的照片,而照片里清晰记录了玩具的摆放形式。

    在 Git 中,这就是 tags 的作用。当你觉得某个 commit 特别重要(比如一个版本的发布),你可以给它打上一个 tag,以便将来快速找到。

这就是 Git 的对象模型的基础,理解这四个概念就像是知道你的玩具是如何被组织和记录的。

也许这会让你逐渐明白 Git 是如何保存和管理你的项目数据的。

2.2 了解 Git 是如何存储内容的,比如内容寻址、散列等

  • 内容寻址:

    你还记得小时候玩的挖宝地图吗?地图上有一系列的标记来指引你找到宝藏的位置,每个标记对应一个宝藏。

    如果我们按照 Git 的方式玩这个游戏,那藏宝图上的标记实际上是基于宝藏本身来的,而不是基于埋藏宝藏的地方。

    这意味着,不管你把这个宝藏埋在哪里,只要宝藏本身不变,这个标记就永远不会改变。

    在 Git 中,文件和内容也是通过它们的内容来寻址的,而不是它们的位置。

    不管文件在仓库中如何移动或重命名,只要其内容不变,它的寻址标记(也叫哈希值)就不会变。

  • 散列:

    想象你现在正准备做菜。

    每当你想做一个菜,你都会按照食谱去准备一组食材,每组食材都会对应一个特定的菜,比如红烧肉的食材组合就是肉、生姜、料酒、糖、盐等。

    即使你只是稍微改变一点点食材,比如多放了一点盐,最后做出的菜就可能完全不同,可能从原本的甜口红烧肉变成了咸口。

    在 Git 中,每个文件或其内容都像是食谱中的食材组合。

    当文件的内容发生任何微小的变化,Git 会为它生成一个全新且独特的"菜品"(也就是哈希值)。这个"菜品"是基于文件内容的,所以只要内容有任何变化,结果就会截然不同。

这两个概念让 Git 能够高效、精确地存储和追踪内容。

通过内容寻址与散列,Git 可以快速地确定内容,并保障数据的一致性与完整性。

2.3 探索 .git 目录,了解其中的各个文件和目录的作用

  • config 文件:

    这就像仓库的管理手册。它记录了所有与这个仓库相关的配置信息,例如你的用户名、电子邮件,以及一些仓库的特定设置。

  • description 文件:

    这是给 GitWeb 用的,你可以简单地理解为仓库的简短描述或者标签。

  • HEAD 文件:

    想象一下你有一个指针,它总是指向仓库中的"当前货物"(也就是当前版本)。这就是 HEAD 文件的作用,它指向你当前正在工作的分支。

  • index 文件:

    这就像仓库的登记册,记录了即将被存储到仓库中的所有货物。当你做了一些改动并用 git add 命令添加这些改动时,这些改动都会被记录在这个登记册中,等待下一次提交。

  • objects 目录:

    这是仓库的主存储区,所有的文件和历史记录都被存储为对象并放在这个目录下。可以想象这里有很多小抽屉,每个抽屉都有一个独特的编号,并且每个抽屉都装着一些特定的货物。

  • refs 目录:

    在这个大仓库里,为了方便找到特定的货物,我们可能会给它们打上各种标签或者按类别分类。这就是 refs 目录的作用,它包含了指向各种数据(如分支和标签)的指针。

  • hooks 目录:

    你可以把这想象成仓库的自动化工具区。这里有很多预置的或自定义的脚本,可以在特定的事件发生时自动运行,比如每次提交前检查代码格式。

  • info 目录:

    这就像仓库的附加信息板,提供有关仓库的额外数据,例如排除某些文件不被追踪的规则。

3. 分支管理:

3.1 理解什么是分支,以及如何使用它们: branch, checkout

  • 分支是什么?

    你有没有玩过游戏?

    在游戏里,你可以自由探索、进行主线任务、或者各种支线任务。

    想象你的主线任务就是主分支,而每当你决定尝试一个新的支线任务或探索一个新地区时,你其实是在创建一个"游戏存档"或者说一个新的"路径"。

    在 Git 中,分支就像是你游戏中的这些不同的"存档"。

    每当你想尝试一个新的功能或修复一个错误,你可以创建一个新的分支,而不会影响你的主线任务(通常称为"master"或"main"分支)。

  • 如何使用分支?

    • branch:

      使用 git branch 就像查看你的所有游戏存档。你可以看到你目前探索过哪些路径或支线任务。

      如果你想创建一个新的存档,可以使用 git branch 新的分支名。

    • checkout:

      当你想回到某个特定的游戏存档时,你就是在"加载"那个存档。在 Git 中,这个动作称为"检出"分支。

      使用 git checkout 分支名 可以帮你"加载"指定的游戏存档。例如,git checkout 探索古老遗迹 就会让你回到这个任务。

      如果你想创建一个新的存档,可以使用 git checkout -b 新的分支名。

如今,在较新的 Git 版本中,为了更直观地表示分支切换,checkout 已被建议用 git switch 替代。但创建和删除分支的命令仍然是 git branch。

总之,分支就像是游戏中的不同存档,让你在不受限的情况下自由地尝试新的想法和变动。

3.2 学习如何合并分支: merge

  • 合并分支是什么?

    继续刚才的游戏。

    假设在游戏中,你完成了一个重要的支线任务,比如找到了一个强大的武器或学到了新的技能。

    现在,你想把这个新的进展应用到你的主线任务中。这个过程,就像是你把支线任务的存档"合并"到主线任务的存档中。

    在 Git 中,当你在一个分支上完成了某个功能或修复了一个错误,并希望将这些更改引入到主分支(比如 master 或 main)时,你可以使用 merge 命令来合并这两个分支。

  • 如何合并分支?

    • 切换到接收更改的分支:

      首先,你需要确保你正处于你想把更改"合入"的那个分支。使用 git checkout 主线任务 可以帮你切换到主线任务的存档。

    • 执行合并:

      现在,你可以使用 git merge 支线任务 来合并支线任务的存档到主线任务中。这就好像你把在支线任务中获得的所有物品和技能带到了主线任务中。

      如果合并过程中出现了冲突(例如,在两个分支中都修改了同一个文件的同一个部分),Git 会提示你解决这些冲突。

      可以想象成,两个存档中都有不同版本的某个装备,现在你需要决定保留哪一个。

    • 解决合并冲突:

      如果出现冲突,你需要手动编辑那些有冲突的文件,然后使用 git add 把它们标记为已解决。

      之后,你可以继续完成合并操作,使用 git commit 命令。

3.3 了解合并冲突是什么,以及如何解决

在 Git 中,合并冲突通常发生在两个分支都修改了同一个文件的同一部分时。Git 不知道你想保留哪个分支的更改,所以它会停下来,询问你如何解决这个冲突。

那么应该如何解决冲突呢?

  1. 找到冲突:

    当 Git 告诉你存在冲突时,首先要做的是找到这个冲突。你可以打开文件,找到如下的标记:

    go 复制代码
    ```
    <<<<<<< HEAD
    主线任务中的魔法剑的属性
    =======
    支线任务中的魔法剑的属性
    >>>>>>> 副任务分支名
    ```
  2. 决定如何解决:

    现在,就像选择游戏中的武器属性一样,你需要决定要保留哪些更改。你可以选择保留主线任务的版本、支线任务的版本,或者创建一个全新的版本,结合两者的优点。

    为此,你只需编辑该文件,删除 Git 添加的那些标记,并确保只留下你想要的内容。

  3. 标记为已解决:

    一旦你解决了冲突并保存了文件,使用 git add 文件名 来告诉 Git 你已经解决了这个冲突。

    最后,执行 git commit 来完成合并操作。这次,Git 不会再自动添加提交消息,因为它希望你提供有关如何解决冲突的详细信息。

4. 深入学习 Rebase:

4.1 了解 rebase 和 merge 之间的区别

继续刚才的游戏。

还记得你的主线任务和支线任务吗?你在两条路径上各自完成了一系列的任务,现在你想把它们结合起来。

这时候,merge 和 rebase 就是两种不同的方法,让你选择如何结合这两条路径。

  • merge

    • 什么是merge?

      使用 merge 就像是在游戏中,当你完成了支线任务后,回到主线任务,并把支线任务的所有进展一次性加入到主线任务中。

    • 效果是什么?

      结果就是你的主线任务历史中会有一个新的节点,这个节点表示了两条路径的结合。这种方法很直接,也容易理解。

  • rebase

    • 什么是rebase?

      使用 rebase 就像是你有了一台时光机。你首先回到支线任务开始之前的时间点,然后把主线任务中在此期间的所有进展应用到支线任务上,最后再完成支线任务。

      这样,当你回到主线任务时,就好像支线任务是在最新的主线任务进展之后完成的一样。

    • 效果是什么?

      结果是你的任务历史看起来像是一条直线,就好像没有任何分叉一样。

      这使得历史更加简洁,但也可能更难理解,因为它改变了原始的时间线。

  • 选择哪种方法?

    • 这取决于你的需求。如果你想要一个简单且直接的历史记录,可能会选择 merge。如果你希望得到一个线性且简洁的历史,那么 rebase 可能是更好的选择。
    • 但要注意,rebase 实际上是在改写提交的历史,这可能会造成困惑,尤其是当多人在同一个项目中工作时。

4.2 学习如何使用 rebase 来整理和清洁你的提交历史

rebase 是一个强大的工具,特别是当你想整理和优化你的提交历史时,使用它可以帮助你创建一个清晰、线性的提交历史,这在查看历史或进行代码审查时还挺有用。

下面是如何使用 rebase 来整理你的提交历史。

4.2.1 交互式 rebase (git rebase -i)

交互式 rebase 允许你修改过去的提交,这包括更改提交信息、合并多个提交或删除某些提交。

假设你想修改过去的 3 个提交,你可以这样操作:

css 复制代码
git rebase -i HEAD~3

这将打开一个编辑器,列出最近的 3 个提交,以及每个提交前面的命令选项(例如,pick)。

在这里,你可以:

  • 更改提交信息 :将 pick 更改为 reword。
  • 合并提交 :将 pick 更改为 squash 或 fixup。
  • 删除提交:简单地删除该行。
  • 重新排序提交:在编辑器中移动行的顺序。

完成上述操作后,保存并关闭编辑器。Git 将按照你的指示进行操作。

4.2.2 重新应用提交到另一分支

如果你想将一系列的提交从一个分支移到另一个分支,你可以这样做:

复制代码
git checkout feature-branch
git rebase master

这会获取 feature-branch 上与 master 不同的提交,并尝试将它们应用到 master 分支上。这样,你的 feature-branch 的提交历史看起来就像是在 master 的最新提交之后完成的。

4.2.3 注意事项

  • 不要在公共分支上执行 rebase :由于 rebase 会改写提交历史,这可能会导致困惑和问题,特别是其他人已经在这基础上做了更改。
  • 可能会遇到冲突 :在 rebase 过程中,你可能会遇到合并冲突。在这种情况下,解决冲突,然后运行 git rebase --continue 来继续 rebase 过程。

使用 rebase 可以帮助你维持一个干净、连续的提交历史。

但是,注意这里的但是,它也带来了一些风险,因此使用时需谨慎。

5. 远程仓库与协同工作:

5.1 确保你理解 origin 是什么,以及如何管理多个远程仓库

origin 是什么?

你有没有和朋友分享过照片或文件?

通常,你可能有一个在你的手机或电脑上的原始版本,然后你发送给朋友一个复制品。

在 Git 里,当你想和他人分享或获取代码时,你需要一个地方来存放这些代码,那就是远程仓库(像 GitHub 或 GitLab 这样的服务)。

当你首次复制(或说"克隆")一个项目到你的电脑上时,Git 给这个远程仓库取了个默认的名字,叫做 origin。

简单来说,origin 就是你最初从哪里获取代码的那个地方的名字。

如何管理多个远程仓库?

现在,想象一下你不仅仅想与一个朋友分享照片,还想与其他朋友或家人分享。

就像有多个朋友一样,在 Git 中,你也可以有多个远程仓库。每个远程仓库都有一个名字,这样你就知道要向哪个地方发送或从哪个地方获取代码了。

如何添加一个新的远程仓库?

css 复制代码
git remote add [给仓库起个名字] [仓库的地址]

例如,如果你想添加一个名为 myfriend 的远程仓库,地址是 https://github.com/myfriend/repo.git,你可以这样做:

csharp 复制代码
git remote add myfriend https://github.com/myfriend/repo.git

查看所有的远程仓库:

复制代码
git remote -v

这会列出所有的远程仓库及其地址,这样你可以知道你有哪些"朋友"。

执行之后没有结果?😯 原来你没有朋友嘛?🐶

删除一个远程仓库:

如果你不再需要某个远程仓库(也就是你不再与那个"朋友"分享代码了),你可以这样做:

arduino 复制代码
git remote remove [仓库的名字]

5.2 学习如何同步远程分支,以及如何解决与远程的冲突

当你玩游戏(原神?)时,有时你可能在手机上玩,有时在电脑上玩,而你希望你在两个设备上的游戏进度是同步的。

这与 Git 中的同步远程分支很相似。

你的代码在本地做了一些更改,同时你的团队成员也在远程仓库做了一些更改,你希望这两部分的更改都能同步。

1. 获取远程的更改

当你想要获取远程仓库的新更改时(就像你想要在电脑上看到你手机上的游戏进度一样),你可以使用:

sql 复制代码
git fetch origin

这个命令会告诉 Git:"兄dei,去查看一下 origin (默认的远程仓库)有没有我还没看到的新内容。"

2. 合并远程的更改到你的当前分支

拿到远程的新内容后,你需要把这些内容合并到你当前的工作中,就像同步你的游戏进度一样。你可以用:

css 复制代码
git merge origin/[你的分支名]

例如,如果你在 master 分支上,你会运行 git merge origin/master。

3. 解决冲突

参考3.3章节。

提醒:为了避免太多冲突,应该定期与远程仓库同步,并且在开始写新的代码前,先更新你的本地分支。

6. 高级技巧和最佳实践:

6.1 学习如何使用 git stash 来临时保存工作

想一下这个场景。

你的房间里摆满了各种没整理好的乱七八糟的东西,这时候女朋友突然来了,于是你赶紧把所有东西都扔到柜子或者箱子里。

在 Git 中,git stash 就专门做这样的事,可以帮助你临时存储当前的工作,而不需要提交一个完整的更改。

1. 临时存储工作

当你正在进行一项任务,但突然需要切换到另一个更紧急的任务时,你可以使用:

复制代码
git stash

这会把你的所有更改(未提交的)保存到一个"临时储藏区",让你的工作区回到最后一次提交的状态。

2. 查看储藏的内容

要查看你已经存储的内容,你可以使用:

复制代码
git stash list

这会显示所有你储藏的内容列表,让你知道有哪些东西在那里等待你处理。

3. 恢复储藏的工作

当你准备好返回到先前的工作时,你可以使用:

复制代码
git stash apply

这会恢复你最近储藏的工作,但仍然保留在储藏区列表中。如果你想恢复工作并从列表中删除它,可以使用:

perl 复制代码
git stash pop

4. 删除储藏的内容

如果你确定不再需要某个储藏的内容,可以使用以下命令删除它:

css 复制代码
git stash drop [stash名,如:stash@{0}]

如果你想清空所有储藏的内容,可以使用:

arduino 复制代码
git stash clear

总结一下

git stash 是一个非常实用的工具,它允许你在不提交更改的情况下临时存储你的工作。

这对于在多个任务之间快速切换或处理紧急问题时特别有用。

就像你最终需要从箱子里取出并整理那些临时放置的物品一样,你也应该经常检查和清理你的储藏列表,以确保不遗漏任何重要的工作。

6.2 了解 git reflog,它可以帮助你恢复丢失的提交

有时候你写了好半天的代码,在提交的时候发现有冲突,然后自己鼓捣鼓捣,发现自己写的代码没了!

不用担心,使用 reflog 来检查你的操作历史,就像查看回收站一样,你会找回那些代码。

在 Git 的世界里,git reflog 就像是这个回收站,帮助你跟踪和恢复曾经到达过的提交状态。

1. 查看最近的操作记录

要查看 Git 的操作历史记录,只需要敲:

复制代码
git reflog

你会看到一个列表,列出了你最近的所有操作,包括提交、分支切换、合并、甚至是由于某些操作而失去的提交。

2. 如何恢复丢失的提交

每个记录前面都有一个引用,像这样:HEAD@{2}。这些是你的历史位置引用。如果你发现一个位置看起来是你失去的提交或分支,你可以简单地检出这个状态:

kotlin 复制代码
git checkout HEAD@{2}

这样你就会切换到这个特定的状态。如果你确定这是你想恢复的提交,你可以为其创建一个新的分支:

kotlin 复制代码
git branch recovery-branch HEAD@{2}

这样,你就在recovery-branch分支上有了那个"丢失"的提交。

6.3 学习如何编写有意义的提交信息

Git Commit 日志风格指南 | LeanCloud 开放资源

建议按照标准结构进行填写:

makefile 复制代码
类型(可选的范畴): 简短描述

可选的详情

可选的注解

比如下面这个示例:

vbnet 复制代码
feat(auth): increase length of new API key

the length is increased from 24 to 32 for new API keys

close #12

如果你用的是JetBrain的IDE工具,那建议安装 Git Commit Template - IntelliJ IDEs Plugin | Marketplace (jetbrains.com) 插件,协助规范化提交信息

6.4 了解 Git Hooks 和如何利用它们来优化工作流程

想象一下,每次你想做某事时,有一个机器人自动为你做预备工作,或在你完成工作后进行一些检查。

Git Hooks 就像这样的机器人,它们是在 Git 仓库中的特定操作触发时自动运行的脚本。

1. 什么是 Git Hooks

Git Hooks 是 Git 仓库中的一些脚本,可以在各种 Git 操作(如提交、推送、接收更改等)的特定点自动触发。这意味着你可以用它们来自动化或优化某些重复的任务。

2. Git Hooks 的种类

Git 有许多内置的钩子,例如:

  • pre-commit: 提交前触发,常用于检查代码风格、运行测试等。
  • post-commit: 提交后触发,常用于通知或其他后续操作。
  • pre-push: 推送到远程前触发,可以用于确保不会推送坏代码。

...还有许多其他钩子可以探索和使用。

3. 如何设置 Git Hook

所有 Git Hooks 都存储在仓库的 .git/hooks 目录中。当你初始化一个新的 Git 仓库时,这个目录通常会包含一些示例钩子。

例如,要设置一个 pre-commit 钩子,你可以在 .git/hooks 目录中创建一个名为 pre-commit 的文件,并确保它有执行权限。

文件内容可能是这样的:

bash 复制代码
#!/bin/sh
# 运行测试
npm test

每次你提交时,这个脚本就会自动运行。如果测试失败,提交将被阻止。

4. 使用现成的工具

有一些工具,如 Husky,可以帮助你更容易地设置和管理 Git Hooks。

6.5 掌握 .gitattributes 和 .gitignore 的使用

6.5.1 .gitattributes

.gitattributes 文件允许你为特定的文件或文件模式定义 Git 属性。

  • 行尾转换 :在多平台的开发团队中,行尾差异(LF 与 CRLF)可能会成为问题。你可以用 .gitattributes 来统一行尾风格。

    ini 复制代码
    # 保证所有文件在提交时使用 LF 行尾
    * text=auto
  • 指定合并策略:某些文件可能需要特定的合并策略。

    ini 复制代码
    # 对于 .mine 文件,使用自定义的合并策略
    *.mine merge=custom-merge-strategy
  • 定义文件类型:你可以指定某些文件应该被视为文本或二进制文件,或者指定其语言高亮。

    ini 复制代码
    # 将 .js 文件视为 JavaScript
    *.js linguist-language=JavaScript

6.5.2 .gitignore

.gitignore 文件允许你定义那些不应该被 Git 跟踪的文件或目录。

  • 通配符支持 :可以使用 * 和 ? 等通配符。

    bash 复制代码
    # 忽略所有 .log 文件
    *.log
  • 目录忽略:可以忽略整个目录。

    bash 复制代码
    # 忽略 node_modules 目录
    node_modules/
  • 白名单 :如果你想忽略某个目录,但想保留其中的某些文件,可以使用 !。

    arduino 复制代码
    # 忽略所有 .config 文件,但保留 main.config
    *.config
    !main.config
  • 注释 :可以在 .gitignore 文件中使用 # 添加注释。

    bash 复制代码
    # 这是一个注释

6.5.3 总结:

.gitattributes 和 .gitignore 是控制 Git 仓库行为的两个强大工具。

通过配置这两个文件,可以确保仓库的整洁、一致性,并有效地管理多人合作的项目。

7. 实践与复盘:

7.1 尝试在实际项目中使用你学到的知识

7.1.1 选择一个项目

  • 自己的小项目:有没有一直想做但迟迟未开展的小项目?现在就开始,并用 Git 来管理它。
  • 贡献开源项目:找一个你喜欢的开源项目,并开始贡献。这会教给你很多关于团队合作的经验。

7.1.2 大胆实践,不怕出错

  • Git 提供了很多恢复工具,例如 git reflog,所以不必害怕犯错误。
  • 你可以先整个Demo进行练习,这样你不用担心出错带来的后果。

7.1.3 完善开发流程

  • 尝试使用 feature 分支进行功能开发。
  • 确保主分支保持稳定,将新功能或修复分离在不同的分支上。

7.1.4 提交要有节制

  • 频繁的提交可以帮助你跟踪你的进度。但每次提交都应有明确的意义。
  • 使用有意义的提交信息描述,这样你和你的团队都能明白每次提交的原因。

7.1.5 与他人协同工作

  • 试着与其他开发者合作,分享你的代码,获取他们的反馈。
  • 学习如何解决合并冲突、如何审查他人的代码等。

7.1.6 持续进阶

  • 无须多言,毕竟学无止尽。

7.2 定期回顾和复盘你的 Git 使用习惯,看是否有可以改进的地方

随着时间的推移和项目的进展,你的 Git 使用习惯可能需要进行调整和优化。

定期的回顾和复盘可以帮助你识别效率低下的地方,找到更好的解决方案,确保你的工作流程始终处于最佳状态。

7.2.1 分析你的提交历史

  • 回顾你的提交历史,看是否有连续的小型提交或重复的提交信息。如果有,考虑使用 git rebase 来清理和合并提交。
  • 确保提交信息简洁明了,能够清楚地告诉其他开发者(包括未来的你)这次提交的目的。

7.2.2 审查合并和冲突解决的策略

  • 回顾过去如何处理合并和冲突。是否总是使用 merge 而不是 rebase?或者反之?
  • 考虑是否有更好的方法来避免合并冲突,比如更频繁地从主分支拉取更新。

7.2.3 评估工作流程

  • 分析你的 Git 工作流程,看看是否有不必要的步骤或可以进一步自动化的部分。
  • 考虑引入 Git Hooks 来自动化一些重复的任务,如代码格式检查、单元测试等。

7.2.4 与团队分享和讨论

  • 定期与团队成员分享和讨论 Git 最佳实践和新的技巧。
  • 通过团队的经验和反馈,找到可能的改进点,并一起寻求更好的解决方案。

7.2.5 学习和更新知识

  • Git 和与之相关的工具不断更新和进化。定期查看 Git 的更新日志,看看是否有新的功能或改进可以利用。
  • 保持对 Git 社区的关注,学习他人的经验和建议,不断优化你的使用习惯。

总结

最后,推荐一些优秀的资料和实践项目,帮助你更深入地理解和应用 Git。

当然最有效的学习方式还是自己建个仓库多练习。

不论学什么知识,无非在于两个"多 ":多提问题 、多实践。

做到这两个"多",你迟早会成为使用 Git 的高手高手高高手。

相关推荐
程序员cxuan15 小时前
讲真,智能路由这事儿,还得看基元律动
人工智能·后端·程序员
YIN_尹16 小时前
【git原理与使用】git基本操作及底层原理(二)
大数据·git·elasticsearch
AI前端工程狮16 小时前
用户点了「取消」,我的服务进程退出了
人工智能·程序员
得物技术19 小时前
压测AI Agent 治理与评测调优实践
程序员·架构·测试
程序员爱德华21 小时前
Git 命令
git
SimonKing1 天前
Workbuddy太占C盘空间了,写个迁移工具迁走10G的数据
java·后端·程序员
挖掘狂人1 天前
Token 都上双十一货架了,AI 电脑的账该怎么算?
大数据·程序员·ai编程
深蓝AI1 天前
26.1% 的 Agent 技能带漏洞:skills 霸榜 GitHub 当天,NVIDIA 和 OpenAI 同时掏出安检仪
人工智能·程序员
Cry丶1 天前
Git Rebase 操作备忘
git·rebase
程序员cxuan1 天前
离谱,AI 大佬顺手搓了个 YouTube ,而我顺手给他搓了个中文插件
人工智能·后端·程序员