概述
Git 是分布式版本控制系统
Git 基本单元
仓库
- 一个所有的历史都可追溯的文件夹 => 历史的最小单位是仓库的某个时刻的状态(快照) => 通常使用 SHA-1 表示
- 可以标识仓库的某个状态
- commit 对象的 SHA-1
- Branch
- HEAD => 当前分支的指针
- Tag
commit
仓库从一个状态转移到另外一个状态是发生的改变 => commit 对象 => commit 对象不可变,其中包含
- id
- parent-id
- committer => name + email
等等
Branch
- 一个可以移动的指针,指向某个commit对象
- 新建一个分支,就是新建一个指针 =>
git checkout -b <new-branch> [仓库的某个状态]
- HEAD => 特殊的指针 => 指代当前分支的头
-
^ 和 ~
^ 和 ~
远程仓库 本地仓库 fork
- 远程仓库/本地仓库/fork 本质上就是复制了整个文件夹
- 只有远程分支和本地分支历史相同时,才能 push => 远程分支是本地分支的祖先
Merge
Join two or more development histories together. => 合并 => 将两个或多个状态(代码快照/代码副本)合并,并产生一个合并提交 => Git 逐行检查冲突并尝试自动解决 =>
解决失败,报错
优点
- 简单,易于理解
- 记录了完整的历史
- 冲突解决简单
缺点
- 历史杂乱无章
- 对 bisect 不友好
git merge --squash
- 优点:把所有变更合在一起,更容易阅读,bisect 友好,想要回滚或者 revert 非常方便
- 缺点:丢失了所有的历史记录
rebase
Reapply commits on top of another base tip. => 将某个状态上的变更(commit)挨个重演 => 共享分支不要 force push
- 使用场景:定时将你的分支和主干进行同步
- 在自己的分支上,尽量使用 rebase
A---B---C master
/
D---E---F feature
// 在 master 分支上
git rebase feature
A'---B'---C' master
/
D---E---F
// 在 feature 分支上
git rebase master
A---B---C
/ \
D E'---F' feature
优点
- 分支历史是一条直线,清楚直观
- 对 bisect 友好
缺点
- 较为复杂
- 冲突可能要重复解决(或者使用 squash => 丢失了提交历史)
log
- 单线历史 => 通常基于时间和提交记录的顺序,不准确但简单
- 多线历史 => 更好地展示分支的合并记录,准确,复杂难懂
checkout
- Switch branches or restore working tree files.
- 将代码复原到任何一个状态上,但不修改仓库中的任何信息 =>
git checkout <仓库的某个状态>
- 新建分支 =>
git checkout -b <new-branch-name> [<start-point>]
- restore working tree files =>
git checkout -- <file>
reset
- Reset current HEAD to the specified status.
-
git reset [<mode>] [<commit>]
=> mode: 处理中间态的文件变更--soft
-
--mixed
=> Resets the index but not working tree(i.e., the changed files are preserved but not marked for commit) and reports what has not been updated. This is the default action. -
--hard
=> Resets the index and working tree. Any changes to tracked files in the working tree since <commit> are discarded. Any untracked files or directories in the way of writing any tracked files are simply deleted.
使用场景
- 迅速将分支恢复到某个状态
- squash commit,方便 rebase
cherry-pick
- Apply the changes introduced by some existing commits. => 将某个提交在另外的分支上重放
使用场景
- 希望把一个 bugfix 同步到较老的产品中
- 在 master 上进行的变更希望进入 release 环节
revert
- Revert some existing commits. => 产生一个反向提交,撤销某个 commit => 产生的反向提交可以再次进行 revert
使用场景
- 撤销历史中的某个更改,如 bug 或不恰当的功能
- 回滚某次发布
bisect
Use binary search to find the commit that introduced a bug.
手动 bisect
-
git bisect start
=> 开始 bisect -
git bisect bad
=> 告知当前版本是 bad -
git checkout <status>
=> 恢复到 status 状态 -
git bisect good
=> 告知当前版本是 good -
git bisect skip
=> 跳过当前版本 - ...
-
git bisect reset
=> 结束 bisect
使用场景
- 在问题可以稳定重现的时候,迅速定位出问题的代码 => 有的时候这比直接去 debug 更快捷
自动 bisect
- touch run.sh
- 将手动的部分写入 run.sh script 中 => shell script:
- exit(0) => good
- exit(1) => bad
-
git checkout <good-status>
=> 恢复到 good status 状态 -
./run.sh
=> 检测脚本是否符合预期 -
git checkout <bad-status>
=> 恢复到 bad status 状态 -
./run.sh
=> 检测脚本是否符合预期 -
git bisect bad
=> 告知当前版本是 bad => 如果没有运行git bisect start
,当前命令会询问是否开启 bisect -
git checkout <good-status>
=> 恢复到 good status 状态 -
git bisect good
=> 告知当前版本是 good -
git bisect run <path>/<to>/<run-shell-script.sh>
=> 告知 bisect 一个范围(good - bad),之后使用脚本在这个范围内进行二分查找
stash
Stash the changes in a dirty working directory away. => 临时性将工作目录的变更存储起来,然后清空工作目录
- git stash
- git stash list
- git stash pop
- git stash apply stash@{n}
使用场景
来了一个紧急的 bug。将手头上的工作使用 git stash
存储(暂存区)起来,之后开始修复 bug
tag
Create, list, delete or verify a tag object signed with GPG.
- 轻量级标签 => lightweight tag =>
git tag v1.0 && git push --tags
- 标注标签 => annotated tag =>
git tag -a v2.0 -m '这是一个有信息的 tag' && git push v2.0
Git 工作流
- 一个或两个共享的稳定分支
- master
- develop
- 临时性的功能分支
- feature
- bugfix
- release
搭建 Git 服务器
gogs => go git service
步骤
Root 用户
- 安装 docker => api-get update && apt-get install docker.io
- 创建 git 用户 => adduser git
- 使 git 用户可以运行 docker => usermod -aG docker git
- 创建 gogs 运行目录 => mkdir -p /app/gogs
- 改变目录的所有人 => chown git:git /app/gogs
Git 用户
- 创建 SSH 目录 => mkdir -p ~/gogs/git/.ssh
- 建立软连接 => ln -s ~/gogs/git/.ssh ~/.ssh
- 生成 SSH key => ssh-keygen -t rsa -P ''
- cat ~/.ssh/id_ras.pub >> ~/.ssh/authorized_keys
- 对 SSH key 更严格的权限 => chmod 700 ~/.ssh && chmod 600 ~/.ssh/*
- 把服务器的 22 端口请求转发到 docker Git 服务器
cat >/app/gogs/gogs <<'END' #!/bin/sh ssh -p 10022 -o StrictHostKeyChecking=no git@127.0.0.1 \ "SSH_ORIGINAL_COMMAND=\"$SSH_ORIGINAL_COMMAND\" $0 $@" END
- chmod 755 /app/gogs/gogs
- 启动 docker => docker run -v ~git/gogs:/data -p 127.0.0.1:10022:22 -p 3000:3000 gogs/gogs
- 运行脚本 => /app/gogs/gogs => Gogs - A painless self-hosted Git service
- 访问 => <ip>:3000
- 数据库类型 => SQLite3
- 数据库文件路径 => /data/gogs.db
- 域名 => ip
- 应用 URL => http://<ip>:3000/
知识点
- octopus merge => octopuss 八爪猫 == octopus pussy => octocat(八爪猫) => github logo
- stage => 舞台
- UNIX 约定 => 程序成功退出 => 返回值0 => 否则非0
- git pull == git fetch + git merge
- git pull --rebase == git fetch + git rebase
- 提交记录是一条线优点
- 清楚直观
- 每个提交代表一个单独的完整的功能点,方便回滚
- 每个提交都是稳定的,方便进行 bisect
网友评论