<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom"><title>SSL的个人Blog - 随笔</title><link href="https://sunshanlu.github.io/sunshanlu/" rel="alternate"></link><link href="https://sunshanlu.github.io/sunshanlu/feeds/sui-bi.atom.xml" rel="self"></link><id>https://sunshanlu.github.io/sunshanlu/</id><updated>2025-06-30T00:00:00+08:00</updated><subtitle>记录开发随笔</subtitle><entry><title>git工具使用总结</title><link href="https://sunshanlu.github.io/sunshanlu/git-learn" rel="alternate"></link><published>2025-06-30T00:00:00+08:00</published><updated>2025-06-30T00:00:00+08:00</updated><author><name>孙善路-github</name></author><id>tag:sunshanlu.github.io,2025-06-30:/sunshanlu/git-learn</id><summary type="html">&lt;h2 id="1-git"&gt;1.&amp;nbsp;git仓库创建&lt;/h2&gt;
&lt;h3 id="11"&gt;1.1&amp;nbsp;本地创建并推送&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;git&lt;span class="w"&gt; &lt;/span&gt;init
git&lt;span class="w"&gt; &lt;/span&gt;remote&lt;span class="w"&gt; &lt;/span&gt;add&lt;span class="w"&gt; &lt;/span&gt;origin&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;your-ssh-or-https-url&amp;gt;

git&lt;span class="w"&gt; &lt;/span&gt;branch&lt;span class="w"&gt; &lt;/span&gt;-M&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;branch-name&amp;gt;&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="c1"&gt;# 推荐将分支名称设置为与origin一致&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;hello world&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;README.md&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="c1"&gt;# 替换成你实际对工作区的 …&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</summary><content type="html">&lt;h2 id="1-git"&gt;1.&amp;nbsp;git仓库创建&lt;/h2&gt;
&lt;h3 id="11"&gt;1.1&amp;nbsp;本地创建并推送&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;git&lt;span class="w"&gt; &lt;/span&gt;init
git&lt;span class="w"&gt; &lt;/span&gt;remote&lt;span class="w"&gt; &lt;/span&gt;add&lt;span class="w"&gt; &lt;/span&gt;origin&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;your-ssh-or-https-url&amp;gt;

