Git/GitHub的基本使用
2026/9/10 22:51:16 网站建设 项目流程

Git/GitHub 常用操作

前言

很多初学者刚接触 Git 时,会把 Git 理解成“上传代码的工具”。

这种理解不完全错,但很容易导致后面遇到分支、冲突、远端同步、push 被拒绝、PR 合并、rebase、stash、reflog 等问题时完全不知道 Git 在做什么。

更准确地说:

Git 是本地代码版本数据库。 GitHub 是远端 Git 仓库 + Web 页面 + 协作平台。

Git 真正重要的不是某一条命令,而是它背后的模型:

工作区 working tree ↓ git add 暂存区 staging area / index ↓ git commit 本地仓库 local repository ↓ git push 远端仓库 remote repository,例如 GitHub

本文面向有一定 Linux C/C++ 基础、但 Git/GitHub 体系还不熟悉的开发者,目标不是罗列命令,而是通过一条完整学习路线,建立可以支撑日常开发的 Git/GitHub 工作流。

本文约定:

  • Linux 环境以 Ubuntu 24.04 为例。
  • Windows 环境以 PowerShell 为例。
  • 远端仓库以 GitHub 为例。
  • 项目以一个简单 C 语言项目git_c_demo为练习载体。
  • 命令或参数第一次出现时会解释其功能和用途,后续重复出现时不再重复解释。

一、安装 Git 与基础配置

在 Linux 上先检查 Git 是否已经安装:

git--version

git:调用 Git 程序。
--version:查看当前安装的 Git 版本。

如果没有安装,可以执行:

sudoaptupdatesudoaptinstallgit-y

sudo:以管理员权限执行命令。
apt:Ubuntu/Debian 系统的软件包管理工具。
update:更新本地软件包索引。
install:安装软件包。
-y:自动回答 yes,避免安装过程中反复确认。

安装后配置用户名和邮箱:

gitconfig--globaluser.name"你的名字"gitconfig--globaluser.email"你的邮箱"

git config:查看或修改 Git 配置。
--global:设置当前用户级别的 Git 配置,对当前系统用户的所有仓库生效。
user.name:提交记录中显示的作者名称。
user.email:提交记录中显示的作者邮箱。

查看配置:

gitconfig--global--list

--list:列出当前配置项。

注意:这里的用户名和邮箱会写进 commit 作者信息里,不等于 GitHub 登录账号,但建议邮箱与 GitHub 账号邮箱保持一致。


二、创建第一个本地 Git 仓库

先创建一个 C 项目目录:

mkdirgit_c_democdgit_c_demo

mkdir:创建目录。
cd:切换当前目录。

创建一个简单的main.c

cat>main.c<<'EOF' #include <stdio.h> int main(void) { printf("hello git\n"); return 0; } EOF

cat:在终端打印或写入文件内容。这里配合重定向创建文件。
>:把输出写入指定文件,会覆盖原文件。
<<'EOF' ... EOF:Here Document,用来一次性写入多行文本。

创建Makefile

cat>Makefile<<'EOF' CC = gcc CFLAGS = -Wall -Wextra -g all: main main: main.c $(CC) $(CFLAGS) -o main main.c clean: rm -f main EOF

测试编译:

make./main

make:根据Makefile中的规则执行构建。
./main:运行当前目录下的main可执行文件。./表示当前目录。

初始化 Git 仓库:

gitinit

git init:在当前目录创建一个新的 Git 仓库,本质是生成.git目录。

查看当前仓库状态:

gitstatus

git status:查看当前分支、工作区、暂存区状态,包括未跟踪文件、已修改文件、待提交内容等。

这时你会看到main.cMakefileuntracked files

untracked files表示:

Git 看到了这些文件, 但还没有开始跟踪它们。

把文件加入暂存区:

gitaddmain.c Makefile

git add:把工作区中的修改加入暂存区。
查看暂存区的文件

gitls-files--cached

等待下一次 commit,提交到本地仓库:

gitcommit-m"初始化 C 项目"

git commit:把暂存区中的内容保存为一次提交。
-m:message,直接在命令行指定提交说明。

查看提交历史:

gitlog--oneline

git log:查看提交历史。
--oneline:每个 commit 只显示一行,便于快速查看。

到这里,最核心流程已经完成:

写代码 ↓ git add ↓ git commit

三、理解 status、diff、log

日常开发中,下面三个命令使用频率非常高:

gitstatusgitdiffgitlog

修改main.c

sed-i's/hello git/hello git and github/'main.c

sed:Linux 下的文本处理工具。
-i:直接修改文件内容。
s/旧内容/新内容/:替换文本。

查看工作区差异:

gitdiff

git diff:查看工作区和暂存区之间的差异。简单理解就是:你改了什么,但还没git add

加入暂存区:

gitaddmain.c

查看暂存区差异:

gitdiff--staged

--staged:查看暂存区和上一次提交之间的差异,也就是即将被 commit 的内容。

提交:

gitcommit-m"修改 hello 输出内容"

查看图形历史:

gitlog--oneline--graph--decorate--all

--graph:用 ASCII 图显示分支关系。
--decorate:显示分支名、HEAD、tag 等引用信息。
--all:显示所有本地分支和远端追踪分支的历史。

建议以后经常使用:

gitlog--oneline--graph--decorate--all

它能帮助你看清楚当前仓库的真实历史结构。


四、撤销错误操作:restore、reset、revert 的基本思想

Git 里“撤销”不是一个命令解决所有问题,而是要先判断你要撤销的是哪一层:

工作区修改? 暂存区修改? 已经 commit 的修改?

撤销工作区修改:

gitrestore main.c

git restore:恢复工作区文件内容。常用于撤销还没有加入暂存区的修改。

如果文件已经git add到暂存区,先撤出暂存区:

gitrestore--stagedmain.c

--staged:只把文件从暂存区移回工作区,不删除实际修改。

如果 commit 已经提交,而且希望用一个新的提交来抵消它,可以使用:

gitrevert<commit_hash>

git revert:创建一个新的 commit,用来反向撤销指定 commit 的修改。
<commit_hash>:某次提交的编号。

revert的特点是安全,因为它不删除历史,而是新增一条“反向修改”。

日常建议:

未 add:git restore 已 add 未 commit:git restore --staged 已 commit 且已共享:优先 git revert

五、分支:branch、switch、merge

分支是 Git 的核心能力之一。

查看当前分支:

gitbranch

git branch:查看、创建或删除本地分支。

创建并切换新分支:

gitswitch-cfeature/demo

git switch:切换分支。
-c:create,创建新分支并切换过去。
feature/demo:分支名。

切换回 main:

gitswitch main

在 feature 分支提交后,可以合并回 main:

gitmerge feature/demo

git merge:把指定分支的修改合并到当前分支。

删除已合并分支:

gitbranch-dfeature/demo

-d:delete,安全删除本地分支。如果 Git 认为该分支未合并,会拒绝删除。

分支的基本模型是:

main | A \ B feature/demo

合并后可能变成:

A --- B main

或者产生 merge commit:

A ---- M main \ / B --

六、冲突:两个分支改了同一处代码怎么办?

冲突的本质是:

两个分支改了同一个位置, Git 不知道最终应该保留哪一个版本。

例如:

<<<<<<<HEADprintf("hello from main branch\n");=======printf("hello from feature branch\n");>>>>>>>feature/demo

含义是:

<<<<<<< HEAD 到 ======= 当前分支的内容。 ======= 到 >>>>>>> 要合并进来的分支内容。

解决冲突的标准流程:

gitstatuscatmain.cnanomain.cgitaddmain.cgitcommit

nano:Linux 下常见的终端文本编辑器。
不带-mgit commit:打开编辑器填写提交信息,常用于 merge commit。

解决冲突时必须删除:

<<<<<<< ======= >>>>>>>

最终文件应该是干净、可编译的代码。

冲突不是错误,而是 Git 在告诉你:

我不能替你决定最终代码应该是什么, 需要你自己判断。

七、GitHub:远端仓库与 SSH 连接

GitHub 可以理解成:

GitHub = 远端 Git 仓库 + Web 页面 + 协作工具

