学会git,这一篇文章就够了!

简洁、直接、结合业务

环境是ubuntu22.04

Git安装与卸载

git --version # 查看版本
git apt-get install git -y # 安装
git apt-get remove git -y # 卸载

配置默认编译器

git config --global core.editor "vim" # 默认编辑器是nano

仓库创建与初始化

git config user.name lpx # 设置提交时显示的用户名
git config user.email lpx@163.com # 设置提交时显示的邮箱
# --global 表示该用户的所有git仓库都设置
# --local 表示仅当前仓库设置(默认)
git config -l # 显示配置信息
git init # 生成.git 文件,这就是版本库(仓库)

版本库、工作区

请添加图片描述

提交相关命令:add commit status diff cat-file

git add file.txt # -u选项表示只添加已跟踪文件的修改和删除
git commit -m "first commit" 
git commit --amend # 修改最新一次提交注释
git push
git cat-file -p + commit id # 查看 commit 对象的元数据
git status # 查看文件状态
git diff +文件名(工作区) # 查看工作区和版本库的区别

版本回退 reset reflog

git reset --soft + commit id # 版本库回退到指定commit id,移动HEAD指针,暂存区、工作区都不变
git reset --mixed + commit id # 版本库和暂存区回退到指定commit id,暂存区(index)移动指针,HEAD也移动指针.默认不加参数就是使用--mixed
git reset --hard + commit id # 带着工作区全部版本回退

示例(使用git add后,在不用git commit 前提下,如何回退版本)

# 我们只希望工作区返回
git checkout -- filename # 工作区版本回退到上次commit 状态。若文件已被 git add(暂存区有记录),则用暂存区的内容覆盖工作区;若文件未被 git add(暂存区无记录),则用版本库最新提交(HEAD)的内容覆盖工作区;该命令会永久丢弃工作区的修改,且无法恢复,执行前需确认。
# 我们只希望工作区和暂存区返回
git reset HEAD filename  # 作用对象是暂存区(.git/index),让暂存区(index)内容修改为当前HEAD指向的commit id文件内容
git checkout -- filename 
# 如果我们使用了git commit后,希望修改工作区、版本库、暂存区的版本
git reset --hard HEAD^ # ^表示上一个版本,^^表示上两个版本
# 这里的示例只是使用HEAD ^ ^^ 代替commit id

怎么查看commit id

使用git log就可以查看当前指向objects之前的所有提交记录,但是如果我们使用版本回退后,因为HEAD指向位置变化,会导致我们之后的log看不到

使用git reflog就可以查看回退前的commit id了,其实回退并不会删除、修改一部分objects,我们ls objects就能发现。

回退原理就是修改HEAD指向commit id 位置

文件删除 git rm

git rm files # 删除工作区和暂存区内容,等价于rm files + git add files 
git commit -m "rm files"

分支

查看当前分支 git branch

cat .git/HEAD 打印出来 refs/heads/master 表示当前分支是master. refs/heads存储所有分支指向的commit id

cat refs/heads/master 打印出来当前commit id

git branch # 查看分支
git branch -r # 查看远端仓库的分支 -a可以查看本地和远端的分支
git branch -vv # 查看本地仓库分支和远端仓库分支的连接情况

创建分支 git branch / checkout -b

git branch dev # 创建dev分支——发现refs/heads/dev文件生成(创建分支基于当前版本,所以cat结果就是newest commit id)

远端仓库创建分支,然后本地连接 -b 创建时链接

git checkout -b dev origin/dev
git branch dev # 查看连接情况
git branch --set-upstream-to=origin/dev dev # 也行

切换分支 checkout

git checkout dev # 切换分支,让HEAD指向refs/heads/dev,这种情况下的commit 都是 HEAD->dev
git checkout -b dev # -b表示没有就创建,同时git checkout dev

合并分支 merge --no-ff

git merge dev # 合并分支,默认为ff——fast forwards快速提交
git merge --no-ff -m "merge dev2" dev2 # 不使用ff,
ff和no-ff区别

ff:Git 仅将master的 HEAD 指针直接移动dev的最新提交C3不生成新的合并提交。最终的提交历史是线性的

master: C1
         \
dev:      C2 → C3


master/dev: C1 → C2 → C3
–no-ff:git merge --no-ff dev

Git 会强制生成一个新的合并提交C4,即使满足快进条件。最终的提交历史是有分叉和合并节点的

master: C1 → C4 (合并提交)
           \   /
  dev:      C2 → C3

企业级开发的核心需求是代码可追溯、团队协作可管理、问题可定位--no-ff恰好能满足这些需求,而快进合并的 “简洁历史” 在团队场景中反而会成为短板

删除分支 branch -d

git branch -d dev # 只能在dev分支外删除dev分支

冲突

冲突:不同分支对同一文件的同一部分内容(或文件元信息)做出了互斥的修改,Git 的自动合并算法无法判断哪一个修改应被保留

同一文件的同一行 / 相邻行被修改同一文件的结构修改导致行号关联冲突同一文件的大范围重叠修改文件被重命名、权限被修改

在合并分支时可能产生冲突

请添加图片描述