git&lt;span class="w"&gt; &lt;/span&gt;branch&lt;span class="w"&gt; &lt;/span&gt;-M&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;branch-name&amp;gt;&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="c1"&gt;# 推荐将分支名称设置为与origin一致&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;hello world&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;README.md&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="c1"&gt;# 替换成你实际对工作区的操作&lt;/span&gt;
git&lt;span class="w"&gt; &lt;/span&gt;add&lt;span class="w"&gt; &lt;/span&gt;.&lt;span class="w"&gt;                           &lt;/span&gt;&lt;span class="c1"&gt;# 添加到暂存区&lt;/span&gt;
git&lt;span class="w"&gt; &lt;/span&gt;commit&lt;span class="w"&gt; &lt;/span&gt;-m&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;your commit message&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;# 将展存区的内容添加到本地存储库 &lt;/span&gt;
git&lt;span class="w"&gt; &lt;/span&gt;push&lt;span class="w"&gt; &lt;/span&gt;-u&lt;span class="w"&gt; &lt;/span&gt;origin&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;branch-name&amp;gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;# 将当前分支推送到远程仓库，推荐本地和远程之间的分支名称一致&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;注意：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;本地创建仓库的&lt;strong&gt;默认名称&lt;/strong&gt;为&lt;code&gt;master&lt;/code&gt;，&lt;code&gt;git branch -M&lt;/code&gt;操作是强制对一个分支进行重命名，等同于&lt;code&gt;git branch --move --force&lt;/code&gt;操作。&lt;/li&gt;
&lt;li&gt;在执行&lt;code&gt;git remote&lt;/code&gt; 和&lt;code&gt;git push&lt;/code&gt;操作之前，需要保证远程仓库已经建立完成。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="12-clone"&gt;1.2&amp;nbsp;远程创建并&lt;code&gt;clone&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;更加推荐的一种方法，可以直接在&lt;code&gt;github&lt;/code&gt;或者&lt;code&gt;gitee&lt;/code&gt;等平台上创建仓库，然后通过&lt;code&gt;git clone&lt;/code&gt;命令完成&lt;code&gt;clone&lt;/code&gt;操作。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;git&lt;span class="w"&gt; &lt;/span&gt;clone&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;your-ssh-or-https-url&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;使用这种方式，可以保证你仓库的&lt;strong&gt;分支名称&lt;/strong&gt;、和&lt;strong&gt;远程仓库的关联关系&lt;/strong&gt;等保持一致。&lt;/p&gt;
&lt;h2 id="2"&gt;2.&amp;nbsp;本地代码存储逻辑&lt;/h2&gt;
&lt;h3 id="21"&gt;2.1&amp;nbsp;工作区遇到的问题&lt;/h3&gt;
&lt;p&gt;试想一下，你对&lt;strong&gt;工作区&lt;/strong&gt;中的内容作了某些修改，但是你发现修改的内容并不能修复你目前存在的问题，你想将修改的部分删除掉，应该怎么做呢？&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;git&lt;span class="w"&gt; &lt;/span&gt;restore&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;file&amp;gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="c1"&gt;# 对单独的某个文件做修改后的恢复操作&lt;/span&gt;
git&lt;span class="w"&gt; &lt;/span&gt;restore&lt;span class="w"&gt; &lt;/span&gt;.&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="c1"&gt;# 对整个工作区中产生修改的所有文件进行恢复操作&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;假设在工作区中，你新建了某个文件，但是发现这个文件貌似没有起到什么作用，但恰好你不知道如何那个文件需要被删除，这里提供两种解决方案：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;使用&lt;code&gt;git status&lt;/code&gt;查看当前工作区状态，在&lt;strong&gt;未跟踪&lt;/strong&gt;部分找到新建的文件，然后使用系统文件管理功能针对性的删除文件。&lt;/li&gt;
&lt;li&gt;使用命令行的方式实现删除操作，当然是在清除需要删除的文件之后执行。&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;git&lt;span class="w"&gt; &lt;/span&gt;clean&lt;span class="w"&gt; &lt;/span&gt;-f&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;file&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;# 删除某个文件&lt;/span&gt;
git&lt;span class="w"&gt; &lt;/span&gt;clean&lt;span class="w"&gt; &lt;/span&gt;-df&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;dir&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;# 删除某个目录，递归删除&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;下面是&lt;code&gt;git clean&lt;/code&gt;命令常见的参数：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;-f&lt;/code&gt;：强制删除&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-i&lt;/code&gt;：在可交互模式下删除&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-d&lt;/code&gt;：对于某个文件夹，递归的删除&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="22"&gt;2.2&amp;nbsp;暂存区存储问题&lt;/h3&gt;
&lt;p&gt;我认为对于暂存区出现的任何问题都可以通过直接修改当前工作区，然后通过&lt;code&gt;git add&lt;/code&gt;命令添加到暂存区解决。不过这里我还是贴出某些问题的&lt;strong&gt;命令行&lt;/strong&gt;解决方法：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;工作区添加到暂存区的方法&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;git&lt;span class="w"&gt; &lt;/span&gt;add&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;file&amp;gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="c1"&gt;# 添加新文件或文件修改到暂存区&lt;/span&gt;
git&lt;span class="w"&gt; &lt;/span&gt;add&lt;span class="w"&gt; &lt;/span&gt;.&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="c1"&gt;# 添加所有更改和新创建文件到暂存区&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;添加到暂存区后,出现问题,如何修改?&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;git&lt;span class="w"&gt; &lt;/span&gt;reset&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;file&amp;gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;# 撤销某个指定文件的暂存区的更改&lt;/span&gt;
git&lt;span class="w"&gt; &lt;/span&gt;reset&lt;span class="w"&gt; &lt;/span&gt;.&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="c1"&gt;# 撤销暂存区的所有更改&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3 id="23"&gt;2.3&amp;nbsp;本地版本库存储问题&lt;/h3&gt;
&lt;p&gt;当团队组合开发某个应用功能时，需要&lt;strong&gt;创建&lt;/strong&gt;新分支，然后当某个分支合并完成后，需要将一个分支进行&lt;strong&gt;删除&lt;/strong&gt;时应该如何操作呢？&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;git&lt;span class="w"&gt; &lt;/span&gt;checkout&lt;span class="w"&gt; &lt;/span&gt;-b&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;new-branch-name&amp;gt;&lt;span class="w"&gt;           &lt;/span&gt;&lt;span class="c1"&gt;# 以当前HEAD指向的commit为起始点，创建并切换到分支下&lt;/span&gt;
git&lt;span class="w"&gt; &lt;/span&gt;branch&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;new-branch-name&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;commit&amp;gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="c1"&gt;# 以某次提交为起始点，创建分支，不切换&lt;/span&gt;
git&lt;span class="w"&gt; &lt;/span&gt;branch&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;new-branch-name&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;branch-name&amp;gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="c1"&gt;# 以branch指向的commit为起始点，创建分支，不切换&lt;/span&gt;
git&lt;span class="w"&gt; &lt;/span&gt;branch&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;new-branch-name&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;tag-name&amp;gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="c1"&gt;# 以某个tag指向的commit为起始点，创建分支，不切换&lt;/span&gt;
git&lt;span class="w"&gt; &lt;/span&gt;branch&lt;span class="w"&gt; &lt;/span&gt;-d&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;branch-name&amp;gt;&lt;span class="w"&gt;                 &lt;/span&gt;&lt;span class="c1"&gt;# 删除某个分支&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;有一种比较清晰的&lt;code&gt;branch&lt;/code&gt;管理方法，即使用&lt;code&gt;name/task&lt;/code&gt;的命令方式，&lt;code&gt;name&lt;/code&gt;对应实际的人名，而&lt;code&gt;task&lt;/code&gt;代表这个人在这个分支下需要完成的人物，这样比较清晰明了，并且当其完成某个任务后，可以为这个分支打上一个&lt;code&gt;name/task&lt;/code&gt;的&lt;code&gt;tag&lt;/code&gt;标签这么作有以下两个好处：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;当&lt;code&gt;task&lt;/code&gt;没有完成时，分支跟着&lt;code&gt;commit&lt;/code&gt;向前滚动，可以明确当前时间下，哪个人员在作哪些事情。&lt;/li&gt;
&lt;li&gt;当&lt;code&gt;task&lt;/code&gt;完成后，可以将最终的&lt;code&gt;commit&lt;/code&gt;标记为一个&lt;code&gt;tag&lt;/code&gt;，做到工作留痕，并可以在未完成时（经过市场验证，发现解决的不是特别好），可以根据这个&lt;code&gt;tag&lt;/code&gt;回滚，继续完善这个任务。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;当团队协作过程中，某个人在&lt;code&gt;name/task&lt;/code&gt;分支下，完成了功能开发以后，经测试没问题，进行向主分支合并时，或许会遇到一些问题：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;当&lt;code&gt;main&lt;/code&gt;分支指向的提交为&lt;code&gt;name/task&lt;/code&gt;指向提交的直接祖先时，&lt;code&gt;git&lt;/code&gt;默认会采用&lt;code&gt;fast forward&lt;/code&gt;策略，不创建提交，而是直接将&lt;code&gt;main&lt;/code&gt;指向&lt;code&gt;name/task&lt;/code&gt;指向的提交。&lt;/li&gt;
&lt;li&gt;当&lt;code&gt;name/task&lt;/code&gt;分支在解决问题，不断的创建提交的过程中，&lt;code&gt;main&lt;/code&gt;分支也在不断的被更新创建提交时，会出现以下两种情况：&lt;/li&gt;
&lt;li&gt;当分支&lt;code&gt;name/task&lt;/code&gt;和&lt;code&gt;main&lt;/code&gt;同时拥有的文件&lt;strong&gt;没有发生改变时&lt;/strong&gt;，将无冲突发生，&lt;code&gt;git merge&lt;/code&gt;会默认合并到&lt;code&gt;main&lt;/code&gt;分支中去，中间会创建新的commit。&lt;/li&gt;
&lt;li&gt;当分支&lt;code&gt;name/task&lt;/code&gt;和&lt;code&gt;main&lt;/code&gt;同时拥有的文件同时发生了修改时，将有冲突发生，&lt;code&gt;git merge&lt;/code&gt;会将冲突产生的文件里面的内容进行标记，并放在暂存区，等待用户解决。&lt;/li&gt;
&lt;li&gt;当&lt;code&gt;git merge&lt;/code&gt;命令可以自己合并分支时，如果产生了提交，&lt;code&gt;git merge&lt;/code&gt;会自动生成提交语句，如果用户想自定义这个提交应该怎么解决？使用下面的命令即可解决这个问题。&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;git&lt;span class="w"&gt; &lt;/span&gt;merge&lt;span class="w"&gt; &lt;/span&gt;--no-commit&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;name/task&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;# 前提保证目前HEAD指向的是main分支&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;代码里面，&lt;code&gt;--no-commit&lt;/code&gt;参数代表的意思是不需要默认提交，而是将修改放到暂存区，等到用户边界提交内容后，再统一提交。&lt;/li&gt;
&lt;li&gt;当存在冲突时，&lt;code&gt;--no-commit&lt;/code&gt;没有任何作用，因为冲突需要用户手动处理，不会默认提交。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;当你刚提交完某个&lt;code&gt;commit&lt;/code&gt;到本地后，发现&lt;code&gt;comment content&lt;/code&gt;并不满意，无法体现你所做工作的内容，因此你想修改这个提交内容，应该怎么做呢？下面是解决思路：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;git&lt;span class="w"&gt; &lt;/span&gt;reset&lt;span class="w"&gt; &lt;/span&gt;--soft&lt;span class="w"&gt; &lt;/span&gt;HEAD^&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;# 将当前分支回退到commit之前&lt;/span&gt;
git&lt;span class="w"&gt; &lt;/span&gt;add&lt;span class="w"&gt; &lt;/span&gt;.
git&lt;span class="w"&gt; &lt;/span&gt;commit&lt;span class="w"&gt; &lt;/span&gt;-m&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&amp;lt;your-new-commit-conten&amp;gt;&amp;quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;注意：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;--soft&lt;/code&gt;表示不删除工作区文件，退回到指定commit之后，工作区的内容并没有发生修改&lt;/li&gt;
&lt;li&gt;保证最近提交没有同步到远程仓库，否则reset后，提交到远程仓库会失败&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="24-committag"&gt;2.4&amp;nbsp;提交&lt;code&gt;commit&lt;/code&gt;的别名&lt;code&gt;tag&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;经常逛&lt;code&gt;github&lt;/code&gt;的你，肯定会发现，某个存储库，除了使用&lt;code&gt;branch&lt;/code&gt;以外，还会有一个名为&lt;code&gt;tag&lt;/code&gt;的东西，这是什么？&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;tag&lt;/code&gt;是一个&lt;code&gt;commit&lt;/code&gt;的类型别名，当使用某个&lt;code&gt;commit&lt;/code&gt;创建了&lt;code&gt;tag&lt;/code&gt;后，这个&lt;code&gt;tag&lt;/code&gt;就不会随着&lt;code&gt;commit&lt;/code&gt;的增加而更新指向了&lt;/li&gt;
&lt;li&gt;&lt;code&gt;branch&lt;/code&gt;会随着&lt;code&gt;commit&lt;/code&gt;的不断更新维护所有的提交，并维护的最后一个&lt;code&gt;commit&lt;/code&gt;，这是&lt;code&gt;branch&lt;/code&gt;与&lt;code&gt;tag&lt;/code&gt;之间最大的区别&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;git&lt;span class="w"&gt; &lt;/span&gt;tag&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;your-tag-name&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;commit-hash&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;-m&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&amp;lt;your-tag-desc-message&amp;gt;&amp;quot;&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="c1"&gt;# 以某个commit添加tag&lt;/span&gt;
git&lt;span class="w"&gt; &lt;/span&gt;tag&lt;span class="w"&gt; &lt;/span&gt;-d&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;your-tag-name&amp;gt;&lt;span class="w"&gt;                                          &lt;/span&gt;&lt;span class="c1"&gt;# 删除tag&lt;/span&gt;
git&lt;span class="w"&gt; &lt;/span&gt;push&lt;span class="w"&gt; &lt;/span&gt;origin&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;your-tag-name&amp;gt;&lt;span class="w"&gt;                                     &lt;/span&gt;&lt;span class="c1"&gt;# 推送tag到远程仓库&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h2 id="3"&gt;3.&amp;nbsp;远程仓库存储逻辑&lt;/h2&gt;
&lt;h3 id="31"&gt;3.1&amp;nbsp;本地与远程的同步操作&lt;/h3&gt;
&lt;p&gt;远程到本地的同步操作：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="c1"&gt;# 存储库同步操作&lt;/span&gt;
git&lt;span class="w"&gt; &lt;/span&gt;clone&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;your-remote-repo-url&amp;gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;# 本地向远程同步所有存储库内容&lt;/span&gt;