它不仅能保存代码,还能支持:

README Issues Pull Request Actions Releases Wiki

Linux 开发中推荐使用 SSH 连接 GitHub。

检查 SSH 目录:

ls-al~/.ssh

ls:列出目录内容。
-a:显示隐藏文件。
-l:使用长格式显示文件详细信息。
~/.ssh:当前用户的 SSH 配置目录。

生成 SSH key:

ssh-keygen-ted25519-C"你的邮箱"

ssh-keygen:生成 SSH 密钥。
-t:指定密钥类型。
ed25519:一种现代 SSH 密钥算法。
-C:添加注释,通常写邮箱,方便识别密钥用途。

启动 ssh-agent:

eval"$(ssh-agent-s)"

eval:执行字符串中的命令。
ssh-agent -s:启动 SSH agent,并输出可被 shell 执行的环境变量设置。

添加私钥:

ssh-add ~/.ssh/id_ed25519

ssh-add:把私钥加入 ssh-agent,避免每次连接都手动指定。

查看公钥:

cat~/.ssh/id_ed25519.pub

只复制.pub公钥到 GitHub,不要复制没有.pub的私钥文件。

测试连接:

ssh-Tgit@github.com

ssh:通过 SSH 协议连接远程主机。
-T:不分配远程终端,只测试认证连接。
git@github.com:GitHub SSH 连接地址。

成功时通常会看到:

Hi 用户名! You've successfully authenticated...

八、本地仓库连接 GitHub:remote、push、origin/main

如果本地已经有仓库,GitHub 上创建了空仓库,可以添加远端:

gitremoteaddorigin git@github.com:用户名/git_c_demo.git

git remote:管理远端仓库。
add:添加远端。
origin:远端仓库别名,约定俗成常用这个名字。
git@github.com:用户名/仓库名.git:SSH 格式的远端仓库地址。

查看远端配置:

gitremote-v

-v:verbose,显示详细远端地址,包括 fetch 和 push 地址。

第一次推送 main:

gitpush-uorigin main

git push:把本地提交推送到远端仓库。
-u:建立 upstream 追踪关系。
origin:远端仓库名。
main:要推送的本地分支名。

执行后建立关系:

本地 main ←→ 远端 origin/main

这里要区分:

main: 本地分支。 origin/main: 本地记录的远端 origin 上 main 分支的状态。 它不是 GitHub 本身,而是本地保存的一份远端分支快照。

如果远端地址写错,可以修改:

gitremote set-url origin git@github.com:用户名/git_c_demo.git

set-url:修改已有远端的 URL 地址。


九、clone:第二台电脑如何接入项目

如果 Windows 主机要接入同一个 GitHub 仓库,应使用:

git clone git@github.com:用户名/git_c_demo.git

git clone:复制一个已有 Git 仓库到本地,包括代码、.git目录、提交历史、分支、远端配置等。

注意:

clone 不是下载源码。 clone 是复制整个 Git 仓库。

所以 clone 后:

不需要 git init。 不需要 git remote add origin。

因为 clone 已经自动完成了:

创建 .git 复制历史 设置 origin 检出默认分支 main 建立 upstream

Windows 上建议使用 PowerShell:

mkdir D:\GitStudy cd D:\GitStudy git clone git@github.com:用户名/git_c_demo.git cd git_c_demo git status

Windows 下查看文件:

dir

dir:PowerShell/CMD 下查看当前目录文件列表。

查看文件内容:

Get-Contentmain.c

Get-Content:PowerShell 下读取并打印文件内容。

打开文本文件:

notepad main.c

notepad:打开 Windows 记事本编辑文件。


十、双机协作:fetch 和 pull

典型环境是:

Ubuntu 24.04 虚拟机 │ │ git push ▼ GitHub ▲ │ git fetch / git pull Windows 主机

一台机器 push 后,另一台机器不会自动变化。

在另一台机器上可以先执行:

git fetch

git fetch:从远端获取最新提交、分支、标签等信息,更新origin/main,但不修改当前本地分支和工作区文件。

fetch 后查看历史:

git log--oneline--graph--decorate--all

你可能看到:

origin/main 已经前进 HEAD -> main 还停在旧提交

如果要真正同步当前分支:

git pull

git pull:从远端拉取并合并到当前分支。简单理解:

git pull = git fetch + git merge

更稳妥的习惯是:

git fetch git log--oneline--graph--decorate--all gitdiffmain origin/main git pull

git diff main origin/main:比较本地main和远端追踪分支origin/main的差异。


十一、push 被拒绝:non-fast-forward

双机协作或多人协作时,经常会遇到:

! [rejected] main -> main (fetch first) error: failed to push some refs Updates were rejected because the remote contains work that you do not have locally.

意思是:

远端有你本地没有的提交。 GitHub 拒绝你的 push,防止你覆盖远端历史。

安全处理流程:

git fetch git log--oneline--graph--decorate--all git pull git push

如果 pull 过程中冲突,就按冲突流程解决:

git statusGet-Contentmain.c notepad main.c git add main.c git commit git push

不要一看到 push 被拒绝就执行:

gitpush-f

-f:force,强制推送。它可能覆盖远端已有提交,团队开发中非常危险。


十二、GitHub Pull Request 工作流

真实团队开发通常不直接往main推代码,而是:

main 保持稳定 feature 分支开发 Pull Request 合并

标准流程:

gitswitchmain git pull gitswitch-c feature/pr-demo notepad main.c gitdiffgit add main.c git commit-m"演示 Pull Request 工作流"git push-u origin feature/pr-demo

然后在 GitHub 网页上:

Pull requests ↓ New pull request ↓ base: main compare: feature/pr-demo ↓ Create pull request

术语解释:

Pull Request: GitHub 上的合并请求,用来请求把某个分支的修改合并到目标分支。 base: 目标分支,通常是 main。 compare: 要合并进来的分支,通常是 feature 分支。

PR 页面重点看:

Conversation: 讨论区。 Commits: 这个 PR 包含哪些提交。 Files changed: 这个 PR 修改了哪些文件和哪些行。 Checks: 自动检查结果,例如测试、编译、代码扫描。

确认没问题后:

Merge pull request Confirm merge Delete branch

PR 合并发生在 GitHub 上,但本地不会自动更新,所以还要:

gitswitchmain git pull git branch-d feature/pr-demo

十三、PR 后续修改与 Code Review

真实开发中,PR 很少一次就合并。常见流程是:

创建 PR ↓ review 提意见 ↓ 本地继续改 ↓ commit + push 到同一个 feature 分支 ↓ 原 PR 自动更新

Code Review 是合并前的代码检查和讨论过程。常见动作包括:

Comment: 只发表评论。 Approve: 批准 PR。 Request changes: 请求修改,暂时不建议合并。

关键点:

PR 跟踪的是 compare 分支,不是某一次 commit。

所以如果你已经创建了feature/review-demo的 PR,后续只需要继续在这个分支上修改:

git branch notepad main.c gitdiffgit add main.c git commit-m"根据 review 修改输出内容"git push

GitHub 上原来的 PR 会自动更新,不需要重新创建 PR。


十四、stash:临时保存做到一半的工作

日常开发中经常会出现:

代码写到一半,还不能 commit, 但突然需要切回 main 处理别的任务。

这时使用 stash。

git stash push-m"临时保存当前修改"

git stash:管理临时保存的修改。
push:把当前未提交修改压入 stash 栈。这里的 push 不是推送到 GitHub。
-m:message,给这次 stash 添加说明。

查看 stash 列表:

git stash list

list:列出当前仓库中的 stash 记录。

恢复 stash:

git stash apply stash@{0}

apply:把指定 stash 的内容恢复到当前工作区,但保留 stash 记录。
stash@{0}:最新的一条 stash 记录。

删除 stash:

git stash drop stash@{0}

drop:删除指定 stash 记录。

更快捷的方式:

git stash pop

pop:恢复最新 stash,并在恢复成功后删除这条 stash。

如果新建了未跟踪文件,也想一起 stash:

git stash push-u-m"保存包括新文件的修改"

-u:include untracked,把未跟踪文件也一起保存进 stash。

注意:

