星恒随风头像
关注
Linux开发工具详解(二):Git版本控制、GitHub协作与GDB调试实战封面图

Linux开发工具详解(二):Git版本控制、GitHub协作与GDB调试实战

Linux开发工具详解(二):Git版本控制、GitHub协作与GDB调试实战

头像

🔥 星恒随风: 个人主页
❄️ 个人专栏: 《指针合集》 | 《C语言基础》 | 《数据结构》 | 《机器学习导论》 | 《前端基础》 | 《python基础》 | 《C++从入门到入土》 | 《Linux的学习之旅》
✨ 数据即知识,压缩即智能

文章目录

前言:写完代码以后还有两个问题

1. 代码怎么管理?

一个项目开发过程中会不断出现:

第一次能运行
第二次加功能
第三次改接口
第四次修Bug
第五次重构

如果使用最原始的方法:

project-v1

project-v2

project-v3

project-final

project-final2

project-真最终版

很快就会遇到:

哪个版本改了什么?

什么时候改的?

谁改的?

还能不能回去?

两个人怎么同时开发?

因此需要:

版本控制系统

2. Bug怎么定位?

程序运行结果错误:

Expected: 5050
Actual:   0

只靠:

printf("here1\n");
printf("here2\n");
printf("x=%d\n", x);

当然也能调试。

但复杂程序中,我们更希望:

让程序停在指定位置
单步执行
进入函数
查看变量
修改变量
查看调用栈
观察变量何时变化

这就是:

GDB

解决的问题。

所以这一篇的主线就是:

Git
↓
管理代码历史

GDB
↓
定位代码问题

一、什么是版本控制?

1. 版本控制解决什么?

版本控制系统可以记录:

谁
在什么时候
修改了哪些文件
具体改了什么
为什么修改

并允许:

查看历史
回退版本
创建分支
合并代码
多人协作

2. Git是什么?

Git 是一个:

分布式版本控制系统

“分布式”非常重要。

传统集中式系统更多依赖:

中央服务器

而 Git 每个完整克隆通常都拥有:

完整版本历史

所以本地也可以进行大量操作:

commit
log
diff
branch

并不要求时刻连接 GitHub。


二、Git和GitHub不是同一个东西

1. Git

Git 是:

版本控制工具

安装在本地。


2. GitHub

GitHub 是:

Git 代码托管与协作平台

除此之外还提供:

Issue
Pull Request
Actions
Release
Code Review

等能力。

所以:

Git != GitHub

关系更接近:

Git
↓
版本控制协议与工具

GitHub
↓
基于Git的远程托管与协作平台

三、安装Git

1. Ubuntu

sudo apt update
sudo apt install -y git

2. Fedora / RHEL

sudo dnf install -y git

旧 CentOS:

sudo yum install -y git

检查:

git --version

四、第一次使用Git要配置身份

1. 配置用户名

git config \
    --global \
    user.name \
    "Your Name"

2. 配置邮箱

git config \
    --global \
    user.email \
    "[email protected]"

查看:

git config --global --list

这些信息会进入:

Commit Metadata

用于标识:

谁进行了这次提交

五、Git最重要的四个区域

1. 工作区

就是你真实看到和编辑的文件:

main.c
Makefile
README.md

2. 暂存区

也叫:

Index
Staging Area

作用是:

准备“下一次 commit 到底包含哪些内容”

3. 本地仓库

执行:

git commit

之后,提交记录进入:

Local Repository

4. 远程仓库

例如:

GitHub

对应常见远端名字:

origin

六、Git数据流一定要理解

Working Tree
     |
     | git add
     v
Staging Area
     |
     | git commit
     v
Local Repository
     |
     | git push
     v
Remote Repository

这张图几乎可以解释:

80%的Git入门问题

七、git add到底在干什么?

1. 它不是“提交代码”

例如:

git add main.c

只是:

把当前 main.c 的内容
加入暂存区

准备参加:

下一次 commit

2. 添加所有变化

git add .

初学阶段非常常见。

但在实际项目中,提交前建议先:

git status

确认到底有哪些文件会被提交。


八、git commit是什么?

git commit \
    -m "fix: correct progress calculation"

意思是:

把当前暂存区的状态
记录为一个新的本地版本

所以:

commit

本质更接近:

创建项目历史快照

九、commit message应该怎么写?

1. 不推荐

update
修改代码
123
test
aaa

过几个月以后几乎无法理解。


2. 更推荐

例如:

fix: prevent division by zero

feat: add progress bar

refactor: split process module

docs: update README