&lt;span class="c1"&gt;# 分支同步操作&lt;/span&gt;
git&lt;span class="w"&gt; &lt;/span&gt;pull&lt;span class="w"&gt;                            &lt;/span&gt;&lt;span class="c1"&gt;# 从远程仓库中拉取merge所有更新(tag、branch、commit)&lt;/span&gt;
git&lt;span class="w"&gt; &lt;/span&gt;pull&lt;span class="w"&gt; &lt;/span&gt;origin&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;your-branch-name&amp;gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="c1"&gt;# 同步指定分支，拉取并merge，同名分支&lt;/span&gt;
git&lt;span class="w"&gt; &lt;/span&gt;pull&lt;span class="w"&gt; &lt;/span&gt;origin&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;remote-branch&amp;gt;:&amp;lt;local-branch&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;# 拉取并merge指定分支，不同名分支(不推荐)&lt;/span&gt;

git&lt;span class="w"&gt; &lt;/span&gt;fetch&lt;span class="w"&gt;                           &lt;/span&gt;&lt;span class="c1"&gt;# 从远程仓库中拉取所有更新，但不merge&lt;/span&gt;
git&lt;span class="w"&gt; &lt;/span&gt;fetch&lt;span class="w"&gt; &lt;/span&gt;origin&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;your-branch-name&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;# 拉取指定分支，不merge，同名分支&lt;/span&gt;
git&lt;span class="w"&gt; &lt;/span&gt;fetch&lt;span class="w"&gt; &lt;/span&gt;origin&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;remote-branch&amp;gt;:&amp;lt;local-branch&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;# 拉取指定分支，不merge，不同名分支(不推荐)&lt;/span&gt;

&lt;span class="c1"&gt;# tag同步操作&lt;/span&gt;
git&lt;span class="w"&gt; &lt;/span&gt;pull&lt;span class="w"&gt; &lt;/span&gt;origin&lt;span class="w"&gt; &lt;/span&gt;--tags&lt;span class="w"&gt;                              &lt;/span&gt;&lt;span class="c1"&gt;# 同步指定分支&lt;/span&gt;
git&lt;span class="w"&gt; &lt;/span&gt;pull&lt;span class="w"&gt; &lt;/span&gt;origin&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;tag-name&amp;gt;&lt;span class="w"&gt;                          &lt;/span&gt;&lt;span class="c1"&gt;# 同步指定tag，并且tag重名&lt;/span&gt;
git&lt;span class="w"&gt; &lt;/span&gt;pull&lt;span class="w"&gt; &lt;/span&gt;origin&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;remote-tag-name&amp;gt;:&amp;lt;local-tag-name&amp;gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="c1"&gt;# 同步指定tag，并且tag不同名&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;本地到远程的同步操作：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="c1"&gt;# 分支同步操作&lt;/span&gt;
git&lt;span class="w"&gt; &lt;/span&gt;push&lt;span class="w"&gt;                        &lt;/span&gt;&lt;span class="c1"&gt;# 当前HEAD指向的分支&lt;/span&gt;
git&lt;span class="w"&gt; &lt;/span&gt;push&lt;span class="w"&gt; &lt;/span&gt;origin&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;brach-name&amp;gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;# 推送指定分支到origin，同名&lt;/span&gt;
git&lt;span class="w"&gt; &lt;/span&gt;push&lt;span class="w"&gt; &lt;/span&gt;origin&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;local-branch-name&amp;gt;:&amp;lt;remote-branch-name&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;# 推送local-branch，不同名&lt;/span&gt;

git&lt;span class="w"&gt; &lt;/span&gt;push&lt;span class="w"&gt; &lt;/span&gt;origin&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;tag-name&amp;gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="c1"&gt;# 推送指定tag，同名&lt;/span&gt;
git&lt;span class="w"&gt; &lt;/span&gt;push&lt;span class="w"&gt; &lt;/span&gt;origin&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;local-tag-name&amp;gt;:&amp;lt;remote-tag-name&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;# 推送local-tag，不同名&lt;/span&gt;
git&lt;span class="w"&gt; &lt;/span&gt;push&lt;span class="w"&gt; &lt;/span&gt;origin&lt;span class="w"&gt; &lt;/span&gt;--tags&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="c1"&gt;# 推送所有tag&lt;/span&gt;

git&lt;span class="w"&gt; &lt;/span&gt;push&lt;span class="w"&gt; &lt;/span&gt;--delete&lt;span class="w"&gt; &lt;/span&gt;origin&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;branch-name&amp;gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="c1"&gt;# 删除远程分支操作&lt;/span&gt;
git&lt;span class="w"&gt; &lt;/span&gt;push&lt;span class="w"&gt; &lt;/span&gt;--delete&lt;span class="w"&gt; &lt;/span&gt;origin&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;tag-name&amp;gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="c1"&gt;# 删除远程tag&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3 id="32"&gt;3.2&amp;nbsp;远程冲突的解决&lt;/h3&gt;
&lt;p&gt;远程冲突的发生，往往是因为直接使用&lt;code&gt;git pull&lt;/code&gt;或者&lt;code&gt;git merge&lt;/code&gt;操作时，导致的冲突，原因都可以归结为&lt;code&gt;git merge&lt;/code&gt;操作，解决远程冲突与本地冲突一样，详情间&lt;strong&gt;2.3&lt;/strong&gt;本地合并的冲突问题。&lt;/p&gt;
&lt;h2 id="4"&gt;4.&amp;nbsp;其他内容&lt;/h2&gt;
&lt;h3 id="41-gitignoregitattributesgitsubmodule"&gt;4.1&amp;nbsp;gitignore和gitattributes和gitsubmodule&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;.gitignore&lt;/code&gt;文件定义了工作区间内，什么的文件或者文件夹不因该被&lt;code&gt;git&lt;/code&gt;所管理。对于&lt;code&gt;C++&lt;/code&gt;的项目来讲，&lt;code&gt;build&lt;/code&gt;文件夹下的编译内容不应该被管理，&lt;code&gt;.idea&lt;/code&gt;下的&lt;code&gt;IDE&lt;/code&gt;配置不应该被管理等等。此外，&lt;code&gt;.gitignore&lt;/code&gt;文件还支持正则表达式匹配。下面就是一个&lt;code&gt;C++&lt;/code&gt;项目的&lt;code&gt;.gitignore&lt;/code&gt;文件。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="c1"&gt;# 不同平台下，源文件编译生成的二进制文件&lt;/span&gt;
*.slo
*.lo
*.o
*.obj

&lt;span class="c1"&gt;# 预编译的头文件&lt;/span&gt;
*.gch
*.pch

&lt;span class="c1"&gt;# 编译的动态库文件&lt;/span&gt;
*.so
*.dylib
*.dll

&lt;span class="c1"&gt;# 编译的静态库文件&lt;/span&gt;
*.lai
*.la
*.a
*.lib

&lt;span class="c1"&gt;# 编译的可执行文件&lt;/span&gt;
*.exe
*.out
*.app

&lt;span class="c1"&gt;# 编译中间文件的文件夹&lt;/span&gt;
build/

&lt;span class="c1"&gt;# IDE生成的文件&lt;/span&gt;
.vscode/

&lt;span class="c1"&gt;# 可自行文件的文件夹&lt;/span&gt;
bin/

&lt;span class="c1"&gt;# 库文件文件夹&lt;/span&gt;
lib/
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;注意，对于不同分支下，可能会存在不同的&lt;code&gt;ignore&lt;/code&gt;操作，比如分支&lt;code&gt;a&lt;/code&gt;里面使用了&lt;code&gt;ros2&lt;/code&gt;完成了某项功能，而分支&lt;code&gt;b&lt;/code&gt;使用&lt;code&gt;ros&lt;/code&gt;完成了某项功能，两个分支&lt;code&gt;.gitignore&lt;/code&gt;应该都需要忽略&lt;code&gt;ros&lt;/code&gt;项目的&lt;code&gt;build devel log&lt;/code&gt;编译文件夹和&lt;code&gt;ros2&lt;/code&gt;项目的&lt;code&gt;build install logs&lt;/code&gt;文件夹，这种情况下，两分支下的&lt;code&gt;.gitignore&lt;/code&gt;应该保持一致，避免在切换分支时的&lt;strong&gt;误添加&lt;/strong&gt;操作。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;.gitattributes&lt;/code&gt;文件主要有以下说明：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;行尾符处理&lt;/strong&gt;，不同的操作系统，对换行符的理解存在差异，可以指定某些系统强相关的文件指定换行符为特定符号，例如指定&lt;code&gt;*.bat&lt;/code&gt;和&lt;code&gt;*.cmd&lt;/code&gt;结尾的windows脚本文件以&lt;code&gt;crlf&lt;/code&gt;结尾，而其余文件指定&lt;code&gt;lf&lt;/code&gt;为结尾，而对于可跨平台的文本文件，则在&lt;code&gt;IDE&lt;/code&gt;指定换行符即可。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;merge&lt;/code&gt;规则指定&lt;/strong&gt;，对于不同的文件，需要指定不同的合并规则，例如&lt;code&gt;*.md&lt;/code&gt;，&lt;code&gt;*.cpp&lt;/code&gt;等文本文件，应该使用&lt;code&gt;merge=text&lt;/code&gt;策略，将内容差异拼接到工作空间的对应文件夹中，进行人为的修改合并即可。而对于&lt;code&gt;binary&lt;/code&gt;文件，其并不会像&lt;code&gt;text&lt;/code&gt;文本文件那些将内容拼接，而是等待用户自行修改，可以选择传入新的文件，也可以使用&lt;code&gt;git checkout --ours&lt;/code&gt;或者&lt;code&gt;git checkout --theirs&lt;/code&gt;来选择当前&lt;code&gt;HEAD&lt;/code&gt;或者其他&lt;code&gt;commit&lt;/code&gt;中的文件。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;文件归档控制&lt;/strong&gt;，&lt;code&gt;git archive&lt;/code&gt;命令可以输出归档后的源文件信息，而某些文件不需要出现在源文件中，例如&lt;code&gt;.gitattributes&lt;/code&gt;文件，&lt;code&gt;.gitignore&lt;/code&gt;文件，文档文件夹，测试文件夹等都不需要归档打包，因此在&lt;code&gt;.gitattributes&lt;/code&gt;文件中，可以使用&lt;code&gt;export-ignore&lt;/code&gt;关键字进行声明；&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;一个比较成熟的项目&lt;code&gt;.gitattributes&lt;/code&gt;文件如下：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="c1"&gt;# 行尾符处理&lt;/span&gt;
*&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;text&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;auto
*.txt&lt;span class="w"&gt; &lt;/span&gt;text
*.md&lt;span class="w"&gt; &lt;/span&gt;text
*.cpp&lt;span class="w"&gt; &lt;/span&gt;text
*.h&lt;span class="w"&gt; &lt;/span&gt;text
*.py&lt;span class="w"&gt; &lt;/span&gt;text&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;eol&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;lf
*.sh&lt;span class="w"&gt; &lt;/span&gt;text&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;eol&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;lf

