手记

我从未有过的Git(版本控制系统)指南。

学习 Git

🩺 医生用听诊器。

🔧 修理工有扳手。

👨‍💻 我们这些开发者有这个工具 Git。

你有没有注意到,Git在编写代码或代码工作中如此重要,以至于人们几乎从不在这他们的技术栈或简历中提及它?人们默认你已经了解它,或者至少足够使用,但你真的了解吗?

Git 是一个版本控制系统(VCS)——这项广泛使用的技术让我们能够存储和编辑代码,并与他人协作。

🚨 作为免责声明,我想指出,Git 是一个非常大的主题。已经有很多关于 Git 的书籍,甚至有些博客文章写得像学术论文那么正式。这不是我在这里想做的。我不是 Git 专家。我的目标是写一篇类似于我当初学习 Git 时希望拥有的基础文章。

作为开发人员,我们的日常工作包括阅读、编写和审查代码。Git 无疑是最重要的工具之一,我们每天都使用它。掌握 Git 的各种特性和功能,对于开发者来说,这是你为自己做的最佳投资之一。

咱们开始吧

Git

如果你觉得我遗漏了某个特定命令或者应该对某个特定命令进行更详细的说明,请在下方留言告诉我。我会根据需要更新这篇文章。🙏

瑞典说到了这个话题

如果你希望利用你的 Git 技能并愿意为 Glasskube 做贡献,我们已在二月正式推出,我们希望成为 Kubernetes 包管理的首选解决方案。有了你的支持,我们可以实现这一目标。最简单的方式就是在 GitHub 上为我们点赞 ⭐

让我们开始打基础

用 Git 时,你有没有觉得像彼得·格里芬一样?

如果你没有正确地学习 Git,你可能会经常感到困惑,卡在同样的问题上,或者一看到终端中的另一个合并冲突就后悔学了 Git。让我们来定义一些基础的 Git 概念,以避免这些问题。

Git的烦恼

分支(Branches)

在一个 Git 仓库中,你会找到一条主要的开发主线,通常命名为“main”或“master”(已经不再推荐使用^1),从这条主线上发展出多个分支(branch)。这些分支代表了同时进行的工作路径,让开发者可以同时处理项目里的多个功能和修复任务。

Git 版本分支

提交

Git 提交相当于打包的更新代码,每次提交都会在特定时间点捕捉项目代码的快照。每次提交都会记录自上次提交以来的更改,共同构建了项目开发历程的完整历史。

Git 提交

当你引用提交时,通常会使用它唯一的哈希值来标识该提交。哈希

比如:

    git show abc123def456789

运行这条命令可以查看提交的详细信息。

这显示了具有该哈希值的提交的详细信息。

