Yifans_Z's Blog.

【Git 权威指南】读书笔记 - 和声

字数统计: 2.1k阅读时长: 30 min
2018/01/17 Share

主要内容:【Git 协议与工作协同】、【冲突解决】、【Git 里程碑】、【Git 分支】、【远程版本库】、【补丁文件交互】

Git 协议与工作协同

Git 支持的协议

SSH、GIT、HTTP、HTTPS、FTP、FTPS、RSYNC 及前面已经看到的本地协议。

SSH 协议:

ssh://[user@]example.com[:port]/path/to/repo.git/

[user@]example.com:path/to/repo.git/

GIT 协议,最常用的只读协议:

git://example.com[:port]/path/to/repo.git/

HTTP[S] 协议:

http[s]://example.com[:port]/path/to/repo.git/

强制非快进式推送

$ git push -f

强制推送,会强制刷新服务器中的版本。

禁止非快进式推送

$ git --git-dir=/path/to/repos/shared.git config receive.denyNonFastForwards true

冲突解决

拉回操作中的合并

git pull = git fetch + git merge

合并策略

Merge Strategis

Git 合并操作支持很多合并策略,默认会选择最适合的合并策略。例如,和一个分支进行合并时会选择 recursive 合并策略,当和两个或两个以上的其他分支进行合并时采用 octopus 合并策略。

git merge [-s <strategy>] [-X <strategy-option>] [<commit>...]

This option forces conflicting hunks to be auto-resolved cleanly by favoring our version.

$ git merge -s recursive -X ours [<commit>...]

Merge branch obsolete into the current branch, using ours merge strategy:

$ git merge -s ours obsolete

Git 里程碑

显示里程碑

$ git tag

显示说明。-n<num> 显示最多 <num> 行里程碑的说明:

$ git tag -n1

使用统配:

$ git tag -l v1.*

查看提交对应的里程碑及其他引用:

$ git log --oneline --decorate

创建里程碑

当创建了里程碑 mytag 后,会在版本库的 .git/refs/tags 目录下创建一个新文件。实际上指向的是一个提交:

$ git tag mytag

$ git cat-file -t mytag
commit

带说明的 tag 指向的不再是一个提交,而是一个 tag 对象:

$ git tag -m "My first annotated tag." mytag2

$ git cat-file -t mytag2
tag

为里程碑对象添加 GnuPG 签名:

$ git tag -s -m "My first GPG-signed tag." mytag3

删除里程碑

$ git tag -d mytag
Deleted tag 'mytag' (was 60a2f4f)

共享里程碑

创建的里程碑,默认只在本地版本库中可见,不会因为对分支执行推送而将里程碑也推送到远程版本库。

将 mytag 里程碑共享到上游版本库:

$ git push origin mytag

所有里程碑全部推送到远程版本库:

$ git push origin refs/tags/*
  • 里程碑共享,必须显式的推送。
  • 执行获取或拉回操作,自动从远程版本库获取新里程碑,并在本地版本库中创建。
  • 如果本地已有同名的里程碑,默认不会从上游同步里程碑,即使两者里程碑的指向是不同的。

删除远程版本库的里程碑

$ git push origin :mytag2

里程碑命名规范

语义化版本 2.0.0

版本格式:主版本号.次版本号.修订号,版本号递增规则如下:

  • 主版本号:当你做了不兼容的 API 修改,
  • 次版本号:当你做了向下兼容的功能性新增,
  • 修订号:当你做了向下兼容的问题修正。

先行版本号及版本编译信息可以加到 主版本号.次版本号.修订号 的后面,作为延伸。

Git 分支

分支是代码管理的利器。如果没有有效的分支管理,代码管理就适应不了复杂的开发过程和项目的需要。

分支命令概述

# 显示
1. git branch

# 创建
2. git branch <branchname>
3. git branch <branchname> <start-point>

# 删除,-d 在删除分支 <branchname> 时会检查所要删除的分支是否已经合并到其他分支中,否则拒绝删除。
4. git branch -d <branchname>
5. git branch -D <branchname>

# 重命名,-m 如果版本库中已经存在名为 <newbranch> 的分支,拒绝执行重命名,而 7 会强制执行。
6. git branch -m <oldbranch> <newbranch>
7. git branch -M <oldbranch> <newbranch>

创建并切换到新分支:

git checkout -b <new_branch> [<start_point>]

分支变基

  • master
  • dev(开发完成,领先 master)
# 先切换到 dev
$ git checkout dev

# 变基操作
$ git rebase master

# 遇到冲突,解决冲突

# 添加到暂存区
$ git add -u

# 继续变基
$ git rebase --continue

# 直接将 dev 推送到远程 master
$ git push origin dev:master

# 切换到 master
$ git checkout master

# 拉取最新代码
$ git pull

# 删除 dev 分支
$ git branch -d dev

远程版本库

远程分支

查看远程分支:

$ git branch -r

在向远程版本库执行获取操作时,不是把远程版本库的分支原封不动地复制到本地版本库的分支中,而是复制到另外的命名空间。

远程分支不是真正意义上的分支,是类似于里程碑一样的引用。如果针对远程分支执行检出命令,会看到大段的错误警告。

远程分支类似于里程碑,如果检出就会使得头指针 HEAD 处于分离头指针状态。实际上除了以 refs/heads 为前缀的引用之外,如果检出任何其他引用,都将使工作区处于分离头指针状态。如果对远程分支进行修改就需要创建新的本地分支。

分支追踪

为了能够在远程分支 origin/hello-1.x 上进行工作,需要基于该远程分支创建本地分支:

$ git checkout hello-1.x

从远程分支创建本地分支,自动建立了分支间的跟踪,而从一个本地分支创建另外一个本地分支则没有。

hello-1.x 分支中创建新的本地分支 hello-jx,并与远程建立联系。

$ git checkout -b hello-jx hello-1.x
cat .git/config

远程版本库

# 设置
$ git remote add new-remote file:///path/to/repos/hello-user1.git

# 修改 url
$ git remote set-url new-remote file:///path/to/repos/hello-user2.git

# 单独修改 push 地址
$ git remote set-url --push new-remote /path/to/repos/hello-user2.git

# 修改 版本库名称
$ git remote rename new-remote user2

# 当注册了多个远程版本库并希望获取所有远程版本库的更新
$ git remote update

# 如果某个远程版本库不想在执行 git remote update 时获得更新
$ git config remote.user2.skipDefaultUpdate true

# 删除
$ git remote rm

PUSH 和 PULL 操作与远程版本库

在执行 git pull 操作的时候可以通过参数 --rebase 设置使用变基而非合并操作,将本地分支的改动变基到跟踪分支上。为了避免因为忘记使用 --rebase 参数导致分支的合并,可进行设置:

$ git config branch.<branchname>.rebase true

这样在遇到冲突(本地和远程分支出现偏离)的情况下,会采用变基操作,而不是默认的合并操作。

如果为本地版本库设置参数 branch.autosetuprebase ,值为 true,则在基于远程分支建立本地追踪分支时,会自动配置 branch.<branchname>.rebase 参数。

分支和里程碑的安全性

  • reflog 记录对分支的操作历史。默认创建的带工作区的版本库都会包含 core.logallrefupdatestrue 的配置,这样在版本库中建立的每个分支都会创建对应的 reflog。但是创建的裸版本库默认不包含这个设置,也就不会为每个分支设置 reflog。可能因为分支误操作导致数据丢失,可以考虑为裸版本库添加此配置。

  • 关闭非快进式提交。配置 receive.denyNonFastForwards 设置为 true,则禁止一切非快进式推送。更好的方法是通过架设基于 SSH 协议的 Git 服务器,配置强制提交的用户权限。

  • 关闭分支删除功能。配置 receive.denyDeletes 设置为 true,则禁止删除分支。更好的方法是:配置分支删除的用户权限。

补丁文件交互

将最近三个提交转换为补丁文件:

$ git format-patch -s HEAD~3..HEAD

-s 会在导出的补丁文件中添加当前用户的签名。

应用补丁:

$ git am user1-mail-archive

git apply 可以应用一般格式的补丁文件,但是不能执行提交,也不能保持补丁中的作者信息。

Reference:

CATALOG
  1. 1. Git 协议与工作协同
    1. 1.1. Git 支持的协议
    2. 1.2. 强制非快进式推送
    3. 1.3. 禁止非快进式推送
  2. 2. 冲突解决
    1. 2.1. 拉回操作中的合并
    2. 2.2. 合并策略
  3. 3. Git 里程碑
    1. 3.1. 显示里程碑
    2. 3.2. 创建里程碑
    3. 3.3. 删除里程碑
    4. 3.4. 共享里程碑
    5. 3.5. 删除远程版本库的里程碑
    6. 3.6. 里程碑命名规范
  4. 4. Git 分支
    1. 4.1. 分支命令概述
    2. 4.2. 分支变基
  5. 5. 远程版本库
    1. 5.1. 远程分支
    2. 5.2. 分支追踪
    3. 5.3. 远程版本库
    4. 5.4. PUSH 和 PULL 操作与远程版本库
    5. 5.5. 分支和里程碑的安全性
  6. 6. 补丁文件交互