主要内容:【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
合并策略
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
里程碑命名规范
版本格式:主版本号.次版本号.修订号,版本号递增规则如下:
- 主版本号:当你做了不兼容的 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.logallrefupdates
为true
的配置,这样在版本库中建立的每个分支都会创建对应的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
可以应用一般格式的补丁文件,但是不能执行提交,也不能保持补丁中的作者信息。