Git 的进阶功能和技巧

news2025/4/13 1:34:46

1、分支的概念和使用

1.1、什么是分支?

分支(Branch)是在版本控制中非常重要的概念。几乎所有版本控制系统都支持某种形式的分支。在 Git 中,分支是 Git 强大功能之一,它允许我们从主开发线分离出来,在不影响主分支的情况下并行地进行开发 (Git 分支管理 | 菜鸟教程)。你可以把分支想象成代码开发的平行宇宙:在一个分支上进行的修改,不会立即出现在另一个分支上。开发者可以利用分支来尝试新功能、修复 Bug 或进行实验,而无需担心弄乱主分支(通常是用于发布的稳定分支)。完成工作后,再把分支的改动合并回主分支,这样主分支就得到了更新,而整个过程主分支始终保持可用和稳定。

简而言之,使用分支可以让团队并行开发成为可能:每个人或每个新功能都在自己的分支上进行,互不干扰。等到需要整合时,再将分支合并。下面我们将介绍 Git 中有关分支操作的常用命令:创建分支、切换分支以及合并分支。

1.2、创建和切换分支(git branch, git checkout)

在 Git 中,新建分支使用命令 git branch,切换分支使用命令 git checkout(在较新的 Git 版本中,也可以使用 git switch 切换分支)。我们先来看如何创建一个分支:

  • git branch <分支名>:创建一个新的分支。此命令将在当前所在提交的基础上创建出一个分支指针。注意,仅执行 git branch 命令不会切换到新分支,只是新建了一个分支。

例如,如果我们当前在主分支 main 上,希望创建一个新分支来开发登陆功能,可以执行:

git branch login-feature

此操作会在当前提交的基础上建立一个名为 login-feature 的新分支。但是此时我们仍停留在 main 分支上。通过 git branch 不带参数可以列出所有本地分支,* 会标识当前所在的分支。

  • git checkout <分支名>:切换到指定的分支。切换分支会更改工作区的文件内容,以匹配该分支最近一次提交的状态。执行切换前,确保当前工作区没有未提交的修改,否则 Git 会拒绝切换(或者要求先 stash 暂存修改)以防止未提交的更改被覆盖。

继续上面的例子,我们创建了 login-feature 分支后,可以切换过去:

git checkout login-feature

执行后,Git 会提示已经切换到 login-feature 分支。现在开始的所有提交都会在 login-feature 分支上,而对 main 分支没有影响。

一个常用的快捷方式是将创建和切换合为一步完成:git checkout -b <分支名>。例如:

git checkout -b login-feature

如果 login-feature 不存在,这条命令会创建该分支并马上切换过去,相当于依次执行了 git branchgit checkout。这样更方便一些。

成功切换到新分支后,你可以像往常一样编辑代码、添加和提交。所有这些提交将属于 login-feature 分支,与主分支main的提交历史分离开。你可以随时使用 git checkout main 切换回主分支,如果此时打开项目文件,会发现那些在 login-feature 分支上做的改动不见了(因为此刻看到的是主分支上的内容)。别担心,这些改动仍然安全地保存在 login-feature 分支,只是当前未合并到主分支而已。

小贴士:在多人协作中,通常每个功能或修复都会新建一个分支进行开发,分支命名应简洁明了,如 feature/login-uibugfix/issue-101 等。主分支一般用来保存已经稳定并准备发布的代码。

1.3、合并分支(git merge)

当一个分支上的开发告一段落,需要将其成果合并回主分支(或其他分支)时,就可以使用 git merge 命令。git merge 用于将另一条分支的修改合并到当前分支上。

最常见的场景是将功能分支合并回主分支。例如,我们在 login-feature 分支上完成了登陆功能的开发和测试,现在希望把它合并到 main。步骤如下:

  1. 首先,切换到目标分支(即我们希望将改动合并到的分支)。这里是主分支 main

    git checkout main
    
  2. 然后执行合并命令,将功能分支合并过来:

    git merge login-feature
    

    这条命令表示:“把分支 login-feature 合并到当前分支(main)”。

执行 git merge 后,可能出现两种情况:

  • 快速前进(Fast-forward)合并: 如果主分支在功能开发期间没有新的提交,那么主分支实际上停留在功能分支的起点上。在这种情况下,Git 不需要创建新的合并提交,而只会简单地将主分支指向功能分支的最新提交。这种合并被称为 “快进”,表现出来就是主分支的历史直接向前推进,包含了功能分支的提交记录。

  • 非快进合并: 如果主分支在功能分支开发期间有自己的新提交,那么两个分支的历史出现了分叉。Git 会进行一次“三方合并”(three-way merge),自动创建一个新的合并提交来把分叉的历史合并起来。合并提交包含两个父提交,一个来自主分支原来的末尾,一个来自功能分支的末尾。合并提交的默认说明一般是“Merge branch 'login-feature' into main”。

