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