Git patch的使用方法和场景
Git补丁在同步不同分支的代码时应用较多,且比较灵活,比如修复了基线的一个bug,同步到各个版本的发布分支。本文介绍两种生成和应用补丁的方案。
1. diff
/apply
方案
此方案使用diff
命令生成patch文件,后使用apply
命令应用patch到分支,从而实现修改复刻。其大致流程如下:
# 生成补丁
git diff > commit.patch
# 检查补丁
git apply --check commit.patch
# 应用补丁
git apply commit.patch
下面具体介绍操作方法:
1.1 diff生成patch
先看下git diff的帮助文档:
usage: git diff [<options>] [<commit>] [--] [<path>...]or: git diff [<options>] --cached [<commit>] [--] [<path>...]or: git diff [<options>] <commit> [<commit>...] <commit> [--] [<path>...]or: git diff [<options>] <commit>...<commit>] [--] [<path>...]or: git diff [<options>] <blob> <blob>]or: git diff [<options>] --no-index [--] <path> <path>]common diff options:-z output diff-raw with lines terminated with NUL.-p output patch format.-u synonym for -p.--patch-with-raw output both a patch and the diff-raw format.--stat show diffstat instead of patch.--numstat show numeric diffstat instead of patch.--patch-with-stat output a patch and prepend its diffstat.--name-only show only names of changed files.--name-status show names and status of changed files.--full-index show full object name on index lines.--abbrev=<n> abbreviate object names in diff-tree header and diff-raw.-R swap input file pairs.-B detect complete rewrites.-M detect renames.-C detect copies.--find-copies-harder try unchanged files as candidate for copy detection.-l<n> limit rename attempts up to <n> paths.-O<file> reorder diffs according to the <file>.-S<string> find filepair whose only one side contains the string.
可见支持单个commit或多个commit生成patch,也支持对某个文件单独生成patch。这么多命令参数,该怎么去记住呢?实际上,diff
本质上是对两个版本之间文件做数据比较得出差异,重点在于两个版本。下面我们逐一分析下不同命令参数下,这两个版本是指什么:
git diff
没有指定任何版本,那默认就是对lastCommit
和working copy
之间作比较。
这里就会出现两种情况:如果当前的
working copy
已经commit过了,那么lastCommit
就是目前working copy
自身,所以diff不会输出任何内容;如果当前的working copy
未commit,那么diff就会输出本次修改的内容。
git diff commitId
指定了一个commitId,那就是对commitId
和working copy
之间作比较。同样的,如果你的working copy
已经commit过了,那么这个命令会等价于git diff commitId lastCommitId
。git diff commitId1 commitId2
指定了两个commitId(注意把时间早的commitId放在前面),这种情况就是对commitId1
和commitId2
之间作比较。
捋清楚这其中的关系,我们下面对日常开发中常见的场景进行介绍。
本地修改未commit
希望把修改的内容生成patch,可以如下操作:
git diff > commit.patch
对于已经add但是未commit的修改:
git diff --cached > commit.patch
本地修改已commit
希望把最近一次的修改生成patch:
# 注意:commitId为倒数第二个提交ID
git diff commitId > commit.patch
1.2 apply应用patch
生成patch文件后,我们切换到希望应用patch的分支,然后按下面的步骤操作:
# 检查patch是否可以应用
git apply --check commit.patch
# 打单个补丁
git apply commit.patch
# 打多个补丁
git apply ../patch/*.patch
打完补丁后再add/commit进行提交。
看下apply
命令的帮助文档:
usage: git apply [<options>] [<patch>...]--exclude <path> 应用补丁时排除指定的目录/文件--include <path> apply changes matching the given path-p <num> remove <num> leading slashes from traditional diff paths--no-add ignore additions made by the patch--stat 仅展示补丁差异内容--numstat show number of added and deleted lines in decimal notation--summary 仅对补丁生成总结报告--check 仅检查补丁是否可用--index make sure the patch is applicable to the current index-N, --intent-to-add mark new files with `git add --intent-to-add`--cached apply a patch without touching the working tree--unsafe-paths accept a patch that touches outside the working area--apply also apply the patch (use with --stat/--summary/--check)-3, --3way attempt three-way merge if a patch does not apply--build-fake-ancestor <file> build a temporary index based on embedded index information-z paths are separated with NUL character-C <n> ensure at least <n> lines of context match--whitespace <action> detect new or modified lines that have whitespace errors--ignore-space-change ignore changes in whitespace when finding context--ignore-whitespace ignore changes in whitespace when finding context-R, --reverse apply the patch in reverse--unidiff-zero don't expect at least one line of context--reject leave the rejected hunks in corresponding *.rej files--allow-overlap allow overlapping hunks-v, --verbose be verbose--inaccurate-eof tolerate incorrectly detected missing new-line at the end of file--recount do not trust the line counts in the hunk headers--directory <root> prepend <root> to all filenames
2. format-patch
/am
方案
这个方案是使用format-patch
命令生成一系列patch文件,然后使用am
命令批量应用patch。可以类比上一个方案进行理解,尤其是两个版本的概念是相同的。其大致流程如下:
# 生成patch
git format-patch -1
# 检查patch
git apply --check 0001-made-some-change.patch
# 应用patch
git am 0001-made-some-change.patch
为什么有了diff还要有format-patch呢?主要还是使用场景的不同:
- diff仅保留了文件重A状态变成B状态的差别,而不会保留commit记录消息等信息,而format-patch则是完整保留了每次提交的完成信息,这也解释了diff可以多个commit生成单个patch,而format-patch则是每个commit都生成一个patch文件。
- 两者是成对使用的,即
git apply
使用的补丁必须是git diff
生成的;git am
的补丁必须是git format-patch
生成的。当然补丁检查都是用git apply --check/--stat
。
2.1 format-patch生成patch
format-patch
命令是对指定版本范围内每次commit的修改生成对应的patch文件。
举个列子,现有如下提交历史的Git仓库:
D:\git_ws\test1>git log --pretty=oneline
4f499fc07597dcb5c7bb337116998a3e3e1f9116 (HEAD -> master) add third line
76a90ee80c67f310f6b6dc4b797cceedfa310368 add second line
ff53dd9d346dd3ab0013c0983160351d49a25024 Add simple.txt
我们对它执行如下命令:
D:\git_ws\test1>git format-patch ff53dd
0001-add-second-line.patch
0002-add-third-line.patch
可见生成了以下两个patch:
- 76a90e -> 0001-add-second-line.patch
- 4f499f -> 0002-add-third-line.patch
文件名格式:序号-消息第一行.patch
。另外值得说明的是,这个仓库其实本地已经修改了文件,但是没有commit,进一步验证了,format-patch
仅对commit后的修改生成patch。这其实也比较好理解,没有提交的话,连commit msg都没有,patch文件名都没法定了。
看下format-patch
命令的帮助文档:
usage: git format-patch [<options>] [<since> | <revision-range>]-n, --numbered use [PATCH n/m] even with a single patch-N, --no-numbered use [PATCH] even with multiple patches-s, --signoff add Signed-off-by:--stdout 指定输出位置,如所有patch输出到一个文件--cover-letter generate a cover letter--numbered-files 文件名只有编号,不包含提交信息--suffix <sfx> 指定patch文件名后缀,默认'.patch',比较常用的还有`.diff`--start-number <n> start numbering patches at <n> instead of 1-v, --reroll-count <n> mark the series as Nth re-roll--rfc Use [RFC PATCH] instead of [PATCH]--cover-from-description <cover-from-description-mode> generate parts of a cover letter based on a branch's description--subject-prefix <prefix> Use [<prefix>] instead of [PATCH]-o, --output-directory <dir> 指定patch的存放目录-k, --keep-subject don't strip/add [PATCH]--no-binary don't output binary diffs--zero-commit output all-zero hash in From header--ignore-if-in-upstream don't include a patch matching a commit upstream-p, --no-stat show patch format instead of default (patch + stat)
当前分支所有超前master的提交
git format-patch -M master
某次提交以后的所有patch
git format-patch commitId
从根到指定提交的所有patch
git format-patch --root commitId
某两次提交之间的所有patch
git format-patch commitId1..commitId2
某次提交(含)之前的几次提交
# -n指patch数
git format-patch -n commitId # 比如单次提交,生成commitId这次提交的patch
git format-patch -1 commitId# 生成commitId前一次到commitId这两次修改的patch
git format-patch -2 commitId
2.2 am应用patch
git am
可以一次合并一个文件,或者批量合并一个目录下所有的patch。在使用git am
之前, 你要首先git am --abort
一次,来放弃掉以前的am信息,这样才可以进行一次全新的am。不然会遇到这样的错误:
.git/rebase-apply still exists but mbox given.
具体操作如下:
- 打单个补丁
# 先检查patch文件:
git apply --stat newpatch.patch
# 检查能否应用成功:
git apply --check newpatch.patch
# 打补丁:使用-s或--signoff选项,可以commit信息中加入Signed-off-by信息
git am --signoff < newpatch.patch
- 批量应用补丁
git am --abort
git am patch/*.patch
am命令的使用说明如下:
usage: git am [<options>] [(<mbox> | <Maildir>)...]or: git am [<options>] (--continue | --skip | --abort)-(<mbox> | <Maildir>)... 补丁路径-i, --interactive run interactively-3, --3way allow fall back on 3way merging if needed-q, --quiet be quiet-s, --signoff add a Signed-off-by line to the commit message-u, --utf8 recode into utf8 (default)-k, --keep pass -k flag to git-mailinfo--keep-non-patch pass -b flag to git-mailinfo-m, --message-id pass -m flag to git-mailinfo--keep-cr pass --keep-cr flag to git-mailsplit for mbox format--no-keep-cr do not pass --keep-cr flag to git-mailsplit independent of am.keepcr-c, --scissors strip everything before a scissors line--whitespace <action> pass it through git-apply--ignore-space-change pass it through git-apply--ignore-whitespace pass it through git-apply--directory <root> pass it through git-apply--exclude <path> pass it through git-apply--include <path> pass it through git-apply-C <n> pass it through git-apply-p <num> pass it through git-apply--patch-format <format> format the patch(es) are in--reject pass it through git-apply--resolvemsg ... override error message when patch failure occurs--continue continue applying patches after resolving a conflict-r, --resolved synonyms for --continue--skip skip the current patch--abort restore the original branch and abort the patching operation.--quit abort the patching operation but keep HEAD where it is.--show-current-patch[=(diff|raw)] show the patch being applied--committer-date-is-author-date lie about committer date--ignore-date use current timestamp for author date--rerere-autoupdate update the index with reused conflict resolution if possible-S, --gpg-sign[=<key-id>] GPG-sign commits
3. cherry-pick方案
比如需要将feature分支的修改同步到master分支上:
# 切换到master分支
git checkout master
# 选择和应用具体需要同步的提交
git cherry-pick <commitId>...
参考资料
- 如何使用git 生成patch 和打入patch
Git patch的使用方法和场景相关推荐
- SVN patch的使用方法及场景
写目录 1. 客户端 1.1 相关功能菜单 1.1.1 `create patch` 1.1.2 `apply patch` 1.2 本次commit生成patch 1.3 多条commit合成pat ...
- git垃圾箱的使用方法
**git垃圾箱的使用方法** 应用场景:当我们编写代码的时候,写到一半,需要修改另外一个bug 应用命令: git stash //当前分支上本次修改的代码存入垃圾箱 git stash list ...
- 45 个 git 合代码的经典操作场景
点击上方"AI遇见机器学习",选择"星标"公众号 重磅干货,第一时间送达 今天我们整理了45个日常用git合代码的经典操作场景,基本覆盖了工作中的需求. git ...
- Git冲突与解决方法【转】
本文转载自:https://www.cnblogs.com/gavincoder/p/9071959.html Git冲突与解决方法 1.git冲突的场景 情景一:多个分支代码合并到一个分支时: 情景 ...
- 基于图像的三维重建——基于空间patch扩散的方法(PMVS)
1.PMVS:多视图匹配经典算法简介 导语:常见的稠密重建方法主要有三种:基于体素的方法.基于深度图融合的方法以及基于3D patch扩张的方法.第一种基于体素的方法仅适用于小场景,单个物体,遮挡较少 ...
- 更改git远程分支的方法
更改git远程分支的方法 Pull失败的解决方法:
- pycharm自带python.exe_Pycharm自带Git实现版本管理的方法步骤
之前一直使用本地的git客户端,通过命令来上传.下载代码到Gitlab:每次都需要启动git客户端,敲git命令来完成,不够灵活,因为强大的Pycharm就自带git功能,可以直接在Pycharm完成 ...
- IDEA导入Git项目后右键项目找不到Git选项的解决方法
IDEA导入Git项目后右键项目找不到Git选项的解决方法 参考文章: (1)IDEA导入Git项目后右键项目找不到Git选项的解决方法 (2)https://www.cnblogs.com/pret ...
- 终端中显示git分支名称的方法
终端中显示git分支名称的方法 大家好,我叫亓官劼(qí guān jié ),在CSDN中记录学习的点滴历程,时光荏苒,未来可期,加油~博客地址为:亓官劼的博客,B站昵称为:亓官劼,地址为亓官劼 ...
- git: patch 是什么/ 如何用
git patch 是什么/ 如何用 ref1 Git的Patch功能 http://www.cnblogs.com/y041039/articles/2411600.html note git提供了 ...
最新文章
- 全球最大医疗器械公司在中国寻找移动医疗新机会
- oracle数据源的报表sql计算慢解决
- JAVASE8流库Stream学习总结(三)
- session 对象的简单实例
- MS CRM 2011 RibbonExport Utility下载以及实用说明
- Sublime Text 2 中运行 PHP
- 根据谁创建资源授权资源
- TFS(Team Foundation Server)敏捷使用教程
- CentOS系统Kernel panic - not syncing: Attempted to k
- 疑似华为Mate 30 Pro上手视频曝光 看完更想买了!
- 编程 常用3500汉字 常用字符
- 基于javaSwing、MySQL的酒店客房管理系统(附源码)
- Layui环境下form表单提交;jquery.form.js;lay-verify,lay-filter;
- 能量景观(Energy landscape)
- android4.4 fragment,在Activity和多个Fragment之间共享资源
- 使用Atom编写以太坊智能合约
- 河南新华计算机学校学费多少,河南新华电脑学院提前三年收费 育人还是圈钱?...
- 计算机之父阿兰·图灵传奇的一生
- eclipse配置hadoop2.7.2开发环境并本地跑起来
- 《图解密码技术》——读书笔记
热门文章
- PPT插入形状,在里面填写文字,文本框过大
- windows添加虚拟机蓝屏的解决方法
- python打包时出现RecursionError: maximum recursion depth exceeded的解决方法
- 通过图书编号查询python_基于Python的图书ISBN查询接口调用代码实例
- 后台任务列表 App 界面模糊处理
- 教育部要求“强保障、上水平”,课后服务该如何提质增效?
- 倒计时3天!这届XIN公益大会很不一般!
- IDEA社区版下载与安装详细教程
- 深度学习论文翻译解析:YOLOv4: Optimal Speed and Accuracy of Object Detection
- 我们上语文英语音乐计算机和美术英语,“制作课程表”教学设计.ppt