唠唠闲话

Git 是目前全球最流行、最先进的分布式版本控制系统,它能够高效、灵活地管理从小型到大型的各种项目。所谓“分布式”意味着项目的完整代码库可以同时存在于多个设备上,开发者能够在本地独立地进行修改和提交,随后将变更推送至共享的远程仓库中。这样,即使在没有网络连接的情况下,也能够持续开发。

使用 Git 的主要目的包括:

  • 备份和同步本地项目
  • 管理多设备项目进度
  • 保存文件的历史版本(改错时的“后悔药”)
  • 管理 GitHub 项目
  • 部署博客等静态网站

本篇博客整理了日常使用 Git 时常用的操作和命令,作为一个便捷的查询工具。关于 Git 的安装和工作原理,这里不再赘述,网络上有许多优秀的资源可以参考。

推荐学习资源:廖雪峰的 Git 教程,我最初学习 Git 就是在这里。
推荐书籍:《Git 从入门到精通》 by 高见龙。

基本操作

修改配置

  1. 设置用户名和邮箱
    提交代码时,Git 需要知道提交人的姓名和邮箱。命令如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    # 设置全局用户名和邮箱
    git config --global user.name "Your Name"
    git config --global user.email "email@example.com"

    # 查看当前用户名和邮箱
    git config --global user.name
    git config --global user.email

    # 取消已设置的用户名和邮箱
    git config --global --unset user.name
    git config --global --unset user.email
  2. 参数说明

    • --global:全局设置用户名和邮箱,适用于所有仓库。
    • 不使用 --global 或改为 --local,则只对当前仓库生效。
    • 用户名和邮箱的双引号 "" 是可选的。
  3. 修改默认编辑器
    Git 默认的文本编辑器是 Vim,可以将其更换为 VS Code:

    1
    git config --global core.editor "code --wait"

    注意:--wait 参数确保在关闭 VS Code 前,Git 会等待编辑完成,否则可能导致提交失败。

  4. 查看当前 Git 配置
    使用 git config --list 查看所有配置项。下图为示例:
    配置示例

  5. 配置文件直接修改
    Git 的全局配置保存在主目录的 .gitconfig 文件中,可以直接编辑该文件进行修改。

  6. 设置命令缩写
    使用 alias.<缩写> 可以为 Git 命令设置别名:

    1
    2
    3
    4
    5
    6
    # 单行显示日志
    git log --pretty=oneline
    # 设置别名
    git config --global alias.pretty "log --pretty=oneline"
    # 使用别名
    git pretty
  7. 常用别名配置
    以下是几个常用的 Git 命令缩写:

    1
    2
    3
    4
    5
    6
    7
    # 撤销工作区的更改
    git config --global alias.discard "restore --staged ."
    # 修改上一次提交
    git config --global alias.amend "commit --amend --no-edit"
    # 简化日志显示
    git config --global alias.pretty "log --pretty=oneline"
    git config --global alias.oneline "log --oneline"

新建、添加、提交

  1. 新建仓库
    在目标文件夹下运行以下命令,初始化 Git 仓库:

    1
    git init
  2. 添加文件到暂存区
    git add 命令将文件从工作区添加到暂存区。常用方式如下:

    1
    2
    3
    4
    5
    git add <文件路径>      # 添加文件
    git add <文件夹路径> # 添加文件夹
    git add *.html # 添加符合正则表达式的文件
    git add . # 添加当前目录的所有文件和修改
    git add --all # 添加所有文件和改动

    补充说明:

    • git add 只能添加仓库目录中的文件。
    • git add -p <文件名> 可以仅提交文件的部分内容。
  3. 提交到版本库
    git commit 命令用于将暂存区的修改提交到版本库:

    1
    2
    3
    4
    5
    6
    7
    8
    # 添加注释并提交
    git commit -m "<提交注释>"
    # 直接打开编辑器编写提交信息
    git commit
    # 提交空内容
    git commit --allow-empty -m "empty commit"
    # 提交所有已追踪文件的改动
    git commit -a -m "提交说明"

    补充说明:

    • 每次提交都必须填写提交说明,尽量简明扼要。
    • git commit -a 只提交已追踪的文件,新文件需要手动添加到暂存区。
  4. 查看当前状态
    使用 git status 命令查看当前工作区的状态。