在大多数情况下,如果没有冲突,Git 会自动完成以上两类合并。合并后,可以使用 git log --graph --oneline 来查看历史,分支的提交记录现在都出现在主分支的历史中了。完成合并后,功能分支的代码已经融合进主分支,通常我们可以选择删除那个已完成的功能分支以保持仓库整洁。删除本地分支的命令是:

git branch -d login-feature

-d 选项表示删除分支(该操作不会影响已经合并到的内容)。如果分支尚未合并就尝试删除,Git 会发出警告并拒绝删除,以免丢失未合并的修改。若确定要强行删除,可以用 -D(不推荐轻易使用)。

注意:合并前请确保将待合并的分支最新内容拉取下来(如果是多人协作且远程有更新的话)。比如在合并远程分支时,先 git pull origin login-feature 更新本地的 login-feature,再切换到 main 合并。这样可以减少合并冲突的概率。

2、合并冲突及解决方法

当两个分支都有各自的提交,并且修改了同一个文件的同一部分时,Git 在合并它们时就会遇到合并冲突(merge conflict)。简单来说,Git 无法自动判断以哪个分支的修改为准,需要人工介入决策。冲突最常发生于多人修改了相同代码的情形,或自己在不同分支对同一文件做了不同改动。

**冲突发生时的现象:**执行 git merge 后,终端会输出类似“Automatic merge failed; fix conflicts and commit the result.”的信息。这表示自动合并未能完成,需要手动解决冲突。此时,可以运行 git status 查看哪些文件存在冲突,输出中会列出冲突文件并标记为“both modified”。

解决合并冲突的一般步骤:

  1. 定位冲突区域: 用文本编辑器打开存在冲突的文件。你会看到特殊的冲突标记。例如,假设 config.txt 文件在两个分支有冲突,打开后可能出现这样的内容:

    <<<<<<< HEAD
    timeout=30
    =======
    timeout=60
    >>>>>>> login-feature
    

    上述标记表示:HEAD(当前分支,即 main 分支)的内容是 timeout=30,而要合并进来的 login-feature 分支的内容是 timeout=60。冲突区域被 <<<<<<<=======>>>>>>> 分隔成两部分,开发者需要决定哪一侧(或如何合并两者)才是正确的。

  2. 手动合并修改: 编辑冲突标记所在位置,根据需要保留或修改代码。例如,如果确定以 login-feature 分支的设置为准,就把 timeout=60 保留下来,删去其他冲突标记。如果两侧的修改都需要,可以手动合并成一个新的内容。总之,要编辑成我们想要的最终结果,并删除所有 <<<<<<, ======, >>>>>> 标记,使文件恢复正常的代码格式。

  3. 标记冲突已解决并暂存: 修改完所有冲突文件后,保存文件并退出编辑器。然后使用 git add <文件> 将刚刚解决冲突的文件添加到暂存区。标记为已解决意味着告诉 Git:“这文件的冲突我已经处理好了,可以纳入下一次提交”。

  4. 完成合并提交: 当所有冲突都解决并 git add 后,再次执行 git status 检查确认没有剩余未解决的冲突。接下来,运行 git commit 提交合并结果。值得注意的是,如果当前正处于合并过程,Git 在提交时会自动带上合并的默认提交信息(也可以自行编辑提交说明)。提交成功后,合并冲突就算解决完成,仓库历史中会出现这次合并提交。

如果在处理冲突过程中发现合并的方向有误或者想放弃此次合并,可以使用:

git merge --abort

该命令会中止合并操作,将分支恢复到合并开始前的状态,就像从未执行过合并一样。然后你可以重新尝试合并或者做其他处理。

小提示:合并冲突虽然听起来可怕,但有些图形化工具可以帮助解决。例如,使用 git mergetool 可以调起图形化冲突解决工具(如 KDiff3、P4Merge 等)对比冲突双方的差异,辅助你选择保留方案。另外,在团队协作中,减少冲突的最好办法是勤奋地沟通和同步:经常 git pull 同步他人修改,及时分享自己的改动。当冲突真的发生时,也尽量和相关开发者商量确认最终修改方案。

3、使用 git stash 暂存变更

在日常开发中,有时我们会遇到这样一种情况:正在一个分支上开发新功能,代码写到一半,突然接到任务需要立即切换到另一分支去修复紧急问题。但当前分支的修改尚未完成也不适合提交,这时该怎么办?直接切换分支会被 Git 拒绝(因为有未提交修改),把不完整的工作硬提交显然也不妥当。git stash 就是为了解决这种场景而设计的。

git stash 命令可以将当前工作目录和暂存区的修改暂时储藏起来,恢复到干净状态,好让你切换到别的分支去处理其他事务。等需要恢复时,再将暂存的修改取出,继续先前的工作。git stash 类似于一个堆栈(stack),可以储存多组未完成的修改。

