git简介
Git为分散性版本管理系统,为版本管理而设计的。
版本系统分为:
- 分散性 git。说个仓库,不用远程连接仓库就可进行开发。所有仓库之间都可push或pull。
- 集中性 svn,将仓库几种放在一个服务器中。便于管理,但一旦开发者所处环境不能连接服务器,就获取不到代码。
仓库
- workspace 工作区
git add .到 stage - Index/Stage 暂存区
git commit 到Repository - Repository 仓库区(本地仓库)
git push 到remote - Remote 远程仓库
git使用
git初始设置
-
设置姓名和邮箱地址
git config --global user.name "" git config --global user.email ""输入
~/.gitconfig可查看[user]配置
git config --list 查看配置项 -
提高命令输出的可读性 git config --global color.ui auto
-
设置 SSH Key
ssh-keygen -t -C "邮箱"一直enter,就会设置成功
id_rsa文件是私有密钥
id_rsa.pub是公开密钥
ssh-keygen -C "邮箱" -f 自定义秘钥名称(github_hub)
-
Giuhub添加公开密钥
Account Settings 选择SSH Keys。-> Add SSH Key
控制台查看公钥内容 cat ~/.ssh/id_rsa.pub
完成设置后,就用私有密钥与GitHub进行认证通信了
ssh -T git@github.com 查看是否通讯成功
-
在Github中new repository(新建 仓库)
-
description 描述可选
-
pubilc/private
-
add .gitignore
把不需要在git仓库中进行版本管理的文件记录在.gitignore中。
-
add a license
许可协议文件。
-
git基本操作
- git init 初始化仓库
生成的.git目标存储这当前目录内容所需的仓库数据 - git status 查看仓库状态
- git add filename 向暂存区中添加文件
- git commit 保存仓库的历史记录
- git commit -m "first commit" -m后接提交信息
- git log 查看提交日志
- git log --pretty=short 只显示提交信息的第一行
- git log 目录名/文件名 只显示该目录、文件的日志
- git log -p filename 查看文件的改动
- git log --graph 以图表形式查看分支
- git reflog 查看当前仓库的操作日志
git log 只会查看以当前状态为中的的历史日志(即用git reset恢复以前的看不到)
- git diff 查看更改前后的差别
可查看工作树、暂存区、最新提交之间的差别
分支的操作
-
git branch 显示分支一览表
-a 查看所有远程分支和本地分支
-r 查看所有远程分支
远程分支和本地分支有什么区别- git branch -d 删除本地branchname
- git branch -m brandcholdname branchewname 重命名分支
- git branch 创建branchname分支
-
git checkout -b 创建、切换分支
- git checkout -b feature-A
等价于
git branch feature-A
git checkout feature-A - git checkout master 切换到master分支
- git checkout - 切换会上一个分支
- git checkout -b feature-A
-
开发分支(feature)
在开发过程中,常会创建多个特性分支(实现不同的功能),保留一个随时可发布软件的稳定分支(release)。 当特性分支完成后,再与master分支合并。 -
发布分支(release)
稳定分支,可随时供人查看。
Tag创建版本信息,同时管理多个版本。拥有多个版本分布时,发布分支也有多个。 -
主干分支(master)
当release分支上线后,当前分支打tag、封板,合并到master。 -
git merge 合并分支
把feature-A分支合并到master
git checkout master
git merge --no--ff feature-A\
更改提交的操作
git的一大特性:可灵活操作历史版本。在不影响其他仓库的前提下对历史版本进行操作。
git跟踪的是管理的修改而非文件。
-
git reset 回溯历史版本
git reset --hard 版本号id(git log查看) 可恢复到该时间点的状态
HEAD指向的版本就是当前版本
git reset --hard HEAD^ 回溯到上一个版本
^^^每个都是返回上一个
-
撤销修改
-
若改了工作区的内容,就丢弃工作区的修改 git checkout --文件名
-
不但该了工作区,还添加到了暂存区,向丢弃修改。分两步
第一步git reset HEAD 文件名 回到场景一
第二步git checkout --文件名
-
若提交到了版本库修改,就用版本回退。前提没有推送到远程库
-
-
删除文件
从版本库中删除文件
git rm test.txt
git commit -m "remove test.txt"
git checkout是用版本库里的版本替换工作区的版本,无论工作区是修改还是删除,都可以一键还原。
git checkout test.txt
如果一个文件已经别提交到版本库,就永远不用担心误删,但要小心,只能恢复文件到最新版本,会丢失最近一次提交后你修改的内容,
-
消除冲突
比如在合并fix-B时发送了冲突(Conflict)。打开README.md文件可看到。
<<<<<<< HEAD - feature-A ====== - fix-B >>>>>>> fix-Bfix-B与feature-A冲突了。修改冲突部分或删除之一
-
提交解决后的结果
git add filename git commit -m "fix confilct" -
git commit --amend 撤销上一次提交,并将暂存区文件重新提交
-
-
git rebase -i 压缩历史
推送远程操作
-
git remote add 添加远程仓库
-
git push 推送至远程仓库
git push -u origin master
git pish -u origin feature-D 将本地feature-D分支推送到GitHun的feature-D分支
从远程仓库获取
不在同一个目录进入,表示另外一名新开发者共同开发。
-
git clone 地址
会默认处于master分支下,同时系统会自动将origin设置成该远程仓库的标识符。
-
获取远程的feature-D到本地仓库
git checkout -b feature-D origin/feature-D
-b 后是本地仓库新建分支的名称。
origin/feature-D 以名origin的(github)仓库的feature-D分支为来源,在本地仓库中创建feature-D分支
-
向本地feature-D分支提交修改
git commit -am "add feature-D"
git push 推送feature-D分支
-
-
git pull 获取最新的远程仓库分支
git pull origin feature-D 将本地的feature-D分支更新到最新状态。
- git pull origin -d 删除远程branchname分支
合并分支
假设初始分支状态:\
-
main 分支: A->B->C(最新提交C)
-
feature分支:基于B开发,D->E(专属提交D、E)
-
git merge main feature(合并后)
- git rebase main feature (变基后)
- git merge(适合团队协作) 需要一次性解决所有冲突,哈希值不变,git rebase(适合个人分支) 逐个解决提交的冲突,哈希值会变
git rebase
-
git rebase -i commitId 将当前commit都合并到commitid一条上
- pick 保留
- squach 用新的commit,且合并到上一条
- fixup 用上一条commit,且合并到上一条
- drop
-
git rebase -i HEAD~3 合并前三次提交
-
git rebase --continue rebase过程中,解决冲突后,执行
-
git rebase --abort 中止:会回到rebase开始前的状态
-
git push --force-with-lease 若远端有更改推送是会被提示的
-
git rebase --onto 目标commit 起始commit 结束commit/分支 想要把指定commit移植到哪个commit之后
-
rebase 后只能用git push -f 强推,但不安全, 对于远端有更改是无感的
-
git rebase main 在当前个人分支rebase mian,拉取最新的main代码,保持自己分支的整洁。
remote 远程
- git remote add origin(别名) git地址
- git remote set-url 别名 新的远程地址
- git remote -v :查看别名和地址
- git remote :查看别名
- git remote rename 旧别名 新别名 :重命名
- git remote rm 别名:删除别名
push
- git push
- git push <远程别名> <分支名> :推送到指定远程的同名分支
- git push <远程别名> <本地分支>:<远程分支> : 当本地和远程分支名不同时
- git push --set-upstream origin main 关联本地分支到远程分支(首次推送):缩写-u
- git push --force-with-lease 安全强制推送,仅远程未被修改时覆盖
- git push --force origin feature (简写 -f) :强推,推之前一定要pull
- git push --dry-run origin main (简写 -n): 模拟推送(仅检查,不实际推送)
- git push --delete origin feature (简写 -d) 删除远程分支/标签
- git push --tags origin 推送本地所有标签到远程
- git push --verbose origin main (简写-v) 显示详细推送日志
标签
- git tag 列出所有tag
- git tag [tag] 在当前commit新建一个tag
- git tag [tag] [commit] 新建一个tag在指定commit
- git tag -d [tag] 删除本地tag
- git push origin :refs/tags/[tagName] 删除tag
- git show [tag] 查看tag信息
- git push [remote] [tag] 提交指定tag
- git push [remote] --tags 提交所有tag
- git checkout -b [branch] [tag] 新建一个分支,指向某个tag
pull 和 fetch
pull = fetch + pull
fetch 后,用rebase线性化历史
git fetch origin main
git rebase origin/main // 替代merge,线性合并远程代码
最好使用fetch, pull用于只有自己开发的这条分分支\
git pull 和 git pull --rebase 区别
- 假设main分支有A、B两个提交
- 本地基于当前切换出dev分支,新增C、D两个本地提交(还没推到远程)
- 此时远程main分支增加了E提交,远程是A、B、E,本地是A、C、D
场景一:使用git pull(默认merge合并)
冲突 \
- 解决冲突后 git add .
- git commit -m "merge: 解决冲突,合并远程代码"
- 特点:只需要解决一次冲突,合并冲突多的场景
场景二:git pull --rebase (变基合并)
相当于 先 暂存本地提交CD,把本地分支挪到远程最新提交E的后面,在把暂存的C、D重新应用到E之后,全程无多余提交
冲突 \
-
git add . // 解决冲突后,添加修改的文件
-
git rebase --continue // 继续处理下一个提交的冲突(若有)
-
若想放弃变基,执行 git rebase --abort
-
特点:需逐个提交解决冲突(比如本地有3个本地提交,可能需要解决3次冲突),但解决后记录更整洁
| 操作 | 提交记录形态 | 核心行为 | 优点 | 缺点 |
|---|---|---|---|---|
| git pull(merge) | 分叉状 | 保留双方提交历史,生成合并提交 | 操作简单,不修改原有提交 | 提交记录混乱,无多意义合并提交 |
| git pull --rebase | 线性 | 把本地提交[重放]到远程最新提交之后,无合并提交 | 记录整洁,易追溯 | 若有冲突,需逐个解决,比merge稍繁琐,但最终记录最优 |
- rebase 重新定基,把最新的提交重新定在远程最新提交的基础上,所以记录是直的
实践问题
修改githuub的commit(版本回退)
- git pull
- git log ->找到版本号id
- git reset --hard 版本号id
- git push -f origin master
直接覆盖
如果直接git push 之前没有git pull 会直接覆盖掉项目,原先的都不存在了。 这种情况git push -u 会报错。 虽然可用git push -f 强制覆盖,但要谨慎使用. git push以前,要先git pull才不会报错
- 或者可用 git push --force-with-lease 如果远程有更改会提示需要fetch的
commit相关
- git cherry-pick 合并某条commit到本分支
- 多条commit合并成一个
git add . git commit --amend :wq 保存 或者Esc编辑commit信息 - git push --force-with-lease
push规范
用于说明commit的类别
- br: 针对bug号,用于向测试反馈bug列表的bug修改情况
- feat: 新功能(feature)
- fix: 修复bug
- docs: 文档(documentation)
- style: 格式(不影响代码运行的变动)
- refactor: 重构
- test: 增加测试
- chore: 构建过程或辅助工具的变动
杂
- 版本库
git add->stage->git commit ->提交到当前分支 - 暂存区(stage),HEAD:指向master的指针
- git status 查看暂存区
- git checkout -- filename
丢弃对fliename的修改
git checkout其实是用版本库里的版本替换工作区的版本
从来没有被添加到版本库就删除的文件,是无法恢复的。 - rm filename 把工作区的file删除
- git rm filename 把版本库的file删除
用git ckeckout -- filename把误删的恢复到最新版本 - git push --set-upstream origin 分支名
将本地分支和远程分支绑定。
参考《GitHub入门与实践》 阮一峰