&lt;span class="c1"&gt;# windows脚本文件行尾说明&lt;/span&gt;
*.bat&lt;span class="w"&gt; &lt;/span&gt;text&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;eol&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;crlf
*.cmd&lt;span class="w"&gt; &lt;/span&gt;text&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;eol&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;crlf

&lt;span class="c1"&gt;# 二进制文件，即当merge时，采用binary合并策略&lt;/span&gt;
*.png&lt;span class="w"&gt; &lt;/span&gt;binary
*.jpg&lt;span class="w"&gt; &lt;/span&gt;binary
*.pdf&lt;span class="w"&gt; &lt;/span&gt;binary
*.exe&lt;span class="w"&gt; &lt;/span&gt;binary

&lt;span class="c1"&gt;# 合并策略声明&lt;/span&gt;
*.conf&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;merge&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;union

&lt;span class="c1"&gt;# 归档控制 - 排除开发相关文件&lt;/span&gt;
.gitignore&lt;span class="w"&gt; &lt;/span&gt;export-ignore
.gitattributes&lt;span class="w"&gt; &lt;/span&gt;export-ignore

&lt;span class="c1"&gt;# 归档控制 - 排除测试和文档目录&lt;/span&gt;
tests/&lt;span class="w"&gt; &lt;/span&gt;export-ignore
docs/&lt;span class="w"&gt; &lt;/span&gt;export-ignore
examples/&lt;span class="w"&gt; &lt;/span&gt;export-ignore