常用的 stash 操作为:

  • 保存当前修改: 在有未提交改动的情况下运行:

    git stash
    

    这会把所有未提交的修改(包含已经 git add 暂存的和尚未暂存的)保存到一个匿名的储藏当中。Git 会输出类似 “Saved working directory and index state WIP on branchName...” 的信息,并将工作区恢复到最近一次提交的状态。你也可以加说明信息,例如 git stash save "message",但较新的 Git 版本中直接 git stash 也可以自动保存。

  • 查看暂存列表: 可以运行:

    git stash list
    

    来查看所有储藏的记录。最新的储藏在最上面,每条记录都有一个索引(如 stash@{0})和描述(包含当时所在的分支名和提交信息的摘要)。

  • 恢复暂存的修改: 当你要继续之前的工作时,在相应的分支上运行:

    git stash pop
    

    这条命令会将最近一次保存的修改取出应用到当前工作目录,同时从储藏列表中移除该记录。假如你想应用但保留储藏记录,可以使用 git stash apply stash@{n}(其中 n 是编号)来应用某个特定储藏但不删除它。

举个例子:你在 feature-X 分支上开发,写了一半代码。这时需要切换到 main 分支修复紧急 Bug。你可以执行 git stashfeature-X 的修改暂存起来,然后 git checkout main 切换分支(现在不会有未提交内容的阻碍)。修复完 Bug 并提交推送后,回到 feature-X 分支,用 git stash pop 将之前的工作恢复出来,继续完成剩下的开发。整个过程就像把工作“按暂停”,处理完其他事情后再“恢复播放”。

git stash 非常适合处理工作中断、上下文切换的场景。需要注意的是,stash 默认会储存未提交的所有内容(包括已暂存和未暂存的部分)。如果你只想暂存尚未暂存的修改而保留已暂存部分,可以使用 git stash -k (keep index)。另外,git stash 也能暂存新建但未追踪的文件(加 -u 参数),不过初学者一开始用默认行为即可。

最后,当某个储藏的修改不再需要时,可以用 git stash drop stash@{n} 删除,或者 git stash clear 清空所有暂存记录。合理地使用 stash,可以帮助你保持仓库提交历史的整洁,不会因为临时切换任务而到处留下零碎的“WIP”提交。

4、git reset 与 git revert 的区别

在使用 Git 的过程中,难免会遇到需要“撤销”更改的时候。Git 提供了多个命令来撤销或回退提交,其中最常见的是 git resetgit revert。它们都能达到“让项目回到之前状态”的目的,但原理和使用场景有所不同。理解两者区别有助于我们在不同情况下选择正确的方法去撤销修改。

4.1、git reset —— 重置提交历史

git reset 通常用于“回退”本地仓库的HEAD到某个旧的提交。通过 reset,我们可以舍弃最近的一些提交,使仓库退回到指定的历史节点。根据参数不同,git reset 既可以影响提交历史,也可以影响暂存区和工作区。

git reset [模式] <提交> 其中常用的模式有三种:

  • --mixed(默认模式):重置 HEAD 到指定提交,同时保留工作区改动但清除暂存区。简言之,就是把选定提交之后的修改全部撤出提交历史,放回工作区未暂存的状态。

  • --soft:更温和的重置,只重置 HEAD 提交,暂存区和工作区都保留这些改动。也就是说撤销最近的提交,但改动仍然保持在暂存区,几乎相当于把提交“取消”回暂存状态。

  • --hard:强制重置,提交历史、暂存区和工作区都同步到指定提交的状态。所有在那个提交之后的改动都会被彻底丢弃,从当前目录中消失(无法通过 Git 恢复)。

一个常见的用法是撤销最近一次提交。例如你发现刚才的提交有问题,不想要了,可以使用:

git reset HEAD~1

这条命令将仓库重置到上一个提交(即舍弃了最新提交)。默认模式下(mixed),最新提交的更改内容会留在工作区,这样你可以修改后重新提交,或者也可以放弃掉。相当于“退一步,但保留现场改动,允许你修正后再提交”。

如果你完全确定最近的提交是错误的且不需要其中的改动,可以用:

git reset --hard HEAD~1

警告:--hard 非常危险,它会抹掉工作区中自上一个提交以来的所有改动!除非你在其他地方还有这些改动的备份,否则此操作不可逆。因此务必谨慎使用。

git reset 更多地被视为一种本地操作,设计用于调整尚未公开(push)的历史。例如,你提交了一些临时代码想回退,或者想将上一个 commit 拆分/合并,这些都可以通过 reset 在本地实现,然后重新整理 commit,再推送。但是如果你已经把提交推送到远程仓库,其他人也基于它展开了工作,贸然 reset 自己的分支并强制推送(force push)会导致团队其他人的仓库历史不一致。因此,git reset 一般不应用于已发布到公用仓库的提交

