-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathsearch.xml
More file actions
1088 lines (848 loc) · 190 KB
/
Copy pathsearch.xml
File metadata and controls
1088 lines (848 loc) · 190 KB
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
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
<?xml version="1.0" encoding="utf-8"?>
<search>
<entry>
<title>Git命令手册</title>
<url>/2022/03/09/Git%E5%91%BD%E4%BB%A4%E6%89%8B%E5%86%8C/</url>
<content><![CDATA[<h2 id="1-版本回退"><a href="#1-版本回退" class="headerlink" title="1. 版本回退"></a>1. 版本回退</h2><p>笔者文件经过两次修改,可以通过<code>git log</code>查看</p>
<figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">[root@LAPTOP-1UJN7PP7 git-learn]# git log</span><br><span class="line">commit 5e3f973bf0248775995e6197cb999c874abc3859</span><br><span class="line">Author: root <root@LAPTOP-1UJN7PP7.localdomain></span><br><span class="line">Date: Tue Mar 1 18:17:58 2022 +0800</span><br><span class="line"></span><br><span class="line"> second commit</span><br><span class="line"></span><br><span class="line">commit 196ad7fafa50d6558e2c4da42344e7ff292d1447</span><br><span class="line">Author: root <root@LAPTOP-1UJN7PP7.localdomain></span><br><span class="line">Date: Tue Mar 1 18:15:54 2022 +0800</span><br><span class="line"></span><br><span class="line"> first commit</span><br><span class="line"></span><br></pre></td></tr></table></figure>
<p>如果嫌输出信息太多,看得眼花缭乱的,可以试试加上<code>--pretty=oneline</code>参数:</p>
<figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">[root@LAPTOP-1UJN7PP7 git-learn]# git log --pretty=oneline</span><br><span class="line">5e3f973bf0248775995e6197cb999c874abc3859 second commit</span><br><span class="line">196ad7fafa50d6558e2c4da42344e7ff292d1447 first commit</span><br><span class="line"></span><br></pre></td></tr></table></figure>
<p>注意:类似于<code>5e3f...</code>这一大串数字是<code>commit id </code>,是一个SHA1计算出来的一个非常大的数字,用十六进制表示,用来唯一辨识每个版本</p>
<p>Git中,用<code>HEAD</code>表示当前版本,上一个版本是<code>HEAD^</code>,上上个版本是<code>HEAD^^</code>,如果数量过多,可用<code>HEAD^n</code>表示,n表示一个数字。</p>
<p>回退上一个版本:</p>
<figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">[root@LAPTOP-1UJN7PP7 git-learn]# git reset --hard HEAD^</span><br><span class="line">HEAD is now at 196ad7f first commit</span><br><span class="line"></span><br></pre></td></tr></table></figure>
<ul>
<li><strong>–hard</strong> 参数撤销工作区中所有未提交的修改内容,将暂存区与工作区都回到上一次版本,并删除之前的所有信息提交</li>
</ul>
<p>此时<code>Git log</code>中已经没有后来那次版本的信息:</p>
<figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">[root@LAPTOP-1UJN7PP7 git-learn]# git log --pretty=oneline</span><br><span class="line">196ad7fafa50d6558e2c4da42344e7ff292d1447 first commit</span><br><span class="line"></span><br></pre></td></tr></table></figure>
<p>可以使用<code>git reflog</code>查看操作记录:</p>
<figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">[root@LAPTOP-1UJN7PP7 git-learn]# git reflog</span><br><span class="line">196ad7f HEAD@{0}: reset: moving to HEAD^</span><br><span class="line">5e3f973 HEAD@{1}: commit: second commit</span><br><span class="line">196ad7f HEAD@{2}: commit (initial): first commit</span><br><span class="line"></span><br></pre></td></tr></table></figure>
<p>可以查看到第二次提交的commit id,从而再次变更为第二次版本:</p>
<figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">[root@LAPTOP-1UJN7PP7 git-learn]# git reset --hard 5e3f973</span><br><span class="line">HEAD is now at 5e3f973 second commit</span><br><span class="line"></span><br></pre></td></tr></table></figure>
<h2 id="2-工作区与暂存区"><a href="#2-工作区与暂存区" class="headerlink" title="2. 工作区与暂存区"></a>2. 工作区与暂存区</h2><p>文件所在地方为工作区,当文件被修改后,用<code>git status</code>查看:</p>
<figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">[root@LAPTOP-1UJN7PP7 git-learn]# git status</span><br><span class="line"><span class="meta"># </span><span class="language-bash">On branch master</span></span><br><span class="line"><span class="meta"># </span><span class="language-bash">Changes not staged <span class="keyword">for</span> commit:</span></span><br><span class="line"><span class="meta"># </span><span class="language-bash"> (use <span class="string">"git add <file>..."</span> to update what will be committed)</span></span><br><span class="line"><span class="meta"># </span><span class="language-bash"> (use <span class="string">"git checkout -- <file>..."</span> to discard changes <span class="keyword">in</span> working directory)</span></span><br><span class="line"><span class="meta">#</span><span class="language-bash"></span></span><br><span class="line"><span class="language-bash"><span class="comment"># modified: README.md</span></span></span><br><span class="line"><span class="meta">#</span><span class="language-bash"></span></span><br><span class="line"><span class="language-bash">no changes added to commit (use <span class="string">"git add"</span> and/or <span class="string">"git commit -a"</span>)</span></span><br><span class="line"></span><br></pre></td></tr></table></figure>
<p>显示文件已被修改但是没有add和commit</p>
<p>add文件后,文件来到暂存区,用<code>git status</code>查看:</p>
<figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">[root@LAPTOP-1UJN7PP7 git-learn]# git status</span><br><span class="line"><span class="meta"># </span><span class="language-bash">On branch master</span></span><br><span class="line"><span class="meta"># </span><span class="language-bash">Changes to be committed:</span></span><br><span class="line"><span class="meta"># </span><span class="language-bash"> (use <span class="string">"git reset HEAD <file>..."</span> to unstage)</span></span><br><span class="line"><span class="meta">#</span><span class="language-bash"></span></span><br><span class="line"><span class="language-bash"><span class="comment"># modified: README.md</span></span></span><br><span class="line"><span class="meta">#</span><span class="language-bash"></span></span><br><span class="line"><span class="language-bash"></span></span><br></pre></td></tr></table></figure>
<p><img src="https://s2.loli.net/2022/03/01/EYoZUWvz8tfis1N.jpg" alt="git-stage"></p>
<p>显示文件没有commit</p>
<p>commit文件后,文件来到版本库,用<code>git status</code>查看:</p>
<figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">[root@LAPTOP-1UJN7PP7 git-learn]# git status</span><br><span class="line"><span class="meta"># </span><span class="language-bash">On branch master</span></span><br><span class="line">nothing to commit, working directory clean</span><br><span class="line"></span><br></pre></td></tr></table></figure>
<p><img src="https://s2.loli.net/2022/03/01/6MscyI19UOJrzuv.jpg" alt="git-stage-after-commit"></p>
<h2 id="3-管理修改"><a href="#3-管理修改" class="headerlink" title="3.管理修改"></a>3.管理修改</h2><p>Git比其他版本控制系统设计得优秀,因为Git跟踪并管理的是修改,而非文件</p>
<p>修改文件:</p>
<figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">[root@LAPTOP-1UJN7PP7 git-learn]# echo "This is a new line" >> README.md</span><br></pre></td></tr></table></figure>
<p>查看修改:</p>
<figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">[root@LAPTOP-1UJN7PP7 git-learn]# cat README.md</span><br><span class="line">This is third commit</span><br><span class="line">This is a new line</span><br></pre></td></tr></table></figure>
<p>添加到暂存区:</p>
<figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">[root@LAPTOP-1UJN7PP7 git-learn]# git add README.md</span><br><span class="line">[root@LAPTOP-1UJN7PP7 git-learn]# git status</span><br><span class="line"><span class="meta"># </span><span class="language-bash">On branch master</span></span><br><span class="line"><span class="meta"># </span><span class="language-bash">Changes to be committed:</span></span><br><span class="line"><span class="meta"># </span><span class="language-bash"> (use <span class="string">"git reset HEAD <file>..."</span> to unstage)</span></span><br><span class="line"><span class="meta">#</span><span class="language-bash"></span></span><br><span class="line"><span class="language-bash"><span class="comment"># modified: README.md</span></span></span><br><span class="line"><span class="meta">#</span><span class="language-bash"></span></span><br><span class="line"><span class="language-bash"></span></span><br></pre></td></tr></table></figure>
<p>再次修改文件:</p>
<figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">[root@LAPTOP-1UJN7PP7 git-learn]# cat README.md</span><br><span class="line">This is third commit</span><br></pre></td></tr></table></figure>
<p>此时我们提交修改:</p>
<figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">[root@LAPTOP-1UJN7PP7 git-learn]# git commit -m "Add a new line"</span><br><span class="line">[master 6e2db9d] Add a new line</span><br><span class="line"> Committer: root <root@LAPTOP-1UJN7PP7.localdomain></span><br><span class="line">Your name and email address were configured automatically based</span><br><span class="line">on your username and hostname. Please check that they are accurate.</span><br><span class="line">You can suppress this message by setting them explicitly:</span><br><span class="line"></span><br><span class="line"> git config --global user.name "Your Name"</span><br><span class="line"> git config --global user.email you@example.com</span><br><span class="line"></span><br><span class="line">After doing this, you may fix the identity used for this commit with:</span><br><span class="line"></span><br><span class="line"> git commit --amend --reset-author</span><br><span class="line"></span><br><span class="line"> 1 file changed, 1 insertion(+)</span><br><span class="line"></span><br></pre></td></tr></table></figure>
<p>可以看到提交的是插入了一行,也就是上一次修改</p>
<p>我们看一下文件状态:</p>
<figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">[root@LAPTOP-1UJN7PP7 git-learn]# git status</span><br><span class="line"><span class="meta"># </span><span class="language-bash">On branch master</span></span><br><span class="line"><span class="meta"># </span><span class="language-bash">Changes not staged <span class="keyword">for</span> commit:</span></span><br><span class="line"><span class="meta"># </span><span class="language-bash"> (use <span class="string">"git add <file>..."</span> to update what will be committed)</span></span><br><span class="line"><span class="meta"># </span><span class="language-bash"> (use <span class="string">"git checkout -- <file>..."</span> to discard changes <span class="keyword">in</span> working directory)</span></span><br><span class="line"><span class="meta">#</span><span class="language-bash"></span></span><br><span class="line"><span class="language-bash"><span class="comment"># modified: README.md</span></span></span><br><span class="line"><span class="meta">#</span><span class="language-bash">vi</span></span><br><span class="line">no changes added to commit (use "git add" and/or "git commit -a")</span><br></pre></td></tr></table></figure>
<p>可以看到工作区的修改存在且未添加到暂存区</p>
<p>所以,Git管理的是修改,当你用<code>git add</code>命令后,在工作区的第一次修改被放入暂存区,准备提交,但是,在工作区的第二次修改并没有放入暂存区,所以,<code>git commit</code>只负责把暂存区的修改提交了,也就是第一次的修改被提交了,第二次的修改不会被提交</p>
<p>提交后,用<code>git diff HEAD -- readme.txt</code>命令可以查看工作区和版本库里面最新版本的区别:</p>
<figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">[root@LAPTOP-1UJN7PP7 git-learn]# git diff HEAD README.md</span><br><span class="line">diff --git a/README.md b/README.md</span><br><span class="line">index 28bc83d..62c3f45 100644</span><br><span class="line">--- a/README.md</span><br><span class="line">+++ b/README.md</span><br><span class="line">@@ -1,2 +1 @@</span><br><span class="line"> This is third commit</span><br><span class="line">-This is a new line</span><br></pre></td></tr></table></figure>
<p>可见,第二次修改确实没有被提交</p>
<h2 id="4-撤销修改"><a href="#4-撤销修改" class="headerlink" title="4.撤销修改"></a>4.撤销修改</h2><h3 id="4-1-修改但未提交"><a href="#4-1-修改但未提交" class="headerlink" title="4.1.修改但未提交"></a>4.1.修改但未提交</h3><p>错误的修改文件但未提交:</p>
<figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">[root@LAPTOP-1UJN7PP7 git-learn]# echo "This is an error" >> README.md</span><br><span class="line">[root@LAPTOP-1UJN7PP7 git-learn]# cat README.md</span><br><span class="line">This git test file</span><br><span class="line">This is an error</span><br><span class="line"></span><br></pre></td></tr></table></figure>
<p>使用<code>git status</code>查看:</p>
<figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">[root@LAPTOP-1UJN7PP7 git-learn]# git status</span><br><span class="line"><span class="meta"># </span><span class="language-bash">On branch master</span></span><br><span class="line"><span class="meta"># </span><span class="language-bash">Changes not staged <span class="keyword">for</span> commit:</span></span><br><span class="line"><span class="meta"># </span><span class="language-bash"> (use <span class="string">"git add <file>..."</span> to update what will be committed)</span></span><br><span class="line"><span class="meta"># </span><span class="language-bash"> (use <span class="string">"git checkout -- <file>..."</span> to discard changes <span class="keyword">in</span> working directory)</span></span><br><span class="line"><span class="meta">#</span><span class="language-bash"></span></span><br><span class="line"><span class="language-bash"><span class="comment"># modified: README.md</span></span></span><br><span class="line"><span class="meta">#</span><span class="language-bash"></span></span><br><span class="line"><span class="language-bash">no changes added to commit (use <span class="string">"git add"</span> and/or <span class="string">"git commit -a"</span>)</span></span><br><span class="line"></span><br></pre></td></tr></table></figure>
<p>Git提示可以<code>use "git checkout -- <file>..." to discard changes in working directory</code>,即使用<code>git checkout -- <file></code>来丢弃修改:</p>
<figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">[root@LAPTOP-1UJN7PP7 git-learn]# git checkout -- README.md</span><br><span class="line">[root@LAPTOP-1UJN7PP7 git-learn]# cat README.md</span><br><span class="line">This git test file</span><br><span class="line"></span><br></pre></td></tr></table></figure>
<ul>
<li>注意:<code>git checkout -- file</code>命令中的<code>--</code>很重要,没有<code>--</code>,就变成了“切换到另一个分支”的命令</li>
</ul>
<p>可见修改被丢弃</p>
<h3 id="4-2-修改已添加到暂存区"><a href="#4-2-修改已添加到暂存区" class="headerlink" title="4.2.修改已添加到暂存区"></a>4.2.修改已添加到暂存区</h3><p>如果已经添加到暂存区:</p>
<figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">[root@LAPTOP-1UJN7PP7 git-learn]# cat README.md</span><br><span class="line">This git test file</span><br><span class="line">This is an error</span><br><span class="line">[root@LAPTOP-1UJN7PP7 git-learn]# git add README.md</span><br><span class="line">[root@LAPTOP-1UJN7PP7 git-learn]# git status</span><br><span class="line"><span class="meta"># </span><span class="language-bash">On branch master</span></span><br><span class="line"><span class="meta"># </span><span class="language-bash">Changes to be committed:</span></span><br><span class="line"><span class="meta"># </span><span class="language-bash"> (use <span class="string">"git reset HEAD <file>..."</span> to unstage)</span></span><br><span class="line"><span class="meta">#</span><span class="language-bash"></span></span><br><span class="line"><span class="language-bash"><span class="comment"># modified: README.md</span></span></span><br><span class="line"><span class="meta">#</span><span class="language-bash"></span></span><br><span class="line"><span class="language-bash"></span></span><br></pre></td></tr></table></figure>
<p>Git提示<code>use "git reset HEAD <file>..." to unstage</code>,即使用<code>git reset HEAD <file></code>来丢弃存储区修改:</p>
<figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">[root@LAPTOP-1UJN7PP7 git-learn]# git reset HEAD README.md</span><br><span class="line">Unstaged changes after reset:</span><br><span class="line">M README.md</span><br><span class="line"></span><br></pre></td></tr></table></figure>
<p>查看状态:</p>
<figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">[root@LAPTOP-1UJN7PP7 git-learn]# git status</span><br><span class="line"><span class="meta"># </span><span class="language-bash">On branch master</span></span><br><span class="line"><span class="meta"># </span><span class="language-bash">Changes not staged <span class="keyword">for</span> commit:</span></span><br><span class="line"><span class="meta"># </span><span class="language-bash"> (use <span class="string">"git add <file>..."</span> to update what will be committed)</span></span><br><span class="line"><span class="meta"># </span><span class="language-bash"> (use <span class="string">"git checkout -- <file>..."</span> to discard changes <span class="keyword">in</span> working directory)</span></span><br><span class="line"><span class="meta">#</span><span class="language-bash"></span></span><br><span class="line"><span class="language-bash"><span class="comment"># modified: README.md</span></span></span><br><span class="line"><span class="meta">#</span><span class="language-bash"></span></span><br><span class="line"><span class="language-bash">no changes added to commit (use <span class="string">"git add"</span> and/or <span class="string">"git commit -a"</span>)</span></span><br><span class="line">[root@LAPTOP-1UJN7PP7 git-learn]# cat README.md</span><br><span class="line">This git test file</span><br><span class="line">This is an error</span><br><span class="line"></span><br></pre></td></tr></table></figure>
<p>可见暂存区的修改被撤销了,工作区文件的修改还存在,这时候再使用<code>git checkout -- <file></code>来丢弃修改:</p>
<figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">[root@LAPTOP-1UJN7PP7 git-learn]# git checkout -- README.md</span><br><span class="line">[root@LAPTOP-1UJN7PP7 git-learn]# cat README.md</span><br><span class="line">This git test file</span><br><span class="line">[root@LAPTOP-1UJN7PP7 git-learn]# git status</span><br><span class="line"><span class="meta"># </span><span class="language-bash">On branch master</span></span><br><span class="line">nothing to commit, working directory clean</span><br><span class="line"></span><br></pre></td></tr></table></figure>
<h3 id="4-3-修改已提交"><a href="#4-3-修改已提交" class="headerlink" title="4.3.修改已提交"></a>4.3.修改已提交</h3><p>回退上一个版本:</p>
<figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">[root@LAPTOP-1UJN7PP7 git-learn]# git reset --hard HEAD^</span><br><span class="line">HEAD is now at 196ad7f first commit</span><br><span class="line"></span><br></pre></td></tr></table></figure>
<h2 id="5-删除文件"><a href="#5-删除文件" class="headerlink" title="5.删除文件"></a>5.删除文件</h2><p>删除工作区文件:</p>
<figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">[root@LAPTOP-1UJN7PP7 git-learn]# rm -rf test.txt</span><br><span class="line"></span><br></pre></td></tr></table></figure>
<p>查看状态:</p>
<figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">[root@LAPTOP-1UJN7PP7 git-learn]# git status</span><br><span class="line"><span class="meta"># </span><span class="language-bash">On branch master</span></span><br><span class="line"><span class="meta"># </span><span class="language-bash">Changes not staged <span class="keyword">for</span> commit:</span></span><br><span class="line"><span class="meta"># </span><span class="language-bash"> (use <span class="string">"git add/rm <file>..."</span> to update what will be committed)</span></span><br><span class="line"><span class="meta"># </span><span class="language-bash"> (use <span class="string">"git checkout -- <file>..."</span> to discard changes <span class="keyword">in</span> working directory)</span></span><br><span class="line"><span class="meta">#</span><span class="language-bash"></span></span><br><span class="line"><span class="language-bash"><span class="comment"># deleted: test.txt</span></span></span><br><span class="line"><span class="meta">#</span><span class="language-bash"></span></span><br><span class="line"><span class="language-bash">no changes added to commit (use <span class="string">"git add"</span> and/or <span class="string">"git commit -a"</span>)</span></span><br><span class="line"></span><br></pre></td></tr></table></figure>
<p>Git知道我们删除了文件并提示<code>use "git add/rm <file>..." to update what will be committed</code>,即我们可以使用<code>git add <file></code>或者<code>git rm <file></code>来删除版本库中的文件:</p>
<figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">[root@LAPTOP-1UJN7PP7 git-learn]# git rm test.txt</span><br><span class="line">rm 'test.txt'</span><br><span class="line"></span><br></pre></td></tr></table></figure>
<p>然后再commit:</p>
<figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">[root@LAPTOP-1UJN7PP7 git-learn]# git commit -m "Delete a file"</span><br><span class="line">[master af52d1c] Delete a dile</span><br><span class="line"> Committer: root <root@LAPTOP-1UJN7PP7.localdomain></span><br><span class="line">Your name and email address were configured automatically based</span><br><span class="line">on your username and hostname. Please check that they are accurate.</span><br><span class="line">You can suppress this message by setting them explicitly:</span><br><span class="line"></span><br><span class="line"> git config --global user.name "Your Name"</span><br><span class="line"> git config --global user.email you@example.com</span><br><span class="line"></span><br><span class="line">After doing this, you may fix the identity used for this commit with:</span><br><span class="line"></span><br><span class="line"> git commit --amend --reset-author</span><br><span class="line"></span><br><span class="line"> 1 file changed, 1 deletion(-)</span><br><span class="line"> delete mode 100644 test.txt</span><br><span class="line"></span><br></pre></td></tr></table></figure>
<p>如果文件只是添加到暂存区但是我们现在需要删除呢?撤销修改即可,使用<code>git reset HEAD <file></code></p>
<ul>
<li>注意:先手动删除文件,然后使用<code>git rm <file></code>和<code>git add<file></code>效果是一样的</li>
<li>文件误删了可以使用版本库来撤销修改</li>
</ul>
<h2 id="6-创建与合并分支"><a href="#6-创建与合并分支" class="headerlink" title="6.创建与合并分支"></a>6.创建与合并分支</h2><p>查看分支:</p>
<figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">[root@LAPTOP-1UJN7PP7 git-learn]# git branch</span><br><span class="line">* master</span><br><span class="line"></span><br></pre></td></tr></table></figure>
<ul>
<li>注意:*表示当前工作分区</li>
</ul>
<p>创建分支:</p>
<figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">[root@LAPTOP-1UJN7PP7 git-learn]# git branch dev</span><br><span class="line"></span><br></pre></td></tr></table></figure>
<p>这个时候我们在查看一下分支的情况:</p>
<figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">[root@LAPTOP-1UJN7PP7 git-learn]# git branch</span><br><span class="line"> dev</span><br><span class="line">* master</span><br><span class="line"></span><br></pre></td></tr></table></figure>
<p>切换分支:</p>
<figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">[root@LAPTOP-1UJN7PP7 git-learn]# git checkout dev</span><br><span class="line">Switched to branch 'dev'</span><br><span class="line"></span><br></pre></td></tr></table></figure>
<ul>
<li><p>注意:在新版本的Git中可使用switch来切换</p>
</li>
<li><p>创建+切换分支:<code>git checkout -b <name></code>或者<code>git switch -c <name></code></p>
</li>
</ul>
<p>合并某分支到当前分支(dev分支已经做了修改并且切换当前工作分支为master):</p>
<figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">[root@LAPTOP-1UJN7PP7 git-learn]# git merge dev</span><br><span class="line">Updating e9442cf..4dfabbc</span><br><span class="line">Fast-forward</span><br><span class="line"> README.md | 1 +</span><br><span class="line"> dev.txt | 1 +</span><br><span class="line"> 2 files changed, 2 insertions(+)</span><br><span class="line"> create mode 100644 dev.txt</span><br><span class="line"></span><br></pre></td></tr></table></figure>
<ul>
<li>注意:此处dev分支和master分支不存在冲突</li>
</ul>
<p>删除分支:</p>
<figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">[root@LAPTOP-1UJN7PP7 git-learn]# git branch -d dev</span><br><span class="line">Deleted branch dev (was 4dfabbc).</span><br><span class="line"></span><br></pre></td></tr></table></figure>
<h2 id="7-解决冲突"><a href="#7-解决冲突" class="headerlink" title="7.解决冲突"></a>7.解决冲突</h2><p>当Git无法自动合并分支时,就必须首先解决冲突。解决冲突后,再提交,合并完成。解决冲突就是把Git合并失败的文件手动编辑为我们希望的内容,再提交。</p>
<p>此处先模拟一个冲突(创建一个分支并在两个分支做一个无法快速合并的提交,即存在冲突):</p>
<figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">[root@LAPTOP-1UJN7PP7 git-learn]# git checkout -b feature</span><br><span class="line">Switched to a new branch 'feature'</span><br><span class="line">[root@LAPTOP-1UJN7PP7 git-learn]# ls</span><br><span class="line">dev.txt README.md test.txt</span><br><span class="line">[root@LAPTOP-1UJN7PP7 git-learn]# echo "This is feature line" >> README.md</span><br><span class="line">[root@LAPTOP-1UJN7PP7 git-learn]# git add README.md</span><br><span class="line">[root@LAPTOP-1UJN7PP7 git-learn]# git commit -m "Add a line in feature branch"</span><br><span class="line">[feature 4ecad70] Add a line in feature branch</span><br><span class="line"> Committer: root <root@LAPTOP-1UJN7PP7.localdomain></span><br><span class="line">Your name and email address were configured automatically based</span><br><span class="line">on your username and hostname. Please check that they are accurate.</span><br><span class="line">You can suppress this message by setting them explicitly:</span><br><span class="line"></span><br><span class="line"> git config --global user.name "Your Name"</span><br><span class="line"> git config --global user.email you@example.com</span><br><span class="line"></span><br><span class="line">After doing this, you may fix the identity used for this commit with:</span><br><span class="line"></span><br><span class="line"> git commit --amend --reset-author</span><br><span class="line"></span><br><span class="line"> 1 file changed, 1 insertion(+)</span><br><span class="line">[root@LAPTOP-1UJN7PP7 git-learn]# git checkout master</span><br><span class="line">Switched to branch 'master'</span><br><span class="line">[root@LAPTOP-1UJN7PP7 git-learn]# echo "This is master line" >> README.md</span><br><span class="line">[root@LAPTOP-1UJN7PP7 git-learn]# git add README.md</span><br><span class="line">[root@LAPTOP-1UJN7PP7 git-learn]# git commit -m "Add a line in master branch"</span><br><span class="line">[master 9a22c75] Add a line in master branch</span><br><span class="line"> Committer: root <root@LAPTOP-1UJN7PP7.localdomain></span><br><span class="line">Your name and email address were configured automatically based</span><br><span class="line">on your username and hostname. Please check that they are accurate.</span><br><span class="line">You can suppress this message by setting them explicitly:</span><br><span class="line"></span><br><span class="line"> git config --global user.name "Your Name"</span><br><span class="line"> git config --global user.email you@example.com</span><br><span class="line"></span><br><span class="line">After doing this, you may fix the identity used for this commit with:</span><br><span class="line"></span><br><span class="line"> git commit --amend --reset-author</span><br><span class="line"></span><br><span class="line"> 1 file changed, 1 insertion(+)</span><br><span class="line"></span><br></pre></td></tr></table></figure>
<p>我们尝试合并:</p>
<figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">[root@LAPTOP-1UJN7PP7 git-learn]# git merge feature</span><br><span class="line">Auto-merging README.md</span><br><span class="line">CONFLICT (content): Merge conflict in README.md</span><br><span class="line">Automatic merge failed; fix conflicts and then commit the result.</span><br><span class="line"></span><br></pre></td></tr></table></figure>
<p>发生冲突,无法自动合并</p>
<p>此时我们查看状态:</p>
<figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">[root@LAPTOP-1UJN7PP7 git-learn]# git status</span><br><span class="line"><span class="meta"># </span><span class="language-bash">On branch master</span></span><br><span class="line"><span class="meta"># </span><span class="language-bash">You have unmerged paths.</span></span><br><span class="line"><span class="meta"># </span><span class="language-bash"> (fix conflicts and run <span class="string">"git commit"</span>)</span></span><br><span class="line"><span class="meta">#</span><span class="language-bash"></span></span><br><span class="line"><span class="language-bash"><span class="comment"># Unmerged paths:</span></span></span><br><span class="line"><span class="meta"># </span><span class="language-bash"> (use <span class="string">"git add <file>..."</span> to mark resolution)</span></span><br><span class="line"><span class="meta">#</span><span class="language-bash"></span></span><br><span class="line"><span class="language-bash"><span class="comment"># both modified: README.md</span></span></span><br><span class="line"><span class="meta">#</span><span class="language-bash"></span></span><br><span class="line"><span class="language-bash">no changes added to commit (use <span class="string">"git add"</span> and/or <span class="string">"git commit -a"</span>)</span></span><br><span class="line"></span><br></pre></td></tr></table></figure>
<p>也提示存在冲突,并且提示<code>fix conflicts and run "git commit"</code>,即修改文件后使用<code>git commit</code>来解决冲突</p>
<p>我们查看文件:</p>
<figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">[root@LAPTOP-1UJN7PP7 git-learn]# cat README.md</span><br><span class="line">This git test file</span><br><span class="line">This is dev line</span><br><span class="line"><<<<<<< HEAD</span><br><span class="line">This is master line</span><br><span class="line">=======</span><br><span class="line">This is feature line</span><br><span class="line"><span class="meta">></span><span class="language-bash">>>>>>> feature</span></span><br><span class="line"></span><br></pre></td></tr></table></figure>
<p>Git用<code><<<<<<<</code>,<code>=======</code>,<code>>>>>>>></code>标记出不同分支的内容,我们修改如下后保存:</p>
<figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">[root@LAPTOP-1UJN7PP7 git-learn]# cat README.md</span><br><span class="line">This git test file</span><br><span class="line">This is dev line</span><br><span class="line">This is master and feature line</span><br><span class="line"></span><br></pre></td></tr></table></figure>
<p>提交修改:</p>
<figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">[root@LAPTOP-1UJN7PP7 git-learn]# git add README.md</span><br><span class="line">[root@LAPTOP-1UJN7PP7 git-learn]# git commit -m "conflict fixed"</span><br><span class="line">[master e52bbb2] conflict fixed</span><br><span class="line"> Committer: root <root@LAPTOP-1UJN7PP7.localdomain></span><br><span class="line">Your name and email address were configured automatically based</span><br><span class="line">on your username and hostname. Please check that they are accurate.</span><br><span class="line">You can suppress this message by setting them explicitly:</span><br><span class="line"></span><br><span class="line"> git config --global user.name "Your Name"</span><br><span class="line"> git config --global user.email you@example.com</span><br><span class="line"></span><br><span class="line">After doing this, you may fix the identity used for this commit with:</span><br><span class="line"></span><br><span class="line"> git commit --amend --reset-author</span><br><span class="line"></span><br></pre></td></tr></table></figure>
<p>可以看到冲突解决了</p>
<p>用带参数的<code>git log</code>可以看到分支的合并情况:</p>
<figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">[root@LAPTOP-1UJN7PP7 git-learn]# git log --graph --pretty=oneline --abbrev-commit</span><br><span class="line">* e52bbb2 conflict fixed</span><br><span class="line">|\</span><br><span class="line">| * 4ecad70 Add a line in feature branch</span><br><span class="line">* | 9a22c75 Add a line in master branch</span><br><span class="line">|/</span><br><span class="line">* 4dfabbc dev branch first commit</span><br><span class="line">* e9442cf Add test.txt</span><br><span class="line">* c2f0b57 Modified a file</span><br><span class="line">* 6e2db9d Add a new line</span><br><span class="line">* 061be34 third commit</span><br><span class="line">* 5e3f973 second commit</span><br><span class="line">* 196ad7f first commit</span><br><span class="line"></span><br></pre></td></tr></table></figure>
<p>其图示意思大致如下:</p>
<p><img src="https://s2.loli.net/2022/03/08/hJgzldVL5qxnYoe.png" alt="image-20220308111031068"></p>
<h2 id="8-分支策略"><a href="#8-分支策略" class="headerlink" title="8.分支策略"></a>8.分支策略</h2><p>通常,合并分支时,如果可能,Git会用<code>Fast forward</code>模式,但这种模式下,删除分支后,会丢掉分支信息</p>
<p>如果要强制禁用<code>Fast forward</code>模式,Git就会在merge时生成一个新的commit,这样,从分支历史上就可以看出分支信息</p>
<p>合并分支时,加上<code>--no-ff</code>参数就可以用普通模式合并,合并后的历史有分支,能看出来曾经做过合并</p>
<p>以下是测试:</p>
<p>Fast-forward(默认)模式:</p>
<figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">[root@LAPTOP-1UJN7PP7 git-learn]# git checkout -b dev</span><br><span class="line">Switched to a new branch 'dev'</span><br><span class="line">[root@LAPTOP-1UJN7PP7 git-learn]# echo "This is a new line" >>dev.txt</span><br><span class="line">[root@LAPTOP-1UJN7PP7 git-learn]# git add dev.txt</span><br><span class="line">[root@LAPTOP-1UJN7PP7 git-learn]# git commit -m "Add a line in dev.txt"</span><br><span class="line">[dev 9f34d0d] Add a line in dev.txt</span><br><span class="line"> Committer: root <root@LAPTOP-1UJN7PP7.localdomain></span><br><span class="line">Your name and email address were configured automatically based</span><br><span class="line">on your username and hostname. Please check that they are accurate.</span><br><span class="line">You can suppress this message by setting them explicitly:</span><br><span class="line"></span><br><span class="line"> git config --global user.name "Your Name"</span><br><span class="line"> git config --global user.email you@example.com</span><br><span class="line"></span><br><span class="line">After doing this, you may fix the identity used for this commit with:</span><br><span class="line"></span><br><span class="line"> git commit --amend --reset-author</span><br><span class="line"></span><br><span class="line"> 1 file changed, 1 insertion(+)</span><br><span class="line">[root@LAPTOP-1UJN7PP7 git-learn]# git checkout master</span><br><span class="line">Switched to branch 'master'</span><br><span class="line">[root@LAPTOP-1UJN7PP7 git-learn]# git merge dev</span><br><span class="line">Updating e52bbb2..9f34d0d</span><br><span class="line">Fast-forward</span><br><span class="line"> dev.txt | 1 +</span><br><span class="line"> 1 file changed, 1 insertion(+)</span><br><span class="line">[root@LAPTOP-1UJN7PP7 git-learn]# git log</span><br><span class="line">commit 9f34d0def7a71384b3528f9a1056fa1badc9d0c2</span><br><span class="line">Author: root <root@LAPTOP-1UJN7PP7.localdomain></span><br><span class="line">Date: Tue Mar 8 11:58:56 2022 +0800</span><br><span class="line"></span><br><span class="line"> Add a line in dev.txt</span><br><span class="line"></span><br><span class="line">commit e52bbb2ec0fd79188b47060ebe5ee515c14ac557</span><br><span class="line">Merge: 9a22c75 4ecad70</span><br><span class="line">Author: root <root@LAPTOP-1UJN7PP7.localdomain></span><br><span class="line">Date: Tue Mar 8 11:06:11 2022 +0800</span><br><span class="line"></span><br><span class="line"> conflict fixed</span><br><span class="line"></span><br><span class="line"></span><br></pre></td></tr></table></figure>
<p>普通模式(–no-ff):</p>
<figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">[root@LAPTOP-1UJN7PP7 git-learn]# git checkout -b dev</span><br><span class="line">Switched to a new branch 'dev'</span><br><span class="line">[root@LAPTOP-1UJN7PP7 git-learn]# echo "This is second new line" >>dev.txt</span><br><span class="line">[root@LAPTOP-1UJN7PP7 git-learn]# git add dev.txt</span><br><span class="line">[root@LAPTOP-1UJN7PP7 git-learn]# git commit -m "Add a line in dev.txt"</span><br><span class="line">[dev 1e70bdc] Add a line in dev.txt</span><br><span class="line"> Committer: root <root@LAPTOP-1UJN7PP7.localdomain></span><br><span class="line">Your name and email address were configured automatically based</span><br><span class="line">on your username and hostname. Please check that they are accurate.</span><br><span class="line">You can suppress this message by setting them explicitly:</span><br><span class="line"></span><br><span class="line"> git config --global user.name "Your Name"</span><br><span class="line"> git config --global user.email you@example.com</span><br><span class="line"></span><br><span class="line">After doing this, you may fix the identity used for this commit with:</span><br><span class="line"></span><br><span class="line"> git commit --amend --reset-author</span><br><span class="line"></span><br><span class="line"> 1 file changed, 1 insertion(+)</span><br><span class="line">[root@LAPTOP-1UJN7PP7 git-learn]# git checkout master</span><br><span class="line">Switched to branch 'master'</span><br><span class="line">[root@LAPTOP-1UJN7PP7 git-learn]# git merge dev --no-ff</span><br><span class="line">Merge made by the 'recursive' strategy.</span><br><span class="line"> dev.txt | 1 +</span><br><span class="line"> 1 file changed, 1 insertion(+)</span><br><span class="line">[root@LAPTOP-1UJN7PP7 git-learn]# git log --graph --pretty=oneline --abbrev-commit</span><br><span class="line">* afca374 Merge branch 'dev'</span><br><span class="line">|\</span><br><span class="line">| * 1e70bdc Add a line in dev.txt</span><br><span class="line">|/</span><br><span class="line">* 9f34d0d Add a line in dev.txt</span><br><span class="line">* e52bbb2 conflict fixed</span><br><span class="line">|\</span><br><span class="line">| * 4ecad70 Add a line in feature branch</span><br><span class="line">* | 9a22c75 Add a line in master branch</span><br><span class="line">|/</span><br><span class="line">* 4dfabbc dev branch first commit</span><br><span class="line">* e9442cf Add test.txt</span><br><span class="line">* c2f0b57 Modified a file</span><br><span class="line">* 6e2db9d Add a new line</span><br><span class="line">* 061be34 third commit</span><br><span class="line">* 5e3f973 second commit</span><br><span class="line">* 196ad7f first commit</span><br><span class="line"></span><br></pre></td></tr></table></figure>
<h2 id="9-BUG分支"><a href="#9-BUG分支" class="headerlink" title="9.BUG分支"></a>9.BUG分支</h2><p>你正在dev分支上开发你的代码,但是临时接到一个BUG修改任务,我们需要先存储现在的未完成的工作区内容,再创建一个BUG修复分支,修复完成后merge到master,并且由于dev分支也有这个BUG,需要也将这个修复复制到dev分支</p>
<p>存储工作区:</p>
<figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">[root@LAPTOP-1UJN7PP7 git-learn]# git stash</span><br><span class="line">Saved working directory and index state WIP on dev: afca374 Merge branch 'dev'</span><br><span class="line">HEAD is now at afca374 Merge branch 'dev'</span><br><span class="line"></span><br></pre></td></tr></table></figure>
<p>切换到master分支并且创建BUG修复分支:</p>
<figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">[root@LAPTOP-1UJN7PP7 git-learn]# git checkout master</span><br><span class="line">Switched to branch 'master'</span><br><span class="line">[root@LAPTOP-1UJN7PP7 git-learn]# git checkout -b bug-fixed</span><br><span class="line">Switched to a new branch 'bug-fixed'</span><br><span class="line"></span><br></pre></td></tr></table></figure>
<p>修复BUG并提交和merge:</p>
<figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">[root@LAPTOP-1UJN7PP7 git-learn]# echo "fix bug" >> README.md</span><br><span class="line">[root@LAPTOP-1UJN7PP7 git-learn]# git add README.md</span><br><span class="line">[root@LAPTOP-1UJN7PP7 git-learn]# git commit -m "bug fixed"</span><br><span class="line">[bug-fixed b5abcdd] bug fixed</span><br><span class="line"> Committer: root <root@LAPTOP-1UJN7PP7.localdomain></span><br><span class="line">Your name and email address were configured automatically based</span><br><span class="line">on your username and hostname. Please check that they are accurate.</span><br><span class="line">You can suppress this message by setting them explicitly:</span><br><span class="line"></span><br><span class="line"> git config --global user.name "Your Name"</span><br><span class="line"> git config --global user.email you@example.com</span><br><span class="line"></span><br><span class="line">After doing this, you may fix the identity used for this commit with:</span><br><span class="line"></span><br><span class="line"> git commit --amend --reset-author</span><br><span class="line"></span><br><span class="line"> 1 file changed, 1 insertion(+)</span><br><span class="line">[root@LAPTOP-1UJN7PP7 git-learn]# git checkout master</span><br><span class="line">Switched to branch 'master'</span><br><span class="line">[root@LAPTOP-1UJN7PP7 git-learn]# git merge bug-fixed</span><br><span class="line">Updating afca374..b5abcdd</span><br><span class="line">Fast-forward</span><br><span class="line"> README.md | 1 +</span><br><span class="line"> 1 file changed, 1 insertion(+)</span><br><span class="line"></span><br></pre></td></tr></table></figure>
<p>我们查看master分支:</p>
<figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">[root@LAPTOP-1UJN7PP7 git-learn]# git branch</span><br><span class="line"> dev</span><br><span class="line">* master</span><br><span class="line">[root@LAPTOP-1UJN7PP7 git-learn]# cat README.md</span><br><span class="line">This git test file</span><br><span class="line">This is dev line</span><br><span class="line">This is master and feature line</span><br><span class="line">fix bug</span><br><span class="line"></span><br></pre></td></tr></table></figure>
<p>可以看到BUG在master上已经修复</p>
<p>可是dev分支呢?</p>
<figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">[root@LAPTOP-1UJN7PP7 git-learn]# git checkout dev</span><br><span class="line">Switched to branch 'dev'</span><br><span class="line">[root@LAPTOP-1UJN7PP7 git-learn]# cat README.md</span><br><span class="line">This git test file</span><br><span class="line">This is dev line</span><br><span class="line">This is master and feature line</span><br><span class="line"></span><br></pre></td></tr></table></figure>
<p>dev上的BUG可没修复</p>
<p>将master上的BUG修复复制到dev上:</p>
<ul>
<li>获得修复的版本的<code>commit id</code></li>
</ul>
<figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">[root@LAPTOP-1UJN7PP7 git-learn]# git checkout master</span><br><span class="line">Switched to branch 'master'</span><br><span class="line">[root@LAPTOP-1UJN7PP7 git-learn]# git log --graph</span><br><span class="line">* commit b5abcdd2cb9294a98874cd3ab78a212566728dec</span><br><span class="line">| Author: root <root@LAPTOP-1UJN7PP7.localdomain></span><br><span class="line">| Date: Tue Mar 8 12:47:40 2022 +0800</span><br><span class="line">|</span><br><span class="line">| bug fixed</span><br><span class="line">|</span><br><span class="line">* commit afca374ed3030782154c0b289378286111006643</span><br><span class="line">|\ Merge: 9f34d0d 1e70bdc</span><br><span class="line">| | Author: root <root@LAPTOP-1UJN7PP7.localdomain></span><br><span class="line">| | Date: Tue Mar 8 12:24:00 2022 +0800</span><br><span class="line">| |</span><br><span class="line">| | Merge branch 'dev'</span><br><span class="line">| |</span><br><span class="line">| * commit 1e70bdc1dee854f049b18e11e0b0971c30fc34e6</span><br><span class="line">|/ Author: root <root@LAPTOP-1UJN7PP7.localdomain></span><br><span class="line">| Date: Tue Mar 8 12:23:09 2022 +0800</span><br><span class="line">|</span><br><span class="line">| Add a line in dev.txt</span><br><span class="line">|</span><br><span class="line"></span><br></pre></td></tr></table></figure>
<p>复制修复到dev:</p>
<figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">[root@LAPTOP-1UJN7PP7 git-learn]# git checkout dev</span><br><span class="line">Switched to branch 'dev'</span><br><span class="line">[root@LAPTOP-1UJN7PP7 git-learn]# git cherry-pick b5abcdd</span><br><span class="line">[dev 7429c57] bug fixed</span><br><span class="line"> Committer: root <root@LAPTOP-1UJN7PP7.localdomain></span><br><span class="line">Your name and email address were configured automatically based</span><br><span class="line">on your username and hostname. Please check that they are accurate.</span><br><span class="line">You can suppress this message by setting them explicitly:</span><br><span class="line"></span><br><span class="line"> git config --global user.name "Your Name"</span><br><span class="line"> git config --global user.email you@example.com</span><br><span class="line"></span><br><span class="line">After doing this, you may fix the identity used for this commit with:</span><br><span class="line"></span><br><span class="line"> git commit --amend --reset-author</span><br><span class="line"></span><br><span class="line"> 1 file changed, 1 insertion(+)</span><br><span class="line"></span><br></pre></td></tr></table></figure>
<p>查看状态:</p>
<figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">[root@LAPTOP-1UJN7PP7 git-learn]# cat README.md</span><br><span class="line">This git test file</span><br><span class="line">This is dev line</span><br><span class="line">This is master and feature line</span><br><span class="line">fix bug</span><br><span class="line">[root@LAPTOP-1UJN7PP7 git-learn]# git log --graph</span><br><span class="line">* commit 7429c57090cf3a146ec6f64ff60658922e08b235</span><br><span class="line">| Author: root <root@LAPTOP-1UJN7PP7.localdomain></span><br><span class="line">| Date: Tue Mar 8 12:47:40 2022 +0800</span><br><span class="line">|</span><br><span class="line">| bug fixed</span><br><span class="line">|</span><br><span class="line">* commit afca374ed3030782154c0b289378286111006643</span><br><span class="line">|\ Merge: 9f34d0d 1e70bdc</span><br><span class="line">| | Author: root <root@LAPTOP-1UJN7PP7.localdomain></span><br><span class="line">| | Date: Tue Mar 8 12:24:00 2022 +0800</span><br><span class="line">| |</span><br><span class="line">| | Merge branch 'dev'</span><br><span class="line">| |</span><br><span class="line">| * commit 1e70bdc1dee854f049b18e11e0b0971c30fc34e6</span><br><span class="line">|/ Author: root <root@LAPTOP-1UJN7PP7.localdomain></span><br><span class="line">| Date: Tue Mar 8 12:23:09 2022 +0800</span><br><span class="line">|</span><br><span class="line">| Add a line in dev.txt</span><br><span class="line">|</span><br><span class="line"></span><br></pre></td></tr></table></figure>
<p>可以看到dev上的BUG确实修复了并且在dev上有了一次新的commit</p>
<p>最后,恢复工作区:</p>
<figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">[root@LAPTOP-1UJN7PP7 git-learn]# git stash pop</span><br><span class="line"><span class="meta"># </span><span class="language-bash">On branch dev</span></span><br><span class="line"><span class="meta"># </span><span class="language-bash">Changes not staged <span class="keyword">for</span> commit:</span></span><br><span class="line"><span class="meta"># </span><span class="language-bash"> (use <span class="string">"git add <file>..."</span> to update what will be committed)</span></span><br><span class="line"><span class="meta"># </span><span class="language-bash"> (use <span class="string">"git checkout -- <file>..."</span> to discard changes <span class="keyword">in</span> working directory)</span></span><br><span class="line"><span class="meta">#</span><span class="language-bash"></span></span><br><span class="line"><span class="language-bash"><span class="comment"># modified: dev.txt</span></span></span><br><span class="line"><span class="meta">#</span><span class="language-bash"></span></span><br><span class="line"><span class="language-bash">no changes added to commit (use <span class="string">"git add"</span> and/or <span class="string">"git commit -a"</span>)</span></span><br><span class="line">Dropped refs/stash@{0} (18f91d7c6f57e8b4b58d6172419a814a61b0d07e)</span><br><span class="line"></span><br></pre></td></tr></table></figure>
<p>恢复的方法有两种:</p>
<ul>
<li>一是用<code>git stash apply</code>恢复,但是恢复后,stash内容并不删除,你需要用<code>git stash drop</code>来删除</li>
<li>另一种方式是用<code>git stash pop</code>,恢复的同时把stash内容也删了</li>
</ul>
<h2 id="10-feature分支"><a href="#10-feature分支" class="headerlink" title="10.feature分支"></a>10.feature分支</h2><p>开发一个新feature,最好新建一个分支</p>
<p>顺利的话,开发完成后merge一下就好</p>
<p>如果要丢弃一个没有被合并过的分支,可以通过<code>git branch -D <name></code>强行删除</p>
<figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">[root@LAPTOP-1UJN7PP7 git-learn]# git branch -d dev</span><br><span class="line">error: The branch 'dev' is not fully merged.</span><br><span class="line">If you are sure you want to delete it, run 'git branch -D dev'.</span><br><span class="line">[root@LAPTOP-1UJN7PP7 git-learn]# git branch -D dev</span><br><span class="line">Deleted branch dev (was 7429c57).</span><br><span class="line"></span><br></pre></td></tr></table></figure>
<h2 id="11-多人协作"><a href="#11-多人协作" class="headerlink" title="11.多人协作"></a>11.多人协作</h2><p>查看远程仓库:</p>
<figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">[root@LAPTOP-1UJN7PP7 git-learn]# git remote -v</span><br><span class="line">origin git@github.com:zhnny/git-learn.git (fetch)</span><br><span class="line">origin git@github.com:zhnny/git-learn.git (push)</span><br><span class="line"></span><br></pre></td></tr></table></figure>
<h3 id="11-1-推送分支"><a href="#11-1-推送分支" class="headerlink" title="11.1.推送分支"></a>11.1.推送分支</h3><p>推送master分支:</p>
<figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">[root@LAPTOP-1UJN7PP7 git-learn]# git push origin master</span><br><span class="line">Everything up-to-date</span><br><span class="line"></span><br></pre></td></tr></table></figure>
<p>推送dev分支:</p>
<figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">[root@LAPTOP-1UJN7PP7 git-learn]# git push origin dev</span><br><span class="line">Counting objects: 5, done.</span><br><span class="line">Delta compression using up to 12 threads.</span><br><span class="line">Compressing objects: 100% (3/3), done.</span><br><span class="line">Writing objects: 100% (3/3), 360 bytes | 0 bytes/s, done.</span><br><span class="line">Total 3 (delta 0), reused 0 (delta 0)</span><br><span class="line">remote:</span><br><span class="line">remote: Create a pull request for 'dev' on GitHub by visiting:</span><br><span class="line">remote: https://github.com/zhnny/git-learn/pull/new/dev</span><br><span class="line">remote:</span><br><span class="line">To git@github.com:zhnny/git-learn.git</span><br><span class="line"> * [new branch] dev -> dev</span><br><span class="line"></span><br></pre></td></tr></table></figure>
<h3 id="11-2-抓取分支"><a href="#11-2-抓取分支" class="headerlink" title="11.2.抓取分支"></a>11.2.抓取分支</h3><p>克隆远端仓库:</p>
<figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">[root@LAPTOP-1UJN7PP7 clone]# git clone git@github.com:zhnny/git-learn.git</span><br><span class="line">Cloning into 'git-learn'...</span><br><span class="line">remote: Enumerating objects: 44, done.</span><br><span class="line">remote: Counting objects: 100% (44/44), done.</span><br><span class="line">remote: Compressing objects: 100% (27/27), done.</span><br><span class="line">remote: Total 44 (delta 4), reused 43 (delta 3), pack-reused 0</span><br><span class="line">Receiving objects: 100% (44/44), 4.02 KiB | 0 bytes/s, done.</span><br><span class="line">Resolving deltas: 100% (4/4), done.</span><br><span class="line"></span><br></pre></td></tr></table></figure>
<p>默认情况下只有master分支:</p>
<figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">[root@LAPTOP-1UJN7PP7 git-learn]# git branch</span><br><span class="line">* master</span><br><span class="line"></span><br></pre></td></tr></table></figure>
<p>抓取dev分支:</p>
<figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">[root@LAPTOP-1UJN7PP7 git-learn]# git checkout -b dev origin/dev</span><br><span class="line">Branch dev set up to track remote branch dev from origin.</span><br><span class="line">Switched to a new branch 'dev'</span><br><span class="line"></span><br></pre></td></tr></table></figure>
<h3 id="11-3-处理冲突"><a href="#11-3-处理冲突" class="headerlink" title="11.3.处理冲突"></a>11.3.处理冲突</h3><p>一个人修改了dev并推送:</p>
<figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">[root@LAPTOP-1UJN7PP7 git-learn]# echo "This is a new line" >> dev.txt</span><br><span class="line">[root@LAPTOP-1UJN7PP7 git-learn]# git add dev.txt</span><br><span class="line">[root@LAPTOP-1UJN7PP7 git-learn]# git commit -m "Add a line"</span><br><span class="line">[dev 29f398e] Add a line</span><br><span class="line"> Committer: root <root@LAPTOP-1UJN7PP7.localdomain></span><br><span class="line">Your name and email address were configured automatically based</span><br><span class="line">on your username and hostname. Please check that they are accurate.</span><br><span class="line">You can suppress this message by setting them explicitly:</span><br><span class="line"></span><br><span class="line"> git config --global user.name "Your Name"</span><br><span class="line"> git config --global user.email you@example.com</span><br><span class="line"></span><br><span class="line">After doing this, you may fix the identity used for this commit with:</span><br><span class="line"></span><br><span class="line"> git commit --amend --reset-author</span><br><span class="line"></span><br><span class="line"> 1 file changed, 1 insertion(+)</span><br><span class="line">[root@LAPTOP-1UJN7PP7 git-learn]# git push origin dev</span><br><span class="line">Counting objects: 5, done.</span><br><span class="line">Delta compression using up to 12 threads.</span><br><span class="line">Compressing objects: 100% (3/3), done.</span><br><span class="line">Writing objects: 100% (3/3), 338 bytes | 0 bytes/s, done.</span><br><span class="line">Total 3 (delta 1), reused 0 (delta 0)</span><br><span class="line">remote: Resolving deltas: 100% (1/1), completed with 1 local object.</span><br><span class="line">To git@github.com:zhnny/git-learn.git</span><br><span class="line"> a7ae8d2..29f398e dev -> dev</span><br><span class="line"></span><br></pre></td></tr></table></figure>
<p>另一个人修改了dev并推送:</p>
<figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">[root@LAPTOP-1UJN7PP7 git-learn]# echo "This is a new line" >> dev.txt</span><br><span class="line">[root@LAPTOP-1UJN7PP7 git-learn]# git add dev.txt</span><br><span class="line">[root@LAPTOP-1UJN7PP7 git-learn]# git commit -m "Add a line"</span><br><span class="line">[dev 2a494fc] Add a line</span><br><span class="line"> Committer: root <root@LAPTOP-1UJN7PP7.localdomain></span><br><span class="line">Your name and email address were configured automatically based</span><br><span class="line">on your username and hostname. Please check that they are accurate.</span><br><span class="line">You can suppress this message by setting them explicitly:</span><br><span class="line"></span><br><span class="line"> git config --global user.name "Your Name"</span><br><span class="line"> git config --global user.email you@example.com</span><br><span class="line"></span><br><span class="line">After doing this, you may fix the identity used for this commit with:</span><br><span class="line"></span><br><span class="line"> git commit --amend --reset-author</span><br><span class="line"></span><br><span class="line"> 1 file changed, 1 insertion(+)</span><br><span class="line">[root@LAPTOP-1UJN7PP7 git-learn]# git push origin dev</span><br><span class="line">To git@github.com:zhnny/git-learn.git</span><br><span class="line"> ! [rejected] dev -> dev (fetch first)</span><br><span class="line">error: failed to push some refs to 'git@github.com:zhnny/git-learn.git'</span><br><span class="line">hint: Updates were rejected because the remote contains work that you do</span><br><span class="line">hint: not have locally. This is usually caused by another repository pushing</span><br><span class="line">hint: to the same ref. You may want to first merge the remote changes (e.g.,</span><br><span class="line">hint: 'git pull') before pushing again.</span><br><span class="line">hint: See the 'Note about fast-forwards' in 'git push --help' for details.</span><br><span class="line"></span><br></pre></td></tr></table></figure>
<p>可以看到后面这个push失败,Git提示我们先pull下来,merge后再推送</p>
<p>pull远程仓库:</p>
<figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">[root@LAPTOP-1UJN7PP7 git-learn]# git pull</span><br><span class="line">remote: Enumerating objects: 5, done.</span><br><span class="line">remote: Counting objects: 100% (5/5), done.</span><br><span class="line">remote: Compressing objects: 100% (2/2), done.</span><br><span class="line">remote: Total 3 (delta 1), reused 3 (delta 1), pack-reused 0</span><br><span class="line">Unpacking objects: 100% (3/3), done.</span><br><span class="line">From github.com:zhnny/git-learn</span><br><span class="line"> a7ae8d2..29f398e dev -> origin/dev</span><br><span class="line">There is no tracking information for the current branch.</span><br><span class="line">Please specify which branch you want to merge with.</span><br><span class="line">See git-pull(1) for details</span><br><span class="line"></span><br><span class="line"> git pull <remote> <branch></span><br><span class="line"></span><br><span class="line">If you wish to set tracking information for this branch you can do so with:</span><br><span class="line"></span><br><span class="line"> git branch --set-upstream-to=origin/<branch> dev</span><br><span class="line"></span><br></pre></td></tr></table></figure>
<ul>
<li><code>git pull</code>提示<code>no tracking information</code>,则说明本地分支和远程分支的链接关系没有创建,用命令<code>git branch --set-upstream-to <branch-name> origin/<branch-name></code></li>
</ul>
<p>建立链接关系:</p>
<figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">[root@LAPTOP-1UJN7PP7 git-learn]# git branch --set-upstream-to=origin/dev dev</span><br><span class="line">Branch dev set up to track remote branch dev from origin.</span><br><span class="line"></span><br></pre></td></tr></table></figure>
<p>再次pull:</p>
<figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">[root@LAPTOP-1UJN7PP7 git-learn]# git pull</span><br><span class="line">Merge made by the 'recursive' strategy.</span><br><span class="line"></span><br></pre></td></tr></table></figure>
<p>merge后再次push:</p>
<figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">[root@LAPTOP-1UJN7PP7 git-learn]# git push origin dev</span><br><span class="line">Counting objects: 2, done.</span><br><span class="line">Delta compression using up to 12 threads.</span><br><span class="line">Compressing objects: 100% (2/2), done.</span><br><span class="line">Writing objects: 100% (2/2), 353 bytes | 0 bytes/s, done.</span><br><span class="line">Total 2 (delta 1), reused 0 (delta 0)</span><br><span class="line">remote: Resolving deltas: 100% (1/1), done.</span><br><span class="line">To git@github.com:zhnny/git-learn.git</span><br><span class="line"> 29f398e..3eda6cf dev -> dev</span><br><span class="line"></span><br></pre></td></tr></table></figure>
<h2 id="12-Rebase操作"><a href="#12-Rebase操作" class="headerlink" title="12.Rebase操作"></a>12.Rebase操作</h2><p>rebase操作:</p>
<ul>
<li><p>rebase操作可以把本地未push的分叉提交历史整理成直线</p>
</li>
<li><p>rebase的目的是使得我们在查看历史提交的变化时更容易,因为分叉的提交需要三方对比</p>
</li>
</ul>
<p>rebase前:</p>
<figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">[root@LAPTOP-1UJN7PP7 git-learn]# git log --graph --pretty=oneline</span><br><span class="line">* b3c1899f42d1364eee047c3ec22ffb7b18912d67 merge conflict</span><br><span class="line">|\</span><br><span class="line">| * 7d9e9e2375785c7d594da445823bc2ceffcb2137 Add a new line</span><br><span class="line">| * 1ed7903f52d52ce675bdedeb29b41f8648aaefbc Add a new line</span><br><span class="line">| * 3bc7183e800263d908d1b7701c9b15860e58beca Add a new line</span><br><span class="line">| * 905a799a93d51d11a588e2493bdc23765b9b3fde merge confict</span><br><span class="line">| |\</span><br><span class="line">| * | aa43bf9c412070c05227e475a5c1f7d633f208c1 Add the fifth line</span><br><span class="line">* | | 6fd7b915a404dbea8dea256c4f5f6e8e4376e9f5 Add a new line</span><br><span class="line">| |/</span><br><span class="line">|/|</span><br><span class="line">* | cda61afd2f6b2c7dcad3db5abe8e1f8304354fbe Add the forth line</span><br><span class="line">* | 44e789020405f50780964136663edd4701bb39d7 Add the third line</span><br><span class="line">|/</span><br><span class="line">* 74a80dc3c466574717ccfffbf341609259e111a6 Add the second new line</span><br><span class="line">* e85a234700ebf67aa23434d9bde59b18845eadee Add a new line</span><br><span class="line">* 1a20b8eba002fcd70bbb6ca039dc41fe66ab1d81 Add a line</span><br><span class="line"></span><br></pre></td></tr></table></figure>
<p>rebase:</p>
<figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">[root@LAPTOP-1UJN7PP7 git-learn]# git rebase</span><br><span class="line">First, rewinding head to replay your work on top of it...</span><br><span class="line">Applying: Add a new line</span><br><span class="line">Using index info to reconstruct a base tree...</span><br><span class="line">M dev.txt</span><br><span class="line">Falling back to patching base and 3-way merge...</span><br><span class="line">Auto-merging dev.txt</span><br><span class="line">CONFLICT (content): Merge conflict in dev.txt</span><br><span class="line">Failed to merge in the changes.</span><br><span class="line">Patch failed at 0001 Add a new line</span><br><span class="line">The copy of the patch that failed is found in:</span><br><span class="line"> /root/clone/git-learn/.git/rebase-apply/patch</span><br><span class="line"></span><br><span class="line">When you have resolved this problem, run "git rebase --continue".</span><br><span class="line">If you prefer to skip this patch, run "git rebase --skip" instead.</span><br><span class="line">To check out the original branch and stop rebasing, run "git rebase --abort".</span><br><span class="line"></span><br><span class="line"></span><br></pre></td></tr></table></figure>
<p>在<code>rebase</code>的过程中,也许会出现冲突(conflict)。在这种情况,Git会停止<code>rebase</code>并会让你去解决冲突;在解决完冲突后,用”<code>git add</code>“命令去更新这些内容的索引(index), 然后,你无需执行 <code>git commit</code>,只要执行:</p>
<figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">[root@LAPTOP-1UJN7PP7 git-learn]# git rebase --continue</span><br><span class="line">Applying: Add a new line</span><br><span class="line"></span><br></pre></td></tr></table></figure>
<p>rebase后:</p>
<figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">[root@LAPTOP-1UJN7PP7 git-learn]# git log --graph --pretty=oneline</span><br><span class="line">* 9119f8fb6a62595fa70456132aa7329aee9630e0 Add a new line</span><br><span class="line">* 7d9e9e2375785c7d594da445823bc2ceffcb2137 Add a new line</span><br><span class="line">* 1ed7903f52d52ce675bdedeb29b41f8648aaefbc Add a new line</span><br><span class="line">* 3bc7183e800263d908d1b7701c9b15860e58beca Add a new line</span><br><span class="line">* 905a799a93d51d11a588e2493bdc23765b9b3fde merge confict</span><br><span class="line">|\</span><br><span class="line">| * cda61afd2f6b2c7dcad3db5abe8e1f8304354fbe Add the forth line</span><br><span class="line">| * 44e789020405f50780964136663edd4701bb39d7 Add the third line</span><br><span class="line">* | aa43bf9c412070c05227e475a5c1f7d633f208c1 Add the fifth line</span><br><span class="line">|/</span><br><span class="line">* 74a80dc3c466574717ccfffbf341609259e111a6 Add the second new line</span><br><span class="line">* e85a234700ebf67aa23434d9bde59b18845eadee Add a new line</span><br><span class="line">* 1a20b8eba002fcd70bbb6ca039dc41fe66ab1d81 Add a line</span><br><span class="line"></span><br></pre></td></tr></table></figure>
<p>在任何时候,可以用<code>--abort</code>参数来终止<code>rebase</code>的操作,并且 分支会回到<code>rebase</code>开始前的状态:</p>
<figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">[root@LAPTOP-1UJN7PP7 git-learn]# git rebase --abort</span><br><span class="line"></span><br></pre></td></tr></table></figure>
<h2 id="13-创建标签"><a href="#13-创建标签" class="headerlink" title="13.创建标签"></a>13.创建标签</h2><p>创建标签:</p>
<figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">[root@LAPTOP-1UJN7PP7 git-learn]# git tag v1.0</span><br><span class="line"></span><br></pre></td></tr></table></figure>
<p>查看标签:</p>
<figure class="highlight shell"><table><tr><td class="code"><pre><span class="line"></span><br><span class="line">[root@LAPTOP-1UJN7PP7 git-learn]# git tag</span><br><span class="line">v1.0</span><br><span class="line"></span><br></pre></td></tr></table></figure>
<p>打之前commit的标签:</p>
<figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">[root@LAPTOP-1UJN7PP7 git-learn]# git log --graph --pretty=oneline</span><br><span class="line">* b5abcdd2cb9294a98874cd3ab78a212566728dec bug fixed</span><br><span class="line">* afca374ed3030782154c0b289378286111006643 Merge branch 'dev'</span><br><span class="line">|\</span><br><span class="line">| * 1e70bdc1dee854f049b18e11e0b0971c30fc34e6 Add a line in dev.txt</span><br><span class="line">|/</span><br><span class="line">* 9f34d0def7a71384b3528f9a1056fa1badc9d0c2 Add a line in dev.txt</span><br><span class="line">* e52bbb2ec0fd79188b47060ebe5ee515c14ac557 conflict fixed</span><br><span class="line">|\</span><br><span class="line">| * 4ecad70e9719d9d5d2e95ca1ef2fc12c7016b4b4 Add a line in feature branch</span><br><span class="line">* | 9a22c75daf397a63a8598094e209f078e0a8a1f7 Add a line in master branch</span><br><span class="line">|/</span><br><span class="line">* 4dfabbce1de291335759960028913e31491ccfce dev branch first commit</span><br><span class="line">* e9442cfef62eada2943e45ac4c2782f2bc54b9b4 Add test.txt</span><br><span class="line">* c2f0b571b6b84becc27440e6670b69b0a9b035a7 Modified a file</span><br><span class="line">* 6e2db9d63f9984e2233a6c3c972b00489f315074 Add a new line</span><br><span class="line">* 061be34209d57299ffe96616f82008ee4655eea0 third commit</span><br><span class="line">* 5e3f973bf0248775995e6197cb999c874abc3859 second commit</span><br><span class="line">* 196ad7fafa50d6558e2c4da42344e7ff292d1447 first commit</span><br><span class="line">[root@LAPTOP-1UJN7PP7 git-learn]# git tag v0.9 afca</span><br><span class="line"></span><br></pre></td></tr></table></figure>
<p>再次查看标签:</p>
<figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">[root@LAPTOP-1UJN7PP7 git-learn]# git tag</span><br><span class="line">v0.9</span><br><span class="line">v1.0</span><br><span class="line"></span><br></pre></td></tr></table></figure>
<ul>
<li>注意,标签不是按时间顺序列出,而是按字母排序的</li>
</ul>
<p>可以用<code>git show <tagname></code>查看标签信息:</p>
<figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">[root@LAPTOP-1UJN7PP7 git-learn]# git show v0.9</span><br><span class="line">commit afca374ed3030782154c0b289378286111006643</span><br><span class="line">Merge: 9f34d0d 1e70bdc</span><br><span class="line">Author: root <root@LAPTOP-1UJN7PP7.localdomain></span><br><span class="line">Date: Tue Mar 8 12:24:00 2022 +0800</span><br><span class="line"></span><br><span class="line"> Merge branch 'dev'</span><br><span class="line"></span><br><span class="line"></span><br></pre></td></tr></table></figure>
<p>还可以创建带有说明的标签,用<code>-a</code>指定标签名,<code>-m</code>指定说明文字:</p>
<figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">[root@LAPTOP-1UJN7PP7 git-learn]# git tag -a v0.1 196a -m "version 0.1 released"</span><br><span class="line"></span><br></pre></td></tr></table></figure>
<ul>
<li>注意:标签总是和某个commit挂钩。如果这个commit既出现在master分支,又出现在dev分支,那么在这两个分支上都可以看到这个标签</li>
</ul>
<h2 id="14-操作标签"><a href="#14-操作标签" class="headerlink" title="14.操作标签"></a>14.操作标签</h2><p>删除标签:</p>
<figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">[root@LAPTOP-1UJN7PP7 git-learn]# git tag -d v0.1</span><br><span class="line">Deleted tag 'v0.1' (was 63f1df9)</span><br><span class="line"></span><br></pre></td></tr></table></figure>
<ul>
<li>因为创建的标签都只存储在本地,不会自动推送到远程。所以,打错的标签可以在本地安全删除</li>
</ul>
<p>推送标签:</p>
<figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">[root@LAPTOP-1UJN7PP7 git-learn]# git push origin v1.0</span><br><span class="line">Total 0 (delta 0), reused 0 (delta 0)</span><br><span class="line">To git@github.com:zhnny/git-learn.git</span><br><span class="line"> * [new tag] v1.0 -> v1.0</span><br><span class="line"></span><br></pre></td></tr></table></figure>
<p>一次性推送全部尚未推送到远程的本地标签:</p>
<figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">[root@LAPTOP-1UJN7PP7 git-learn]# git push origin --tags</span><br><span class="line">Total 0 (delta 0), reused 0 (delta 0)</span><br><span class="line">To git@github.com:zhnny/git-learn.git</span><br><span class="line"> * [new tag] show -> show</span><br><span class="line"> * [new tag] v0.9 -> v0.9</span><br><span class="line"></span><br></pre></td></tr></table></figure>
<p>删除远程标签就麻烦一点,先从本地删除:</p>
<figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">[root@LAPTOP-1UJN7PP7 git-learn]# git tag -d show</span><br><span class="line">Deleted tag 'show' (was afca374)</span><br><span class="line"></span><br></pre></td></tr></table></figure>
<p>然后,从远程删除。删除命令也是push,但是格式如下:</p>
<figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">[root@LAPTOP-1UJN7PP7 git-learn]# git push origin :refs/tags/show</span><br><span class="line">To git@github.com:zhnny/git-learn.git</span><br><span class="line"> - [deleted] show</span><br><span class="line"></span><br></pre></td></tr></table></figure>
<ul>
<li><p>上面这种操作的含义是,将冒号前面的空值推送到远程标签名,从而高效地删除它(参考资料[3])</p>
</li>
<li><p>第二种更直观的删除远程标签的方式是:</p>
<figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">git push origin --delete <tagname></span><br></pre></td></tr></table></figure></li>
</ul>
<h2 id="15-配置Git"><a href="#15-配置Git" class="headerlink" title="15.配置Git"></a>15.配置Git</h2><h3 id="15-1-配置全局信息"><a href="#15-1-配置全局信息" class="headerlink" title="15.1.配置全局信息"></a>15.1.配置全局信息</h3><p>配置用户信息:</p>
<figure class="highlight shell"><table><tr><td class="code"><pre><span class="line"><span class="meta">$ </span><span class="language-bash">git config --global user.name <span class="string">"Your Name"</span></span></span><br><span class="line"><span class="meta">$ </span><span class="language-bash">git config --global user.email <span class="string">"email@example.com"</span></span></span><br></pre></td></tr></table></figure>
<p>配置控制台回显颜色:</p>
<figure class="highlight shell"><table><tr><td class="code"><pre><span class="line"><span class="meta">$ </span><span class="language-bash">git config --global color.ui <span class="literal">true</span></span></span><br></pre></td></tr></table></figure>
<h3 id="15-2-配置忽略文件"><a href="#15-2-配置忽略文件" class="headerlink" title="15.2.配置忽略文件"></a>15.2.配置忽略文件</h3><p>有些文件我们需要忽略,比如密码等配置文件、编译产生的中间文件等</p>
<p>忽略文件的原则是:</p>
<ul>
<li>忽略操作系统自动生成的文件,比如缩略图等</li>
<li>忽略编译生成的中间文件、可执行文件等,也就是如果一个文件是通过另一个文件自动生成的,那自动生成的文件就没必要放进版本库,比如Java编译产生的<code>.class</code>文件</li>
<li>忽略你自己的带有敏感信息的配置文件,比如存放口令的配置文件</li>
</ul>
<p>Git工作区的根目录下创建一个特殊的<code>.gitignore</code>文件,然后把要忽略的文件名填进去,Git就会自动忽略这些文件</p>
<p>不需要从头写<code>.gitignore</code>文件,GitHub已经为我们准备了各种配置文件,只需要组合一下就可以使用了。所有配置文件可以直接在线浏览:</p>
<p><a href="https://github.com/github/gitignore">github/gitignore: A collection of useful .gitignore templates</a></p>
<p>规则:</p>
<figure class="highlight python"><table><tr><td class="code"><pre><span class="line"><span class="comment"># 排除所有.开头的隐藏文件:</span></span><br><span class="line">.*</span><br><span class="line"><span class="comment"># 排除所有.class文件:</span></span><br><span class="line">*.<span class="keyword">class</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 不排除.gitignore和App.class:</span></span><br><span class="line">!.gitignore</span><br><span class="line">!App.<span class="keyword">class</span></span><br></pre></td></tr></table></figure>
<p> 强制添加:</p>
<figure class="highlight shell"><table><tr><td class="code"><pre><span class="line"><span class="meta">$ </span><span class="language-bash">git add -f App.class</span></span><br></pre></td></tr></table></figure>
<ul>
<li>值得注意的是,如果忽略了某个文件排除只能排除子文件下的,子文件夹的子文件下是不能排除的</li>
</ul>
<h3 id="15-3-配置别名"><a href="#15-3-配置别名" class="headerlink" title="15.3.配置别名"></a>15.3.配置别名</h3><p>配置Git命令的别名:</p>
<figure class="highlight shell"><table><tr><td class="code"><pre><span class="line"><span class="meta">$ </span><span class="language-bash">git config --global <span class="built_in">alias</span>.<别名> <命令名></span></span><br></pre></td></tr></table></figure>
<h2 id="16-参考资料"><a href="#16-参考资料" class="headerlink" title="16.参考资料"></a>16.参考资料</h2><p>[1]<a href="https://www.liaoxuefeng.com/wiki/896043488029600">Git教程 - 廖雪峰的官方网站 (liaoxuefeng.com)</a></p>
<p>[2]<a href="https://www.yiibai.com/git/git_rebase.html">git rebase命令 - Git教程™ (yiibai.com)</a></p>
<p>[3]<a href="https://git-scm.com/book/zh/v2/Git-%E5%9F%BA%E7%A1%80-%E6%89%93%E6%A0%87%E7%AD%BE">Git - 打标签 (git-scm.com)</a></p>
]]></content>
<categories>
<category>开发工具</category>
</categories>
<tags>
<tag>Git</tag>
</tags>
</entry>
<entry>
<title>Git的快速使用</title>
<url>/2022/03/09/Git%E7%9A%84%E6%97%A5%E5%B8%B8%E4%BD%BF%E7%94%A8/</url>
<content><![CDATA[<h2 id="1-Git简介"><a href="#1-Git简介" class="headerlink" title="1. Git简介"></a>1. Git简介</h2><ul>
<li><p>Git最初是Linus花了两周时间自己用C写了一个分布式版本控制系统</p>
</li>
<li><p>特点:</p>
<ul>
<li>分布式,每一个主机都有完整版本库</li>
<li>开源免费性能好</li>
</ul>
<p>注:类似GitHub这种中心环境的存在是为了交换方便,换言之,即使不存在这种中心设备,Git也是可以正常使用的</p>
</li>
</ul>
<h2 id="2-Git安装"><a href="#2-Git安装" class="headerlink" title="2. Git安装"></a>2. Git安装</h2><p>笔者使用OS是CentOS Linux,Git的安装命令为</p>
<figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">yum install git</span><br></pre></td></tr></table></figure>
<h2 id="3-创建仓库"><a href="#3-创建仓库" class="headerlink" title="3. 创建仓库"></a>3. 创建仓库</h2><p>创建新文件夹</p>
<figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">mkdir daily-scripts</span><br><span class="line">cd daily-scripts/</span><br></pre></td></tr></table></figure>
<p>初始化Git仓库</p>
<figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">git init</span><br></pre></td></tr></table></figure>
<p>添加文件到目录中</p>
<figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">mv ../POI聚类分析.ipynb POI聚类分析.ipynb </span><br></pre></td></tr></table></figure>
<p>添加文件到仓库</p>
<figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">git add POI聚类分析.ipynb</span><br></pre></td></tr></table></figure>
<p>添加文件夹</p>
<figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">git add jupyter-note-book/</span><br></pre></td></tr></table></figure>
<p>添加多个文件(夹)</p>
<figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">git add jupyter-note-book/ python-file/</span><br></pre></td></tr></table></figure>
<p>注意:Git是不允许提交一个空的目录到版本库上的</p>
<p>提交文件到仓库</p>
<figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">git commit -m "Add a file POI聚类分析.ipynb"</span><br></pre></td></tr></table></figure>
<p>解释:</p>
<ul>
<li><p>Git的工作流如图所示:</p>
<p><img src="https://s2.loli.net/2022/02/28/BDz5JSbxjw8AGTF.png" alt="img"></p>
<p>第一次add命令将改动添加到缓冲区,第二次的commit命令将改动添加到版本库中</p>
</li>
<li><p>- m “…” 表示此次提交的版本的描述信息</p>
</li>
</ul>
<h2 id="4-添加远程库"><a href="#4-添加远程库" class="headerlink" title="4. 添加远程库"></a>4. 添加远程库</h2><p>笔者在GitHub上创建了一个仓库daily-scripts</p>
<p>根据Github的提示,可以把一个已有的本地仓库与之关联,然后,把本地仓库的内容推送到GitHub仓库</p>
<figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">git remote add origin https://github.com/zhnny/daily-scripts.git</span><br></pre></td></tr></table></figure>
<p>下一步,就可以把本地库的所有内容推送到远程库上:</p>
<figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">git push -u origin master</span><br></pre></td></tr></table></figure>
<p>注意:第一次push的时候,提示输入用户名和密码,需要去GitHub的Settings中去生成Token</p>
<p>关于连接远程仓库使用的ssh key和Token,具体可参考博客[<a href="https://www.cnblogs.com/chenyablog/p/15397548.html">GitHub使用Personal access token</a>]</p>
<p>push完成后,GitHub中对应的repo中就有一个相同的仓库了</p>
<p>GitHub上的仓库既可以作为备份,又可以让其他人通过该仓库来协作</p>
<h2 id="5-克隆远程库"><a href="#5-克隆远程库" class="headerlink" title="5. 克隆远程库"></a>5. 克隆远程库</h2><p>克隆GitHub上的仓库</p>
<figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">git clone https://github.com/zhnny/PyTorch-Learning-Note.git</span><br></pre></td></tr></table></figure>
<p>Git支持多种协议,包括<code>https</code>,但<code>ssh</code>协议速度最快</p>
<p>ssh协议需要设置公钥,https不需要,但是https在push时要Token</p>
<p>以下步骤将引导完成生成SSH密钥并将公钥添加到GitHub帐户(参考<a href="https://docs.github.com/en/authentication/connecting-to-github-with-ssh/checking-for-existing-ssh-keys">Checking for existing SSH keys - GitHub Docs</a>)</p>
<ul>
<li><p>cd到home目录</p>
<figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">cd ~</span><br></pre></td></tr></table></figure>
</li>
<li><p>查看是否存在密钥(如果存在密钥可以上传)</p>
<figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">ls .ssh/</span><br></pre></td></tr></table></figure>
</li>
<li><p>生成密钥(使用GitHub电子邮箱替换)</p>
<figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">ssh-keygen -t ed25519 -C "your_email@example.com"</span><br></pre></td></tr></table></figure>
<p>接下来一直默认就好,除非你知道你在做什么</p>
</li>
<li><p>复制公钥</p>
<figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">cat .ssh/id_ed25519.pub</span><br></pre></td></tr></table></figure>
</li>
<li><p>将公钥粘贴到你的GitHub账户Settings中的SSH keys中</p>
<p><img src="https://s2.loli.net/2022/02/28/vXpe5N2LQUzYbHP.png" alt="image-20220228215435546"></p>
</li>
</ul>
<p>完成ssh key配置后就可以使用ssh协议克隆repo</p>
<figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">git clone git@github.com:zhnny/PyTorch-Learning-Note.git</span><br></pre></td></tr></table></figure>
<p>push时也可以直接使用ssh协议</p>
<figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">git push git@github.com:zhnny/PyTorch-Learning-Note.git</span><br></pre></td></tr></table></figure>
<p>而不必再使用Token</p>
<h2 id="6-参考资料"><a href="#6-参考资料" class="headerlink" title="6. 参考资料"></a>6. 参考资料</h2><p><a href="https://docs.github.com/en/authentication/connecting-to-github-with-ssh/checking-for-existing-ssh-keys">Checking for existing SSH keys - GitHub Docs</a></p>
<p><a href="https://www.liaoxuefeng.com/wiki/896043488029600/898732792973664">从远程库克隆 - 廖雪峰的官方网站 (liaoxuefeng.com)</a></p>
<p><a href="https://www.cnblogs.com/chenyablog/p/15397548.html">GitHub使用Personal access token - 小旭2021 - 博客园 (cnblogs.com)</a></p>
]]></content>
<categories>
<category>开发工具</category>
</categories>
<tags>
<tag>Git</tag>
<tag>Github</tag>
</tags>
</entry>
<entry>
<title>Hello World</title>
<url>/2022/03/09/hello-world/</url>
<content><![CDATA[<p>Welcome to <a href="https://hexo.io/">Hexo</a>! This is your very first post. Check <a href="https://hexo.io/docs/">documentation</a> for more info. If you get any problems when using Hexo, you can find the answer in <a href="https://hexo.io/docs/troubleshooting.html">troubleshooting</a> or you can ask me on <a href="https://github.com/hexojs/hexo/issues">GitHub</a>.</p>
<h2 id="Quick-Start"><a href="#Quick-Start" class="headerlink" title="Quick Start"></a>Quick Start</h2><h3 id="Create-a-new-post"><a href="#Create-a-new-post" class="headerlink" title="Create a new post"></a>Create a new post</h3><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ hexo new <span class="string">"My New Post"</span></span><br></pre></td></tr></table></figure>
<p>More info: <a href="https://hexo.io/docs/writing.html">Writing</a></p>
<h3 id="Run-server"><a href="#Run-server" class="headerlink" title="Run server"></a>Run server</h3><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ hexo server</span><br></pre></td></tr></table></figure>
<p>More info: <a href="https://hexo.io/docs/server.html">Server</a></p>
<h3 id="Generate-static-files"><a href="#Generate-static-files" class="headerlink" title="Generate static files"></a>Generate static files</h3><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ hexo generate</span><br></pre></td></tr></table></figure>
<p>More info: <a href="https://hexo.io/docs/generating.html">Generating</a></p>
<h3 id="Deploy-to-remote-sites"><a href="#Deploy-to-remote-sites" class="headerlink" title="Deploy to remote sites"></a>Deploy to remote sites</h3><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ hexo deploy</span><br></pre></td></tr></table></figure>
<p>More info: <a href="https://hexo.io/docs/one-command-deployment.html">Deployment</a></p>
]]></content>
<categories>
<category>web前端</category>
</categories>
<tags>
<tag>Hexo</tag>
</tags>
</entry>
<entry>
<title>基于Hexo的GitHub Pages个人博客搭建</title>
<url>/2022/03/09/%E5%9F%BA%E4%BA%8EHexo%E7%9A%84GitHub%20Pages%E4%B8%AA%E4%BA%BA%E5%8D%9A%E5%AE%A2%E6%90%AD%E5%BB%BA/</url>
<content><![CDATA[<h2 id="1-创建一个个人主页仓库"><a href="#1-创建一个个人主页仓库" class="headerlink" title="1.创建一个个人主页仓库"></a>1.创建一个个人主页仓库</h2><p>仓库命名最好为<code>github账户名.github.io</code>,这样可以通过<code>https://github账户名.github.io</code>访问</p>
<p><img src="https://s2.loli.net/2022/03/06/5EZRBIJmxXNoViM.png" alt="image-20220306152739542"></p>
<h2 id="2-安装Hexo"><a href="#2-安装Hexo" class="headerlink" title="2.安装Hexo"></a>2.安装Hexo</h2><p>此处采用局部安装:</p>
<figure class="highlight shell"><table><tr><td class="code"><pre><span class="line"><span class="meta"># </span><span class="language-bash">npm install hexo</span></span><br></pre></td></tr></table></figure>
<h2 id="3-初始化Hexo"><a href="#3-初始化Hexo" class="headerlink" title="3.初始化Hexo"></a>3.初始化Hexo</h2><p>创建一个新的文件夹:</p>
<figure class="highlight shell"><table><tr><td class="code"><pre><span class="line"><span class="meta"># </span><span class="language-bash"><span class="built_in">mkdir</span> blog</span></span><br></pre></td></tr></table></figure>
<p>初始化Hexo</p>
<figure class="highlight shell"><table><tr><td class="code"><pre><span class="line"><span class="meta"># </span><span class="language-bash">npx hexo init blog/</span></span><br></pre></td></tr></table></figure>
<p>进入文件夹并安装Hexo相关组件</p>
<figure class="highlight shell"><table><tr><td class="code"><pre><span class="line"><span class="meta"># </span><span class="language-bash"><span class="built_in">cd</span> blog/</span></span><br><span class="line"><span class="meta"># </span><span class="language-bash">npm install</span></span><br></pre></td></tr></table></figure>
<h2 id="4-测试本地Hexo服务"><a href="#4-测试本地Hexo服务" class="headerlink" title="4.测试本地Hexo服务"></a>4.测试本地Hexo服务</h2><p>在本地运行Hexo</p>
<figure class="highlight shell"><table><tr><td class="code"><pre><span class="line"><span class="meta"># </span><span class="language-bash">npx hexo server</span></span><br></pre></td></tr></table></figure>
<p>浏览器访问<code>http://localhost:4000</code>,出现以下界面即为启动成功:</p>
<p><img src="https://s2.loli.net/2022/03/06/lnfAWDyKOpwUg1s.png" alt="image-20220306154058992"></p>
<h2 id="5-部署到GitHub"><a href="#5-部署到GitHub" class="headerlink" title="5.部署到GitHub"></a>5.部署到GitHub</h2><p>安装Git部署工具:</p>
<figure class="highlight shell"><table><tr><td class="code"><pre><span class="line"><span class="meta"># </span><span class="language-bash">npm install hexo-deployer-git --save</span></span><br></pre></td></tr></table></figure>
<p>修改<code> _config.yml</code>文件末尾的 Deployment 部分,修改成如下:</p>
<figure class="highlight yaml"><table><tr><td class="code"><pre><span class="line"><span class="attr">deploy:</span></span><br><span class="line"> <span class="attr">type:</span> <span class="string">git</span></span><br><span class="line"> <span class="attr">repository:</span> <span class="string">git@github.com:用户名/用户名.github.io.git</span></span><br><span class="line"> <span class="attr">branch:</span> <span class="string">master</span></span><br></pre></td></tr></table></figure>
<p>使用以下命令进行部署:</p>
<figure class="highlight shell"><table><tr><td class="code"><pre><span class="line"><span class="meta"># </span><span class="language-bash">npx hexo deploy</span></span><br></pre></td></tr></table></figure>
<h2 id="6-在GitHub设置Page"><a href="#6-在GitHub设置Page" class="headerlink" title="6.在GitHub设置Page"></a>6.在GitHub设置Page</h2><p>打开刚才创建的仓库可以看到已经添加了一些文件:</p>
<p><img src="https://s2.loli.net/2022/03/06/NIkXl3ZCqKQoLyH.png" alt="image-20220306155326068"></p>
<p>在<code>Settings</code>里的<code>Pages</code>选项中将<code>source</code>设置为<code>master</code>(笔者在推送后GitHub已经自动设置为GitHub Pages):</p>
<p><img src="https://s2.loli.net/2022/03/06/v3H7kGxy9ntwAWE.png" alt="image-20220306155511038"></p>
<p>最后在浏览器里访问<code>https://github账户名.github.io</code>,出现如下结果即为部署成功:</p>
<p><img src="https://s2.loli.net/2022/03/06/mvJCetqU4ElPisk.png" alt="image-20220306155832968"></p>
<h2 id="7-信息修改(可选)"><a href="#7-信息修改(可选)" class="headerlink" title="7.信息修改(可选)"></a>7.信息修改(可选)</h2><p>修改<code> _config.yml</code>文件中的一些信息,包括网站信息、作者信息等</p>
<h2 id="8-安装主题(可选)"><a href="#8-安装主题(可选)" class="headerlink" title="8.安装主题(可选)"></a>8.安装主题(可选)</h2><p>笔者使用的是<code>Next</code>主题:</p>
<figure class="highlight shell"><table><tr><td class="code"><pre><span class="line"><span class="meta"># </span><span class="language-bash">git <span class="built_in">clone</span> https://github.com/iissnan/hexo-theme-next themes/next</span></span><br></pre></td></tr></table></figure>
<p>修改<code> _config.yml</code>文件中的<code>theme</code>信息:</p>
<figure class="highlight yaml"><table><tr><td class="code"><pre><span class="line"><span class="attr">theme:</span> <span class="string">next</span></span><br></pre></td></tr></table></figure>
<h2 id="9-安装插件(可选)"><a href="#9-安装插件(可选)" class="headerlink" title="9.安装插件(可选)"></a>9.安装插件(可选)</h2><h3 id="9-1-本地搜索插件"><a href="#9-1-本地搜索插件" class="headerlink" title="9.1.本地搜索插件"></a>9.1.本地搜索插件</h3><p>添加本地搜索插件:</p>
<figure class="highlight shell"><table><tr><td class="code"><pre><span class="line"><span class="meta"># </span><span class="language-bash">npm install hexo-generator-searchdb --save</span></span><br></pre></td></tr></table></figure>
<p>编辑 <strong>站点配置文件</strong>(网站的<code>_config.yml</code>),新增以下内容到任意位置:</p>
<figure class="highlight yaml"><table><tr><td class="code"><pre><span class="line"><span class="attr">search:</span></span><br><span class="line"> <span class="attr">path:</span> <span class="string">search.xml</span></span><br><span class="line"> <span class="attr">field:</span> <span class="string">post</span></span><br><span class="line"> <span class="attr">format:</span> <span class="string">html</span></span><br><span class="line"> <span class="attr">limit:</span> <span class="number">10000</span></span><br></pre></td></tr></table></figure>
<p>编辑 <strong>主题配置文件</strong>(主题的<code>_config.yml</code>),启用本地搜索功能:</p>
<figure class="highlight yaml"><table><tr><td class="code"><pre><span class="line"><span class="comment"># Local search</span></span><br><span class="line"><span class="attr">local_search:</span></span><br><span class="line"> <span class="attr">enable:</span> <span class="literal">true</span></span><br></pre></td></tr></table></figure>
<h3 id="9-2-MathJax数学公式"><a href="#9-2-MathJax数学公式" class="headerlink" title="9.2.MathJax数学公式"></a>9.2.MathJax数学公式</h3><p>编辑 <strong>主题配置文件</strong>主题的<code>_config.yml</code>), 将 <code>mathjax</code> 下的 <code>enable</code> 设定为 <code>true</code> 即可。 <code>cdn</code> 用于指定 MathJax 的脚本地址,默认是 MathJax 官方提供的 CDN 地址</p>
<figure class="highlight yaml"><table><tr><td class="code"><pre><span class="line"><span class="comment"># MathJax Support</span></span><br><span class="line"><span class="attr">mathjax:</span></span><br><span class="line"> <span class="attr">enable:</span> <span class="literal">true</span></span><br><span class="line"> <span class="attr">cdn:</span> <span class="string">//cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML</span></span><br></pre></td></tr></table></figure>
<h3 id="9-3-字数统计与阅读时间"><a href="#9-3-字数统计与阅读时间" class="headerlink" title="9.3.字数统计与阅读时间"></a>9.3.字数统计与阅读时间</h3><p>安装统计插件:</p>
<figure class="highlight shell"><table><tr><td class="code"><pre><span class="line"><span class="meta"># </span><span class="language-bash">npm install hexo-wordcount --save</span></span><br></pre></td></tr></table></figure>
<p>在主题配置<code>_config.yml</code>里修改:</p>
<figure class="highlight yaml"><table><tr><td class="code"><pre><span class="line"><span class="comment"># Post wordcount display settings</span></span><br><span class="line"><span class="comment"># Dependencies: https://github.com/willin/hexo-wordcount</span></span><br><span class="line"><span class="attr">post_wordcount:</span></span><br><span class="line"> <span class="attr">item_text:</span> <span class="literal">true</span></span><br><span class="line"> <span class="attr">wordcount:</span> <span class="literal">true</span></span><br><span class="line"> <span class="attr">min2read:</span> <span class="literal">true</span></span><br><span class="line"> <span class="attr">totalcount:</span> <span class="literal">true</span></span><br><span class="line"> <span class="attr">separated_meta:</span> <span class="literal">true</span></span><br></pre></td></tr></table></figure>
<h2 id="10-修改主题样式(可选)"><a href="#10-修改主题样式(可选)" class="headerlink" title="10.修改主题样式(可选)"></a>10.修改主题样式(可选)</h2><p>修改<code>theme</code>下对于主题下的<code> _config.yml</code>文件中的一些信息以定制样式</p>
<h2 id="11-参考资料"><a href="#11-参考资料" class="headerlink" title="11.参考资料"></a>11.参考资料</h2><p><a href="https://pages.github.com/">GitHub Pages | Websites for you and your projects, hosted directly from your GitHub repository. Just edit, push, and your changes are live.</a></p>
<p><a href="https://hexo.io/docs/">Documentation | Hexo</a></p>
<p><a href="http://theme-next.iissnan.com/">NexT 使用文档 (iissnan.com)</a></p>
<p><a href="https://zhuanlan.zhihu.com/p/60578464">使用 Hexo+GitHub 搭建个人免费博客教程(小白向) - 知乎 (zhihu.com)</a></p>
<p><a href="https://zhuanlan.zhihu.com/p/424930588">Next主题设置 - 知乎 (zhihu.com)</a></p>
]]></content>
<categories>
<category>web前端</category>
</categories>
<tags>
<tag>Hexo</tag>
<tag>NEXT</tag>
<tag>GitHub</tag>
</tags>
</entry>
<entry>
<title>基于Linux编译JDK18</title>
<url>/2022/03/11/%E5%9F%BA%E4%BA%8ELinux%E7%BC%96%E8%AF%91JDK18/</url>
<content><![CDATA[<h2 id="1-概述"><a href="#1-概述" class="headerlink" title="1.概述"></a>1.概述</h2><p>JDK都没手动编译过,敢说自己是Java程序员吗?(By 羊哥——<a href="https://www.bilibili.com/video/BV1zT4y177Zf?spm_id_from=333.999.0.0">JDK都没手动编译过,敢说自己是Java程序员吗?实战编译Java源码(JDK源码,JVM)视频教程_哔哩哔哩_bilibili</a>)</p>
<ul>
<li>自己动手编译JDK理论上可以得到更适合自己电脑的JDK</li>
<li>可以自己在源码中加入自己的DIY部分,或许会好玩?</li>
<li>阅读JDK源码的时候可以修改测试一些功能,在源码中加入自己的笔记</li>
</ul>
<p>本文基于Ubuntu虚拟机,使用JDK17编译JDK18(应该是目前官方最新的release版本)</p>
<h2 id="2-安装Ubuntu虚拟机"><a href="#2-安装Ubuntu虚拟机" class="headerlink" title="2.安装Ubuntu虚拟机"></a>2.安装Ubuntu虚拟机</h2><p>安装好虚拟机软件,笔者使用的是VMware</p>
<p>在Ubuntu官网下载好UbuntuISO镜像,笔者下载的是Ubuntu20.04 desktop</p>
<p>下载地址为:</p>
<p><a href="https://cn.ubuntu.com/download/desktop">下载Ubuntu桌面系统 | Ubuntu</a></p>
<p>下载好后启动VMware,设置虚拟机的一些配置信息,建议配置给大一点,毕竟是编译程序,CPU核心多一点会比较快</p>
<p>配置好后挂载ISO镜像,启动虚拟机,配置Ubuntu的一些信息(主要是密码),等待安装完成</p>
<p><img src="https://s2.loli.net/2022/03/10/rnmFYi1UAbQa7H8.png" alt="image-20220310144014491"></p>
<h2 id="3-配置Ubuntu"><a href="#3-配置Ubuntu" class="headerlink" title="3.配置Ubuntu"></a>3.配置Ubuntu</h2><h3 id="3-1-配置SSH(可选)"><a href="#3-1-配置SSH(可选)" class="headerlink" title="3.1. 配置SSH(可选)"></a>3.1. 配置SSH(可选)</h3><p>配置SSH工具后就可以在虚拟机外进行SSH连接并操作,当然,可以直接在虚拟机内操作</p>
<figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">sudo apt install openssh-server</span><br></pre></td></tr></table></figure>
<p>参考链接:<a href="https://www.cnblogs.com/livelab/p/13033175.html">如何在Ubuntu 20.04上启用SSH - GlaryJoker - 博客园 (cnblogs.com)</a></p>
<h3 id="3-2-下载vim(可选)"><a href="#3-2-下载vim(可选)" class="headerlink" title="3.2. 下载vim(可选)"></a>3.2. 下载vim(可选)</h3><p>vim是Linux上普遍使用的终端文本编辑工具,当然,可以选择其他文本工具</p>
<figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">sudo apt install vim</span><br></pre></td></tr></table></figure>
<h3 id="3-3-配置安装源"><a href="#3-3-配置安装源" class="headerlink" title="3.3. 配置安装源"></a>3.3. 配置安装源</h3><p>Ubuntu自带的安装源比较慢,此处笔者配置的是阿里云的源</p>
<p>参考链接:</p>
<p><a href="https://developer.aliyun.com/mirror/ubuntu">ubuntu镜像-ubuntu下载地址-ubuntu安装教程-阿里巴巴开源镜像站 (aliyun.com)</a></p>
<p>备份原文件(可选):</p>
<figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">sudo cp /etc/apt/sources.list /etc/apt/sources.list.bak</span><br></pre></td></tr></table></figure>
<p>删除原文件:</p>
<figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">sudo rm -rf /etc/apt/sources.list</span><br></pre></td></tr></table></figure>
<p>编辑镜像文件:</p>
<figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">sudo vim /etc/apt/sources.list</span><br></pre></td></tr></table></figure>
<p>粘贴入镜像站给出的地址:</p>
<figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">deb http://mirrors.aliyun.com/ubuntu/ focal main restricted universe multiverse</span><br><span class="line">deb-src http://mirrors.aliyun.com/ubuntu/ focal main restricted universe multiverse</span><br><span class="line"></span><br><span class="line">deb http://mirrors.aliyun.com/ubuntu/ focal-security main restricted universe multiverse</span><br><span class="line">deb-src http://mirrors.aliyun.com/ubuntu/ focal-security main restricted universe multiverse</span><br><span class="line"></span><br><span class="line">deb http://mirrors.aliyun.com/ubuntu/ focal-updates main restricted universe multiverse</span><br><span class="line">deb-src http://mirrors.aliyun.com/ubuntu/ focal-updates main restricted universe multiverse</span><br><span class="line"></span><br><span class="line">deb http://mirrors.aliyun.com/ubuntu/ focal-proposed main restricted universe multiverse</span><br><span class="line">deb-src http://mirrors.aliyun.com/ubuntu/ focal-proposed main restricted universe multiverse</span><br><span class="line"></span><br><span class="line">deb http://mirrors.aliyun.com/ubuntu/ focal-backports main restricted universe multiverse</span><br><span class="line">deb-src http://mirrors.aliyun.com/ubuntu/ focal-backports main restricted universe multiverse</span><br><span class="line"></span><br></pre></td></tr></table></figure>
<h2 id="4-安装编译工具"><a href="#4-安装编译工具" class="headerlink" title="4.安装编译工具"></a>4.安装编译工具</h2><p>根据openjdk官方给出的编译指导(<a href="https://openjdk.java.net/groups/build/doc/building.html">Building the JDK (java.net)</a>),分别需要安装以下工具:</p>
<h3 id="4-1-工具链-Toolchain"><a href="#4-1-工具链-Toolchain" class="headerlink" title="4.1. 工具链(Toolchain)"></a>4.1. 工具链(Toolchain)</h3><figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">sudo apt-get install build-essential</span><br></pre></td></tr></table></figure>
<h3 id="4-2-基础JDK(Boot-JDK)"><a href="#4-2-基础JDK(Boot-JDK)" class="headerlink" title="4.2. 基础JDK(Boot JDK)"></a>4.2. 基础JDK(Boot JDK)</h3><p>需要邻近版本的JDK,一般选用前一个版本</p>
<figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">sudo apt-get install openjdk-17-jdk </span><br></pre></td></tr></table></figure>
<h3 id="4-3-链接库(External-Library)"><a href="#4-3-链接库(External-Library)" class="headerlink" title="4.3. 链接库(External Library)"></a>4.3. 链接库(External Library)</h3><h4 id="4-3-1-FreeType"><a href="#4-3-1-FreeType" class="headerlink" title="4.3.1. FreeType"></a>4.3.1. FreeType</h4><figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">sudo apt-get install libfreetype6-dev</span><br></pre></td></tr></table></figure>
<h4 id="4-3-2-CUPS"><a href="#4-3-2-CUPS" class="headerlink" title="4.3.2. CUPS"></a>4.3.2. CUPS</h4><figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">sudo apt-get install libcups2-dev</span><br></pre></td></tr></table></figure>
<h4 id="4-3-3-X11"><a href="#4-3-3-X11" class="headerlink" title="4.3.3. X11"></a>4.3.3. X11</h4><figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">sudo apt-get install libx11-dev libxext-dev libxrender-dev libxrandr-dev libxtst-dev libxt-dev</span><br></pre></td></tr></table></figure>
<h4 id="4-3-4-ALSA"><a href="#4-3-4-ALSA" class="headerlink" title="4.3.4. ALSA"></a>4.3.4. ALSA</h4><figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">sudo apt-get install libasound2-dev</span><br></pre></td></tr></table></figure>
<h4 id="4-3-5-libffi"><a href="#4-3-5-libffi" class="headerlink" title="4.3.5. libffi"></a>4.3.5. libffi</h4><figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">sudo apt-get install libffi-dev</span><br></pre></td></tr></table></figure>
<h3 id="4-4-构建工具(Build-Tools)"><a href="#4-4-构建工具(Build-Tools)" class="headerlink" title="4.4. 构建工具(Build Tools)"></a>4.4. 构建工具(Build Tools)</h3><h4 id="4-4-1-Autoconf"><a href="#4-4-1-Autoconf" class="headerlink" title="4.4.1. Autoconf"></a>4.4.1. Autoconf</h4><p>需要最低版本2.69</p>
<figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">sudo apt-get install autoconf</span><br></pre></td></tr></table></figure>
<h4 id="4-4-2-GNU-Make"><a href="#4-4-2-GNU-Make" class="headerlink" title="4.4.2. GNU Make"></a>4.4.2. GNU Make</h4><p>需要最低版本3.81</p>
<h4 id="4-4-3-GNU-Bash"><a href="#4-4-3-GNU-Bash" class="headerlink" title="4.4.3. GNU Bash"></a>4.4.3. GNU Bash</h4><p>需要最低版本3.2</p>
<h2 id="5-配置Configure"><a href="#5-配置Configure" class="headerlink" title="5. 配置Configure"></a>5. 配置Configure</h2><p>具体配置项请看:</p>
<p><a href="https://openjdk.java.net/groups/build/doc/building.html">Building the JDK (java.net)</a></p>
<p>此处默认配置</p>
<h2 id="6-配置Make"><a href="#6-配置Make" class="headerlink" title="6. 配置Make"></a>6. 配置Make</h2><p>具体配置项请看:</p>
<p><a href="https://openjdk.java.net/groups/build/doc/building.html">Building the JDK (java.net)</a></p>
<p>此处默认配置</p>
<h2 id="7-编译JDK"><a href="#7-编译JDK" class="headerlink" title="7. 编译JDK"></a>7. 编译JDK</h2><p>生成配置</p>
<figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">bash configure</span><br></pre></td></tr></table></figure>
<ul>
<li>如果依赖库没装完或者存在问题,请根据输出的提示安装或者修改</li>
</ul>
<p>编译全部</p>
<figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">make all</span><br></pre></td></tr></table></figure>
<h2 id="8-编译输出"><a href="#8-编译输出" class="headerlink" title="8. 编译输出"></a>8. 编译输出</h2><p>编译完成后编译后的文件在<code>build</code>文件夹下</p>
<p>查看文件:</p>
<figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">zhanny@ubuntu:~/Downloads/jdk18$ ls build/linux-x86_64-server-release/</span><br><span class="line">bootcycle-spec.gmk build.log.old configure.log images make-support</span><br><span class="line">buildjdk-spec.gmk buildtools configure-support jdk spec.gmk</span><br><span class="line">build.log compare.sh hotspot Makefile support</span><br><span class="line"></span><br></pre></td></tr></table></figure>
<p>其中<code>images</code>就是release文件夹</p>
<figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">zhanny@ubuntu:~/Downloads/jdk18$ ls build/linux-x86_64-server-release/images/</span><br><span class="line">docs docs-javase docs-reference gengraphs jdk jmods sec-bin.zip symbols test</span><br><span class="line"></span><br></pre></td></tr></table></figure>
<p><code>images</code>下的<code>jdk</code>的<code>bin</code>下就是常见的Java编译器</p>
<figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">zhanny@ubuntu:~/Downloads/jdk18$ ls build/linux-x86_64-server-release/images/jdk/bin/</span><br><span class="line">jar jconsole.debuginfo jlink jstack.debuginfo</span><br><span class="line">jar.debuginfo jdb jlink.debuginfo jstat</span><br><span class="line">jarsigner jdb.debuginfo jmap jstatd</span><br><span class="line">jarsigner.debuginfo jdeprscan jmap.debuginfo jstatd.debuginfo</span><br><span class="line">java jdeprscan.debuginfo jmod jstat.debuginfo</span><br><span class="line">javac jdeps jmod.debuginfo jwebserver</span><br><span class="line">javac.debuginfo jdeps.debuginfo jpackage jwebserver.debuginfo</span><br><span class="line">java.debuginfo jfr jpackage.debuginfo keytool</span><br><span class="line">javadoc jfr.debuginfo jps keytool.debuginfo</span><br><span class="line">javadoc.debuginfo jhsdb jps.debuginfo rmiregistry</span><br><span class="line">javap jhsdb.debuginfo jrunscript rmiregistry.debuginfo</span><br><span class="line">javap.debuginfo jimage jrunscript.debuginfo serialver</span><br><span class="line">jcmd jimage.debuginfo jshell serialver.debuginfo</span><br><span class="line">jcmd.debuginfo jinfo jshell.debuginfo</span><br><span class="line">jconsole jinfo.debuginfo jstack</span><br><span class="line"></span><br></pre></td></tr></table></figure>
<h2 id="9-参考资料"><a href="#9-参考资料" class="headerlink" title="9. 参考资料"></a>9. 参考资料</h2><p>[1]<a href="https://openjdk.java.net/groups/build/doc/building.html">Building the JDK (java.net)</a></p>
<p>[2]<a href="https://github.com/openjdk/jdk18">openjdk/jdk18: JDK 18 development (github.com)</a></p>
<p>[3]<a href="https://www.jianshu.com/p/d03ef2e89801">真·手把手,从头教你编译JDK - 简书 (jianshu.com)</a></p>
<p>[4]<a href="https://www.jianshu.com/p/108c984f8872">实战:自己编译JDK - 简书 (jianshu.com)</a></p>
]]></content>
<categories>
<category>编译器</category>
</categories>
<tags>
<tag>Java</tag>
<tag>Linux</tag>
</tags>
</entry>
<entry>
<title>灰度变换之伽马变换</title>
<url>/2022/03/12/%E7%81%B0%E5%BA%A6%E5%8F%98%E6%8D%A2%E4%B9%8B%E4%BC%BD%E9%A9%AC%E5%8F%98%E6%8D%A2/</url>
<content><![CDATA[<h2 id="1-概述"><a href="#1-概述" class="headerlink" title="1.概述"></a>1.概述</h2><p>伽玛变换又名指数变换、幂次变换或幂律变换,是另一种常用的非线性变换</p>
<p>伽马变换主要用于图像的校正,将灰度过高或者灰度过低的图片进行修正,增强对比度。变换公式就是对原图像上每一个像素值做乘积运算:</p>
<p>$$ s = c \cdot r^ \gamma \quad r \in [0,1]$$</p>
<p>其中 c 和 γ 为正常数,有时考虑到偏移量,也将表达式写为:</p>
<p>$$ s = c \cdot (r+ \epsilon)^ \gamma \quad r \in [0,1]$$</p>
<p>与对数变换不同,伽玛变换可以根据 $\gamma$ 的不同取值选择性地增强低灰度区域的对比度或是高灰度区域的对比度。$\gamma$是图像灰度校正中非常重要的一个参数,其取值决定了输入图像和输出图像之间的灰度映射方式,即决定了是增强低灰度( 阴影区域)还是增强高灰度(高亮区域)。其中:</p>
<p><img src="https://s2.loli.net/2022/03/12/RbAlX6OVvacWpxI.png" alt="image.png"></p>
<ul>
<li>$ \gamma $ > 1 时,图像的高灰度区城对比度得到增强</li>
<li>$ \gamma $ < 1 时,图像的低灰度区城对比度得到增强</li>
<li>$ \gamma $ = 1 时,图像是线性变换,对比度保持不变</li>
</ul>
<p>针对于数字图像处理,我们可以将公式写为:</p>
<p>$$ output = (input + \epsilon)^\gamma $$</p>
<p>由于幂运算值域变化范围可能太大,对于当前主要的8 bit显示器,我们采用归一化手段:</p>
<p>$$ output = 255 \times (\frac{input + \epsilon} {255})^\gamma $$</p>
<h2 id="2-补偿系数的作用"><a href="#2-补偿系数的作用" class="headerlink" title="2. 补偿系数的作用"></a>2. 补偿系数的作用</h2><p>导入库:</p>
<figure class="highlight python"><table><tr><td class="code"><pre><span class="line"><span class="keyword">from</span> PIL <span class="keyword">import</span> Image</span><br><span class="line"><span class="keyword">import</span> numpy <span class="keyword">as</span> np</span><br><span class="line"><span class="keyword">import</span> matplotlib.pyplot <span class="keyword">as</span> plt</span><br></pre></td></tr></table></figure>
<p>定义伽马变换函数:</p>
<figure class="highlight python"><table><tr><td class="code"><pre><span class="line"><span class="keyword">def</span> <span class="title function_">gamma_trans</span>(<span class="params"><span class="built_in">input</span>, gamma=<span class="number">2</span>, eps=<span class="number">0</span> </span>):</span><br><span class="line"> <span class="keyword">return</span> <span class="number">255.</span> * (((<span class="built_in">input</span> + eps)/<span class="number">255.</span>) ** gamma)</span><br></pre></td></tr></table></figure>
<p>测试补偿系数为0时的效果:</p>
<figure class="highlight python"><table><tr><td class="code"><pre><span class="line">input_arr = np.array( [ [<span class="number">0</span>, <span class="number">50</span>, <span class="number">100</span>, <span class="number">150</span>],</span><br><span class="line"> [<span class="number">0</span>, <span class="number">50</span>, <span class="number">100</span>, <span class="number">150</span>],</span><br><span class="line"> [<span class="number">0</span>, <span class="number">50</span>, <span class="number">100</span>, <span class="number">150</span>],</span><br><span class="line"> [<span class="number">0</span>, <span class="number">50</span>, <span class="number">100</span>, <span class="number">150</span>]] )</span><br><span class="line"></span><br><span class="line">fig = plt.figure()</span><br><span class="line">ax0 = fig.add_subplot(<span class="number">221</span>)</span><br><span class="line">ax0.set_title(<span class="string">"input"</span>)</span><br><span class="line">ax0.imshow(input_arr, cmap=<span class="string">'gray'</span>,vmin=<span class="number">0</span>,vmax=<span class="number">255</span>)</span><br><span class="line"></span><br><span class="line">gamma = <span class="number">0.25</span></span><br><span class="line">output = gamma_trans(input_arr, gamma=gamma, eps=<span class="number">0</span>)</span><br><span class="line">ax1 = fig.add_subplot(<span class="number">222</span>)</span><br><span class="line">ax1.set_title(<span class="string">"output, gamma = "</span> + <span class="built_in">str</span>(gamma))</span><br><span class="line">ax1.imshow(output, cmap=<span class="string">'gray'</span>, vmin=<span class="number">0</span>, vmax=<span class="number">255</span>)</span><br><span class="line"></span><br><span class="line">gamma = <span class="number">0.75</span></span><br><span class="line">output = gamma_trans(input_arr, gamma=gamma, eps=<span class="number">0</span>)</span><br><span class="line">ax1 = fig.add_subplot(<span class="number">223</span>)</span><br><span class="line">ax1.set_title(<span class="string">"output, gamma = "</span> + <span class="built_in">str</span>(gamma))</span><br><span class="line">ax1.imshow(output, cmap=<span class="string">'gray'</span>, vmin=<span class="number">0</span>, vmax=<span class="number">255</span>)</span><br><span class="line"></span><br><span class="line">gamma = <span class="number">1.5</span></span><br><span class="line">output = gamma_trans(input_arr, gamma=gamma, eps=<span class="number">0</span>)</span><br><span class="line">ax1 = fig.add_subplot(<span class="number">224</span>)</span><br><span class="line">ax1.set_title(<span class="string">"output, gamma = "</span> + <span class="built_in">str</span>(gamma))</span><br><span class="line">ax1.imshow(output, cmap=<span class="string">'gray'</span>, vmin=<span class="number">0</span>, vmax=<span class="number">255</span>)</span><br><span class="line"><span class="built_in">print</span>(output)</span><br><span class="line"></span><br><span class="line">plt.show()</span><br></pre></td></tr></table></figure>
<pre><code>[[ 0. 22.14037214 62.62242911 115.04474833]
[ 0. 22.14037214 62.62242911 115.04474833]
[ 0. 22.14037214 62.62242911 115.04474833]
[ 0. 22.14037214 62.62242911 115.04474833]]
</code></pre>
<p><img src="https://s2.loli.net/2022/03/12/BLwCIrM78gpDVxb.png" alt="png"></p>
<p>由图可以看到,如果补偿系数 $\epsilon = 0$,则灰度等于0的区域将不会产生任何变化,我们添加一个补偿系数$\epsilon = 0.5$: </p>
<figure class="highlight python"><table><tr><td class="code"><pre><span class="line">input_arr = np.array( [ [<span class="number">0</span>, <span class="number">50</span>, <span class="number">100</span>, <span class="number">150</span>],</span><br><span class="line"> [<span class="number">0</span>, <span class="number">50</span>, <span class="number">100</span>, <span class="number">150</span>],</span><br><span class="line"> [<span class="number">0</span>, <span class="number">50</span>, <span class="number">100</span>, <span class="number">150</span>],</span><br><span class="line"> [<span class="number">0</span>, <span class="number">50</span>, <span class="number">100</span>, <span class="number">150</span>]] )</span><br><span class="line"></span><br><span class="line">fig = plt.figure()</span><br><span class="line">ax0 = fig.add_subplot(<span class="number">221</span>)</span><br><span class="line">ax0.set_title(<span class="string">"input"</span>)</span><br><span class="line">ax0.imshow(input_arr, cmap=<span class="string">'gray'</span>,vmin=<span class="number">0</span>,vmax=<span class="number">255</span>)</span><br><span class="line"></span><br><span class="line">gamma = <span class="number">0.25</span></span><br><span class="line">output = gamma_trans(input_arr, gamma=gamma, eps=<span class="number">0.5</span>)</span><br><span class="line">ax1 = fig.add_subplot(<span class="number">222</span>)</span><br><span class="line">ax1.set_title(<span class="string">"output, gamma = "</span> + <span class="built_in">str</span>(gamma))</span><br><span class="line">ax1.imshow(output, cmap=<span class="string">'gray'</span>, vmin=<span class="number">0</span>, vmax=<span class="number">255</span>)</span><br><span class="line"></span><br><span class="line">gamma = <span class="number">0.75</span></span><br><span class="line">output = gamma_trans(input_arr, gamma=gamma, eps=<span class="number">0.5</span>)</span><br><span class="line">ax1 = fig.add_subplot(<span class="number">223</span>)</span><br><span class="line">ax1.set_title(<span class="string">"output, gamma = "</span> + <span class="built_in">str</span>(gamma))</span><br><span class="line">ax1.imshow(output, cmap=<span class="string">'gray'</span>, vmin=<span class="number">0</span>, vmax=<span class="number">255</span>)</span><br><span class="line"></span><br><span class="line">gamma = <span class="number">1.5</span></span><br><span class="line">output = gamma_trans(input_arr, gamma=gamma, eps=<span class="number">0.5</span>)</span><br><span class="line">ax1 = fig.add_subplot(<span class="number">224</span>)</span><br><span class="line">ax1.set_title(<span class="string">"output, gamma = "</span> + <span class="built_in">str</span>(gamma))</span><br><span class="line">ax1.imshow(output, cmap=<span class="string">'gray'</span>, vmin=<span class="number">0</span>, vmax=<span class="number">255</span>)</span><br><span class="line"><span class="built_in">print</span>(output)</span><br><span class="line"></span><br><span class="line">plt.show()</span><br></pre></td></tr></table></figure>
<pre><code>[[2.21403721e-02 2.24733066e+01 6.30926839e+01 1.15620451e+02]
[2.21403721e-02 2.24733066e+01 6.30926839e+01 1.15620451e+02]
[2.21403721e-02 2.24733066e+01 6.30926839e+01 1.15620451e+02]
[2.21403721e-02 2.24733066e+01 6.30926839e+01 1.15620451e+02]]
</code></pre>
<p><img src="https://s2.loli.net/2022/03/12/aJhNy5sRucOGDkr.png" alt="png"></p>
<p>可以看到整体的对比度都有变化,灰度值为0的问题可以避免</p>
<h2 id="3-伽马变换矫正显示失真"><a href="#3-伽马变换矫正显示失真" class="headerlink" title="3. 伽马变换矫正显示失真"></a>3. 伽马变换矫正显示失真</h2><p>老式电视机CRT会有显示失真的问题,不同的电视有不同的失真指数<br>我们假设某老式电视失真指数$\gamma = 0.5$,我们使用伽马变换进行矫正,只需取矫正指数$\gamma ‘ = \frac{1}{\gamma}$</p>
<p>原图像:</p>
<figure class="highlight python"><table><tr><td class="code"><pre><span class="line">gray_img = np.asarray(Image.<span class="built_in">open</span>(<span class="string">'./img/intensity_ramp.tif'</span>).convert(<span class="string">'L'</span>))</span><br><span class="line">fig = plt.figure()</span><br><span class="line">ax0 = fig.add_subplot()</span><br><span class="line">ax0.set_title(<span class="string">"origin"</span>)</span><br><span class="line">ax0.imshow(gray_img, cmap=<span class="string">'gray'</span>,vmin=<span class="number">0</span>,vmax=<span class="number">255</span>)</span><br><span class="line">plt.show()</span><br></pre></td></tr></table></figure>
<p><img src="https://s2.loli.net/2022/03/12/JzZT46yhiEX71Nf.png" alt="png"><br> </p>
<p>失真图像和伽马矫正:</p>
<figure class="highlight python"><table><tr><td class="code"><pre><span class="line">gray_img = np.asarray(Image.<span class="built_in">open</span>(<span class="string">'./img/intensity_ramp.tif'</span>).convert(<span class="string">'L'</span>))</span><br><span class="line"></span><br><span class="line">fig = plt.figure()</span><br><span class="line">ax0 = fig.add_subplot(<span class="number">131</span>)</span><br><span class="line">ax1 = fig.add_subplot(<span class="number">132</span>)</span><br><span class="line">ax2 = fig.add_subplot(<span class="number">133</span>)</span><br><span class="line"></span><br><span class="line">gamma=<span class="number">0.5</span></span><br><span class="line">ax0.set_title(<span class="string">"origin"</span>)</span><br><span class="line">ax0.imshow(gray_img, cmap=<span class="string">'gray'</span>,vmin=<span class="number">0</span>,vmax=<span class="number">255</span>)</span><br><span class="line">ax1.set_title(<span class="string">"distortion"</span>)</span><br><span class="line">distortion = gamma_trans(gray_img, gamma=gamma, eps=<span class="number">0</span>)</span><br><span class="line">ax1.imshow(distortion, cmap=<span class="string">'gray'</span>,vmin=<span class="number">0</span>,vmax=<span class="number">255</span>)</span><br><span class="line">ax2.set_title(<span class="string">"correct"</span>)</span><br><span class="line">correct = gamma_trans(distortion, gamma=<span class="number">1</span>/gamma, eps=<span class="number">0</span>)</span><br><span class="line">ax2.imshow(correct, cmap=<span class="string">'gray'</span>,vmin=<span class="number">0</span>,vmax=<span class="number">255</span>)</span><br><span class="line">plt.show()</span><br></pre></td></tr></table></figure>
<p><img src="https://s2.loli.net/2022/03/12/GNm6e9bXQ5VUlgW.png" alt="png"><br> </p>
<p>此处看起来是脱裤子放屁多此一举,但是实际中失真指数是不知道的,需要去得到矫正指数</p>
<h2 id="4-伽马变换拉伸对比度"><a href="#4-伽马变换拉伸对比度" class="headerlink" title="4. 伽马变换拉伸对比度"></a>4. 伽马变换拉伸对比度</h2><p>对于暗色照片,我们可以进行伽马系数小于一的伽马变换从而提高低灰度值的对比度</p>
<p>原图像:</p>
<figure class="highlight python"><table><tr><td class="code"><pre><span class="line">gray_img = np.asarray(Image.<span class="built_in">open</span>(<span class="string">'./img/fractured_spine.tif'</span>).convert(<span class="string">'L'</span>))</span><br><span class="line">fig = plt.figure()</span><br><span class="line">ax0 = fig.add_subplot()</span><br><span class="line">ax0.set_title(<span class="string">"origin"</span>)</span><br><span class="line">ax0.imshow(gray_img, cmap=<span class="string">'gray'</span>,vmin=<span class="number">0</span>,vmax=<span class="number">255</span>)</span><br><span class="line">plt.show()</span><br></pre></td></tr></table></figure>
<p><img src="https://s2.loli.net/2022/03/12/tbj1x3XEk2WqQPe.png" alt="png"></p>
<p>伽马变换:</p>
<figure class="highlight python"><table><tr><td class="code"><pre><span class="line">gray_img = np.asarray(Image.<span class="built_in">open</span>(<span class="string">'./img/fractured_spine.tif'</span>).convert(<span class="string">'L'</span>))</span><br><span class="line"></span><br><span class="line">fig = plt.figure()</span><br><span class="line">ax0 = fig.add_subplot(<span class="number">121</span>)</span><br><span class="line">ax1 = fig.add_subplot(<span class="number">122</span>)</span><br><span class="line"></span><br><span class="line">gamma=<span class="number">0.4</span></span><br><span class="line">ax0.set_title(<span class="string">"origin"</span>)</span><br><span class="line">ax0.imshow(gray_img, cmap=<span class="string">'gray'</span>,vmin=<span class="number">0</span>,vmax=<span class="number">255</span>)</span><br><span class="line">ax1.set_title(<span class="string">"correct"</span>)</span><br><span class="line">correct = gamma_trans(gray_img, gamma=gamma, eps=<span class="number">0</span>)</span><br><span class="line">ax1.imshow(correct, cmap=<span class="string">'gray'</span>,vmin=<span class="number">0</span>,vmax=<span class="number">255</span>)</span><br><span class="line">plt.show()</span><br></pre></td></tr></table></figure>
<p><img src="https://s2.loli.net/2022/03/12/FgaJVsn6j53qPui.png" alt="png"><br> </p>
<ul>
<li>注意此处的伽马系数0.4是一种探索得出的数字,不一定是最佳值,下面的2.0同理</li>
</ul>
<p>对于亮色照片,我们可以进行伽马系数大于一的伽马变换从而提高低灰度值的对比度</p>
<p>原图像:</p>
<figure class="highlight python"><table><tr><td class="code"><pre><span class="line">gray_img = np.asarray(Image.<span class="built_in">open</span>(<span class="string">'./img/washed_out.tif'</span>).convert(<span class="string">'L'</span>))</span><br><span class="line">fig = plt.figure()</span><br><span class="line">ax0 = fig.add_subplot()</span><br><span class="line">ax0.set_title(<span class="string">"origin"</span>)</span><br><span class="line">ax0.imshow(gray_img, cmap=<span class="string">'gray'</span>,vmin=<span class="number">0</span>,vmax=<span class="number">255</span>)</span><br><span class="line">plt.show()</span><br></pre></td></tr></table></figure>
<p><img src="https://s2.loli.net/2022/03/12/tLJwvGMSnPu4VIl.png" alt="png"><br> </p>
<p>伽马变换:</p>
<figure class="highlight python"><table><tr><td class="code"><pre><span class="line">gray_img = np.asarray(Image.<span class="built_in">open</span>(<span class="string">'./img/washed_out.tif'</span>).convert(<span class="string">'L'</span>))</span><br><span class="line"></span><br><span class="line">fig = plt.figure()</span><br><span class="line">ax0 = fig.add_subplot(<span class="number">121</span>)</span><br><span class="line">ax1 = fig.add_subplot(<span class="number">122</span>)</span><br><span class="line"></span><br><span class="line">gamma = <span class="number">2.0</span></span><br><span class="line">ax0.set_title(<span class="string">"origin"</span>)</span><br><span class="line">ax0.imshow(gray_img, cmap=<span class="string">'gray'</span>,vmin=<span class="number">0</span>,vmax=<span class="number">255</span>)</span><br><span class="line">ax1.set_title(<span class="string">"correct"</span>)</span><br><span class="line">correct = gamma_trans(gray_img, gamma=gamma, eps=<span class="number">0</span>)</span><br><span class="line">ax1.imshow(correct, cmap=<span class="string">'gray'</span>,vmin=<span class="number">0</span>,vmax=<span class="number">255</span>)</span><br><span class="line">plt.show()</span><br></pre></td></tr></table></figure>
<p><img src="https://s2.loli.net/2022/03/12/tLjd36ui2TpUNRo.png" alt="png"><br> </p>
<p>可以看到伽马变换带来的图像增强效果还是显著的</p>
<h2 id="5-参考资料"><a href="#5-参考资料" class="headerlink" title="5. 参考资料"></a>5. 参考资料</h2><p>[1]<a href="https://www.cnblogs.com/xianyufpga/p/12514861.html">FPGA实现图像的非线性变换:伽玛(幂律)变换</a></p>
<p>[2]<a href="https://www.jianshu.com/p/46503ef647fc">opencv+python学习记录(九)伽马变换</a></p>
<p>[3]<a href="https://www.bilibili.com/video/BV1iS4y1o7Ek/?spm_id_from=333.788">【手写图像处理库2】耳熟能详的对比度调节,伽马变换当仁不让,Photoshop默默点了个赞!冈萨雷斯《数字图像处理》,灰度变</a></p>
]]></content>
<categories>
<category>数字图像处理</category>
</categories>
<tags>
<tag>数字图像处理</tag>
<tag>Python</tag>
</tags>
</entry>
<entry>
<title>Java对象布局</title>
<url>/2022/03/13/Java%E5%AF%B9%E8%B1%A1%E5%B8%83%E5%B1%80/</url>
<content><![CDATA[<h2 id="1-引言"><a href="#1-引言" class="headerlink" title="1. 引言"></a>1. 引言</h2><p>由于Java面向对象的思想,在JVM中需要大量存储对象,存储时为了实现一些额外的功能,需要在对象中添加一些标记字段用于增强对象功能 。在学习并发编程知识<code>synchronized</code>时,我们总是难以理解其实现原理,因为偏向锁、轻量级锁、重量级锁都涉及到对象头,所以了解<code>java</code>对象头是我们深入了解<code>synchronized</code>的前提条件</p>
<ul>
<li>注意:本文所有代码基于JDK 1.8</li>
</ul>
<h2 id="2-对象布局概述"><a href="#2-对象布局概述" class="headerlink" title="2. 对象布局概述"></a>2. 对象布局概述</h2><p>HotSpot虚拟机中,对象在内存中存储的布局可以分为三块区域:对象头(Header)、实例数据(Instance Data)和对齐填充(Padding)</p>
<p>从Java虚拟机Hotpot的源代码(<a href="https://github.com/openjdk">openjdk</a>)中,根据对象实例文件(<a href="https://github.com/openjdk/jdk8/blob/master/hotspot/src/share/vm/oops/instanceOop.hpp">jdk8/instanceOop.hpp at master · openjdk/jdk8 (github.com)</a>)中的代码:</p>
<figure class="highlight c++"><table><tr><td class="code"><pre><span class="line"></span><br><span class="line"><span class="meta">#<span class="keyword">ifndef</span> SHARE_VM_OOPS_INSTANCEOOP_HPP</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> SHARE_VM_OOPS_INSTANCEOOP_HPP</span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">"oops/oop.hpp"</span></span></span><br><span class="line"></span><br><span class="line"><span class="comment">// An instanceOop is an instance of a Java Class</span></span><br><span class="line"><span class="comment">// Evaluating "new HashTable()" will create an instanceOop.</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">instanceOopDesc</span> : <span class="keyword">public</span> oopDesc {</span><br><span class="line"> <span class="keyword">public</span>:</span><br><span class="line"> <span class="comment">// aligned header size.</span></span><br><span class="line"> <span class="function"><span class="type">static</span> <span class="type">int</span> <span class="title">header_size</span><span class="params">()</span> </span>{ <span class="keyword">return</span> <span class="built_in">sizeof</span>(instanceOopDesc)/HeapWordSize; }</span><br><span class="line"></span><br><span class="line"> <span class="comment">// If compressed, the offset of the fields of the instance may not be aligned.</span></span><br><span class="line"> <span class="function"><span class="type">static</span> <span class="type">int</span> <span class="title">base_offset_in_bytes</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="comment">// offset computation code breaks if UseCompressedClassPointers</span></span><br><span class="line"> <span class="comment">// only is true</span></span><br><span class="line"> <span class="keyword">return</span> (UseCompressedOops && UseCompressedClassPointers) ?</span><br><span class="line"> <span class="built_in">klass_gap_offset_in_bytes</span>() :</span><br><span class="line"> <span class="built_in">sizeof</span>(instanceOopDesc);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="type">static</span> <span class="type">bool</span> <span class="title">contains_field_offset</span><span class="params">(<span class="type">int</span> offset, <span class="type">int</span> nonstatic_field_size)</span> </span>{</span><br><span class="line"> <span class="type">int</span> base_in_bytes = <span class="built_in">base_offset_in_bytes</span>();</span><br><span class="line"> <span class="keyword">return</span> (offset >= base_in_bytes &&</span><br><span class="line"> (offset-base_in_bytes) < nonstatic_field_size * heapOopSize);</span><br><span class="line"> }</span><br><span class="line">};</span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="keyword">endif</span> <span class="comment">// SHARE_VM_OOPS_INSTANCEOOP_HPP</span></span></span><br></pre></td></tr></table></figure>
<p>可以可到一个Java对象在内存中包含<code>header</code>、<code>field</code>、<code>offset</code>。Java对象的布局图示如下:</p>
<p>32位虚拟机:</p>
<p><img src="https://s2.loli.net/2022/03/13/YF3n57BrkDHTu1o.png" alt="img"></p>
<p>64位虚拟机:</p>
<p><img src="https://s2.loli.net/2022/03/13/XehLJiVDr5u6QES.png" alt="img"></p>
<p>图像来源:<a href="https://www.cnblogs.com/duanxz/p/4967042.html">java对象在内存中的结构(HotSpot虚拟机) - duanxz - 博客园 (cnblogs.com)</a></p>
<p>如果对象是数组类型,占用4个字节/8个字节,因为JVM虚拟机可以通过Java对象的元数据信息确定Java对象的大小,但是无法从数组的元数据来确认数组的大小,所以用一块来记录数组长度:</p>
<p><img src="https://s2.loli.net/2022/03/13/oDPSHi1yYO9mpRM.png" alt="img"></p>
<p>图像来源:<a href="https://www.cnblogs.com/jajian/p/13681781.html">Java对象的内存布局 - JaJian - 博客园 (cnblogs.com)</a></p>
<p>从上面的这张图里面可以看出,对象在内存中的结构主要包含以下几个部分:</p>
<ul>
<li>Header (对象头)<ul>
<li>Mark Word(标记字段):用于存储对象自身的运行时数据,如哈希码(HashCode)、GC分代年龄、锁状态标志、线程持有的锁、偏向线程ID、偏向时间戳等等</li>
<li>Klass Pointer(Class对象指针):即类型指针,是对象指向它的类元数据的指针,虚拟机通过这个指针来确定这个对象是哪个类的实例</li>
<li>数组长度:如果对象是数组类型,记录数组长度</li>
</ul>
</li>
<li>Instance Data(对象实际数据):如果对象有属性字段,则这里会有数据信息。如果对象无属性字段,则这里就不会有数据。根据字段类型的不同占不同的字节,例如boolean类型占1个字节,int类型占4个字节等等</li>
<li>Padding (对齐):如果上面的数据所占用的空间不能被8整除,padding则占用空间凑齐使之能被8整除。被8整除在读取数据的时候会比较快</li>
</ul>
<p><strong>为什么要对齐数据</strong>?</p>
<p>字段内存对齐的其中一个原因,是让字段只出现在同一CPU的缓存行中。如果字段不是对齐的,那么就有可能出现跨缓存行的字段。也就是说,该字段的读取可能需要替换两个缓存行,而该字段的存储也会同时污染两个缓存行。这两种情况对程序的执行效率而言都是不利的。其实对其填充的最终目的是为了计算机高效寻址。</p>
<h2 id="3-Mark-Word"><a href="#3-Mark-Word" class="headerlink" title="3. Mark Word"></a>3. Mark Word</h2><p>HotSpot虚拟机的<strong>对象头</strong>包括两部分信息,第一部分是<strong>“Mark Word</strong>”,用于存储对象自身的运行时数据, 如哈希码(HashCode)、GC分代年龄、锁状态标志、线程持有的锁、偏向线程ID、偏向时间戳等等,这部分数据的长度在32位和64位的虚拟机(暂 不考虑开启压缩指针的场景)中分别为32个和64个Bits,官方称它为“Mark Word”。对象需要存储的运行时数据很多,其实已经超出了32、64位Bitmap结构所能记录的限度,但是对象头信息是与对象自身定义的数据无关的额 外存储成本,考虑到虚拟机的空间效率,Mark Word被设计成一个非固定的数据结构以便在极小的空间内存储尽量多的信息,它会根据对象的状态复用自己的存储空间。</p>
<p>我们打开openjdk的源码包(<a href="https://github.com/openjdk/jdk8">openjdk/jdk8: Read-only mirror of https://hg.openjdk.java.net/jdk8 (github.com)</a>),对应路径<code>hotspot/src/share/vm/oops</code>,Mark Word对应到C++的代码<code>markOop.hpp</code>,可以从注释中看到它们的组成:</p>
<figure class="highlight c++"><table><tr><td class="code"><pre><span class="line"><span class="comment">// Bit-format of an object header (most significant first, big endian layout below):</span></span><br><span class="line"><span class="comment">//</span></span><br><span class="line"><span class="comment">// 32 bits:</span></span><br><span class="line"><span class="comment">// --------</span></span><br><span class="line"><span class="comment">// hash:25 ------------>| age:4 biased_lock:1 lock:2 (normal object)</span></span><br><span class="line"><span class="comment">// JavaThread*:23 epoch:2 age:4 biased_lock:1 lock:2 (biased object)</span></span><br><span class="line"><span class="comment">// size:32 ------------------------------------------>| (CMS free block)</span></span><br><span class="line"><span class="comment">// PromotedObject*:29 ---------->| promo_bits:3 ----->| (CMS promoted object)</span></span><br><span class="line"><span class="comment">//</span></span><br><span class="line"><span class="comment">// 64 bits:</span></span><br><span class="line"><span class="comment">// --------</span></span><br><span class="line"><span class="comment">// unused:25 hash:31 -->| unused:1 age:4 biased_lock:1 lock:2 (normal object)</span></span><br><span class="line"><span class="comment">// JavaThread*:54 epoch:2 unused:1 age:4 biased_lock:1 lock:2 (biased object)</span></span><br><span class="line"><span class="comment">// PromotedObject*:61 --------------------->| promo_bits:3 ----->| (CMS promoted object)</span></span><br><span class="line"><span class="comment">// size:64 ----------------------------------------------------->| (CMS free block)</span></span><br><span class="line"><span class="comment">//</span></span><br><span class="line"><span class="comment">// unused:25 hash:31 -->| cms_free:1 age:4 biased_lock:1 lock:2 (COOPs && normal object)</span></span><br><span class="line"><span class="comment">// JavaThread*:54 epoch:2 cms_free:1 age:4 biased_lock:1 lock:2 (COOPs && biased object)</span></span><br><span class="line"><span class="comment">// narrowOop:32 unused:24 cms_free:1 unused:4 promo_bits:3 ----->| (COOPs && CMS promoted object)</span></span><br><span class="line"><span class="comment">// unused:21 size:35 -->| cms_free:1 unused:7 ------------------>| (COOPs && CMS free block)</span></span><br></pre></td></tr></table></figure>
<p>Mark Word在不同的锁状态下存储的内容不同,在32位JVM中是这么存的:</p>
<p><img src="https://s2.loli.net/2022/03/13/HMTXjLN92Wsfyqo.png" alt="img"></p>
<p>在64位JVM中是这么存的:</p>
<p><img src="https://s2.loli.net/2022/03/13/jlP8XcYv7wAK9Dm.png" alt="img"></p>
<p>图像来源:<a href="https://www.cnblogs.com/jajian/p/13681781.html">Java对象的内存布局 - JaJian - 博客园 (cnblogs.com)</a></p>
<ul>
<li>注意:如果对象是数组类型,则需要三个机器码,因为JVM虚拟机可以通过Java对象的元数据信息确定Java对象的大小,但是无法从数组的元数据来确认数组的大小,所以用一块来记录数组长度</li>
</ul>
<p>虽然它们在不同位数的JVM中长度不一样,但是基本组成内容是一致的:</p>
<ul>
<li><strong>锁标志位(lock)</strong>:区分锁状态,11时表示对象待GC回收状态, 只有最后2位锁标识(11)有效。</li>
<li><strong>biased_lock</strong>:是否偏向锁,由于无锁和偏向锁的锁标识都是 01,没办法区分,这里引入一位的偏向锁标识位。</li>
<li><strong>分代年龄(age)</strong>:表示对象被GC的次数,当该次数到达阈值的时候,对象就会转移到老年代。</li>
<li><strong>对象的hashcode(hash)</strong>:运行期间调用System.identityHashCode()来计算,延迟计算,并把结果赋值到这里。当对象加锁后,计算的结果31位不够表示,在偏向锁,轻量锁,重量锁,hashcode会被转移到Monitor中。</li>
<li><strong>偏向锁的线程ID(JavaThread)</strong>:偏向模式的时候,当某个线程持有对象的时候,对象这里就会被置为该线程的ID。 在后面的操作中,就无需再进行尝试获取锁的动作。</li>
<li><strong>epoch</strong>:偏向锁在CAS锁操作过程中,偏向性标识,表示对象更偏向哪个锁。</li>
<li><strong>ptr_to_lock_record</strong>:轻量级锁状态下,指向栈中锁记录的指针。当锁获取是无竞争的时,JVM使用原子操作而不是OS互斥。这种技术称为轻量级锁定。在轻量级锁定的情况下,JVM通过CAS操作在对象的标题字中设置指向锁记录的指针。</li>
<li><strong>ptr_to_heavyweight_monitor</strong>:重量级锁状态下,指向对象监视器Monitor的指针。如果两个不同的线程同时在同一个对象上竞争,则必须将轻量级锁定升级到Monitor以管理等待的线程。在重量级锁定的情况下,JVM在对象的ptr_to_heavyweight_monitor设置指向Monitor的指针。</li>
</ul>
<p>我们通常说的通过synchronized实现的同步锁,真实名称叫做重量级锁。但是重量级锁会造成线程排队(串行执行),且会使CPU在用户态和核心态之间频繁切换,所以代价高、效率低。为了提高效率,不会一开始就使用重量级锁,JVM在内部会根据需要,按如下步骤进行锁的升级:</p>
<ol>
<li>初期锁对象刚创建时,还没有任何线程来竞争,对象的Mark Word是下图的第一种情形,这偏向锁标识位是0,锁状态01,说明该对象处于无锁状态(无线程竞争它)。</li>
<li>当有一个线程来竞争锁时,先用偏向锁,表示锁对象偏爱这个线程,这个线程要执行这个锁关联的任何代码,不需要再做任何检查和切换,这种竞争不激烈的情况下,效率非常高。这时Mark Word会记录自己偏爱的线程的ID,把该线程当做自己的熟人。如下图第二种情形。</li>
<li>当有两个线程开始竞争这个锁对象,情况发生变化了,不再是偏向(独占)锁了,锁会升级为轻量级锁,两个线程公平竞争,哪个线程先占有锁对象并执行代码,锁对象的Mark Word就执行哪个线程的栈帧中的锁记录。如下图第三种情形。</li>
<li>如果竞争的这个锁对象的线程更多,导致了更多的切换和等待,JVM会把该锁对象的锁升级为重量级锁,这个就叫做同步锁,这个锁对象Mark Word再次发生变化,会指向一个监视器对象,这个监视器对象用集合的形式,来登记和管理排队的线程。如下图第四种情形。</li>
</ol>
<p><img src="https://s2.loli.net/2022/03/13/nf8jbKCHoBuyAVM.png" alt="img"></p>
<ul>
<li><p>偏向锁Biased Locking:Java6引入的一项多线程优化,偏向锁,顾名思义,它会偏向于第一个访问锁的线程,如果在运行过程中,同步锁只有一个线程访问,不存在多线程争用的情况,则线程是不需要触发同步的,这种情况下,就会给线程加一个偏向锁。 如果在运行过程中,遇到了其他线程抢占锁,则持有偏向锁的线程会被挂起,JVM会消除它身上的偏向锁,将锁恢复到标准的轻量级锁。</p>
</li>
<li><p>自旋锁:自旋锁的目的是为了占着CPU的资源不释放,等到获取到锁立即进行处理。一直在自旋也是占用CPU的,如果自旋的线程非常多,自旋次数也非常大CPU可能会跑满,所以需要升级。</p>
</li>
<li><p>重量级锁:内核态的锁,资源开销较大。内部会将等待中的线程进行wait处理,防止消耗CPU。</p>
</li>
</ul>
<h2 id="4-Klass-Pointer"><a href="#4-Klass-Pointer" class="headerlink" title="4. Klass Pointer"></a>4. Klass Pointer</h2><p><strong>对象头</strong>的<strong>另外一部分是类型指针</strong>,这一部分用于存储对象的类型指针,该指针指向它的类元数据,JVM通过这个指针确定对象是哪个类的实例。该指针的位长度为JVM的一个字大小,即32位的JVM为32位,64位的JVM为64位。如果应用的对象过多,使用64位的指针将浪费大量内存,统计而言,64位的JVM将会比32位的JVM多耗费50%的内存。为了节约内存可以使用选项+UseCompressedOops开启指针压缩,其中,oop即ordinary object pointer普通对象指针。开启该选项后,下列指针将压缩至32位:</p>
<ol>
<li>每个Class的属性指针(即静态变量)</li>
<li>每个对象的属性指针(即对象变量)</li>
<li>普通对象数组的每个元素指针</li>
</ol>
<p>当然,也不是所有的指针都会压缩,一些特殊类型的指针JVM不会优化,比如指向PermGen的Class对象指针(JDK8中指向元空间的Class对象指针)、本地变量、堆栈元素、入参、返回值和NULL指针等。</p>
<h2 id="5-使用JOL验证"><a href="#5-使用JOL验证" class="headerlink" title="5. 使用JOL验证"></a>5. 使用JOL验证</h2><p>JOL(Java对象布局)是Tiny Toolbox,用于分析JVM中的对象布局。这些工具使用Unsafe、JVMTI和Serviceability Agent (SA) ,可重复解码实际对象布局,占用件和引用。这使得JOL比依赖于堆转储,规格假设等的其他工具更准确。</p>
<h3 id="5-1-创建maven项目"><a href="#5-1-创建maven项目" class="headerlink" title="5.1. 创建maven项目"></a>5.1. 创建maven项目</h3><p>笔者使用IDEA创建一个maven项目</p>
<h3 id="5-2-添加maven依赖包"><a href="#5-2-添加maven依赖包" class="headerlink" title="5.2. 添加maven依赖包"></a>5.2. 添加maven依赖包</h3><p>在<code>pom.xml</code>中添加:</p>
<figure class="highlight xml"><table><tr><td class="code"><pre><span class="line"><span class="tag"><<span class="name">dependency</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">groupId</span>></span>org.openjdk.jol<span class="tag"></<span class="name">groupId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">artifactId</span>></span>jol-core<span class="tag"></<span class="name">artifactId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">version</span>></span>0.9<span class="tag"></<span class="name">version</span>></span></span><br><span class="line"><span class="tag"></<span class="name">dependency</span>></span></span><br></pre></td></tr></table></figure>
<h3 id="5-3-创建类并输出JOL信息"><a href="#5-3-创建类并输出JOL信息" class="headerlink" title="5.3. 创建类并输出JOL信息"></a>5.3. 创建类并输出JOL信息</h3><p>创建一个空的新类并输出JOL信息:</p>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="keyword">import</span> org.openjdk.jol.info.ClassLayout;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">JolTest</span> {</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">class</span> <span class="title class_">T</span> {</span><br><span class="line"></span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> {</span><br><span class="line"> <span class="type">T</span> <span class="variable">t</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">T</span>();</span><br><span class="line"> System.out.println(ClassLayout.parseInstance(t).toPrintable());</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br></pre></td></tr></table></figure>
<p>输出信息:</p>
<figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">JolTest$T object internals:</span><br><span class="line"> OFFSET SIZE TYPE DESCRIPTION VALUE</span><br><span class="line"> 0 4 (object header) 01 00 00 00 (00000001 00000000 00000000 00000000) (1)</span><br><span class="line"> 4 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0)</span><br><span class="line"> 8 4 (object header) 43 c1 00 20 (01000011 11000001 00000000 00100000) (536920387)</span><br><span class="line"> 12 4 (loss due to the next object alignment)</span><br><span class="line">Instance size: 16 bytes</span><br><span class="line">Space losses: 0 bytes internal + 4 bytes external = 4 bytes total</span><br></pre></td></tr></table></figure>
<p>可以看到有 OFFSET、SIZE、TYPE DESCRIPTION、VALUE 这几个名词头,它们的含义分别是</p>
<ul>
<li>OFFSET:偏移地址,单位字节;</li>
<li>SIZE:占用的内存大小,单位为字节;</li>
<li>TYPE DESCRIPTION:类型描述,其中object header为对象头;</li>
<li>VALUE:对应内存中当前存储的值,二进制32位;</li>
</ul>
<p>输出信息图示:</p>
<p><img src="https://s2.loli.net/2022/03/13/boAmJgQrxL6GC5D.png" alt="image-20220313173222454"></p>
<p>可以看到,t对象实例共占据16byte,对象头(object header)占据12byte(96bit),其中 mark word占8byte(64bit),klass pointe 占4byte,另外剩余4byte是填充对齐的</p>
<p>这里由于默认开启了<strong>指针压缩</strong> ,所以对象头占了12byte,具体的指针压缩的概念这里就不再阐述了,感兴趣的读者可以自己查阅下<a href="https://docs.oracle.com/javase/8/docs/technotes/guides/vm/performance-enhancements-7.html">官方文档</a>。jdk8版本是默认开启指针压缩的,可以通过配置vm参数开启关闭指针压缩,<code>-XX:-UseCompressedOops</code></p>
<p><img src="https://s2.loli.net/2022/03/13/XcvYbx2LU9yZQKf.png" alt="image-20220313165148795"></p>
<p>再次输出JOL信息:</p>
<figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">JolTest$T object internals:</span><br><span class="line"> OFFSET SIZE TYPE DESCRIPTION VALUE</span><br><span class="line"> 0 4 (object header) 01 00 00 00 (00000001 00000000 00000000 00000000) (1)</span><br><span class="line"> 4 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0)</span><br><span class="line"> 8 4 (object header) 70 35 a4 17 (01110000 00110101 10100100 00010111) (396637552)</span><br><span class="line"> 12 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0)</span><br><span class="line">Instance size: 16 bytes</span><br><span class="line">Space losses: 0 bytes internal + 0 bytes external = 0 bytes total</span><br></pre></td></tr></table></figure>
<p>关闭指针压缩重新打印对象的内存布局,可以发现总SIZE变大了,从下图中可以看到,对象头所占用的内存大小变为16byte(128bit),其中 mark word占8byte,klass pointe 占8byte,无对齐填充</p>
<p>创建一个数组对象:</p>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="keyword">import</span> org.openjdk.jol.info.ClassLayout;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">JolTest</span> {</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">class</span> <span class="title class_">T</span> {</span><br><span class="line"></span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> {</span><br><span class="line"><span class="comment">// T t = new T();</span></span><br><span class="line"> <span class="type">int</span>[] t = {};</span><br><span class="line"> System.out.println(ClassLayout.parseInstance(t).toPrintable());</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br></pre></td></tr></table></figure>
<p>输出信息:</p>
<figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">[I object internals:</span><br><span class="line"> OFFSET SIZE TYPE DESCRIPTION VALUE</span><br><span class="line"> 0 4 (object header) 01 00 00 00 (00000001 00000000 00000000 00000000) (1)</span><br><span class="line"> 4 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0)</span><br><span class="line"> 8 4 (object header) 6d 01 00 20 (01101101 00000001 00000000 00100000) (536871277)</span><br><span class="line"> 12 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0)</span><br><span class="line"> 16 0 int [I.<elements> N/A</span><br><span class="line">Instance size: 16 bytes</span><br><span class="line">Space losses: 0 bytes internal + 0 bytes external = 0 bytes total</span><br><span class="line"></span><br></pre></td></tr></table></figure>
<p>输出信息图示:</p>
<p><img src="https://s2.loli.net/2022/03/13/muSlK32hk7dAvbc.png" alt="image-20220313172402232"></p>
<p>可以看到这时总SIZE为共16byte,对象头占16byte,其中Mark Work占8byte,Klass Point 占4byte,array length 占4byte,因为里面没有数据,所以数组对象的实例数据占据0byte,无填充</p>
<h2 id="6-参考资料"><a href="#6-参考资料" class="headerlink" title="6. 参考资料"></a>6. 参考资料</h2><p>[1]<a href="https://www.cnblogs.com/duanxz/p/4967042.html">java对象在内存中的结构(HotSpot虚拟机) - duanxz - 博客园 (cnblogs.com)</a></p>
<p>[2]<a href="https://www.cnblogs.com/jajian/p/13681781.html">Java对象的内存布局 - JaJian - 博客园 (cnblogs.com)</a></p>
<p>[3]<a href="https://github.com/openjdk/jdk8">openjdk/jdk8: Read-only mirror of https://hg.openjdk.java.net/jdk8 (github.com)</a></p>
<p>[4]<a href="https://github.com/openjdk/jol">openjdk/jol: https://openjdk.java.net/projects/code-tools/jol/ (github.com)</a></p>
]]></content>
<categories>
<category>Java</category>
</categories>
<tags>
<tag>Java</tag>
<tag>JVM</tag>
</tags>
</entry>
<entry>
<title>C与Java中的动态数组</title>
<url>/2022/03/15/C%E4%B8%8EJava%E4%B8%AD%E7%9A%84%E5%8A%A8%E6%80%81%E6%95%B0%E7%BB%84/</url>
<content><![CDATA[<h2 id="1-引言"><a href="#1-引言" class="headerlink" title="1. 引言"></a>1. 引言</h2><p>在实际的编程中,往往会发生这种情况,即所需的内存空间取决于实际输入的数据,而无法预先确定。对于这种问题,用静态数组的办法很难解决。</p>
<p>动态数组,是相对于静态数组而言。静态数组的长度是预先定义好的,在整个程序中,一旦给定大小后就无法改变。而动态数组则不然,它可以随程序需要而重新指定大小。</p>
<h2 id="2-Java中的动态数组"><a href="#2-Java中的动态数组" class="headerlink" title="2. Java中的动态数组"></a>2. Java中的动态数组</h2><p>Java动态数组是一种可以任意伸缩数组长度的对象,在Java中比较常用的是ArrayList,ArrayList是javaAPI中自带的java.util.ArrayList。</p>
<p>在JDK1.8源码中,ArrayList的自动增长以适应数组长度的实现代码如下:</p>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Increases the capacity to ensure that it can hold at least the</span></span><br><span class="line"><span class="comment"> * number of elements specified by the minimum capacity argument.</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> minCapacity the desired minimum capacity</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title function_">grow</span><span class="params">(<span class="type">int</span> minCapacity)</span> {</span><br><span class="line"> <span class="comment">// overflow-conscious code</span></span><br><span class="line"> <span class="type">int</span> <span class="variable">oldCapacity</span> <span class="operator">=</span> elementData.length;</span><br><span class="line"> <span class="type">int</span> <span class="variable">newCapacity</span> <span class="operator">=</span> oldCapacity + (oldCapacity >> <span class="number">1</span>);</span><br><span class="line"> <span class="keyword">if</span> (newCapacity - minCapacity < <span class="number">0</span>)</span><br><span class="line"> newCapacity = minCapacity;</span><br><span class="line"> <span class="keyword">if</span> (newCapacity - MAX_ARRAY_SIZE > <span class="number">0</span>)</span><br><span class="line"> newCapacity = hugeCapacity(minCapacity);</span><br><span class="line"> <span class="comment">// minCapacity is usually close to size, so this is a win:</span></span><br><span class="line"> elementData = Arrays.copyOf(elementData, newCapacity);</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p>简言之,就是不断判断原来那个数组长度够不够用,不够就增加原来的一半,还不够就继续增加,然后再将原来的数组的值拷贝过来</p>
<p>可见其存在一定的空间浪费和增长时反复拷贝的性能损失</p>
<h2 id="3-C-x2F-C-中的动态数组"><a href="#3-C-x2F-C-中的动态数组" class="headerlink" title="3. C/C++中的动态数组"></a>3. C/C++中的动态数组</h2><p>C语言中,数组长度必须在创建数组时指定,并且只能是一个常数,不能是变量。动态数组的内存空间是从堆(heap)上分配(即动态分配)的。是通过执行代码而为其分配存储空间。当程序执行到这些语句时,才为其分配。程序员自己负责释放内存。</p>
<p>C的动态数组示例:</p>
<figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><stdio.h></span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><stdlib.h></span></span></span><br><span class="line"><span class="type">int</span> <span class="title function_">main</span><span class="params">()</span>{</span><br><span class="line"> <span class="type">int</span> arrLen; <span class="comment">// 数组长度</span></span><br><span class="line"> <span class="type">int</span> *<span class="built_in">array</span>; <span class="comment">// 数组指针</span></span><br><span class="line"> <span class="type">int</span> i; <span class="comment">// 数组下标</span></span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"输入数组长度:"</span>);</span><br><span class="line"> <span class="built_in">scanf</span>(<span class="string">"%d"</span>, &arrLen);</span><br><span class="line"> </span><br><span class="line"> <span class="comment">// 动态分配内存空间,如果失败就退出程序</span></span><br><span class="line"> <span class="built_in">array</span> = (<span class="type">int</span>*)<span class="built_in">malloc</span>( arrLen*<span class="keyword">sizeof</span>(<span class="type">int</span>) );</span><br><span class="line"> <span class="keyword">if</span>(!<span class="built_in">array</span>){</span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"创建数组失败!\n"</span>);</span><br><span class="line"> <span class="built_in">exit</span>(<span class="number">1</span>); </span><br><span class="line"> }</span><br><span class="line"> <span class="comment">// 向内存中写入数据</span></span><br><span class="line"> <span class="keyword">for</span>(i=<span class="number">0</span>; i<arrLen; i++){</span><br><span class="line"> <span class="built_in">array</span>[i] = i+<span class="number">1</span>;</span><br><span class="line"> }</span><br><span class="line"> </span><br><span class="line"> <span class="comment">// 循环输出数组元素</span></span><br><span class="line"> <span class="keyword">for</span>(i=<span class="number">0</span>; i<arrLen; i++){</span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"%d "</span>, <span class="built_in">array</span>[i]);</span><br><span class="line"> }</span><br><span class="line"> </span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"\n"</span>);</span><br><span class="line"> <span class="built_in">free</span>(<span class="built_in">array</span>); </span><br><span class="line"> </span><br><span class="line"> system(<span class="string">"pause"</span>);</span><br><span class="line"> <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p>malloc() 用来动态分配指定大小的内存空间,以字节计,其原型为:</p>
<figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="type">void</span> *<span class="title function_">malloc</span><span class="params">( <span class="type">size_t</span> size )</span>;</span><br></pre></td></tr></table></figure>
<p>size_t 是一种自定义数据类型,在 stddef.h 头文件中定义为:</p>
<figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="keyword">typedef</span> <span class="type">unsigned</span> <span class="type">int</span> <span class="type">size_t</span>; <span class="comment">// 无符号整型</span></span><br></pre></td></tr></table></figure>
<p>malloc()返回值类型为 void *,这并不是说该函数调用后无返回值,而是返回一个内存结点的地址,该地址的类型为void(无类型或类型不确定),即一段存储区的首址,其具体类型无法确定,只有使用时根据各个域值数据再确定。</p>
<h2 id="4-参考资料"><a href="#4-参考资料" class="headerlink" title="4. 参考资料"></a>4. 参考资料</h2><p>[1]<a href="https://www.cnblogs.com/jokerjason/p/10419129.html">Java ArrayList动态数组 - JokerJason - 博客园 (cnblogs.com)</a></p>
<p>[2]<a href="http://c.biancheng.net/cpp/html/2790.html">C语言实现动态数组,克服静态数组大小固定的缺陷_C语言中文网 (biancheng.net)</a></p>
]]></content>
<categories>
<category>Java</category>
</categories>
<tags>
<tag>Java</tag>
<tag>C</tag>
</tags>
</entry>
<entry>
<title>异或运算</title>
<url>/2022/03/15/%E5%BC%82%E6%88%96%E8%BF%90%E7%AE%97/</url>
<content><![CDATA[<h2 id="1-简介"><a href="#1-简介" class="headerlink" title="1. 简介"></a>1. 简介</h2><p>异或运算XOR 是 exclusive OR 的缩写。英语的 exclusive 意思是”专有的,独有的”,可以理解为 XOR 是更单纯的 OR 运算。</p>
<p>我们知道,OR 运算的运算子有两种情况,计算结果为<code>true</code></p>
<ul>
<li><p>一个为 true,另一个为 false;</p>
</li>
<li><p>两个都为 true。</p>
</li>
</ul>
<p>上面两种情况,有时候需要明确区分,所以引入了 XOR</p>
<p>XOR 排除了第二种情况,只有第一种情况(一个运算子为<code>true</code>,另一个为<code>false</code>)才会返回 true,所以可以看成是更单纯的 OR 运算。也就是说, <strong>XOR 主要用来判断两个值是否不同</strong>:</p>
<ul>
<li>相同为True</li>
<li>不同为False</li>
</ul>
<h2 id="2-性质"><a href="#2-性质" class="headerlink" title="2. 性质"></a>2. 性质</h2><ul>
<li><strong>一个值与自身的运算,总是为 false</strong></li>
<li><strong>一个值与 0 的运算,总是等于其本身</strong></li>
<li><strong>满足交换律和结合律</strong></li>
</ul>
<h2 id="3-应用"><a href="#3-应用" class="headerlink" title="3. 应用"></a>3. 应用</h2><h3 id="3-1-简化计算"><a href="#3-1-简化计算" class="headerlink" title="3.1. 简化计算"></a>3.1. 简化计算</h3><p>运用异或运算的性质进行计算简化</p>
<h3 id="3-2-交换值"><a href="#3-2-交换值" class="headerlink" title="3.2. 交换值"></a>3.2. 交换值</h3><p>利用异或运算的性质,实现无空间开销的交换数值:</p>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">swap</span><span class="params">(<span class="type">int</span>[] arr, <span class="type">int</span> i, <span class="type">int</span> j)</span> {</span><br><span class="line"> arr[i] = arr[i]^arr[j];</span><br><span class="line"> arr[j] = arr[i]^arr[j];</span><br><span class="line"> arr[i] = arr[i]^arr[j];</span><br><span class="line">}</span><br></pre></td></tr></table></figure>