&lt;span class="c1"&gt;# 归档控制 - 排除构建相关目录&lt;/span&gt;
*.log&lt;span class="w"&gt; &lt;/span&gt;export-ignore
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;export-ignore&lt;/code&gt;在归档时，控制着&lt;code&gt;commit&lt;/code&gt;中忽视的内容&lt;/li&gt;
&lt;li&gt;&lt;code&gt;git archive -o xxx/xxx.tar.gz [commit]&lt;/code&gt;，会查看&lt;code&gt;.gitattributes&lt;/code&gt;文家里面有关的归档操作。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;.gitattributes&lt;/code&gt;文件里面的等号相连之间&lt;strong&gt;不能存在空格&lt;/strong&gt;，否则为非法，就像&lt;code&gt;json&lt;/code&gt;文件里面不能使用单引号表示字符串一样。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;code&gt;.gitsubmodules&lt;/code&gt;文件用于管理项目下的子模块,其主要在以下几种情况下比较有用:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;当子模块和当前项目都是你们自己团队的任务时,你们可以同时对子模块和当前项目进行开发;&lt;/li&gt;
&lt;li&gt;当子模块为项目依赖的某个开源三方库时,使用子模块操作,可以减少当前项目占用的仓库空间;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;为项目添加一个现有的子模块,可以使用下面的命令实现:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;git&lt;span class="w"&gt; &lt;/span&gt;submodule&lt;span class="w"&gt; &lt;/span&gt;add&lt;span class="w"&gt; &lt;/span&gt;-b&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;branch-name&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;--&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;url&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;path&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;branch-name&lt;/code&gt;为模块依赖的分支名称&lt;/li&gt;
&lt;li&gt;&lt;code&gt;url&lt;/code&gt;为模块对应的远程仓库地址&lt;/li&gt;
&lt;li&gt;&lt;code&gt;path&lt;/code&gt;为模块在项目工作空间存放的路径位置&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;当添加了某个子模块后,应该如何删除呢?&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;git&lt;span class="w"&gt; &lt;/span&gt;submodule&lt;span class="w"&gt; &lt;/span&gt;deinit&lt;span class="w"&gt; &lt;/span&gt;--&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;path&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;# 取消子模块与当前工作区间的关联&lt;/span&gt;
rm&lt;span class="w"&gt; &lt;/span&gt;-rf&lt;span class="w"&gt; &lt;/span&gt;.git/modules/&amp;lt;path&amp;gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="c1"&gt;# 删除.git下对于子模块的存储逻辑&lt;/span&gt;
nano&lt;span class="w"&gt; &lt;/span&gt;.gitmodules&lt;span class="w"&gt;               &lt;/span&gt;&lt;span class="c1"&gt;# 针对性的处理.gitmodules文件,对相关模型进行删除&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;当模块中的内容发生改变时,项目和子模块如何使用&lt;code&gt;git&lt;/code&gt;进行管理呢?&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nb"&gt;cd&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;submodule-path&amp;gt;
git&lt;span class="w"&gt; &lt;/span&gt;add&lt;span class="w"&gt; &lt;/span&gt;.
git&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;commit&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;m&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&amp;lt;module-commit-message&amp;gt;&amp;quot;&lt;/span&gt;
&lt;span class="nb"&gt;cd&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;project-path&amp;gt;
git&lt;span class="w"&gt; &lt;/span&gt;add&lt;span class="w"&gt; &lt;/span&gt;.
git&lt;span class="w"&gt; &lt;/span&gt;commit&lt;span class="w"&gt; &lt;/span&gt;-m&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&amp;lt;project-sync-module-message&amp;gt;&amp;quot;&lt;/span&gt;
git&lt;span class="w"&gt; &lt;/span&gt;push&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="c1"&gt;# 同步更新子模块远程仓库和项目远程仓库&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;当&lt;code&gt;clone&lt;/code&gt;某个带有子模块的项目时,应该同步&lt;code&gt;clone&lt;/code&gt;它的子模块呢?&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;git&lt;span class="w"&gt; &lt;/span&gt;clone&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;project-with-submodule&amp;gt;
git&lt;span class="w"&gt; &lt;/span&gt;submodule&lt;span class="w"&gt; &lt;/span&gt;update&lt;span class="w"&gt; &lt;/span&gt;--init&lt;span class="w"&gt; &lt;/span&gt;--recursive
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;--init&lt;/code&gt; 初始化子模块和项目关联&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--recursive&lt;/code&gt; 递归的处理所有子模块下的子模块&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="42-diff"&gt;4.2&amp;nbsp;diff操作查看文件差异&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;git&lt;span class="w"&gt; &lt;/span&gt;diff&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;commit&amp;gt;&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="c1"&gt;# 查看工作区和某次commit之间的差异&lt;/span&gt;
git&lt;span class="w"&gt; &lt;/span&gt;diff&lt;span class="w"&gt; &lt;/span&gt;--staged&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;commit&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;# 查看暂存区和某次commit之间的差异，默认为HEAD&lt;/span&gt;
git&lt;span class="w"&gt; &lt;/span&gt;diff&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;commit-a&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;commit-b&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;--&lt;span class="w"&gt; &lt;/span&gt;file&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;# 查看两个commit之间的file差异&lt;/span&gt;
git&lt;span class="w"&gt; &lt;/span&gt;diff&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;commit-a&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;commit-b&amp;gt;&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="c1"&gt;# 查看两个commot之间所有文件差异&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;针对两个&lt;code&gt;commit&lt;/code&gt;之间的差异，&lt;code&gt;&amp;lt;commit-a&amp;gt;&lt;/code&gt;为原始&lt;code&gt;commit&lt;/code&gt;而&lt;code&gt;&amp;lt;commit-b&amp;gt;&lt;/code&gt;为修改&lt;code&gt;commit&lt;/code&gt;，相当于查看&lt;code&gt;&amp;lt;commit-b&amp;gt;&lt;/code&gt;相比与&lt;code&gt;&amp;lt;commit-a&amp;gt;&lt;/code&gt;之间修改了什么内容。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--stat&lt;/code&gt;可选参数可以输出统计信息，即显示某个文件修改的行数，可以快速查看那些文件作了多少的修改，比较直观。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="43-log"&gt;4.3&amp;nbsp;log操作查看某次提交的提交记录&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;当直接使用&lt;code&gt;git log&lt;/code&gt;时，会将&lt;code&gt;HEAD&lt;/code&gt;指向的&lt;code&gt;commit&lt;/code&gt;对应的所有父级（包含其本身）对应的&lt;code&gt;commit&lt;/code&gt;对应的&lt;code&gt;hash&lt;/code&gt;值和&lt;code&gt;commit content&lt;/code&gt;内容打印出来（包括时间、作者和邮箱信息）。&lt;/li&gt;
&lt;li&gt;注意，这里的父级不仅包含同一&lt;code&gt;branch&lt;/code&gt;下的&lt;code&gt;commit&lt;/code&gt;关系，还包含了&lt;code&gt;merge&lt;/code&gt;后，&lt;code&gt;merge&lt;/code&gt;节点对应的&lt;code&gt;commit&lt;/code&gt;的父子关系。&lt;/li&gt;
&lt;li&gt;当&lt;code&gt;git log &amp;lt;commit/branch/tag&amp;gt;&lt;/code&gt;时，对应的都是其指向的&lt;code&gt;commit&lt;/code&gt;对应的所有父级（包含其本身）的&lt;code&gt;commit&lt;/code&gt;节点信息。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="44-rebase"&gt;4.4&amp;nbsp;团队合作谨用rebase操作&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;git rebase&lt;/code&gt; 一个比较危险的操作，它最普通的用法是可以将某个&lt;code&gt;branch&lt;/code&gt;的所有&lt;code&gt;commit&lt;/code&gt;的父&lt;code&gt;commit&lt;/code&gt;转换到指定的&lt;code&gt;commit&lt;/code&gt;下，也叫做&lt;code&gt;branch&lt;/code&gt;的换基操作。&lt;/li&gt;
&lt;li&gt;此外，交互式&lt;code&gt;rebase&lt;/code&gt;操作通过&lt;code&gt;-i&lt;/code&gt;选项打开，通过指定某个&lt;code&gt;commit&lt;/code&gt;，对其子&lt;code&gt;commit&lt;/code&gt;进行统一的修改操作&lt;/li&gt;
&lt;li&gt;&lt;code&gt;edit&lt;/code&gt;，对某个&lt;code&gt;commit&lt;/code&gt;提交的内容不满意，可以对这个&lt;code&gt;commit&lt;/code&gt;进行针对性的修改，然后使用&lt;code&gt;git rebase --continue&lt;/code&gt;继续&lt;/li&gt;
&lt;li&gt;&lt;code&gt;reword&lt;/code&gt;，对某个&lt;code&gt;commit&lt;/code&gt;提交的&lt;code&gt;commit message&lt;/code&gt;进行修改&lt;/li&gt;
&lt;li&gt;&lt;code&gt;squash&lt;/code&gt;，对多个&lt;code&gt;commit&lt;/code&gt;操作执行合并操作&lt;/li&gt;
&lt;li&gt;&lt;code&gt;fix-up&lt;/code&gt;，对多个&lt;code&gt;commit&lt;/code&gt;合并但丢弃提交信息&lt;/li&gt;
&lt;li&gt;&lt;code&gt;drop&lt;/code&gt;，删除提交，或者直接在交互界面删除某行即可。&lt;/li&gt;
&lt;li&gt;注意，&lt;code&gt;git rebase&lt;/code&gt;操作会在指定的&lt;code&gt;upstream&lt;/code&gt;的基础上，生成新的&lt;code&gt;commit&lt;/code&gt;，新生成的&lt;code&gt;commit&lt;/code&gt;的&lt;code&gt;commit hash&lt;/code&gt;发生了改变，因此当向远程推送时，远程仓库无法执行&lt;code&gt;fast forward&lt;/code&gt;的合并操作，会导致推送失败。因此当团队合作开发时，请谨慎使用&lt;code&gt;git rebase&lt;/code&gt;。&lt;/li&gt;
&lt;/ul&gt;</content><category term="随笔"></category><category term="git"></category></entry><entry><title>如何使用cmake构建一个自定义的可安装的库呢？</title><link href="https://sunshanlu.github.io/sunshanlu/cmake-build-your-lib" rel="alternate"></link><published>2025-03-01T00:00:00+08:00</published><updated>2025-03-01T00:00:00+08:00</updated><author><name>孙善路-github</name></author><id>tag:sunshanlu.github.io,2025-03-01:/sunshanlu/cmake-build-your-lib</id><summary type="html">&lt;h2 id="_1"&gt;背景&lt;/h2&gt;
&lt;p&gt;我觉得所有学习过某种编程语言的人，或多或少都希望自己构建一个可使用&lt;strong&gt;标准化流程&lt;/strong&gt;安装的三方库。当然我也不 …&lt;/p&gt;</summary><content type="html">&lt;h2 id="_1"&gt;背景&lt;/h2&gt;
&lt;p&gt;我觉得所有学习过某种编程语言的人，或多或少都希望自己构建一个可使用&lt;strong&gt;标准化流程&lt;/strong&gt;安装的三方库。当然我也不例外，我平时的大部分精力都会放在SLAM的学习上，我的想法是做一个简单方便的SLAM可视化小工具，用来帮助自己快速验证一个SLAM算法的效果和可行性。几个月前，我确实把一个名为&lt;a href="https://github.com/sunshanlu/SLAM_VIEWER"&gt;SLAM_VIEWER&lt;/a&gt;的小工具开源了出来。为了方便自己也是为了方便大家的使用，我希望我写的三方库可以像主流的三方库一样，能够使用一个&lt;strong&gt;标准化的编译和安装&lt;/strong&gt;流程，并能够在cmake中很方便地导入使用。在我查阅了cmake官方文档并奴役了许多AI后，得到了一套流程化的解决方案：&lt;/p&gt;
&lt;h2 id="_2"&gt;解决方案&lt;/h2&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="c"&gt;# CMakeLists.txt&lt;/span&gt;

