$ Git笔记

$ Git协议种类

git支持四种协议:Local, HTTP, Secure Shell (SSH) 和 Git。

$ Local协议

比如克隆一个本地仓库:

git clone /path/to/repo.git
# 或者
git clone file:///path/to/repo.git

基于文件的存储库的优点在于它们很简单,并且使用现有的文件权限和网络访问权限。

$ HTTP协议

比如克隆github的apache/hadoop仓库 (opens new window)

git clone https://github.com/apache/hadoop.git

与SSH相比,能够使用用户名和密码进行身份验证也是一个很大的优势,因为用户不必在本地生成SSH密钥并将其公共密钥上载到服务器即可与之交互。

另一个好处是,HTTPS是常用的协议,因此公司防火墙通常被设置为允许通过这些端口的通信。

记住密码配置:

git config --global credential.helper store

$ SSH协议

格式:

# 类似scp命令的形式:
[user@]host:path_to_repo.git
# 或者URL格式的形式:
ssh://[user@]host[:port]/path_to_repo.git

其中user默认为当前登录用户,port默认为22。

比如克隆github的apache/hadoop仓库 (opens new window)

git clone git@github.com:apache/hadoop.git
git clone ssh://git@github.com/apache/hadoop.git

SSH是经过身份验证的网络协议,并且由于它无处不在,因此通常易于设置和使用。

像HTTPS,Git和本地协议一样,SSH高效,在传输数据之前使数据尽可能紧凑。

$ Git协议

Git协议的缺点是缺少身份验证。它还需要防火墙访问端口9418,这通常不是公司防火墙允许的标准端口。

$ 参考

$ Git命令

$ 记住 HTTP 协议密码

永久记住账号密码:

git config --global credential.helper store

账号密码会记录在~/.git-credentials文件中:

${PROTOCOL}://${USER}:${PASSWORD}@${HOST}

$ diff

显示 stage 区和HEAD 的 diff:

git diff --staged

$ clone单个分支

git clone --single-branch -b "jdk/jdk" git@github.com:yx91490/openjdk.git openjdk2

$ 修改历史commit的author信息

按如下输入进入一个类似vim编辑器的交互页:

git rebase -i HEAD~3

将要修改的commit 1开头的pick改成edit

edit aaaa commit 1
pick bbbb commit 2
pick cccc commit 3

然后保存退出,即:wq。接着输入下面的命令来修改提交者信息:

$git commit --amend --author="Foo <foo@bar.com>"

最后输入保存命令:

git commit --continue

参考:Git修改历史commit的author信息 (opens new window)

$ 修改已push的所有user信息

执行脚本:

#!/bin/sh

git filter-branch --env-filter '

OLD_EMAIL="your-old-email@example.com"
CORRECT_NAME="Your Correct Name"
CORRECT_EMAIL="your-correct-email@example.com"

if [ "$GIT_COMMITTER_EMAIL" = "$OLD_EMAIL" ]
then
    export GIT_COMMITTER_NAME="$CORRECT_NAME"
    export GIT_COMMITTER_EMAIL="$CORRECT_EMAIL"
fi
if [ "$GIT_AUTHOR_EMAIL" = "$OLD_EMAIL" ]
then
    export GIT_AUTHOR_NAME="$CORRECT_NAME"
    export GIT_AUTHOR_EMAIL="$CORRECT_EMAIL"
fi
' --tag-name-filter cat -- --branches --tags

强制提交:

git push --force --tags origin 'refs/heads/*'

强制拉取:

git merge --allow-unrelated-histories

参考:changing author info (opens new window)

$ 修改已push commit的提交日期

  1. 修改日期格式:

    git config log.date iso-local
    
  2. 执行命令:

    git filter-branch --env-filter \
        'if [ $GIT_COMMIT = b0e3533c1e25ef19bd68ad54c987fd9aac7b8372 ]
         then
             export GIT_AUTHOR_DATE="2020-01-9 18:01:49 +0800"
             export GIT_COMMITTER_DATE="2020-01-9 18:01:49 +0800"
         fi'
    

$ 从远程仓库同步tags

git fetch --all --tags

参考:How To Checkout Git Tags (opens new window)

$ 删除远程分支

git push origin --delete <branch_name>

参考:git删除远程分支和本地分支 (opens new window)

$ 同步上游仓库

1.配置上游remote:

git remote add upstream https://github.com/ORIGINAL_OWNER/ORIGINAL_REPOSITORY.git

2.Fetch上游变更(如果有必要的话):

git fetch upstream

3.Checkout到本地分支:

git checkout main

4.Merge对应的上游分支:

git merge upstream/main

参考:

Configuring a remote for a fork (opens new window)

Syncing a fork (opens new window)

$ 合并

# “仅快进”的合并
git merge --ff-only origin/master

$ Git pull不能快进问题

git pull --rebase

参考:Fatal: Not possible to fast-forward, aborting (opens new window)

$ 生成及合入patch

生成patch 的方法:

git format-patch <SinceCommitId>

打入patch 的方法:

git am <file1>, <file2>...

参考

Git 打补丁-- patch 和 diff 的使用(详细) (opens new window)

$ 子模块

克隆并自动初始化并更新仓库中的每一个子模块:

git clone --recurse-submodules https://github.com/<account>/<repo>

或者克隆之后再进行子模块的初始化:

# 克隆不包含子模块
git clone https://github.com/<account>/<repo>

# 初始化本地配置文件
git submodule init

# 从该项目中抓取所有数据并检出父项目中列出的合适的提交
git submodule update

参考:

7.11 Git 工具 - 子模块 (opens new window)

$ 根据变更内容查找commit

查看某行的内容在哪个commit被新增或删除:

git log -S <SearchString> [[--] <path>...]

$ 提交中保留可执行权限

git update-index --chmod=+x <file>

$ Git工作流

$ Git flow

$ 图示

img

$ 特点

  • 项目存在两个长期分支:

    • master分支用于存放稳定的发布版
    • develop分支用于存放最新的开发版
  • 项目存在三种短期分支(一旦完成开发,它们就会被合并进developmaster,然后被删除):

    • feature-*分支(功能分支)
    • hotfix-*分支(补丁分支)
    • release-*分支(预发分支,分配新版本号)

$ 来源和去向

  • develop分支:
  • 来源于master分支(首次)、release分支(以及feature分支、hotfix分支)
    • 合并到release分支(最终合并到master分支)
  • release分支:
    • 来源于develop分支
      • 合并到master分支以及develop分支
  • feature分支(通常仅存在于开发者本地仓库):
    • 来源于develop分支
    • 合并到develop分支
  • hotfix分支:
    • 来源于master分支
    • 合并到master分支以及develop分支(以及release分支如果存在的话)

$ 总结

  • 需要长期维护两个分支,维护复杂
  • 适合较长版本发布周期的项目
  • 稳定发布版的分支维护在master分支

$ Github flow

$ 图示

github_flow

$ 特点

  • master 分支中包含稳定的代码。该分支已经或即将被部署到生产环境。
  • 对代码的任何修改,包括 bug 修复、hotfix、新功能开发等都在单独的分支中进行。
  • 当新分支中的代码全部完成之后:
    • 通过 GitHub 提交一个新的 pull request。
    • 团队中的其他人员会对代码进行审查,提出相关的修改意见。
    • 由持续集成服务器(如 Jenkins)对新分支进行自动化测试。
    • 当代码通过自动化测试和代码审查之后,该分支的代码被合并到 master 分支。
  • 要求项目有完善的自动化测试、持续集成和部署等相关的基础设施。每个新分支都需要测试和部署。
  • 要求团队有代码审查的相应流程。

$ 总结

  • 单一主分支,维护简单
  • 适合持续发布
  • 稳定发布版的分支维护在master分支上

$ Gitlab flow

包括两种模式:

  • 版本发布
  • 持续发布

$ 版本发布

版本发布

总结:

  • 发布的时候创建新的release分支,通常使用带有次要版本号的命名方式,如2-3-stable
  • bug修复先合并到master分支,再cherry-pick到相应的release分支(上游优先原则)
  • 引入bug修复后的release分支打上新版本号(修订号+1)的标签
  • 稳定发布版的分支维护在*-stable分支上

$ 持续发布

图示:

持续发布

总结:

  • master、pre-production、production分支分别对应暂存环境,预生产环境,生产环境
  • commit信息仅从上游流到下游,确保任何更改都在所有环境测试通过
  • bug修复通常新建feature分支然后合并到master,测试通过后继续向下游合并
  • 稳定发布版的分支维护在production分支

$ 参考

更新时间: 2/1/2023, 9:37:26 AM