-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathlocal-search.xml
167 lines (80 loc) · 96.3 KB
/
local-search.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
<?xml version="1.0" encoding="utf-8"?>
<search>
<entry>
<title>laravel-permission 中文翻译</title>
<link href="/articles/201811/chinese-translation-of-laravel-permission.html"/>
<url>/articles/201811/chinese-translation-of-laravel-permission.html</url>
<content type="html"><![CDATA[<p>初次接触到 <a href="https://github.com/spatie/laravel-permission" target="_blank" rel="noopener"><strong>spatie/laravel-permission</strong></a> 这个包,没找到中文文档,自己抽空翻译了一下,做了很小部分的删减,基本没影响。</p><h2 id="安装"><a href="#安装" class="headerlink" title="安装"></a>安装</h2><p>此扩展包适用于 Laravel 5.4 或更高版本。<br>可以用 composer 安装:<br><code>composer require spatie/laravel-permission</code><br>在 Laravel 5.5 中,服务提供器会被自动注册,而在早一点的版本中,需要手动添加服务提供器到<br><code>config/app.php</code> 中:</p><div class="hljs"><pre><code class="hljs php"><span class="hljs-string">'providers'</span> => [<span class="hljs-comment">// ...</span>Spatie\Permission\PermissionServiceProvider::class,];</code></pre></div><p>通过 <code>vendor:publish</code> 发布相关迁移文件:<br><code>php artisan vendor:publish --provider="Spatie\Permission\PermissionServiceProvider" --tag="migrations"</code><br>然后运行 <code>php artisan migrate</code> 生成相关数据表。<br>发布配置文件:<br><code>php artisan vendor:publish --provider="Spatie\Permission\PermissionServiceProvider" --tag="config"</code></p><h2 id="使用"><a href="#使用" class="headerlink" title="使用"></a>使用</h2><h3 id="使用概览"><a href="#使用概览" class="headerlink" title="使用概览"></a>使用概览</h3><ul><li><p>首先,需要添加 <code>Spatie\Permission\Traits\HasRoles</code> <strong>traits</strong> 到 <code>User</code> model(s):</p><div class="hljs"><pre><code class="hljs php"><span class="hljs-keyword">use</span> <span class="hljs-title">Spatie</span>\<span class="hljs-title">Permission</span>\<span class="hljs-title">Traits</span>\<span class="hljs-title">HasRoles</span>;<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">User</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Authenticatable</span></span><span class="hljs-class"></span>{<span class="hljs-keyword">use</span> <span class="hljs-title">HasRoles</span>;<span class="hljs-comment">// ...</span>}</code></pre></div><blockquote><p>Note: 如果要使用 <code>HasRoles</code> trait 到其它 model,需要添加属性 <code>protected $guard_name = 'web';</code>,否则会出现错误!</p></blockquote></li><li><p>此扩展包允许用户与权限和角色相关联,每一个角色关联多个权限,任意一个 Role 和 Permission 都是 Eloquent models。<br>可以通过 <code>create</code> 创建:</p><div class="hljs"><pre><code class="hljs php"><span class="hljs-keyword">use</span> <span class="hljs-title">Spatie</span>\<span class="hljs-title">Permission</span>\<span class="hljs-title">Models</span>\<span class="hljs-title">Role</span>;<span class="hljs-keyword">use</span> <span class="hljs-title">Spatie</span>\<span class="hljs-title">Permission</span>\<span class="hljs-title">Models</span>\<span class="hljs-title">Permission</span>;$role = Role::create([<span class="hljs-string">'name'</span> => <span class="hljs-string">'writer'</span>]);$permission = Permission::create([<span class="hljs-string">'name'</span> => <span class="hljs-string">'edit'</span>]);</code></pre></div><p>给角色分配一个或多个权限:</p><div class="hljs"><pre><code class="hljs php">$role->givePermissionTo(<span class="hljs-string">'edit'</span>);$role->givePermissionTo(<span class="hljs-string">'edit'</span>, <span class="hljs-string">'delete'</span>);$permission->assignRole($role);</code></pre></div><p>权限与角色 <strong>同步</strong>:</p><div class="hljs"><pre><code class="hljs php">$role->syncPermissions($permissions);$permission->syncRoles($roles);</code></pre></div><p>从角色移除一个权限:</p><div class="hljs"><pre><code class="hljs php">$role->revokePermissionTo($permission);$permission->removeRole($role);</code></pre></div></li></ul><p>如果你使用多个 guards,需要设置 <code>guard_name</code>。</p><ul><li><p><code>HasRoles</code> <strong>trait</strong> 为你的 model 添加了 Eloquent relationships,因此可直接使用这些关联方法:</p><div class="hljs"><pre><code class="hljs php"><span class="hljs-comment">// 获取直接分配给用户的所有权限</span>$permissions = $user->permissions;<span class="hljs-comment">// 获取用户的所有权限,包括直接分配的、通过角色继承的,或者两者全部</span>$permissions = $user->getDirectPermissions();$permissions = $user->getPermissionsViaRoles();$permissions = $user->getAllPermissions();<span class="hljs-comment">// 获取用户所有角色名称</span>$roles = $user->getRoleNames(); <span class="hljs-comment">// 返回一个集合(collection)</span></code></pre></div></li><li><p><code>HasRoles</code> trait 还提供了本地作用域, <code>role</code> 和 <code>permission</code> <strong>scope</strong>,去查询特定的角色或权限</p><div class="hljs"><pre><code class="hljs php">$users = User::role(<span class="hljs-string">'writer'</span>)->get(); <span class="hljs-comment">// 返回拥有 'writer' 角色的用户</span>$users = User::permission(<span class="hljs-string">'edit'</span>)->get(); <span class="hljs-comment">// 返回拥有特定权限的用户(包括直接分配的和通过角色继承的)</span></code></pre></div><blockquote><p><code>role</code> 和 <code>permission</code> <strong>scope</strong> 可接收字符串,角色(\Spatie\Permission\Models\Role)/权限(Permission)实体或集合(\Illuminate\Support\Collection)实体</p></blockquote></li></ul><h3 id="「直接」-权限"><a href="#「直接」-权限" class="headerlink" title="「直接」 权限"></a>「直接」 权限</h3><ul><li><p>权限可以分配给任何一个用户:</p><div class="hljs"><pre><code class="hljs php">$user->givePermissionTo(<span class="hljs-string">'edit'</span>);<span class="hljs-comment">// 一次赋予多个权限</span>$user->givePermissionTo(<span class="hljs-string">'edit'</span>, <span class="hljs-string">'delete'</span>);<span class="hljs-comment">// 也可传入一个数组</span>$user->givePermissionTo([<span class="hljs-string">'edit'</span>, <span class="hljs-string">'delete'</span>]);</code></pre></div></li><li><p>从用户移除权限:</p><div class="hljs"><pre><code class="hljs php">$user->revokePermissionTo(<span class="hljs-string">'edit'</span>);<span class="hljs-comment">// 同步权限,没有的权限会添加,不一致的会移除</span>$user->syncPermissions([<span class="hljs-string">'edit'</span>, <span class="hljs-string">'delete'</span>]);</code></pre></div></li><li><p>检测用户是否有某个权限:</p><div class="hljs"><pre><code class="hljs php">$user->hasPermissionTo(<span class="hljs-string">'edit'</span>);<span class="hljs-comment">// 或者传入权限的 id</span>$user->hasPermissionTo(<span class="hljs-string">'1'</span>);$user->hasPermissionTo(Permission::find(<span class="hljs-number">1</span>)->id);$user->hasPermissionTo($somePermission->id);</code></pre></div></li><li><p>判断用户是否具有一组权限中的任意一个或全部:</p><div class="hljs"><pre><code class="hljs php">$user->hasAnyPermission([<span class="hljs-string">'edit'</span>, <span class="hljs-string">'publish'</span>, <span class="hljs-string">'unpublish'</span>]);$user->hasAllPermissions([<span class="hljs-string">'edit'</span>, <span class="hljs-string">'publish'</span>, <span class="hljs-string">'unpublish'</span>]);<span class="hljs-comment">// 同样可以仅传入权限的 id</span>$user->hasAnyPermission([<span class="hljs-string">'edit'</span>, <span class="hljs-number">1</span>, <span class="hljs-number">5</span>]);</code></pre></div></li><li><p>保存的权限会被 <code>Illuminate\Auth\Access\Gate</code> 类注册为默认的 guard,所以可以用 Laravel 的 <code>can</code> 函数来检测权限:<br><code>$user->can('edit');</code></p></li></ul><h3 id="通过角色使用权限"><a href="#通过角色使用权限" class="headerlink" title="通过角色使用权限"></a>通过角色使用权限</h3><ul><li><p>一个角色可以赋予给任何用户:</p><div class="hljs"><pre><code class="hljs php">$user->assignRole(<span class="hljs-string">'writer'</span>);<span class="hljs-comment">// 一次赋予多个角色</span>$user->assignRole(<span class="hljs-string">'writer'</span>, <span class="hljs-string">'admin'</span>);<span class="hljs-comment">// 或者传入一个数组</span>$user->assignRole([<span class="hljs-string">'writer'</span>, <span class="hljs-string">'admin'</span>]);</code></pre></div></li><li><p>移除角色:<br><code>$user->removeRole('writer');</code></p></li><li><p>同步角色:<br>// 不一致的角色会被移除,替换为数组中提供的角色<br><code>$user->syncRoles(['writer', 'admin']);</code></p></li><li><p>检测用户是否具有特定角色,一个、任意或全部:</p><div class="hljs"><pre><code class="hljs php">$user->hasRole(<span class="hljs-string">'writer'</span>);$user->hasAnyRole(Role::all());$user->hasAllRoles(Role::all());</code></pre></div><blockquote><p>assignRole, hasRole, hasAnyRole, hasAllRoles 和 removeRole,这些函数可接收字符串、角色(<code>\Spatie\Permission\Models\Role</code>)实例、集合(<code>\Illuminate\Support\Collection</code>)实例</p></blockquote></li><li><p>给角色分配权限:<br><code>$role->givePermissionTo('edit articles');</code></p></li><li><p>检测:<br><code>$role->hasPermissionTo('edit articles');</code></p></li><li><p>从角色中移除权限:<br><code>$role->revokePermissionTo('edit articles');</code></p><blockquote><p>givePermissionTo 和 revokePermissionTo 函数可接收字符串或权限(<code>Spatie\Permission\Models\Permission</code>)实体</p></blockquote></li><li><p>权限会自动依附于角色,另外,权限也可直接分配给用户。比如下面的示例:</p><div class="hljs"><pre><code class="hljs php">$role = Role::findByName(<span class="hljs-string">'writer'</span>);$role->givePermissionTo(<span class="hljs-string">'edit articles'</span>);$user->assignRole(<span class="hljs-string">'writer'</span>);$user->givePermissionTo(<span class="hljs-string">'delete articles'</span>);</code></pre></div><p>例子中,用户拥有了 ‘edit articles’ 和 ‘delete articles’ 权限,edit 是通过角色,而 delete 是用户的直接权限,因为它是被直接分配的。<br>当我们调用 <code>$user->hasDirectPermission('delete articles')</code> 时,会返回 <code>true</code>,<br>而调用 <code>$user->hasDirectPermission('edit articles')</code> 会返回 <code>false</code>。</p><blockquote><p>在需要对用户的直接权限和角色权限分别操作时,这个方法是有用的。</p></blockquote></li><li><p>获取用户的权限:</p><div class="hljs"><pre><code class="hljs php"><span class="hljs-comment">// 「直接」 权限</span>$user->getDirectPermissions() <span class="hljs-comment">// 或者 $user->permissions;</span><span class="hljs-comment">// 继承自角色的权限</span>$user->getPermissionsViaRoles();<span class="hljs-comment">// 所有权限(直接的、继承的)</span>$user->getAllPermissions();</code></pre></div><p>结合上面的用例,第一个返回的结果会是 ‘delete articles’ 权限,第二个是 ‘edit articles’,第三个则是两个权限都有。</p><blockquote><p>注意:返回的结果都是权限(<code>Spatie\Permission\Models\Permission</code>)实例集合</p></blockquote></li></ul><h3 id="使用-Blade-指令"><a href="#使用-Blade-指令" class="headerlink" title="使用 Blade 指令"></a>使用 Blade 指令</h3><p>扩展包还添加了 <code>Blade</code> 指令来判断已登录用户是否具有某些角色。</p><p>可选的,你可以传入 <code>guard</code> 作为第二个参数来进行检测。</p><ul><li>Blade and Roles</li></ul><p>检测是否有特定角色:</p><div class="hljs"><pre><code class="hljs plain">@role('writer') I am a writer!@else I am not a writer...@endrole// 等同于@hasrole('writer') I am a writer!@else I am not a writer...@endhasrole</code></pre></div><p>检测是否有角色列表中的任意一个:</p><div class="hljs"><pre><code class="hljs plain">@hasanyrole($collectionOfRoles) I have one or more of these roles!@else I have none of these roles...@endhasanyrole// or@hasanyrole('writer|admin') I am either a writer or an admin or both!@else I have none of these roles...@endhasanyrole</code></pre></div><p>检测是否拥有所列的所有角色:</p><div class="hljs"><pre><code class="hljs plain">@hasallroles($collectionOfRoles) I have all of these roles!@else I do not have all of these roles...@endhasallroles// or@hasallroles('writer|admin') I am both a writer and an admin!@else I do not have all of these roles...@endhasallroles</code></pre></div><p>作为一种选择,还可使用 <code>@unlessrole</code> 对特定角色进行反向判断</p><div class="hljs"><pre><code class="hljs plain">@unlessrole('does not have this role') I do not have the role@else I do have the role@endunlessrole</code></pre></div><ul><li>Blade and Permissions</li></ul><p>扩展包没有添加任何权限相关的 Blade 指令,可以使用 Laravel 自带的 <code>@can</code> 指令来检测用户是否拥有特定权限</p><div class="hljs"><pre><code class="hljs plain">@can('edit articles') // ...@endcan// or@if(auth()->user()->can('edit articles') && $some_other_condition) // ...@endif</code></pre></div><h3 id="定义一个超级管理员-Super-Admin"><a href="#定义一个超级管理员-Super-Admin" class="headerlink" title="定义一个超级管理员(Super-Admin)"></a>定义一个超级管理员(Super-Admin)</h3><p>强烈建议:「超级管理员」 通过设定全局 <code>Gate::before</code> 规则来检测所有期望的角色。</p><p>这样就能实现在整个应用中使用基于权限操作的最佳实践,而不需要在所有地方总是要进行是否是 「超级管理员」 的检测。</p><p>看一个在应用中定义一个 <code>Super-Admin Gate</code> 规则的例子:<a href="https://github.com/spatie/laravel-permission/wiki/Global-%22Admin%22-role" target="_blank" rel="noopener">Defining a Super-Admin Gate rule</a></p><h3 id="最佳实践-–-roles-vs-permissions"><a href="#最佳实践-–-roles-vs-permissions" class="headerlink" title="最佳实践 – roles vs permissions"></a>最佳实践 – roles vs permissions</h3><p>只用 <strong>权限相关</strong> 的代码来构建你的应用通常是最好的。在这种方式中,你可以在应用的任何地方使用 Laravel 自带的 <code>@can</code> 和 <code>can()</code> 方法。</p><p><strong>角色</strong> 仍然可被用来划分权限对于简单的分配,在有必要时,你仍然能使用基于角色的辅助方法。<br>但是,大部分与应用相关的逻辑,通常使用 <code>can</code> 方法能被最好的控制,它能让 Laravel 的 <code>Gate</code> 层去做所有繁重的工作。</p><h3 id="多个-guards"><a href="#多个-guards" class="headerlink" title="多个 guards"></a>多个 guards</h3><p>当使用 Laravel 默认的 auth 配置,上面所有方法都可以解决常规需求,不需要额外的设置。</p><p>然而,当使用多个 guards 时,权限和角色的呈现就会像命名空间一样,那意味着每个 guard 会有它自己独有的一组权限和角色分配给用户。</p><ul><li>使用权限和角色 with multiple guards</li></ul><p>在创建新的权限或角色时,如果没有指定 guard,那么将会使用 <code>auth.guards</code> 配置数组中设置的第一个 guard。<br>若要为特定 guard 创建权限或角色,你必须指定 <code>guard_name</code>:</p><div class="hljs"><pre><code class="hljs php"><span class="hljs-comment">// Create a superadmin role for the admin users</span>$role = Role::create([<span class="hljs-string">'guard_name'</span> => <span class="hljs-string">'admin'</span>, <span class="hljs-string">'name'</span> => <span class="hljs-string">'superadmin'</span>]);<span class="hljs-comment">// Define a `publish articles` permission for the admin users belonging to the admin guard</span>$permission = Permission::create([<span class="hljs-string">'guard_name'</span> => <span class="hljs-string">'admin'</span>, <span class="hljs-string">'name'</span> => <span class="hljs-string">'publish articles'</span>]);<span class="hljs-comment">// Define a *different* `publish articles` permission for the regular users belonging to the web guard</span>$permission = Permission::create([<span class="hljs-string">'guard_name'</span> => <span class="hljs-string">'web'</span>, <span class="hljs-string">'name'</span> => <span class="hljs-string">'publish articles'</span>]);</code></pre></div><p>检测一个用户在指定 guard 下是否有某些权限:<br><code>$user->hasPermissionTo('publish articles', 'admin');</code></p><blockquote><p>Note: 当要决定一个角色/权限对于给定模型是否有效时,会按下面的顺序选择 guard :<br>1,此 model 中的 <code>$guard_name</code> 属性;2(暂定,不知道怎么翻),the guard in the config (through a provider);3,<code>auth.guards</code> 配置数组中设置的第一个 guard;4,<code>auth.defaults.guard</code> 中的设置。</p></blockquote><blockquote><p>Note: 当使用默认 <code>web</code> 之外的 guard 时,需要在你的 model 中声明 <code>$guard_name</code> 属性。</p></blockquote><blockquote><p>Note: 如果你的应用只用一个 guard,但并不是 <code>web</code>,那就改变 <code>config/app.php</code> 中所列 guards 的顺序,将你的 guard 放在 guards 列表的第一个,作为唯一默认。</p></blockquote><ul><li>分配权限或角色给 guard users</li></ul><p>你可以使用相同的方法来分配权限和角色给用户,只需要确认权限或角色的 <code>guard_name</code> 与用户的相匹配,否则会抛出一个 <code>GuardDoesNotMatch</code> 异常。</p><ul><li>使用 Blade 指令 with multiple guards</li></ul><p>你可以使用上面提到的所有 Blade 指令,需要传入你想使用的 guard 作为第二个参数。</p><div class="hljs"><pre><code class="hljs plain">@role('super-admin', 'admin') I am a super-admin!@else I am not a super-admin...@endrole</code></pre></div><h3 id="使用中间件"><a href="#使用中间件" class="headerlink" title="使用中间件"></a>使用中间件</h3><p>扩展包中还包含了几个中间件:<code>RoleMiddleware</code>、<code>PermissionMiddleware</code>、<code>RoleOrPermissionMiddleware</code>,你可以将它们加入到 <code>app/Http/Kernel.php</code> 中:</p><div class="hljs"><pre><code class="hljs php"><span class="hljs-keyword">protected</span> $routeMiddleware = [ <span class="hljs-comment">// ...</span> <span class="hljs-string">'role'</span> => \Spatie\Permission\Middlewares\RoleMiddleware::class, <span class="hljs-string">'permission'</span> => \Spatie\Permission\Middlewares\PermissionMiddleware::class, <span class="hljs-string">'role_or_permission'</span> => \Spatie\Permission\Middlewares\RoleOrPermissionMiddleware::class,];</code></pre></div><p>然后就可以使用它们来保护路由了:</p><div class="hljs"><pre><code class="hljs php">Route::group([<span class="hljs-string">'middleware'</span> => [<span class="hljs-string">'role:super-admin'</span>]], <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-params">()</span> </span>{ <span class="hljs-comment">//</span>});Route::group([<span class="hljs-string">'middleware'</span> => [<span class="hljs-string">'permission:publish articles'</span>]], <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-params">()</span> </span>{ <span class="hljs-comment">//</span>});Route::group([<span class="hljs-string">'middleware'</span> => [<span class="hljs-string">'role:super-admin'</span>,<span class="hljs-string">'permission:publish articles'</span>]], <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-params">()</span> </span>{ <span class="hljs-comment">//</span>});Route::group([<span class="hljs-string">'middleware'</span> => [<span class="hljs-string">'role_or_permission:super-admin'</span>]], <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-params">()</span> </span>{ <span class="hljs-comment">//</span>});Route::group([<span class="hljs-string">'middleware'</span> => [<span class="hljs-string">'role_or_permission:publish articles'</span>]], <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-params">()</span> </span>{ <span class="hljs-comment">//</span>});</code></pre></div><p>可选择地,在使用多个角色或权限时,可以用管道符(<strong><code>|</code></strong>)来隔开:</p><div class="hljs"><pre><code class="hljs php">Route::group([<span class="hljs-string">'middleware'</span> => [<span class="hljs-string">'role:super-admin|writer'</span>]], <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-params">()</span> </span>{ <span class="hljs-comment">//</span>});Route::group([<span class="hljs-string">'middleware'</span> => [<span class="hljs-string">'permission:publish articles|edit articles'</span>]], <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-params">()</span> </span>{ <span class="hljs-comment">//</span>});Route::group([<span class="hljs-string">'middleware'</span> => [<span class="hljs-string">'role_or_permission:super-admin|edit articles'</span>]], <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-params">()</span> </span>{ <span class="hljs-comment">//</span>});</code></pre></div><p>同样也可在控制器中使用,在其构造函数中设置想要的中间件即可:</p><div class="hljs"><pre><code class="hljs php"><span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">__construct</span><span class="hljs-params">()</span></span><span class="hljs-function"></span>{ <span class="hljs-keyword">$this</span>->middleware([<span class="hljs-string">'role:super-admin'</span>,<span class="hljs-string">'permission:publish articles|edit articles'</span>]);}<span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">__construct</span><span class="hljs-params">()</span></span><span class="hljs-function"></span>{ <span class="hljs-keyword">$this</span>->middleware([<span class="hljs-string">'role_or_permission:super-admin|edit articles'</span>]);}</code></pre></div><h4 id="捕捉角色或权限的异常"><a href="#捕捉角色或权限的异常" class="headerlink" title="捕捉角色或权限的异常"></a>捕捉角色或权限的异常</h4><p>如果要重写默认的 <code>403</code> 响应,可以用应用的异常处理来捕捉 <code>UnauthorizedException</code>:</p><div class="hljs"><pre><code class="hljs php"><span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">render</span><span class="hljs-params">($request, Exception $exception)</span></span><span class="hljs-function"></span>{ <span class="hljs-keyword">if</span> ($exception <span class="hljs-keyword">instanceof</span> \Spatie\Permission\Exceptions\UnauthorizedException) { <span class="hljs-comment">// Code here ...</span> } <span class="hljs-keyword">return</span> <span class="hljs-keyword">parent</span>::render($request, $exception);}</code></pre></div><h3 id="使用-Artisan-命令"><a href="#使用-Artisan-命令" class="headerlink" title="使用 Artisan 命令"></a>使用 Artisan 命令</h3><p>还可以在 console 端用 artisan 命令来创建角色或权限:</p><div class="hljs"><pre><code class="hljs bash">php artisan permission:create-role writerphp artisan permission:create-permission <span class="hljs-string">"edit articles"</span></code></pre></div><p>若要为特定 guard 创建权限或角色,则需要指定 guard 名称作为第二个参数:</p><div class="hljs"><pre><code class="hljs bash">php artisan permission:create-role writer webphp artisan permission:create-permission <span class="hljs-string">"edit articles"</span> web</code></pre></div><p>在创建角色时,可以同时创建并分配权限:</p><p><code>php artisan permission:create-role writer web "create articles|edit articles"</code></p><h2 id="单元测试-(暂不翻,还没学到单元测试)"><a href="#单元测试-(暂不翻,还没学到单元测试)" class="headerlink" title="单元测试 (暂不翻,还没学到单元测试)"></a>单元测试 (暂不翻,还没学到单元测试)</h2><p>In your application’s tests, if you are not seeding roles and permissions as part of your test setUp() then you may run into a chicken/egg situation where roles and permissions aren’t registered with the gate (because your tests create them after that gate registration is done). Working around this is simple: In your tests simply add a setUp() instruction to re-register the permissions, like this:</p><div class="hljs"><pre><code class="hljs php"><span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">setUp</span><span class="hljs-params">()</span></span><span class="hljs-function"></span>{ <span class="hljs-comment">// first include all the normal setUp operations</span> <span class="hljs-keyword">parent</span>::setUp(); <span class="hljs-comment">// now re-register all the roles and permissions</span> <span class="hljs-keyword">$this</span>->app->make(\Spatie\Permission\PermissionRegistrar::class)->registerPermissions();}</code></pre></div><h2 id="数据库填充-Seeding"><a href="#数据库填充-Seeding" class="headerlink" title="数据库填充(Seeding)"></a>数据库填充(Seeding)</h2><p>对于数据库填充有 2 点说明:</p><ol><li>在填充前最好先清除 <code>spatie.permission.cache</code> 缓存,避免缓存冲突出现错误。清除缓存可以通过一条 Artisan 命令来完成,或者直接在填充类中完成(看下面示例)。</li><li>下面示例中演示了清除缓存、创建权限并分配给角色:<div class="hljs"><pre><code class="hljs php"><span class="hljs-keyword">use</span> <span class="hljs-title">Illuminate</span>\<span class="hljs-title">Database</span>\<span class="hljs-title">Seeder</span>;<span class="hljs-keyword">use</span> <span class="hljs-title">Spatie</span>\<span class="hljs-title">Permission</span>\<span class="hljs-title">Models</span>\<span class="hljs-title">Role</span>;<span class="hljs-keyword">use</span> <span class="hljs-title">Spatie</span>\<span class="hljs-title">Permission</span>\<span class="hljs-title">Models</span>\<span class="hljs-title">Permission</span>;<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">RolesAndPermissionsSeeder</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Seeder</span></span><span class="hljs-class"></span>{ <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">run</span><span class="hljs-params">()</span></span><span class="hljs-function"> </span>{ <span class="hljs-comment">// Reset cached roles and permissions</span> app()[<span class="hljs-string">'cache'</span>]->forget(<span class="hljs-string">'spatie.permission.cache'</span>); <span class="hljs-comment">// create permissions</span> Permission::create([<span class="hljs-string">'name'</span> => <span class="hljs-string">'edit articles'</span>]); Permission::create([<span class="hljs-string">'name'</span> => <span class="hljs-string">'delete articles'</span>]); Permission::create([<span class="hljs-string">'name'</span> => <span class="hljs-string">'publish articles'</span>]); Permission::create([<span class="hljs-string">'name'</span> => <span class="hljs-string">'unpublish articles'</span>]); <span class="hljs-comment">// create roles and assign created permissions</span> $role = Role::create([<span class="hljs-string">'name'</span> => <span class="hljs-string">'writer'</span>]); $role->givePermissionTo(<span class="hljs-string">'edit articles'</span>); $role = Role::create([<span class="hljs-string">'name'</span> => <span class="hljs-string">'moderator'</span>]); $role->givePermissionTo([<span class="hljs-string">'publish articles'</span>, <span class="hljs-string">'unpublish articles'</span>]); $role = Role::create([<span class="hljs-string">'name'</span> => <span class="hljs-string">'super-admin'</span>]); $role->givePermissionTo(Permission::all()); }}</code></pre></div></li></ol><h2 id="扩展"><a href="#扩展" class="headerlink" title="扩展"></a>扩展</h2><p>如果需要 <strong>扩展</strong> 已有的 <code>Role</code> 和 <code>Permission</code> 模型,请注意:</p><ul><li>你的 <code>Role</code> model 需要继承自 <code>Spatie\Permission\Models\Role</code> model</li><li>你的 <code>Permission</code> model 需要继承自 <code>Spatie\Permission\Models\Permission</code> model</li></ul><p>如果需要 <strong>替换</strong> 已有的 <code>Role</code> 和 <code>Permission</code> 模型,请注意:</p><ul><li>你的 <code>Role</code> model 需要实现(implement) <code>Spatie\Permission\Contracts\Role</code> contract</li><li>你的 <code>Permission</code> model 需要实现(implement) <code>Spatie\Permission\Contracts\Permission</code> contract</li></ul><p>在这两种情况下,不论是扩展还是替换,都需要在配置中指定你的新模型。在用下面的命令发布(publish)了配置文件后,你必须更新配置文件中的 <code>models.role</code> 和 <code>models.permission</code> 值。</p><p><code>php artisan vendor:publish --provider="Spatie\Permission\PermissionServiceProvider" --tag="config"</code></p><h2 id="缓存"><a href="#缓存" class="headerlink" title="缓存"></a>缓存</h2><p>角色和权限数据会被缓存起来以提升速度。</p><p>当使用提供的方法来操作角色和权限时,其缓存会自动重置:</p><div class="hljs"><pre><code class="hljs php">$user->assignRole(<span class="hljs-string">'writer'</span>);$user->removeRole(<span class="hljs-string">'writer'</span>);$user->syncRoles(params);$role->givePermissionTo(<span class="hljs-string">'edit articles'</span>);$role->revokePermissionTo(<span class="hljs-string">'edit articles'</span>);$role->syncPermissions(params);$permission->assignRole(<span class="hljs-string">'writer'</span>);$permission->removeRole(<span class="hljs-string">'writer'</span>);$permission->syncRoles(params);</code></pre></div><p><strong>然而</strong>,如果你没有用扩展包提供的方法,而是直接在数据库里手动操作权限/角色数据时,你将看不到应用改变的反馈,除非你手动重置缓存。</p><h3 id="手动重置缓存"><a href="#手动重置缓存" class="headerlink" title="手动重置缓存"></a>手动重置缓存</h3><p>执行 Artisan 命令即可:<br><code>php artisan cache:forget spatie.permission.cache</code></p><h3 id="缓存标识符"><a href="#缓存标识符" class="headerlink" title="缓存标识符"></a>缓存标识符</h3><p><strong>TIP:</strong> 如果用了某些缓存服务比如 <code>redis</code>、<code>memcached</code>,或有其他站点运行在你的服务器上,这可能会导致缓存冲突。<br>一个简单有效的方式是在 <code>/config/cache.php</code> 中设置你自己的 「缓存前缀」 来区分每个应用,这将会避免其他应用意外地使用或更改了你的缓存数据。</p>]]></content>
<categories>
<category>翻译</category>
</categories>
<tags>
<tag>Laravel package</tag>
<tag>laravel permission</tag>
</tags>
</entry>
<entry>
<title>Hexo 博客搭建记录</title>
<link href="/articles/201809/hexo-blog-building-records.html"/>
<url>/articles/201809/hexo-blog-building-records.html</url>
<content type="html"><![CDATA[<p>说来惭愧,搭建博客这已经是第三次了,每次都是三分钟热度,一搭好就放那不管了。隔个一年半载,突然又心血来潮,回头一看,坟头草都长满了,当初怎么弄的,完全记不清了。如此往复,太耗心力,虽然再次搭建会比第一次快很多,但还是记录一下,万一<del>~</del>好吧,这次没有万一,仅仅记录,尽量精简。</p><h3 id="Hexo-是什么?"><a href="#Hexo-是什么?" class="headerlink" title="Hexo 是什么?"></a><a href="https://hexo.io/zh-cn/" target="_blank" rel="noopener">Hexo</a> 是什么?</h3><p>一款快速、简洁且高效的博客框架,基于 <a href="http://nodejs.cn/" target="_blank" rel="noopener">Node.js</a><br><strong>特点</strong>:速度快,支持 Markdown,一键部署,丰富的插件。<br>虽然相比 WordPress 主题偏少,但贵在简洁,毕竟是做博客的。折腾过 wp,个人感觉太臃肿。</p><h3 id="安装-Hexo"><a href="#安装-Hexo" class="headerlink" title="安装 Hexo"></a>安装 Hexo</h3><h4 id="准备"><a href="#准备" class="headerlink" title="准备"></a>准备</h4><p><strong>先安装 Node.js</strong><br>我下的压缩包,解压后,将解压目录加入系统环境变量,以便全局可用 node 和 npm。<br>稍微配置下 npm:</p><div class="hljs"><pre><code class="hljs plain">npm config set prefix D:\Nodejs\node_global //在node主目录下配置 全局模块 安装路径npm config set cache D:\Nodejs\node_cache //在node主目录下配置 cache缓存 路径</code></pre></div><p>之后会在 C 盘用户主目录下生成 .npmrc 文件(不知道要不要将其移到 D:\Nodejs 目录下)</p><p><strong>再安装 Git</strong><br>这次下的安装包,全局安装,会自动配置环境变量</p><p>命令窗口看是否准备成功</p><div class="hljs"><pre><code class="hljs plain">node -vnpm -vgit --version</code></pre></div><h4 id="安装-Hexo-1"><a href="#安装-Hexo-1" class="headerlink" title="安装 Hexo"></a>安装 Hexo</h4><p><code>npm install -g hexo-cli</code></p><p>既然是用 npm 安装的,目录就在之前配置的 node_global 文件夹内<br>这时候去 <code>hexo -v</code> 会提示 command not found,需要将 node_global 文件夹路径加入环境变量(可能用安装包安装会自动配置吧)。</p><p>再次 <code>hexo -v</code>,会显示 hexo-cli 和相关依赖的版本。</p><p>安装完 Hexo 命令行,可以去生成一个博客站点了:</p><ul><li>进入自定义目录中,<code>hexo init</code>,或者在任意位置 <code>hexo init <folder></code></li><li>cd <folder> //进入站点目录</li><li>npm install //安装相关依赖</li></ul><p>成功后,站点目录如下:</p><div class="hljs"><pre><code class="hljs plain">_config.yml —— 站点配置信息package.json —— 程序信息scaffolds —— 模板source —— 资源文件夹,其中 Markdown 和 Html 文件会被解析到 public,其他文件被复制过去 └─ _posts 同上,但其它开头有下划线(_)的文件或文件夹都会被忽略themes —— 主题</code></pre></div><h4 id="简单配置"><a href="#简单配置" class="headerlink" title="简单配置"></a>简单配置</h4><p>需要配置的东西不多,主要有以下几项,其他配置具体看文档</p><div class="hljs"><pre><code class="hljs bash">language: zh-Hanstimezone: Asia/Shanghaipermalink: :year/:month/:id/ (暂时不知道对链接是否有影响)render_drafts: <span class="hljs-literal">true</span> —— 开启渲染草稿预览</code></pre></div><h3 id="使用"><a href="#使用" class="headerlink" title="使用"></a>使用</h3><h4 id="常用命令"><a href="#常用命令" class="headerlink" title="常用命令"></a>常用命令</h4><p><code>hexo -h</code> 查看所有可用命令<br>常用命令:</p><div class="hljs"><pre><code class="hljs bash">hexo new [layout] <title>—— 新建页面,默认为 post,其中格式以 scaffolds 为模板。已有的 layout: page、post、draft,也可以自定义hexo server —— 启动服务器进入浏览器预览,默认网址:http://localhost:4000hexo clean —— 清除缓存文件(db.json)和生成的静态文件(public)hexo generate —— 生成静态文件,都放入 public 文件夹hexo deploy —— 部署网站,推送到远程库</code></pre></div><blockquote><p>几乎所有命令都可以简写为首字母</p></blockquote><h4 id="新建页面"><a href="#新建页面" class="headerlink" title="新建页面"></a>新建页面</h4><p>默认页面有 index、post、archive<br>一般我们博客还需要 categories、tags、about</p><p>都用 <code>hexo new page <title></code> 生成<br>会在 source 中生成对应的文件夹,文件夹中都会有一个 index.md 文件,编辑文件的 Front-matter,去掉 <code>title</code> 字段,加上 <code>type</code> 字段,值为对应的类型:categories、tags、about(好像不起作用)</p><h4 id="Writing"><a href="#Writing" class="headerlink" title="Writing"></a>Writing</h4><p><code>hexo new "title"</code><br>生成新的 md 文件在 <code>source/_posts</code> 中,以 <code>scaffold/post.md</code> 为模板<br>编辑完成后保存即可,生成静态文件时,此文件夹中的 md 文件都会被解析到 public</p><p>或者将已有的 md 文件直接放入 <code>source/_posts</code>,但要加上 Front-matter。</p><h4 id="Front-matter"><a href="#Front-matter" class="headerlink" title="Front-matter"></a>Front-matter</h4><p>Front-matter 是文件最上方以 — 分隔的区域,用于指定个别文件的变量<br>写文章时一般要加上分类和标签,其他可用参数请看文档</p><p>example:</p><div class="hljs"><pre><code class="hljs plain">---title: 标题date: 时间categories:(!注意,分类有层次性,标签没有)- 技术 - 随笔(这里随笔会成技术的子类)tags: [程序,学习](标签注意要用英文逗号)photos: (!待检验)- imgurl- imgurl---正文……</code></pre></div><blockquote><p>另外,首页文章一般需要截断,在需要的位置添加<code><!-- more --></code>,这是官方推荐的方法</p></blockquote><p><strong>草稿</strong><br><code>hexo new draft "title"</code><br>或者自己生成 md 文件放入 <code>source/_draft</code> 即可。<br>需要将草稿转为正式博文发布时,运行 <code>hexo publish draft <"title"></code> 将会把草稿移动到 <code>source/_posts</code> 文件夹。</p><h3 id="主题-Next"><a href="#主题-Next" class="headerlink" title="主题 Next"></a>主题 <a href="https://theme-next.org/" target="_blank" rel="noopener">Next</a></h3><p>找了好几圈,还是 Next 简洁又小清新,以文章展示为主。其它也有几款有眼缘的,以后再试。</p><p><strong>下载主题</strong></p><div class="hljs"><pre><code class="hljs plain">cd your-hexo-sitegit clone https://gitHub.com/theme-next/hexo-theme-next themes/next</code></pre></div><p>然后在站点配置文件中启用主题:<br><code>theme: next</code></p><p>Next 提供了3种界面,我们选 Mist,在主题配置文件中:<br><code>scheme: Mist</code></p><p><strong>主题设置</strong><br>设置比较简单,另外还有第三方插件配置,具体请看官网文档</p><p>目前插件还未集成,需要:评论、统计、搜索、(音乐)</p><h3 id="部署到-GitHub-Pages"><a href="#部署到-GitHub-Pages" class="headerlink" title="部署到 GitHub Pages"></a>部署到 <a href="https://pages.github.com/" target="_blank" rel="noopener">GitHub Pages</a></h3><p>GitHub Pages 是一个<strong>静态网站托管服务</strong>,可以直接托管来自 GitHub 仓库的个人或项目页面。<br>GitHub Pages 的<strong>限制</strong>:1GB 的仓库空间、每月 100GB 的流量、每小时 10次 部署</p><p>前提,有 GitHub 账户,绑定过 SSH Key。(SSH Key 生成查看另一篇文章:Git 学习笔记)</p><p>GitHub 上新建一个空库,命名为 username.gitHub.io</p><p>站点配置文件中设置推送方式:</p><div class="hljs"><pre><code class="hljs plain">deploy: type: git repo: git@github.com:yixvan6/yixvan6.github.io.git branch: master</code></pre></div><p>推送部署时,最好先清一下缓存</p><div class="hljs"><pre><code class="hljs bash">hexo cleanhexo g -d</code></pre></div><p>成功后,就可以在浏览器中以 <a href="https://yixvan6.github.io" target="_blank" rel="noopener">https://yixvan6.github.io</a> 访问了。</p><blockquote><p>买域名,解析到我们的仓库名</p></blockquote><p><strong>?疑问</strong><br>之前搭建博客时,已绑定过 SSH Key,这次却连不上 GitHub,百思不得其解。<br>去账户一看,原来 SSH Key 是空的,以前绑定的“不翼而飞”?<br>我想可能有有效期限吧,但谷歌了一下还是没找到答案。</p>]]></content>
<categories>
<category>笔记</category>
</categories>
<tags>
<tag>Hexo</tag>
<tag>GitHub Pages</tag>
</tags>
</entry>
<entry>
<title>Git 学习笔记</title>
<link href="/articles/201809/git-learning-notes.html"/>
<url>/articles/201809/git-learning-notes.html</url>
<content type="html"><![CDATA[<p>简单记录,以便之后复习。学习的是 <a href="https://www.liaoxuefeng.com/wiki/0013739516305929606dd18361248578c67b8067c8c017b000" target="_blank" rel="noopener">廖雪峰 Git 教程</a>,浅显易懂,循序渐进!<br><a href="https://git-scm.com/" target="_blank" rel="noopener"><strong>Git 官网</strong></a> 有中文文档,有更详细的说明。常用的命令运用熟练已足够,若需要更复杂更高级的操作,就要去查文档了。</p><h3 id="什么是-Git?"><a href="#什么是-Git?" class="headerlink" title="什么是 Git?"></a>什么是 Git?</h3><p>Git 是目前世界上最先进的 <strong>分布式版本控制系统</strong>。</p><h4 id="Git-的诞生:"><a href="#Git-的诞生:" class="headerlink" title="Git 的诞生:"></a>Git 的诞生:</h4><p><strong>Linus</strong> 在 1991 年创建了开源的 Linux,在全世界的热心志愿者参与下,Linux 不断发展壮大,已经成为最大的服务器系统软件。</p><p>Linux 靠世界各地的大牛贡献代码,但代码的管理始终是个问题。<br>在 2002 年之前,志愿者们通过 <code>diff</code> 的方式将代码发给 Linus,然后由他本人手工合并代码。</p><p><strong>Linus 为什么不用当时已有版本控制系统呢?</strong></p><ol><li>CVS 和 SVN,这些集中式版本控制系统速度慢,且必须联网;</li><li>一些商业的版本控制系统虽然好用,但要付费,和 Linux 的开源精神不符。</li></ol><p>到了 02 年,Linux 系统已发展十年,代码库之大已经很难通过手工方式管理,于是不得不选择一个版本控制系统,Linus 选择了商业的 BitKeeper,而 BitKeeper 的公司 BitMover 出于人道主义精神,授权 Linux 社区免费使用。</p><p>好景不长,2005 年时,Linux 社区的 Andrew 试图破解 BitKeeper 的协议,被 BitMover 公司发现,于是收回了 Linux 社区的免费使用权。</p><p>Linus 没有重新选择另一个版本控制系统,而是花了 <strong>2周时间</strong> 自己用 C 写了一个分布式版本控制系统,便是 Git!一个月之内,Linux 系统的源码已经由 Git 管理了。</p><p>Git 迅速成为最流行的分布式版本控制系统,到了2008年,GitHub 网站上线,它为开源项目免费提供 Git 存储,无数开源项目开始迁移至 GitHub,包括 jQuery,PHP,Ruby 等。</p><h4 id="集中式-vs-分布式"><a href="#集中式-vs-分布式" class="headerlink" title="集中式 vs 分布式"></a>集中式 vs 分布式</h4><ul><li><p>集中式:版本库存放在中央服务器,每次干活前,先从中央服务器取得最新的版本,干完活后再推送给中央服务器。<br>最大的问题是必须联网才能工作,如果网速慢的话,非常费时间。一旦中央服务器崩溃,所有人都无法工作。</p></li><li><p>分布式:每个人的电脑上都是完整的版本库,所以就不用联网了。多人协作时,只需将自己的修改互相推送。而这里的“中央服务器”只是方便大家交换修改,没有它照样可以工作,只是有了它交换更方便而已。<br>另外,Git 的优势还有强大的 <strong>分支管理</strong>。</p></li></ul><blockquote><p>常见的版本控制系统有:<br>集中式:CVS(最早,不稳定)、SVN(最流行)、ClearCase(IBM的,商用,大,慢)、VSS(微软自己的)等<br>分布式:Git(最快,最流行)、BitKeeper、Mercurial、Bazaar 等</p></blockquote><h3 id="安装-Git"><a href="#安装-Git" class="headerlink" title="安装 Git"></a>安装 Git</h3><p>Git 最开始只能在 Linux 和 Unix 系统上运行,现在也可以在 Mac 和 Windows 上运行。</p><p>Windows 上安装:</p><blockquote><p>下载 Git 安装,包含了 Git Bash 和 Git GUI。<br>下载 msysgit 安装,msysgit 已将所需模拟环境和 Git 打包,默认安装即可。<br>下载 GitHub 安装,包含了可视化工具 GitHub 和命令行窗口 Git Shell 。</p></blockquote><h3 id="创建版本库"><a href="#创建版本库" class="headerlink" title="创建版本库"></a>创建版本库</h3><p>版本库(Repository),库里的每个文件都能被 Git 跟踪</p><p><strong>> 创建库</strong></p><ol><li><p>先创建一个空目录(如 …\GitHub\study)</p><div class="hljs"><pre><code class="hljs bash">mkdir study<span class="hljs-built_in">cd</span> study<span class="hljs-built_in">pwd</span> // 显示当前目录</code></pre></div></li><li><p>将这个目录变成 Git 可管理的仓库</p><div class="hljs"><pre><code class="hljs plain">git init</code></pre></div><p>于是建成了一个空的仓库,此时 study 目录下多了一个 <strong>.git</strong> 的隐藏目录</p></li></ol><p><strong>> 添加文件入库</strong></p><div class="hljs"><pre><code class="hljs bash">git add readme.txtgit commit -m <span class="hljs-string">"add a readme.txt"</span></code></pre></div><p>可以多次 add,只需一次 commit</p><h3 id="时空穿梭"><a href="#时空穿梭" class="headerlink" title="时空穿梭"></a>时空穿梭</h3><p><strong>> 基本操作</strong></p><div class="hljs"><pre><code class="hljs bash">git status // 查看工作区状态git diff readme.txt // 查看不同git add readme.txtgit statusgit commit -m <span class="hljs-string">"add word distributed"</span>git status</code></pre></div><h4 id="版本回退"><a href="#版本回退" class="headerlink" title="版本回退"></a>版本回退</h4><p>每 commit 一次,就在 git 里保存了一个「快照」</p><div class="hljs"><pre><code class="hljs bash">git <span class="hljs-built_in">log</span> // 查看版本历史记录,从最近的版本到最远排列git <span class="hljs-built_in">log</span> --pretty==oneline // 添加参数简化信息/*d1e563cda89f530ac466e3c0ed216a9f814ad700 append GPLc5e16db582973fcaf9e1b7ab534c83b22d206221 add word distributed18010d7984d1b9e693ad98a15372da6177f54366 add a readme.txt*/</code></pre></div><p>如上,每个版本对应一个 <strong>commit id</strong>(经过特殊处理,防止冲突)</p><p>可用 <strong>reset</strong> 来回退到指定版本:</p><div class="hljs"><pre><code class="hljs bash">git reset --hard HEAD^</code></pre></div><p>HEAD 表示当前版本,HEAD^ 表示上一个,HEAD^^ 表示上上一个,HEAD~10 表示往上10个版本<br>回退到上一个版本后再查看:</p><div class="hljs"><pre><code class="hljs bash">git <span class="hljs-built_in">log</span>/* c5e16db582973fcaf9e1b7ab534c83b22d206221 add word distributed18010d7984d1b9e693ad98a15372da6177f54366 add a readme.txt */</code></pre></div><p>发现”append GPL”版本没有了,怎么办?<br>如果还知道那个版本的 id,则:</p><div class="hljs"><pre><code class="hljs plain">git reset --hard d1e563cd(版本号没必要写全)`</code></pre></div><p>如果找不到版本的id了,则</p><div class="hljs"><pre><code class="hljs bash">git reflog/*c5e16db HEAD@{0}: reset: moving to HEAD^d1e563c HEAD@{1}: commit: append GPLc5e16db HEAD@{2}: commit: add word distributed18010d7 HEAD@{3}: commit (initial): add a readme.txt*/</code></pre></div><p>又能找到版本的 id 了</p><h4 id="工作区和暂存区"><a href="#工作区和暂存区" class="headerlink" title="工作区和暂存区"></a>工作区和暂存区</h4><p>工作区(working directory):在你的电脑里能看到的目录<br>版本库(repository):工作区中隐藏的目录 .git,就是版本库</p><p>.git 里存了很多东西,最重要的就是 stage(或叫 index)的暂存区,还有自动创建的 master 分支,以及指向 master 的指针 HEAD</p><p>暂存区如何工作?(详看教程文档p25-27)<br>将工作区的修改,添加到 stage,再将 stage 的所有修改提交到分支。</p><h4 id="管理修改"><a href="#管理修改" class="headerlink" title="管理修改"></a>管理修改</h4><p>Git 管理的是修改,而不是文件。删除内容、增添内容、修改内容、新增文件、删除文件等等,都算修改。</p><blockquote><p><strong>!</strong> 所有工作区的修改都必须先 add 到 stage,才能提交成功。</p></blockquote><p>如果没有 add,那只会提交 stage 中的修改,而不是工作区的修改。<br>比如:<br>第一次修改 > add > 第二次修改 > commit<br>因为只有第一次修改添加到 stage,所以只提交了第一次修改<br>第一次修改 >add > 第二次修改 > add > commit<br>这样两次修改都提交了</p><p>查看工作区和最新版本的区别:</p><div class="hljs"><pre><code class="hljs plain">git diff HEAD -- readme.txt</code></pre></div><p><strong>! git diff 说明:</strong></p><div class="hljs"><pre><code class="hljs plain">git diff 比较工作区和暂存区git diff HEAD 比较工作区和版本库git diff --cached 比较暂存区和版本库</code></pre></div><p><strong>> 撤销修改</strong><br>工作区的修改,怎么撤销?</p><div class="hljs"><pre><code class="hljs plain">git checkout -- readme.txt // 特定文件git reset --hard HEAD // 所有修改git clean -f // 未追踪的文件(即新增的文件),常与上一个命令配合使用</code></pre></div><p>已添加到暂存区的修改,怎么撤销?</p><div class="hljs"><pre><code class="hljs plain">git reset HEAD readme.txt</code></pre></div><p>这样便把暂存区的修改撤销(unstage),重新放到工作区</p><p>如果已经提交,怎么办?<br>版本回退,回退到上一个版本,前提是没有推送到远程库。</p><p><strong>> 删除文件</strong><br>先添加一个 test.txt 并提交<br>删除:<code>rm test.txt</code></p><p>若是误删想恢复,同撤销修改相同:</p><div class="hljs"><pre><code class="hljs bash">git checkout -- test.txt</code></pre></div><p>确实要删:</p><div class="hljs"><pre><code class="hljs bash">git rm test.txtgit commit -m <span class="hljs-string">"remove test.txt"</span></code></pre></div><h3 id="远程仓库"><a href="#远程仓库" class="headerlink" title="远程仓库"></a>远程仓库</h3><p>Git 是分布式版本控制系统,同一个 Git 仓库,可以分布到不同的机器上。怎么分布呢?</p><p>最早,肯定只有一台机器有一个原始版本库,此后,别的机器可以“克隆”这个原始版本库,而且每台机器的版本库其实都是一样的,并没有主次之分。</p><p>其实一台电脑上也是可以克隆多个版本库的,只要不在同一个目录下。不过,现实中是不会有人在一台电脑上搞几个远程库玩,完全没有意义。</p><p>实际情况往往是,找一台电脑充当服务器的角色,全天开机,其他每个人都从这个“服务器”仓库克隆一份到自己的电脑上,并且各自把各自的提交推送到服务器仓库里,也从服务器仓库中拉取别人的提交。</p><p>为了学 Git 先搭建个服务器绝对是小题大做,好在有很多代码托管网站,比如 GitHub,免费提供托管服务,免费获得 Git 远程仓库。</p><p>因为本地 Git 仓库和 GitHub 仓库之间是通过 SSH 加密,所以,要先设置:</p><ul><li>创建 SSH Key:<div class="hljs"><pre><code class="hljs plain">ssh-keygen -t rsa -C "yixvan6@163.com"</code></pre></div>一路回车,使用默认值,也无需设置密码。</li></ul><p>如果成功,会在用户主目录里找到 <strong>.ssh</strong> 目录,里面有 <code>github_rsa</code> 和 <code>github_rsa.pub</code> 两个文件,一个是私钥,不能泄露,一个是公钥,可以公开。<br>如果已经有这两个文件,那直接第二步。</p><ul><li><p>添加 SSH Key 到 GitHub:<br>登录 GitHub,<code>Settings > SSH and GPG keys</code><br>点”New SSH key”,Title 任意填写,Key 文本框里粘贴 github_rsa.pub 文件的内容,然后确认。</p></li><li><p>测试 ssh key 是否成功:</p><div class="hljs"><pre><code class="hljs plain">ssh -T git@github.com</code></pre></div><p>如果出现 You’ve successfully authenticated, but GitHub does not provide shell access 。这就表示已成功连上 GitHub,否则会显示 access denied。</p></li></ul><p>可添加 <strong>多个</strong> Key,使你在不同的电脑上都能推送到自己的 GitHub</p><blockquote><p>提示:<br>GitHub 免费托管 Git 仓库,但任何人都能看到(只有自己能改),是公开的。<br>若想不让别人看到,i.付费;ii.自己搭建 Git 服务器。</p></blockquote><h4 id="添加远程库"><a href="#添加远程库" class="headerlink" title="添加远程库"></a>添加远程库</h4><p>登陆 GitHub > <code>New repository</code>,创建新库。<br>目前是空的,可以把已有的本地库与之关联,然后,把本地库的内容推送到 GitHub 库</p><div class="hljs"><pre><code class="hljs bash">git remote add origin git@github.com:yixvan6/study.git // origin是代表远程库的名称git push -u origin master // 推送所有内容,实际是推送当前分支master// -u 是首次推送时与分支关联</code></pre></div><p>以后提交,就通过 <code>git push origin master</code></p><h4 id="从远程库克隆"><a href="#从远程库克隆" class="headerlink" title="从远程库克隆"></a>从远程库克隆</h4><p>克隆到本地:</p><div class="hljs"><pre><code class="hljs plain">git clone git@github.com:yixvan6/gitskills.git</code></pre></div><p>Git 支持多种协议,包括 https,但 ssh 最快。</p><p><strong>> 从远程库同步修改</strong><br>有时候修改是在远程库完成的,需要把远程的修改拉到本地库,使之相同<br>介绍两种方式:</p><ul><li><p>fetch 或 merge</p><div class="hljs"><pre><code class="hljs bash">git remote -v // 查看有哪些远程仓库,本例为一个/*origin git@github.com:yixvan6/yixvan6.github.io.git (fetch)origin git@github.com:yixvan6/yixvan6.github.io.git (push)*/git fetch origin master // 从远程获取最新版本到本地git merge origin/master // 将远程下载的代码合并到本地库</code></pre></div></li><li><p>pull</p><div class="hljs"><pre><code class="hljs bash">git pull origin master // 下载并合并</code></pre></div></li></ul><h3 id="分支管理"><a href="#分支管理" class="headerlink" title="分支管理"></a>分支管理</h3><p>分支之间各自独立,互不干扰,既安全,又不影响别人工作。自己的开发完毕之后,可以一次性合并到原来的分支上。</p><p>其他的版本控制系统如 SVN 等也有分支管理,但分支的创建和切换非常慢,几乎成了摆设。<br>但 Git 的分支无论是创建、切换还是删除,都能迅速完成,无论你的版本库是1个文件还是上万个文件。</p><h4 id="创建与合并分支"><a href="#创建与合并分支" class="headerlink" title="创建与合并分支"></a>创建与合并分支</h4><p>Git 的每次提交,都把它们串成一条时间线,这条时间线就是一个分支。目前我们只有一条时间线,默认为 <code>master</code> 分支,也称为主分支。<br><code>HEAD</code> 严格来说不是指向提交,而是指向 <code>master</code>,而 <code>master</code> 才指向提交,所以,<code>HEAD</code> 指向当前分支。</p><p><img src="https://blog-picture.oss-cn-chengdu.aliyuncs.com/20200504202156.png" srcset="/img/loading.gif" alt="git-branch1"></p><p>每次提交,<code>master</code> 分支都向前移动一步,随着不断提交,分支的线也越来越长。<br>当创建新分支,例如 <code>dev</code>,Git 新建了一个指针叫 <code>dev</code>,指向 <code>master</code> 相同的提交,再把 <code>HEAD</code> 指向 <code>dev</code>,就表示当前在 <code>dev</code> 分支上:</p><p><img src="https://blog-picture.oss-cn-chengdu.aliyuncs.com/20200504202234.png" srcset="/img/loading.gif" alt="git-branch2"></p><p>从现在起,修改和提交就是针对 <code>dev</code> 分支了,<code>dev</code> 指针向前移动,而 <code>master</code> 指针不变:</p><p><img src="https://blog-picture.oss-cn-chengdu.aliyuncs.com/20200504202324.png" srcset="/img/loading.gif" alt="git-branch3"></p><p>假如我们在新分支上的工作完成了,可以将其合并到主分支上。最简单的方法,就是把 <code>master</code> 指向 <code>dev</code> 的当前提交,完成合并:</p><p><img src="https://blog-picture.oss-cn-chengdu.aliyuncs.com/20200504202552.png" srcset="/img/loading.gif" alt="git-branch4"></p><p>合并完成后,如果要删除 <code>dev</code> 分支,只要删除这个分支对应的指针就可以了,删除后,只剩下了主分支:</p><p><img src="https://blog-picture.oss-cn-chengdu.aliyuncs.com/20200504202615.png" srcset="/img/loading.gif" alt="git-branch5"></p><p><strong>> 具体命令</strong><br>理解了原理,我们来了解具体的命令来实现。<br>创建分支:</p><div class="hljs"><pre><code class="hljs plain">git checkout -b dev // 加上 -b 参数表示创建并切换,相当于下面两条命令git branch devgit checkout dev</code></pre></div><p>然后,查看当前分支:</p><div class="hljs"><pre><code class="hljs plain">git branch // 列出所有分支,并用 * 号标出当前分支</code></pre></div><p>这时做一次新的提交,再切换到主分支查看,会发现没有变化,因为那个提交是在 <code>dev</code> 分支上,不会影响到 <code>master</code> 分支。</p><p><img src="https://blog-picture.oss-cn-chengdu.aliyuncs.com/20200504202634.png" srcset="/img/loading.gif" alt="git-branch6"></p><p>现在,将 <code>dev</code> 分支上的工作成果合并到 <code>master</code> 分支上:</p><div class="hljs"><pre><code class="hljs plain">git merge dev</code></pre></div><p><code>git merge</code> 用于将指定分支合并到当前分支,这时再查看修改,会发现与 <code>dev</code> 分支的最新提交是一样的。<br>合并完成,可以放心删除了:</p><div class="hljs"><pre><code class="hljs plain">git branch -d dev// 如果没有合并想直接删除git branch -D dev</code></pre></div><p>!因为 Git 的分支操作只是改变指针,所以速度非常快,所以「鼓励」使用分支完成某个任务,合并后再删除分支,这跟直接在主分支上工作效果是一样的,但过程更安全。</p><h4 id="解决冲突"><a href="#解决冲突" class="headerlink" title="解决冲突"></a>解决冲突</h4><p>先创建一个新分支来演示:</p><div class="hljs"><pre><code class="hljs plain">git checkout -b feature1</code></pre></div><p>修改 <code>readme.txt</code> 文件,然后提交。<br>切换到主分支,修改 <code>readme.txt</code>,提交。<br>合并 <code>feature1</code> 分支,因为两次修改并不相同,所以出现冲突:</p><div class="hljs"><pre><code class="hljs plain">git checkout master...git merge feature1git status // 可查看冲突的文件</code></pre></div><p><img src="https://blog-picture.oss-cn-chengdu.aliyuncs.com/20200504202731.png" srcset="/img/loading.gif" alt="git-branch7"></p><p><strong>解决:</strong><br>先查看文件,发现 Git 帮我们标记出来了冲突,用 <code><<<<<<<</code>,<code>=======</code>,<code>>>>>>>></code> 标记不同分支的内容:</p><p><img src="https://blog-picture.oss-cn-chengdu.aliyuncs.com/20200504202757.png" srcset="/img/loading.gif" alt="git-diff1"></p><p>手动修改后保存,提交。这样就解决了冲突,分支关系如下:</p><p><img src="https://blog-picture.oss-cn-chengdu.aliyuncs.com/20200504202814.png" srcset="/img/loading.gif" alt="git-branch8"></p><p>最后即可删除 <code>feature1</code> 分支。</p><h4 id="分支管理策略"><a href="#分支管理策略" class="headerlink" title="分支管理策略"></a>分支管理策略</h4><p>通常,合并分支时,如果可能,Git 会用 <code>Fast forward</code> 模式,但这种模式下,删除分支后,会丢掉分支信息。</p><p>如果要强制禁用 <code>Fast forward</code> 模式,Git 就会在 merge 时生成一个新的 commit,这样,从分支历史上就可以看出分支信息。</p><p>我们创建一个新分支 <code>dev</code>,并做一次提交。然后切换回主分支用普通模式(即非’ff’模式)来合并:</p><div class="hljs"><pre><code class="hljs plain">git merge --no-ff -m "merge with no-ff" dev</code></pre></div><p>因为本次合并要创建一个新的 commit,所以加上 -m 参数,把 commit 描述写进去。<br>不使用 <code>Fast forward</code> 模式,合并后像这样:</p><p><img src="https://blog-picture.oss-cn-chengdu.aliyuncs.com/20200504202829.png" srcset="/img/loading.gif" alt="git-branch9"></p><p><strong>> 分支策略</strong><br>实际开发中,应该按照这个原则进行分支管理:<br>首先,master 分支应该是非常稳定的,也就是仅用来发布新版本,平时不能在上面干活;</p><p>干活都在 dev 分支上,也就是说,dev 分支是不稳定的,到某个时候,比如1.0版本发布时,再把 dev 分支合并到 master 上,在 master 分支发布1.0版本;</p><p>你和你的小伙伴们每个人都在 dev 分支上干活,每个人都有自己的分支,时不时地往 dev 分支上合并就可以了。</p><p>所以,团队合作的分支看起来就像这样:</p><p><img src="https://blog-picture.oss-cn-chengdu.aliyuncs.com/20200504203012.png" srcset="/img/loading.gif" alt="git-branch10"></p><h4 id="Bug-分支"><a href="#Bug-分支" class="headerlink" title="Bug 分支"></a>Bug 分支</h4><p>软件开发中,bug 就像家常便饭。在Git中,由于分支是如此的强大,所以,每个 bug 都可以通过一个新的临时分支来修复,修复后,合并分支,然后将临时分支删除。</p><p>通常会碰到一种情况:当收到任务要立即修复某 bug,但当前正在进行的工作还没有完成,没法提交。<br>Git 提供了一个 <strong>stash</strong> 功能,可以把当前工作现场暂存起来,等修复完 bug 再回来恢复现场继续工作。</p><p>具体流程:</p><div class="hljs"><pre><code class="hljs plain">git stash // 暂存当前工作git checkout master // 切换回 master 分支(假定需要在 master 分支上修复该 bug)git checkout -b bug-x // 从 master 分支创建临时分支// 修复完成,提交后,切换回 master 分支,合并,最后删除 bug-x 分支git checkout dev // 切换到之前工作的分支git stash list // 查看 stash 列表git stash pop // 恢复工作现场并删除 stash,等同于下面两个命令git stash apply // 恢复git stash drop // 删除</code></pre></div><p>可以多次 <code>stash</code>,恢复时,先查看,然后用对应标号恢复</p><div class="hljs"><pre><code class="hljs plain">git stash apply stash@{0}</code></pre></div><blockquote><p><strong>{Note}</strong>在 dev 分支的修改,无论是否 add 到 stage,切换回 master 分支时都可以看到修改;<br>无论是否 add,都可以进行 stash 暂存。</p></blockquote><h4 id="Feature-分支"><a href="#Feature-分支" class="headerlink" title="Feature 分支"></a>Feature 分支</h4><p>同 bug 临时分支一样,在开发新功能时,以防一些实验性质的代码搞乱了主分支,最好新建一个 feature 分支,等新功能开发完成后,合并,这个 feature 分支就可以删除了。</p><h4 id="多人协作"><a href="#多人协作" class="headerlink" title="多人协作"></a>多人协作</h4><p>当从远程库克隆时,Git 会把本地 master 分支和远程的 master 分支对应起来,远程的仓库默认名称为 <code>origin</code>。<br>查看远程库的信息:</p><div class="hljs"><pre><code class="hljs plain">git remotegit remote -v // 会显示抓取和推送的地址,如果没有推送权限,就看不到 push 的地址</code></pre></div><p><strong>> 推送分支</strong><br>推送分支,就是把该分支上的所有本地提交推送到远程库。推送时,要指定本地分支,这样,Git 就会把该分支推送到远程库对应的远程分支上:</p><div class="hljs"><pre><code class="hljs plain">git push origin master// 推送其他分支,比如 devgit push origin dev</code></pre></div><p>但是,并不一定要把本地所有分支推送到远程,那么,哪些分支需要推送,哪些不需要呢?</p><ul><li>master 分支是主分支,因此要时刻与远程同步;</li><li>dev 分支是开发分支,团队所有成员都需要在上面工作,所以也需要与远程同步;</li><li>bug 分支只用于在本地修复 bug,就没必要推到远程了,除非老板要看看你每周到底修复了几个 bug;</li><li>feature 分支是否推到远程,取决于你是否和你的小伙伴合作在上面开发。<br>总之,在Git中,分支完全可以在本地自己藏着玩,是否推送,视你的心情而定!</li></ul><p><strong>> 抓取分支</strong><br>多人协作时,大家都会往 master 和 dev 分支上推送各自的修改。</p><p>模拟一下场景:假设现在有 C 君,要在另一台电脑上克隆项目。</p><blockquote><p><strong>{Note}</strong> 从远程库克隆时,默认情况下,只能看到本地的 master 分支。</p></blockquote><p>C 君要在 <code>dev</code> 分支上开发,先要创建远程 <code>dev</code> 分支到本地:</p><div class="hljs"><pre><code class="hljs plain">git checkout -b dev origin/dev</code></pre></div><p>现在,他可以在 <code>dev</code> 分支上工作了,并时不时地把分支 <code>push</code> 到远程。</p><p>C 君已向远程推送了提交,恰巧,你也做了修改,并试图推送:</p><div class="hljs"><pre><code class="hljs plain">git push origin dev</code></pre></div><p>但却推送失败,因为 C 君的最新提交和你要推送的提交有冲突。要解决冲突,先要把最新的提交抓取下来,然后在本地合并,解决冲突,再推送:</p><div class="hljs"><pre><code class="hljs plain">git pull</code></pre></div><p>但抓取也失败了,原因是没有指定本地 <code>dev</code> 分支和远程 <code>origin/dev</code> 的链接,根据 Git 的提示,设置链接:</p><div class="hljs"><pre><code class="hljs plain">git branch --set-upstream-to=origin/dev dev</code></pre></div><p>这时再 <code>git pull</code>,抓取成功,但合并有冲突,需要手动修改冲突。<br>解决冲突后提交,最后 <code>push</code>。</p><p><strong>总结</strong> 一下过程:</p><ol><li>试图 <code>git push origin dev</code> 推送修改;</li><li>若推送失败,则因为远程分支比你本地的更新,先用 <code>git pull</code> 抓取并合并;</li><li>若抓取失败,并提示 <code>no tracking information</code>,则是没有建立本地分支与远程的链接,先设置链接再 <code>pull</code>;</li><li>若合并有冲突,则先解决冲突,解决后再推送。</li></ol><h4 id="Rebase"><a href="#Rebase" class="headerlink" title="Rebase"></a>Rebase</h4><p>多人在同一分支上协作时,很容易出现冲突。即使没有冲突,后推送的童鞋不得不先 <code>pull</code>,在本地合并,才能推送成功。<br>每次合并再推送后,分支线就变得很凌乱,如下:</p><p><img src="https://blog-picture.oss-cn-chengdu.aliyuncs.com/20200504203210.png" srcset="/img/loading.gif" alt="git-log1"></p><p>Git 有一种 <code>rebase</code> 操作,可以将提交历史变为一条直线!所以有人亲切地将其称为「变基」</p><p>举例说明:<br>查看提交历史,远程的最新提交是 <code>init hello</code>,而自上次推送后我们又在本地新增了两次提交,<code>add comment</code> 和 <code>add author</code>,即本地比远程提前两个提交。</p><div class="hljs"><pre><code class="hljs plain">$ git log --graph --pretty=oneline --abbrev-commit* 582d922 (HEAD -> master) add author* 8875536 add comment* d1be385 (origin/master) init hello* e5e69f1 Merge branch 'dev'...</code></pre></div><p>现在我们要去推送这两次提交:<code>git push origin master</code><br>但是失败了,说明有人先于我们推送,应该先抓取合并一下:<code>git pull</code><br>没有冲突,抓取合并成功。<br>再查看一下提交历史,加上刚才合并的提交,现在本地比远程提前三个提交:</p><div class="hljs"><pre><code class="hljs plain">$ git log --graph --pretty=oneline --abbrev-commit* e0ea545 (HEAD -> master) Merge branch 'master' of github.com:michaelliao/learngit|\ | * f005ed4 (origin/master) set exit=1* | 582d922 add author* | 8875536 add comment|/ * d1be385 init hello...</code></pre></div><p>唉,怎么多了个分叉?如果现在提交,强迫症表示不能接受,那怎么办?<br>用 <code>rebase</code> 来变基操作:</p><div class="hljs"><pre><code class="hljs plain">git rebase</code></pre></div><p>变基后,再来查看提交历史:</p><div class="hljs"><pre><code class="hljs plain">$ git log --graph --pretty=oneline --abbrev-commit* 7e61ed4 (HEAD -> master) add author* 3611cfe add comment* f005ed4 (origin/master) set exit=1* d1be385 init hello...</code></pre></div><p>分叉没了!这下清爽多了,可以开心推送了:<code>git push origin master</code><br>再来看看效果,远程分支也是一条直线:</p><div class="hljs"><pre><code class="hljs plain">$ git log --graph --pretty=oneline --abbrev-commit* 7e61ed4 (HEAD -> master, origin/master) add author* 3611cfe add comment* f005ed4 set exit=1* d1be385 init hello...</code></pre></div><p><strong>总结:</strong><br>有了 <code>rebase</code> 可以把本地「未推送」的分叉提交历史整理成直线,这样看起来会更直观。但变基之后相关推送的 commit id 会发生改变。<br>另外,在 <code>rebase</code> 过程中还可能发生冲突,就需要其他操作了,这篇文章可作为参考:<a href="http://gitbook.liuhui998.com/4_2.html" target="_blank" rel="noopener">rebase</a></p><h3 id="标签管理"><a href="#标签管理" class="headerlink" title="标签管理"></a>标签管理</h3><p>发布一个版本时,通常会在版本库中打一个标签(tag),这样,就唯一确定了打标签时刻的版本。将来无论什么时候,取某个标签的版本,就是把那个打标签时刻的历史版本取出来。所以,标签也是版本库的一个快照。</p><p>Git 的标签虽然是版本库的快照,但其实它就是指向某个 <code>commit</code> 的指针(跟分支很像,但是分支可以移动,标签不能移动),所以,创建和删除标签都是瞬间完成的。</p><p>有了 <code>commit</code>,为什么还要引入 <code>tag</code>?<br>因为 commit id 是一串字符串,不好查找。有了标签,可以迅速找到对应的 <code>commit</code>。</p><p>所以,tag 就是一个让人容易记住的有意义的名字,它跟某个 commit 绑在一起。</p><h4 id="创建标签"><a href="#创建标签" class="headerlink" title="创建标签"></a>创建标签</h4><div class="hljs"><pre><code class="hljs plain">git tag <name> // 创建标签git tag // 查看所有标签</code></pre></div><p>默认标签对应到最新提交,如果要在历史提交上打标签,需要先找到对应提交的 commit id:</p><div class="hljs"><pre><code class="hljs plain">git tag <name> <commit id></code></pre></div><blockquote><p><strong>{Note}</strong> 查看标签时,标签不是按时间顺序列出,而是按字母排序的</p></blockquote><div class="hljs"><pre><code class="hljs plain">git show <tagname> // 查看标签信息</code></pre></div><p>还可以创建有说明的标签:</p><div class="hljs"><pre><code class="hljs plain">git tag -a v0.3 -m "version 0.3 released" 1094adb</code></pre></div><blockquote><p><strong>注意</strong><br>标签总是和某个 commit 挂钩。如果这个 commit 既出现在 master 分支,又出现在 dev 分支,那么在这两个分支上都可以看到这个标签。</p></blockquote><h4 id="操作标签"><a href="#操作标签" class="headerlink" title="操作标签"></a>操作标签</h4><div class="hljs"><pre><code class="hljs plain">git tag -d v0.3 // 删除标签</code></pre></div><p>标签只存储在本地,不会自动推送到远程。若要推送标签:</p><div class="hljs"><pre><code class="hljs plain">git push origin v1.0 // 推送单个标签git push origin --tags // 推送所有未推送过的本地标签</code></pre></div><p>若标签已推送到远程,要删除远程标签:</p><div class="hljs"><pre><code class="hljs plain">git tag -d v0.9 // 需要先删除本地标签git push origin :refs/tags/v0.9 // 然后再删除远程标签,命令也是 push</code></pre></div><h3 id="使用-GitHub"><a href="#使用-GitHub" class="headerlink" title="使用 GitHub"></a>使用 GitHub</h3><p>GitHub 不仅是个远程仓库,还是一个开源协作社区。</p><p>利用 Git 强大的克隆和分支功能,人们可以自由参与各种开源项目。</p><p><strong>如何参与?</strong><br>访问相关项目的 GitHub 主页,点 <strong>Fork</strong> 就在自己的账号下克隆一个相同仓库,然后再从自己的仓库克隆到本地<br>(!必须从自己的仓库克隆,不然没有权限推送)</p><p>推送修改到自己的仓库,如果想让项目官方接受你的修改,就可以发起一个 <strong>pull request</strong>,是否接受就是对方的权限了。</p><h3 id="自定义-Git"><a href="#自定义-Git" class="headerlink" title="自定义 Git"></a>自定义 Git</h3><p>在安装 Git 一节中,我们已经配置了 user.name 和 user.email,实际上,Git 还有很多可配置项。</p><p>比如,让 Git 显示颜色,会让命令输出看起来更醒目:</p><div class="hljs"><pre><code class="hljs plain">$ git config --global color.ui true</code></pre></div><p>这样,Git 会适当地显示不同的颜色,比如 git status 命令,文件名就会标上颜色。</p><h4 id="忽略特殊文件"><a href="#忽略特殊文件" class="headerlink" title="忽略特殊文件"></a>忽略特殊文件</h4><p>有时候,某些文件并不需要放入版本库进行管理,但工作目录又少不了它们,比如配置文件,这时就要创建一个 <code>.gitignore</code> 文件来让 Git 忽略它们。</p><p>在项目根目录或者特定目录中新建 <code>.gitignore</code> 文件,将要忽略的文件名写入即可。可以是某个文件,某个文件夹。<br><a href="https://github.com/github/gitignore" target="_blank" rel="noopener"><code>github/gitignore</code></a> 提供了很多示例,可以参考。<br>当然,别忘了提交 <code>gitignore</code> 文件。</p><p><strong>> 忽略文件的原则:</strong></p><ol><li>忽略操作系统自动生成的文件,比如缩略图等;</li><li>忽略编译生成的中间文件、可执行文件等。也就是如果一个文件是通过另一个文件自动生成的,那自动生成的文件就没必要放进版本库,比如Java编译产生的.class文件;</li><li>忽略带有敏感信息的文件,比如存放口令的配置文件。</li></ol><p>另外,如果某个文件已被忽略,但确实想添加,可以用 <code>-f</code> 强制添加:</p><div class="hljs"><pre><code class="hljs plain">git add -f .env</code></pre></div><h4 id="配置别名"><a href="#配置别名" class="headerlink" title="配置别名"></a>配置别名</h4><p>配置别名可以有效地「偷懒」<br>比如,之前学到的命令 <code>git reset HEAD file</code>,将暂存区的内容撤销,重新放回工作区,可以配置为 <code>unstage</code></p><div class="hljs"><pre><code class="hljs plain">git config --global alias.unstage 'reset HEAD'</code></pre></div><p>比如,配置一个命令来查看最近一次提交:</p><div class="hljs"><pre><code class="hljs plain">git config --global alias.last 'log -1'</code></pre></div><p>比如,将复杂的命令简化,用 <code>git lg</code> 查看漂亮可视化的提交历史:</p><div class="hljs"><pre><code class="hljs plain">git config --global alias.lg "log --color --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' --abbrev-commit"</code></pre></div><p><strong>配置文件</strong><br>在配置时若加上 <code>--global</code> 参数,表示全局配置所有仓库,但只对当前用户起作用;<br>如果不加,只对当前仓库起作用。</p><p>如果加上全局参数,配置文件在用户主目录下的 <code>.gitconfig</code> 文件;<br>如果不加,会在对应仓库的 <code>.git/config</code> 文件中。</p><p>配置文件可以自定义修改,别名配置也可以在其中修改,如果改错了,可以删除配置文件重新通过命令配置。</p><h4 id="搭建-Git-服务器"><a href="#搭建-Git-服务器" class="headerlink" title="搭建 Git 服务器"></a>搭建 Git 服务器</h4><p>搭建 Git 服务器很简单,主要在于权限的管理。<br>现在还用不到,就不记录了。</p>]]></content>
<categories>
<category>笔记</category>
</categories>
<tags>
<tag>Git</tag>
<tag>GitHub</tag>
</tags>
</entry>
<entry>
<title>Sublime Text从安装到配置</title>
<link href="/articles/201809/sublime-text-from-installation-to-configuration.html"/>
<url>/articles/201809/sublime-text-from-installation-to-configuration.html</url>
<content type="html"><![CDATA[<h2 id="安装"><a href="#安装" class="headerlink" title="安装"></a>安装</h2><p>从 <a href="http://www.sublimetext.com/" target="_blank" rel="noopener">Sublime Text 官网</a></p><ul><li>下载安装包,然后安装(默认的扩展包文件夹装在 C 盘,不习惯,选择另一种)</li><li>下载移动版,解压后使用(<strong>推荐</strong>)</li></ul><p>自此之前,先认识两个快捷键,以后会经常用到:</p><ul><li><code>ctrl+shift+p</code> 打开命令面板(menu: <code>Tools > Command Palette</code>)</li><li><code>ctrl+`</code> 打开控制台(menu: <code>View > Show Console</code>)</li></ul><h2 id="基本设置"><a href="#基本设置" class="headerlink" title="基本设置"></a>基本设置</h2><p>通过菜单 <code>Preferences > settings</code> 打开设置页进行设置,不要动默认的设置文件,在用户设置文件中进行设置</p><blockquote><p>最好将自定义的设置文件备份,以备不时之需</p></blockquote><p>我的设置:</p><div class="hljs"><pre><code class="hljs plain">{"always_show_minimap_viewport": true,"bold_folder_labels": true,"color_scheme": "Packages/Monokai Extended/Monokai Extended.tmTheme","font_size": 12,"ignored_packages":["Vintage"],"indent_guide_options"://缩进显示稍有不同["draw_normal","draw_active"],"line_padding_bottom": 2,"line_padding_top": 2,"overlay_scroll_bars": "enabled",//滚动条自动隐藏"show_encoding": true,"theme": "Soda Light 3.sublime-theme","wrap_width": 80,"word_wrap": true}</code></pre></div><h2 id="让-Sublime-Text-支持浏览器中预览"><a href="#让-Sublime-Text-支持浏览器中预览" class="headerlink" title="让 Sublime Text 支持浏览器中预览"></a>让 Sublime Text 支持浏览器中预览</h2><p>菜单 <code>Tools > Developer >New Plugin</code> 新建一个插件,文件名自取,用 <code>python</code> 编写,然后绑定自定义快捷键。</p><blockquote><p>具体实现在另一篇文章里:<strong>让 Sublime Text 支持浏览器中预览</strong></p></blockquote><h2 id="扩展包管理器"><a href="#扩展包管理器" class="headerlink" title="扩展包管理器"></a>扩展包管理器</h2><p>Sublime Text 的强大之处在于可以融合丰富的扩展包,安装扩展包可以手动下载对应的包文件放入 ST,而更方便的方式是用 Package Control。除此之外,已安装的扩展包的功能也能通过 Package Control 来调用。</p><p>Package Control 本身也是一个扩展包,需要先进行安装。<br>安装方式:打开控制台,输入 python 安装代码,回车等待。</p><p>具体代码和方式不同版本可能会不同,最好去<a href="https://packagecontrol.io/" target="_blank" rel="noopener">官网</a>查看。</p><p>Package Control 网站收录了丰富的扩展包,可以寻找自己的想要的扩展功能和主题。<br>在安装任意扩展包前,可以先去此网站中寻找,查看包信息。</p><h2 id="主题与配色"><a href="#主题与配色" class="headerlink" title="主题与配色"></a>主题与配色</h2><p>Sublime Text 的主题和配色方案,通过菜单 <code>Preferences > Color Scheme</code> 和 <code>Theme</code> 来选择使用。</p><p>ST 一般会自带几个主题和配色,也能凑合用。</p><p>我比较习惯 <a href="https://packagecontrol.io/packages/Theme%20-%20Soda" target="_blank" rel="noopener"><strong>Soda</strong></a> 主题和 <a href="https://packagecontrol.io/packages/Monokai%20Extended" target="_blank" rel="noopener"><strong>Monokai</strong></a> 配色,虽然 <a href="https://packagecontrol.io/packages/Material%20Theme" target="_blank" rel="noopener">Material</a> 主题很酷炫,但有些废眼,弃了。虽然可以通过其他方式自定义配色方案,懒得折腾了。</p><p>安装 Soda 很简单,打开命令面板,利用 Package Control:Install Package 找到 Theme Soda 回车安装。<br>接着用同样的方式安装专门配套 Soda 主题的 Monokai 配色包:Monokai Extended。</p><p>安装完成后通过菜单选择来使用,或者在 settings 文件中设置相关字段。</p><h2 id="常用扩展包"><a href="#常用扩展包" class="headerlink" title="常用扩展包"></a>常用扩展包</h2><p>在 Package Control 网站上可以看到扩展包的下载量和受欢迎程度。</p><p>常用的包介绍可以看另一篇文章:</p><p>这里只列举我自己安装的几个包。(打开 Package Control 的 settings-user 可以看到已安装的所有包)</p><h4 id="Emmet"><a href="#Emmet" class="headerlink" title="Emmet"></a><a href="https://packagecontrol.io/packages/Emmet" target="_blank" rel="noopener">Emmet</a></h4><p>Emmet 是一个前端开发的利器,其前身是 Zen Coding。它让编写 HTML/CSS 代码变得简单快速。<br>使用时输入简写形式,然后按 Tab 键。<br>Emmet 还重写配备了许多快捷键来操作 Html 代码,非常强大。</p><p>Emmet 是受到 snippets 的启发,说白了就是重用代码块,将常用的代码块保存成智能模板,需要时用快速高效的调用。</p><p>很多编辑器都有 snippets 功能,ST 也不例外。<br>menu:<code>Tools > Snippets</code> 可以查看当前已有的 snippets;<br>menu:<code>Tools > Developer > New Snippet</code> 可以新建 snippet,自己编写。</p><blockquote><p>收藏的一篇文章中有具体实现:<a href="">教你写Sublime中的Snippet</a></p></blockquote><p>如果要自定义 Emmet 中的 snippets,需要新建 snippet.json 保存在扩展文件夹,具体请查看文档。</p><p>关于 Emmet 的更多用法,请看<a href="https://docs.emmet.io/" target="_blank" rel="noopener">官方文档</a>,<a href="https://docs.emmet.io/cheat-sheet/" target="_blank" rel="noopener">速查表</a>可以帮你快速记忆简写形式。</p><h4 id="SublimeLinter"><a href="#SublimeLinter" class="headerlink" title="SublimeLinter"></a><a href="https://packagecontrol.io/packages/SublimeLinter" target="_blank" rel="noopener">SublimeLinter</a></h4><p>SublimeLinter 是一个代码校验插件,它可以帮你找出语法错误或编写不规范的代码。<br>其本身并不包含具体的 Linters 组件,需要针对不同的语言安装对应的组件。</p><p>安装<a href="https://packagecontrol.io/packages/SublimeLinter-php" target="_blank" rel="noopener">SublimeLinter-php</a>,安装完成后,打开:<code>Preferences > Package Settings > SublimeLinter > Settings</code> 设置:</p><div class="hljs"><pre><code class="hljs plain">{ "paths": { "linux": [], "osx": [], "windows": [ "D:\\wamp\\bin\\php\\php7.0.10" ] }}</code></pre></div><p>SublimeLinter 默认以 background 模式运行,在用户输入的同时即时校验,如果想要 Sublime Text 运行得更流畅,可以改为 load-save 模式或 save-only 模式,在读取和保存时才校验。</p><blockquote><p>另外,如果想校验 Javascript 和 CSS 语法,查看转载的文章:<a href="">SublimeLinter 校验 JS 和 CSS</a></p></blockquote><h4 id="SublimeCodeintel"><a href="#SublimeCodeintel" class="headerlink" title="SublimeCodeintel"></a><a href="https://packagecontrol.io/packages/SublimeCodeIntel" target="_blank" rel="noopener">SublimeCodeintel</a></h4><p>SublimeCodeIntel 是一个代码提示、自动补全插件,支持大多数语言,是 Sublime Text 自带代码提示功能的很好扩展。</p><p>它还有一个功能就是跳转到变量、函数定义的地方,十分方便。</p><p>使用之前需要安装相应程序并配置路径到 <code>~/.codeintel/config</code> 或 <code>project_root/.codeintel/config</code> 中,ReadMe 中有详细的说明,不再赘述。</p><p>设置内容如下:</p><div class="hljs"><pre><code class="hljs plain">{"PHP": {"php": 'D:\wamp\bin\php\php7.0.10\php.exe',"phpExtraPaths": ['D:\wamp\bin\php\php7.0.10\ext'],"phpConfigFile": 'D:\wamp\bin\php\php7.0.10\php.ini'},"JavaScript": { "javascriptExtraPaths": [] }}</code></pre></div><blockquote><p>windows 下无法用一般方式新建 .codeintel 文件夹,可以用 cmd 命令框来创建,或者直接用 Sublime Text 创建。</p></blockquote><h4 id="Markdown-Preview"><a href="#Markdown-Preview" class="headerlink" title="Markdown Preview"></a><a href="https://packagecontrol.io/packages/MarkdownPreview" target="_blank" rel="noopener">Markdown Preview</a></h4><p>Markdown Preview 可以高亮 md 语法,并且可输出为 Html 文件。在 ST 下的 Markdown 插件有很多,<a href="https://packagecontrol.io/packages/MarkdownEditing" target="_blank" rel="noopener">MarkdownEditing</a> 也比较受欢迎。</p><p>Markdown Preview 的具体用法请看另一篇:<strong>Sublime Text 下的 Markdown 写作</strong></p><h4 id="BracketHighlighter"><a href="#BracketHighlighter" class="headerlink" title="BracketHighlighter"></a><a href="https://packagecontrol.io/packages/BracketHighlighter" target="_blank" rel="noopener">BracketHighlighter</a></h4><p>BracketHighlighter 是一个括号、引号、标签高亮插件,比如 []、()、{}、””、’’、<tag></tag> 和自定义的括号,比 Sublime Text 自带的高亮更加明显、美观。</p>]]></content>
<categories>
<category>生产环境</category>
</categories>
<tags>
<tag>Sublime Text</tag>
<tag>Package Control</tag>
</tags>
</entry>
<entry>
<title>让Sublime Text支持浏览器中预览</title>
<link href="/articles/201809/let-sublime-text-support-browser-preview.html"/>
<url>/articles/201809/let-sublime-text-support-browser-preview.html</url>
<content type="html"><![CDATA[<p>原文链接:<a href="https://imququ.com/post/view-sublime-text-2-file-in-browser.html" target="_blank" rel="noopener">https://imququ.com/post/view-sublime-text-2-file-in-browser.html</a></p><p>此方法是用 <strong>Python</strong> 来新建一个插件。原文是在 Sublime Text2 版本下,在 ST3 下仍然可用。</p><h3 id="一、新建插件"><a href="#一、新建插件" class="headerlink" title="一、新建插件"></a>一、新建插件</h3><p>点击菜单 <code>Tools -> Developer -> New Plugin</code>,在创建好的 py 文件输入下列内容:</p><div class="hljs"><pre><code class="hljs python"><span class="hljs-keyword">import</span> sublime, sublime_plugin<span class="hljs-keyword">import</span> webbrowserurl_map = { <span class="hljs-string">'D:\\wamp\\www\\'</span> : <span class="hljs-string">'http://localhost/'</span>,}<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">OpenBrowserCommand</span><span class="hljs-params">(sublime_plugin.TextCommand)</span>:</span> <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">run</span><span class="hljs-params">(self,edit)</span>:</span> window = sublime.active_window() window.run_command(<span class="hljs-string">'save'</span>) url = self.view.file_name() flag = <span class="hljs-literal">False</span> <span class="hljs-keyword">for</span> path, domain <span class="hljs-keyword">in</span> url_map.items(): <span class="hljs-keyword">if</span> url.startswith(path): url = url.replace(path, domain).replace(<span class="hljs-string">'\\'</span>, <span class="hljs-string">'/'</span>) flag = <span class="hljs-literal">True</span> <span class="hljs-keyword">break</span> <span class="hljs-keyword">if</span> <span class="hljs-keyword">not</span> flag: url = <span class="hljs-string">'file://'</span> + url webbrowser.open_new(url)</code></pre></div><p>代码只有几行,大部分还是参考的 <a href="http://www.sublimetext.com/forum/viewtopic.php?f=2&t=3851" target="_blank" rel="noopener">这个帖子</a></p><p>将文件保存到 <code>Packages/User</code> 目录(Packages 可通过菜单里的 Browse Packages…打开),文件名随意,如 open_browser.py。插件部分完工了。</p><h3 id="二、为新插件设置快捷键"><a href="#二、为新插件设置快捷键" class="headerlink" title="二、为新插件设置快捷键"></a>二、为新插件设置快捷键</h3><p>选择 <code>Preferences -> key Bindings-User</code> 打开个人快捷键配置,输入下列内容:</p><p><code>{ "keys": ["ctrl+b"], "command": "open_browser" }</code></p><p><strong>ok!</strong>这样就完成了,可以测试下了。<br>打开一个 html 或 php 文件,<code>ctrl+b</code> 试试,没意外的话文件会在默认浏览器打开了。url_map 里配置的站点目录会映射到 URL (这里为 localhost)。</p><blockquote><p>PS:如果要用指定浏览器预览,也可以将最后一行代码改成这样:</p></blockquote><p><code>webbrowser.get(<span class="hljs-string">'safari'</span>).open_new(url)</code></p><p>webbrowser 具体支持 get 哪些浏览器,可以通过 webbrowser_browsers 查看。</p><p><strong>另外</strong>:安装扩展包也能实现,只是稍微复杂点,但功能更丰富。<br>主要是这两个包:<strong><code>SideBarEnhancements、View In Browser</code></strong></p>]]></content>
<categories>
<category>生产环境</category>
</categories>
<tags>
<tag>Sublime Text</tag>
</tags>
</entry>
<entry>
<title>Sublime Text 下的 Markdown 写作</title>
<link href="/articles/201809/markdown-writing-under-sublime-text.html"/>
<url>/articles/201809/markdown-writing-under-sublime-text.html</url>
<content type="html"><![CDATA[<h3 id="安装-Markdown-Preview"><a href="#安装-Markdown-Preview" class="headerlink" title="安装 Markdown Preview"></a>安装 <a href="https://packagecontrol.io/packages/MarkdownPreview" target="_blank" rel="noopener">Markdown Preview</a></h3><p>按下键 <code>Ctrl+Shift+p</code> 调出命令面板,找到 Package Control:install Pakage 这一项。搜索 Markdown Preview,选择安装。</p><h3 id="快捷键绑定"><a href="#快捷键绑定" class="headerlink" title="快捷键绑定"></a>快捷键绑定</h3><p>从菜单 <code>Preferences -> Key Bindings</code> 打开快捷键设置页,添加以下代码:<br><code>{ "keys": ["alt+m"], "command": "markdown_preview", "args": { "target": "browser"} }</code></p><h3 id="使用"><a href="#使用" class="headerlink" title="使用"></a>使用</h3><p>Markdown Preview 较常用的功能:(用 package control 在命令面板中调用)</p><ul><li>快速在浏览器预览:<strong><em>Preview in Browser</em></strong></li><li>转为 Html 文件:<strong><em>Save to Html 或 Export HTML in Sublime Text</em></strong></li><li>万一忘了Markdown语法,可调出语法文档:<strong><em>Open Markdown Cheat sheet</em></strong></li></ul><h4 id="设置语法高亮和-mathjax-支持"><a href="#设置语法高亮和-mathjax-支持" class="headerlink" title="- 设置语法高亮和 mathjax 支持"></a>- 设置语法高亮和 mathjax 支持</h4><p>找到 Markdown Preview 的下面两项设为 true 即可。<br><code>"enable_mathjax": true,"enable_highlight": true,</code><br>语法高亮跟编辑器的主题有关,本人安装的 Monokai extended 配色主题已提供完美方案。</p><h4 id="关于目录生成"><a href="#关于目录生成" class="headerlink" title="- 关于目录生成"></a>- 关于目录生成</h4><p>只要文章是按照 Markdown 语法写作的。在需要生成目录的地方写 <strong>[TOC]</strong> 即可。</p><h4 id="打印成-PDF"><a href="#打印成-PDF" class="headerlink" title="- 打印成 PDF"></a>- 打印成 PDF</h4><p>将 Markdown 转换为 PDF 应该有很多种方法,可直接用谷歌浏览器虚拟打印功能生成,云笔记也有输出pdf功能。</p>]]></content>
<categories>
<category>生产环境</category>
</categories>
<tags>
<tag>Sublime Text</tag>
<tag>Markdown</tag>
</tags>
</entry>
</search>