跳至主要内容

Git Diff 全面解析:完整指南与示例

学习如何使用 git diff 高效跟踪代码更改,从基础比较到高级技巧。了解可视化工具、专用命令与更优的代码管理工作流。
· 12分钟 阅读

使用 AI 探索

git diff 是您洞察代码仓库变更的窗口。从本质上说,它是一条命令,用来展示文件在不同状态之间的差异——无论是将当前的工作与已暂存的内容进行比较,还是比较分支与提交之间的更改。把它看作 Git 回答“发生了什么变化?”这个问题的方式。当您运行 git diff 时,Git 会逐行分析文件内容,识别新增、删除或修改的部分,并以标准化的格式呈现,精确突出变更的内容与位置。

git diff 通过在提交前清晰展示修改,帮助开发者保障代码质量。本文将从基础比较到进阶技巧,讲解如何高效使用这条核心命令,以改进您的开发流程与团队协作。

先决条件

要跟进本教程,您应熟悉以下 Git 概念:

  • 基本 Git 工作流(init、add、commit)
  • Git 仓库及其结构
  • 分支及其工作方式
  • 提交与提交历史
  • 暂存区(index)

如果您需要复习这些概念,以下资源将有所帮助:

要跟随示例操作,您需要在系统上 安装 Git。所有命令均可在终端或命令提示符中运行。

为何 git diff 对开发者至关重要

无论单兵作战还是在百人团队中,每位开发者都需要知道自己的代码发生了哪些变化。没有 git diff,您就很难准确判断修改了哪些行,排查问题与协作几乎无从谈起。

git diff 是变更管理的关键工具,也是通过有效评审流程构建高质量软件的基石。在审查更改时,git diff 不仅提供“改了什么”的上下文,也帮助理解“为何这些更改重要”。 

这种对代码演化的直观可见性,帮助团队维持标准,并阻止缺陷流入生产环境。

随着项目复杂度增加,git diff 在以下几个关键方面愈发不可或缺:

  • 变更核对 :准确确认即将提交的内容,避免误把调试代码或无关更改纳入提交
  • 知识传递 :无需通读整份文件即可理解同事做了哪些修改
  • 冲突解决:在合并时精确定位变更冲突的位置与方式
  • 历史分析 :追踪特定更改的引入时间,用于定位缺陷或理解功能演进
  • 聚焦代码评审 :将注意力集中在实际发生变化的代码上,节省时间并提升评审质量

要高效使用 git diff,您需要理解支撑这些比较的底层架构——Git 的“三棵树”模型。

Git 的“三棵树”架构

要理解 git diff,首先需要掌握 Git 基本的“三棵树”架构。尽管名为“树”,它们并非文件系统中的真实树结构,而是代码存在的三种不同状态。

可以把这三种状态看作 Git 同时追踪的三个项目版本:工作区(您的实际文件)、暂存区(或 index,用于准备要提交的更改)以及仓库(存储在 .git 目录中的项目提交历史)。

Git 的三棵树架构:工作区、暂存区与仓库

来源:Hashnode

工作区包含您正在编辑的文件——您在这里编写代码、进行更改并测试。暂存区是一个“预备区”,您可以选择哪些更改应纳入下一次提交。您可以把它想象成发货前整理包裹(更改)的装卸平台。

最后,仓库存储着整个项目的历史,作为一系列提交——在特定时间点对代码的快照,并串联形成一条历史链。

git diff 通过以不同组合比较这三种状态来工作。当您不带参数运行 git diff 时,它会比较工作区与暂存区,显示已修改但尚未暂存的更改。 

使用 git diff --staged 会比较暂存区与上一次提交,展示下一次提交将包含的内容。 

而 git diff HEAD 则直接比较工作区与上一次提交,展示所有未提交的更改(无论是否已暂存)。

这些比较点构成了 Git 中所有 diff 操作的基础:

  • 工作区 ↔ 暂存区:我做了哪些还未暂存的更改?(git diff)
  • 暂存区 ↔ 仓库:我已暂存、即将提交的更改有哪些?(git diff --staged)
  • 工作区 ↔ 仓库:我的工作文件与上一次提交的整体差异是什么?(git diff HEAD)
  • 提交之间:在历史的特定两个时间点之间,代码如何演进?(git diff commit1-hash commit2-hash)