查看历史信息

  1. 查看提交历史
    直接输入 git log 查看提交历史的详细信息:

    1
    git log

    提交历史

  2. 简化显示提交历史
    以下是三种简洁的提交历史显示方式:

    1
    2
    3
    git log --pretty=oneline
    git log --oneline
    git log --oneline --graph

    简化历史

  3. 版本号和 HEAD 的用法

    • HEAD:当前最新版本。
    • HEAD^:上一个版本,多个 ^ 表示更早的版本。
    • HEAD~n:表示 n 个版本之前。
  4. 检索特定提交
    通过提交信息或作者信息筛选提交记录:

    1
    2
    3
    4
    # 根据作者检索
    git log --oneline --author="rex"
    # 检索提交信息包含关键字
    git log --oneline --grep="1.txt"
  5. 根据时间或内容检索提交
    通过时间范围或提交内容关键字筛选历史:

    1
    2
    3
    4
    # 检索提交中涉及特定内容的修改
    git log -S "txt change"
    # 按时间段筛选提交
    git log --oneline --since="9am" --until="12am"
  6. 查看特定文件的修改历史
    使用 git log --oneline <文件名> 查看文件的修改历史,添加 -p 参数可以查看具体改动。

  7. 查看代码提交者
    使用 git blame <文件名> 查看特定文件的提交者。下图为示例:
    提交者信息

删除和变更文件

  1. 删除文件并添加到暂存区
    使用 git rm 删除文件,同时将删除操作记录到暂存区:

    1
    2
    3
    4
    git rm <文件>
    # 等同于以下操作
    rm <文件>
    git add <删除的文件>
  2. 取消文件的追踪
    如果只想取消文件的 Git 追踪,而保留工作区的文件内容,可以使用 --cached 参数:

    1
    git rm <文件> --cached

    说明: 这种方法通常用于删除已被 .gitignore 文件忽略但仍然在暂存区中的文件。

  3. 移动文件并添加到暂存区
    使用 git mv 命令可以移动文件,同时记录到暂存区:

    1
    2
    3
    4
    git mv <旧文件> <新文件>
    # 等同于
    mv <旧文件> <新文件>
    git add <旧文件> <新文件>

修改最后一次提交 (--amend)

  1. 场景 1:修改提交信息
    当提交信息填写不当时,可以通过以下几种方式修改:

    • 使用 git reset 回退版本后重新提交
    • 使用 git rebase(高级操作,稍后介绍)
    • 使用 --amend 参数修改最后一次的提交信息
  2. 示例
    假设上次提交时误输入了错误信息,如 “WTF”,可以使用 --amend 进行修改:

    1
    2
    git log --oneline
    git commit --amend -m "Welcome To Facebook"

    修改提交信息示例

  3. 场景 2:修改提交内容
    刚完成一次 commit 后,发现还有细节未改好,但不想再进行一次新的提交,可以使用以下方法:

    • 使用 git reset --soft--mixed 回退版本后添加修改
    • 使用 --amend 直接修改最后一次提交
  4. 示例
    当发现提交后有细节需要更改,可以这样操作:

    1
    2
    # 修改文件后,将其添加到暂存区
    git commit --amend --no-edit

    说明: --no-edit 参数表示保持原来的提交信息不变。

