安装与配置
文档 以 mac 为例,使用 brew
进行安装。
brew install git
# 验证版本 git version 2.39.5 (Apple Git-154)
git version
IMPORTANT
核心概念
工作区 (Working Directory):你电脑上直接看到的文件和目录。
暂存区 (Staging Area):像一个“购物车”,你把你想要下次提交的改动“放进去”。
仓库 (Repository):最终存储你所有版本记录的地方(本地仓库在 .git 隐藏文件夹里)。
安装完成之后对个人信息进行配置,这些信息最终会在仓库中体现出哪些人修改了这些信息。
# 如果不使用 --global 仅对当前工作区生效。
git config --global user.name "xsq"
git config --global user.email "xsq.@example.com"
初始化
当你想要在本地创建一个 git
仓库时,只需要执行 git init
即可。该指令会在本地创建一个 .git
的目录。
但是一般不会这么用的,就算你是新项目或者接手别人的项目 以 github
新建项目为例。提供了两种方式,秩序按照要求执行即可完成关联。
当然现有的代码托管仓库创建新项目时都会有这样的初始页。按照要求执行即可。
SSH 配置
在项目的最开始,先做的事情是将代码拉至本地,仓库都会提供两种地址,都能进行拉取。使用的指令如下
# HTTP 地址
git clone https://github.com/DoubleXm/study-git.git
# SSH 地址
git clone git@github.com:DoubleXm/study-git.git
远程仓库都是属于某个组织,或者某个人的,并不是谁都可以 clone
的,你应当具有权限;如果你能确保你有用该权限,就应当生成 SSH key
与远程仓库用户建立关联。
这是本机与远程仓库用户的关联
使用 ssh-keygen
无脑下一步生成 SSH
公钥。将生成的 .pub
文件配置到远端仓库,即可执行 clone
指令
# 该指令的返回,会将生成的秘钥位置告知与你
ssh-keygen
# Generating public/private ed25519 key pair.
# Enter file in which to save the key (/Users/a1234/.ssh/id_ed25519):
# Enter passphrase for "/Users/a1234/.ssh/id_ed25519" (empty for no passphrase):
# Enter same passphrase again:
# Your identification has been saved in /Users/a1234/.ssh/id_ed25519
# Your public key has been saved in /Users/a1234/.ssh/id_ed25519.pub
# The key fingerprint is:
# SHA256:dz6pGwZKEjn4srgmz/aDmsvYfZR3WDNXEUTdaw4S+7E a1234@1234deMacBook-Pro.local
# The key's randomart image is:
# +--[ED25519 256]--+
# | o=+.|
# | . . . . o|
# | . + o. .|
# | . o +o.o o |
# | . o ..So.++ * |
# | . o oo.oo.o E . |
# |. .. ... .o + |
# |+*o.. . . o . |
# |O*+.oo o. |
# +----[SHA256]-----+
# 将内容复制到远端仓库的 ssh 中,以 github 为例,如下图
cat /Users/a1234/.ssh/id_ed25519.pub
注意,这不是仓库的设置,而是对于用户的设置,一个用户可以拥有任意个仓库;
也可以为用户添加无数个 key
,比如家里的电脑和公司的电脑。
至此你就可以顺畅的 clone
项目,并且安装远端新仓库的提示,直接将这个空项目 clone
到本地了。
远程仓库配置
细致的你一定发现了,在 github
给出的指令示例中,有一行指令 git remote add origin http://xxx.git
这样的指令。
这条指令的意思是将你的工作区和远程仓库做绑定。除了 add
也有一些其他操作。
# 添加远程仓库
git remote add origin http://xxx.git
# 查看远程仓库
git remote get-url origin
# 修改远程仓库 -> 将 http 的地址修改为 ssh 地址
git remote set-url origin git@github.com:DoubleXm/study-git.git
# 删除远程仓库
git remote remove origin
拉取、暂存、提交、状态、日志
将代码拉至本地后,就可以开发内容了,当完成一个功能的开发或者一个 bug
的修复后,你大概率会用到以下指令
# 查看当前工作区的文件状态
git status
# 将工作去文件提交到暂存区
# 将当前目录下的所有文件提交到暂存区
git add .
# 添加某一文件
git add README.md
# 将暂存区代码提交 -m 后跟提交信息
git commit -m "登录注册功能"
# 修改最后一次的提交信息,会使命令行进行 vim 交互窗口,修改后 wq 保存即可
git commit --amend
# 查看 commit 日志
git log
# 提交到远端
# origin 是远端地址 main 是分支名。当前分支提交到远端的当前分支,不可以跨分支
git push origin main
# --force 强推 如果你能保证推上去不会影响代码,可以使用
git push --force origin main
# 远程代码拉取到本地
git pull orgin main
当执行 git add
之后再使用 git status
一般的指令窗口都能很清晰的标注出来区别。以 oh-my-zshell
为例
分支管理
在日常的开发过程中,分支主要的目的去区分出环境,以及多人协作时的隔离作用。
# 查看本地所有分支
git branch
# -D 删除本地分支
git branch -D test
# 同步远程仓库最新信息,更新本地的远程追踪分支
git fetch
# 切换分支
git checkout main
# 创建一个新分支并切换到此分支,如果有未提交的内容,也会一并同步到新的分支
git checkout -b feat/dev
# 丢弃没有提交到暂存区的修改
# . 标识当前工作区 可以是指定的名称
git checkout -- .
merge 合并
CAUTION
多人协同以及多分支修改同一功能的过程中,避免不了出现代码冲突的场景,合并代码是日常开发过程中经常遇到的问题。
无论你是 merge
还是 rebase
首先要明确是谁合并谁的关系。比如你想把 dev
分支的代码 合并到 test
,就应当在 test
分支去执行命令。
# 当前分支合并 test 分支
git merge test
# 如果分支冲突,想关闭这次合并使用 --abort
git merge --abort
# 如果分支冲突,解决完冲突应该继续使用 --continue
git merge --continue
常规流程来说,如果没有冲突。则会出现下图情况,进入 vim
模式,使用 :wq
保存退出即可,即生成一条 merge
记录。
git log
查看内容如下
冲突合并
合并冲突时,命令行一般也会指出冲突的地方有几处,如下图。
此时如果你的语言中不是 >>>
使用频率很高,可以考虑使用 IDE
的全局搜索,找到所有的冲突,挨个解决,自行选择这些冲突代码是否使用。如下图
当处理完后,再次执行
# 将改动过得代码,提交到暂存区
git add .
# 继续合并
git merge --continue
如果 commit
次数较多冲突较多,可能重复以上步骤的次数就会变多。直至最后和没有冲突时一致,生成新的记录即合并成功。可以提交到远端仓库。
rebase 合并
rebase
和 commit
的最大区别就是,rebase
不会生成额外的 commit
信息。
# 合并 test 分支到当前分支
git rebase test
# 冲突合并时,取消本次合并
git rebase --abort
# 冲突合并时,解决冲突后
git rebase --continue
# 进入交互模式 可以在此模式下压缩 commit、修改 commit message
git rebase -i
合并前 test 及 main 分支 commit 如下
此时在 main
分支执行 git rebase test
,没冲突的情况下直接提示 Successfully rebased and updated refs/heads/main.
再次查看 log
内容如下
冲突合并
当合并冲突时,警告信息提示的很明确你应当如何操作。
同样的,你也能在 IDE
中清楚的看到冲突的地方在哪里,自行选择如何合并这些代码。
如果 commit 次数比较多,合并的操作一样会存在多次。重复步骤即可
# 将合并后的代码添加到暂存区
git add .
# 继续合并操作
git rebase --continue
合并提交、批量修改 commit 信息
# 将最近几次的提交作为交互式窗口以 vim 的方式进行编辑
# n 可以是任意数字
git rebase -i HEAD~3
# 常用的有
# p、pick 保留的 commit
# e、edit 要编辑的 commit
# s、squash 压缩的 commit
# 比如将三条 commit 压缩成一条,并且把第一条的 commit 信息进行修改
# 第一条 commit 修改为 edit c1a9ac7 feat: latest commit message
# 第二条 commit 修改为 squash ea2c494 feat: import requests
# 第三条 commit 修改为 squash ad5f895 feat: 变更内容
# 执行完成之后会进入交互模式,再次按照提示执行指令即可完成 commit 压缩及重命名操作。
# 一般情况下在 GUI 环境下去做这些操作。交互式命令还是比较麻烦的
tag 管理
个人理解标签一般在管理版本时比较有用。版本号的制定也是存在绝对的讲究。推荐参考
# 列出所有标签
git tag
# 创建标签
git tag v1.0.0
# 创建带有详细信息的标签
git tag -a v1.0.1 -m "这是 1.0 的版本"
# 查看标签的详细信息
git show v1.0.1
# 推送某一个标签到远程,分支和版本的顺序可以尝试切换,我也忘记了
git push orgin main v1.0.0
# 推送所有标签到远程
git push origin --tags
# 删除标签
git tag -d v1.0.1
# 删除远程标签
git push origin main --delete v1.0.1
项目实践
commit message 应该怎么写
应当遵循以下规范,比如增加登录注册功能完成的指令加内容应该是
git commit -m "feat: 登录注册接口"
feat:新功能(feature)
fix:修补bug
docs:文档(documentation)
style: 格式(不影响代码运行的变动)
refactor:重构(即不是新增功能,也不是修改bug的代码变动)
test:增加测试
chore:构建过程或辅助工具的变动
代码 pull 不下来,一堆黄色警告~~~
有一种情况是本地的代码和远端的代码存在了冲突,导致你在执行 git pull origin
的时候,出现一堆黄色警告,导致代码无法成功拉取。
只想将某一个 commit 合并到指定分支
在实际开发中,某些情况下我清楚的知道,一旦执行 merge
和 rebase
注定要处理一大堆冲突,而我只是改个小问题,可能验证一下就发布了。
此时可以使用 git cherry-pick commit-id
将某个分支指定的 commit
合并到当前分支。
如何回滚版本
使用 git reset --hard commit-id
可以将代码回滚到指定的 commit
在 dev 分支写代码,优雅修改 test 分支 bug
一般情况下都是这个版本提测了,下个版本又在开发中,此时有了 bug
我还要去测试分支修,那我的开发分支就写了一点代码,怎么办呢?要不要提交一次 commit
?
不用的兄弟,使用 git stash
来解决你的问题。使用 stash
将代码保存起来之后,可以任意的切换分支,对你的代码没有任何影响。
# 将代码暂时保存
git stash
# 查看暂时保存的列表
git stash list
# 返回示例
# stash@{0}: WIP on test: 657d953 add code 1
# stash@{1}: WIP on test: 657d953 add code 1
# 使用某一个 stash 像数组下标一样
git stash apply 0
# 删除某一个 stash
git stash drop 0
# 清空所有的 stash
git stash clear
你心目中完整的工作流是什么?
# 迭代开始
main ----------------------------------------------------------→
↓(每人检出)
dev-A ----┐
↓(功能完成)
dev-B ----┼--------┐
↓ ↓
dev-C ----┼--------┼--------┐
↓ ↓ ↓
# 提测节点 (fix bug 可以从 test 新开分支,也可以直接在开发分支修改后 merge 到 test)
test <------┼--------┼--------┘
↑merge ↑merge ↑merge
# 回归通过
test ------------------------------------------→(稳定)
↓(rebase & squash)
main ---------------------------------------------------→
↑最终仅保留一条提交:feat: 登录注册功能 & 文章预览功能
# 清理战场
test, dev-* 分支被删除
# 下一次迭代
main ----------------------------------------------------------→
↓(重新检出新的 test & dev-*)
个人认为在开发的过程中,没有必要保证 commit
的干净,就算使用 merge
污染也没有问题。只要保证最终到 main
分支的 commit
是干净的即可。
当然上面的工作流会让你错过很多重要的 commit
提交,对于回退版本存在很大的障碍。