Git¶
安装¶
- Windows:官网下载
Git for Windows
客户端安装即可 - Ubuntu/Debian:
apt install git
- CentOS/Fedora:
yum install git
- Mac:可以下载安装包安装,也可以用
brew install git
方式安装
Mac 中可以查看 Git 版本触发安装 Xcode CLT,CLT 默认自带 Git,此时用 brew 安装会提示已经存在,根据提示执行 brew link --overwrite git
覆盖
# 查看版本
git --version
# 查看帮助
git help
git xxx -h # 或 --help
配置¶
# 优先级及影响范围依次为
'
--local 对当前用户、当前仓库有效,默认(.git/config)
--global 对当前用户、所有仓库有效(~/.config/git/config)
--system 对所有用户、所有仓库有效,需要root权限(/etc/gitconfig)
'
# 查看配置
git config --list
git config --list --show-origin # 显示配置路径
git config --list --global
git config user.name
- 配置代码提交者信息
git config --global user.name "demo"
git config --global user.email "demo@test.com"
- 配置密钥
Git 服务器(比如GitLab)或者说远程仓库(比如GitHub)通常会支持两种传输协议:HTTPS 和 SSH
如果使用 SSH 协议传输则需要配置密钥进行认证
# 如果之前没生成过密钥,需要先生成
ssh-keygen
'
回车,会提示保存位置
再回车,如果已存在则会提示是否重新生成
然后会提示设置密码,可以为空直接回车
如果提示输入密钥类型,推荐选择ed25519,没提示一般默认会是rsa类型
'
ls ~/.ssh
'
authorized_keys2 id_dsa known_hosts
config id_dsa.pub
'
# ed类型的文件名为 id_ed25519.pub
# 查看公钥,将其配置到项目托管平台中
cat ~/.ssh/id_rsa.pub
远程仓库¶
git remote -v # 列出添加过的远程库
git remote show origin_name # 查看远程库详细信息
git remote rename old_name new_name # 修改远程库简写名
git remote remove demo # 删除已添加的远程库,remove可简写为rm
# 如果远程库修改了名称,可以修改url重新关联
git remote set-url origin new_url
获取仓库¶
git clone <url> [path_name] -o <origin_name> -b <branch>
'
url
https协议:https://github.com/ZuoRight/demo.git
ssh协议:git@github.com:ZuoRight/demo.git
path_name 默认同远程库名称
origin_name 默认为 origin
默认拷贝主分支,也可指定分支
'
git clone
其实是对以下命令的封装
# 创建新目录
mkdir demo
# 切换到新目录
cd demo
# 初始化,生成 .git 跟踪文件
git init
# 为指定的 url 添加一个远程库,默认名称 origin
git remote add origin_name url
# 获取远程库数据
git fetch origin_name
# 检出并创建一个同远程主分支相同的本地分支
git checkout -b main
fetch¶
将远程仓库中有但当前仓库没有的所有数据拉取下来,然后存储在本地仓库中
git fetch origin dev
# 新建本地dev分支并与远程dev分支关联
git checkout -b dev origin/dev
pull¶
# 从已跟踪服务器拉取并自动合并,等同于:git fetch + git merge
git pull [origin main]
'
不带参数,先尝试快进合并,如果不行再进行正常合并生成一个新的提交。
--ff-only 快进合并,只尝试快进合并,如果不行则终止当前合并操作。
--no-ff 普通合并,禁止快进合并,即无论是否能快进合并,最后都会进行正常合并生成一个新的提交。
--rebase 变基合并,先尝试快进合并,如果不行再进行变基合并。
'
push¶
将提交后的代码推到远程仓库
# 从本地仓库中,取出本地 dev 分支的所有最新提交,推送到名为 origin 的远程仓库中的 dev 分支(默认与本地分支同名)
git push origin_name dev
'
如果远程仓库中已有名为 dev 的分支,则会将变更合并到远程的 dev 分支中
如果没有冲突,远程分支将被更新到与本地分支相同的状态
如果远程仓库中没有名为 dev 的分支,则会创建一个新的 dev 分支,然后将变推送到远程的 dev 分支中
如果本地 dev 分支与远程 dev 分支的历史没有直接的线性关系(比如本地分支已经被重新基于其他提交),可能会遇到一个非快进(non-fast-forward)推送错误。
在这种情况下,可能需要使用 --force 或 --force-with-lease 选项进行强制推送,或者合并变更到你的本地分支再尝试推送
'
# 也可以提交到与远程库不同名的分支
git push origin_name 本地分支:指定远程分支
# 如果第一次推送一个分支到远程,或者希望设置追踪信息,可以使用 -u 或 --set-upstream 选项
# 推送代码的同时还会设置 dev 分支的上游(upstream)追踪信息,之后便可以使用 git pull 或 git push 而无需指定远程库和分支名
git push -u origin dev
# 提交后返回的一些信息
'
To xxx.git
1edee6b..fbff5bc main -> main
(oldref..newref fromref → toref)
'
# 删除远程分支(仅移除指针,一段时间后才会被垃圾回收,这期间可以恢复)
git push origin --delete dev
本地仓库¶
查看状态¶
git status
'
On branch main
当前分支
Your branch is up-to-date with "origin/main".
当前分支是最新的,没有落后远程分支
nothing to commit, working directory clean
工作区是干净的,没有文件需要提交
'
# 文件主要有以下状态
'
未跟踪 new file untracked
已跟踪
未修改 unmodified
已修改未暂存 modified unstage
已暂存准备提交 modified staged
'
查看修改¶
git diff # 查看未暂存的改动,即工作区和暂存区的比较
git diff --staged # 查看已暂存但未提交的改动,也可用--cached
git diff branch1 branch2 # 比较两个提交记录的差异
# 撤销修改
git checkout -- xxx
add¶
# 将未跟踪或已修改文件添加到暂存区,变为已跟踪已暂存状态
git add xx # 添加某个
git add . # 添加全部,也可用-A或--all参数
# 部分暂存
git add --patch
重命名¶
# 如果只是重命名文件而不修改其内容时可以这样做
git mv old_name new_name
commit¶
# 创建快照,将当前分支指针向前移动
git commit -m "init" # 不加-m会打开默认编辑器编辑
'
-a,可以不用先git add,直接提交
--ament 重新提交,可以覆盖上一次的提交
'
# 如果切换分支但开发到一半不想提交,可以先临时储存
git stash
查看历史¶
https://git-scm.com/book/en/v2/Git-Basics-Viewing-the-Commit-History
git log # 时间倒序列出所有提交记录
'
--patch/-p 显示每次提交所引入的差异
--graph 在日志旁以 ASCII 图形显示分支与合并历史
--pretty=oneline 每个提交记录放在一行显示
--pretty=format:"%h - %an, %ar : %s" 显示格式
'
分支¶
# 查看分支
git branch
'
-a 显示远程分支
-v 显示最后一次提交
--merged 已合并到当前分支的分支
--no-merged main 没有合并到当前分支的分支
-vv 查看各分支正在跟踪的上游分支
-u 或 --set-upstream-to 显示设置当前分支正在跟踪的上游分支,clone 或 checkout 时会自动设置
'
# 新建分支
git branch dev
# 删除分支,删除未合并的分支需要用-D强制删除
git branch -d dev1 dev2
git branch -m old_name new_name # 修改本地分支名称
git branch -M main # 修改本地主分支(改为main,与GitHub远程主分支保持一致)
- 切换分支 checkout
# 切换分支,就是改变指针指向,即检出
git checkout dev # 也可以用:git switch dev
# 新建并切换分支
git checkout -b dev
# 新建自远程xxx分支,并切换
git checkout -b test origin/xxx
git checkout --track origin/xxx # 简写
git checkout xxx # 如果本地没有但恰巧远程有唯一匹配的xxx分支,则等同于上面命令
标签¶
git tag # 列出标签
git tag -l "v1.8.5*" # 模糊匹配
git show tag v1.0 # 查看标签信息
git tag tmp1 # 打轻量标签
git tag -a v1.0 -m "version 1.0" # 打附注标签
git tag -a v1.2 9fceb02 # 给过去的某次提交打标签
git push origin v1.0 # 推送分支时不会带上标签,所以标签需要单独推送
git push origin --tags # 推送所有标签
git tag -d v0.5 # 删除本地标签
git push origin --delete v0.5 # 删除远程标签
合并¶
merge¶
将其它分支合并到当前分支,创建一个新的合并提交,如果没有冲突则可以快进合并
如果两个分支同时修改了同一处,合并时会产生冲突,此时冲突的文件会变为未追踪状态,文件中会用 `=======
上下分割标识出两个分支冲突的部分,需要手动解决后再次 add 到暂存区后提交。
# 将 dev 合并到 main
git checkout main
git merge dev
'
如果有冲突,可以选择终止合并
git merge --abort
也可以解决冲突后继续合并
git add 有冲突修改的文件
git commit -m "冲突修改后的说明"
'
rebase¶
变基合并,改变分支的分叉合并点
比如,基于本地 main 分支分叉出一个 dev 分支,然后远程 main 分支有新的更新(此时本地分支被称之为偏离分支),使用 rebase 合并更新,dev 分支的分叉点将变为基于最新的 main 分支
git checkout dev
git rebase origin/main # 直接基于远程仓库 rebase,当然也可以基于本地 main 分支,但需要先 pull
'
如果有冲突,可以取消合并
git rebase --abort
也可以解决冲突后继续合并
git add 有冲突修改的文件
解决冲突后继续合并
git rebase --continue
'
# 在 rebase 过程中,冲突可能在每个被重新应用的提交上发生,需要逐个解决,反复重复以上过程
Git 会找到 dev
和 origin/main
分支的共同祖先,取回所有分叉后的更新重放到 dev 分支,然后再拼接上 dev 分支的提交(已提交的哈希值将会被改变),使 dev 看起来就像基于最新的 main 分支检出然后提交的一样
通常建议只对尚未推送的本地修改执行变基操作,如果本地分支已经推送过远程,并且有人基于它开发,那么 rebase 后会导致其他人的本地仓库与远程仓库不一致
cherry-pick¶
只将某个分支上的指定提交合并到当前分支
比如在 dev 分支修改一个 bug,然后只想将这次修复提交先合并到 main 分支,而不合入其它提交
git checkout main
git cherry-pick commit_id
回滚¶
# 回滚到某个版本,注意,之后的版本都将消失
git reset [--参数] 版本 [指定文件]
git push --force # 回滚后要推向远程,否则会报错
# 参数
'
--soft 回到 commit 前的状态
--mixed 回到 add 前的状态,默认
--hard 回到工作区修改前状态,重置
'
# 版本,有3种形式
'
版本号:后七位即可
标签
HEAD指针
HEAD 当前版本
HEAD^ 上个版本,如果有多个父提交,则表示第1个父提交HEAD^1
HEAD^^ 上上版本
HEAD~ 上个版本,如果有多个父提交,则表示直接的父提交,表示其它父提交需要用HEAD^n
HEAD~100 上100个版本
'
比如不小心提交了隐私记录,可以reset到这次提交前的版本
注意,删除后通过 https://github.com/ZuoRight/demo/commit/hash_id 依然可以访问到
git log # 查看提交记录,找到包含隐私的那一次提交记录,copy它上一个版本的hash_id
git reset --hard hash_id
git push --force origin HEAD
取消暂存¶
git reset HEAD
# 变为未跟踪状态但不删除文件
git rm --cached xxx
# 删除已跟踪文件,如果已修改或已暂存,需要加 -f
git rm xxx
取消合并¶
- 如果合并尚未提交
git merge --abort
# 或
git reset --merge
- 如果合并已提交,但还没推送到远程
git reset --soft HEAD^ # 撤回到合并前状态,保留更改
git reset --hard HEAD^ # 完全撤回,丢弃更改
- 如果合并已提交,并且已推送到远程
git revert -m 1 HEAD # -m 1 表示保留第1个父提交的更改
完善仓库¶
touch README.md # 项目介绍文件
touch LICENSE # 授权声明文件
# 忽略规则文件
# 一个项目可以有多个,通常放在根目录一个,子目录也可以有额外的
touch .gitignore
# 各语言通用模版:https://github.com/github/gitignore
# 规则举例
'
# 表示注释
! 取反
? 匹配任意1个
* 匹配任意个字符
** 匹配任意中间目录
[abc] 匹配其中任意一个
[0-9] 匹配0到9
*.a 忽略所有.a文件
*.[oa] 忽略以.o或.a结尾的文件
*~ 忽略所有以~结尾的文件
!lib.a 跟踪所有的 lib.a,即便你在前面忽略了 .a 文件
/demo 只忽略当前目录下的 demo 文件,而不忽略 xxx/demo
demo/ 忽略任何目录下名为 demo 的文件夹
doc/*.txt 忽略 doc/notes.txt,但不忽略 doc/server/arch.txt
doc/**/*.pdf 忽略 doc/ 目录及其所有子目录下的 .pdf 文件
'
Git Flow¶
# 克隆远程仓库到本地master分支
git clone git@code.xxx.net:demo/test.git
'
参与没有代码推送权限的项目,比如开源项目,可以
1. 先 fork 副本到自己的远程仓库
2. 然后 clone 副本到本地,创建新分支进行修改提交
3. push 到自己的远程仓库,然后创建一个 PR(Pull Request) 给开源项目,在 GitLab 中叫做 MR(Merge Requests)
关联公用的远程库,假设命名为 upstream
git remote add upstream common.git
'
# 新建并切换到新分支开发
git checkout -b dev
git add . # 最好每个修改暂存一次,而不是都混在一起
git commit -m "改动说明"
# 获取远程分支是否有新的改动
git fetch origin master
# 如果获取到新的改动则可以变基合并
git rebase origin/master
# 也可以使用 merge 合并
'
git checkout master # 切回本地主分支
git pull origin master # 拉取最新代码,也可以 fetch + merge
git merge master # 将 master 合并到 dev
'
# 将 dev 分支推送到远程
git push origin dev
# 删除已被合并的分支
git branch -d dev