git

Posted by Andrew Blog on May 18, 2015

版本模型

  • 原则:新分支只能合并到来源分支(不能在新分支之间做合并),来源分支可以将部分改进合并到新分支
  • 资料:分支模型英文原版
分支类型 名称 永久 命名规范 来源 操作 合并到 角色
master 主干,正式环境 Y master release,hotfix 发布人员
develop 开发分支,开发环境,测试环境 Y dev 任意 开发人员
feature 功能分支 N V2.3_ft_pay_lyx。V版本号__ft_功能说明_负责人 dev 任意 dev 开发人员
release 版本发布分支 N V2.3_rl_20161111。V版本号__rl_版本日期 dev bugfix dev 发布人员,开发人员
hotfix 补丁分支 N V2.2_hf_123456-332452_wyq。V版本号__hf_bug说明_负责人 master bugfix dev 发布人员,开发人员

精简模型的操作:

  1. hotfix无需另开分支,直接在master开发【否则还需部署一套环境】。合并操作同hotfix。
  2. 当前版本的feature无需另开分支,直接在dev开发。长期feature需开分支。

环境清单

  1. 每个环境都有一套:执行程序,数据库,配置
环境 对应分支 执行程序 数据库 设置 说明
开发环境 dev+feature 开发人员自行搭建,独立 可复用测试数据库 可复用测试配置  
测试环境 dev 独立 独立 独立  
发布环境 release或者hotfix 独立 可复用测试数据库 独立  
正式环境 master 独立 独立 独立  

使用

日常流程

初始化

  1. 从master克隆dev:git checkout master; git branch dev;

开发feature分支

  1. 从dev克隆feature:git checkout dev; git branch V2.3_ft_pay_lyx;
  2. 开发人员检出:git checkout V2.3_ft_pay_lyx;
  3. feature合并回dev:git checkout dev; git merge V2.3_ft_pay_lyx;

开发release分支

  1. 从dev克隆release:git checkout dev; git branch V2.3_rl_20161111;
  2. 开发人员检出:git checkout V2.3_rl_20161111;
  3. release合并回dev:
  4. release合并到master(是一个发布版本。同时需要打标签):

开发hotfix分支

  1. 从master克隆hotfix:git checkout master; git branch V2.2_hf_123456-332452_wyq;
  2. 开发人员检出:git checkout V2.2_hf_123456-332452_wyq;
  3. hotfix合并回master:
  4. hotfix合并到dev/release:

hotfix时,当有一个release分支同时存在(当前版本快发布了,却发现上个版本的bug)。这个hotfix分支必须被合并到release分支而不是dev分支(release后续会合并到dev)。

部署环境

  1. 获取代码(测试环境):git -C DIR checkout dev; git -C DIR pull;
  2. 部署

常用操作

选择提交的分支

按照以下顺序选择:

  1. release分支:bugfix(无bugfix分支的情况下),需尽快发布的小改动和功能
  2. dev分支:
    • 下个版本 && 小改动
    • 下个版本 && (新增功能 && 不修改原有逻辑)
  3. feature分支:到了测试和发布阶段再合并回dev分支
    • !下个版本
    • 下个版本 && 调整功能
    • 下个版本 && (新增功能 && 修改原有逻辑)

暂存文件

  • 工作区代码暂存,会记录来源分支
  • 使用场景:有新工作要做(如bugfix)+ 当前工作区有不少修改了却无法提交的文件
  • 暂存当前工作区,切换到新工作,恢复当前工作区

打补丁

  • 跨分支代码迁移
  • 使用场景:提交了代码到主分支+该功能代码需要先发布上线
  • 在主分支上选择该功能对应的所有提交,创建成一个补丁,在发布分支上应用本补丁

取消本地没push的commit

  1. 重置到commit前的上一个版本,常用mixed
    • soft:提交内容放在缓冲区(相当于git add了)
    • mixed:提交内容不放在缓冲区(相当于改动后什么都没操作,git add后等于soft)
    • hard:丢弃提交内容

pull时冲突处理

无commit(2种方法,推荐暂存)

暂存处理
  1. stash暂存改动
  2. pull最新的版本
  3. stash pop,手动解决冲突
冲突处理
  1. commit
  2. “有commit”的流程

有commit

  1. pull,手工解决冲突
  2. commit(解决冲突)merge版本
  3. push