stash 是本地操作。 不会 push 到 GitHub。 Windows 的 stash,Ubuntu 看不到。

十五、rebase:让 feature 分支基于最新 main

当你从main创建 feature 分支后,别人又往main合并了新代码,你的 feature 分支就落后了。

这时有两种方式:

merge main 到 feature rebase feature 到最新 main 后面

基础 rebase 用法:

gitswitchmain git pull gitswitchfeature/rebase-demo git rebase main

git rebase:把当前分支上的提交重新应用到另一个分支后面。
main:这里表示把当前 feature 分支的提交重新放到最新main后面。

rebase 前:

F feature / A --- M main

rebase 后:

A --- M --- F' feature | main

注意:F会变成F',commit hash 可能变化。

commit hash:每个 commit 的唯一编号。提交内容、父提交、作者信息或时间变化时,hash 通常也会变化。

如果 rebase 过程中冲突:

git status notepad 冲突文件 git add 冲突文件 git rebase--continue

--continue:解决冲突并git add后,继续执行被暂停的 rebase。

如果状态混乱:

git rebase--abort

--abort:取消当前 rebase,恢复到 rebase 开始前的状态。

安全原则:

自己的本地 feature 分支可以 rebase。 main 分支不要随便 rebase。 已经共享给别人的分支不要随便 rebase。

十六、.gitignore:已经被跟踪的文件为什么 ignore 不掉?

.gitignore的核心规则是:

.gitignore 只影响未跟踪文件。

如果一个文件已经被git add/git commit过,它已经是 tracked file。之后即使写进.gitignore,Git 也会继续跟踪它。

判断文件是否被 Git 跟踪:

gitls-files local_config.txt

git ls-files:列出 Git 当前正在跟踪的文件。后面跟文件名时,用来判断该文件是否在跟踪列表中。

让 Git 停止跟踪文件,但保留本地文件:

gitrm--cached local_config.txt

git rm:让 Git 删除某个文件。
--cached:只从 Git 的索引/跟踪列表中移除,不删除工作区真实文件。

如果是目录:

gitrm-r--cached build/

-r:recursive,递归处理目录中的所有文件。

查看被忽略文件:

git status--ignored

--ignored:让git status额外显示被.gitignore忽略的文件。

C/C++ 项目常见.gitignore

# object files *.o *.out *.a *.so *.exe # executable main # build directories build/ cmake-build-*/ # debug/core/log core core.* *.log # editor .vscode/ .idea/ *.swp # local config local_config.txt

通常应该提交:

.c / .h / .cpp / .hpp Makefile CMakeLists.txt README.md .gitignore 测试代码 必要脚本

通常不应该提交:

.o 文件 可执行文件 build 目录 core dump 日志文件 本地配置 IDE 个人配置 临时测试文件

十七、reflog:误操作后的救命记录

如果你 reset 错了,或者发现 commit “不见了”,先不要慌。

执行:

git reflog

git reflog:查看本地 HEAD 或分支引用的移动记录,常用于找回 reset、rebase、切分支等操作后“看起来丢失”的提交。

git loggit reflog的区别:

git log: 查看当前分支能访问到的提交历史。 git reflog: 查看 HEAD 和分支指针最近移动过的位置。

模拟回退:

git reset--hard HEAD~1

git reset:移动当前分支指针,让当前分支回到指定 commit。
--hard:让当前分支、暂存区、工作区都恢复到指定 commit,会丢弃未提交修改,危险。
HEAD~1:当前 HEAD 的上一个提交。

如果 reflog 里看到:

abc1234 HEAD@{1}: commit: 添加 reflog 演示提交

可以恢复:

git reset--hard abc1234

abc1234:目标 commit hash,要换成你自己终端里看到的编号。

注意:

reflog 是本地记录。 不会 push 到 GitHub。 Windows 的 reflog,Ubuntu 看不到。

如果你只是演示分支,想强制删除:

git branch-D feature/reflog-demo

-D:强制删除本地分支,即使它没有合并到 main,也会删除。比-d危险。


十八、日常开发推荐流程

1. 开始一个新功能

gitswitchmain git pull gitswitch-c feature/功能名

