Skip to content

安装与配置

文档 以 mac 为例,使用 brew 进行安装。

bash
brew install git
# 验证版本 git version 2.39.5 (Apple Git-154)
git version

IMPORTANT

核心概念

工作区 (Working Directory):你电脑上直接看到的文件和目录。

暂存区 (Staging Area):像一个“购物车”,你把你想要下次提交的改动“放进去”。

仓库 (Repository):最终存储你所有版本记录的地方(本地仓库在 .git 隐藏文件夹里)。

安装完成之后对个人信息进行配置,这些信息最终会在仓库中体现出哪些人修改了这些信息。

bash
# 如果不使用 --global 仅对当前工作区生效。
git config --global user.name "xsq"
git config --global user.email "xsq.@example.com"

初始化

当你想要在本地创建一个 git 仓库时,只需要执行 git init 即可。该指令会在本地创建一个 .git 的目录。

但是一般不会这么用的,就算你是新项目或者接手别人的项目github 新建项目为例。提供了两种方式,秩序按照要求执行即可完成关联。

当然现有的代码托管仓库创建新项目时都会有这样的初始页。按照要求执行即可。

alt text

SSH 配置

在项目的最开始,先做的事情是将代码拉至本地,仓库都会提供两种地址,都能进行拉取。使用的指令如下

bash
# 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 指令

bash
# 该指令的返回,会将生成的秘钥位置告知与你
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,比如家里的电脑和公司的电脑。

alt text

至此你就可以顺畅的 clone 项目,并且安装远端新仓库的提示,直接将这个空项目 clone 到本地了。

远程仓库配置

细致的你一定发现了,在 github 给出的指令示例中,有一行指令 git remote add origin http://xxx.git 这样的指令。

这条指令的意思是将你的工作区和远程仓库做绑定。除了 add 也有一些其他操作。

bash
# 添加远程仓库
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 的修复后,你大概率会用到以下指令

bash
# 查看当前工作区的文件状态
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 为例

alt text

分支管理

在日常的开发过程中,分支主要的目的去区分出环境,以及多人协作时的隔离作用。

bash
# 查看本地所有分支
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 分支去执行命令。

bash
# 当前分支合并 test 分支
git merge test

# 如果分支冲突,想关闭这次合并使用 --abort
git merge --abort
# 如果分支冲突,解决完冲突应该继续使用 --continue
git merge --continue

常规流程来说,如果没有冲突。则会出现下图情况,进入 vim 模式,使用 :wq 保存退出即可,即生成一条 merge 记录。

alt text

git log 查看内容如下

alt text

冲突合并

合并冲突时,命令行一般也会指出冲突的地方有几处,如下图。

alt text

此时如果你的语言中不是 >>> 使用频率很高,可以考虑使用 IDE 的全局搜索,找到所有的冲突,挨个解决,自行选择这些冲突代码是否使用。如下图

alt text

当处理完后,再次执行

bash
# 将改动过得代码,提交到暂存区
git add .
# 继续合并
git merge --continue

如果 commit 次数较多冲突较多,可能重复以上步骤的次数就会变多。直至最后和没有冲突时一致,生成新的记录即合并成功。可以提交到远端仓库。

rebase 合并

rebasecommit 的最大区别就是,rebase 不会生成额外的 commit 信息。

bash
# 合并 test 分支到当前分支
git rebase test

# 冲突合并时,取消本次合并
git rebase --abort
# 冲突合并时,解决冲突后
git rebase --continue

# 进入交互模式 可以在此模式下压缩 commit、修改 commit message
git rebase -i

合并前 test 及 main 分支 commit 如下 alt textalt text

此时在 main 分支执行 git rebase test,没冲突的情况下直接提示 Successfully rebased and updated refs/heads/main.

再次查看 log 内容如下

alt text

冲突合并

当合并冲突时,警告信息提示的很明确你应当如何操作。

alt text

同样的,你也能在 IDE 中清楚的看到冲突的地方在哪里,自行选择如何合并这些代码。

alt text

如果 commit 次数比较多,合并的操作一样会存在多次。重复步骤即可

bash
# 将合并后的代码添加到暂存区
git add .

# 继续合并操作
git rebase --continue

合并提交、批量修改 commit 信息

bash
# 将最近几次的提交作为交互式窗口以 vim 的方式进行编辑
# n 可以是任意数字
git rebase -i HEAD~3

alt text

bash
# 常用的有
# 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 管理

个人理解标签一般在管理版本时比较有用。版本号的制定也是存在绝对的讲究。推荐参考

bash
# 列出所有标签
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 合并到指定分支

在实际开发中,某些情况下我清楚的知道,一旦执行 mergerebase 注定要处理一大堆冲突,而我只是改个小问题,可能验证一下就发布了。

此时可以使用 git cherry-pick commit-id 将某个分支指定的 commit 合并到当前分支。

如何回滚版本

使用 git reset --hard commit-id 可以将代码回滚到指定的 commit

在 dev 分支写代码,优雅修改 test 分支 bug

一般情况下都是这个版本提测了,下个版本又在开发中,此时有了 bug 我还要去测试分支修,那我的开发分支就写了一点代码,怎么办呢?要不要提交一次 commit

不用的兄弟,使用 git stash 来解决你的问题。使用 stash 将代码保存起来之后,可以任意的切换分支,对你的代码没有任何影响。

bash
# 将代码暂时保存
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 提交,对于回退版本存在很大的障碍。