冲突各方说明

方式 我的(LOCAL) 他人(REMOTE)
暂存 本地文件 暂存
分支合并 目标分支(LOCAL) 源分支(REMOTE, 被合并的)
补丁 本地文件 补丁

代码合并

仓库迁移

  • https://help.github.com/cn/articles/duplicating-a-repository

重置目录

  • “git -C src fetch && git -C src reset –hard && git -C src checkout B1 && git -C src pull”
  • src是git目录路径,B1是分支或者标签。如是标签pull会失败,可忽略

信息获取

  • git -C $3 symbolic-ref –short -q HEAD // 分支
  • git -C $3 describe –always –tag // 标签
  • git -C $3 rev-parse –short HEAD // 提交

变基(rebase)

  • merge和rebase的最终结果没有任何区别
  • https://xiaozhuanlan.com/topic/6873210549
  • https://git-scm.com/book/zh/v2/Git-%E5%88%86%E6%94%AF-%E5%8F%98%E5%9F%BA
  • https://blog.csdn.net/kuangdacaikuang/article/details/79619828
方式 说明 优点 缺点
merge 合并时遇到冲突,修改后重新commit 记录commit的实际情况,方便查看 无改动会快进合并,否则自动创建一个新的merge commit
rebase 将commit历史进行合并,并行变串行。本质是补丁模式 提交历史更加整洁 发生冲突时不容易定位问题,因为rewrite了history

清除已删除的文件(其存在于历史提交中)

寻找并删除Git记录中的大文件

// 下载全部分支
git clone --bare <git_url>
// 获取前十个最大的文件
git rev-list --objects --all | grep "$(git verify-pack -v .git/objects/pack/*.idx | sort -k 3 -n | tail -10 | awk '{print$1}')"
// 将文件名存入large_files.txt,基于文件清除
git filter-branch -f --prune-empty --index-filter "git rm -rf --cached --ignore-unmatch `cat large_files.txt`" --tag-name-filter cat -- --all
// 如果文件所在目录删除了,就无法清除文件了,只能清除目录
git filter-branch -f --prune-empty --index-filter 'git rm -rf --cached --ignore-unmatch 相对目录' --tag-name-filter cat -- --all
// 提交到远程仓库
git push origin --all -f

提交失败相关处理

设置大缓存,用于大文件提交失败:git config --global http.postBuffer 52428000
显示命令的详细信息,用于提交失败原因定位:export GIT_CURL_VERBOSE=1
显示所有配置:git config -l

统计

  1. 统计工具:cloc, git_stats
  2. 统计脚本
    echo "统计结果:" && git log --first-parent master --author="andrew" --after="2018-09-16 12:00:00" --before="2019-09-16 00:00:01" --pretty=tformat: --numstat | gawk '{ add += $1 ; subs += $2 ; loc += $1 - $2 } END { printf "增加行数:%s 删除行数:%s 变化总行数:%s\n",add,subs,loc }'
    echo "详情如下:" && git log --first-parent master --author="andrew" --word-diff --since="2019-05-16 00:00:01" --until="2019-09-16 12:00:00" -p --stat
    

同一台电脑上的仓库目录用不同账号提交

  1. 相同或不同仓库都可以
  2. 操作如下,核心是设置仓库实例的git账号信息
    cd 仓库目录
    git config --local user.name NAME
    git config --local user.email EMAIL@email.com
    

下载部分文件

  • 只能生效一次,再做需要重头操作
  • 支持多层目录
    git init && git config core.sparseCheckout true && echo "design/" >> .git/info/sparse-checkout
    git remote add -f origin url && git pull origin master
    

命令脚本

branch

  1. git clone -b master –single-branch –depth=1 URL // 只克隆指定的版本,克隆深度是1
  2. 显示当前分支:git branch
  3. 显示所有分支,含远程分支:git branch -va
  4. 显示分支的提交记录:git show-branch
  5. 显示当前分支的版本号(commit id):git rev-parse HEAD
  6. 切换分支/标签
  7. 切换本地分支:git checkout 分支/tag/commit,git checkout branch1, git checkout tag1, git checkout commit1
  8. 下载远程分支并切换【下载前先git pull同步】:git checkout -b <本地分支> origin/<远程分支>,git checkout -b lb origin/rb
  9. 下载远程标签并切换【下载前先git pull同步】:git checkout -b <本地分支> origin/<远程tag>
  10. 基于当前分支创建新分支/切换分支:git branch <分支>
  11. 删除分支:git branch -d <远程分支>

