Git命令核心思想

首先,我们需要理解 Git 是如何看待我们的代码的。它主要涉及四个关键区域

  1. 工作区 (Workspace): 就是你在电脑上能看到的项目文件夹,包含了你当前正在编辑和修改的文件。
  2. 暂存区 (Staging Area / Index): 一个“待提交”的缓冲区。当你对文件做了修改,并希望在下一次“存档”(commit)时包含这些修改,你就需要先把它们放到暂存区。这是一个 Git 的核心特色,它让你能够精确控制每次提交包含哪些内容。
  3. 本地仓库 (Local Repository): 你的个人代码数据库,存放在项目根目录下的 .git 文件夹里。它包含了项目所有的历史版本(commits)。你提交的代码都保存在这里。
  4. 远程仓库 (Remote Repository): 托管在网络服务器上的代码仓库(如 GitHub, GitLab)。这是你与团队成员协作、共享代码的地方。

我们的绝大部分 Git 操作,本质上就是在这四个区域之间移动和管理你的代码。

整体流程

image.png

  • 工作区 -> 暂存区 (git add): git add 是将工作区的修改“打包”,准备进行下一次提交。
  • 暂存区 -> 本地仓库 (git commit): git commit 将暂存区的内容生成一个永久快照(版本),保存在本地仓库。
  • 本地仓库 -> 远程仓库 (git push): git push 将本地的提交分享到远程服务器。
  • 远程仓库 -> 本地仓库 (git pull/fetch): fetch 只下载更新,pullfetch 的基础上还会尝试合并。
  • 暂存区 -> 工作区 (git restore): git retore 用暂存区的版本覆盖工作区的修改。
  • 以上为部分核心流程,更多详情见git命令分类内容。

Git命令分类

初始化与配置 (Setup & Config)

  • 目的:开始一个新项目或获取一个现有项目,并设置你的个人信息。
  • 在 Git 中,几乎所有命令都有丰富的拓展和变形,通常通过添加不同的标志 (flags)参数 (arguments) 来实现,下面我们分析拆解“初始化与配置”分类下这三个命令的基本用法和常用拓展。

git init创建新git仓库

基本用法: git init

在当前目录下创建一个新的 Git 仓库(即一个 .git 文件夹)。

常用变形与拓展:

  • git init [directory_name]
    • 作用: 在指定位置创建一个新文件夹,并将其初始化为 Git 仓库。
    • 场景: 你想创建一个名为 my-new-project 的项目并马上让它成为 Git 仓库,但你现在不在那个目录下。你可以直接运行 git init my-new-project,而不需要 mkdir my-new-project && cd my-new-project && git init 这一连串操作。
  • git init --bare
    • 作用: 创建一个裸仓库 (Bare Repository)
    • 区别:
      • 普通仓库(git init)包含一个 .git 目录和一个工作区(你能直接看到和编辑的项目文件)。
      • 裸仓库没有工作区,它只包含 .git 目录里的版本历史、分支信息等核心内容。它的目录结构看起来就像 .git 文件夹本身。
    • 场景: 这是用来搭建中央服务器/远程仓库的。团队成员不会直接在裸仓库里修改文件,而是将各自的修改 push 到这个裸仓库中,再从里面 pull 更新。你自己在 GitHub/GitLab 上创建的仓库,其本质就是一个裸仓库。
  • git init -b [branch_name]git init --initial-branch=[branch_name]
    • 作用: 在初始化仓库时,指定初始分支的名称。
    • 场景: 传统上,Git 的默认主分支是 master。但现在社区和很多平台(如 GitHub)推荐使用 main 作为默认主分支。通过 git init -b main,你可以让新创建的仓库直接使用 main 作为主分支名,避免后续再重命名的麻烦。

git clone克隆仓库到本地

基本用法: git clone [repository_url]

从指定的 URL 克隆一个远程仓库到本地。

常用变形与拓展:

  • git clone [url] [new_directory_name]
    • 作用: 克隆仓库,并将其保存到一个自定义名称的文件夹中。
    • 场景: 如果远程仓库名叫 project-backend-v2,但你想在本地把它命名为 api-server,就可以使用 git clone [url] api-server
    • 其他的:
      • git clone [url] . 克隆项目到目录,但是不会创建子目录
      • git clone [url] 克隆项目到目录,默认使用原项目名称创建项目
  • git clone -b [branch_name] [url]git clone --branch [branch_name] [url]
    • 作用: 只克隆指定的特定分支。
    • 场景: 一个项目有很多分支,但你只关心 development 分支的开发工作。使用这个命令,克隆完成后你的工作区会自动切换到 development 分支,而不是默认的主分支。
  • git clone --depth [number] [url]
    • 作用: 创建一个浅克隆 (Shallow Clone),只包含最近的 [number] 次提交记录,而不是全部历史。
    • 场景:
      1. 大型项目: 如果一个项目历史非常悠久、体积巨大,完整克隆可能要花费很长时间和大量磁盘空间。如果你只关心最新的代码,git clone --depth 1 [url] 会非常快。
      2. 持续集成 (CI/CD): 在自动化构建和部署流程中,通常只需要最新代码来运行测试和打包,不需要完整的 Git 历史。浅克隆可以极大提升流水线效率。
  • git clone --mirror [url]
    • 作用: 创建一个远程仓库的镜像。这会克隆一个裸仓库 (-bare),并保留所有远程跟踪分支、标签等所有引用信息。
    • 场景: 你想完整地备份一个远程仓库,或者想把一个项目从一个平台(如 GitLab)迁移到另一个平台(如 GitHub)。你可以先创建一个镜像,然后再推送到新的远程地址。