理解这一架构能为您建立正确心智模型,从而用 git diff 精确定位代码库中何处、何时、发生了哪些变化。

在打好架构基础后,我们就可以动手实践 git diff 命令,洞察代码在三种状态间的演变。

git diff 的基础用法

我们来创建一个示例数据分析项目,演示 git diff 的实际效果。我们会搭建一个包含 Python 脚本、CSV 数据与文本文件的小型仓库,方便在教程过程中不断修改。

# Create and initialize our project
mkdir data-analysis-project
cd data-analysis-project
git init

# Create initial files
echo "# Data Analysis Project\nA sample project to demonstrate git diff functionality." > README.md
echo "import pandas as pd\n\ndef load_data(filename):\n return pd.read_csv(filename)\n\ndef analyze_data(data):\n return data.describe()" > analysis.py
echo "id,name,value\n1,alpha,10\n2,beta,20\n3,gamma,30" > data.csv
echo "DEBUG=False\nDATABASE_PATH=./data/" > config.txt
echo "def normalize_data(data):\n return (data - data.min()) / (data.max() - data.min())" > utils.py

# Make our first commit
git add .
git commit -m "Initial commit with basic project structure"

# Check the directory structure
> tree

.
├── README.md
├── analysis.py
├── config.txt
├── data.csv
└── utils.py

我们的项目现在有五个受版本控制的文件,为展示各种 diff 场景打下了基础。接下来我们会修改这些文件,展示 git diff 如何在不同情境下揭示更改。

理解 git diff 的输出

当您运行 git diff 命令时,输出遵循标准化格式,旨在清晰指示发生的更改。我们修改一下 analysis.py 文件,看看实际 diff:

# Update analysis.py with a new function
echo "import pandas as pd\n\ndef load_data(filename):\n return pd.read_csv(filename)\n\ndef analyze_data(data):\n return data.describe()\n\ndef visualize_data(data):\n return data.plot(kind='bar')" > analysis.py

现在来查看产生的 git diff:

git diff

您会看到类似如下的输出:

示例 git diff 命令的输出

提示:要退出 git diff 输出,请在终端按 “q”。

我们来分解一下这段输出:

  1. 头部(diff --git a/analysis.py b/analysis.py)显示正在比较的文件,即 analysis.py
  2. 文件元数据(index db0e049..a7a7ab0 100644)显示修改前后版本的 Git 内部标识
  3. 文件标记(--- a/analysis.py and +++ b/analysis.py)指示“之前”和“之后”的文件
  4. 分块(hunk)头(@@ -5,3 +5,6 @@)显示受影响的行。其含义为:
  • -5,3 表示原文件从第 5 行开始,diff 展示了 3 行
  • +5,6 表示修改后文件从第 5 行开始,diff 展示了 6 行
  • 两者差异表明新增了 3 行

5. 内容变更中以 + 开头的行表示新增内容

在较大的文件中,git diff 会将更改分组为“分块(hunks)”——包含更改的文件片段。每个分块都有带行号的头部,帮助您在文件中定位更改。

比较工作区与暂存区

不带参数运行 git diff 会比较工作区(文件当前状态)与暂存区(准备提交的更改)。这有助于审阅您已修改但尚未纳入下次提交的内容。

我们修改多个文件进行演示:

# Update README.md
echo "# Data Analysis Project\nA sample project to demonstrate git diff functionality.\n\n## Installation\nRun \pip install -r requirements.txt" > README.md

# Update data.csv
echo "id,name,value\n1,alpha,10\n2,beta,20\n3,gamma,30\n4,delta,40" > data.csv

现在仅暂存 README.md 的更改:

git add README.md

此时运行 git diff 将只显示 data.csv 与上文的 analysis.py 的未暂存更改:

git diff 命令的示例输出

这有助于您聚焦尚未暂存的内容。如果想查看已暂存的内容:

git diff --staged # 或 git diff --cached(同义)

git diff 命令的输出

这将显示已暂存、准备提交的 README.md 变更。此工作流对于构建干净、逻辑清晰的提交至关重要。您可以按照逻辑关系分批暂存修改,审阅已暂存的 diff 以确保其构成一致的变更单元,然后再提交。

比较暂存区与上一次提交

git diff --staged 会比较暂存区与上一次提交。这将准确展示如果现在运行 git commit,下一次提交会包含哪些内容。

我们把 data.csv 的更改也暂存,再查看已暂存的内容:

