Git 常用操作笔记

按日常开发流程整理 Git 配置、提交、分支、远程同步、撤销、stash 和日志排查等常用操作。

GitGit版本控制常用命令

Git 是日常开发里绕不开的版本控制工具。命令很多,但真正高频使用的操作通常集中在几个场景:初始化仓库、提交代码、切分支、同步远程、撤销误操作、临时保存现场、处理冲突和查看历史。

Git 解决什么问题

没有版本控制时,项目很容易变成这样:

project-final
project-final-new
project-final-new-2
project-final-really-final

这种方式最大的问题是:你很难准确知道每个版本改了什么、是谁改的、为什么改,也很难稳定回到某个历史状态。

Git 解决的是版本记录和协作问题。它会记录:

修改了哪些文件
新增或删除了哪些内容
谁提交了这次修改
什么时候提交的
这次提交的说明是什么

所以 Git 不只是“保存代码”,而是把项目变化保存成一条可追踪、可回退、可对比的历史线。

Git 和 GitHub 的区别

Git 和 GitHub 不是一回事。

Git:安装在本地的版本控制工具
GitHub:托管 Git 仓库并支持团队协作的远程平台

只用 Git,不用 GitHub,也可以在本地完成版本控制:

git init
git add .
git commit -m "初始化项目"

GitHub 的价值在于把本地仓库放到云端,并提供协作能力,例如:

远程仓库
分支协作
Pull Request
Issue
代码审查
CI/CD 自动化
开源项目管理

除了 GitHub,GitLab、Gitee、Bitbucket 也能托管 Git 仓库。

先理解 Git 的几个区域

Git 的很多命令看起来复杂,本质上是在几个区域之间移动内容。

工作区 -> 暂存区 -> 本地仓库 -> 远程仓库

对应含义:

工作区:当前项目目录里的真实文件
暂存区:准备进入下一次提交的改动
本地仓库:已经 commit 的历史记录
远程仓库:GitHub、GitLab、Gitee 等服务器上的仓库

常见文件状态:

untracked:Git 还没有追踪的新文件
modified:已追踪文件被修改,但还没有放入暂存区
staged:改动已经放入暂存区,等待 commit
committed:改动已经提交到本地仓库

日常最常见的提交流程是:

git status
git add .
git commit -m "提交说明"
git push

配置 Git

查看当前配置:

git config --list

配置用户名和邮箱:

git config --global user.name "Your Name"
git config --global user.email "your-email@example.com"

只给当前仓库配置用户名和邮箱:

git config user.name "Your Name"
git config user.email "your-email@example.com"

查看某一项配置:

git config user.name
git config user.email

配置默认分支名:

git config --global init.defaultBranch main

创建和获取仓库

查看 Git 是否安装成功:

git --version

如果能看到类似 git version 2.x.x 的输出,说明本机已经可以使用 Git。

在当前目录初始化 Git 仓库:

git init

执行 git init 后,当前目录会出现一个隐藏的 .git 文件夹。它保存提交历史、分支、配置等内部数据,通常不要手动修改或删除。

克隆远程仓库:

git clone <repository-url>

克隆到指定目录:

git clone <repository-url> <directory>

查看远程地址:

git remote -v

添加远程仓库:

git remote add origin <repository-url>

修改远程仓库地址:

git remote set-url origin <repository-url>

查看状态和差异

查看当前工作区状态:

git status

用更简洁的格式查看状态:

git status -sb

查看工作区和暂存区之间的差异:

git diff

查看暂存区和上一次提交之间的差异:

git diff --cached

查看某个文件的差异:

git diff -- path/to/file

查看两个提交之间的差异:

git diff <commit-a> <commit-b>

添加和提交

添加指定文件到暂存区:

git add path/to/file

添加当前目录下所有改动:

git add .

交互式选择要暂存的改动:

git add -p

提交暂存区内容:

git commit -m "提交说明"

跳过暂存步骤,直接提交已经被 Git 追踪的文件:

git commit -am "提交说明"

修改最近一次提交的提交信息:

git commit --amend

把当前暂存区内容追加到最近一次提交:

git commit --amend --no-edit

git commit -am 只会处理已经被 Git 追踪的文件。新文件仍然需要先执行 git add