&lt;span class="nb"&gt;cmake_minimum_required&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;VERSION&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;3.5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nb"&gt;project&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;slam_viewer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;VERSION&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;0.0.2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nb"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;CMAKE_CXX_STANDARD&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;17&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nb"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;CMAKE_CXX_STANDARD_REQUIRED&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;ON&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nb"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;NOT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;CMAKE_BUILD_TYPE&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nb"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;CMAKE_BUILD_TYPE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;Release&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nb"&gt;endif&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="nb"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;NOT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;DEFINED&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;BUILD_EXAMPLES&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nb"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;BUILD_EXAMPLES&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;ON&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nb"&gt;endif&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="nb"&gt;find_package&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;Pangolin&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;REQUIRED&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nb"&gt;find_package&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;Sophus&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;REQUIRED&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nb"&gt;find_package&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;PCL&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;REQUIRED&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nb"&gt;find_package&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;TBB&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;REQUIRED&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nb"&gt;find_package&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;OpenCV&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;REQUIRED&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nb"&gt;find_package&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;Eigen3&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;REQUIRED&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nb"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;CMAKE_RUNTIME_OUTPUT_DIRECTORY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;CMAKE_CURRENT_SOURCE_DIR&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;&lt;span class="s"&gt;/bin&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nb"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;CMAKE_LIBRARY_OUTPUT_DIRECTORY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;CMAKE_CURRENT_SOURCE_DIR&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;&lt;span class="s"&gt;/lib&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nb"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;CMAKE_ARCHIVE_OUTPUT_DIRECTORY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;CMAKE_CURRENT_SOURCE_DIR&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;&lt;span class="s"&gt;/lib&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nb"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;PACKAGE_INCLUDE_INSTALL_DIR&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;CMAKE_INSTALL_PREFIX&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;&lt;span class="s"&gt;/include&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nb"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;PACKAGE_LIBS_INSTALL_DIR&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;CMAKE_INSTALL_PREFIX&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;&lt;span class="s"&gt;/lib&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nb"&gt;include_directories&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;CMAKE_CURRENT_SOURCE_DIR&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;&lt;span class="s"&gt;/include&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nb"&gt;file&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;GLOB&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;SRC_FILES&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;CMAKE_CURRENT_SOURCE_DIR&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;&lt;span class="s"&gt;/src/*.cc&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nb"&gt;add_library&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;slam_viewer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;SHARED&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;SRC_FILES&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nb"&gt;target_link_libraries&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="s"&gt;slam_viewer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;PUBLIC&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;Pangolin_LIBRARY&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;PCL_LIBRARIES&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;Sophus::Sophus&lt;/span&gt;
&lt;span class="w"&gt;                       &lt;/span&gt;&lt;span class="s"&gt;TBB::tbb&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;OpenCV_LIBS&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;Eigen3::Eigen&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nb"&gt;target_include_directories&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="s"&gt;slam_viewer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;PUBLIC&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;OpenCV_INCLUDE_DIRS&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;PCL_INCLUDE_DIRS&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;                       &lt;/span&gt;&lt;span class="o"&gt;$&amp;lt;&lt;/span&gt;&lt;span class="nv"&gt;BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="w"&gt;                       &lt;/span&gt;&lt;span class="o"&gt;$&amp;lt;&lt;/span&gt;&lt;span class="nv"&gt;INSTALL_INTERFACE:include&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nb"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;BUILD_EXAMPLES&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nb"&gt;add_subdirectory&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;examples&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nb"&gt;endif&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="c"&gt;# 添加安装指令&lt;/span&gt;
&lt;span class="nb"&gt;install&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="s"&gt;TARGETS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;slam_viewer&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="s"&gt;EXPORT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;PROJECT_NAME&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;&lt;span class="s"&gt;Targets&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="s"&gt;LIBRARY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;DESTINATION&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;PACKAGE_LIBS_INSTALL_DIR&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="s"&gt;ARCHIVE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;DESTINATION&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;PACKAGE_LIBS_INSTALL_DIR&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nb"&gt;install&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;DIRECTORY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;PROJECT_SOURCE_DIR&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;&lt;span class="s"&gt;/include/slam_viewer&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="s"&gt;DESTINATION&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;PACKAGE_INCLUDE_INSTALL_DIR&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c"&gt;# 安装导出文件&lt;/span&gt;
&lt;span class="nb"&gt;install&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="s"&gt;EXPORT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;PROJECT_NAME&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;&lt;span class="s"&gt;Targets&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="s"&gt;FILE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;PROJECT_NAME&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;&lt;span class="s"&gt;Targets.cmake&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="s"&gt;NAMESPACE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;PROJECT_NAME&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;&lt;span class="s"&gt;::&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="s"&gt;DESTINATION&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;CMAKE_INSTALL_PREFIX&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;&lt;span class="s"&gt;/lib/cmake/&lt;/span&gt;&lt;span class="o"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;PROJECT_NAME&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c"&gt;# 生成并安装Config文件&lt;/span&gt;
&lt;span class="nb"&gt;include&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;CMakePackageConfigHelpers&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nb"&gt;write_basic_package_version_file&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="o"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;PROJECT_BINARY_DIR&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;&lt;span class="s"&gt;/&lt;/span&gt;&lt;span class="o"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;PROJECT_NAME&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;&lt;span class="s"&gt;ConfigVersion.cmake&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="s"&gt;VERSION&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;PROJECT_VERSION&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="s"&gt;COMPATIBILITY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;SameMajorVersion&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nb"&gt;configure_file&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;Config.cmake.in&lt;/span&gt;
&lt;span class="w"&gt;               &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;${PROJECT_BINARY_DIR}/${PROJECT_NAME}Config.cmake&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;@ONLY&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nb"&gt;install&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;FILES&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;PROJECT_BINARY_DIR&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;&lt;span class="s"&gt;/&lt;/span&gt;&lt;span class="o"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;PROJECT_NAME&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;&lt;span class="s"&gt;Config.cmake&lt;/span&gt;
&lt;span class="w"&gt;              &lt;/span&gt;&lt;span class="o"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;PROJECT_BINARY_DIR&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;&lt;span class="s"&gt;/&lt;/span&gt;&lt;span class="o"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;PROJECT_NAME&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;&lt;span class="s"&gt;ConfigVersion.cmake&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="s"&gt;DESTINATION&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;CMAKE_INSTALL_PREFIX&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;&lt;span class="s"&gt;/lib/cmake/&lt;/span&gt;&lt;span class="o"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;PROJECT_NAME&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c"&gt;# 输出配置信息，以查看是否配置正确&lt;/span&gt;
&lt;span class="nb"&gt;message&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;====================================================================&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nb"&gt;message&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;STATUS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;PROJECT_NAME&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;Configure:&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nb"&gt;message&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;STATUS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;CMAKE_BUILD_TYPE:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;CMAKE_BUILD_TYPE&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nb"&gt;message&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;STATUS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;BUILD_EXAMPLES:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;BUILD_EXAMPLES&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nb"&gt;message&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;STATUS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;CMAKE_INSTALL_PREFIX:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;CMAKE_INSTALL_PREFIX&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nb"&gt;message&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;====================================================================&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;上面的cmake代码是我根据这一套流程配置的slam_viewer库，其主要涵盖以下几个方面的内容：&lt;/p&gt;
&lt;h3 id="1-targets"&gt;1.&amp;nbsp;安装Targets和头文件目录&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nb"&gt;install&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;TARGETS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;slam_viewer&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="s"&gt;EXPORT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;PROJECT_NAME&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;&lt;span class="s"&gt;Targets&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="s"&gt;LIBRARY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;DESTINATION&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;PACKAGE_LIBS_INSTALL_DIR&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="s"&gt;ARCHIVE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;DESTINATION&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;PACKAGE_LIBS_INSTALL_DIR&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nb"&gt;install&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;DIRECTORY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;PROJECT_SOURCE_DIR&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;&lt;span class="s"&gt;/include/slam_viewer&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="s"&gt;DESTINATION&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;PACKAGE_INCLUDE_INSTALL_DIR&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;code&gt;install&lt;/code&gt;是&lt;code&gt;cmake&lt;/code&gt;中比较常用的一个命令，其作用主要是将某个&lt;strong&gt;文件夹&lt;/strong&gt;，&lt;strong&gt;某个文件&lt;/strong&gt;或者&lt;strong&gt;某些Target&lt;/strong&gt;安装到指定的位置。如果你需要安装的是某个目录，就需要使用&lt;code&gt;DIRECTORY&lt;/code&gt;关键字，并在后面跟上待文件夹的位置，然后使用&lt;code&gt;DESTINATION&lt;/code&gt;关键字来指定安装的位置。在标准工作流程里面，使用安装文件夹的命令，将头文件目录安装到&lt;code&gt;${PACKAGE_INCLUDE_INSTALL_DIR}&lt;/code&gt;位置，其中&lt;code&gt;${PACKAGE_INCLUDE_INSTALL_DIR}&lt;/code&gt;=&lt;code&gt;${CMAKE_INSTALL_PREFIX}/include&lt;/code&gt;，如果不指定&lt;code&gt;CMAKE_INSTALL_PREFIX&lt;/code&gt;的话，默认为&lt;code&gt;/usr/local&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;使用&lt;code&gt;install&lt;/code&gt;将&lt;code&gt;TARGETS&lt;/code&gt;安装到某个位置时就比较繁琐了，首先需要指定&lt;code&gt;TARGETS&lt;/code&gt;关键字，并在后面跟上需要安装的&lt;code&gt;target&lt;/code&gt;的名称（在&lt;code&gt;cmake&lt;/code&gt;中，可执行文件，库文件都是以&lt;code&gt;TARGET&lt;/code&gt;的形式维护）。&lt;code&gt;EXPORT&lt;/code&gt;关键字代表需要生成一个&lt;code&gt;TARGETS&lt;/code&gt;相关的依赖文件，这个依赖文件就是&lt;code&gt;${PROJECT_NAME}Targets.cmake&lt;/code&gt;。里面维护了&lt;code&gt;TARGETS&lt;/code&gt;中的依赖关系，主要有两个内容，一个是&lt;code&gt;INTERFACE_LINK_LIBRARIES&lt;/code&gt;，另一个是&lt;code&gt;INTERFACE_INCLUDE_DIRECTORIES&lt;/code&gt;。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;INTERFACE_LINK_LIBRARIES&lt;/code&gt;维护的是&lt;code&gt;TARGET&lt;/code&gt;所有依赖的动态库的&lt;code&gt;TARGET&lt;/code&gt;名字，这部分是通过解析&lt;code&gt;target_link_libraries&lt;/code&gt;指令内容生成的。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;INTERFACE_INCLUDE_DIRECTORIES&lt;/code&gt;维护的是&lt;code&gt;TARGET&lt;/code&gt;所有依赖的头文件的路径，这部分是通过解析&lt;code&gt;target_include_directories&lt;/code&gt;指令内容生成的。&lt;/li&gt;
&lt;li&gt;当然，只有使用&lt;code&gt;PUBLIC&lt;/code&gt;和&lt;code&gt;INTERFACE&lt;/code&gt;关键字指定的依赖才会被解析并放在&lt;code&gt;INTERFACE_LINK_LIBRARIES&lt;/code&gt;和&lt;code&gt;INTERFACE_INCLUDE_DIRECTORIES&lt;/code&gt;中。&lt;/li&gt;
&lt;li&gt;这里并不会对&lt;code&gt;PUBLIC&lt;/code&gt;、&lt;code&gt;INTERFACE&lt;/code&gt;和&lt;code&gt;PRIVATE&lt;/code&gt;关键字进行解析，网上也有很多这方面的资料可以参考。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;下面是&lt;code&gt;slam_viewerTargets.cmake&lt;/code&gt;文件的部分截图，这部分内容相当&lt;strong&gt;重要&lt;/strong&gt;，或者中可以通过这个&lt;code&gt;xxxTargets.cmake&lt;/code&gt;文件来找到三方库的&lt;code&gt;Target&lt;/code&gt;信息，并且可以明确这个&lt;code&gt;Target&lt;/code&gt;的依赖关系。&lt;/p&gt;
&lt;div align="center"&gt;
    &lt;img src="https://sunshanlu.github.io/sunshanlu/images/target-cmake.png" alt="xxxTargets.cmake" width="100%"&gt;
&lt;/div&gt;

&lt;h3 id="2-target"&gt;2.&amp;nbsp;安装导出的Target依赖文件到指定位置&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nb"&gt;install&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;EXPORT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;PROJECT_NAME&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;&lt;span class="s"&gt;Targets&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="s"&gt;FILE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;PROJECT_NAME&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;&lt;span class="s"&gt;Targets.cmake&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="s"&gt;NAMESPACE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;PROJECT_NAME&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;&lt;span class="s"&gt;::&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="s"&gt;DESTINATION&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;CMAKE_INSTALL_PREFIX&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;&lt;span class="s"&gt;/lib/cmake/&lt;/span&gt;&lt;span class="o"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;PROJECT_NAME&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;这一步主要是为了将&lt;code&gt;Target&lt;/code&gt;的依赖文件和&lt;code&gt;slam_viewerConfig.cmake&lt;/code&gt;文件导出到同一目录下方便&lt;code&gt;slam_viewerConfig.cmake&lt;/code&gt;文件的引用&lt;code&gt;include()&lt;/code&gt;操作。根据&lt;a href="https://cmake.org/cmake/help/latest/command/install.html#export"&gt;&lt;code&gt;cmake&lt;/code&gt;官方文档&lt;/a&gt;部分的说明，安装&lt;code&gt;TARGET&lt;/code&gt;的依赖文件必须使用带有&lt;code&gt;EXPORT&lt;/code&gt;关键字的安装命令，并且&lt;code&gt;EXPORT&lt;/code&gt;关键字后面与安装&lt;code&gt;TARGETS&lt;/code&gt;的&lt;code&gt;EXPORT&lt;/code&gt;关键字后面的内容保持一致，&lt;code&gt;FILE&lt;/code&gt;关键字后指定安装文件的文件名。&lt;code&gt;NAMESPACE&lt;/code&gt;关键字是一个可选的参数，如果带有&lt;code&gt;NAMESPACE&lt;/code&gt;，那么在其他依赖当前编译的三方库文件时，就需要在&lt;code&gt;Target&lt;/code&gt;名字前指定命名空间，在上面&lt;code&gt;slam_viewerTargets.cmake&lt;/code&gt;文件的部分截图中也能体现。在一定程度上，可以防止同名&lt;code&gt;TARGET&lt;/code&gt;的出现。&lt;/p&gt;
&lt;h3 id="3"&gt;3.&amp;nbsp;生成并安装配置文件&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nb"&gt;include&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;CMakePackageConfigHelpers&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nb"&gt;write_basic_package_version_file&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="o"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;PROJECT_BINARY_DIR&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;&lt;span class="s"&gt;/&lt;/span&gt;&lt;span class="o"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;PROJECT_NAME&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;&lt;span class="s"&gt;ConfigVersion.cmake&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="s"&gt;VERSION&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;PROJECT_VERSION&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="s"&gt;COMPATIBILITY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;SameMajorVersion&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nb"&gt;configure_file&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;Config.cmake.in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;${PROJECT_BINARY_DIR}/${PROJECT_NAME}Config.cmake&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;@ONLY&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nb"&gt;install&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;FILES&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;PROJECT_BINARY_DIR&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;&lt;span class="s"&gt;/&lt;/span&gt;&lt;span class="o"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;PROJECT_NAME&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;&lt;span class="s"&gt;Config.cmake&lt;/span&gt;
&lt;span class="w"&gt;              &lt;/span&gt;&lt;span class="o"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;PROJECT_BINARY_DIR&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;&lt;span class="s"&gt;/&lt;/span&gt;&lt;span class="o"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;PROJECT_NAME&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;&lt;span class="s"&gt;ConfigVersion.cmake&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="s"&gt;DESTINATION&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;CMAKE_INSTALL_PREFIX&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;&lt;span class="s"&gt;/lib/cmake/&lt;/span&gt;&lt;span class="o"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;PROJECT_NAME&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;首先需要引入&lt;code&gt;CMakePackageConfigHelpers&lt;/code&gt;模块，需要这个模块的&lt;code&gt;write_basic_package_version_file&lt;/code&gt;函数来写版本配置文件&lt;code&gt;xxxConfigVersion.cmake&lt;/code&gt;。其中&lt;code&gt;VERSION&lt;/code&gt;关键字后面跟项目版本号，&lt;code&gt;COMPATIBILITY&lt;/code&gt;关键字后面指定版本兼容信息，这里的版本兼容性可以为后续&lt;code&gt;find_package&lt;/code&gt;提供信息。一共有&lt;code&gt;AnyNewerVersion&lt;/code&gt;|&lt;code&gt;SameMajorVersion&lt;/code&gt;|&lt;code&gt;SameMinorVersion&lt;/code&gt;|&lt;code&gt;ExactVersion&lt;/code&gt;这四种版本兼容要求，其详细的内容解释可以看&lt;a href="https://cmake.org/cmake/help/latest/module/CMakePackageConfigHelpers.html#command:write_basic_package_version_file"&gt;&lt;code&gt;cmake&lt;/code&gt;文档&lt;/a&gt;。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;configure_file&lt;/code&gt;函数配置&lt;code&gt;xxxConfig.cmake&lt;/code&gt;文件，当我们使用&lt;code&gt;find_pacakge(xxx)&lt;/code&gt;函数来查找&lt;code&gt;xxx&lt;/code&gt;三方库时，&lt;code&gt;find_package&lt;/code&gt;函数会试图找到一个&lt;code&gt;xxxConfig.cmake&lt;/code&gt;或&lt;code&gt;xxxConfigVersion.cmake&lt;/code&gt;文件来判断是否找到了&lt;code&gt;xxx&lt;/code&gt;库。代码中&lt;code&gt;Config.cmake.in&lt;/code&gt;为配置&lt;code&gt;source&lt;/code&gt;文件路径，而&lt;code&gt;"${PROJECT_BINARY_DIR}/${PROJECT_NAME}Config.cmake"&lt;/code&gt;为配置&lt;code&gt;target&lt;/code&gt;文件路径，其中&lt;code&gt;@ONLY&lt;/code&gt;限定了替换的变量只能用&lt;code&gt;@&lt;/code&gt;符号包裹起来。&lt;code&gt;configure_file&lt;/code&gt;函数的一些实例内容解释可以看&lt;a href="https://cmake.org/cmake/help/latest/command/configure_file.html"&gt;&lt;code&gt;cmake&lt;/code&gt;文档&lt;/a&gt;。&lt;/p&gt;
&lt;p&gt;最后安装&lt;code&gt;xxxConfig.cmake&lt;/code&gt;和&lt;code&gt;xxxConfigVersion.cmake&lt;/code&gt;文件到指定位置即可。这个位置&lt;strong&gt;建议&lt;/strong&gt;和&lt;code&gt;xxxTargets.cmake&lt;/code&gt;的安装位置保持一致。&lt;/p&gt;
&lt;h3 id="4-configcmakein"&gt;4.&amp;nbsp;配置Config.cmake.in文件&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="c"&gt;# Config.cmake.in&lt;/span&gt;

&lt;span class="nb"&gt;include&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;CMakeFindDependencyMacro&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nb"&gt;find_dependency&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;Pangolin&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;REQUIRED&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nb"&gt;find_dependency&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;Sophus&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;REQUIRED&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nb"&gt;find_dependency&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;PCL&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;REQUIRED&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nb"&gt;find_dependency&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;TBB&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;REQUIRED&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nb"&gt;find_dependency&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;OpenCV&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;REQUIRED&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nb"&gt;find_dependency&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;Eigen3&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;REQUIRED&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nb"&gt;include&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;${CMAKE_CURRENT_LIST_DIR}/@PROJECT_NAME@Targets.cmake&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;最后需要配置&lt;code&gt;Config.cmake.in&lt;/code&gt;文件，在第3步中，&lt;code&gt;configure_file&lt;/code&gt;函数将&lt;code&gt;Config.cmake.in&lt;/code&gt;文件配置到&lt;code&gt;${PROJECT_BINARY_DIR}/${PROJECT_NAME}Config.cmake&lt;/code&gt;文件中，其中&lt;code&gt;@PROJECT_NAME@&lt;/code&gt;为&lt;code&gt;PROJECT_NAME&lt;/code&gt;变量，&lt;code&gt;${CMAKE_CURRENT_LIST_DIR}&lt;/code&gt;为当前&lt;code&gt;xxxConfig.cmake&lt;/code&gt;文件所在的目录。也就是为什么第3步的结尾建议要和&lt;code&gt;xxxTargets.cmake&lt;/code&gt;的安装装位置保持一致，如果不一致，这里&lt;code&gt;include()&lt;/code&gt;参数路径就需要更改。&lt;/p&gt;
&lt;p&gt;除此之外，还需要对自定义的三方库依赖的三方库进行配置，这里需要使用&lt;code&gt;find_dependency&lt;/code&gt;函数，而&lt;code&gt;find_dependency&lt;/code&gt;函数在模块&lt;code&gt;CMakeFindDependencyMacro&lt;/code&gt;中定义。配置好&lt;code&gt;find_dependency&lt;/code&gt;后，当其他库文件或者可执行文件依赖当前定义的库文件时，就不需要对自定义的三方库依赖的三方库进行&lt;code&gt;find_package&lt;/code&gt;操作了。&lt;/p&gt;
&lt;h3 id="5-interface_include_directories"&gt;5.&amp;nbsp;配置依赖自身的头文件路径的INTERFACE_INCLUDE_DIRECTORIES&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nb"&gt;target_include_directories&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="s"&gt;slam_viewer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;PUBLIC&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;OpenCV_INCLUDE_DIRS&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;PCL_INCLUDE_DIRS&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="o"&gt;$&amp;lt;&lt;/span&gt;&lt;span class="nv"&gt;BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="o"&gt;$&amp;lt;&lt;/span&gt;&lt;span class="nv"&gt;INSTALL_INTERFACE:include&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;在讲解这里的用法之前，我们需要理清楚一个比较重要的问题：&lt;/p&gt;
&lt;p&gt;在源码中可以看到，对某些库文件，没有使用&lt;code&gt;include_directories&lt;/code&gt;或者&lt;code&gt;target_include_directories&lt;/code&gt;明确指定它们的头文件路径，而有些库像&lt;code&gt;OpenCV&lt;/code&gt;和&lt;code&gt;PCL&lt;/code&gt;都需要在&lt;code&gt;CMakeLists.txt&lt;/code&gt;中&lt;strong&gt;明确指定&lt;/strong&gt;头文件路径。在第一部分讲到，如果你在&lt;code&gt;target_include_directories&lt;/code&gt;中指定了某些头文件路径，那么在导出的含有依赖关系的文件&lt;code&gt;xxxTargets.cmake&lt;/code&gt;中会有一个&lt;code&gt;INTERFACE_INCLUDE_DIRECTORIES&lt;/code&gt;，这里会维护这个&lt;code&gt;Target&lt;/code&gt;依赖的头文件路径。当某些库严格按照&lt;code&gt;target_include_directories&lt;/code&gt;来维护&lt;code&gt;Target&lt;/code&gt;的依赖关系时，导出的&lt;code&gt;xxxTargets.cmake&lt;/code&gt;文件中必然保存着该&lt;code&gt;Target&lt;/code&gt;依赖的所有头文件路径，因此这种库只需要使用&lt;code&gt;target_link_libraries&lt;/code&gt;函数即可搞定头文件依赖和库文件依赖关系。然而总有些三方库因为这样或者那样的原因，选择不使用&lt;code&gt;target_include_directories&lt;/code&gt;来维护头文件依赖关系，这种库往往都会提供一个&lt;code&gt;xxx_INCLUDE_DIRS&lt;/code&gt;这个变量，供调用者使用，因此遇到这种三方库依赖时，需要将&lt;code&gt;target_include_directories&lt;/code&gt;来单独维护这份头文件依赖，然后导入到自身的&lt;code&gt;INTERFACE_INCLUDE_DIRECTORIES&lt;/code&gt;中。&lt;/p&gt;
&lt;p&gt;我相信通过上面一段阐述的内容，同学们应该能理解为什么&lt;code&gt;OpenCV&lt;/code&gt;和&lt;code&gt;PCL&lt;/code&gt;库需要单独使用&lt;code&gt;target_include_directories&lt;/code&gt;来维护头文件依赖关系，而其他库则不需要。除此之外，&lt;code&gt;$&amp;lt;BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include&amp;gt;&lt;/code&gt;和&lt;code&gt;$&amp;lt;INSTALL_INTERFACE:include&amp;gt;&lt;/code&gt;这两个内容应该吸引了你的注意。根据&lt;a href="https://cmake.org/cmake/help/latest/command/target_include_directories.html#target-include-directories"&gt;&lt;code&gt;cmake&lt;/code&gt;官方文档&lt;/a&gt;的解释，以&lt;code&gt;$&amp;lt;BUILD_INTERFACE:&lt;/code&gt;开头的内容是声明构建过程中所需要的头文件依赖关系，并且后面需要跟绝对路径，而以&lt;code&gt;$&amp;lt;INSTALL_INTERFACE:&lt;/code&gt;开头的内容则是安装过程中的头文件依赖或者使用的头文件依赖，后面需要跟以&lt;code&gt;${CMAKE_INSTALL_PREFIX}$&lt;/code&gt;为前缀的&lt;strong&gt;相对路径&lt;/strong&gt;。在&lt;code&gt;xxxTargets.cmake&lt;/code&gt;中会忽略&lt;code&gt;$&amp;lt;BUILD_INTERFACE:&lt;/code&gt;开头的头文件依赖。而没有&lt;code&gt;$&amp;lt;&lt;/code&gt;开头的&lt;code&gt;CMAKE&lt;/code&gt;会认定这种头文件依赖发生在编译和安装使用过程，因此也会在&lt;code&gt;xxxTargets.cmake&lt;/code&gt;中保存下来。&lt;/p&gt;
&lt;h3 id="6"&gt;6.&amp;nbsp;如何使用？&lt;/h3&gt;
&lt;p&gt;根据上面的解释，我们不难理解所有的库文件依赖关系都在&lt;code&gt;xxxTargets.cmake&lt;/code&gt;维护的&lt;code&gt;INTERFACE_LINK_LIBRARIES&lt;/code&gt;中，而所有的头文件依赖关系都在&lt;code&gt;xxxTargets.cmake&lt;/code&gt;维护的&lt;code&gt;INTERFACE_INCLUDE_DIRECTORIES&lt;/code&gt;中，而在&lt;code&gt;xxxConfig.cmake&lt;/code&gt;中使用&lt;code&gt;find_dependency&lt;/code&gt;代替了&lt;code&gt;find_package&lt;/code&gt;函数来导入依赖库文件的&lt;code&gt;Target&lt;/code&gt;。因此使用自定义的&lt;code&gt;slam_viewer&lt;/code&gt;库时，只需要使用下面的两行代码就可以搞定，可以说非常的简单：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="c"&gt;# your project CMakeLists.txt&lt;/span&gt;

&lt;span class="nb"&gt;find_package&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;slam_viewer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;REQUIRED&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nb"&gt;target_link_libraries&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;lt;your_target&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;slam_viewer::slam_viewer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;div class="admonition important"&gt;
&lt;p class="admonition-title"&gt;标准流程？&lt;/p&gt;
&lt;p&gt;上面的内容，是我自己在看了网上的教程和一些通用三方库的CMakeLists.txt总结来的一套适合我自己使用的建库流程，当然这并不是唯一的建库方法。&lt;a href="https://cmake.org/cmake/help/latest/guide/tutorial/index.html"&gt;&lt;code&gt;cmake&lt;/code&gt;官方教程&lt;/a&gt;的&lt;code&gt;step9&lt;/code&gt;-&lt;code&gt;step11&lt;/code&gt;也是非常好的建库流程。我想说的是，无论使用什么样的方式，只要能实现一般三方库导入项目的功能，就是一个好的标准流程。我也非常希望我写的东西能对你有所帮助。&lt;/p&gt;
&lt;/div&gt;</content><category term="随笔"></category><category term="cmake"></category><category term="c++"></category><category term="library"></category></entry></feed>