git add data.csv
git diff --staged

现在的输出会显示 README.md 与 data.csv 的更改,因为两者都已暂存。提交前的这一步审查至关重要——它是防止意外提交的最后一道防线。

一个常见的工作流可能如下:

  1. 修改多个文件
  2. 运行 git diff 审阅所有更改
  3. 有选择地使用 git add <file> 暂存逻辑相关的一组更改
  4. 运行 git diff --staged 验证即将提交的内容
  5. 使用 git commit -m "Your message" 提交已暂存的更改
  6. 对其他逻辑分组的更改重复上述步骤

这种有条理的方法有助于维持干净、信息量充足的提交历史,使理解项目演进与定位问题更加容易。随着经验积累,这些 diff 命令会变成条件反射,成为您开发过程中的常驻助手。

进入下一阶段之前,我们先完成提交:

# data.csv and README.md are to be committed
git commit -m "Modify data.csv and README.md files"

# Stage and commit analysis.py
git add analysis.py
git diff --staged  # Review the changes one more time
git commit -m "Add a new function to analysis.py"

git diff 的进阶技巧

在掌握 git diff 的基础用法后,我们继续探索更强大的技巧,以增强您在项目中跟踪和分析更改的能力。我们将继续使用数据分析项目来演示这些进阶概念。

比较不同引用之间的更改

Git 围绕“引用(reference)”的概念构建——即指向代码特定状态的指针。这些引用包括分支、提交与标签。git diff 可以比较任意两个引用,展示它们之间的变更。

我们创建一个用于开发功能的新分支,并进行修改:

# Create and switch to a new branch
git checkout -b feature/advanced-analytics

# Modify the analysis.py file with a new function
echo "import pandas as pd
import numpy as np

def load_data(filename):
   return pd.read_csv(filename)

def analyze_data(data):
   return data.describe()

def visualize_data(data):
   return data.plot(kind='bar')

def perform_advanced_analysis(data):
   """Performs advanced statistical analysis on the dataset"""
   results = {}
   results['correlation'] = data.corr()
   results['skew'] = data.skew()
   return results" > analysis.py

# Commit the changes
git add analysis.py
git commit -m "Add advanced analysis function"

现在我们把功能分支与主分支进行比较:

git diff main feature/advanced-analytics

该命令会展示两个分支之间的所有差异——包括被修改、新增或删除的文件。您将看到我们对 analysis.py 的修改,包括新增的导入与函数(在终端中按多次回车以浏览被截断的完整 diff)。

若要与某个特定提交进行比较,可以使用提交哈希:

git log --oneline  # 查找想要比较的提交哈希

git log --oneline 命令的输出

git diff 7b3105e  # 将 7b3105e 替换为您要比较的实际提交哈希

这种比较能力在以下情况下尤为有用:

  • 为代码评审做准备,查看功能分支中的所有更改
  • 在合并前检查同事分支将引入哪些更改
  • 理解代码库在不同版本或发布之间的演进

比较特定文件

处理大型仓库时,您常常希望只关注特定文件或目录的更改,而不是查看所有差异。git diff 允许通过指定路径轻松实现这一点。

我们先修改多个文件:

# Update config.txt
echo "DEBUG=True
DATABASE_PATH=./data/
LOG_LEVEL=INFO" > config.txt

# Update utils.py
echo "def normalize_data(data):
   return (data - data.min()) / (data.max() - data.min())

def clean_data(data):
   return data.dropna()" > utils.py

若仅查看配置文件的更改:

git diff config.txt

或者比较分支间的特定文件:

# 比较 main 与 feature/advanced-analytics 分支的 analysis.py 文件
git diff main feature/advanced-analytics -- analysis.py

上述命令中的 -- 帮助 Git 区分引用与文件路径。以下场景尤为实用:

  • 在包含大量文件的仓库中工作,但仅聚焦于特定组件(这很常见)
  • 检查配置在不同分支间的变化
  • 在庞大变更集中仅审阅最关键的文件

上下文差异(Context)选项

git diff 提供多种选项来调整差异的展示方式,便于聚焦有意义的更改。

例如,在处理代码格式化更改时,空白字符差异可能掩盖重要的语义更改。我们用格式化更改演示:

# 对 analysis.py 做空白字符更改
sed -i '' 's/    return/  return/g' analysis.py  # 减少缩进

