-
Notifications
You must be signed in to change notification settings - Fork 34
Expand file tree
/
Copy pathsec_git_basics.ptx
More file actions
1256 lines (1006 loc) · 60 KB
/
sec_git_basics.ptx
File metadata and controls
1256 lines (1006 loc) · 60 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"?>
<section xml:id="sec_git_basics" xmlns:xi="http://www.w3.org/2001/XInclude">
<title>Git Basics</title>
<introduction>
<p>
If you could read only one section to get going with Git, this would be the one to read. This section covers every basic command you need to do the vast majority of the things you’ll eventually spend your time doing with Git. By the end of this section, you should be able to configure and initialize a repository, begin and stop tracking files, and stage and commit changes. You will also learn how to set up Git to ignore certain files and file patterns, how to undo mistakes quickly and easily, how to browse the history of your project and view changes between commits, and how to push and pull from remote repositories.
</p>
</introduction>
<subsection xml:id="_getting_a_repo">
<title>Getting a Git Repository</title>
<!-- div attr= class="paragraph"-->
<p>
You typically obtain an existing Git repository in one of two ways:
</p><!--</div attr= class="paragraph">-->
<!-- div attr= class="olist arabic"-->
<p><ol>
<li>
<p>
You can take an existing local directory that is currently not under version control, and turn it into a Git repository, or
</p>
</li>
<li>
<p>
You can <em>clone</em> an existing Git repository from elsewhere.
</p>
</li>
</ol></p><!--</div attr= class="olist arabic">-->
<!-- div attr= class="paragraph"-->
<p>
In either case, you end up with a Git repository on your local machine, ready for work.
</p><!--</div attr= class="paragraph">-->
<!-- div attr= class="sect3"-->
<subsection xml:id="_initializing_a_repository_in_an_existing_directory">
<title>Initializing a Repository in an Existing Directory</title>
<!-- div attr= class="paragraph"-->
<p>
If you have a project directory that is currently not under version control and you want to start controlling it with Git, you first need to go to that project’s directory. If you’ve never done this, it looks a little different depending on which system you’re running:
</p><!--</div attr= class="paragraph">-->
<!-- div attr= class="paragraph"-->
<p>
for Linux:
</p><!--</div attr= class="paragraph">-->
<!-- div attr= class="listingblock"-->
<!-- div attr= class="content"-->
<pre>$ cd /home/user/my_project</pre><!--</div attr= class="content">--><!--</div attr= class="listingblock">-->
<!-- div attr= class="paragraph"-->
<p>
for macOS:
</p><!--</div attr= class="paragraph">-->
<!-- div attr= class="listingblock"-->
<!-- div attr= class="content"-->
<pre>$ cd /Users/user/my_project</pre><!--</div attr= class="content">--><!--</div attr= class="listingblock">-->
<!-- div attr= class="paragraph"-->
<p>
for Windows:
</p><!--</div attr= class="paragraph">-->
<!-- div attr= class="listingblock"-->
<!-- div attr= class="content"-->
<pre>$ cd C:/Users/user/my_project</pre><!--</div attr= class="content">--><!--</div attr= class="listingblock">-->
<!-- div attr= class="paragraph"-->
<p>
and type:
</p><!--</div attr= class="paragraph">-->
<!-- div attr= class="listingblock"-->
<!-- div attr= class="content"-->
<pre>$ git init</pre><!--</div attr= class="content">--><!--</div attr= class="listingblock">-->
<!-- div attr= class="paragraph"-->
<p>
This creates a new subdirectory named <c>.git</c> that contains all of your necessary repository files — a Git repository skeleton. At this point, nothing in your project is tracked yet.
</p><!--</div attr= class="paragraph">-->
<!-- div attr= class="paragraph"-->
<p>
If you want to start version-controlling existing files (as opposed to an empty directory), you should probably begin tracking those files and do an initial commit. You can accomplish that with a few <c>git add</c> commands that specify the files you want to track, followed by a <c>git commit</c>:
</p><!--</div attr= class="paragraph">-->
<!-- div attr= class="listingblock"-->
<!-- div attr= class="content"-->
<pre>$ git add *.c
$ git add LICENSE
$ git commit -m 'Initial project version'</pre><!--</div attr= class="content">--><!--</div attr= class="listingblock">-->
<!-- div attr= class="paragraph"-->
<p>
We’ll go over what these commands do in just a minute. At this point, you have a Git repository with tracked files and an initial commit.
</p><!--</div attr= class="paragraph">--><!--</div attr= class="sect3">-->
<!-- div attr= class="sect3"-->
</subsection>
<subsection xml:id="_git_cloning">
<title>Cloning an Existing Repository</title>
<!-- div attr= class="paragraph"-->
<p>
If you want to get a copy of an existing Git repository — for example, a project you’d like to contribute to — the command you need is <c>git clone</c>. If you’re familiar with other VCSs such as Subversion, you’ll notice that the command is "clone" and not "checkout". This is an important distinction — instead of getting just a working copy, Git receives a full copy of nearly all data that the server has. Every version of every file for the history of the project is pulled down by default when you run <c>git clone</c>.
</p><!--</div attr= class="paragraph">-->
<!-- div attr= class="paragraph"-->
<p>
You clone a repository with <c>git clone <url></c>. For example, if you want to clone the Git linkable library called <c>libgit2</c>, you can do so like this:
</p><!--</div attr= class="paragraph">-->
<!-- div attr= class="listingblock"-->
<!-- div attr= class="content"-->
<pre>$ git clone https://github.com/libgit2/libgit2</pre><!--</div attr= class="content">--><!--</div attr= class="listingblock">-->
<!-- div attr= class="paragraph"-->
<p>
That creates a directory named <c>libgit2</c>, initializes a <c>.git</c> directory inside it, pulls down all the data for that repository, and checks out a working copy of the latest version. If you go into the new <c>libgit2</c> directory that was just created, you’ll see the project files in there, ready to be worked on or used.
</p><!--</div attr= class="paragraph">-->
<!-- div attr= class="paragraph"-->
<p>
If you want to clone the repository into a directory named something other than <c>libgit2</c>, you can specify the new directory name as an additional argument:
</p><!--</div attr= class="paragraph">-->
<!-- div attr= class="listingblock"-->
<!-- div attr= class="content"-->
<pre>$ git clone https://github.com/libgit2/libgit2 mylibgit</pre><!--</div attr= class="content">--><!--</div attr= class="listingblock">-->
<!-- div attr= class="paragraph"-->
<p>
That command does the same thing as the previous one, but the target directory is called <c>mylibgit</c>.
</p><!--</div attr= class="paragraph">-->
<!-- div attr= class="paragraph"-->
<p>
Git has a number of different transfer protocols you can use. The previous example uses the <c>https://</c> protocol, but you may also see <c>git://</c> or <c>user@server:path/to/repo.git</c>, which uses the SSH transfer protocol.
</p><!--</div attr= class="paragraph">--><!--</div attr= class="sect3">-->
</subsection>
</subsection>
<subsection xml:id="_recording_changes_to_the_repository">
<title>Recording Changes to the Repository</title>
<!-- div attr= class="paragraph"-->
<p>
At this point, you should have a <em>bona fide</em> Git repository on your local machine, and a checkout or <em>working copy</em> of all of its files in front of you. Typically, you’ll want to start making changes and committing snapshots of those changes into your repository each time the project reaches a state you want to record.
</p><!--</div attr= class="paragraph">-->
<!-- div attr= class="paragraph"-->
<p>
Remember that each file in your working directory can be in one of two states: <em>tracked</em> or <em>untracked</em>. Tracked files are files that were in the last snapshot, as well as any newly staged files; they can be unmodified, modified, or staged. In short, tracked files are files that Git knows about.
</p><!--</div attr= class="paragraph">-->
<!-- div attr= class="paragraph"-->
<p>
Untracked files are everything else — any files in your working directory that were not in your last snapshot and are not in your staging area. When you first clone a repository, all of your files will be tracked and unmodified because Git just checked them out and you haven’t edited anything.
</p><!--</div attr= class="paragraph">-->
<!-- div attr= class="paragraph"-->
<p>
As you edit files, Git sees them as modified, because you’ve changed them since your last commit. As you work, you selectively stage these modified files and then commit all those staged changes, and the cycle repeats.
</p><!--</div attr= class="paragraph">-->
<!-- div attr= class="imageblock"-->
<!-- div attr= class="content"-->
<figure xml:id="git-lifecycle">
<caption>The lifecycle of the status of your files</caption>
<image source='lifecycle.png'>
<description>An image using arrows to describe different changes to the status of your files during their lifecycle when working with git.</description>
</image><!--</div attr= class="content">-->
</figure>
<!-- div attr= class="title"-->
<!--</div attr= class="title">--><!--</div attr= class="imageblock">-->
<!-- div attr= class="sect3"-->
<subsection xml:id="_checking_status">
<title>Checking the Status of Your Files</title>
<!-- div attr= class="paragraph"-->
<p>
The main tool you use to determine which files are in which state is the <c>git status</c> command. If you run this command directly after a clone, you should see something like this:
</p><!--</div attr= class="paragraph">-->
<!-- div attr= class="listingblock"-->
<!-- div attr= class="content"-->
<pre>$ git status
On branch main
Your branch is up-to-date with 'origin/main'.
nothing to commit, working tree clean</pre><!--</div attr= class="content">--><!--</div attr= class="listingblock">-->
<!-- div attr= class="paragraph"-->
<p>
This means you have a clean working directory; in other words, none of your tracked files are modified. Git also doesn’t see any untracked files, or they would be listed here. Finally, the command tells you which branch you’re on and informs you that it has not diverged from the same branch on the server. That branch is typically <c>main</c>, which is the current default. It could also be <c>master</c>, which was the default until October 1, 2020. Don't worry about it here. The next section on Git Branching will go over branches and references in detail.
</p><!--</div attr= class="paragraph">-->
<!-- div attr= class="paragraph"-->
<p>
Let’s say you add a new file to your project, a simple <c>README</c> file. If the file didn’t exist before, and you run <c>git status</c>, you see your untracked file like so:
</p><!--</div attr= class="paragraph">-->
<!-- div attr= class="listingblock"-->
<!-- div attr= class="content"-->
<pre>$ echo 'My Project' > README
$ git status
On branch main
Your branch is up-to-date with 'origin/main'.
Untracked files:
(use "git add <file>..." to include in what will be committed)
README
nothing added to commit but untracked files present (use "git add" to track)</pre><!--</div attr= class="content">--><!--</div attr= class="listingblock">-->
<!-- div attr= class="paragraph"-->
<p>
You can see that your new <c>README</c> file is untracked, because it’s under the “Untracked files” heading in your status output. Untracked basically means that Git sees a file you didn’t have in the previous snapshot (commit), and which hasn’t yet been staged; Git won’t start including it in your commit snapshots until you explicitly tell it to do so. It does this so you don’t accidentally begin including generated binary files or other files that you did not mean to include. You do want to start including <c>README</c>, so let’s start tracking the file.
</p><!--</div attr= class="paragraph">--><!--</div attr= class="sect3">-->
<!-- div attr= class="sect3"-->
</subsection>
<subsection xml:id="_tracking_files">
<title>Tracking New Files</title>
<!-- div attr= class="paragraph"-->
<p>
In order to begin tracking a new file, you use the command <c>git add</c>. To begin tracking the <c>README</c> file, you can run this:
</p><!--</div attr= class="paragraph">-->
<!-- div attr= class="listingblock"-->
<!-- div attr= class="content"-->
<pre>$ git add README</pre><!--</div attr= class="content">--><!--</div attr= class="listingblock">-->
<!-- div attr= class="paragraph"-->
<p>
If you run your status command again, you can see that your <c>README</c> file is now tracked and staged to be committed:
</p><!--</div attr= class="paragraph">-->
<!-- div attr= class="listingblock"-->
<!-- div attr= class="content"-->
<pre>$ git status
On branch main
Your branch is up-to-date with 'origin/main'.
Changes to be committed:
(use "git restore --staged <file>..." to unstage)
new file: README</pre><!--</div attr= class="content">--><!--</div attr= class="listingblock">-->
<!-- div attr= class="paragraph"-->
<p>
You can tell that it’s staged because it’s under the “Changes to be committed” heading. If you commit at this point, the version of the file at the time you ran <c>git add</c> is what will be in the subsequent historical snapshot. You may recall that when you ran <c>git init</c> earlier, you then ran <c>git add <files></c> — that was to begin tracking files in your directory. The <c>git add</c> command takes a path name for either a file or a directory; if it’s a directory, the command adds all the files in that directory recursively.
</p><!--</div attr= class="paragraph">--><!--</div attr= class="sect3">-->
<!-- div attr= class="sect3"-->
</subsection>
<subsection xml:id="_staging_modified_files">
<title>Staging Modified Files</title>
<!-- div attr= class="paragraph"-->
<p>
Let’s change a file that was already tracked. If you change a previously tracked file called <c>CONTRIBUTING.md</c> and then run your <c>git status</c> command again, you get something that looks like this:
</p><!--</div attr= class="paragraph">-->
<!-- div attr= class="listingblock"-->
<!-- div attr= class="content"-->
<pre>$ git status
On branch main
Your branch is up-to-date with 'origin/main'.
Changes to be committed:
(use "git reset HEAD <file>..." to unstage)
new file: README
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git checkout -- <file>..." to discard changes in working directory)
modified: CONTRIBUTING.md</pre><!--</div attr= class="content">--><!--</div attr= class="listingblock">-->
<!-- div attr= class="paragraph"-->
<p>
The <c>CONTRIBUTING.md</c> file appears under a section named “Changes not staged for commit” — which means that a file that is tracked has been modified in the working directory but not yet staged. To stage it, you run the <c>git add</c> command. <c>git add</c> is a multipurpose command — you use it to begin tracking new files, to stage files, and to do other things like marking merge-conflicted files as resolved. It may be helpful to think of it more as “add precisely this content to the next commit” rather than “add this file to the project”. Let’s run <c>git add</c> now to stage the <c>CONTRIBUTING.md</c> file, and then run <c>git status</c> again:
</p><!--</div attr= class="paragraph">-->
<!-- div attr= class="listingblock"-->
<!-- div attr= class="content"-->
<pre>$ git add CONTRIBUTING.md
$ git status
On branch main
Your branch is up-to-date with 'origin/main'.
Changes to be committed:
(use "git reset HEAD <file>..." to unstage)
new file: README
modified: CONTRIBUTING.md</pre><!--</div attr= class="content">--><!--</div attr= class="listingblock">-->
<!-- div attr= class="paragraph"-->
<p>
Both files are staged and will go into your next commit. At this point, suppose you remember one little change that you want to make in <c>CONTRIBUTING.md</c> before you commit it. You open it again and make that change, and you’re ready to commit. However, let’s run <c>git status</c> one more time:
</p><!--</div attr= class="paragraph">-->
<!-- div attr= class="listingblock"-->
<!-- div attr= class="content"-->
<pre>
$ git status
On branch main
Your branch is up-to-date with 'origin/main'.
Changes to be committed:
(use "git reset HEAD <file>..." to unstage)
new file: README
modified: CONTRIBUTING.md
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git checkout -- <file>..." to discard changes in working directory)
modified: CONTRIBUTING.md</pre><!--</div attr= class="content">--><!--</div attr= class="listingblock">-->
<!-- div attr= class="paragraph"-->
<p>
What the heck? Now <c>CONTRIBUTING.md</c> is listed as both staged <em>and</em> unstaged. How is that possible? It turns out that Git stages a file exactly as it is when you run the <c>git add</c> command. If you commit now, the version of <c>CONTRIBUTING.md</c> as it was when you last ran the <c>git add</c> command is how it will go into the commit, not the version of the file as it looks in your working directory when you run <c>git commit</c>. If you modify a file after you run <c>git add</c>, you have to run <c>git add</c> again to stage the latest version of the file:
</p><!--</div attr= class="paragraph">-->
<!-- div attr= class="listingblock"-->
<!-- div attr= class="content"-->
<pre>$ git add CONTRIBUTING.md
$ git status
On branch main
Your branch is up-to-date with 'origin/main'.
Changes to be committed:
(use "git reset HEAD <file>..." to unstage)
new file: README
modified: CONTRIBUTING.md</pre><!--</div attr= class="content">--><!--</div attr= class="listingblock">--><!--</div attr= class="sect3">-->
<!-- div attr= class="sect3"-->
</subsection>
<subsection xml:id="_short_status">
<title>Short Status</title>
<!-- div attr= class="paragraph"-->
<p>
While the <c>git status</c> output is pretty comprehensive, it’s also quite wordy. Git also has a short status flag so you can see your changes in a more compact way. If you run <c>git status -s</c> or <c>git status --short</c> you get a far more simplified output from the command:
</p><!--</div attr= class="paragraph">-->
<!-- div attr= class="listingblock"-->
<!-- div attr= class="content"-->
<pre>$ git status -s
M README
MM Rakefile
A lib/git.rb
M lib/simplegit.rb
?? LICENSE.txt</pre><!--</div attr= class="content">--><!--</div attr= class="listingblock">-->
<!-- div attr= class="paragraph"-->
<p>
New files that aren’t tracked have a <c>??</c> next to them, new files that have been added to the staging area have an <c>A</c>, modified files have an <c>M</c> and so on. There are two columns to the output — the left-hand column indicates the status of the staging area and the right-hand column indicates the status of the working tree. So for example in that output, the <c>README</c> file is modified in the working directory but not yet staged, while the <c>lib/simplegit.rb</c> file is modified and staged. The <c>Rakefile</c> was modified, staged and then modified again, so there are changes to it that are both staged and unstaged.
</p><!--</div attr= class="paragraph">--><!--</div attr= class="sect3">-->
<!-- div attr= class="sect3"-->
</subsection>
<subsection xml:id="_ignoring">
<title>Ignoring Files</title>
<!-- div attr= class="paragraph"-->
<p>
Often, you’ll have a class of files that you don’t want Git to automatically add or even show you as being untracked. These are generally automatically generated files such as log files or files produced by your build system. In such cases, you can create a file listing patterns to match them named <c>.gitignore</c>. Here is an example <c>.gitignore</c> file:
</p><!--</div attr= class="paragraph">-->
<!-- div attr= class="listingblock"-->
<!-- div attr= class="content"-->
<pre>$ cat .gitignore
*.[oa]
*~</pre><!--</div attr= class="content">--><!--</div attr= class="listingblock">-->
<!-- div attr= class="paragraph"-->
<p>
The first line tells Git to ignore any files ending in “.o” or “.a” — object and archive files that may be the product of building your code. The second line tells Git to ignore all files whose names end with a tilde (<c>~</c>), which is used by some text editors to mark temporary files. You may also include a log, tmp, or pid directory; automatically generated documentation; and so on. Setting up a <c>.gitignore</c> file for your new repository before you get going is generally a good idea so you don’t accidentally commit files that you really don’t want in your Git repository.
<notation>
<usage><m>\tilde{}</m></usage>
<description>tilde - temporary file symbol</description>
</notation>
</p><!--</div attr= class="paragraph">-->
<!-- div attr= class="paragraph"-->
<p>
The rules for the patterns you can put in the <c>.gitignore</c> file are as follows:
</p><!--</div attr= class="paragraph">-->
<!-- div attr= class="ulist"-->
<p><ul>
<li>
<p>
Blank lines or lines starting with <c>#</c> are ignored.
<notation>
<usage><m>\#</m></usage>
<description>pound symbol - begins single line comment in shell script</description>
</notation>
</p>
</li>
<li>
<p>
Standard glob patterns work, and will be applied recursively throughout the entire working tree.
</p>
</li>
<li>
<p>
You can start patterns with a forward slash (<c>/</c>) to avoid recursivity.
<notation>
<usage><m>/</m></usage>
<description>foward slash - avoids recursivity</description>
</notation>
</p>
</li>
<li>
<p>
You can end patterns with a forward slash (<c>/</c>) to specify a directory.
<notation>
<usage><m>/</m></usage>
<description>forward slash - specifies a directory</description>
</notation>
</p>
</li>
<li>
<p>
You can negate a pattern by starting it with an exclamation point (<c>!</c>).
<notation>
<usage><m>!</m></usage>
<description>exclamation point - negates</description>
</notation>
</p>
</li>
</ul></p><!--</div attr= class="ulist">-->
<!-- div attr= class="paragraph"-->
<p>
Glob patterns are like simplified regular expressions that shells use. An asterisk (<c>*</c>) matches zero or more characters; <c>[abc]</c> matches any character inside the brackets (in this case a, b, or c); a question mark (<c>?</c>) matches a single character; and brackets enclosing characters separated by a hyphen (<c>[0-9]</c>) matches any character between them (in this case 0 through 9). You can also use two asterisks to match nested directories; <c>a/**/z</c> would match <c>a/z</c>, <c>a/b/z</c>, <c>a/b/c/z</c>, and so on.
<notation>
<usage><m>[ - ]</m></usage>
<description>brackets - encloses characters</description>
</notation>
<notation>
<usage><m>*</m></usage>
<description>asterisk - matches zero or more characters</description>
</notation>
</p><!--</div attr= class="paragraph">-->
<!-- div attr= class="paragraph"-->
<p>
Here is another example <c>.gitignore</c> file:
</p><!--</div attr= class="paragraph">-->
<!-- div attr= class="listingblock"-->
<!-- div attr= class="content"-->
<pre># ignore all .a files
*.a
# but do track lib.a, even though you're ignoring .a files above
!lib.a
# only ignore the TODO file in the current directory, not subdir/TODO
/TODO
# ignore all files in any directory named build
build/
# ignore doc/notes.txt, but not doc/server/arch.txt
doc/*.txt
# ignore all .pdf files in the doc/ directory and any of its subdirectories
doc/**/*.pdf</pre><!--</div attr= class="content">--><!--</div attr= class="listingblock">-->
<hint>
<p>
Tip: GitHub maintains a fairly comprehensive list of good <c>.gitignore</c> file examples for dozens of projects and languages at <url href="https://github.com/github/gitignore" visual="github.com/github/gitignore">https://github.com/github/gitignore</url> if you want a starting point for your project.
</p>
</hint>
<p>
Note: In the simple case, a repository might have a single <c>.gitignore</c> file in its root directory, which applies recursively to the entire repository. However, it is also possible to have additional <c>.gitignore</c> files in subdirectories. The rules in these nested <c>.gitignore</c> files apply only to the files under the directory where they are located. The Linux kernel source repository has 206 <c>.gitignore</c> files.
</p><!--</div attr= class="paragraph">-->
<!-- div attr= class="paragraph"-->
<p>
It is beyond the scope of this book to get into the details of multiple <c>.gitignore</c> files; see <c>man gitignore</c> for the details.
</p><!--</div attr= class="paragraph">-->
<!-- div attr= class="sect3"-->
</subsection>
<subsection xml:id="_git_diff_staged">
<title>Viewing Your Staged and Unstaged Changes</title>
<!-- div attr= class="paragraph"-->
<p>
If the <c>git status</c> command is too vague for you — you want to know exactly what you changed, not just which files were changed — you can use the <c>git diff</c> command. We’ll cover <c>git diff</c> in more detail later, but you’ll probably use it most often to answer these two questions: What have you changed but not yet staged? And what have you staged that you are about to commit? Although <c>git status</c> answers those questions very generally by listing the file names, <c>git diff</c> shows you the exact lines added and removed — the patch, as it were.
</p><!--</div attr= class="paragraph">-->
<!-- div attr= class="paragraph"-->
<p>
Let’s say you edit and stage the <c>README</c> file again and then edit the <c>CONTRIBUTING.md</c> file without staging it. If you run your <c>git status</c> command, you once again see something like this:
</p><!--</div attr= class="paragraph">-->
<!-- div attr= class="listingblock"-->
<!-- div attr= class="content"-->
<pre>$ git status
On branch main
Your branch is up-to-date with 'origin/main'.
Changes to be committed:
(use "git reset HEAD <file>..." to unstage)
modified: README
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git checkout -- <file>..." to discard changes in working directory)
modified: CONTRIBUTING.md</pre><!--</div attr= class="content">--><!--</div attr= class="listingblock">-->
<!-- div attr= class="paragraph"-->
<p>
To see what you’ve changed but not yet staged, type <c>git diff</c> with no other arguments:
</p><!--</div attr= class="paragraph">-->
<!-- div attr= class="listingblock"-->
<!-- div attr= class="content"-->
<pre>$ git diff
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 8ebb991..643e24f 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -65,7 +65,8 @@ branch directly, things can get messy.
Please include a nice description of your changes when you submit your PR;
if we have to read the whole diff to figure out why you're contributing
in the first place, you're less likely to get feedback and have your change
-merged in.
+merged in. Also, split your changes into comprehensive chunks if your patch is
+longer than a dozen lines.
If you are starting to work on a particular area, feel free to submit a PR
that highlights your work in progress (and note in the PR title that it's</pre><!--</div attr= class="content">--><!--</div attr= class="listingblock">-->
<!-- div attr= class="paragraph"-->
<p>
That command compares what is in your working directory with what is in your staging area. The result tells you the changes you’ve made that you haven’t yet staged.
</p><!--</div attr= class="paragraph">-->
<!-- div attr= class="paragraph"-->
<p>
If you want to see what you’ve staged that will go into your next commit, you can use <c>git diff --staged</c>. This command compares your staged changes to your last commit:
</p><!--</div attr= class="paragraph">-->
<!-- div attr= class="listingblock"-->
<!-- div attr= class="content"-->
<pre>$ git diff --staged
diff --git a/README b/README
new file mode 100644
index 0000000..03902a1
--- /dev/null
+++ b/README
@@ -0,0 +1 @@
+My Project</pre><!--</div attr= class="content">--><!--</div attr= class="listingblock">-->
<!-- div attr= class="paragraph"-->
<p>
It’s important to note that <c>git diff</c> by itself doesn’t show all changes made since your last commit — only changes that are still unstaged. If you’ve staged all of your changes, <c>git diff</c> will give you no output.
</p><!--</div attr= class="paragraph">-->
<!-- div attr= class="paragraph"-->
<p>
For another example, if you stage the <c>CONTRIBUTING.md</c> file and then edit it, you can use <c>git diff</c> to see the changes in the file that are staged and the changes that are unstaged. If our environment looks like this:
</p><!--</div attr= class="paragraph">-->
<!-- div attr= class="listingblock"-->
<!-- div attr= class="content"-->
<pre>$ git add CONTRIBUTING.md
$ echo '# test line' >> CONTRIBUTING.md
$ git status
On branch main
Your branch is up-to-date with 'origin/main'.
Changes to be committed:
(use "git reset HEAD <file>..." to unstage)
modified: CONTRIBUTING.md
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git checkout -- <file>..." to discard changes in working directory)
modified: CONTRIBUTING.md</pre><!--</div attr= class="content">--><!--</div attr= class="listingblock">-->
<!-- div attr= class="paragraph"-->
<p>
Now you can use <c>git diff</c> to see what is still unstaged:
</p><!--</div attr= class="paragraph">-->
<!-- div attr= class="listingblock"-->
<!-- div attr= class="content"-->
<pre>$ git diff
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 643e24f..87f08c8 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -119,3 +119,4 @@ at the
## Starter Projects
See our [projects list](https://github.com/libgit2/libgit2/blob/development/PROJECTS.md).
+# test line</pre><!--</div attr= class="content">--><!--</div attr= class="listingblock">-->
<!-- div attr= class="paragraph"-->
<p>
and <c>git diff --cached</c> to see what you’ve staged so far (<c>--staged</c> and <c>--cached</c> are synonyms):
</p><!--</div attr= class="paragraph">-->
<p>
<!-- div attr= class="listingblock"-->
<!-- div attr= class="content"-->
<pre>$ git diff --cached
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 8ebb991..643e24f 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -65,7 +65,8 @@ branch directly, things can get messy.
Please include a nice description of your changes when you submit your PR;
if we have to read the whole diff to figure out why you're contributing
in the first place, you're less likely to get feedback and have your change
-merged in.
+merged in. Also, split your changes into comprehensive chunks if your patch is
+longer than a dozen lines.
If you are starting to work on a particular area, feel free to submit a PR
that highlights your work in progress (and note in the PR title that it is so.
</pre>
</p>
<!-- div attr= class="sect3"-->
</subsection>
<subsection xml:id="_committing_changes">
<title>Committing Your Changes</title>
<!-- div attr= class="paragraph"-->
<p>
Now that your staging area is set up the way you want it, you can commit your changes. Remember that anything that is still unstaged — any files you have created or modified that you haven’t run <c>git add</c> on since you edited them — won’t go into this commit. They will stay as modified files on your disk. In this case, let’s say that the last time you ran <c>git status</c>, you saw that everything was staged, so you’re ready to commit your changes. The simplest way to commit is to type <c>git commit</c>:
</p><!--</div attr= class="paragraph">-->
<!-- div attr= class="listingblock"-->
<!-- div attr= class="content"-->
<pre>$ git commit</pre><!--</div attr= class="content">--><!--</div attr= class="listingblock">-->
<!-- div attr= class="paragraph"-->
<p>
Doing so launches your editor of choice.
</p><!--</div attr= class="paragraph">-->
<p>
Note: This is set by your shell’s <c>EDITOR</c> environment variable, although you can configure it with whatever you want using the <c>git config - -global core.editor</c> command as you saw in the previous section.
</p>
<!-- div attr= class="paragraph"-->
<p>
The editor displays the following text:
</p><!--</div attr= class="paragraph">-->
<!-- div attr= class="listingblock"-->
<!-- div attr= class="content"-->
<pre># Please enter the commit message for your changes. Lines starting
# with '#' will be ignored, and an empty message aborts the commit.
# On branch main
# Your branch is up-to-date with 'origin/main'.
#
# Changes to be committed:
# new file: README
# modified: CONTRIBUTING.md
#
~
~
~
".git/COMMIT_EDITMSG" 9L, 283C</pre><!--</div attr= class="content">--><!--</div attr= class="listingblock">-->
<!-- div attr= class="paragraph"-->
<p>
You can see that the default commit message contains the latest output of the <c>git status</c> command commented out and one empty line on top. You can remove these comments and type your commit message, or you can leave them there to help you remember what you’re committing.
</p><!--</div attr= class="paragraph">-->
<p>
Note: For an even more explicit reminder of what you’ve modified, you can pass the <c>-v</c> option to <c>git commit</c>. Doing so also puts the diff of your change in the editor so you can see exactly what changes you’re committing.
</p>
<!-- div attr= class="paragraph"-->
<p>
When you exit the editor, Git creates your commit with that commit message (with the comments and diff stripped out).
</p><!--</div attr= class="paragraph">-->
<!-- div attr= class="paragraph"-->
<p>
Alternatively, you can type your commit message inline with the <c>commit</c> command by specifying it after a <c>-m</c> flag, like this:
</p><!--</div attr= class="paragraph">-->
<!-- div attr= class="listingblock"-->
<!-- div attr= class="content"-->
<pre>$ git commit -m "Story 182: fix benchmarks for speed"
[main 463dc4f] Story 182: fix benchmarks for speed
2 files changed, 2 insertions(+)
create mode 100644 README</pre><!--</div attr= class="content">--><!--</div attr= class="listingblock">-->
<!-- div attr= class="paragraph"-->
<p>
Now you’ve created your first commit! You can see that the commit has given you some output about itself: which branch you committed to (<c>main</c>), what SHA-1 checksum the commit has (<c>463dc4f</c>), how many files were changed, and statistics about lines added and removed in the commit.
</p><!--</div attr= class="paragraph">-->
<!-- div attr= class="paragraph"-->
<p>
Remember that the commit records the snapshot you set up in your staging area. Anything you didn’t stage is still sitting there modified; you can do another commit to add it to your history. Every time you perform a commit, you’re recording a snapshot of your project that you can revert to or compare to later.
</p><!--</div attr= class="paragraph">--><!--</div attr= class="sect3">-->
<!-- div attr= class="sect3"-->
</subsection>
<subsection xml:id="_skipping_the_staging_area">
<title>Skipping the Staging Area</title>
<!-- div attr= class="paragraph"-->
<p>
Although it can be amazingly useful for crafting commits exactly how you want them, the staging area is sometimes a bit more complex than you need in your workflow. If you want to skip the staging area, Git provides a simple shortcut. Adding the <c>-a</c> option to the <c>git commit</c> command makes Git automatically stage every file that is already tracked before doing the commit, letting you skip the <c>git add</c> part:
</p><!--</div attr= class="paragraph">-->
<!-- div attr= class="listingblock"-->
<!-- div attr= class="content"-->
<pre>$ git status
On branch main
Your branch is up-to-date with 'origin/main'.
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git checkout -- <file>..." to discard changes in working directory)
modified: CONTRIBUTING.md
no changes added to commit (use "git add" and/or "git commit -a")
$ git commit -a -m 'Add new benchmarks'
[main 83e38c7] Add new benchmarks
1 file changed, 5 insertions(+), 0 deletions(-)</pre><!--</div attr= class="content">--><!--</div attr= class="listingblock">-->
<!-- div attr= class="paragraph"-->
<p>
Notice how you don’t have to run <c>git add</c> on the <c>CONTRIBUTING.md</c> file in this case before you commit. That’s because the <c>-a</c> flag includes all changed files. This is convenient, but be careful; sometimes this flag will cause you to include unwanted changes.
</p><!--</div attr= class="paragraph">--><!--</div attr= class="sect3">-->
<!-- div attr= class="sect3"-->
</subsection>
<subsection xml:id="_removing_files">
<title>Removing Files</title>
<!-- div attr= class="paragraph"-->
<p>
To remove a file from Git, you have to remove it from your tracked files (more accurately, remove it from your staging area) and then commit. The <c>git rm</c> command does that, and also removes the file from your working directory so you don’t see it as an untracked file the next time around.
</p><!--</div attr= class="paragraph">-->
<!-- div attr= class="paragraph"-->
<p>
If you simply remove the file from your working directory, it shows up under the “Changes not staged for commit” (that is, <em>unstaged</em>) area of your <c>git status</c> output:
</p><!--</div attr= class="paragraph">-->
<!-- div attr= class="listingblock"-->
<!-- div attr= class="content"-->
<pre>$ rm PROJECTS.md
$ git status
On branch main
Your branch is up-to-date with 'origin/main'.
Changes not staged for commit:
(use "git add/rm <file>..." to update what will be committed)
(use "git checkout -- <file>..." to discard changes in working directory)
deleted: PROJECTS.md
no changes added to commit (use "git add" and/or "git commit -a")</pre><!--</div attr= class="content">--><!--</div attr= class="listingblock">-->
<!-- div attr= class="paragraph"-->
<p>
Then, if you run <c>git rm</c>, it stages the file’s removal:
</p><!--</div attr= class="paragraph">-->
<!-- div attr= class="listingblock"-->
<!-- div attr= class="content"-->
<pre>$ git rm PROJECTS.md
rm 'PROJECTS.md'
$ git status
On branch main
Your branch is up-to-date with 'origin/main'.
Changes to be committed:
(use "git reset HEAD <file>..." to unstage)
deleted: PROJECTS.md</pre><!--</div attr= class="content">--><!--</div attr= class="listingblock">-->
<!-- div attr= class="paragraph"-->
<p>
The next time you commit, the file will be gone and no longer tracked. If you modified the file or had already added it to the staging area, you must force the removal with the <c>-f</c> option. This is a safety feature to prevent accidental removal of data that hasn’t yet been recorded in a snapshot and that can’t be recovered from Git.
</p><!--</div attr= class="paragraph">-->
<!-- div attr= class="paragraph"-->
<p>
Another useful thing you may want to do is to keep the file in your working tree but remove it from your staging area. In other words, you may want to keep the file on your hard drive but not have Git track it anymore. This is particularly useful if you forgot to add something to your <c>.gitignore</c> file and accidentally staged it, like a large log file or a bunch of <c>.a</c> compiled files. To do this, use the <c>--cached</c> option:
</p><!--</div attr= class="paragraph">-->
<!-- div attr= class="listingblock"-->
<!-- div attr= class="content"-->
<pre>$ git rm --cached README</pre><!--</div attr= class="content">--><!--</div attr= class="listingblock">-->
<!-- div attr= class="paragraph"-->
<p>
You can pass files, directories, and file-glob patterns to the <c>git rm</c> command. That means you can do things such as:
</p><!--</div attr= class="paragraph">-->
<!-- div attr= class="listingblock"-->
<!-- div attr= class="content"-->
<pre>$ git rm log/\*.log</pre><!--</div attr= class="content">--><!--</div attr= class="listingblock">-->
<!-- div attr= class="paragraph"-->
<p>
Note the backslash (<c>\</c>) in front of the <c>*</c>. This is necessary because Git does its own filename expansion in addition to your shell’s filename expansion. This command removes all files that have the <c>.log</c> extension in the <c>log/</c> directory. Or, you can do something like this:
</p>
<pre>$ git rm \*~</pre><!--</div attr= class="content">--><!--</div attr= class="listingblock">-->
<p>
This command removes all files whose names end with a <c>~</c>.
<notation>
<usage><m>\backslash</m></usage>
<description>backslash - escape character</description>
</notation>
</p>
<!-- div attr= class="sect3"-->
</subsection>
<subsection xml:id="_git_mv">
<title>Moving Files</title>
<!-- div attr= class="paragraph"-->
<p>
Unlike many other VCSs, Git doesn’t explicitly track file movement. If you rename a file in Git, no metadata is stored in Git that tells it you renamed the file. However, Git is pretty smart about figuring that out after the fact — we’ll deal with detecting file movement a bit later.
</p><!--</div attr= class="paragraph">-->
<!-- div attr= class="paragraph"-->
<p>
Thus it’s a bit confusing that Git has a <c>mv</c> command. If you want to rename a file in Git, you can run something like:
</p><!--</div attr= class="paragraph">-->
<!-- div attr= class="listingblock"-->
<!-- div attr= class="content"-->
<pre>$ git mv file_from file_to</pre><!--</div attr= class="content">--><!--</div attr= class="listingblock">-->
<!-- div attr= class="paragraph"-->
<p>
and it works fine. In fact, if you run something like this and look at the status, you’ll see that Git considers it a renamed file:
</p><!--</div attr= class="paragraph">-->
<!-- div attr= class="listingblock"-->
<!-- div attr= class="content"-->
<pre>$ git mv README.md README
$ git status
On branch main
Your branch is up-to-date with 'origin/main'.
Changes to be committed:
(use "git reset HEAD <file>..." to unstage)
renamed: README.md -> README</pre><!--</div attr= class="content">--><!--</div attr= class="listingblock">-->
<!-- div attr= class="paragraph"-->
<p>
However, this is equivalent to running something like this:
</p><!--</div attr= class="paragraph">-->
<!-- div attr= class="listingblock"-->
<!-- div attr= class="content"-->
<pre>$ mv README.md README
$ git rm README.md
$ git add README</pre><!--</div attr= class="content">--><!--</div attr= class="listingblock">-->
<!-- div attr= class="paragraph"-->
<p>
Git figures out that it’s a rename implicitly, so it doesn’t matter if you rename a file that way or with the <c>mv</c> command. The only real difference is that <c>git mv</c> is one command instead of three — it’s a convenience function. More importantly, you can use any tool you like to rename a file, and address the <c>add</c>/<c>rm</c> later, before you commit.
</p><!--</div attr= class="paragraph">--><!--</div attr= class="sect3">-->
</subsection>
</subsection>
<subsection xml:id="_viewing_history">
<title>Viewing the Commit History</title>
<!-- div attr= class="paragraph"-->
<p>
After you have created several commits, or if you have cloned a repository with an existing commit history, you’ll probably want to look back to see what has happened. The most basic and powerful tool to do this is the <c>git log</c> command.
</p><!--</div attr= class="paragraph">-->
<!-- div attr= class="paragraph"-->
<p>
These examples use a very simple project called “simplegit”. To get the project, run:
</p><!--</div attr= class="paragraph">-->
<!-- div attr= class="listingblock"-->
<!-- div attr= class="content"-->
<pre>$ git clone https://github.com/schacon/simplegit-progit</pre><!--</div attr= class="content">--><!--</div attr= class="listingblock">-->
<!-- div attr= class="paragraph"-->
<p>
When you run <c>git log</c> in this project, you should get output that looks something like this:
</p><!--</div attr= class="paragraph">-->
<!-- div attr= class="listingblock"-->
<!-- div attr= class="content"-->
<pre>$ git log
commit ca82a6dff817ec66f44342007202690a93763949
Author: Scott Chacon <schacon@gee-mail.com>
Date: Mon Mar 17 21:52:11 2008 -0700
Change version number
commit 085bb3bcb608e1e8451d4b2432f8ecbe6306e7e7
Author: Scott Chacon <schacon@gee-mail.com>
Date: Sat Mar 15 16:40:33 2008 -0700
Remove unnecessary test
commit a11bef06a3f659402fe7563abf99ad00de2209e6
Author: Scott Chacon <schacon@gee-mail.com>
Date: Sat Mar 15 10:31:28 2008 -0700
Initial commit</pre><!--</div attr= class="content">--><!--</div attr= class="listingblock">-->
<!-- div attr= class="paragraph"-->
<p>
By default, with no arguments, <c>git log</c> lists the commits made in that repository in reverse chronological order; that is, the most recent commits show up first. As you can see, this command lists each commit with its SHA-1 checksum, the author’s name and email, the date written, and the commit message.
</p><!--</div attr= class="paragraph">-->
<!-- div attr= class="paragraph"-->
<p>
A huge number and variety of options to the <c>git log</c> command are available to show you exactly what you’re looking for. If interested, see <url href="https://www.git-scm.com/docs/git-log">git-log - Show commit logs</url> for the details, but don't worry about the overwhelming number of options — be reassured that you don't need them right now.
</p>
<p>
Here, we’ll show you only the most popular.
</p><!--</div attr= class="paragraph">-->
<!-- div attr= class="paragraph"-->
<p>
One of the more helpful options is <c>-p</c> or <c>--patch</c>, which shows the difference (the <em>patch</em> output) introduced in each commit. You can also limit the number of log entries displayed, such as using <c>-2</c> to show only the last two entries.
</p><!--</div attr= class="paragraph">-->
<!-- div attr= class="listingblock"-->
<!-- div attr= class="content"-->
<pre>$ git log -p -2
commit ca82a6dff817ec66f44342007202690a93763949
Author: Scott Chacon <schacon@gee-mail.com>
Date: Mon Mar 17 21:52:11 2008 -0700
Change version number
diff --git a/Rakefile b/Rakefile
index a874b73..8f94139 100644
--- a/Rakefile
+++ b/Rakefile
@@ -5,7 +5,7 @@ require 'rake/gempackagetask'
spec = Gem::Specification.new do |s|
s.platform = Gem::Platform::RUBY
s.name = "simplegit"
- s.version = "0.1.0"
+ s.version = "0.1.1"
s.author = "Scott Chacon"
s.email = "schacon@gee-mail.com"
s.summary = "A simple gem for using Git in Ruby code."
commit 085bb3bcb608e1e8451d4b2432f8ecbe6306e7e7