git config设置用户信息

基本用法: git config --global user.name "Your Name"

设置全局的用户信息。

git config 最重要的拓展在于它的作用域 (Scope)

作用域的层级:

Git 的配置有三个主要级别,优先级从高到低:

  1. -local (本地)
    • 作用: 配置只对当前仓库有效。配置信息保存在当前仓库的 .git/config 文件中。
    • 用法: git config --local user.name "ProjectSpecific Name" (或者不加标志,默认为 -local)
    • 场景: 你在公司的项目需要使用公司邮箱,但在自己的开源项目里想用个人邮箱。你可以在每个仓库内部进行本地配置。
  2. -global (全局)
    • 作用: 配置对当前用户的所有仓库都有效。配置信息保存在用户主目录下的 .gitconfig 文件中(例如 ~/.gitconfig)。
    • 用法: git config --global user.name "Your Default Name"
    • 场景: 设置你最常用的用户名和邮箱,这样就不用每个项目都设置一遍了。
      git config --global user.name "Your Name"
      git config --global user.email "Your email”
  3. -system (系统)
    • 作用: 配置对系统上的所有用户都有效。配置信息保存在 Git 的安装目录下(例如 /etc/gitconfig)。
    • 用法: git config --system ... (通常需要管理员权限)
    • 场景: 系统管理员为服务器上的所有用户设置统一的配置,比如公司内部的代理服务器。

其他常用拓展:

  • git config --list: 查看当前生效的所有配置项(会显示 local, global, system 的合并结果)。
  • git config --list --show-origin: 不仅显示配置项,还显示它们分别来自哪个配置文件(local, global, or system),非常适合用来排查配置问题。
  • git config --unset [key]: 删除一个配置项。
  • git config alias.[alias_name] "[command]": 设置命令别名,这是提升效率的神器!
    • 场景: 你觉得 git status 太长,可以设置 git config --global alias.st status。之后你只需要输入 git st 即可。
    • 常用别名设置:
      • git config --global alias.co checkout
      • git config --global alias.br branch
      • git config --global alias.ci commit
      • git config --global alias.lg "log --oneline --graph --decorate" (一个复杂的、带格式的日志输出)

总结

  • git init 的拓展主要关注在哪里和以什么形式创建仓库(普通 vs. 裸仓库)。
  • git clone 的拓展主要关注克隆什么(特定分支、部分历史)和克隆到哪里
  • git config 的拓展核心是作用域(本地、全局、系统)和自定义功能(如别名)。

理解了这些变形,你就能从一个 Git 的“使用者”向一个“高效使用者”和“定制者”迈进了。

本地核心工作流 (Core Local Workflow) - 这是你最常用的部分

  • 目的:在你的本地电脑上进行代码修改、保存和版本管理。
  • 下面围绕工作区 -> 暂存区 -> 本地仓库这个核心流程,来拆解“本地核心工作流”分类下命令的基本用法和常用拓展。

git status显示状态

基本用法: git status

显示工作区和暂存区的状态,告诉你哪些文件被修改、哪些是新增的、哪些已经准备好提交。

常用变形与拓展:

  • git status -sgit status --short
    • 作用: 提供一个简短、紧凑的输出格式。这是很多经验丰富的开发者最常用的状态查看方式。
    • 输出解读: 输出是两列字符,后面跟着文件名。
      • 第一列表示暂存区的状态。
      • 第二列表示工作区的状态。
      • M (左M): 文件被修改后已暂存 (git add)
      • M (右M): 文件被修改但未暂存
      • A : 新文件已暂存
      • ??: 未被Git跟踪的新文件
      • D : 文件被删除后已暂存
      • D (右D): 文件在工作区被删除但未暂存
    • 场景: 当你只想快速扫一眼当前有哪些文件发生了变化时,git status -s 的输出一目了然,没有多余的文字干扰。
  • git status -bgit status --branch
    • 作用: 在状态输出的顶部,额外显示当前所在的分支,以及与上游(远程)分支的同步情况。

    • 输出示例:

      ## main...origin/main [ahead 1]

      这表示你当前在 main 分支,该分支跟踪的是 origin/main,并且你有一个本地提交(ahead 1)尚未推送到远程。

    • 场景: 随时了解你的本地分支与远程分支的关系,是领先、落后还是同步,对于协作开发至关重要。

  • git status -sb
    • 作用: shortbranch 两个选项的结合,提供了最紧凑但信息又足够丰富的状态概览。很多开发者会为它设置一个别名,如 git sb

git add添加到暂存区

基本用法: git add [file]

将指定文件的修改从工作区添加到暂存区。