除了回退整个提交,git reset 还可以用于取消暂存(unstage)。比如不小心 git add 了不想提交的文件,可以用 git reset HEAD <文件> 将其从暂存区移除,回到未暂存状态。

4.2、git revert —— 还原提交

与 reset 不同,git revert 是通过创建一个新的提交抵消某个历史提交的影响,从而达到“撤销更改”的目的。git revert <提交> 会根据指定的提交,产生一个内容相反的新提交,应用这个新提交后,仓库状态看起来就像撤回了指定的提交一样。但是,原先的提交记录依然保留在历史中,只是后面附加了一个“反向提交”来消除它的效果。

git revert 常用于已经推送到远程仓库并分享给他人的提交的撤销。因为 revert 不会重写历史,它是往历史里添加记录,所以对团队其他成员不会产生破坏性的影响。实际上,revert 后大家同步代码时,会拿到一个新的提交,该提交做了撤销更改的操作。

举例来说,假如在主分支有一个错误的提交 C 已经推送,现在想撤销它。如果用 reset,我们必须强制修改历史,会给协作者带来困扰;但使用 revert:

git revert <提交C的哈希>

Git 会自动创建一个新提交 C'(内容为将提交 C 引入的改动反向修改回去),提交消息会注明它是一次 revert。例如 “Revert "添加XX功能"”。推送这个新提交后,其他人拉取更新,他们的仓库会保留提交 CC' 两条记录,但最终文件内容与 C 未发生前一致了。

git revert 的语法通常是指定具体的提交哈希,也可以使用诸如 HEADHEAD~2 这类引用来表示相对位置。还可以连续 revert 多个提交(需要逐个执行或使用...范围)。需要注意,如果要 revert 的提交不是最新的,或者涉及文件改动与后续提交有重叠,可能也会出现冲突,处理方式和合并冲突类似:修改冲突文件然后继续 git revert --continue 完成操作(revert 一个提交序列的情况)。

小结比较:git revertgit reset 的根本区别在于是否保留历史git revert 是用一次新的 commit 来回滚之前的 commit,而 git reset 是直接删除指定的 commit 。换句话说:

  • 使用 git reset,仓库会“丢弃”某段历史,就好像那些提交从未发生过。而使用 git revert,仓库历史会完整保留每一次改变,只是附加记录某次改动被撤销了。

  • git reset 改变了当前分支的 commit 链(HEAD 向后移动),而 git revert 则让 HEAD 继续前进,只是新增的那个提交的内容与被还原的提交相反,从效果上抵消了它 。

  • 从协作角度,reset 要求所有协作者都配合修改历史(否则会出现分歧),而 revert 则是一个正常的提交,其他人只需拉取即可。因此,撤销公开发布的提交建议使用 git revert ;仅在本地调整尚未发布的提交时可以使用 git reset

使用场景建议:

  • 当你提交后立刻发现错误,且该提交尚未推送,想彻底抹除这次错误提交,可以考虑 git reset 将 HEAD 回退(或者用 git commit --amend 更正提交,这也是改历史的方法之一)。但如果该提交已经分享出去,不要用 reset 撤销。

  • 当某次提交已经推送并被他人拉取,如果后来证明需要撤销,就用 git revert 来安全地回滚。这样所有人的历史都会保持一致,只是多了一条修正记录。

  • 如果需要清除多个无用的提交(比如试验性质的提交),而这些提交尚未推送,可以用 git reset 一次性回退。不过Git还有更高级的工具如交互式 rebase 可以用于整理多个提交(见下一节)。

总之,谨记:不要在公共仓库的分支上使用 git reset --hard 等破坏性命令;撤销公开提交请选择 git revert。两者各有用途:reset 修剪历史,revert 保持历史连续性地进行撤销。

5、使用 git rebase 优化提交历史

在多人协作和长期开发的项目中,提交历史很容易变得复杂。频繁的合并会产生很多分支交叉点和合并提交,而且每个人的提交粒度和风格也不尽相同。Git 提供的 git rebase 命令可以在一定程度上优化和整理提交历史,使之更加线性和简洁。不过,rebase 修改历史的特性也需要我们小心使用。

5.1、变基(Rebase)简介