使用标准 git diff 比较时会显示空白字符的变化(注意 return 语句缩进错位):

git diff analysis.py

# OUT:
--- a/analysis.py
+++ b/analysis.py
@@ -2,17 +2,17 @@ import pandas as pd
import numpy as np

def load_data(filename):
-    return pd.read_csv(filename)
+  return pd.read_csv(filename)

def analyze_data(data):
-    return data.describe()
+  return data.describe()

def visualize_data(data):
-    return data.plot(kind='bar')
+  return data.plot(kind='bar')

def perform_advanced_analysis(data):
    Performs advanced statistical analysis on the dataset
    results = {}
    results['correlation'] = data.corr()
    results['skew'] = data.skew()
-    return results
+  return results

但我们也可以忽略空白字符的变化(由于仅移除了空白,本例将不显示变化):

git diff -w analysis.py  # 或 --ignore-all-space

另一个有用的选项是控制上下文行数——也就是在修改周围显示的未变更行:

git diff -U1 analysis.py  # 仅显示 1 行上下文(默认是 3 行)
git diff -U5 analysis.py  # 显示 5 行上下文

这些上下文选项在以下情况下尤其有价值:

  • 审阅经过自动格式化的代码
  • 聚焦功能性变更而非风格变更
  • 需要更多上下文来理解特定更改
  • 处理大文件时,默认上下文会产生过多输出

掌握这些进阶技巧,您就能更细致地控制审阅与理解代码库中的更改,使开发流程更高效、代码评审更有成效。

继续前进到高级应用前,先提交最新更改:

git add .
git commit -m "Modify analysis.py, config.txt, and utils.py"

git diff 的高级应用

在进阶技巧的基础上,我们再来看一些更高级的应用,这将让您的 Git 技能更上一层楼。它们在处理复杂代码库或与大型团队协作时尤为实用。

使用外部 diff 工具

虽然 Git 内置的 diff 已经很强大,但对复杂变更而言,可视化的 diff 工具常能提供更清晰的视图。Git 允许您配置外部工具来增强 diff 体验。

我们以 VSCode 为例配置流行的可视化 diff 工具,但对于 Beyond Compare、Meld 或 KDiff3 等工具,配置方式也类似:

# Configure Git to use VSCode as the diff tool (project-specific)
git config diff.tool vscode
git config difftool.vscode.cmd "code --wait --diff \$LOCAL \$REMOTE"

# To use other popular tools, you could use:
# For Beyond Compare (project-specific):
git config diff.tool bc3
git config difftool.bc3.path "/path/to/beyond/compare"

# Installation commands:
# For Beyond Compare:
# On macOS: brew install --cask beyond-compare
# On Ubuntu: sudo apt-get install beyond-compare
# On Windows: Download from https://www.scootersoftware.com/download.php

# Note: To apply these settings globally instead of just the current project,
# add the --global flag to each command, for example:
# git config --global diff.tool vscode

此后,您可以用如下命令替代 git diff:

git difftool main feature/advanced-analytics

这将打开您配置的可视化 diff 工具展示更改。下图为 Beyond Compare 的界面:

Beyond Compare git diff 工具界面

可视化 diff 工具有以下优势:

  1. 并排对比,更易把握上下文
  2. 与编辑器偏好一致的语法高亮
  3. 在变更间进行高级导航
  4. 在审阅差异时可直接编辑文件

审阅大型变更或结构复杂(如嵌套 JSON 或 XML)的文件时,可视化 diff 工具能显著提升理解效率。

专用 diff 命令

Git 提供了多种专用 diff 命令,以便在特定场景下获得更细粒度的控制。我们来看看其中一些强大的命令:

git diff-tree 用于比较树对象(目录)之间的差异:

# Get the hash of the last two commits
LAST_COMMIT=$(git rev-parse HEAD)
PREV_COMMIT=$(git rev-parse HEAD~1)

# Show changes in the last commit
git diff-tree --patch $PREV_COMMIT $LAST_COMMIT

git diff-index 用于比较工作树与索引(暂存区)或某棵树:

# Compare working directory with the index
git diff-index --patch HEAD

git diff-index 对脚本编写与自动化尤其有用。它允许以编程方式检查下一次提交将包含哪些更改,适合用于 pre-commit 钩子与校验脚本。