忽略文件(.gitignore

参考资料:
CSDN:Git 中使用 .gitignore
CSDN:.gitignore 失效解决方法

  1. 使用 .gitignore 文件
    .gitignore 文件用于指定 Git 应该忽略的文件和文件夹。
    使用说明:

    • <文件/文件夹>:忽略所有目录中的该文件或文件夹
    • ./<文件/文件夹>:仅忽略当前目录下的该文件或文件夹
    • ! <文件/文件夹>:取消对该文件或文件夹的忽略
  2. 强制添加被忽略的文件
    如果文件夹被 .gitignore 忽略,可以通过 git add <路径> -f 强制添加。但注意,只有当时添加的文件会被 Git 记录,之后文件夹内的其他文件变化不会被追踪。

  3. 忽略 .gitignore 文件
    .gitignore 文件本身也可以被忽略,尽管这种场景不常见。例如,在不同设备上使用不同的 .gitignore 文件,可以通过在每个设备上添加 .gitignore 并忽略自身来实现这一目的。

  4. 清理被忽略的文件
    使用 git clean -fX 命令可以删除所有被 .gitignore 忽略的文件。

    • -f:强制删除

版本库相关

在学习 Git 时,必须理解的三个基本概念是:工作区缓存区(暂存区)和 版本库

查看改动

参考链接
简书:Git diff 比较两个版本文件之间的差异
博客园:Git 还原文件到之前版本

当某个文件修改后出现 bug,您可以使用 git diff 来比较当前修改与之前版本的差异,从而找到问题所在。以下是常见的 git diff 用法:

1
2
3
4
5
6
7
8
9
10
11
# 查看工作区与暂存区的差异
git diff [<文件>]

# 查看工作区与指定版本的区别
git diff <commit-id> [<文件>]

# 查看两个版本之间的差异
git diff <commit-id1> <commit-id2> [<文件>]

# 使用 --stat 参数查看简略区别
git diff <commit-id1> <commit-id2> --stat [<文件>]

示例图片:

回退文件

当文件修改出错时,需要回退到之前的版本,Git 提供了两种方法:

  1. 使用 git checkout 回退文件

    1
    2
    3
    git checkout <commit-id> <文件名> # 将文件回退到指定版本
    git checkout <文件名> # 将文件回退到 HEAD 版本
    git checkout . # 将当前目录的所有文件回退到 HEAD 版本

    注意: git checkout 会同时回退工作区和暂存区的文件,因此无需额外使用 git add

  2. 使用 git restore 回退文件

    1
    2
    git restore --staged <文件> # 将暂存区的文件回退到 HEAD 状态
    git restore <文件> # 将文件回退到 HEAD 状态,等同于 git checkout

    添加 --staged 参数可仅回退暂存区的文件。

版本回退

git reset 用于版本回退,实际上是修改 HEAD 指向的位置。常用的参数包括 softmixedhard,它们对工作区和暂存区的影响不同。默认参数为 mixed。更多详情可参考这里

三种回退模式的区别如下:

  1. git reset --soft
    保留工作区和暂存区的内容,仅将提交记录回退为未提交状态。代码仍然存在,只是变为未提交或未添加状态。
    20241010230547

  2. git reset --hard
    回退工作区和暂存区到指定的 commit 版本,所有的改动都会丢失。
    20241010230624

  3. git reset --mixed
    保留工作区的内容,但回退暂存区到指定的 commit 版本。
    20241010230635

Git 分支

分支是 Git 最重要的功能之一,尤其在团队协作中,分支可以提高开发效率,保证代码的独立性。即便在个人项目中,Git 分支也能发挥很大的作用。

基本分支操作

1
2
3
4
5
6
7
8
git branch                   # 查看本地分支
git branch -v # 查看分支及其对应的提交信息
git branch -r # 查看远程分支列表
git branch -a # 查看所有分支(本地和远程)
git branch <分支名> # 创建新分支
git branch -m <旧分支> <新分支> # 重命名分支
git checkout <分支名> # 切换到指定分支
git checkout -b <分支名> # 切换到分支,不存在时创建分支

当远程存在分支但本地尚未同步时,可以使用 git switch 命令在本地创建并切换到相应分支:

1
git switch <分支名>

常用分支命令

1
2
3
git clone -b <分支名> <远程仓库地址>  # 克隆远程仓库的指定分支
git push origin master:<分支名> # 推送本地 master 分支到远程的指定分支
git push origin <分支名> # 推送当前分支到远程仓库的同名分支

删除分支

参考:Git删除分支/恢复分支

  1. 删除非当前分支:

    1
    git branch -d <分支名>
  2. 强制删除未合并或当前正使用的分支:

    1
    git branch -D <分支名>
  3. 删除远程分支:

    1
    git push origin --delete <分支名>

恢复已删除的分支

当删除分支时,Git 仅删除了分支的指针,提交历史仍然保留在版本库中。因此,如果知道删除时的提交散列值,可以通过以下命令恢复分支:

1
git branch <分支名> <hash值>

如果不知道散列值,可以使用 git reflog 来查看历史记录并找出对应的提交。操作示例:

  1. 删除分支
    删除分支示例

  2. 恢复分支
    使用 git reflog 找到分支的 commit ID,并使用以下命令恢复:

    1
    git branch <分支名> HEAD@{1}

    恢复分支示例

注: git reflog 会显示本地仓库中所有的 commit 历史,包括所有分支的提交记录,甚至包括已撤销的提交。只要 HEAD 发生变化,它就会在 reflog 中记录下来。

GitHub

GitHub 是全球最大的同性交友网站一个基于 Git 的代码托管平台。开发者可以在 GitHub 上开源项目,浏览他人的代码,fork 项目到自己的账号下进行修改,然后 clone 到本地(当然,private repo 需要有访问权限)。你还可以发起 pull request,将自己的修改提交给原项目。

本节整理了在 GitHub 中常见的 Git 操作场景。如果你是 GitHub 新手,可能还需要参考这篇文章:GitHub | 多账户设置以及下载加速

小贴士:除了 GitHub,还有许多其他基于 Git 的代码托管平台,比如 GitLabGitee(码云) 等。但 GitHub 因为生态强大而独具优势。正如 Coding 所说:GitHub 的精髓在于两个功能——ForkPull Request。这两个功能构建了整个 GitHub 生态系统,赋予它生命力。Fork 复制基因,而 Pull Request 则使基因进化。优秀的代码会被大量 Fork,实现优胜劣汰。说 GitHub 仅是代码仓库?那你是低估它了!

将本地项目推送到远端

  1. 在 GitHub 上新建远程仓库。
  2. 使用 git remote 命令,将本地仓库与远端仓库关联:
    1
    git remote add origin <git 仓库地址>  # 添加远端仓库为 "origin"
  3. 将本地代码推送到远端仓库:
    1
    git push -u origin master  # 推送到远端 master 分支

    注:-u 参数可以设置默认推送的分支,以后只需简单执行 git push 即可。

克隆远程仓库到本地

  1. 在 GitHub 上复制仓库的地址。
  2. 使用 git clone 命令将远端仓库克隆到本地,这会在本地创建一个仓库副本:
    1
    git clone <git 仓库地址>
  3. 如果你对这个仓库有修改权限,可以在本地修改后使用 git push 将更改推送回远端。

修改远端仓库链接

有时候远端仓库需要更改,例如:

  1. 先取消与当前远程仓库的连接:

    1
    2
    3
    git remote          # 查看当前远端分支名称
    git remote -v # 查看远端仓库链接
    git remote remove origin # 删除远端仓库连接
  2. 然后添加新仓库,并将本地内容推送到新远端:

    1
    2
    git remote add origin <git 仓库地址>
    git push -u origin master # 推送到新远端的 master 分支

其他事项

在使用 Git 的过程中,可能会遇到一些常见问题。以下是问题的汇总及解决方案。

未跟踪文件

未被 Git 跟踪的文件不会受到 Git 命令的影响。

例如,被 .gitignore 文件忽略的文件,或者尚未通过 git add 添加到暂存区的文件,无论是使用 git reset 重置工作区、git checkout 切换分支,还是使用 git rm * -rf 删除文件,都不会影响这些未跟踪文件。

Windows 换行符问题

参考:fatal: LF would be replaced by CRLF 问题解决

在 Windows 平台下使用 git add 时,可能会遇到如下错误提示:
20241010230747

问题原因:
Git 在 Windows 上默认使用 CRLF 作为换行符,而 Linux 系统中使用 LF。当 Git 发现提交的文本文件包含 LF 换行符时,就会出现警告。

解决方法:
让 Git 忽略换行符的检查,执行以下命令:

1
git config --global core.autocrlf false

fetchpull 的区别

git fetchgit pull 是 Git 中常用的两个命令,它们的区别如下:

  • git fetch
    该命令从远程仓库获取最新的代码更新,并将其保存到本地版本库的远程跟踪分支(例如 origin/master)中。这些更新不会直接影响当前分支或工作区,只有手动合并(merge)这些更新后,才能应用到本地分支。

  • git pull
    git pullgit fetchgit merge 的组合操作。它不仅会从远程仓库获取最新的代码更新,还会将这些更新自动合并到当前分支中。如果当前分支有未提交的修改,git pull 会自动提交这些修改并进行合并。

简单来说,git fetch 只是获取更新并存储,而 git pull 则是获取更新后直接合并到当前分支。

最后

以上,我们整理了 Git 在日常开发中的常见操作和命令,从基础配置到分支管理、文件操作,再到 GitHub 的实际使用场景。无论是个人项目还是团队协作,Git 都能为代码管理提供强大支持,让开发者在版本控制、分支切换、远程协作等方面更加灵活高效。

Git 的学习曲线或许会有些陡峭,但掌握了它的基本用法后,你会发现这个工具的威力无穷。它不仅是开发者的时间机器,还可以成为你日常开发中的好帮手,让代码更有条理、项目管理更高效。