git rebase 的直译是“变基”。它的作用是改变提交的基底。具体来说,就是将一系列提交“剪下来”,然后重新应用(Replay)在另一位置。结果就是提交历史发生了重排或重构。在实际操作中,rebase 常用于两种情况:

  1. 在分支合并前,更新分支以基于最新的主分支: 假设我们有一个功能分支 feature 从主分支 main 分出。一段时间后,main 上有了新的提交,而 feature 也有自己的提交。这时,我们可以在将 feature 合并回 main 之前,先切到 feature 分支执行 git rebase main。这会把 feature 分支上的提交转移到 main 分支最新提交之后,仿佛 feature 是从当前最新的 main 开始开发的一样。这样处理后,当我们再合并 feature 到 main 时,可以避免产生额外的合并提交,使历史呈现为一条直线。

    例如:最初 main 有 A 提交,feature 分支从 A 分出做了提交 B;期间 main 上又有了提交 C。此时 feature 分支执行 git rebase main 后,feature 上的 B 提交会被移到 C 的后面,形成一个新的提交 B'。现在 main 的历史是 A - C,feature 的历史是 A - C - B'。随后如果 fast-forward 合并,主分支将线性包含 A - C - B',看起来就像 B'是在 C 之后提交的一样,消除了分叉记录。

    Rebase 后由于提交被重新应用,其 SHA-1 哈希值会发生变化(B 变成 B'),所以这个过程重写了分支的历史。Git 会逐个应用 feature 分支的每个 commit,因此如果这些提交与 main 的更改有冲突,会暂停并要求解决冲突(类似前面合并冲突的过程,但命令变为 git rebase --continue 继续下一个,或者 git rebase --abort 放弃变基)。

  2. 整理本地的多次碎片提交: 在开发一个功能时,可能我们会进行很多次临时的提交(比如调试信息、实验尝试等)。在提交到主分支前,团队往往希望这些历史被整理得整洁一些,例如合并相关的改动、编辑规范提交消息等。git rebase -i(交互式变基)可以帮助实现这一点。通过交互式 rebase,我们可以选择**压缩(squash)**多个提交为一个、修改(edit)某些提交的内容或消息、甚至改变提交顺序等。

    例如,假设我们在当前分支有最近的5个提交需要整理,只需执行:

    git rebase -i HEAD~5
    

    Git 会打开一个文本界面,列出这5个提交以及可选的操作(pick, squash, edit 等)。根据需要编辑保存后,Git 就会按照新的指令重新依次应用这5个提交(期间如果有冲突需解决)。整理完成后,分支历史就被改写成了我们想要的样子。常用的操作包括将多次“小提交”合并成一次有意义的大提交(squash),或修改提交信息(reword/edit)以更清晰地描述改动。

rebase vs merge: Rebase 和 Merge 是实现分支集成的两种方式,各有优劣。Merge保留了完整的历史轨迹(包括分叉点和合并节点),能看出代码是如何在分支上演进再合流的;而Rebase则让历史看上去像一条直线,没有分叉(就像所有改动都串行发生在一个分支上)。Rebase后的历史往往更加简洁、线性,使用 git log 浏览时不会被大量的合并提交干扰。但另一方面,Merge不改变已有历史,而Rebase通过重写历史来达成线性,可能会让历史记录失去分支上下文。

**使用注意:由于 rebase 会重写提交历史,所以有一个“变基黄金法则”**必须牢记:绝不要在公共分支上对已经推送的提交执行 rebase 。换句话说,仅对尚未分享给别人的本地分支使用 rebase。一旦你在协作的分支(比如 origin/main 或团队共享的feature分支)上做了变基,然后强制推送,会导致他人的仓库出现冲突和混乱(因为他们的提交历史与你的不一致)。因此,在共享环境下,rebase 只能用于更新自己本地的开发分支,再正常推送,或用于自己fork后在PR合并前整理提交。遵循“变基黄金法则”:绝不在公有仓库的分支上执行 rebase。

5.2、举例:使用 rebase 更新分支

假设你正在开发分支 feature-A 上工作,此时需要同步主分支 main 最新的更新。在 merge 和 rebase 两种做法中,如果选择 rebase:

# 确保主分支是最新的
git checkout main
git pull origin main

# 切回功能分支,执行变基
git checkout feature-A
git rebase main

执行上述操作后,Git 会将 feature-A 分支上的提交一个接一个地转移到 main最新提交之后。如果没有冲突,变基会自动完成。若有冲突,Git 会停止并让你解决冲突,解决完毕后用 git add 将更改暂存,然后 git rebase --continue 继续剩下的提交。全部结束后,切换到 main,可以使用 git merge feature-A 快速合并(fast-forward)或者直接 git push origin feature-A:main 推送 feature-A 分支作为 main 分支的新更新(比如在pull request被接受时)。这样 main 的历史就是线性的,没有额外的分叉点。相比直接 merge,这种方法避免了合并提交,使历史更干净。

5.3、举例:交互式 rebase 整理提交

假如在开发一个功能过程中,你做了3次提交:第一次提交遗漏了一些文件,第二次补上遗漏,第三次修正了前面提交信息的一个拼写错误。最终这些其实都是为实现同一个功能,理想情况下可以合并成一个提交。使用 git rebase -i 可以实现:

git rebase -i HEAD~3

在打开的编辑界面中,你会看到类似:

pick f1a2b3c Implement feature X
pick a3d4e5f Add missing files for feature X
pick b4c6d7e Fix typo in feature X description

将后两行的 pick 改为 squash(或缩写 s),表示将它们压缩到第一个提交中。保存退出后,Git 会应用第一个提交,然后将后两个提交的改动合并进第一个。在这个过程中会让你编辑合并后的提交消息,你可以整合原先三个提交的信息为一条完整描述。完成后,历史中就只剩下一条提交,包含所有改动。这就是一次提交压缩操作。类似地,你可以重新排序提交顺序(调整行的先后)、丢弃某些提交(改为 drop),或者标记 edit 手动修改某个提交的内容(在 rebase 过程中暂停让你修正然后继续),等等。

通过 rebase 的这些技巧,我们能够在不影响最终代码结果的情况下,让提交历史更符合阅读和维护的需要。例如,将“修复拼写错误”“调整格式”这类杂碎 commit 合并到主要 commit 中,保持主干历史的清晰。当然,这种修改历史的动作只应对自己本地分支进行,在与团队协作前完成整理。

6、推荐的 Git 使用流程与团队协作技巧

掌握了上述 Git 高级功能后,我们来讨论一下在团队协作中,如何高效地使用 Git 工作,以及一些值得遵循的实践规范。良好的协作流程可以避免很多问题,确保团队所有成员各司其职又步调一致。

下面是一套常见的 Git 团队协作开发流程(以功能开发为例):

  1. 同步主分支: 在开始新的工作之前,先切换到主分支(例如 maindevelop),执行 git pull 拉取远程最新代码。这样可以确保你的主分支是最新状态,为后续创建新分支打好基础。

  2. 新建功能分支: 从主分支创建一个新的功能分支用于开发你的任务:

    git checkout -b feature/some-feature
    

    分支命名应清晰反映工作内容,比如 feature/login-authbugfix/issue-101。在这个分支上进行你的开发工作,与此同时主分支的代码保持不变。

  3. 在分支上进行开发并频繁提交: 在功能分支上编写代码。建议遵循“早提交、勤提交”的原则,每实现一个独立的小功能或达到一个里程碑就使用 git addgit commit 提交一次。提交信息要清晰描述修改目的,例如 “Add login form UI” 而不是 “update code”。频繁提交有助于记录开发轨迹,也使得出现问题时更容易定位和回溯。

  4. 将分支推送到远程: 虽然还在开发中,但也最好经常将本地分支推送到远程仓库备份,并让团队可见你的进展:

    git push -u origin feature/some-feature
    

    使用 -u 将本地分支与远程同名分支建立跟踪关系。之后如果继续有新的提交,可定期 git push 更新远程。这样即使你的电脑发生故障,代码也不会丢失,同时同事也能看到并拉取你的最新代码(如果需要协作)。

  5. 与主分支保持同步: 开发过程中,主分支可能也在推进其他更新。为避免分支长期偏离主线,最好定期用主分支的变化更新你的功能分支。例如可以执行 git pull origin main(或 git fetch 然后在分支上 git merge origin/main)将主分支的修改合并过来。如果希望更整洁,可以用 git rebase origin/main 将你的提交变基到主分支后。这能减少最终合并时的冲突概率。

  6. 提交合并请求(Pull Request)并代码审查: 功能开发完成并经过自测后,将你的分支代码合并回主分支。通常做法是在托管平台上创建一个 Pull Request(合并请求),描述你的更改,通知团队其他成员审核代码。代码审查(Code Review)可以发现潜在问题并确保代码质量。在 PR 通过后,维护者会将你的功能分支合并到主分支。合并可以采用 Squash Merge(压缩成一次提交)或者普通 Merge,根据团队约定。

  7. 清理分支并部署: 功能成功合并进主分支后,可以删除远程和本地的功能分支(以避免过多分支混乱仓库):

    git branch -d feature/some-feature        # 删除本地分支
    git push origin --delete feature/some-feature  # 删除远程分支
    

    之后,在本地切回主分支并 git pull 获取最新的代码。如果需要部署或发布,可以根据主分支最新代码进行。

在上述流程中,有一些值得强调的团队协作技巧和最佳实践:

  • 确保主分支始终可用: 主分支(如 main/master)通常代表产品的稳定版本。不在主分支上直接开发新功能,所有对主分支的修改都通过分支合并来完成。这样主分支上的代码始终是可以随时发布或部署的。如果需要紧急修复,也使用热修复分支来完成并尽快合并。

  • 善用分支命名和标签: 清晰的分支命名有助于协作。例如见到 feature/login-auth 自然知道是开发登录认证功能。对于重要的里程碑或发布版本,使用 Git 标签(tag)来标记提交,方便以后查找对应版本的代码。

  • 编写有意义的提交消息: 一个好的提交消息能够简洁概括更改内容或原因,方便日后查阅历史时了解每次改动的目的。避免使用含糊不清的描述如“修改代码”“更新了几个文件”。常见格式是在简短的标题后可选地补充细节描述,团队可以采用一致的 commit message 风格(比如遵循 Angular 提交信息规范等)。

  • 及时拉取和合并: 团队协作中,每个人应经常同步远程仓库的最新变化(git pull),特别是在开始新的任务或准备将自己的修改推送前。这可以最大限度减少冲突。当发现与他人有冲突时,积极沟通,共同决定如何解决。

  • 不要在公共分支上强制推送: 避免使用 git push --force 强制推送主分支或他人也在用的分支。如果必须(例如更正错误的历史),也要提前与团队说明,确保别人没有基于旧历史继续工作。强制推送可能覆盖他人的提交,通常只有仓库管理员在特殊情况下才执行,而且通常通过 Pull Request 来协同完成。

  • 使用 .gitignore 保持仓库整洁: 在协作项目中,制定 .gitignore 文件很重要,确保编译产物、临时文件、不需要纳入版本控制的文件不被提交。例如日志文件、IDE配置、依赖生成的文件等应被忽略。这可以减少不必要的冲突和仓库臃肿。

  • 定期备份和维护仓库: 虽然远程仓库本身就是备份,但也可以克隆镜像仓库作为额外备份。对长期项目,定期清理无用的分支,避免仓库中累积过多过期分支。对于超大的历史(比如大量二进制文件意外提交),可以考虑使用 Git 工具(如 BFG Repo-Cleaner)清理,但这些都是进阶话题了。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2331984.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Spark Core编程

一 Spark 运行架构 1 运行架构 定义 Spark 框架的核心是一个计算引擎&#xff0c;整体来说&#xff0c;它采用了标准 master-slave 的结构 如图所示 2 核心组件 Spark 框架有两个核心组件: 1)Driver 2)Spark 驱动器节点&#xff08;用于执行 Spark 任务中的 main 方法&…

无人机装调与测试

文章目录 前言一、无人机基本常识/预备知识&#xff08;一&#xff09;无人机飞行原理无人机硬件组成/各组件作用1.飞控2.GPS3.接收机4.电流计5.电调6.电机7.电池8.螺旋桨9.UBEC&#xff08;稳压模块&#xff09; &#xff08;二&#xff09;飞控硬件简介&#xff08;三&#x…

【图书管理系统】全栈开发图书管理系统获取图书列表接口(后端:计算图书页数、查询当前页展示的书籍)

图书列表 实现服务器代码(计算图书总数量查询当前页需要展示的书籍) 后端响应时&#xff0c;需要响应给前端的数据 records&#xff1a;第 pageNum 页要展示的图书有哪些&#xff08;存储到List集合中&#xff09;total&#xff1a;计算一共有多少本书&#xff08;用于告诉前…

正则表达式补充——python

简介 本章是对前面正则表达式的补充。 一、复杂的查找替换等任务 content 张三是脑卒中病 李四&#xff0c;是高血脂 苏齐&#xff0c;是肺结核病 六六&#xff0c;是血血血血import re p re.compile(r...病) for one in p.findall(content):print(one) 运行结果&#xf…

[ctfshow web入门] web7

信息收集 题目提示&#xff1a;版本控制很重要&#xff0c;但不要部署到生产环境更重要。 那么很有可能&#xff0c;版本控制相关的信息被部署到环境了&#xff0c;比如比如version.txt记录了一些相关配件的版本&#xff0c;git版本管理工具中的.git文件夹未删除 信息收集就是…

DeepSeek-V3 API:开启下一代AI应用开发的新篇章

引言 在人工智能技术日新月异的今天&#xff0c;大型语言模型(LLM)正以前所未有的速度改变着我们与技术互动的方式。DeepSeek-V3作为国内领先的大语言模型之一&#xff0c;其API的开放为开发者提供了强大的AI能力集成方案。 DeepSeek-V3 API的核心优势 1.强大的语言理解与生…

go语言应该如何学习

以下是学习Go语言的高效路径及关键技巧&#xff0c;结合多个优质来源整理而成&#xff0c;适合不同基础的学习者&#xff1a; 一、基础语法快速入门&#xff08;1-2周&#xff09; 1、环境搭建 下载安装Go SDK&#xff0c;配置GOPATH和GOROOT环境变量&#xff0c;推荐使用Go…

NO.84十六届蓝桥杯备战|动态规划-路径类DP|矩阵的最小路径和|迷雾森林|过河卒|方格取数(C++)

路径类dp是线性dp的⼀种&#xff0c;它是在⼀个nm的矩阵中设置⼀个⾏⾛规则&#xff0c;研究从起点⾛到终点的⽅案数、最⼩路径和或者最⼤路径和等等的问题 矩阵的最小路径和_牛客题霸_牛客网 状态表⽰&#xff1a; dp[i][j]表⽰&#xff1a;到达[i, j]位置处&#xff0c;最⼩…

React + TipTap 富文本编辑器 实现消息列表展示,类似Slack,Deepseek等对话框功能

经过几天折腾再折腾&#xff0c;弄出来了&#xff0c;弄出来了&#xff01;&#xff01;&#xff01; 消息展示 在位编辑功能。 两个tiptap实例1个用来展示 消息列表&#xff0c;一个用来在位编辑消息。 tiptap灵活富文本编辑器&#xff0c;拓展性太好了!!! !!! 关键点&#x…

博途 TIA Portal之1200做主站与汇川EASY的TCP通讯

前言,虽然已经做了几篇关于TCP通讯的文章,但是不同的PLC之间的配合可能不同,下面将演示这种差异。 关于汇川EASY做从站的配置请参见下方链接文章:汇川EASY系列之以太网通讯(套接字socket做从站)_汇川以太网tcp套接字fb块-CSDN博客 1、硬件准备: 1200PLC,汇川EASY320…

蓝桥杯速成刷题清单(上)

一、1.排序 - 蓝桥云课 &#xff08;快速排序&#xff09;算法代码&#xff1a; #include <bits/stdc.h> using namespace std; const int N 5e5 10; int a[N];int main() {int n;cin >> n;for (int i 0; i < n; i) {cin >> a[i];}sort(a, a n);for …

Go并发背后的双引擎:CSP通信模型与GMP调度|Go语言进阶(4)

为什么需要理解CSP与GMP&#xff1f; 当我们启动一个Go程序时&#xff0c;可能会创建成千上万个goroutine&#xff0c;它们是如何被调度到有限的CPU核心上的&#xff1f;为什么Go能够如此轻松地处理高并发场景&#xff1f;为什么有时候我们的并发程序会出现奇怪的性能瓶颈&…

Linux服务器——Samba服务器

简介 Samba 是一个开源的跨平台文件共享服务​​&#xff0c;允许 Linux/Unix 系统与 Windows 系统实现文件和打印机的共享与互操作。其核心协议为 ​​SMB/CIFS​​&#xff08;Server Message Block / Common Internet File System&#xff09;&#xff0c;是 Windows 网络中…

华为网路设备学习-17

目录 一、加密算法 二、验证算法 三、IPsec协议 1.IKE协议&#xff08;密钥交换协议&#xff09; ①‌ISAKMP&#xff08;Internet Security Association and Key Management Protocol&#xff09;互联网安全关联和密钥管理协议 ②安全关联&#xff08;SA&#xff09; ③…

机器学习12-集成学习-案例

参考 【数据挖掘】基于XGBoost的垃圾短信分类与预测 【分类】使用XGBoost算法对信用卡交易进行诈骗预测 银行卡电信诈骗危险预测(LightGBM版本) 【数据挖掘】基于XGBoost的垃圾短信分类与预测 基于XGBoost的垃圾短信分类与预测 我分享了一个项目给你《【数据挖掘】基于XG…

【数据库原理及安全实验】实验二 数据库的语句操作

目录 指导书原文 实操备注 指导书原文 【实验目的】 1) 掌握使用SQL语言进行数据操纵的方法。 【实验原理】 1) 面对三个关系表student&#xff0c;course&#xff0c;sc。利用SQL语句向表中插入数据&#xff08;insert&#xff09;&#xff0c;然后对数据进行delete&…

