我从未有过的 Git 指南。
🩺 医生有听诊器。🔧
机械师有扳手。👨💻
我们开发人员有 Git。
你有没有注意到,Git 在代码编写中如此重要,以至于人们几乎从未在自己的技术栈或简历中提到过它?人们通常认为你已经了解它,或者至少了解得差不多了,但你真的了解吗?
Git 是一个版本控制系统 (VCS)。这项无处不在的技术使我们能够存储、修改代码并与他人协作。
🚨 声明一下,我想指出 Git 是一个庞大的话题。Git 书籍已经有很多,博客文章也可能被误认为是学术论文。但这并不是我在这里的目的。我不是 Git 专家。我的目标是写一篇我学习 Git 时希望看到的 Git 基础知识文章。
作为开发者,我们的日常工作围绕着阅读、编写和审查代码。Git 可以说是我们使用的最重要的工具之一。掌握 Git 提供的特性和功能是作为开发者对自己最好的投资之一。
让我们开始吧
如果您觉得我遗漏了某个命令,或者需要更详细地讲解,请在下方评论区告诉我。我会相应地更新这篇文章。🙏
当我们讨论这个话题时
如果您想将自己的 Git 技能运用到工作中,并希望为 Glasskube 做出贡献,我们已于二月正式上线,致力于成为 Kubernetes 包管理的首选解决方案。有了您的支持,我们就能实现这一目标。表达支持的最佳方式是在 GitHub 上为我们点赞⭐
让我们奠定基础
Git 是否让你感觉自己像 Peter Griffin 一样?
如果你没有正确学习 Git,你可能会不断摸不着头脑,陷入同样的问题,或者后悔有一天在终端里再次看到合并冲突。让我们通过定义一些基本的 Git 概念来确保这种情况不会发生。
分支
在 Git 仓库中,你会发现一条开发主线,通常名为“main”或“master”(已弃用),从主线衍生出多个分支。这些分支代表着同步的工作流,使开发人员能够在同一项目中同时处理多个功能或修复问题。
提交
Git 提交充当更新代码的捆绑包,捕获项目代码在特定时间点的快照。每次提交都记录了自上次提交以来所做的更改,所有这些共同构成了项目开发历程的完整历史记录。
当引用提交时,您通常会使用其唯一标识的加密哈希。
例子:
git show abc123def456789
这显示了有关该哈希的提交的详细信息。
标签
Git标签是 Git 历史记录中的里程碑,通常标记项目开发过程中的重要里程碑,例如releases
、versions
或standout commits
。这些标签对于标记特定时间点非常有用,通常代表项目历程中的起点或主要成就。
头
当前检出分支上的最新提交由 表示HEAD
,它作为指向存储库中任何引用的指针。当您位于特定分支时,指向该分支上的最新提交。有时,也可以直接指向特定的提交(状态) HEAD
,而不是指向分支的末端。HEAD
detached HEAD
阶段
理解 Git 阶段对于指导你的 Git 工作流程至关重要。它们代表了文件更改在提交到仓库之前发生的逻辑转换。
让我们深入探讨一下 Git 阶段的概念:
工作目录👷
这working directory
是您编辑、修改和创建项目文件的地方。它代表了您本地计算机上文件的当前状态。
暂存区🚉
该staging
区域就像一个存放区或预提交区,您可以在其中准备更改,然后再将其提交到存储库。
此处有用的命令:
git add
也git rm
可用于取消暂存更改
本地存储库🗄️
本地仓库是 Git 永久存储已提交更改的地方。它允许您查看项目历史记录、恢复到之前的状态,并与同一代码库上的其他人协作。
您可以使用以下命令提交暂存区中已准备好的更改:
git commit
远程存储库🛫
远程存储库是一个集中位置,通常托管在服务器上(如 GitHub、GitLab 或 Bitbucket),您可以在其中与其他人共享和协作您的项目。
git push
您可以使用诸如和之类的命令git pull
将已提交的更改从本地存储库推送/拉取到远程存储库。
Git 入门
嗯,你必须从某个地方开始,在 Git 中,那就是你的workspace
。你可以fork
创建clone
一个现有仓库,并拥有该工作区的副本;或者,如果你在机器上的新本地文件夹中全新创建,则必须使用 将其转换为 git 仓库git init
。下一步,至关重要的不容忽视的步骤是设置你的凭据。
凭证设置
当运行推送和拉取到远程存储库时,您不想每次都必须输入用户名和密码,只需执行以下命令即可避免这种情况:
git config --global credential.helper store
首次与远程仓库交互时,Git 会提示您输入用户名和密码。之后,将不再提示您输入用户名和密码。
值得注意的是,凭证以纯文本格式存储在
.git-credentials
文件中。
要检查配置的凭据,您可以使用以下命令:
git config --global credential.helper
使用分支
在本地工作时,了解当前位于哪个分支至关重要。以下命令很有用:
# Will show the changes in the local repository
git branch
# Or create a branch directly with
git branch feature-branch-name
要在分支之间转换,请使用:
git switch
除了在它们之间转换之外,您还可以使用:
git checkout
# A shortcut to switch to a branch that is yet to be created with the -b flag
git checkout -b feature-branch-name
要检查存储库的状态,请使用:
git status
想要始终清晰地查看当前分支,一个好方法是直接在终端中查看。许多终端插件可以帮助你做到这一点。这里有一个。
使用提交
处理提交时,使用 git commit -m 记录更改,使用 git amend 修改最近的提交,并尽量遵守提交消息约定。
# Make sure to add a message to each commit
git commit -m "meaningful message"
如果您对上次提交进行了更改,则不必完全创建另一个提交,您可以使用 -—amend 标志来修改最近的提交,其中包含暂存的更改
# make your changes
git add .
git commit --amend
# This will open your default text editor to modify the commit message if needed.
git push origin your_branch --force
⚠️ 使用时请谨慎
--force
,因为它可能会覆盖目标分支的历史记录。通常应避免在主分支/master 上使用它。经验法则是,最好多提交几次,以免丢失进度或意外重置未暂存的更改。之后可以通过压缩多个提交或执行交互式 rebase 来重写历史记录。
用于git log
显示按时间顺序排列的提交列表,从最近的提交开始,按时间倒序排列
操纵历史
操作历史涉及一些强大的命令。Rebase
重写提交历史,Squashing
将多个提交合并为一个,并Cherry-picking
选择特定的提交。
变基和合并
将 rebase 与 merging 进行比较是有意义的,因为它们的目标相同,但实现方式不同。关键区别在于 rebase 会重写项目历史记录。对于重视清晰易懂的项目历史记录的项目来说,rebase 是一个理想的选择。而 merging 则通过生成新的合并提交来维护两个分支的历史记录。
在 rebase 期间,功能分支的提交历史记录在移至HEAD
主分支时进行重组
这里的工作流程非常简单。
确保您位于要重新设定的分支上并从远程存储库获取最新更改:
git checkout your_branch
git fetch
现在选择您想要重新定位的分支并运行以下命令:
git rebase upstream_branch
重新定基后,如果分支已被推送到远程存储库,则可能需要强制推送更改:
git push origin your_branch --force
⚠️ 使用时请谨慎
--force
,因为它可能会覆盖目标分支的历史记录。通常应避免在主分支/master 上使用它。
挤压
Git 压缩用于将多个提交压缩为单个、有凝聚力的提交。
这个概念很容易理解,如果使用 rebase 来统一代码,则尤其有用。由于历史记录会被更改,因此务必注意其对项目历史记录的影响。我曾经多次尝试执行 squash,尤其是在使用交互式 rebase 时,幸运的是,我们有一些工具可以帮助我们。这是我首选的 squash 方法,它将 HEAD 指针向后移动 X 个提交,同时保留已暂存的更改。
# Change to the number after HEAD~ depending on the commits you want to squash
git reset --soft HEAD~X
git commit -m "Your squashed commit message"
git push origin your_branch --force
⚠️ 使用时请谨慎
--force
,因为它可能会覆盖目标分支的历史记录。通常应避免在主分支/master 上使用它。
挑选
Cherry-picking 可以选择性地将一个分支的更改合并到另一个分支,尤其是在合并整个分支不可行或不可行的情况下。然而,谨慎使用 Cherry-picking 至关重要,因为如果使用不当,可能会导致重复提交和不同的历史记录。
要执行此操作,首先必须确定要选择的提交的提交哈希值,可以使用 来执行此操作git log
。确定提交哈希值后,您可以运行:
git checkout target_branch
git cherry-pick <commit-hash> # Do this multiple times if multiple commits are wanted
git push origin target_branch
高级 Git 命令
签署提交
签名提交是 Git 中验证提交真实性和完整性的一种方法。它允许您使用 GPG(GNU Privacy Guard,隐私保护)密钥对提交进行加密签名,从而向 Git 保证您确实是提交的作者。您可以通过创建 GPG 密钥并将 Git 配置为在提交时使用该密钥来实现签名。
具体步骤如下:
# Generate a GPG key
gpg --gen-key
# Configure Git to Use Your GPG Key
git config --global user.signingkey <your-gpg-key-id>
# Add the public key to your GitHub account
# Signing your commits with the -S flag
git commit -S -m "Your commit message"
# View signed commits
git log --show-signature
Git 引用日志
我们尚未探讨的一个主题是 Git 引用,它们是指向仓库中各种对象的指针,这些对象主要是提交,但也包括标签和分支。它们充当 Git 历史记录中的命名点,允许用户浏览仓库的时间线并访问项目的特定快照。了解如何浏览 Git 引用非常有用,他们可以使用 git reflog 来实现这一点。
以下是一些好处:
- 恢复丢失的提交或分支
- 调试和故障排除
- 纠正错误
交互式变基
交互式变基是 Git 的一项强大功能,它允许你以交互方式重写提交历史记录。它允许你在将提交应用到分支之前修改、重新排序、合并或删除它们。
为了使用它,您必须熟悉可能的操作,例如:
- 挑选(“p”)
- 重复(“r”)
- 编辑(“e”)
- 壁球(“s”)
- 掉落(“d”)
这是一个有用的视频,可以帮助您了解如何在终端中执行交互式变基,我还在博客文章的底部链接了一个有用的工具。
与 Git 协作
源站与上游
克隆本地 Git 仓库时,源仓库是与其关联的默认远程仓库。如果您已 fork 某个仓库,则该 fork 默认成为您的“源”仓库。
另一方面,上游是指您的存储库从中分叉出来的原始存储库。
为了使您的分叉存储库与原始项目的最新更改保持同步,您可以git fetch
从“上游”存储库中进行更改并将其合并或重新定位到本地存储库中。
# By pulling the pulled changes will be merged into your working branch
git pull <remote_name> <branch_name>
# If you don't want to merge the changes use
git fetch <remote_name>
要查看与本地 Git 存储库关联的远程存储库,请运行:
git remote -v
冲突
不要惊慌,当尝试合并或重新设置分支并检测到冲突时,这仅意味着存储库中同一文件或文件的不同版本之间存在冲突的更改,并且可以轻松解决(大多数时候)。
它们通常会在受影响的文件中指示出来,Git 会在其中插入冲突标记<<<<<<<
,=======
并>>>>>>>
突出显示冲突的部分。
决定保留、修改或删除哪些更改,确保生成的代码合理并保留预期的功能。
手动解决冲突文件中的冲突后,删除冲突标记<<<<<<<
、=======
和 ,>>>>>>>
并根据需要调整代码。
一旦您对解决方案满意,请保存冲突文件中的更改。
如果您在解决冲突方面遇到问题,该视频可以很好地解释这一点。
流行的 Git 工作流程
Git 工作流程多种多样,但需要注意的是,没有普遍适用的“最佳” Git 工作流程。每种方法都有各自的优缺点。让我们探索一下这些不同的工作流程,了解它们的优缺点。
功能分支工作流程🌱
每个新功能或错误修复都在其自己的分支中开发,然后在完成后通过打开 PR 将其合并回主分支。
- 优点:隔离变化并减少冲突。
- 缺点:可能变得复杂并需要勤勉的分支管理。
Gitflow 工作流程
Gitflow 定义了一个严格的分支模型,其中为不同类型的开发任务预定义了分支。
它包括主分支、开发分支、功能分支、发布分支和修补程序分支等长期分支。
- 优点:适合有计划发布和长期维护的项目。
- 缺点:对于较小的团队来说可能过于复杂
分叉工作流程🍴
在此工作流程中,每个开发人员都会克隆主代码库,但不会直接将更改推送到主代码库,而是将更改推送到他们自己的代码库分支。然后,开发人员会创建拉取请求 (Pull Request) 来向主代码库提交更改,以便在合并之前进行代码审查和协作。
这是我们用于协作开源 Glasskube 存储库的工作流程。
- 优势:鼓励外部贡献者的合作,而无需授予对主存储库的直接写访问权限。
- 缺点:维护分支和主存储库之间的同步可能具有挑战性。
基于主干的开发🪵
如果您所在的团队专注于快速迭代和持续交付,您可能会使用基于主干的开发,即开发人员直接在主分支上进行小而频繁的更改。
- 优势:促进快速迭代、持续集成,并专注于向生产中提供小而频繁的变更。
- 缺点:需要强大的自动化测试和部署管道来确保主分支的稳定性,可能不适合发布时间表严格或功能开发复杂的项目。
什么叉子?
对于开源项目的协作,强烈建议使用 fork 的方式,因为您可以完全控制自己的代码库副本。您可以进行更改、尝试新功能或修复错误,而不会影响原始项目。
💡 我花了很长时间才弄清楚,虽然分叉的仓库一开始是独立的实体,但它们仍然保留着与原始仓库的连接。这种连接让你能够跟踪原始项目中的更改,并将你的分叉与其他人所做的更新同步。
这就是为什么即使你推送到你的原始存储库,你的更改也会显示在远程存储库上。
Git 备忘单
# Clone a Repository
git clone <repository_url>
# Stage Changes for Commit
git add <file(s)>
# Commit Changes
git commit -m "Commit message"
# Push Changes to the Remote Repository
git push
# Force Push Changes (use with caution)
git push --force
# Reset Working Directory to Last Commit
git reset --hard
# Create a New Branch
git branch <branch_name>
# Switch to a Different Branch
git checkout <branch_name>
# Merge Changes from Another Branch
git merge <branch_name>
# Rebase Changes onto Another Branch (use with caution)
git rebase <base_branch>
# View Status of Working Directory
git status
# View Commit History
git log
# Undo Last Commit (use with caution)
git reset --soft HEAD^
# Discard Changes in Working Directory
git restore <file(s)>
# Retrieve Lost Commit References
git reflog
# Interactive Rebase to Rearrange Commits
git rebase --interactive HEAD~3
# Pull changes from remote repo
git pull <remote_name> <branch_name>
# Fetch changes from remote repo
git fetch <remote_name>
福利!一些 Git 工具和资源,让你的生活更轻松。
如果您喜欢这类内容并希望看到更多,请考虑在 GitHub 上给我们一个 Star 来支持我们🙏
文章来源:https://dev.to/glasskube/the-guide-to-git-i-never-had-1450