例如,您可以在 CI/CD 流水线中使用它,验证某些文件未被修改,或确保配置更改符合特定模式,然后再允许提交。

git diff-files 展示工作区文件与索引之间的差异:

# Check differences for specific files
git diff-files --patch config.txt

这些专用命令在以下方面尤其有用:

  • 创建自定义的 Git 工作流与脚本
  • 调试 Git 内部机制相关问题
  • 对仓库状态进行定向分析
  • 构建与 Git 交互的自动化工具

分析代码历史

git diff 的一大强力应用是分析代码随时间的演变,这对调试或理解功能开发过程至关重要。

我们使用特殊的 ^! 记法来审查某个特定提交:

# Get the hash of our advanced analytics commit
ANALYTICS_COMMIT=$(git log --oneline | grep "advanced analysis" | cut -d ' ' -f 1)

# Show only changes introduced in that specific commit
git diff $ANALYTICS_COMMIT^!

^! 的语法是将该提交与其父提交进行比较的速记法,仅展示该提交引入的变更。

要追踪某个文件随时间的演变:

# Analyze how analysis.py changed over the last 3 commits
git log -p -3 analysis.py

在查找缺陷时,您可以将 git diff 与 git bisect 结合使用:

# Add a bug to simulate a regression
echo "import pandas as pd
import numpy as np

def load_data(filename):
   # Bug: accidentally returning None instead of the data
   pd.read_csv(filename)
   return None

def analyze_data(data):
   return data.describe()

def visualize_data(data):
   return data.plot(kind='bar')

def perform_advanced_analysis(data):
   results = {}
   results['correlation'] = data.corr()
   results['skew'] = data.skew()
   return results" > analysis.py

git add analysis.py
git commit -m "Update analysis.py with a hidden bug"

# Now use git bisect to find when the bug was introduced
git bisect start
git bisect bad  # Mark current commit as containing the bug
git bisect good main  # Mark the main branch as working correctly

# Git will check out commits for you to test
# Once found, you can examine the exact change that introduced the bug
git diff HEAD^!

Git bisect 是一款强大的调试工具,它会在提交历史中执行二分查找,定位引入缺陷的提交。配合 git diff,可形成高效流程:

1. 使用 git bisect start 开始二分过程

2. 使用 git bisect bad 将当前提交标记为“坏的”(包含缺陷)

3. 使用 git bisect good <commit-hash> 标记一个已知“好的”提交(无缺陷)

4. Git 会自动检出历史中间的一个提交供您测试。

5. 测试当前提交后,告知 git 测试结果:

  • 若该提交存在缺陷:git bisect bad
  • 若该提交不存在缺陷:git bisect good

6. Git 会根据您的反馈(每次执行 git bisect bad/good 命令后)继续检出不同提交,并逐步缩小范围。重复测试与标记,直到 Git 定位到第一个坏的提交。

7. Git 找到问题提交后,会显示一条消息,指出是哪个提交引入了缺陷。

8. 使用 git diff HEAD^! 精确查看该提交中的变更。

9. 该命令将精确展示引入缺陷的提交所修改的代码,帮助您将调试工作聚焦在这些具体更改上。

10. 随时使用 git bisect reset 退出 bisect,这会让您回到开始 bisect 前所在的分支。

11. 您也可以使用 git bisect run <test-script> 来自动化 bisect,只需提供返回 0 表示“好”、非 0 表示“坏”的命令。

该流程能大幅缩短调试时间,尤其适用于在大量提交之间穿梭、从“可用”状态变为“损坏”状态的场景。

这些历史分析技巧在以下方面价值巨大:

  • 查明缺陷的引入时间与原因
  • 理解某个功能或组件的演进过程
  • 对变更进行安全审计
  • 记录代码更改背后的决策过程

掌握这些高级应用,您就能精确地在项目历史中穿梭,更高效地调试问题,并更深入地洞察代码库的演变。

git diff 命令参考

git diff 提供了广泛的选项,可针对特定场景自定义输出与行为。以下是最常用参数的全面参考,以提升您的差异分析:

基础比较选项

  • git diff - 比较工作区与暂存区
  • git diff --staged(或 --cached)- 比较暂存区与上一次提交
  • git diff HEAD - 比较工作区与上一次提交
  • git diff <commit> - 比较工作区与指定提交
  • git diff <commit1> <commit2> - 比较两个指定提交
  • git diff <branch1> <branch2> - 比较两个分支