【BFT帝国】20250409更新PBFT总结

2411 2411 2411 Zhang G R, Pan F, Mao Y H, et al. Reaching Consensus in the Byzantine Empire: A Comprehensive Review of BFT Consensus Algorithms[J]. ACM COMPUTING SURVEYS, 2024,56(5).出版时间: MAY 2024 索引时间&#xff08;可被引用&#xff09;: 240412 被引:…

Linux-CentOS-7—— 配置静态IP地址

文章目录 CentOS-7——配置静态IP地址VMware workstation的三种网络模式配置静态IP地址1. 编辑虚拟网络2. 确定网络接口名称3. 切换到网卡所在的目录4. 编辑网卡配置文件5. 查看网卡文件信息6. 重启网络服务7. 测试能否通网8. 远程虚拟主机&#xff08;可选&#xff09; 其他补…

Jupyter Lab 无法启动 Kernel 问题排查与解决总结

&#x1f4c4; Jupyter Lab 无法启动 Kernel 问题排查与解决总结 一、问题概述 &#x1f6a8; 现象描述&#xff1a; 用户通过浏览器访问远程服务器的 Jupyter Lab 页面&#xff08;http://xx.xx.xx.xx:8891/lab&#xff09;后&#xff0c;.ipynb 文件可以打开&#xff0c;但无…

算法训练之位运算

♥♥♥~~~~~~欢迎光临知星小度博客空间~~~~~~♥♥♥ ♥♥♥零星地变得优秀~也能拼凑出星河~♥♥♥ ♥♥♥我们一起努力成为更好的自己~♥♥♥ ♥♥♥如果这一篇博客对你有帮助~别忘了点赞分享哦~♥♥♥ ♥♥♥如果有什么问题可以评论区留言或者私信我哦~♥♥♥ ✨✨✨✨✨✨ 个…