理解 Git
🩺 医生有听诊器。
🔧 机械师有扳手。
👨💻 我们开发者有 Git。
你有没有注意到,Git 在代码开发中如此重要,以至于人们几乎从不把它包含在他们的技术栈或简历中?人们假设你已经熟悉它,或者至少足够熟悉以应对日常工作,但你真的熟悉吗?
Git 是一个版本控制系统(VCS)。这项广泛使用的技术使我们能够存储、更改并与他人协作代码。
🚨 需要说明的是,Git 是一个非常庞大的主题。已经有很多关于 Git 的书籍出版,甚至有些博客文章看起来像学术论文一样详尽。这里我并不是要写那样的内容。我不是 Git 专家。我的目标是写一篇我当初学习 Git 时希望拥有的基础知识文章。
作为开发者,我们的日常工作围绕着阅读、编写和审查代码展开。Git 可谓是我们使用的重要工具之一。掌握 Git 提供的各项功能和特性,是你作为开发者可以做出的最佳投资之一。
那我们就开始吧
Git
一个相关的话题如果你觉得我遗漏了某个命令或者应该对某个命令进行更详细的说明,请在下方评论中告诉我。我会相应地更新这篇文章。🙏
如果你希望运用你的 Git 技能并希望为 Glasskube 做贡献,我们已于二月正式推出,并致力于成为 Kubernetes 包管理的默认解决方案。有了你的支持,我们可以实现这一目标。最直接的支持方式是给我们的 GitHub 项目点个星⭐。
Git 让你感觉像彼得·格里芬一样吗?
如果你没有正确地学习 Git,你可能会经常感到困惑,卡在同样的问题上,或者在终端中看到合并冲突时后悔不已。让我们通过定义一些基础的 Git 概念来确保这种情况不会发生。
Git 烦恼
分支在 Git 仓库中,你会找到一条主要的开发主线,通常命名为“main”或“master”(已弃用),从这条主线中会分出多个分支。这些分支代表了同时进行的工作流,使开发人员能够在同一个项目中同时处理多个功能或修复。
Git 分支
提交记录Git 提交作为更新代码的集合,记录了项目代码在特定时间点的状态快照。每个提交记录了自上次提交以来所做的更改,共同构建了项目开发历程的全面历史。
Git 提交记录
当你引用提交时,通常会使用其唯一标识的加密hash。
示例:
git show abc123def456789
这显示了该哈希值对应的提交的详细信息。
标签Git 标签 作为 Git 历史中的地标,通常标记项目开发过程中的重要里程碑,如 发布
, 版本
, 或 突出的提交
。这些标签对于标记特定时间点非常有价值,通常代表项目旅程中的起点或重大成就。
Git 标签
HEAD当前检出分支的最新提交由 HEAD
指示,作为仓库中任何引用的指针。当你在特定分支上时,HEAD
指向该分支的最新提交。有时,HEAD
不是指向分支的顶端,而是直接指向某个特定的提交(detached HEAD
状态)。
理解 Git 阶段对于导航你的 Git 工作流至关重要。它们代表了在你的文件更改被提交到仓库之前所经历的逻辑过渡。让我们深入了解一下 Git 阶段的概念:
Git 阶段
工作目录 👷工作目录是你编辑、修改和创建项目文件的地方,代表了你在本地机器上文件的当前状态。
阶段区 🚉暂存区就像是一个暂存区域或预提交区,在你将更改提交到仓库之前,可以在这里准备你的更改。
本地仓库 🗄️这里有用的命令是:
git add
同样,可以使用git rm
来取消暂存的更改
本地仓库是 Git 永久存储已提交更改的地方。它允许你回顾项目的版本历史,回退到之前的版本,并与他人在同一个代码库上进行协作。
远程仓库 🛫您可以使用
git commit
提交准备好的暂存区更改。
远程仓库是一个集中位置,通常托管在服务器上(如 GitHub、GitLab 或 Bitbucket),你可以在那里与他人共享和协作你的项目。
使用 Git 入门您可以使用如
git push
和git pull
这样的命令将本地仓库中的已提交更改推送到远程仓库或将远程仓库中的更改拉取到本地仓库。
好吧,你总得有个开始的地方,在 Git 中,这便是你的 工作区
。你可以 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 branch
# 或者直接创建一个分支
git branch feature-branch-name
要切换分支,请使用:
git switch
此外,除了在它们之间切换之外,你还可以使用:
git checkout
# 使用 -b 标志快速切换到尚未创建的新分支
git checkout -b feature-branch-name
要检查仓库的状态,使用:
git status
一个很好的方法是始终在终端中清晰地看到你当前的分支。许多终端插件可以帮助做到这一点。这里有一个插件。
终端视图
处理提交在处理提交时,使用 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
显示从最近的提交开始的提交记录的 chronology,按时间倒序排列。
修改历史涉及一些强大的命令。Rebase
重写提交历史,Squashing
将多个提交合并为一个,而 Cherry-picking
选择特定的提交。
将变基与合并进行比较是有道理的,因为它们的目标相同,但实现方式不同。关键的区别在于,变基会重写项目的提交历史。对于重视清晰且易于理解的项目历史的项目来说,这是一个理想的选择。另一方面,合并通过生成一个新的合并提交来保留两个分支的历史记录。
在重新基于主分支的 HEAD
进行合并时,功能分支的提交历史会被重新组织。
Git 重新基于操作
这里的流程非常简单。
确保你切换到了想要重新基于的分支,并从远程仓库获取最新的更改:
git checkout your_branch
git fetch
现在选择你想要重新基于的分支,并运行以下命令:
git rebase upstream_branch
重新基于其他分支后,如果您的分支已经推送到远程仓库,您可能需要强制推送您的更改:
git push origin your_branch --force
合并提交⚠️ 使用
--force
时要小心,因为它有可能会覆盖目标分支的历史记录。一般情况下应避免在主分支(main/master)上使用它。
Git 打包(squashing)用于将多个提交合并为一个连贯的提交。
Git 合并提交
这个概念很容易理解,特别是当你使用统一代码的方法是变基(rebase)时,因为历史记录会被修改,所以要注意对项目历史的影响。我曾经在执行 squash 操作时遇到困难,尤其是使用交互式变基时,幸运的是我们有一些工具可以帮助我们。这是我最喜欢的 squash 方法,它涉及将 HEAD 指针回退到 X 个提交前,同时保留已暂存的更改。
# 根据你想要合并的提交数更改 HEAD~ 后的数字
git reset --soft HEAD~X
git commit -m "你的合并提交信息"
git push origin your_branch --force
樱桃挑选⚠️ 使用
--force
时要小心,因为它有可能会覆盖目标分支的历史记录。一般情况下应避免在主分支(main/master)上使用它。
挑拣合并很有用,可以用于从一个分支选择性地将更改合并到另一个分支,特别是在合并整个分支不理想或不可行时。然而,挑拣合并需要谨慎使用,因为如果使用不当,可能会导致重复的提交和不同的历史记录。
Git 樱桃挑选
为了执行此操作,首先你需要确定你想要选择的提交的提交哈希,你可以使用 git log
来完成。一旦确定了提交哈希,你可以运行:
git checkout 目标分支
git cherry-pick <commit-hash> # 如果需要多个提交,重复此操作多次
git push origin 目标分支
高级 Git 命令
签名提交
签署提交是一种验证你在 Git 中提交的真实性和完整性的方法。它允许你使用你的 GPG(GNU Privacy Guard)密钥对提交进行加密签名,确保 Git 知道你确实是该提交的作者。你可以通过生成一个 GPG 密钥并配置 Git 在提交时使用该密钥来实现这一点。以下是步骤:
# 生成一个 GPG 密钥
gpg --gen-key
# 配置 Git 使用你的 GPG 密钥
git config --global user.signingkey <your-gpg-key-id>
# 将公钥添加到你的 GitHub 账户
# 使用 -S 标志签署你的提交
git commit -S -m "你的提交信息"
# 查看已签署的提交
git log --show-signature
Git 日志参考
我们还没有探讨过的是 Git 引用,它们是指向仓库内各种对象的指针,主要指向提交,但也包括标签和分支。它们作为 Git 历史中的命名点,让用户能够浏览仓库的时间线并访问项目的特定快照。了解如何导航 Git 引用非常有用,用户可以使用 git reflog
来实现这一点。以下是其中的一些好处:
- 恢复丢失的提交或分支
- 调试和故障排除
- 撤销错误
交互式变基是 Git 的一个强大功能,它允许你交互式地重写提交历史。你可以使用它来修改、重新排序、合并或删除提交,然后再将它们应用到分支上。
为了使用它,你必须熟悉可能的操作,例如:
- 选择 (“p“)
- 重新表述 (“r“)
- 编辑 (“e“)
- 合并 (“s“)
- 删除 (“d“)
Git 交互式重新基于
这里有一个有用的视频,教你如何在终端中进行交互式变基。我在博客文章的底部也链接了一个有用的工具。
使用 Git 进行协作 原始 vs 上游origin 是你在克隆仓库时与本地 Git 仓库关联的默认远程仓库。如果你分叉了一个仓库,那么那个分叉默认就会成为你的“origin”仓库。
上游指的是你的仓库所分叉的原始仓库。
为了让你的 forked 仓库保持最新,你可以从“upstream”仓库获取最新的更改,并将这些更改合并或 rebase 到你的本地仓库中。
要查看与你本地 Git 仓库关联的远程仓库,请运行:
git remote -v
矛盾之处
不要惊慌,在尝试合并或重新基于某个分支时,如果检测到冲突,这仅仅意味着在你的仓库中,同一文件或文件的不同版本之间存在冲突的更改,这些冲突通常可以轻松解决。
Git 合并
它们通常会在受影响的文件中被标记出来,Git 会在冲突的地方插入冲突标记 <<<<<<<
、=======
和 >>>>>>>
来突出显示冲突的部分。决定保留哪些更改、修改或移除哪些更改,确保最终的代码有意义并保留了预期的功能。
在手动解决冲突文件中的冲突后,移除冲突标记 <<<<<<<
、=======
和 >>>>>>>
,并根据需要调整代码。
在您对冲突解决满意后,保存冲突文件中的更改。
流行的 Git 工作流如果你在解决冲突时遇到问题,这个视频对此解释得很清楚。
Git 工作流
各种 Git 工作流存在,不过需要注意的是,并不存在一种普遍适用的“最佳”Git 工作流。相反,每种方法都有其优缺点。让我们来探讨这些不同的工作流,以了解它们的优点和缺点。
团队协作
功能分支工作流 🌱每个新功能或 bug 修复都在其自己的分支中开发,完成后将其合并回主分支。
- 优点: 隔离更改并减少冲突。
- 缺点: 可能变得复杂,并需要勤勉的分支管理。
Gitflow 定义了一个严格的分支模型,为不同类型的发展任务预定义了不同的分支。
它包括长期存在的分支,如 main、develop、feature、release 和 hotfix 分支。
- 优点: 适合具有计划发布和长期维护的项目。
- 缺点: 对于较小的团队来说可能过于复杂。
在这个工作流中,每位开发者克隆主仓库,但不是直接将更改推送到主仓库,而是将更改推送到他们自己的仓库分叉。开发者随后创建拉取请求,以向主仓库提议更改,这允许在合并之前进行代码审查和协作。
这是我们用于在开源 Glasskube 仓库上协作的工作流程。
- 优点: 鼓励外部贡献者协作,而不授予他们对主仓库的直接写权限。
- 缺点: 维护分支和主仓库之间的同步可能具有挑战性。
类似于 Forking 工作流,但开发者不是将仓库fork出去,而是在主仓库中直接创建功能分支。
- 优点: 促进代码审查、协作和团队成员之间的知识共享。
- 缺点: 依赖人工代码审查者可能会导致开发过程中的延迟。
如果你所在的团队专注于快速迭代和持续交付,你可能会使用主干开发模式,即开发人员直接在主分支上工作,并频繁提交小的更改。
- 优势: 促进快速迭代,持续集成,专注于将小而频繁的更改部署到生产环境。
- 劣势: 需要强大的自动化测试和部署管道来确保主分支的稳定性,可能不适合具有严格发布计划或复杂功能开发的项目。
强烈建议在开源项目中协作时进行 Fork 操作,因为你对自己的仓库副本拥有完全的控制权。你可以进行更改、尝试新功能或修复错误,而不会影响原始项目。
💡 让我花了很多时间才明白的是,虽然分叉的仓库最初是独立的实体,但它们仍然与原始仓库保持连接。这种连接允许你跟踪原始项目中的更改,并将你的分叉与他人所做的更新同步。
那就是为什么即使你推送到你的源仓库,你的更改也会显示在远程仓库中。
Git 快捷指令表 # 克隆仓库
git clone <仓库_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 工具和资源,让您的生活更轻松。
如果你喜欢这类内容并希望看到更多,请考虑通过在 GitHub 上给我们点个 Star 来支持我们 🙏
如果你愿意的话,给我们一个 GitHub 星标。
共同學習,寫下你的評論
評論加載中...
作者其他優質文章