Git
介绍
Git 是分布式版本控制系统(Distributed Version Control System - DVCS)。官网:https://git-scm.com/docs
- Workspace:工作区
- Index / Stage:暂存区
- Repository:本地仓库
- Remote:远程仓库
配置单个 SSH-Key
全局配置用户信息
git config --global user.name "your_name"
git config --global user.email "your_email"
# 查看全局的用户名
git config --global user.name
# 查看全局的邮箱
git config --global user.email
生成 SSH 密钥
ssh-keygen -t rsa -C "youremail@email.com"
在 Mac 终端里查看密钥:vim ~/.ssh/id_rsa.pub
,然后将公共密钥添加进 github 或者 gitlab 里。或者直接复制密钥:
pbcopy < ~/.ssh/id_ras.pub
测试连接是否成功: ssh -T git@github.com
如果提示:Hi Ivanzgh! You've successfully authenticated, but GitHub does not provide shell access.
说明连接成功了
查看当前仓库配置信息
git config --local --list
查看全局配置信息
git config --global --list
配置多个 SSH-Key
如果想将个人的 GitHub 密钥和公司的密钥区分开来,就需要配置多个 SSH Key
1、删除本地的 SSH
这个步骤不是必需的,如果想全部重来就可以使用。打开终端输入cd ~/.ssh
,如果顺利进入到 .ssh
文件夹,使用命令:
cd ..
rm -r .ssh
2、清空默认的用户名和邮箱
查看已配置的 git 列表 git config --list
如果没有默认的用户名和邮箱就忽略,否则执行以下命令重置:
git config --global --unset user.name
git config --global --unset user.email
3、创建新的 SSH
打开终端输入cd ~/.ssh
,如果没有 .ssh
目录,先创建该目录
mkdir ~/.ssh
在 .ssh
目录下生成 ssh-key
,填入自己的邮箱地址
ssh-keygen -t rsa -C "youremail@email.com"
然后会要输入 SSH key 的名字,如id_rsa
、id_rsa_github
随你自定义,然后不要输入密码,一直回车就行。
然后配置其他的 SSH Key,如 gitlab,邮箱也可以变更
ssh-keygen -t rsa -f ~/.ssh/id_rsa_gitlab -C "youremail@email.com"
然后同上要输入名字,一路回车
4、将私钥添加到 ssh-agent 信任列表
ssh-add ~/.ssh/id_rsa
如果出现Identity added: /Users/zgh/.ssh/id_rsa (youremail@email.com)
,表示添加成功了。
继续添加另一个ssh-add ~/.ssh/id_rsa_gitlab
关于ssh-agent
信任列表:
# 查看信任列表
ssh-add -l
# 清空所有的ssh key
ssh-add -D
5、配置 config 文件
终端输入open ~/.ssh/
,看看有没有 config 文件,文件没有后缀,如果没有就新建一个。
新建 config 文件:
cd ~/.ssh
touch config
然后可以在终端修改vim config
,也可以直接打开 config 文件修改,Mac 下通过文本编辑打开。
cd ~/.ssh
vim config
内容如下:
Host github
HostName github.com
User git
PreferredAuthentications publickey
IdentityFile ~/.ssh/id_rsa
Host gitlab
HostName gitlab.com
User git
PreferredAuthentications publickey
IdentityFile ~/.ssh/id_rsa_gitlab
- 以
#
开头的是注释,会被忽略 Host
: 机器别名,用于标识特定的配置HostName
: 主机名,一般为 ip 或者主机域名IdentityFile
: 私钥证书文件位置,默认位置是~/.ssh/id_rsa
,如果采用默认证书,可不填此项User
:用于连接的用户名Port
: SSH 访问主机的端口号,默认是 22 端口
6、将公钥添加到远程仓库
将公钥复制到剪贴板,然后去添加到各个远程仓库
pbcopy < ~/.ssh/id_rsa.pub
# gitlab
# pbcopy < ~/.ssh/id_rsa_gitlab.pub
查看公钥内容:vim ~/.ssh/id_rsa.pub
7、测试连接
ssh -T git@github.com
如果 config 配置的用户名是其他的,如 zgh,那么在@
后面还需加上用户名,克隆的时候也需要加上
ssh -T git@zgh.github.com
然后在不同的仓库下设置局部的用户名和邮箱
git config user.name "yourname"
git config user.email "youremail"
概念
HEAD
- HEAD 是指向当前 commit 的引⽤,它具有唯⼀性,每个仓库中只有⼀个 HEAD。在每次提交时它都会⾃动向前移动到最新的 commit
- branch 是⼀类引⽤。HEAD 除了直接指向 commit,也可以通过指向某个 branch 来间接指向 commit。当 HEAD 指向⼀个 branch 时,commit 发⽣时,HEAD 会带着它所指向的 branch ⼀起移动
常用命令
克隆远程仓库
git clone 仓库地址
rebase
git merge 和 git rebase 都是用于分支合并,关键在 commit 记录的处理上不同:
- git merge 会新建一个新的 commit 对象,然后两个分支以前的 commit 记录都指向这个新 commit 记录。这种方法会保留之前每个分支的 commit 历史。
- git rebase 会先找到两个分支的第一个共同的 commit 祖先记录,然后将提取当前分支这之后的所有 commit 记录,然后将这个 commit 记录添加到目标分支的最新提交后面。经过这个合并后,两个分支合并后的 commit 记录就变为了线性的记录了。
总之:
- git merge 会产生无关的提交记录
- git rebase 会让历史记录干净整洁,不要在公共分支上使用
多个 commit 合并提交
假设你写完了一个 A 功能,执行git add .
、git commit
,然后发现还要改动一下,如果继续 add、commit,那么在 push 的时候会有 2 条提交记录,其实你只是完成了一个功能,保留一条提交信息才是简洁明了的。这时就需要将第一次 commit 撤销,回到暂存区,然后再 commit 提交,就只有一条记录了
修复最新提交的错误
在提交时,如果加上 --amend
参数,则不会在当前 commit 上增加 commit,⽽是会把当前 commit ⾥的内容和暂存区⾥的内容合并起来后创建⼀个新的 commit,⽤这个新的 commit 把当前 commit 替换掉,对最新⼀条 commit 进⾏修正
git commit --amend
HEAD
描述 | |
---|---|
HEAD | 当前版本 |
HEAD^ | 上一个版本 |
HEAD^^ | 上上一个版本 |
HEAD^^^ | 上上上一个版本 |
HEAD~n | 回撤 n 个版本,这种也是更加方便的 |
如:
# 切换到上一个版本
git checkout HEAD^
# 切换到上上上个版本
git checkout HEAD~3
撤销最新的提交
git reset [--soft | --mixed | --hard] [HEAD]
git reset --hard ⽬标commit
git reset --hard HEAD^
stash 临时存放⼯作区的改动
stash 指令可以把⼯作区的内容全部放在本地的⼀个独⽴的地⽅,它不会被提交和删除。
假设你当前正在开发中,突然需要优先干其他工作,又不想 add 和 commit,这时就可以将当前内容放入临时区,等其他工作干完了,再切换回你的分支,将临时区的内容取出来,就可以继续之前的工作了。
# 保存当前工作区的修改
git stash
# 保存当前工作区的修改,可以省略 push 参数
git stash push
# 保存当前工作区的修改,并添加说明信息
git stash push -m 'message'
# 已废弃,用于添加说明信息
git stash save "message"
# 没有被 track 的⽂件,即从来没有被 add 的⽂件不会被 stash
# 可以加上 -u 参数,它是 --includeuntracked 的简写
git stash -u
# 查看储存区所有提交列表
git stash list
# 应用最新 的stash,并将其从stash列表中删除
# git stash push 的逆操作
git stash pop
# 应用最新的stash,并保留stash的副本
git stash apply
# 如果有多个stash,想要应用特定的stash,其中n是stash的索引号,下标从0开始
git stash apply stash@{n}
# 从存储条目列表中删除单个存储条目
git stash drop stash@{n}
# 清空所有的stash
git stash clear
常用的命令:
# 放进去
git stash
# 放进去,并添加说明信息
git stash push -m 'message'
# 取出来,并从列表中删除
git stash pop
# 如果有多个,要取指定的
git stash pop stash@{n}
# 查看列表
git stash list
暂存区
# 添加单个文件到暂存区
git add 文件名
# 将当前目录下的所有文件都添加到暂存区
git add .
# 将当前仓库的所有文件都添加到暂存区
git add -A
# 从暂存区撤销文件,工作区的代码还在
git rm --cached 文件名
提交到本地仓库
# -m 后表示提交信息
git commit -m 'xx'
删除本地仓库的文件
# 删除单个文件
git rm 文件名
# 删除目录
git rm -r 目录名
拉取远程仓库
# 如果当前分支和远程分支已经建立了联系
git pull
# 拉取指定远端分支合并到本地当前分支
git pull origin 分支名
git pull
命令是 git fetch
和 git merge
两个操作的组合。
pull 的内部操作其实是把远程仓库取到本地后(使⽤的是 fetch),再⽤⼀次 merge 来把远端仓库的新 commits 合并到本地。
提交到远程仓库
git push
# 初次提交,需要和远程仓库先建立联系
git push --set-upstream origin 分支名
查看仓库当前状态
git status
查看历史记录
git log
# 查看详细改动,-p 是 --patch的缩写
git log -p
# 查看大致改动
git log --stat
查看 commit
# 看当前的commit
git show
# 看任意一个commit
# 在 show 后⾯加上这个 commit 的引⽤(branch 或 HEAD 标记)或它的 SHA-1 码
git show 4fc58ba6808329d98146be8543aa14112c632213
# 看指定commit的指定文件
# 在 commit 的引⽤或 SHA-1 后输⼊⽂件名
git show 4fc58ba6808329d98146be8543aa14112c632213 test.txt
查看未提交的内容
# 查看⼯作区和暂存区的区别
git diff
# 查看暂存区和上⼀条 commit 的区别
git diff --staged(或 --cached)
# 查看⼯作区和上⼀条 commit 的区别
git diff HEAD
- 第一条命令表示:如果你现在把所有⽂件都 add,你会向暂存区中增加哪些内容
- 第二条命令表示:如果你输⼊ git commit,你将会提交什么
- 第三条命令表示:如果你把所有⽂件都 add, 然后 git commit,你将会提交什么。是上⾯两条命令的内容相加
查看 origin 的详细信息
git remote show origin
查看本地关联的仓库地址
git remote -v
仓库备份
# 添加备份仓库
git remote set-url --add origin http://xxx.git
分支
新建分支
git branch 分支名称
切换分支,并更新工作区
git checkout 分支名称
新建分支,并切换到该分支
等同于以上两条命令
git checkout -b 分支名称
基于远程仓库创建新分支
# 基于远程仓库创建新分支
git branch branch_name remote_name/branch
# 基于远程仓库创建新分支并且切换到新分支
git checkout -b branch_name remote_name/branch
如基于远程 develop 分支创建开发分支feture-test:git checkout -b feture-test origin/develop
,origin 是远程仓库的别名
这样就可以不用创建本地的 develop 分支
- 在本地创 建 develop 分支,基于它创建开发分支,每次提交前拉取最新的 develop 分支,然后合并进开发分支,最后提交
- 基于远程分支创建新分支,本地不用维护 develop 分支,每次提交前先拉取最新的代码,然后提交。这里执行
git pull
就是拉取远程 develop 分支的代码
git add .
git commit -m '提交信息'
git pull
git push
查看分支
# 查看本地分支
git branch
# 查看远程分支
git branch -r
# 查看本地远程所有分支
git branch -a
# 查看本地分支所关联的远程分支
git branch -vv
合并分支
比如你的代码提交之前需要合并最新的 develop 分支,则要做如下操作:
- 切到 develop 分支,git pull 拉一下最新代码
- 切回开发分支,执行
git merge develop
合并一下 develop 代码
git merge 被合并的分支名称
## 撤销合并到执行合并以前的状态
git merge --abort
## 如果合并后的提交还停留在本地Git库,没有被推送到远程
git reset --hard HEAD
删除分支
# -d 表示delete,用于已经合并过的分支
git branch -d 分支名称
# -D 用于强制删除,不管是否合并过
git branch -D 分支名称
分支重命名
git branch -m 旧分支名称 新分支名称
同步本地的远程分支
删除远程已经不存在但本地还存在的远程分支
git remote prune origin
git remote update origin --prune
本地分支关联远程分支
如果远程新建了一个分支,本地没有该分支,那么可以使用该命令在本地新建一个分支名叫 dev ,会自动跟踪远程的同名分支 dev
git checkout --track origin/dev
首次推送新分支到远程
git push --set-upstream origin 分支名称
tag 标签
https://git-scm.com/docs/git-tag
标签是跟 commit 挂钩的,是对某次历史提交的引用,用来给发布版本打标记
创建 tag
# 创建tag,打在最近的一次 commit 记录上
git tag v1.0.0
# 给历史版本添加tag,后接commit ID
# 这里id可以取前7位表示,先执行 git log --pretty=oneline --abbrev-commit 可以看到
git tag v1.0.1 b3c214115924f9de069aa81d866143e52f4b5348
# 创建有备注的tag
git tag -a v1.0.0 -m '发布v1.0.0版本'
# 给历史版本创建有备注的tag
git tag -a v1.0.0 b3c214115924f9de069aa81d866143e52f4b5348 -m '历史版本带备注'
查看 tag
# 查看所有tag
git tag
# 使用通配符过滤tag
git tag -l "v1.1*"
# 查看某个tag的详细信息
git show v1.0.0
发布 tag
通常的 git push 不会将本地标签推送到远程,需要进行显式的操作
# 推送单个tag
git push origin v1.0.0
# 推送本地所有tag
git push origin --tags
删除 tag
# 删除本地tag
git tag -d v1.0.1
# 删除远程tag,有两种方式
git push origin :refs/tags/v1.0.1
git push origin --delete v1.0.1
检出标签
如果你做了某些更改然后提交它们,标签不会发生变化, 但你的新提交将不属于任何分支,并且将无法访问,除非通过确切的提交哈希才能访问,通常需要创建一个新分支
git checkout v1.0.0
# 推荐
git checkout -b new-branch v1.0.0
cherry-pick:把选中的 commits ⼀个个合并进来
cherry-pick 是⼀种特殊的合并操作,使⽤它可以点选⼀批 commits,按序合并
https://git-scm.com/docs/git-cherry-pick
关联远程仓库
1、在远程创建一个新的仓库,克隆到本地后推送
git clone git@github.com:Ivanzgh/elasticsearch.git
cd report_web
touch README.md
git add README.md
git commit -m "add README"
git push -u origin main
2、如果存在本地项目,想将其推送到 github 上,要先和远程仓库关联,然后推送
# 地址换成自己的,这里的 origin 可以自定义名称,但是一般不会更改
git remote add origin git@github.com:Ivanzgh/elasticsearch.git
git branch -M main
git push -u origin main
3、推送一个已经存在的文件夹
cd existing_folder
git init
git add .
git commit -m "Initial commit"
git branch -M main
git remote add origin git@github.com:Ivanzgh/elasticsearch.git
git push -u origin main
4、推送一个已经存在的 git 仓库
cd existing_repo
git remote rename origin old-origin
git remote add origin git@github.com:Ivanzgh/elasticsearch.git
git push -u origin --all
git push -u origin --tags
提交规范
格式:<type>(<scope>): <subject>
常用的 type 值
- feat: 新功能
- fix: 修复 bug
- docs: 仅仅修改了文档,比如 README 等等
- style: 仅仅修改了空格、格式缩进、不改变代码逻辑
- refactor: 代码重构,没有加新功能或者修复 bug
- perf: 性能优化,比如提升性能、体验
- test: 测试用例,包括单元测试、集成测试等
- build: 改变了 build 工具 如 grunt 换成了 npm
- chore: 改变构建流程、或者增加依赖库、工具等
- revert: 撤销上一次的 commit
scope 用来说明此次修改的影响范围
- all: 表示影响面大 ,如修改了网络框架,会对整个程序产生影响
- location: 表示影响小,某个小小的功能
- module: 表示会影响某个模块,如登录模块、首页模块等
subject 用来简要描述本次改动
示例: feat(all): project init
、docs(location): edit README
关于 .git 目录
# 查看 .git 目录大小
du -sh .git
# 查看当前目录大小
du -h
随着项目迭代,项目体积越来越大。发现是 .git
文件占的存储空间太大了。下面是暴力的方式,适合自己的项目、不需要保留 git 提交记录的情况。
- 在本地删除
.git
目录 - 执行下面的命令,重新初始化项目
- 根据仓库的主分支是 main 还是 master,调整 push 命令
git init
git add .
git commit -m "Initial commit"
git remote add origin git仓库地址
git push -u origin main -f
Gitflow 工作流
Gitflow 工作流(Gitflow Workflow)是目前最流行的 git 团队协作模式
- master/main: 主分支,正式环境部署使用,唯一一个正式对外发布的分支,通常还要加上相应版本号的 tag
- develop: 集成分支,专门用来集成开发完成的各种功能的,保存了开发的最新代码,由 main 分支创建而来
- feature: 功能分支,由 develop 分支创建而来,开发完成后被合并进 develop 分支
- release: 预发布分支,为发布新的产品版本而设计的分支
- 当 develop 分支已经有了本次上线的所有代码,并且已通过全部测试的时候,就可以从 develop 分支创建 release 分支了
- release 分支创建以后,就不允许再有新的功能特性被加入到这个分支了,只有 bug 修复或者文档编辑之类的工作才允许进入该分支
- 有了 release 分支就可以让 develop 分支空闲出来以接受新的 feature 分支上的代码提交,进入新的软件开发迭代周期
- 生产上线时将 release 代码合并到 main 分支,并给 main 分支打上带有版本信息的 tag
- 同时 release 分支 也会被合并到 develop 分支
- hotfix: 线上 bug 紧急修复分支,从 main 分支创建而来,修改完成后合并到 main 分支和 develop 分支,以及当前的 release 分支
比如现在需要开发登录功能,首先从 develop 分支拉取最新代码,然后执行git checkout -b feat-login
,表示新建了feat-login
分支,并切换到了这个分支的工作区。代码提交后发起合并申请,期望合并到 develop 分支,仓库管理者同意合并后将删除这个分支。
如果是修复测试环境的 bug,例如fix-login
分支,那么需要合并到对应的 release 分支。release 分支可以有多个版本,如 release1.0.0、release2.0.1 等。
如何 fork 仓库
1、Fork 项目
在 GitHub 上找到你想研究的项目,点击右上角的"Fork"按钮,将项目复制到你自己的账户下。
2、克隆到本地
使用 git clone
命令将你 fork 的项目克隆到本地计算机,注意使用的是你的仓库地址而不是原始仓库地址。
3、设置上游仓库
进入本地仓库后,添加原始项目作为上游仓库(upstream),以便随时拉取最新更新。
git remote add upstream 原始项目地址
然后使用git remote -v
查看远程仓库地址
4、保持同步
方式一、如果没创建新分支,直接在本地主分支上修改的,假设本地主分支是 main
# 直接使用该条命令,表示拉取、合并远程仓库的main分支
git pull upstream main
如果远程仓库的主分支是 master,那么要使用 git pull upstream master
命令
下面的方式也可以:
# 将会从原始仓库的远程地址获取最新的变更,但不会将它们合并到你的本地分支中
git fetch upstream
# 将原始仓库的最新变更合并到本地的 mian 分支中
git merge upstream/main
如果原始仓库的主分支不是 main,而是 master,那么需要修改 upstream/main
为 upstream/master
方式二、如果创建了新分支,在新分支上进行更改,假设新分支是 dev
# 1、切换到main分支,拉取、合并
git pull upstream main
# 2、切换到dev分支,合并
git merge main
下面这种方式能让 dev 分支是最新的,但是 main 分支不是最新的。
# 1、切换到main分支,拉取
git fetch upstream
# 2、切换到dev分支,合并
git merge upstream/main
- 在主分支修改:执行
git pull upstream main
- 在新分支修改:
- 在 main 分支执行
git pull upstream main
- 在 dev 分支执行
git merge main
- 在 main 分支执行
5、提交和推送更改
在进行了自己的修改并同步了上游更新后,将本地更改添加到暂存区,提交,并推送到你自己的 GitHub 仓库。
git add .
git commit -m "描述你所做的更改"
git push