标签 (#标签)

Git 标签在Git历史中起地标作用,通常用来标记重要的项目发展中重要的里程碑,比如发布版本、或突出的提交。这些标签对于标记项目中的特定时间点非常有用,往往代表项目旅程中的关键节点或重要里程碑。

Git标签(tag)

HEAD

HEAD 指向当前检出分支的最近一次提交,作为指向仓库中任何引用的指针。当你在特定分支上时,HEAD 指向该分支上的最新提交版本。有时,HEAD 不是指向任何分支,而是直接指向一个具体的提交(处于 detached HEAD 状态)。

步骤

理解 Git 阶段对于导航你的 Git 工作流非常重要。它们代表了文件更改在提交到仓库之前所经历的逻辑中间阶段。让我们来了解一下 Git 阶段的概念:

Git 暂存区

工作文件夹 👷

工作目录是你编辑、修改和创建项目文件的地方,这里代表你本地文件的当前状态。

舞台区 🚉

staging区就像是一个暂存区,就像一个预备提交的地方,在这里你可以准备你的修改,在正式提交到仓库之前进行调整前的准备。

这里有个有用的命令:git add。如果想取消暂存的文件更改,也可以使用 git rm

本地小仓库 🗄️

本地仓库是 Git 永久存储已提交更改的地方。它让你可以查看项目的版本历史,回退到之前的版本状态,并在同一代码库上与他人协作。

你可以用 git commit 命令提交准备好的更改,这些更改已经在暂存区准备好了。

远程代码库 🛫

远程仓库(如 GitHub、GitLab 或 Bitbucket)是一个集中位置,用于托管你的项目,通常托管在服务器上(例如 GitHub、GitLab 或 Bitbucket),你可以在那里与他人共享和协作。

你可以使用像 git pushgit pull 这样的命令,将已提交的更改推送到远程仓库或从远程仓库拉取更改。

开始使用 Git 版本控制

好吧,你总得有个起点,而在 Git 中,你的起点就是 workspace。你可以 fork 或者 clone 一个现有的仓库,获得该工作区的一个副本,或者如果你在一个全新的本地文件夹里从头开始,你需要用 git init 将其变成 Git 仓库。下一步,重要的是设置好你的凭据。

这个网址来自:https://li.earthonline.us/

设置账号

当你推送或拉取到远程仓库,不想每次都要输入用户名和密码时,可以试试以下命令:

git config --global credential.helper store  # 设置全局git凭证存储器

当你第一次与远程仓库交互时,Git 会让你输入用户名和密码。之后你就不需要再输入了。

需要注意的是,凭据是以明文形式存储在名为 .git-credentials 的文件中的。

你可以使用以下命令来检查配置的凭证。

    git config --global credential.helper

设置全局凭证助手,该命令用于配置 Git 的全局凭证助手,以便在需要时存储和使用凭证。

使用分支

在本地工作时,知道你现在所在的分支非常重要。这些命令很有用。

# 将显示本地仓库中的分支  
git branch   
# 或直接创建一个分支  
git branch feature-branch-name

要切换分支,请使用:git checkout 分支名

比如
git checkout <branch-name>

git switch (用于切换分支的命令)

除了转换它们之外,你还可以这样切换它们哦:

git checkout   
# 创建并切换到新分支(使用 -b 标志)
git checkout -b feature-branch-name

要检查仓库状态,请使用:

git状态?

一个保持你对当前分支清晰视野的好方法是在终端直接查看它。许多终端插件可以帮助做到这一点。这里有一个例子:链接

终端界面

提交管理

在使用提交时,记得用 git commit -m 记录你的改动,如果需要修改最新的提交,可以用 git amend 来修改最近的一次提交。同时,尽量按照提交消息规范来写提交信息。

确保给每个提交都加上一个有意义的说明,比如使用 `git commit -m "有意义的说明"`

如果你需要修改上一次提交,你无需再进行一次新的提交,可以直接用 --amend 标志更新上一次提交,使用暂存区更改。

    # 请进行您的更改  
    git add .  
    git commit --amend  
    # 这将会使用你的默认编辑器来修改提交信息,如果需要的话.  
    git push origin your_branch --force
    # 将强制推送至您的分支(注意:此操作会覆盖远程仓库的更改).

⚠️ 使用 --force 时要格外小心,因为它有可能覆盖目标分支的历史。通常应避免将其应用于主分支(如main或master)。

通常来说,最好尽量频繁地提交,以避免丢失进度或不小心重置未暂存的更改。之后可以通过合并提交或进行交互式变基来重写历史。

使用 git log 命令可以按时间顺序逆向显示从最近的提交开始的所有提交记录。

玩弄历史

修改历史包括一些强大的命令:Rebase 重写提交记录,Squashing 合并多个提交,而 Cherry-picking 则是选择特定的提交。

基于重新和合并

将重新基线化与合并进行比较是有道理的,因为它们的目标相同,但实现方式不同。关键的区别在于,重新基线化会重写项目的提交历史记录。对于那些重视项目历史清晰易懂的项目来说,这是一个理想的选择。另一方面,合并会保持两个分支的提交历史,通过生成一个新的合并提交来实现。

当功能分支合并到主分支的 HEAD 时,它的提交记录会被重新整理。

Git 重新组织

这里的流程非常简单直接。

确保你在想要重新基于的分支上,并从远程仓库拉取最新的更改。

git checkout your_branch # 切换到你的分支
git fetch               # 获取最新更新

现在选择你想要基于的分支,然后运行该命令。

将当前分支的更改应用到上游分支上 # git rebase upstream_branch

在重新设置基准之后,如果该分支已经被推送到远程仓库,你可能需要强制推送了所做的更改。

    git push origin 你的分支 --force  # 强制推送你的分支

⚠️ 使用 --force 时要小心,因为它可能会覆盖目标分支的历史记录。通常应避免在主线分支(main 或 master)上使用它。

压扁

Git squash 用来将多个提交合并成一个干净且连贯的提交。

Git 压缩提交

这个概念很容易理解,特别是如果用 rebase 来统一代码,因为这种方法会改变历史记录,因此要注意对项目历史的影响。我曾经在做 squash 时遇到过困难,尤其是在使用交互式 rebase 时,还好我们有一些工具能帮上忙。这是我首选的 squash 方法,它涉及将 HEAD 指针回退 X 个提交记录,同时保留已暂存的更改。

    # 将后面的数字改为你想合并的提交次数  
    git reset --soft HEAD~X  
    git commit -m "合并后的提交信息"  
    git push origin your_branch --force

⚠️ 在使用 --force 时要格外小心,因为它可能会覆盖目标分支的历史。通常最好避免在主分支(如 main 或 master)上使用。

挑樱桃

拣选提交功能对于选择性地将更改从一个分支引入另一个分支非常有用,尤其是在不宜或无法合并整个分支时。然而,重要的是要谨慎使用拣选提交,因为它如果使用不当可能会导致重复提交和分支历史的分歧。

Git 选择性合并

或更常用的表达方式:

Git 拣选

要这样做,你需要首先找到你想要选择的提交的哈希,可以使用 git log 命令找到它。找到哈希后,你可以运行:

    git checkout target_branch  
    git cherry-pick <commit-hash>, # 如果需要多个提交,重复执行此命令多次  
    git push origin target_branch
Git 的高级命令
为提交签名

对提交进行签名是在 Git 中验证提交合法性和完整性的方法。它允许你使用你的 GPG(GNU 隐私守卫)密钥对你的提交进行数字签名,确保 Git 知道提交确实是你所为。你可以通过创建一个 GPG 密钥并配置 Git 使用该密钥来签名提交。下面是操作步骤:

    # 生成一个GPG密钥  
    gpg --gen-key  
    # 配置Git以使用你的GPG密钥  
    git config --global user.signingkey <你的GPG密钥ID>  
    # 将公钥添加到你的GitHub账号  
    # 使用-S标志签署提交  
    git commit -S -m "提交信息"  
    # 查看已签署的提交记录  
    git log --show-signature
Git reflog (Git记录日志)

我们还没聊过 Git 引用,它们是仓库中各种对象的指针,主要是提交,但也包括标签和分支。它们作为 Git 历史中的命名点,允许用户在仓库的时间线上导航并访问项目的特定快照。了解如何导航 Git 引用非常有用,用户可以使用 git reflog。这里列出一些好处:

  • 恢复丢失的提交或分支
  • 调试和排除故障
  • 撤销错误操作
交互式变基操作

交互式变基是 Git 的一个强大功能,允许您以交互方式重写提交记录的历史。它使您能够在将这些更改应用到分支之前修改、重新排序、合并、删除或调整这些提交记录。

为了使用它,你需要熟悉一些可能的操作,比如:

  • 选中 (p)
  • 改述 (r)
  • 修改 (e)
  • 简化 (s)
  • 删除 (d)

Git 交互式重新整理

这里有个有用的视频,教你如何在终端里做交互式提交合并,我还在我的博客文章底部推荐了一个实用工具。

与Git协作指南
源头 vs 上游

当你第一次克隆一个 Git 仓库时,默认关联的远程仓库称为“源仓库”。如果你分叉了一个仓库,那么那个分叉就会默认成为你的“源仓库”。

你的仓库是从原始仓库分叉出来的,而上游指的是这个原始仓库。

为了让你的分叉仓库与原项目的最新更改保持同步,首先你需要从“上游”仓库中拉取更改,并将这些更改合并或重置到你的本地仓库。

要查看与你的本地 Git 仓库关联的远程仓库,请运行:

运行 git remote -v 命令

冲突

不要惊慌,当你尝试合并或重新合并一个分支时,如果检测到冲突,这意味着在你的仓库中,相同文件的不同版本之间存在冲突。这些冲突通常可以轻松解决(大多数时候)。

执行git 合并

它们通常会在受影响的文件中被标识出来,Git 会在冲突的地方插入标记符号 <<<<<<<=======>>>>>>> 来突出显示冲突的部分。决定保留、修改还是移除哪些部分,确保最终代码清晰且具备预期功能。

在手动解决冲突文件里的冲突后,删除冲突标记<<<<<<<=======>>>>>>>,并调整相应的代码。

保存有冲突文件的更改,在你对解决结果满意后。

如果你在解决冲突时遇到问题,这个视频讲解得很清楚,它对此解释得很清楚。

常用的 Git工作流

Git 工作流程

存在各种 Git 工作流,值得注意的是,不存在一种普遍适用的“最佳”Git 工作流。相反,每种方法都有其各自的优缺点。让我们来探讨这些不同的工作流,以便了解它们的长处和短处。

团队工作

功能分支流程 🌱

每个新功能或修复的 bug 都是在其自己的分支中开发的,完成后再把它合并回主分支。

  • 优势: 更好地隔离变更并减少冲突。
  • 劣势: 可能会变得很复杂,并需要仔细管理分支。
Gitflow 流程 🌊

Gitflow 定义了一套严格的分支规范,为各种开发任务预设了特定的分支。

这包括主分支(main)、开发分支(develop)、功能分支、发布分支和热修复分支这些长期分支。

  • 优势: 适用于有明确发布时间表和持续长期维护的项目。
  • 劣势: 对于较小的团队来说可能会有点过于复杂。
分支工作流

在这个工作流中,每个开发者克隆主仓库,但他们不是直接将更改推送到主仓库里,而是将更改推送到他们自己的主仓库副本。开发者随后提交拉取请求,提议将更改合并到主仓库,这使得代码审查和合作成为可能,然后再进行合并。

这是我们用来在开源Glasskube项目上合作的工作流程。

  • 优势: 鼓励外部贡献者协作,但不直接授予主仓库的写入权限。
  • 劣势: 维护分支与主仓库之间的同步可能较难。
拉取请求流程

类似分支工作流,但开发者直接在主仓库中创建特性分支。

  • 优点: 有助于促进代码审查,团队成员间的合作和知识共享。
  • 缺点: 依赖人工进行代码审查可能会导致开发过程中的延误问题。
主干驱动 🪵

如果你在一个专注于快速迭代和持续集成与交付的团队中,你可能更倾向于使用主干分支开发,在这种情况下,开发人员直接在主分支上提交小而频繁的更改。

  • 优势: 促进快速迭代和持续集成,专注于频繁的小规模变更部署到生产环境。
  • 劣势: 需要强大的自动化测试和部署管道来确保主分支的稳定性,可能不适合那些有严格发布周期或复杂功能开发的项目,涉及复杂功能开发的项目。
这是什么梗?

分叉(也就是创建自己的代码库)在参与开源项目时非常推荐,因为你对自己的仓库拥有完全的控制权。你可以修改代码,尝试新功能,或修复错误,而不会影响原始项目。

💡 让我花费了很长时间才明白的是,尽管分叉仓库最初是独立的,但它们仍然和原始仓库保持联系。这种联系让你可以跟踪原始项目中的变更,并同步你的分叉与他人的更新。

这就是为什么即使你推送到本地仓库,更改也会被同步到远程。

Git 快速入门
    # 克隆仓库命令
    git clone <repository_url>

    # 添加变更到暂存区命令
    git add <文件(s)>

    # 提交变更命令
    git commit -m "提交消息"

    # 将变更推送到远程仓库命令
    git push

    # 强制推送变更命令(可能覆盖他人提交,谨慎使用)
    git push --force

    # 将工作目录重置到最近一次提交命令
    git reset --hard

    # 创建一个新分支命令
    git branch <分支名>

    # 切换到另一个分支命令
    git checkout <分支名>

    # 合并另一个分支的变更命令
    git merge <分支名>

    # 变基变更到另一个基础分支名命令(谨慎使用)
    git rebase <基础分支名>

    # 查看工作目录的状态信息命令
    git status

    # 查看提交历史命令
    git log

    # 撤销最近一次提交命令(谨慎使用)
    git reset --soft HEAD^

    # 丢弃工作目录中的修改命令
    git restore <文件(s)>

    # 找回丢失的提交引用命令
    git reflog

    # 交互式变基以重排提交命令
    git rebase --interactive HEAD~3
额外福利!一些实用的 Git 工具和资源让你生活更轻松。
  • 工具 用于交互式变基。
  • Cdiff 以查看彩色、增量差异。
  • 交互式 Git 分支 演练场

如果你喜欢这种内容,并希望看到更多这样的内容,请考虑在 GitHub 上给我们点个 Star,支持我们

有兴趣的话,请在 GitHub 上给我们点个赞。

0人推荐
随时随地看视频
慕课网APP