路径限制

  • git diff -- <path> - 将比较范围限制为特定文件或目录
  • git diff --stat - 展示更改摘要(变更文件数、插入与删除),对大型 diff 非常有用
  • git diff --name-only - 仅显示变更文件名
  • git diff --name-status - 显示变更文件名与状态(新增、修改、删除)

显示控制

  • git diff -w(或 --ignore-all-space)- 忽略空白字符变更
  • git diff --ignore-space-change - 忽略空白数量上的变化
  • git diff --color-words - 以词级别并带颜色显示差异
  • git diff --word-diff - 以另一种格式显示词级别差异
  • git diff -U<n> - 显示 n 行上下文(默认 3 行)
  • git diff --no-prefix - 在 diff 输出中不显示 a/ 与 b/ 前缀

内容过滤

  • git diff --binary - 显示二进制文件的变化
  • git diff -S<string> - 查找新增或移除指定字符串的更改
  • git diff -G<regex> - 查找匹配指定正则模式的更改
  • git diff --pickaxe-all - 配合 -S 或 -G 使用,显示文件中所有更改,而非仅匹配项

格式选项

  • git diff --patch-with-stat - 同时显示补丁与统计摘要
  • git diff --compact-summary - 以精简格式显示统计摘要
  • git diff --numstat - 以机器友好格式显示统计
  • git diff --summary - 显示创建/删除摘要

这些选项可以组合使用,以创建强大、定向的比较。例如,要在忽略空白字符的同时按词级别查看特定文件的更改:

git diff --color-words -w -- analysis.py

或者查找某个函数可能被新增或移除的所有位置:

git diff -S"def perform_advanced_analysis" main feature/advanced-analytics

理解这些选项能帮助您过滤噪音,精准聚焦重要变更,从而让代码审阅与分析工作更高效。无论是在排查缺陷、准备发起 Pull Request,还是单纯想弄清楚“发生了什么变化”,合适的 git diff 选项都能让任务事半功倍。

结语

在本文中,我们将 git diff 作为查看代码更改的多功能命令进行了探讨。我们涵盖了将工作文件与已暂存更改进行对比、比较分支与提交之间的差异,以及使用专用命令获取更深层洞见。将 git diff 融入您的工作流,有助于构建更干净的提交、及早发现问题,并促进更高质量的代码评审。 

无论是单人开发还是团队合作,精通 git diff 都能让您从“仅仅写代码”迈向“理解代码库如何随时间演变”。

若要继续提升 Git 技能,请参考以下资源: 

这些资源将帮助您在已有的 git diff 知识之上继续精进,全面提升版本控制能力。

Git Diff 常见问答

git diff 与 git diff --staged 有何区别?

git diff 显示工作区与暂存区之间的更改(未暂存的更改),而 git diff --staged 显示暂存区与上一次提交之间的更改(下一次将被提交的内容)。

如何比较两个分支之间的变化?

使用 git diff branch1 branch2 查看两个分支之间的全部差异。若要比较特定文件,在分支名后添加 -- path/to/file。

如何在 git diff 中忽略空白字符变更?

使用 git diff -w 或 git diff --ignore-all-space 忽略所有空白字符更改,便于聚焦于实质性的代码差异而非格式化。

我能用 git diff 找到某项更改是何时引入的吗?

可以!使用 git diff -S"search string" 查找文本何时被添加/移除,或结合 git log -p 查看特定代码的演变。为精准定位缺陷,将 git bisect 与 diff 结合非常有效。

如何以更直观的方式查看 git diff?

通过 git config diff.tool <toolname> 配置外部 diff 工具,即可使用 VSCode、Beyond Compare 或 Meld 等可视化工具,获得并排对比与更佳可视化体验。

Bexruz (Bex) Tuychiev

作者

Bexruz (Bex) Tuychiev

我是一名数据科学内容创作者,拥有超过 2 年的经验,并在 Medium 上拥有较大的读者群。我喜欢用略带讽刺的笔调撰写有关 AI 和机器学习的深度文章——毕竟总得想点办法让这些内容不那么枯燥。我已发表 130 多篇文章,并制作了一门 DataCamp 课程,另有一门正在筹备中。我的内容已被超过 500 万人次阅读,其中有 2 万人在 Medium 和 LinkedIn 上成为关注者。 

主题