git log --graph --abbrev-commit # 查看“时间表”

请添加图片描述

bug分支

在实际开发中,master是上线代码,如果现在上线代码有问题,那么就要在当前位置创建一个新分支用于解决bug(文章中将其这一分支命名为bug_fixed)。解决bug后完成测试再进行分支合并

情景:master主分支有问题,需要经过测试,最终将稳定的branch合并到master分支,但是目前项目又在开发新功能,要求解决bug后顺带新功能一起上线。

(可以先把线上版本回退到上一版本,然后修改后再调回新版本)

  • 我们在使用bug_fixed分支解决冲突时,发现dispatcher.hpp文件有问题,现在解决bug:开始修改dispatcher.hpp 的 bug。然后git checkout master,发现因为dev分支修改了工作区的内容,导致master、bug_fixed能看到dev修改的内容,怎么办?

    git checkout dev 
    git stash # 将工作区更新的内容存到refs/stash中。(这个refs/stash只负责被git追踪管理的文件,如果仅仅只是touch .txt,不会被保留到stash中)
    # 此时在dev分支看不到修改了,同时其他分支也看不到修改了
    
  • ok,解决了这一问题,现在我们解决了bug,开始merge——git merge bug_fixed

  • 别忘记了,我们在dev还有未开发完毕的东西。现在回到dev分支继续开发,第一步,将stash内容取出来——git stash pop

  • 可以通过git stash list查看哪里存了.你完成了dev分支的开发工作,现在要merge了,

  • 问题来了,刚刚master主分支有bug,你dev分支还是master修bug前开发的,如果直接merge,就要解决冲突,如果一行一行手动解决冲突就容易导致bug,然后还要自己再测试,很浪费效率。而且会污染master分支,那么怎么解决?

    在这里插入图片描述

  • 可以现在dev分支完成测试,再合并到master

  • 假如说,修完bug后,告诉你不需要开发新功能了,把dev分支删了吧。但是你已经对dev分支内容commit了,git会将commit内容保护起来,如果不merge,就不能git branch -d删除,所以git branch -D dev——完成强制删除分支功能

这里扩展一些stash指令

git stash save "this is a comment" # 可以给stash描述
git stash list # 查看当前暂存区有哪些内容
git stash show stash@{0} # 查看stash修改了哪些文件,-p参数相当于diff
git stash apply stash@{0} # 将指定的暂存区内容应用到当前目录,但不删除
git stash drop stash@{0} # 删除指定暂存区内容

远端仓库

github就是分布式版本控制系统。选择中央服务器(远程仓库)存储代码,主机可以选择上传或从远程仓库拉取代码,一起完成不同主机协同开发的操作。

查看远程仓库git remote -v

仓库名称

名字和项目内容相关即可。

模板文件

ReadMe

项目介绍

Issue

与管理者交流,比如你是仓库成员,你发现了bug,就可以把问题描述上传Issue,把Issue直接通过远端仓库交给管理者。管理者接收到可以选择是否审查、是否解决等操作

PullRequest

申请merge到主分支

建立一个仓库

设置好相关文件内容后,在github创建仓库,然后通过git clone同步到本地,这个clone,会自动将本地和远端分支建立联系

SSH和https
git remote -v # 查看远端仓库
git clone ... # 完成克隆操作
# ssh
# 查看~/.ssh是否有id_rsa.pub(存储公钥),没有的话需要创建公钥:
ssh -keygen -t rsa -C "邮箱" # 创建公钥私钥 
# 然后cv公钥到github ssh密钥处 你就可以通过ssh进行clone了
  • SSH:依赖 22 端口,部分企业防火墙、校园网或公共网络会封禁 22 端口,导致无法连接远程仓库。但是不用输密码了
  • HTTPS:使用 443 端口(与网页访问的端口相同),几乎所有网络都不会封禁,兼容性远优于 SSH,是网络受限环境下的首选。但是每次都要输密码

拉取和上传

git push origin master:master # 第一个表示本地分支,第二个表示远端分支。表示把本地master分支内容上传到远端master分支(如果本地和远端分支名字项目,可以不加:以及后边内容)
git pull origin master:master # 第一个表示远端分支,第二个表示本地分支。表示把远端master分支内容拉取到本地master分支,并完成merge操作(如果本地和远端分支名字项目,可以不加:以及后边内容)
.gitignore

忽略一些文件。echo "*.so" > .gitignore 在add时就会对*.so文件视而不见。如果有个b.so例外,echo "!b.so" >> .gitignore(也可以git add -f b.so强制添加,但不推荐)

查看为什么c.so文件被ignore
git check-ignore -v c.so

重命名 alias.

git config --global alias.lpa 'log --pretty=oneline --abbrev-commit'
git lpa # 等价于 git log --pretty=oneline --abbrev-commit

标签

场景:标签作为里程碑的意义,也可以方便快速定位到指定标签,代替commit id寻找版本

打标签

git tag v1.0 -m "first banben" # 给当前commit打标签
git tag v0.9 3ea30g2 # 给指定commit id 设置tag
# -a 可以让标签包含标签创建者(姓名 / 邮箱)、创建时间、标签说明、GPG 签名(可选)等丰富信息。
git tag -a v1.1 -m "修改部分bug" 