让别人看到历史时能够快速知道:

为什么改

十、git push是什么?

执行:

git push

意味着:

把本地提交
同步到远程仓库

第一次绑定上游分支时可能使用:

git push -u origin main

以后:

git push

即可。


十一、2026年使用GitHub要注意认证方式

1. 不要再使用GitHub账户密码进行Git认证

GitHub 已经不再支持:

用户名 + GitHub登录密码

完成 Git 的 HTTPS 操作认证。

现在常见方法有:

SSH

Personal Access Token

GitHub CLI

Git Credential Manager

2. HTTPS方式

远程地址类似:

https://github.com/user/project.git

如果命令行要求输入 Password:

不是输入GitHub登录密码

而是使用PAT等认证方式

3. SSH方式

远程地址类似:

[email protected]:user/project.git

比较适合:

长期在自己的开发机器上使用

配置完成后:

git pull
git push

都比较方便。


十二、git clone:把远程仓库复制到本地

git clone <repository>

结果大致是:

远程 GitHub 仓库
        ↓
    git clone
        ↓
本地工作区 + .git仓库

进入:

cd project

即可开始开发。


十三、本地已有项目如何接入Git?

1. 初始化

git init

2. 添加文件

git add .

3. 第一次提交

git commit \
    -m "init: initial project"

4. 添加远端

git remote add origin <repository>

查看:

git remote -v

5. 推送

git push -u origin main

具体默认分支可能取决于:

仓库配置
Git版本
项目设置

所以遇到问题先:

git branch

确认本地分支名称。


十四、git status:最应该频繁使用的命令

执行:

git status

可以看到:

当前在哪个分支

哪些文件被修改

哪些文件未跟踪

哪些修改已经暂存

哪些修改还未暂存

初学 Git 时,遇到:

我现在到底什么状态?

第一条命令应该就是:

git status

十五、git diff:提交前看看自己改了什么

1. 工作区与暂存区的差异

git diff

2. 暂存区与最近提交的差异

git diff --cached

因此一个不错的提交习惯是:

修改代码
↓
git diff
↓
git add
↓
git diff --cached
↓
git commit

十六、git log:查看历史

git log

更紧凑:

git log --oneline

例如:

7c19f20 fix: correct calculation
123af92 feat: add progress bar
98cb3ab init: initial project

这里每个提交都有一个:

Commit Hash

用于唯一标识这次提交。


十七、git pull是什么?

git pull

用于:

从远端获取更新
+
整合进当前分支

多人协作时:

先 pull
再开发/提交

是一种常见流程。

但真实项目中还需要进一步理解:

fetch
merge
rebase

之间的关系。

入门阶段先掌握:

clone
status
add
commit
pull
push
log
diff

即可。


十八、.gitignore有什么用?

有些文件不应该提交:

*.o
可执行文件
构建目录
IDE配置
日志文件
临时文件

例如:

*.o
*.out

build/

.vscode/

*.log

之后:

Git默认忽略这些文件

十九、一个C/C++项目的.gitignore示例

# object files
*.o
*.obj

# executables
*.out
*.exe

# build directories
build/
cmake-build-*/

# debug files
*.core

# editor
.vscode/
.idea/

# temporary files
*.swp
*.tmp

二十、为什么Git要有暂存区?

很多人第一次接触 Git 会问:

为什么不能直接:

修改
↓
commit

暂存区的价值在于:

一次工作中可能改了很多东西

但你希望拆成:

Commit 1
修Bug

Commit 2
修改文档

Commit 3
重构函数

于是可以:

选择性 git add

让每个 Commit 更清晰。

甚至:

git add -p

可以按代码块选择:

哪些修改进入下一次提交

二十一、Git分支的基本思想

1. 为什么需要分支?

假设:

main

是稳定版本。

你要开发一个:

progress-bar

新功能。

不希望开发到一半影响主线。

于是:

main
  |
  o----o
       \
        o----o feature

2. 创建并切换分支

现代 Git:

git switch -c feature/progress

开发完成后:

git switch main

再根据团队流程:

merge
Pull Request

整合代码。


二十二、从Git进入GDB:版本管理解决不了Bug本身

Git 可以告诉我们:

代码什么时候变坏了
谁改了什么

但要真正回答:

程序为什么得到错误结果?

需要:

Debugger

Linux 下最经典的就是:

GDB

二十三、GDB是什么?

GDB:

GNU Debugger

可以帮助我们:

设置断点
单步执行
查看变量
修改变量
查看栈帧
查看调用链
监视内存或变量变化