常用变形与拓展:

  • git add .
    • 作用: 将当前目录下所有被修改(modified)和新增(untracked)的文件都添加到暂存区。这是最常用的 add 命令之一。
    • 场景: 你在项目中修改了多个文件,并新建了几个文件,想一次性全部提交,直接在项目根目录运行 git add . 即可。
  • git add -ugit add --update
    • 作用: 只添加已被跟踪的文件的修改(包括修改和删除),不会添加新创建的文件(untracked files)。
    • 场景: 你改了3个文件,同时又在项目里创建了一些临时的测试文件。你只想提交那3个文件的改动,而不希望把新文件加进去,这时 git add -u 就非常方便。
  • git add -Agit add --all
    • 作用: add 命令的“终极版”,将所有变化(包括新文件、修改、删除)都添加到暂存区。可以看作是 git add .git add -u 的合集。
  • git add -pgit add --patch
    • 作用: 交互式添加。Git 会逐一展示文件中每一块(hunk)的修改,然后询问你是否要将这一块修改添加到暂存区。
    • 交互选项: 你会看到 Stage this hunk [y,n,q,a,d,s,e,?]?
      • y: 暂存这个代码块
      • n: 不暂存这个代码块
      • s: 将这个代码块拆分成更小的块,进行更精细的选择
      • e: 手动编辑这个代码块
      • q: 退出交互模式
    • 场景: 这是创建清晰、原子化提交的神器。比如你在一个文件里同时修复了一个 Bug 并做了一些代码格式化,你可以通过 git add -p 只把修复 Bug 的那几行代码添加到暂存区并提交,然后再进行下一次提交。

git commit创建提交

基本用法: git commit -m "Your concise message"

将暂存区的内容创建一个新的提交,并附上一句简短的说明。

常用变形与拓展:

  • git commit (不带 m)
    • 作用: Git 会自动打开你配置的默认文本编辑器(如 Vim, Nano, VS Code),让你输入一个完整格式的提交信息。
    • 格式规范: 通常是第一行写一个不超过50个字符的简短摘要,然后空一行,再写详细的描述。
    • 场景: 对于比较重要的修改,一句话说不清楚,需要详细解释“为什么这么改”以及“带来了什么影响”。这是编写高质量提交信息的标准做法。
  • git commit -a -m "Message"git commit --all -m "Message"
    • 作用: 一个快捷方式,它会跳过 git add 步骤,直接将所有已被跟踪的文件(不包括新文件)的修改进行提交。相当于 git add -ugit commit -m 的组合。
    • 注意: 这个命令很方便,但也存在风险,因为它可能会将你不想提交的修改也一并提交了。建议在确认所有修改都无误的小型提交中使用。
  • git commit --amend
    • 作用: 修改你最后一次的提交。这是一个非常有用的“后悔药”。
    • 场景:
      1. 修改提交信息: 刚提交完发现消息里有错别字,运行 git commit --amend 会打开编辑器让你重新编辑上次的提交信息。
      2. 补充文件: 刚提交完发现漏掉了一个文件,可以先 git add [missed_file],然后运行 git commit --amend --no-edit-no-edit 选项表示沿用上一次的提交信息,只把新暂存的文件添加进去。
    • 黄金法则: 绝对不要对已经推送到共享远程仓库的提交使用 -amend,因为它会重写历史,给协作者带来麻烦。只在你的本地修改时使用。
  • git commit -vgit commit --verbose
    • 作用: 在打开的编辑器中,除了让你填写提交信息外,还会将本次提交的具体代码差异(diff)显示在下方(作为注释)。
    • 场景: 当你准备编写详细的提交信息时,可以直接在编辑器里看到所有代码改动,帮助你写出更准确的描述,而无需切回命令行再用 git diff 查看。

补充:本地文件管理命令:rm和mv

与核心工作流紧密相关的还有两个命令:删除文件、移动/重命名文件,它们是 Git 推荐的文件操作方式:

  • git rm [file]: 从工作区和暂存区同时删除一个文件。它相当于 rm [file] + git add [file]
    • 变形: git rm --cached [file] 是一个非常重要的命令,它只从暂存区删除文件,但保留工作区的文件
    • 场景: 你不小心把一个日志文件或者包含密码的配置文件 add 甚至 commit 了。你想让 Git 不再跟踪它,但又不想删除这个文件本身。这时用 git rm --cached [file],然后再把文件名加入 .gitignore,就完美解决了问题。
  • git mv [old_name] [new_name]: 用 Git 的方式移动或重命名文件。它相当于 mv [old] [new] + git rm [old] + git add [new]

通过掌握这些变形,你可以将这一套核心工作流玩得非常熟练,极大地提升代码管理的质量和效率。

分支管理 (Branching)

  • 目的:在不影响主线(通常是 mastermain 分支)的情况下,进行新功能开发或Bug修复。这是 Git 实现并行开发、保持主线稳定的核心功能。
  • 分支管理是 Git 的精髓所在,它让并行开发、功能实验和 Bug 修复变得安全和高效。因此,这个模块下的命令有着极其重要和强大的拓展,理解它们是从 Git 新手迈向高手的关键一步。下面我们来拆解“分支管理”分类下命令的基本用法和常用拓展。

git branch列出/创建/跟踪/删除分支等