查看已有的标签

git tag # 查看已有tag
git show v1.1 # 查看tag信息

删除标签

git tag -d v0.9 # 删除指定tag

标签推送到远端

git push origin v1.0 # v1.0推送远端
git push origin --tags # 推送所有标签

从远端删除标签

git push origin :v1.0 # 从远端删除,:前表示本地,后表示远端

团队协作

场景:在dev分支下对file.txt文件添加aaa,然后在另一个用户的dev分支下对文件添加bbb,同步到远端仓库master分支(或者说:团队中另一个人需要你去帮助写代码)

  • 查看远端仓库分支——git branch -r

  • 查看本地和远端仓库分支内容——git branch -a

第一步:建立分支链接。本地和远程需要建立连接才能push——有两种方法连接本地和远端的分支

  • 如果希望在命令行上对远程仓库开启新分支(需要保证本地有相应分支)

    git push origin dev
    
  • 最好在远端仓库先创建好分支,然后本地创建分支与远端仓库完成同步工作:

git checkout -b dev origin/dev # 创建时就建立好连接
# 还有下面这一种方法
git branch --set-upstream-to=origin/dev dev # 将本地已有的分支与远端建立连接
git branch -vv # 查看链接情况

第二步:开发者1完成aaa的添加,然后push到远端

第三步:开发者2使用git pull ,pull完毕后可以自动将本地的dev分支与远端dev分支建立联系,并且同步dev消息(如果git pull时本地没有dev分支,不会自动生成dev分支,仍需要自己手动创建,不过创建完毕后,dev分支内容就是远端仓库内容了)

第四步:开发者2使用git push完成内容推送

第五步:完成分支合并,两种方法:

第一种(推荐):PR

由开发者在远端仓库上提交PR,申请分支合并,由管理员完成测试和审批后进行合并

第二种:命令行

开发者2先切换到master分支,然后对分支git pull,保证master最新。然后切换到dev分支,git merge master,然后解决冲突、测试bug,然后切换到master分支,git merge dev,完成合并,git push 完成代码上传

第六步:删除不需要的dev分支

开发过程

保持和远端仓库同步

同一个分支允许多人使用,可能已经有其他人提交了代码

获取远程仓库版本 git fetch

这个操作不会merge到本地仓库

远程仓库合并到本地仓库 git rebase origin/develop

这个合并操作会消除无用的merge commit

git rebase origin/develop 之所以能避免无用的 merge commit,是因为它通过重写提交历史、线性移植本地提交的方式同步代码,而非像 git merge 那样创建新的合并节点。但使用时需遵循协作规范,避免在公共分支上执行 rebase。

简化commit历史,使用squash合并commit

rebase不修改公共仓库中已存在的commit历史

git rebase -i HEAD-4 # 合并最近4次commit
git远程分支已经删除,但是本地还能看到
# 远端分支已经删除,本地使用git branch -r看到了不应该存在的东西
git remote show origin
git remote prune origin

或者

git fetch -p # (--prune缩写),更新本地仓库残留的分支(对于本地有的,远端没有的,不会删除)

git flow模型

环境隔离

开发有三种工作:plan\code\built

测试有test工作

运维有release\deploy\operate工作

环境隔离就是:开发有自己的开发环境,测试有自己的测试环境,运维负责把完整的代码部署到发布/线上环境

发布/线上环境分为预发布集群和生产集群,会在预发布集群测试一批用户后,再在生产集群大规模应用,有的公司可能没有预发布集群,或者有的公司还有个灰度测试。视公司而定。

分支介绍

master: 生产环境,只读、唯一,用于直接部署到线上,可以tag打标记、master分支直接部署到线上环境

feature: 本地开发分支,命名规则:feature/user_createtime_ablecomment。分别表示使用者、创建时间、功能描述,开发后讲内容放到develop分支即可

develop: 开发环境, 基于master分支创建的只读且唯一的分支,始终保持最新完成以及bug修复后的代码。可部署到开发环境对应集群(ps: 可根据需求判断feature直接合并在develop上还是在master上)

hotfix: 补丁分支,只要用于线上版本bug修复,线上版本有紧急问题是,基于mater分支创建hotfix分支,命名: hotfix/user_createtime_hotfixcomment。问题修复完毕后合并到master和develop分支并push。然后就可以删除了

release: 预发布分支、测试分支, 基于本次所有功能在feature开发完毕后合并到develop上,然后基于develop创建的分支。可以部署到测试或者预发布集群。命名:release/version_publishtime 如果测试出问题,回归develop分支看是否存在此问题,产品上线后可删除此分支

请添加图片描述

Logo

火山引擎开发者社区是火山引擎打造的AI技术生态平台,聚焦Agent与大模型开发,提供豆包系列模型(图像/视频/视觉)、智能分析与会话工具,并配套评测集、动手实验室及行业案例库。社区通过技术沙龙、挑战赛等活动促进开发者成长,新用户可领50万Tokens权益,助力构建智能应用。

更多推荐