二十四、调试之前为什么要加-g?

假设:

gcc main.c -o app

程序当然可以运行。

但是 GDB 很难获得完整的:

源文件
行号
变量名
类型

映射信息。

因此调试版本应该加入:

-g

例如:

gcc main.c \
    -g \
    -O0 \
    -Wall \
    -Wextra \
    -o app

其中:

-g
↓
生成调试信息

-O0
↓
尽量减少优化造成的调试干扰

也可以根据需求考虑:

-Og

二十五、启动GDB

gdb ./app

进入:

(gdb)

退出:

quit

或者:

Ctrl + D

二十六、list:查看源代码

list

简写:

l

查看:

main函数
list main

查看指定文件:

list main.c:20

二十七、break:设置断点

1. 按行号

break 20

简写:

b 20

2. 按函数

break main
break Sum

3. 文件加行号

break main.c:20

适合:

多文件工程

二十八、查看和管理断点

1. 查看

info breakpoints

常见简写:

i b

2. 删除

删除编号 2:

delete 2

删除全部:

delete

3. 禁用

disable 2

4. 重新启用

enable 2

二十九、run与continue

1. run

run

简写:

r

含义:

从程序开头开始执行

直到:

遇到断点
收到信号
程序结束

2. continue

continue

简写:

c

表示:

从当前停止位置继续运行

直到下一个停止点。


三十、next与step:调试最常用的区别

假设:

int n = Sum(1, 100);

1. next

next

简称:

n

执行:

下一行

但遇到:

函数调用

一般:

不会进入函数内部

2. step

step

简称:

s

遇到:

函数调用

会尝试进入:

函数内部

3. 可以类比IDE

next
≈ Step Over / F10

step
≈ Step Into / F11

三十一、finish:把当前函数执行完

如果已经进入:

Sum()

但不想继续一行一行走:

finish

作用:

运行到当前函数返回

并通常显示返回值。


三十二、until:快速执行到后面

例如:

until 30

可以让程序继续运行到:

指定位置

在调试循环时比较方便。


三十三、print:查看表达式

查看变量:

print result

简称:

p result

也可以计算表达式:

p start + end

甚至:

p array[10]

三十四、display:每次暂停自动显示

display i

之后每次程序停下:

GDB都会自动输出 i

查看 display:

info display

取消:

undisplay 1

三十五、set var:临时修改程序变量

假设程序:

int flag = 0;

导致:

结果错误

调试时可以:

set var flag = 1

再继续运行。

如果结果立刻恢复正常:

说明 flag 很可能就是问题来源

这种方法非常适合:

验证Bug假设

但注意:

修改只发生在当前调试进程

源代码本身并没有被改

三十六、backtrace:查看调用栈

backtrace

简称:

bt

例如:

#0 Divide()
#1 Calculate()
#2 Process()
#3 main()

它能回答:

程序到底是从哪一条调用链走到这里的?

在:

崩溃
段错误
深层函数错误
递归

场景中非常重要。


三十七、info locals:查看当前局部变量

info locals

可以一次看到:

当前栈帧中的局部变量

相比逐个:

p a
p b
p c

更方便。


三十八、watch:变量什么时候被改坏了?

这是一条非常有用的命令。

假设:

result

本来应该保持正确。

但某个地方莫名其妙变了。

你不知道:

是谁改的

可以:

watch result

继续:

continue

当 result 的值发生变化时:

GDB会暂停程序

并显示:

Old value
New value

这属于:

Watchpoint
数据断点

非常适合:

变量被意外修改
内存被错误覆盖
状态莫名变化

的 Bug。GDB 官方文档同样把 watchpoint 定义为在表达式值发生变化时停止程序。


三十九、条件断点

假设:

for (int i = 0;
     i < 100000;
     ++i)
{
    Process(i);
}

Bug 只在:

i == 30000

出现。

如果每次都停:

完全不可用

所以可以:

break main.c:20 if i == 30000

程序只有在:

到达20行
并且
i == 30000

时才停止。

GDB 的断点可以附加条件,条件为真时才真正停下,这在循环和高频路径中特别有用。


四十、给已有断点添加条件

假设断点编号:

2

可以:

condition 2 i == 30

于是:

Breakpoint 2

以后只在:

i == 30

时生效。


四十一、GDB最常用命令速查

目的命令
启动gdb ./app
查看代码list
设置断点break
查看断点info breakpoints
运行run
继续continue
单步不进入函数next
单步进入函数step
执行完当前函数finish
查看变量print
自动显示变量display
修改变量set var
查看调用栈backtrace
查看局部变量info locals
监视变量变化watch
删除断点delete
退出quit