基本用法:

  • git branch: 列出所有本地分支。
  • git branch [branch-name]: 基于当前 commit 创建一个新分支,但切换过去。

常用变形与拓展:

  • git branch -vvv:
    • 作用: 显示更详细的信息 (-verbose)。
    • v: 显示每个分支的最后一个 commit 的哈希值和提交信息。
    • vv: 非常有用!v 的基础上,还会显示每个分支的上游跟踪分支信息(如果有的话),以及领先/落后情况。
    • 输出示例: my-feature 2a4b6c1 [origin/my-feature: ahead 1] Add new button
    • 场景: 快速查看所有分支的最新进展以及它们与远程仓库的同步状态。
  • git branch -r (-remotes):
    • 作用: 只列出所有远程跟踪分支(例如 origin/main, origin/feature-x)。
    • 场景: 你想看看远程仓库上都有哪些分支,以便决定接下来要 pullcheckout 哪个。
  • git branch -a (-all):
    • 作用: 列出所有本地分支远程跟踪分支
    • 场景: 获取项目所有分支的“全景图”。
  • git branch -d [branch-name] (-delete):
    • 作用: 删除一个已经完全合并到当前分支的分支。这是一个安全操作,如果分支上有没有被合并的修改,Git 会阻止你删除。
    • 场景: 功能开发完成并合并到主线后,清理掉无用的功能分支。
  • git branch -D [branch-name]:
    • 作用: 强制删除一个分支,无论它是否已被合并。
    • 场景: 你在一个分支上的开发工作半途而废,确定这些代码完全没用了,需要彻底清除这个分支。请谨慎使用!
  • git branch -m [old-name] [new-name] (-move):
    • 作用: 重命名一个分支。如果省略 [old-name],则重命名当前所在的分支。
    • 场景: 分支名有拼写错误,或者想根据团队规范更新分支命名。
  • git branch --merged / -no-merged:
    • 作用: 非常实用的筛选命令。
      • -merged: 显示所有已经合并到当前分支的分支列表。这些通常是可以安全删除的。
      • -no-merged: 显示所有尚未合并到当前分支的分支列表。这些分支上包含独立的工作。
    • 场景: 定期进行项目维护,使用 git branch --merged | xargs git branch -d 命令可以批量清理所有已合并的本地分支。

git switch / git checkout(切换分支)

说明: git checkout 是一个功能非常庞杂的旧命令,既能切换分支,又能恢复文件。为了清晰,Git 在 2.23 版本中引入了 git switch (专用于切换分支) 和 git restore (专用于恢复文件)。推荐使用新命令,但 checkout 仍然通用。

基本用法:

  • git switch [branch-name]: 切换到已存在的指定分支。
  • git checkout [branch-name]: 同样是切换分支。

常用变形与拓展:

  • git switch -c [new-branch-name] (-create):
    • 作用: 创建一个新分支并立即切换过去。这是一个原子操作。
    • 旧命令: git checkout -b [new-branch-name]
    • 场景: 这是开始新功能开发最常用的命令。 例如:git switch -c feature/user-login
  • git switch -:
    • 作用: 一个超级方便的快捷键,用于在当前分支上一个分支之间来回切换。
    • 旧命令: git checkout -
    • 场景: 你正在 feature 分支写代码,需要频繁切回 main 分支查看或合并最新代码,这个命令能极大提升效率。
  • git switch --track origin/[branch-name]:
    • 作用: 在本地创建一个新分支,并设置它跟踪一个同名的远程分支。
    • 场景: 你的同事创建了一个 feature/api-docs 分支并推送到了远程。你想在本地基于这个分支工作,就可以运行 git switch --track origin/feature-api-docs。通常,如果本地不存在同名分支,git switch feature/api-docs 也能智能地完成这个操作。

git merge合并分支

基本用法: git merge [branch-to-merge-in]

将指定分支的更改合并到当前所在的分支。

常用变形与拓展:

  • 理解两种合并方式: Git Merge 主要有两种模式,Git 会自动选择。
    1. Fast-Forward (快进合并): 如果你的当前分支没有任何新的提交,而目标分支在你的基础上前进了一步。Git 只会简单地将你的分支指针“快进”到目标分支的最新状态。历史记录是一条直线。
    2. Three-Way Merge (三方合并): 如果两个分支都各自有了新的提交(历史分叉了),Git 会找到它们的共同祖先,然后将两边的修改合并起来,并创建一个新的“合并提交” (Merge Commit)。历史记录上会看到一个分叉和汇合的“钻石”形状。
  • git merge --no-ff (-no-fast-forward):
    • 作用: 禁用 Fast-Forward 模式,强制 Git 总是创建一个新的“合并提交”,即使快进合并是可能的。
    • 场景: 这是一个非常流行的策略。它能清晰地在提交历史中标记出“某个功能分支在此处被合并进来”,即使它技术上可以被快进。这样能保持功能开发的脉络清晰可追溯,让 git log --graph 的输出更有意义。
  • git merge --squash:
    • 作用: 将目标分支上的所有提交“压扁”成一个变更集,然后放入当前分支的暂存区。它不会自动创建提交。
    • 流程: 运行 git merge --squash feature-branch 后,你需要接着运行 git commit 来手动创建一个提交。
    • 场景: 你的功能分支上有10个零碎的提交(如 “修复拼写”、”WIP”、”再试一次”)。你不想让这些杂乱无章的历史污染主分支。使用 -squash 可以将这个功能的所有代码改动,作为一个干净、完整的提交合入主分支。
  • git merge --abort:
    • 作用: 撤销/中止一次失败的合并。
    • 场景: 你在合并时遇到了大量的冲突(Conflicts),你觉得很棘手,想先放弃合并,让工作区回到合并之前的状态。git merge --abort 就是你的“救生筏”。
  • git merge -X[strategy-option]:
    • 作用: 为合并策略提供额外的选项,用于处理冲突。
    • 场景: git merge -Xignore-all-spacegit merge -Xignore-space-change 可以在解决冲突时忽略所有空白字符(空格、换行)的差异,有时能自动解决一些因为格式化工具导致的“伪冲突”。