分支操作

查看本地分支:

git branch

查看本地和远程分支:

git branch -a

创建新分支:

git branch feature/login

切换分支:

git switch feature/login

创建并切换到新分支:

git switch -c feature/login

老版本 Git 也可以使用:

git checkout -b feature/login

重命名当前分支:

git branch -m new-branch-name

删除已经合并的本地分支:

git branch -d feature/login

强制删除本地分支:

git branch -D feature/login

合并和变基

把目标分支合并到当前分支:

git merge <branch>

注意合并方向:git merge <branch> 是把 <branch> 的变化合并到当前所在分支。

git switch main
git merge feature/login

这表示把 feature/login 合并进 main

如果两个分支修改了同一个文件的同一段内容,Git 可能无法自动判断该保留哪一份,于是产生冲突。冲突文件中通常会出现类似标记:

<<<<<<< HEAD
当前分支的内容
=======
被合并分支的内容
>>>>>>> feature/login

解决冲突的流程:

git status
# 打开冲突文件,手动保留正确内容,并删除冲突标记
git add .
git commit -m "解决合并冲突"

冲突不是 Git 出错,而是 Git 在提示:这里需要开发者自己判断最终内容。

把当前分支变基到目标分支:

git rebase <branch>

常见场景:在功能分支上同步 main 的最新代码。

git switch feature/login
git fetch origin
git rebase origin/main

如果 rebase 过程中发生冲突:

git status
# 手动解决冲突
git add .
git rebase --continue

放弃本次 rebase:

git rebase --abort

简单规则:

公共分支优先 merge,避免改写别人正在使用的历史。
个人功能分支可以 rebase,让提交历史更线性。

远程同步

拉取远程分支信息,但不自动合并:

git fetch origin

拉取并合并远程代码:

git pull

等价于:

git fetch
git merge

使用 rebase 方式拉取:

git pull --rebase

推送当前分支:

git push

首次推送新分支并建立 upstream:

git push -u origin feature/login

删除远程分支:

git push origin --delete feature/login

查看本地分支和远程分支的跟踪关系:

git branch -vv

撤销和回退

撤销工作区中某个文件的修改:

git restore path/to/file

撤销所有工作区修改:

git restore .

把文件从暂存区移回工作区:

git restore --staged path/to/file

撤销最近一次提交,但保留改动在暂存区:

git reset --soft HEAD~1

撤销最近一次提交,并保留改动在工作区:

git reset --mixed HEAD~1

撤销最近一次提交,并丢弃对应改动:

git reset --hard HEAD~1

reset --hard 会丢弃工作区内容,执行前一定要确认没有未保存的重要改动。

生成一个新的反向提交,用来撤销某次提交:

git revert <commit>

已经推送到公共分支的提交,优先使用 git revert,因为它不会改写历史。

删除和移动文件

删除文件并放入暂存区:

git rm path/to/file

停止追踪文件,但保留本地文件:

git rm --cached path/to/file

重命名或移动文件:

git mv old-name new-name

如果某个文件已经被提交过,后来才加入 .gitignore,需要先取消追踪:

git rm --cached path/to/file
git commit -m "停止追踪某文件"

临时保存现场 stash

保存当前未提交改动:

git stash

保存时加说明:

git stash push -m "临时保存登录页改动"

查看 stash 列表:

git stash list

恢复最近一次 stash,并从列表中删除:

git stash pop

恢复最近一次 stash,但保留在列表中:

git stash apply

恢复指定 stash:

git stash apply stash@{1}

删除指定 stash:

git stash drop stash@{1}

清空所有 stash:

git stash clear

如果希望把未跟踪的新文件也一起保存:

git stash -u

查看提交历史

查看提交日志:

git log

单行查看:

git log --oneline

带分支图查看:

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

查看最近 5 条提交:

git log -5 --oneline

查看某个文件的提交历史:

git log -- path/to/file

查看某次提交的详情:

git show <commit>

切到某个历史提交查看当时的代码:

git checkout <commit>

这时可能会进入 detached HEAD 状态,表示当前不在某个正常分支上,而是在一个历史提交点上查看代码。如果只是查看旧版本没有问题;如果要继续开发,应该基于它创建新分支:

