Git

作者: bowen_wu | 来源:发表于2022-07-13 11:24 被阅读0次

概述

Git 是分布式版本控制系统

Git 基本单元

仓库

  • 一个所有的历史都可追溯的文件夹 => 历史的最小单位是仓库的某个时刻的状态(快照) => 通常使用 SHA-1 表示
  • 可以标识仓库的某个状态
    1. commit 对象的 SHA-1
    2. Branch
    3. HEAD => 当前分支的指针
    4. 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

  1. git bisect start => 开始 bisect
  2. git bisect bad => 告知当前版本是 bad
  3. git checkout <status> => 恢复到 status 状态
  4. git bisect good => 告知当前版本是 good
  5. git bisect skip => 跳过当前版本
  6. ...
  7. git bisect reset => 结束 bisect

使用场景

  • 在问题可以稳定重现的时候,迅速定位出问题的代码 => 有的时候这比直接去 debug 更快捷

自动 bisect

  1. touch run.sh
  2. 将手动的部分写入 run.sh script 中 => shell script:
    • exit(0) => good
    • exit(1) => bad
  3. git checkout <good-status> => 恢复到 good status 状态
  4. ./run.sh => 检测脚本是否符合预期
  5. git checkout <bad-status> => 恢复到 bad status 状态
  6. ./run.sh => 检测脚本是否符合预期
  7. git bisect bad => 告知当前版本是 bad => 如果没有运行 git bisect start,当前命令会询问是否开启 bisect
  8. git checkout <good-status> => 恢复到 good status 状态
  9. git bisect good => 告知当前版本是 good
  10. 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 工作流

  1. 一个或两个共享的稳定分支
    • master
    • develop
  2. 临时性的功能分支
    • feature
    • bugfix
    • release

搭建 Git 服务器

gogs => go git service

步骤

Root 用户

  1. 安装 docker => api-get update && apt-get install docker.io
  2. 创建 git 用户 => adduser git
  3. 使 git 用户可以运行 docker => usermod -aG docker git
  4. 创建 gogs 运行目录 => mkdir -p /app/gogs
  5. 改变目录的所有人 => chown git:git /app/gogs

Git 用户

  1. 创建 SSH 目录 => mkdir -p ~/gogs/git/.ssh
  2. 建立软连接 => ln -s ~/gogs/git/.ssh ~/.ssh
  3. 生成 SSH key => ssh-keygen -t rsa -P ''
  4. cat ~/.ssh/id_ras.pub >> ~/.ssh/authorized_keys
  5. 对 SSH key 更严格的权限 => chmod 700 ~/.ssh && chmod 600 ~/.ssh/*
  6. 把服务器的 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
    
  7. chmod 755 /app/gogs/gogs
  8. 启动 docker => docker run -v ~git/gogs:/data -p 127.0.0.1:10022:22 -p 3000:3000 gogs/gogs
  9. 运行脚本 => /app/gogs/gogs => Gogs - A painless self-hosted Git service
  10. 访问 => <ip>:3000
  11. 数据库类型 => SQLite3
  12. 数据库文件路径 => /data/gogs.db
  13. 域名 => ip
  14. 应用 URL => http://<ip>:3000/

知识点

  1. octopus merge => octopuss 八爪猫 == octopus pussy => octocat(八爪猫) => github logo
  2. stage => 舞台
  3. UNIX 约定 => 程序成功退出 => 返回值0 => 否则非0
  4. git pull == git fetch + git merge
  5. git pull --rebase == git fetch + git rebase
  6. 提交记录是一条线优点
    • 清楚直观
    • 每个提交代表一个单独的完整的功能点,方便回滚
    • 每个提交都是稳定的,方便进行 bisect

相关文章

网友评论

      本文标题:Git

      本文链接:https://www.haomeiwen.com/subject/njidbrtx.html