commitadd命令

  1. git add -f . && git commit -m “msg” && git push // 快速提交
  2. git checkout -b abc && git push origin abc:abc // 本地创建分支并推送到远程同名分支
  3. 添加所有的文件,包括删除的[所有跟踪文件中被修改过或已删除文件,所有未跟踪的文件]:git add -A .
  4. 查看所有的commit提交记录:git log
  5. 查看所有的commit提交记录(含文件清单):git log –name-status
  6. 查看最新的commit:git show
  7. 查看指定commit hashID的所有修改:git show commitId
  8. 查看某次commit中具体某个文件的修改:git show commitId fileName

其他


  1. git fetch && git reset –hard @{upstream} && git clean -ffdx // 重置目录到服务器状态
  2. git status // 显示当前目录的文件情况
  3. git blame file_path // 显示文件内容的具体修改情况
  4. git cat-file -p commitid // 显示提交号的具体内容
  5. git show commitid // 显示提交号的具体内容
  6. “git clone –depth 1 <目录>" // 下载最后一次commit,加快速度
  7. **指定在特定目录执行git:git -C <目录> 执行命令**
  8. 拉取当前分支:git pull
  9. 拉取分支:git pull <远程主机> <远程分支>:<本地分支>,git pull origin master:master
  10. 合并分支(远程分支合并到当前分支):git merge <远程分支>
  11. 查看提交信息:git show <提交号(7位)>
  12. 清除当前目录所有commit冲突的文件,不会回退:git reset hard
  13. git reset .
  14. 清除当前目录下所有没commit的管理文件的修改:git checkout .
  15. 清除当前目录下所有非管理文件:git -C . clean -xdf
  16. 撤销合并,需指定parent:git revert -m 1 <提交号(7位)> m参数的值可以是1或2,对应parent在merge commit信息中的顺序,1是合并目标,2是合并来源
  17. 永久删除远程分支上的提交。非常规操作,不建议使用【本方法已无效】
      cd <目录>
      git reset --hard HEAD^ // 删除最近的一次提交,删除n次提交就执行n次
      git push origin master -f // 提交到远程, origin是远程名称,master是分支名称
    
  18. 重置branch:分支存在但所有commit记录清空了,一般用于master
    思路:用空分支替换需重置的branch(master)
    步骤:
    git clone并进入目录
    git checkout --orphan new_branch && rm * -rf // 创建孤儿空分支,清空
    echo linux > README.md && git add -A && git commit -am "Initial commit" // 空分支加一个文件,没有文件无法创建commit,就没法替换master
    git branch -D master && git branch -m master && git push -f origin master // 删除master,将空分支提交到master
    
  19. Git查看和修改账户, git config
  20. git 免除账号密码的设置
    • git config –global credential.helper store // 记住账号密码
    • rm ~/.git-credentials // 取消账号密码记忆
  21. 忽略SSL证书:git config –global http.emptyAuth true

gitlfs

  1. gitlfs安装后默认git clone是下载lfs文件的
  2. 不下载lfs文件 配置: git config –global filter.lfs.smudge “git-lfs smudge –skip”
  3. 下载lfs文件 配置: git config –global filter.lfs.smudge “git-lfs smudge – %f”

资料

参考

  1. Learn Git Branching,很好的示范
  2. git push & git pull 推送/拉取分支
  3. Git - 分支的新建与合并
  4. SourceTree使用流程和方法
  5. git – 简易指南
  6. 强制删除远程分支上的某次提交
  7. Git下的冲突解决
  8. git多账号提交适配
  9. git中detached HEAD、amend、rebase和reset
  10. Detached HEAD

账号

  1. git账号:通过邮箱区分
  2. author:作者,通过commit命令添加
  3. committer:提交者,通过配置添加 1. 全局配置: /user/NAME/.gitconfig
  4. 服务商账号:服务商自定义,比如github账号密码

提交

  1. github提交时不会检查服务商账号是否和git的committer一致,所以只要有github仓库权限就可以伪造成其他人的提交
  2. github仓库首次输入会记忆