2. 开发并提交

git status gitdiffgit add 具体文件 gitdiff--staged git commit-m"清晰说明修改"

3. 推送 feature 分支

git push-u origin feature/功能名

4. GitHub 上创建 PR

Pull requests ↓ New pull request ↓ base: main compare: feature/功能名 ↓ Create pull request

5. 根据 review 修改

gitdiffgit add 具体文件 git commit-m"根据 review 修改代码"git push

6. PR 合并后本地收尾

gitswitchmain git pull git branch-d feature/功能名

7. 另一台机器同步

gitswitch maingitpullgitstatus

这就是日常开发最常用的 GitHub Flow。


十九、常见问题处理流程

1. push 被拒绝

git fetch git log--oneline--graph--decorate--all git pull git push

不要直接git push -f


2. 发生冲突

git statusGet-Content冲突文件 notepad 冲突文件 git add 冲突文件 git commit

整理文件时删除:

<<<<<<< ======= >>>>>>>

3. 代码写到一半要切任务

git stash push-u-m"说明当前临时工作"gitswitchmain git pull

恢复:

gitswitchfeature/原来的分支 git stash list git stash apply stash@{0}git stash drop stash@{0}

4. feature 分支落后 main

gitswitchmain git pull gitswitchfeature/功能名 git rebase main

如果冲突:

git status notepad 冲突文件 git add 冲突文件 git rebase--continue

5. .gitignore 不生效

gitls-files 文件名 gitrm--cached 文件名 git add.gitignore git commit-m"停止跟踪本地文件"

6. commit 看起来丢了

git status git reflog git reset--hard <commit_hash>

不确定时,不要继续乱操作,先保存git statusgit loggit reflog的输出。


二十、危险命令清单

这些命令不是不能用,而是必须知道风险。

gitreset--hard

危险点:

会丢弃未提交的工作区和暂存区修改。
gitpush-f

危险点:

会强制覆盖远端历史,可能删除别人已经 push 的提交。
gitbranch-D分支名

危险点:

会强制删除本地分支,即使它没有合并。
gitrm文件名

危险点:

会从 Git 跟踪中删除文件,也会删除工作区真实文件。

相对安全版本是:

gitrm--cached文件名

它只停止跟踪,保留本地文件。


总结

完成上述全部内容已经足够满足日常开发。上述内容总结如下:

1. 创建仓库。 2. 提交代码。 3. 查看修改。 4. 创建分支。 5. 合并分支。 6. 解决冲突。 7. 推送到 GitHub。 8. 克隆仓库。 9. 双机同步。 10. 处理 push 被拒绝。 11. 使用 Pull Request。 12. 根据 Code Review 继续修改。 13. 使用 stash 临时保存。 14. 使用 rebase 让 feature 基于最新 main。 15. 正确处理 .gitignore。 16. 使用 reflog 找回误操作后的提交。

这些能力已经能支撑:

个人项目 课程项目 实验室代码管理 GitHub 开源项目基础协作 公司中普通 feature 分支开发

进阶部分

下面这些内容在本文中未曾涉及,读者若有需要可以等真实遇到场景再学:

cherry-pick interactive rebase squash submodule Git LFS bisect worktree GitHub Actions Git 内部对象 blob / tree / commit / tag 复杂 release 流程

对于刚接触 Git 的开发者,最重要的不是继续堆命令,而是把下面这条主线用熟:

main 拉新 feature 开发 commit 保存 push 远端 PR 合并 pull 同步 stash 临时切任务 rebase 跟上 main reflog 处理误操作 .gitignore 管理无关文件

结语

Git 真正难的地方,不是记命令,而是理解每条命令在改变什么:

它改的是工作区? 它改的是暂存区? 它创建了 commit? 它移动了分支指针? 它同步了远端? 它重写了历史? 它只是本地操作,还是会影响 GitHub?

使用 Git 的最重要的习惯

提交前看 git status。 提交前看 git diff。 不要提交编译产物和本地配置。 新功能从 feature 分支开始。 合并用 PR。 出错先看状态,不要乱用危险命令。

以上就是本文全部内容

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询