git switch -c recover-from-old-commit

回到主分支:

git switch main

查看每一行最后是谁改的:

git blame path/to/file

查看所有 HEAD 移动记录:

git reflog

git reflog 很适合用来找回误删分支、误 reset 前的提交位置。

标签 tag

查看标签:

git tag

创建轻量标签:

git tag v1.0.0

创建带说明的标签:

git tag -a v1.0.0 -m "版本 1.0.0"

推送指定标签:

git push origin v1.0.0

推送所有标签:

git push origin --tags

删除本地标签:

git tag -d v1.0.0

删除远程标签:

git push origin --delete v1.0.0

常见场景速查

1. 新项目第一次提交并推送

git init
git add .
git commit -m "初始化项目"
git branch -M main
git remote add origin <repository-url>
git push -u origin main

2. 开发新功能

git switch main
git pull --rebase
git switch -c feature/login
# 修改代码
git add .
git commit -m "实现登录功能"
git push -u origin feature/login

3. 提交前检查改了什么

git status -sb
git diff
git diff --cached

4. 刚提交完发现漏了一个文件

git add missing-file
git commit --amend --no-edit

5. 本地改乱了,只想恢复某个文件

git restore path/to/file

6. 本地提交错了分支

先记录当前提交:

git log -1 --oneline

切到正确分支并应用提交:

git switch correct-branch
git cherry-pick <commit>

回到错误分支撤销那次提交:

git switch wrong-branch
git reset --hard HEAD~1

如果错误提交已经推送到公共分支,不要直接 reset --hard 后强推,应该先确认团队协作影响。

7. 想找回误删的提交

git reflog
git switch -c recover-branch <commit>

Pull Request 协作流程

在团队协作中,通常不建议直接把代码推到 main 分支。更常见的流程是:

从 main 创建功能分支
在功能分支上开发
提交并 push 到远程
在 GitHub 上创建 Pull Request
团队成员进行 code review
确认没问题后合并到 main

Pull Request 简称 PR,本质是:我在某个分支完成了一组修改,请团队检查并合并到目标分支。

创建 PR 时常见的两个概念:

base:目标分支,比如 main
compare:来源分支,比如 feature/login

也就是把 compare 分支的修改合并进 base 分支。

GitHub 会在 PR 页面展示:

包含哪些提交
哪些文件发生变化
哪些行被新增或删除
是否存在冲突
是否通过自动检查

PR 的价值不只是合并代码,更重要的是让代码进入稳定分支之前经过 review,降低问题直接进入主分支的风险。

一条完整的日常工作流

# 1. 回到主分支并同步远程最新代码
git switch main
git pull --rebase

# 2. 创建并切换到功能分支
git switch -c feature/login

# 3. 修改代码后检查状态
git status -sb
git diff

# 4. 添加到暂存区并提交
git add .
git commit -m "新增登录功能"

# 5. 推送到远程分支
git push -u origin feature/login

之后在 GitHub 上创建 PR。 如果 review 后需要继续修改,就在同一个分支上继续提交并推送:

git add .
git commit -m "根据 review 修改登录校验逻辑"
git push

PR 会自动更新。

初学时最容易混淆的点

git add 不是提交。它只是把修改放入暂存区,真正保存版本的是 git commit

git commit 不是上传 GitHub。它只保存到本地仓库,上传远程需要 git push

git fetch 不会直接改你的工作区文件。它只是下载远程更新信息;如果要拉取并合并,使用 git pull

分支之间不会自动同步。你在 feature/login 上提交的内容,不会自动出现在 main,需要 mergerebase 或通过 PR 合并。

git rebase 可以让历史更线性,但会改写提交历史。自己的本地功能分支可以用;多人共享的公共分支要谨慎。

几个使用习惯

提交前先看状态:

git status -sb

提交前先看差异:

git diff
git diff --cached

推送前同步远程:

git fetch origin
git status -sb

不确定某个危险命令会影响什么时,先创建一个临时分支:

git switch -c backup-before-reset

Git 的重点不是背命令,而是知道当前改动在哪个区域、下一步要把它移动到哪里。只要围绕“工作区、暂存区、本地仓库、远程仓库”这条线理解,常见操作都会清晰很多。