通过这些拓展,你可以像一位“代码时空管理员”一样,精确地控制项目的历史脉络,实现整洁、可追溯且高效的团队协作。

远程协作 (Collaboration & Remote)

  • 目的:将你的本地代码与团队成员共享,或获取团队成员的最新代码。
  • 毫无疑问!远程协作是 Git 作为分布式版本控制系统的核心价值所在,因此围绕这个主题的命令提供了大量强大且精细的拓展,以应对各种团队协作场景。下面我们来深入探索它们的基础用法和变形。

git remote列出/添加/修改/显示/删除分支

基本用法:

  • git remote: 列出你配置的远程仓库的简称(通常是 origin)。
  • git remote -v: 列出简称和对应的 URL。

常用变形与拓展:

  • git remote add [name] [url]:
    • 作用: 添加一个新的远程仓库连接。
    • 场景: 最经典的场景是参与开源项目。你 fork 了一个项目到自己的 GitHub,然后 clone 到本地,这时你的 origin 指向你自己的 fork。为了能同步原作者的更新,你需要添加原项目仓库作为另一个远程连接,通常命名为 upstream
    • 示例: git remote add upstream https://github.com/original-author/project.git
  • git remote set-url [name] [new_url]:
    • 作用: 修改一个已存在的远程仓库的 URL。
    • 场景:
      1. 项目迁移,仓库地址换了。
      2. 从 HTTPS 切换到 SSH 协议以使用密钥认证,免去每次输入密码。
        • 示例: git remote set-url origin git@github.com:user/repo.git
      3. 从A仓库转到B仓库(https://github.com/mingnify/my-deepwiki-open)
        • 示例:git remote set-url origin https://github.com/mingnify/my-deepwiki-open.git
  • git remote show [name]:
    • 作用: 显示一个远程仓库的详细信息。
    • 信息包括: Fetch 和 Push 的 URL、远程仓库的 HEAD 分支(默认分支)、远程跟踪分支的状况、以及本地分支与远程分支的跟踪关系。
    • 场景: 一个非常有用的诊断工具。当你对一个远程连接的状态感到困惑时,用 git remote show origin 可以获得非常全面的信息。
  • git remote remove [name]git remote rm [name]
    • 作用: 删除一个远程仓库的连接。
    • 场景: upstream 项目已经不再维护,或者你想清理掉一个无效的远程连接。

git fetch下载分支

基本用法: git fetch [remote_name] (e.g., git fetch origin)

从远程仓库下载最新的对象(commits, files, tags),并更新你的远程跟踪分支(如 origin/main)。

核心概念: fetch 是一个绝对安全的操作。它只更新你本地的“远程数据快照”,不会以任何方式修改你的本地工作分支(如 main),也不会碰你的工作区。它让你有机会在合并前先查看远程的变动 (git log origin/main)。

常用变形与拓展:

  • git fetch --prunep:
    • 作用: 在抓取前,修剪/清理掉那些在本地存在、但远程仓库上已经被删除了的远程跟踪分支。
    • 场景: 这是保持仓库整洁的必备命令。你的同事合并并删除了一个功能分支 feature/login,在你的本地 git branch -r 列表中可能还留着 origin/feature/login-prune 会帮你清理掉这些“幽灵”分支。
    • 专业提示: 很多人会设置 git config --global fetch.prune true,让每次 fetch 都自动执行修剪。
  • git fetch --all:
    • 作用: 从所有配置的远程仓库(如 origin, upstream 等)抓取更新。
    • 场景: 当你需要同时与自己的 fork 和上游的官方仓库保持同步时,这个命令可以一次性更新所有远程信息。
  • git fetch [remote_name] [branch_name]:
    • 作用: 只从指定的远程仓库抓取一个特定的分支。
    • 场景: 你只关心某个特定功能分支的更新,不想下载其他所有分支的变动,这样可以节省时间和带宽。

git pull拉取分支

基本用法: git pull [remote_name] [branch_name] (e.g., git pull origin main)

抓取远程更新并立即尝试合并到你当前的本地分支。

核心概念: git pull 本质上是两个命令的快捷方式:git fetch + git merge。理解这一点是关键,因为它解释了为什么 pull 有时会产生合并冲突或创建一个合并提交。

常用变形与拓展:

  • git pull --rebase:
    • 作用: 使用 rebase(变基)代替 merge 来整合远程变更。
    • 流程: 它执行 git fetch,然后不是用 merge,而是用 git rebase。它会把你本地尚未推送的提交“摘下来”,然后将远程的最新提交应用到你的分支,最后再把你本地的提交“重新播放”在最顶端。
    • 结果对比:
      • pull (默认 merge): 会在历史记录中产生一个“Merge”提交,形成分叉再汇合的图形。
      • pull --rebase: 不会产生合并提交,能保持提交历史是一条干净的直线。
    • 场景: 很多团队强制使用 -rebase 来维持一个清爽、线性的提交历史。这是目前非常流行的协作策略。你可以通过 git config --global pull.rebase true 把它设为默认行为。
  • git pull --prune:
    • 作用: 和 fetch 一样,在拉取前先修剪远程已删除的分支。

git push提交分支

基本用法: git push [remote_name] [branch_name] (e.g., git push origin main)

将你的本地分支的提交上传到远程仓库。

常用变形与拓展:

  • git push -u [remote_name] [branch_name] (-set-upstream):
    • 作用: 在推送的同时,建立本地分支与远程分支的跟踪关系
    • 场景: 当你第一次推送一个在本地创建的新分支时,必须使用 u。设置好之后,未来在这个分支上工作时,你就可以简单地使用 git pushgit pull,Git 会自动知道该推送到哪里、从哪里拉取。
  • git push --force:
    • 作用: 强制推送。它会用你本地的分支状态粗暴地覆盖远程分支,忽略远程仓库上可能有的、你本地没有的任何新提交。
    • 警告: 这是一个危险的操作,尤其是在共享分支(如 main)上,因为它会销毁其他人的提交。只在你非常确定自己在做什么时使用(例如,修复一次错误的私有分支推送)。
  • git push --force-with-lease:
    • 作用: 更安全的强制推送。这是 -force 的绝佳替代品。
    • 工作原理: 它在推送前会检查一下:远程分支的状态是否和你上次 fetch 时一样。如果期间有其他人推送了新的提交,-force-with-lease拒绝推送,从而避免覆盖他人的工作。如果远程没有变化,它才会执行强制推送。
    • 场景: 当你因为 rebase 本地分支而需要强制推送时,永远优先使用 -force-with-lease
  • git push [remote_name] --delete [branch_name]:
    • 作用: 删除一个远程分支。
    • 旧语法: git push [remote_name] :[branch_name] (冒号前为空,表示推送一个“空”到远程分支,即删除它)。两个命令效果一样。
  • git push --tags:
    • 作用: 将你本地创建的所有标签(tags)推送到远程仓库。默认情况下,git push 并不会推送标签。
    • 场景: 当你完成一个版本发布(如 v1.0.0),打好标签后,需要用这个命令将版本标记共享给团队。

掌握这些远程命令的拓展,你就能自信地处理复杂的团队协作流程,无论是维护清晰的历史,还是安全地修复错误,都游刃有余。

历史记录与审查 (History & Inspection)

  • 目的:查看项目的演变历史,对比不同版本之间的差异。
  • 当然,历史记录与审查是 Git 的“侦探工具箱”,这个工具箱里的命令拥有海量的拓展选项,能让你像使用数据库查询语言一样,精准地挖掘和分析项目的全部历史。
  • 下面我们来深入探索 git loggit diff 这两个核心审查命令的强大变形。

git log显示提交历史

基本用法: git log

按时间倒序显示所有提交历史,信息比较完整。

git log 的拓展主要分为两大类:格式化输出(让信息更美观易读)和筛选过滤(只看你想看的信息)。

格式化输出 (Formatting)

  • git log --oneline:
    • 作用: 将每次提交压缩到一行显示,只包含 commit 哈希值和提交标题。
    • 场景: 快速浏览最近的提交历史,对项目的演进有一个宏观的了解。
  • git log --graph:
    • 作用: 在输出的左侧用 ASCII 字符绘制出分支与合并的图形化历史
    • 场景: 这是理解项目分支结构和合并历史的最直观方式。
  • git log --decorate:
    • 作用: 在提交记录旁显示指向该提交的所有引用(如分支名、标签名 HEAD 等)。
    • 场景: 清楚地看到 main 分支、feature 分支、v1.0 标签等分别指向哪个提交。
  • 组合使用:****git log --oneline --graph --decorate:
    • 作用: 这是最常用、最强大的日志查看命令之一,它以紧凑、图形化、信息丰富的方式展示了提交历史。强烈建议为它设置一个别名,例如 git lg
  • git log -p-patch:
    • 作用: 在显示每次提交信息的同时,附带上该次提交的具体代码变更差异 (diff)
    • 场景: 你想详细审查某几次提交到底修改了什么代码。

筛选过滤 (Filtering)

  • 按数量:
    • git log -n <number>git log -<number> (e.g., git log -5): 只显示最近的 n 次提交。
  • 按时间:
    • git log --since="2 weeks ago" (或 -after="2025-06-20"): 显示指定时间点之后的提交。
    • git log --until="yesterday" (或 -before="2025-07-01"): 显示指定时间点之前的提交。
    • 场景: 查看本周或某个时间段内团队的所有工作。
  • 按作者/提交者:
    • git log --author="John Doe": 只显示指定作者的提交。
    • git log --committer="Jane Smith": 只显示指定提交者的提交(在 rebasecherry-pick 时作者和提交者可能不同)。
    • 场景: 查看某个成员的所有提交记录,进行 Code Review 或绩效评估。
  • 按提交信息:
    • git log --grep="fix: login bug": 筛选出提交信息中包含指定字符串的提交。
    • 场景: 查找所有与修复“登录bug”相关的提交。
  • 按文件/路径:
    • git log -- <file_path>: 只显示修改过指定文件或路径的提交历史。双破折号 - 是为了将文件名和分支名等引用明确分开。
    • 场景: 查看某个特定文件的“前世今生”,了解它的所有变更历史。
  • 按代码内容 (Pickaxe):
    • git log -S"functionName": 超级强大的功能! 筛选出那些新增或删除了包含指定字符串的代码的提交。它不关心提交信息,只关心代码内容本身。
    • 场景: 查找是哪个提交引入或删除了对某个特定函数 functionName 的调用。
  • 按范围:
    • git log <branch1>..<branch2>: 显示在 branch2 中存在,但在 branch1 中不存在的提交。
    • git log main..feature/login: 查看 feature/login 分支相比 main 分支多出了哪些提交。
    • 场景: 在合并分支前,预览将要合并过来哪些新的提交。

git diff显示工作/暂存区差异

基本用法: git diff

显示工作区和暂存区之间的差异。

git diff 的强大之处在于它可以对比 Git 中任意两个点之间的代码差异。

常用变形与拓展:

  • git diff --staged-cached:
    • 作用: 显示暂存区上一次提交 (HEAD) 之间的差异。
    • 场景: 在 git commit 之前,最后检查一下你准备提交的内容(即已经 git add 的内容)是否准确无误。
  • git diff HEAD:
    • 作用: 显示工作区+暂存区上一次提交之间的所有差异。
    • 场景: 查看从上次提交到现在,你总共做了哪些修改,无论是否已暂存。
  • git diff [branch1]..[branch2]:
    • 作用: 比较两个分支最新提交 (tip) 之间的差异。
    • 场景: 查看 develop 分支和 main 分支的代码内容有哪些不同,为合并做准备。
  • git diff [commit1]..[commit2]:
    • 作用: 比较任意两次提交之间的差异。
    • 场景: 你发现某个功能在版本 v1.1 中出错了,但在 v1.0 中是好的。使用 git diff v1.0..v1.1 可以精确地看到这两个版本之间所有的代码改动,帮助你定位问题。
  • git diff --stat:
    • 作用: 不显示详细的代码差异,而是显示一个变更统计,列出哪些文件被修改了,以及每个文件增删的行数。
    • 场景: 当变更文件很多时,先用 -stat 宏观地看一下变更范围,再针对特定文件进行详细 diff
  • git diff --color-words:
    • 作用: 进行词级 (word-level) 而不是行级 (line-level) 的比较。它会高亮显示一行中具体是哪个单词发生了变化。
    • 场景: 当你只是修改了一行中的一个变量名或修正了一个拼写错误时,这个模式能让你更清晰地看到微小变动。

通过组合使用这些命令和选项,你可以构建出非常强大的审查工作流,无论是调试 Bug、理解代码演进,还是进行代码审查 (Code Review),都将变得得心应手。Git 的历史不仅仅是备份,更是一个内容丰富、可供深入挖掘的知识库。

撤销与修复 (Undoing & Fixing)

  • 目的:当你犯了错误,需要“反悔”或修改历史时使用。
  • “撤销与修复”模块是 Git 中最能体现其“时空穿梭机”能力的部分,也是新手最容易感到困惑的地方。这个模块下的命令不仅有丰富的拓展,理解它们之间的核心区别至关重要。
  • 最大的区别在于:有些命令会重写历史(对本地私有工作很方便,但对共享历史有风险),而另一些命令则通过创建新的历史来“撤销”过去(对共享历史是安全的)。
  • 下面我们来深入拆解这个“后悔药”工具箱。

git restore撤销工作/暂存区修改

核心思想: 这是 Git 2.23 版本后推出的新命令,专门用于撤销工作区和暂存区的修改,它不触及提交历史,因此非常安全。它是对 git checkoutgit reset 部分旧功能的清晰替代。

基本用法:

  • git restore [file]: 丢弃工作区中某个文件的修改,将其恢复成和暂存区一致的状态。如果该文件未被暂存,则恢复成和上一次提交 (HEAD) 一致的状态。

常用变形与拓展:

  • git restore --staged [file]:
    • 作用: “取消暂存”。将一个已经 git add 到暂存区的文件移出暂存区,但保留工作区的修改。
    • 旧命令: git reset HEAD [file] (这个老命令因为 reset 这个词有歧义,所以不推荐了)。
    • 场景: 你 git add . 的时候不小心把一个不想提交的文件加进去了,用这个命令可以把它“捞”出来。
  • git restore --source=[commit|branch] [file]:
    • 作用: 从指定的某个历史提交分支中拉取文件,并用它覆盖工作区和暂存区中的版本。
    • 场景: 你知道 feature 分支上的 config.js 文件是好的,想用它来覆盖当前分支上被改坏的版本,就可以运行 git restore --source=feature config.js。这就像一个定向的文件“时空穿梭”。

git revert新提交覆盖旧提交

核心思想: 这是最安全的“撤销提交”方式,尤其适用于共享分支。它不会删除或修改旧的提交,而是创建一个全新的提交,其内容与要撤销的提交完全相反

基本用法: git revert [commit-hash]

创建一个新提交,用来抵消指定 commit 所做的所有更改。

常用变形与拓展:

  • git revert HEAD: 撤销最近的一次提交。
  • git revert [commit1]..[commit2]:
    • 作用: 撤销一个连续的提交范围(不包括 commit1,但包括 commit2)。Git 会为这个范围内的每一次提交都尝试创建一个对应的撤销提交。
    • 场景: 一个功能分支合并进来后发现有严重问题,需要撤销整个分支的所有提交。
  • git revert -n-no-commit:
    • 作用: 只执行撤销的动作(即在工作区和暂存区应用相反的更改),但不自动创建那个新的“撤销提交”。
    • 场景:
      1. 你想一次性撤销多个不连续的提交,然后将这些撤销的更改合并成一个“撤销提交”。你可以对每个目标提交都运行 git revert -n,最后再手动 git commit
      2. 在提交前,你想先审查或修改一下撤销操作所带来的代码变动。

git reset重置

核心思想: 这是一个非常强大但有潜在危险的命令。它的本质是移动 HEAD 指针,让它指向某个历史提交,从而达到“重置”或“撤销”的目的。它会重写历史,因此绝对不要在已经推送到共享分支的提交上使用它

reset 最重要的拓展是它的三个模式 (--soft, --mixed, --hard),它们决定了在移动 HEAD 指针后,对暂存区工作区做什么。

基本用法: git reset [commit-hash]

三大模式:

  • git reset --soft [commit]:
    • 作用: 最温柔的重置。只移动 HEAD 指针到指定的提交。暂存区和工作区的内容完全不变
    • 效果: 所有在 [commit] 之后提交的更改,现在都变成了“已暂存”状态。
    • 场景: 你刚刚提交了 3 次,但觉得这 3 次提交应该合并成一个。你可以运行 git reset --soft HEAD~3,这样你的 HEAD 回到了 3 次提交之前,但所有的代码改动都已在暂存区,你只需运行一次 git commit 就可以把它们合并成一个干净的提交。
  • git reset --mixed [commit] (这是默认模式):
    • 作用: 移动 HEAD 指针,并清空暂存区工作区内容不变
    • 效果: 所有在 [commit] 之后提交的更改,现在都变成了“未暂存”的本地修改状态。
    • 场景: 你最近的几次提交很混乱,你想撤销这几次提交记录,但保留所有的代码修改,然后重新整理、重新 addcommit
  • git reset --hard [commit]:
    • 作用: 最彻底的重置,威力巨大。移动 HEAD 指针,同时清空暂存区,并用目标提交的状态覆盖工作区
    • 效果: 所有在 [commit] 之后提交的更改全部被永久丢弃。你的代码文件会真的变回 [commit] 时的样子。
    • 场景: 你发现最近的几次提交完全是错误的,代码和思路都有问题,你只想彻底回到某个干净的历史节点,丢弃之后的所有工作。使用前请三思!

总结:何时使用哪个命令?

你的意图 使用的命令 影响范围 是否重写历史? 安全性
丢弃工作区的本地修改 git restore [file] 工作区 非常安全
取消暂存某个文件 git restore --staged [file] 暂存区 非常安全
撤销一个已推送的共享提交 git revert [commit] 创建新提交 否 (追加历史) 团队协作安全
合并最近的几个私有提交 git reset --soft HEAD~n 本地历史, 暂存区 仅限本地
撤销最近的私有提交,但保留代码修改 git reset --mixed HEAD~n 本地历史, 暂存区, 工作区 仅限本地
彻底销毁最近的私有提交和所有修改 git reset --hard HEAD~n 本地历史, 暂存区, 工作区 危险,仅限本地
修改最后一次私有提交的信息或内容 git commit --amend 本地历史 仅限本地

理解这个表格,你就掌握了 Git “后悔药”的精髓,能够从容应对各种“翻车”现场。

学习路径

  1. 第一步:掌握本地核心工作流
    • 重点练习 init, status, add, commit。这是你每天都要用的循环。理解工作区和暂存区的概念是关键。
  2. 第二步:学习分支管理
    • 练习 branch, switch, merge。尝试创建一个新功能分支,做一些修改和提交,然后合并回主分支。
  3. 第三步:融入远程协作
    • 在 GitHub 或 Gitee 上创建一个仓库,练习 clone, pull, push。模拟与他人协作的流程。
  4. 第四步:学会查看历史和撤销操作
    • 当你熟悉了基本流程后,再学习 log, diff, reset, revert。这些命令能让你在出问题时从容应对。

记住,多用 git statusgit --help。它会是你最好的向导。

git命令清单

待更新