四十二、一个完整GDB调试案例

1. Bug代码

#include <stdio.h>

int flag = 0;

int Sum(
    int start,
    int end)
{
    int result = 0;

    for (int i = start;
         i <= end;
         ++i)
    {
        result += i;
    }

    return result * flag;
}

int main(void)
{
    int start = 1;
    int end = 100;

    int ret =
        Sum(start, end);

    printf(
        "%d\n",
        ret
    );

    return 0;
}

我们期待:

5050

实际:

0

2. 编译调试版本

gcc main.c \
    -g \
    -O0 \
    -Wall \
    -Wextra \
    -o app

3. 启动

gdb ./app

4. main设置断点

b main
r

5. 找到Sum调用位置

l

然后:

s

进入:

Sum

6. 执行循环

可以:

until

或者逐步:

n

7. 查看result

p result

得到:

5050

说明:

求和本身正确

8. 查看flag

p flag

得到:

0

于是我们怀疑:

result * flag

就是问题。


9. 临时修改

set var flag = 1

继续:

n

最终:

5050

此时就基本确认:

Bug来自flag初始值

四十三、GDB调试思路比命令更重要

真正调试时不要:

程序一错
↓
从第一行开始next
↓
一直按几百次

更高效的思路应该是:

观察错误现象
↓
提出假设
↓
确定可疑代码区域
↓
设置断点
↓
观察关键变量
↓
缩小范围
↓
验证假设

GDB 只是:

验证假设的工具

而不是:

自动帮你找到Bug的魔法

四十四、什么是CGDB?

CGDB 可以理解成:

GDB
+
更方便查看源码的终端界面

如果纯 GDB 的:

list

使用起来不够直观,可以尝试:

CGDB

但学习阶段仍建议先掌握原生 GDB 的:

break
run
next
step
print
watch
bt

因为这些调试思想在:

VS
VSCode
CLion
GDB
LLDB

中都是共通的。


四十五、Git和GDB如何形成完整工作流?

可以形成:

拉取代码
   ↓
git pull
   ↓
编辑代码
   ↓
Vim / VSCode
   ↓
编译
   ↓
gcc / g++
   ↓
程序出现Bug
   ↓
GDB
   ↓
修复Bug
   ↓
重新测试
   ↓
git diff
   ↓
git add
   ↓
git commit
   ↓
git push

这已经是一套最基础的:

真实开发流程

四十六、一套推荐的日常Git工作流程

git status

git pull

# 修改代码

git diff

# 编译和测试

git status

git add .

git diff --cached

git commit \
    -m "fix: correct sum calculation"

git push

随着项目复杂度提高,再继续学习:

branch
merge
rebase
stash
tag
reset
revert
cherry-pick

即可。


四十七、Git与GDB最容易混淆的几个问题

1. git add不是提交

git add
↓
暂存

git commit
↓
本地提交

git push
↓
上传远程

2. commit不等于GitHub已经更新

只执行:

git commit

代码仍然主要在:

本地仓库

还需要:

git push

才能同步到远程。


3. GitHub密码不能再直接用于git push

HTTPS:

PAT / GitHub CLI / Credential Manager

或者:

SSH

而不是账户登录密码。


4. 没有-g也能用GDB,但调试体验会很差

没有调试信息时:

源码行号
变量名
函数信息

可能大量缺失。

所以:

-g

是源码级调试的核心选项。


5. next和step区别

next
↓
不进入函数

step
↓
进入函数

这是最需要记住的一组。


6. watch和display不是一回事

display x
↓
每次程序停下时显示x

watch x
↓
x发生变化时让程序停下

四十八、整套Linux开发工具知识图

                  Linux开发
                      |
      ┌───────────────┼───────────────┐
      ↓               ↓               ↓
    编辑            构建             管理
      |               |               |
     Vim          GCC / G++          Git
                      |
                   Makefile

                      |
                      ↓
                    运行
                      |
               ┌──────┴──────┐
               ↓             ↓
             正常            Bug
                              |
                              ↓
                             GDB
                              |
                              ↓
                           修复代码
                              |
                              ↓
                         Git Commit

转载自 CSDN-专业IT技术社区

原文链接:https://blog.csdn.net/Face_FeaR/article/details/167082155

文章来源转载

评论

赞0

评论列表

微信小程序
QQ小程序

关于作者

点赞数:0
关注数:0
粉丝:0
文章:0
关注标签:0
加入于:--