-
Notifications
You must be signed in to change notification settings - Fork 2
/
ch03.html
3024 lines (2997 loc) · 168 KB
/
ch03.html
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" standalone="no"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>Kapitel 3. Praktische Versionsverwaltung</title>
<link rel="stylesheet" type="text/css" href="gitbuch.css" />
<meta name="generator" content="DocBook XSL Stylesheets V1.78.1" />
<link rel="home" href="index.html" title="Git" />
<link rel="up" href="index.html" title="Git" />
<link rel="prev" href="ch02.html" title="Kapitel 2. Grundlagen" />
<link rel="next" href="ch04.html" title="Kapitel 4. Fortgeschrittene Konzepte" />
<meta xmlns="" name="language" content="de" />
<script xmlns="" src="http://hyphenator.googlecode.com/svn/trunk/Hyphenator.js" type="text/javascript"></script>
<script xmlns="" type="text/javascript">
Hyphenator.run();
</script>
</head>
<body class="hyphenate">
<div xmlns="" class="toc">
<p><a href="index.html">Startseite</a></p>
<dl class="toc">
<dt>
<span class="preface">
<a href="pr01.html">Vorwort</a>
</span>
</dt>
<dd>
<dl>
<dt>
<span class="section">
<a href="pr01.html#sec.leser">1. An wen richtet sich dieses Buch?</a>
</span>
</dt>
<dt>
<span class="section">
<a href="pr01.html#sec.struktur">2. Wie ist das Buch zu lesen?</a>
</span>
</dt>
<dt>
<span class="section">
<a href="pr01.html#sec.konventionen">3. Konventionen</a>
</span>
</dt>
<dt>
<span class="section">
<a href="pr01.html#sec.install-git-repo">4. Installation und „das Git-Repository“</a>
</span>
</dt>
<dt>
<span class="section">
<a href="pr01.html#sec.doku">5. Dokumentation und Hilfe</a>
</span>
</dt>
<dt>
<span class="section">
<a href="pr01.html#sec.kontakt">6. Downloads und Kontakt</a>
</span>
</dt>
<dt>
<span class="section">
<a href="pr01.html#sec.dank">7. Danksagungen</a>
</span>
</dt>
<dt>
<span class="section">
<a href="pr01.html#chap.vorwort-2te-auflage">8. Vorwort zur 2. Auflage</a>
</span>
</dt>
<dt>
<span class="section">
<a href="pr01.html#chap.vorwort-cc-ausgabe">9. Vorwort zur CreativeCommons-Ausgabe</a>
</span>
</dt>
</dl>
</dd>
<dt>
<span class="chapter">
<a href="ch01.html">1. Einführung und erste Schritte</a>
</span>
</dt>
<dd>
<dl>
<dt>
<span class="section">
<a href="ch01.html#sec.begriffe">1.1. Grundbegriffe</a>
</span>
</dt>
<dt>
<span class="section">
<a href="ch01.html#sec.erste-schritte">1.2. Erste Schritte mit Git</a>
</span>
</dt>
<dt>
<span class="section">
<a href="ch01.html#chap.git-config">1.3. Git konfigurieren</a>
</span>
</dt>
</dl>
</dd>
<dt>
<span class="chapter">
<a href="ch02.html">2. Grundlagen</a>
</span>
</dt>
<dd>
<dl>
<dt>
<span class="section">
<a href="ch02.html#sec.grundlagen">2.1. Git-Kommandos</a>
</span>
</dt>
<dt>
<span class="section">
<a href="ch02.html#sec.objektmodell">2.2. Das Objektmodell</a>
</span>
</dt>
</dl>
</dd>
<dt>
<span class="chapter">
<a href="ch03.html">3. Praktische Versionsverwaltung</a>
</span>
</dt>
<dd>
<dl>
<dt>
<span class="section">
<a href="ch03.html#sec.branches">3.1. Referenzen: Branches und Tags</a>
</span>
</dt>
<dt>
<span class="section">
<a href="ch03.html#sec.undo">3.2. Versionen wiederherstellen</a>
</span>
</dt>
<dt>
<span class="section">
<a href="ch03.html#sec.merge">3.3. Branches zusammenführen: Merges</a>
</span>
</dt>
<dt>
<span class="section">
<a href="ch03.html#sec.merge-conflicts">3.4. Merge-Konflikte lösen</a>
</span>
</dt>
<dt>
<span class="section">
<a href="ch03.html#sec.cherry-pick">3.5. Einzelne Commits übernehmen: Cherry-Pick</a>
</span>
</dt>
<dt>
<span class="section">
<a href="ch03.html#sec.visualization">3.6. Visualisierung von Repositories</a>
</span>
</dt>
<dt>
<span class="section">
<a href="ch03.html#sec.reflog">3.7. Reflog</a>
</span>
</dt>
</dl>
</dd>
<dt>
<span class="chapter">
<a href="ch04.html">4. Fortgeschrittene Konzepte</a>
</span>
</dt>
<dd>
<dl>
<dt>
<span class="section">
<a href="ch04.html#sec.rebase">4.1. Commits verschieben – Rebase</a>
</span>
</dt>
<dt>
<span class="section">
<a href="ch04.html#sec.rebase-i">4.2. Die Geschichte umschreiben – Interaktives Rebase</a>
</span>
</dt>
<dt>
<span class="section">
<a href="ch04.html#sec.blame">4.3. Wer hat diese Änderungen gemacht? – git blame</a>
</span>
</dt>
<dt>
<span class="section">
<a href="ch04.html#sec.ignore">4.4. Dateien ignorieren</a>
</span>
</dt>
<dt>
<span class="section">
<a href="ch04.html#sec.stash">4.5. Veränderungen auslagern – git stash</a>
</span>
</dt>
<dt>
<span class="section">
<a href="ch04.html#sec.notes">4.6. Commits annotieren – git notes</a>
</span>
</dt>
<dt>
<span class="section">
<a href="ch04.html#sec.multi-root">4.7. Mehrere Root-Commits</a>
</span>
</dt>
<dt>
<span class="section">
<a href="ch04.html#sec.bisect">4.8. Regressionen finden – git bisect</a>
</span>
</dt>
</dl>
</dd>
<dt>
<span class="chapter">
<a href="ch05.html">5. Verteiltes Git</a>
</span>
</dt>
<dd>
<dl>
<dt>
<span class="section">
<a href="ch05.html#sec.verteilte_systeme">5.1. Wie funktioniert verteilte Versionsverwaltung?</a>
</span>
</dt>
<dt>
<span class="section">
<a href="ch05.html#sec.clone">5.2. Repositories klonen</a>
</span>
</dt>
<dt>
<span class="section">
<a href="ch05.html#sec.git_fetch">5.3. Commits herunterladen</a>
</span>
</dt>
<dt>
<span class="section">
<a href="ch05.html#sec.hochladen">5.4. Commits hochladen: git push</a>
</span>
</dt>
<dt>
<span class="section">
<a href="ch05.html#sec.remotes-check">5.5. Remotes untersuchen</a>
</span>
</dt>
<dt>
<span class="section">
<a href="ch05.html#sec.multi-remote">5.6. Verteilter Workflow mit mehreren Remotes</a>
</span>
</dt>
<dt>
<span class="section">
<a href="ch05.html#sec.remotes-verwalten">5.7. Remotes verwalten</a>
</span>
</dt>
<dt>
<span class="section">
<a href="ch05.html#sec.remote-tags">5.8. Tags austauschen</a>
</span>
</dt>
<dt>
<span class="section">
<a href="ch05.html#sec.patch-queue">5.9. Patches per E-Mail</a>
</span>
</dt>
<dt>
<span class="section">
<a href="ch05.html#sec.dictator">5.10. Ein verteilter, hierarchischer Workflow</a>
</span>
</dt>
<dt>
<span class="section">
<a href="ch05.html#sec.subprojects">5.11. Unterprojekte verwalten</a>
</span>
</dt>
</dl>
</dd>
<dt>
<span class="chapter">
<a href="ch06.html">6. Workflows</a>
</span>
</dt>
<dd>
<dl>
<dt>
<span class="section">
<a href="ch06.html#sec.workflows-user">6.1. Anwender</a>
</span>
</dt>
<dt>
<span class="section">
<a href="ch06.html#sec.branch-modell">6.2. Ein Branching-Modell</a>
</span>
</dt>
<dt>
<span class="section">
<a href="ch06.html#sec.releases-management">6.3. Releases-Management</a>
</span>
</dt>
</dl>
</dd>
<dt>
<span class="chapter">
<a href="ch07.html">7. Git auf dem Server</a>
</span>
</dt>
<dd>
<dl>
<dt>
<span class="section">
<a href="ch07.html#sec.server">7.1. Einen Git-Server hosten</a>
</span>
</dt>
<dt>
<span class="section">
<a href="ch07.html#sec.gitolite">7.2. Gitolite: Git einfach hosten</a>
</span>
</dt>
<dt>
<span class="section">
<a href="ch07.html#sec.git-daemon">7.3. Git-Daemon: Anonymer, lesender Zugriff</a>
</span>
</dt>
<dt>
<span class="section">
<a href="ch07.html#sec.gitweb">7.4. Gitweb: Das integrierte Web-Frontend</a>
</span>
</dt>
<dt>
<span class="section">
<a href="ch07.html#sec.cgit">7.5. CGit – CGI for Git</a>
</span>
</dt>
</dl>
</dd>
<dt>
<span class="chapter">
<a href="ch08.html">8. Git automatisieren</a>
</span>
</dt>
<dd>
<dl>
<dt>
<span class="section">
<a href="ch08.html#sec.attributes">8.1. Git-Attribute – Dateien gesondert behandeln</a>
</span>
</dt>
<dt>
<span class="section">
<a href="ch08.html#sec.hooks">8.2. Hooks</a>
</span>
</dt>
<dt>
<span class="section">
<a href="ch08.html#sec.scripting">8.3. Eigene Git-Kommandos schreiben</a>
</span>
</dt>
<dt>
<span class="section">
<a href="ch08.html#sec.filter-branch">8.4. Versionsgeschichte umschreiben</a>
</span>
</dt>
</dl>
</dd>
<dt>
<span class="chapter">
<a href="ch09.html">9. Zusammenspiel mit anderen Versionsverwaltungssystemen</a>
</span>
</dt>
<dd>
<dl>
<dt>
<span class="section">
<a href="ch09.html#sec.subversion">9.1. Subversion</a>
</span>
</dt>
<dt>
<span class="section">
<a href="ch09.html#sec.fast-import">9.2. Eigene Importer</a>
</span>
</dt>
</dl>
</dd>
<dt>
<span class="chapter">
<a href="ch10.html">10. Shell-Integration</a>
</span>
</dt>
<dd>
<dl>
<dt>
<span class="section">
<a href="ch10.html#sec.bash-integration">10.1. Git und die Bash</a>
</span>
</dt>
<dt>
<span class="section">
<a href="ch10.html#sec.zsh-integration">10.2. Git und die Z-Shell</a>
</span>
</dt>
</dl>
</dd>
<dt>
<span class="chapter">
<a href="ch11.html">11. Github</a>
</span>
</dt>
<dt>
<span class="appendix">
<a href="apa.html">A. Installation</a>
</span>
</dt>
<dd>
<dl>
<dt>
<span class="section">
<a href="apa.html#linux">A.1. Linux</a>
</span>
</dt>
<dt>
<span class="section">
<a href="apa.html#sec.osx">A.2. Mac OS X</a>
</span>
</dt>
<dt>
<span class="section">
<a href="apa.html#sec.windows">A.3. Windows</a>
</span>
</dt>
</dl>
</dd>
<dt>
<span class="appendix">
<a href="apb.html">B. Struktur eines Repositorys</a>
</span>
</dt>
<dd>
<dl>
<dt>
<span class="section">
<a href="apb.html#sec.gc">B.1. Aufräumen</a>
</span>
</dt>
<dt>
<span class="section">
<a href="apb.html#sec.gc-performance">B.2. Performance</a>
</span>
</dt>
</dl>
</dd>
</dl></div>
<div class="navheader">
<table width="100%" summary="Navigation header">
<tr>
<td width="20%" align="left"><a accesskey="p" href="ch02.html">Zurück</a> </td>
<th width="60%" align="center"> </th>
<td width="20%" align="right"> <a accesskey="n" href="ch04.html">Weiter</a></td>
</tr>
</table>
<hr />
</div>
<div class="chapter">
<div class="titlepage">
<div>
<div>
<h1 class="title"><a id="chap.praxis"></a>Kapitel 3. Praktische Versionsverwaltung</h1>
</div>
</div>
</div>
<p>Das folgende Kapitel stellt alle wesentlichen Techniken vor, die Sie
im täglichen Umgang mit Git einsetzen werden. Neben einer
genaueren Beschreibung des Index und wie man alte Versionen
wiederherstellt, liegt der Fokus auf der effektiven Arbeit mit
Branches.</p>
<div class="section">
<div class="titlepage">
<div>
<div>
<h2 class="title" style="clear: both"><a id="sec.branches"></a>3.1. Referenzen: Branches und Tags</h2>
</div>
</div>
</div>
<p>„Branch“ und „Merge“ sind im CVS-/SVN-Umfeld für
Neulinge oft ein Buch mit sieben Siegeln, für Könner regelmäßig Grund
zum Haare raufen. In Git sind das Abzweigen im Entwicklungszyklus
(<span class="emphasis"><em>Branching</em></span>) und das anschließende Wiederzusammenführen
(<span class="emphasis"><em>Merging</em></span>) alltäglich, einfach, transparent und schnell. Es
kommt häufig vor, dass ein Entwickler an einem Tag mehrere Branches
erstellt und mehrere Merges durchführt.</p>
<p>Das Tool Gitk ist hilfreich, um bei mehreren Branches nicht den
Überblick zu verlieren. Mit
<code class="literal">gitk --all</code> zeigen Sie alle Branches an. Das Tool visualisiert den im vorigen Abschnitt
erläuterten Commit-Graphen. Jeder Commit stellt eine Zeile dar.
Branches werden als grüne Labels, Tags als gelbe Zeiger dargestellt.
Für weitere Informationen siehe <a class="xref" href="ch03.html#sec.gitk" title="3.6.2. Gitk">Abschnitt 3.6.2, „Gitk“</a>.</p>
<div class="figure">
<a id="fig.gitk-basic"></a>
<p class="title">
<strong>Abbildung 3.1. Das Beispiel-Repository aus <a class="xref" href="ch02.html" title="Kapitel 2. Grundlagen">Kapitel 2, <em>Grundlagen</em></a> in Gitk. Zur Illustration wurde der zweite Commit mit dem Tag <code class="literal">v0.1</code> versehen.</strong>
</p>
<div class="figure-contents">
<div class="mediaobject">
<img src="bilder_ebook/gitk-basic.png" width="486" alt="bilder_ebook/gitk-basic.png" />
</div>
</div>
</div>
<br class="figure-break" />
<p>Da Branches in Git „billig“ und Merges einfach sind, können
Sie es sich leisten, Branches exzessiv zu verwenden. Sie wollen etwas
probieren, einen kleinen Bugfix vorbereiten oder mit einem
experimentellen Feature beginnen? Für all das erstellen Sie jeweils
einen neuen Branch. Sie wollen testen, ob sich ein Branch mit dem
anderen verträgt? Führen Sie die beiden zusammen, testen Sie alles,
und löschen Sie danach den Merge wieder und entwickeln weiter. Das
ist gängige Praxis unter Entwicklern, die Git einsetzen.</p>
<p>Zunächst wollen wir uns mit Referenzen generell auseinandersetzen.
Referenzen sind nichts weiter als symbolische Namen für die schwierig
zu merkenden SHA-1-Summen von Commits.</p>
<p>Diese Referenzen liegen in <code class="literal">.git/refs/</code>. Der Name einer
Referenz wird anhand des Dateinamens, das Ziel anhand des Inhalts der
Datei bestimmt. Der Master-Branch, auf dem Sie schon die ganze Zeit
arbeiten, sieht darin zum Beispiel so aus:</p>
<pre class="screen">$ <span class="strong"><strong>cat .git/refs/heads/master</strong></span>
89062b72afccda5b9e8ed77bf82c38577e603251</pre>
<div class="tip" style="margin-left: 0; margin-right: 10%;">
<h3 class="title">Tipp</h3>
<p>Wenn Git sehr viele Referenzen verwalten muss, liegen diese nicht
zwingend als Dateien unterhalb von <code class="literal">.git/refs/</code>. Git erstellt
dann stattdessen einen Container, der <span class="emphasis"><em>gepackte Referenzen</em></span> (<span class="emphasis"><em>Packed
Refs</em></span>) enthält: Eine Zeile pro Referenz mit Name und SHA-1-Summe. Das
sequentielle Auflösen vieler Referenzen geht dann schneller.
Git-Kommandos suchen Branches und Tags in der Datei <code class="literal">.git/packed-refs</code>, wenn die entsprechende Datei
<code class="literal">.git/refs/<name></code> nicht existiert.</p>
</div>
<p>Unterhalb von <code class="literal">.git/refs/</code> gibt es verschiedene Verzeichnisse,
die für die „Art“ von Referenz stehen. Fundamental
unterscheiden sich diese Referenzen aber nicht, lediglich darin, wann
und wie sie angewendet werden. Die Referenzen, die Sie am häufigsten
verwenden werden, sind Branches. Sie sind unter <code class="literal">.git/refs/heads/</code> gespeichert. <span class="emphasis"><em>Heads</em></span> bezeichnet das,
was in anderen Systemen zuweilen auch „Tip“ genannt wird:
Den neuesten Commit auf einem Entwicklungsstrang.<a href="#ftn.idm45240359203264" class="footnote" id="idm45240359203264"><sup class="footnote">[29]</sup></a> Branches rücken weiter, wenn Sie
Commits auf einem Branch erstellen – sie bleiben also an der Spitze
der Versionsgeschichte.</p>
<div class="figure">
<a id="fig.commit"></a>
<p class="title">
<strong>Abbildung 3.2. Der Branch referenziert immer den aktuellsten Commit</strong>
</p>
<div class="figure-contents">
<div class="mediaobject">
<img src="bilder_ebook/commit.png" width="432" alt="bilder_ebook/commit.png" />
</div>
</div>
</div>
<br class="figure-break" />
<p>Branches in Repositories anderer Entwickler (z.B. der Master-Branch
des offiziellen Repositorys), sog.
Remote-Tracking-Branches, werden unter <code class="literal">.git/refs/remotes/</code> abgelegt (siehe <a class="xref" href="ch05.html#sec.remote_tracking_branches" title="5.2.2. Remote-Tracking-Branches">Abschnitt 5.2.2, „Remote-Tracking-Branches“</a>). Tags, statische
Referenzen, die meist der Versionierung dienen, liegen unter <code class="literal">.git/refs/tags/</code> (siehe <a class="xref" href="ch03.html#sec.tags" title="3.1.3. Tags – Wichtige Versionen markieren">Abschnitt 3.1.3, „Tags – Wichtige Versionen markieren“</a>).</p>
<div class="section">
<div class="titlepage">
<div>
<div>
<h3 class="title"><a id="sec.branch-refs"></a>3.1.1. HEAD und andere symbolische Referenzen</h3>
</div>
</div>
</div>
<p>Eine Referenz, die Sie selten explizit, aber ständig implizit
benutzen, ist <code class="literal">HEAD</code>. Sie referenziert meist den gerade
ausgecheckten Branch, hier <code class="literal">master</code>:</p>
<pre class="screen">$ <span class="strong"><strong>cat .git/HEAD</strong></span>
ref: refs/heads/master</pre>
<p><code class="literal">HEAD</code> kann auch direkt auf einen Commit zeigen, wenn Sie
<code class="literal">git checkout <commit-id></code> eingeben. Sie sind dann
allerdings im sogenannten <span class="emphasis"><em>Detached-Head</em></span>-Modus, in dem Commits
möglicherweise verlorengehen, siehe auch
<a class="xref" href="ch03.html#sec.detached-head" title="3.2.1. Detached HEAD">Abschnitt 3.2.1, „Detached HEAD“</a>.</p>
<p>Der <code class="literal">HEAD</code> bestimmt, welche Dateien im Working Tree zu finden
sind, welcher Commit Vorgänger bei der Erstellung eines neuen wird,
welcher Commit per <code class="literal">git show</code> angezeigt wird etc. Wenn wir
hier von „dem aktuellen Branch“ sprechen, dann ist damit
technisch korrekt der <code class="literal">HEAD</code> gemeint.</p>
<p>Die simplen Kommandos <code class="literal">log</code>, <code class="literal">show</code> und <code class="literal">diff</code>
nehmen ohne weitere Argumente <code class="literal">HEAD</code> als erstes Argument an.
Die Ausgabe von <code class="literal">git log</code> ist gleich der von <code class="literal">git log HEAD</code> usw. – dies gilt für die meisten Kommandos, die auf einem
Commit operieren, wenn Sie keinen explizit angeben. <code class="literal">HEAD</code> ist
somit vergleichbar mit der Shell-Variable <code class="literal">PWD</code>, die angibt
„wo man ist“.</p>
<p>Wenn wir von einem Commit sprechen, dann ist es einem Kommando in der
Regel egal, ob man die Commit-ID komplett oder verkürzt angibt oder
den Commit über eine Referenz, wie z.B. ein Tag oder Branch,
ansteuert. Eine solche Referenz muss aber nicht immer eindeutig sein.
Was passiert, wenn es einen Branch <code class="literal">master</code> gibt und ein Tag
gleichen Namens? Git überprüft, ob die folgenden Referenzen
existieren:</p>
<div class="itemizedlist">
<ul class="itemizedlist" style="list-style-type: disc; ">
<li class="listitem">
<code class="literal">.git/<name></code> (meist nur sinnvoll für <code class="literal">HEAD</code> o.ä.)
</li>
<li class="listitem">
<code class="literal">.git/refs/<name></code>
</li>
<li class="listitem">
<code class="literal">.git/refs/tags/<name></code>
</li>
<li class="listitem">
<code class="literal">.git/refs/heads/<name></code>
</li>
<li class="listitem">
<code class="literal">.git/refs/remotes/<name></code>
</li>
<li class="listitem">
<code class="literal">.git/refs/remotes/<name>/HEAD</code>
</li>
</ul>
</div>
<p>Die erste gefundene Referenz nimmt Git als Treffer an. Sie sollten
also Tags immer ein eindeutiges Schema geben, um sie nicht mit
Branches zu verwechseln. So können Sie Branches direkt über den Namen
statt über <code class="literal">heads/<name></code> ansprechen.</p>
<p>Besonders wichtig sind dafür die Suffixe <code class="literal">^</code> und <code class="literal">~<n></code>. Die Syntax
<code class="literal"><ref>^</code> bezeichnet den direkten Vorfahren von <code class="literal"><ref></code>. Dieser muss
aber nicht immer eindeutig sein: Wenn zwei oder mehr Branches
zusammengeführt wurden, hat der Merge-Commit mehrere direkte
Vorfahren. <code class="literal"><ref>^</code> bzw. <code class="literal"><ref>^1</code> bezeichnen dann den ersten
<span class="emphasis"><em>direkten</em></span> Vorfahren, <code class="literal"><ref>^2</code> den zweiten usw.<a href="#ftn.idm45240359162272" class="footnote" id="idm45240359162272"><sup class="footnote">[30]</sup></a> Die Syntax <code class="literal">HEAD^^</code> bedeutet also „der zwei
Ebenen vorher liegende direkte Vorfahre des aktuellen
Commits“. Achten Sie darauf, dass <code class="literal">^</code> in Ihrer Shell möglicherweise
eine spezielle Bedeutung hat und Sie es durch Anführungszeichen oder
mit einem Backslash schützen müssen.</p>
<div class="figure">
<a id="fig.relative-refs"></a>
<p class="title">
<strong>Abbildung 3.3. Relative-Referenzen, <code class="literal">^</code> und <code class="literal">~<n></code></strong>
</p>
<div class="figure-contents">
<div class="mediaobject">
<img src="bilder_ebook/relative-refs.png" width="351" alt="bilder_ebook/relative-refs.png" />
</div>
</div>
</div>
<br class="figure-break" />
<p>Die Syntax <code class="literal"><ref>~<n></code> kommt einer
<span class="emphasis"><em>n</em></span>-fachen Wiederholung von <code class="literal">^</code> gleich:
<code class="literal">HEAD~10</code> bezeichnet also den zehnten direkten
Vorgänger des aktuellen Commits. Achtung: Das heißt nicht, dass
zwischen <code class="literal">HEAD</code> und <code class="literal">HEAD~10</code> nur elf
Commits liegen: Da <code class="literal">^</code> bei einem etwaigen Merge nur dem
ersten Strang folgt, liegen zwischen den beiden Referenzen die elf
und alle durch einen Merge integrierten weiteren Commits.
Die Syntax ist übrigens in der Man-Page <code class="literal">git-rev-parse(1)</code> im Abschnitt
„Specifying Revisions“ dokumentiert.</p>
</div>
<div class="section">
<div class="titlepage">
<div>
<div>
<h3 class="title"><a id="sec.branch-management"></a>3.1.2. Branches verwalten</h3>
</div>
</div>
</div>
<p>Ein Branch ist in Git im Nu erstellt. Git muss lediglich den aktuell
ausgecheckten Commit identifizieren und die SHA-1-Summe in der Datei
<code class="literal">.git/refs/heads/<branch-name></code> ablegen.</p>
<pre class="screen">$ <span class="strong"><strong>time git branch neuer-branch</strong></span>
git branch neuer-branch 0.00s user 0.00s system 100% cpu 0.008 total</pre>
<p>Das Kommando ist so schnell, weil (im Gegensatz zu anderen Systemen)
keine Dateien kopiert und keine weiteren Metadaten abgelegt werden
müssen. Informationen über die Struktur der Versionsgeschichte sind
immer aus dem Commit, den ein Branch referenziert, und seinen
Vorfahren ableitbar.</p>
<p>Hier eine Übersicht der wichtigsten Optionen:</p>
<div class="variablelist">
<dl class="variablelist">
<dt>
<span class="term">
<code class="literal">git branch [-v]</code>
</span>
</dt>
<dd>
<p class="simpara">
Listet lokale Branches auf.
Dabei ist der aktuell ausgecheckte Branch mit einem Sternchen
markiert. Mit <code class="literal">-v</code> werden außerdem die Commit-IDs, auf die
die Branches zeigen, sowie die erste Zeile der Beschreibung der
entsprechenden Commits angezeigt.
</p>
<pre class="screen">$ <span class="strong"><strong>git branch -v</strong></span>
maint 65f13f2 Start 1.7.5.1 maintenance track
* master 791a765 Update draft release notes to 1.7.6
next b503560 Merge branch 'master' into next
pu d7a491c Merge branch 'js/info-man-path' into pu</pre>
</dd>
<dt>
<span class="term">
<code class="literal">git branch <branch> [<ref>]</code>
</span>
</dt>
<dd>
Erstellt einen neuen
Branch <code class="literal"><branch></code>, der auf Commit <code class="literal"><ref></code> zeigt
(<code class="literal"><ref></code> kann die SHA-1-Summe eines Commits sein, ein
anderer Branch usw.). Wenn Sie keine Referenz
angeben, ist dies <code class="literal">HEAD</code>, der aktuelle Branch.
</dd>
<dt>
<span class="term">
<code class="literal">git branch -m <neuer-name></code>
</span>
</dt>
<dd>
<p class="simpara">
<code class="literal">git branch -m <alter-name> <neuer-name></code>
</p>
<p class="simpara">In der ersten Form
wird der aktuelle Branch in <code class="literal"><neuer-name></code> umbenannt.
In der zweiten Form wird <code class="literal"><alter-name></code> in
<code class="literal"><neuer-name></code> umbenannt. Das Kommando schlägt fehl,
wenn dadurch ein anderer Branch überschrieben würde.</p>
<pre class="screen">$ <span class="strong"><strong>git branch -m master</strong></span>
fatal: A branch named 'master' already exists.</pre>
<p class="simpara">Wenn Sie einen Branch umbenennen, gibt Git keine Meldung aus. Sie können
also hinterher überprüfen, dass die Umbenennung erfolgreich war:</p>
<pre class="screen">$ <span class="strong"><strong>git branch</strong></span>
* master
test
$ <span class="strong"><strong>git branch -m test pu/feature</strong></span>
$ <span class="strong"><strong>git branch</strong></span>
* master
pu/feature</pre>
</dd>
<dt>
<span class="term">
<code class="literal">git branch -M ...</code>
</span>
</dt>
<dd>
Wie <code class="literal">-m</code>, nur dass
ein Branch auch umbenannt wird, wenn dadurch ein anderer
überschrieben wird. Achtung: Dabei können Commits des
überschriebenen Branches verlorengehen!
</dd>
<dt>
<span class="term">
<code class="literal">git branch -d <branch></code>
</span>
</dt>
<dd>
Löscht
<code class="literal"><branch></code>. Sie können mehrere Branches gleichzeitig
angeben. Git weigert sich, einen Branch zu löschen,
wenn er noch nicht komplett in seinen Upstream-Branch, oder, falls
dieser nicht existiert, in <code class="literal">HEAD</code>, also den aktuellen Branch,
integriert ist. (Mehr über Upstream-Branches finden Sie in
<a class="xref" href="ch05.html#sec.pull" title="5.3.2. git pull">Abschnitt 5.3.2, „git pull“</a>.)
</dd>
<dt>
<span class="term">
<code class="literal">git branch -D ...</code>
</span>
</dt>
<dd>
Löscht einen Branch, auch wenn
er Commits enthält, die noch nicht in den Upstream- oder aktuellen Branch
integriert wurden. Achtung: Diese Commits können möglicherweise
verlorengehen, wenn sie nicht anders referenziert werden.
</dd>
</dl>
</div>
<div class="section">
<div class="titlepage">
<div>
<div>
<h4 class="title"><a id="sec.branch-checkout"></a>Branches wechseln: checkout</h4>
</div>
</div>
</div>
<p>Branches wechseln Sie mit <code class="literal">git checkout <branch></code>. Wenn Sie
einen Branch erstellen und direkt darauf wechseln
wollen, verwenden Sie <code class="literal">git checkout -b <branch></code>. Das Kommando
ist äquivalent zu <code class="literal">git branch <branch> && git checkout
<branch></code>.</p>
<p>Was passiert bei einem Checkout? Jeder Branch referenziert einen
Commit, der wiederum einen Tree referenziert, also das Abbild einer
Verzeichnisstruktur. Ein <code class="literal">git checkout <branch></code> löst nun die
Referenz <code class="literal"><branch></code> auf einen Commit auf und repliziert den
Tree des Commits auf den Index und auf den Working Tree (d.h. auf
das Dateisystem).</p>
<p>Da Git weiß, in welcher Version Dateien aktuell in Index und Working
Tree vorliegen, müssen nur die Dateien, die sich auf dem aktuellen und
dem neuen Branch unterscheiden, ausgecheckt werden.</p>
<p>Git macht es Anwendern schwer, Informationen zu verlieren. Daher
wird ein Checkout eher fehlschlagen als eventuell nicht abgespeicherte
Änderungen in einer Datei überschreiben. Das passiert in den folgenden
beiden Fällen:</p>
<div class="itemizedlist">
<ul class="itemizedlist" style="list-style-type: disc; ">
<li class="listitem">
Der Checkout würde eine Datei im Working Tree
überschreiben, in der sich Änderungen befinden. Git gibt folgende
Fehlermeldung aus: <code class="literal">error: Your local changes to the following files
would be overwritten by checkout: datei</code>.
</li>
<li class="listitem">
Der Checkout würde eine ungetrackte Datei überschreiben,
d.h. eine Datei, die nicht von Git verwaltet wird. Git bricht dann mit
der Fehlermeldung ab: <code class="literal">error: The following untracked working tree
files would be overwritten by checkout: datei</code>.
</li>
</ul>
</div>
<p>Liegen allerdings Änderungen im Working Tree oder Index vor, die mit
beiden Branches verträglich sind, übernimmt ein Checkout diese
Änderungen. Das sieht dann z.B. so aus:</p>
<pre class="screen">$ <span class="strong"><strong>git checkout master</strong></span>
A neue-datei.txt
Switched to branch <span class="emphasis"><em>master</em></span></pre>
<p>Das bedeutet, dass die Datei <code class="literal">neue-datei.txt</code> hinzugefügt
wurde, die auf keinem der beiden Branches existiert. Da hier also
keine Informationen verlorengehen können, wird die Datei einfach
übernommen. Die Meldung: <code class="literal">A neue-datei.txt</code> erinnert Sie, um
welche Dateien Sie sich noch kümmern sollten. Dabei steht <code class="literal">A</code>
für hinzugefügt (<span class="emphasis"><em>added</em></span>), <code class="literal">D</code> für gelöscht (<span class="emphasis"><em>deleted</em></span>)
und <code class="literal">M</code> für geändert (<span class="emphasis"><em>modified</em></span>).</p>
<p>Wenn Sie ganz sicher sind, dass Sie Ihre Änderungen nicht mehr
brauchen, können Sie per <code class="literal">git checkout -f</code> die Fehlermeldungen
ignorieren und den Checkout trotzdem ausführen.</p>
<p>Wenn Sie sowohl die Änderungen behalten als auch den Branch wechseln
wollen (Beispiel: Arbeit unterbrechen und auf einem anderen Branch
einen Fehler korrigieren), dann hilft <code class="literal">git stash</code> (<a class="xref" href="ch04.html#sec.stash" title="4.5. Veränderungen auslagern – git stash">Abschnitt 4.5, „Veränderungen auslagern – git stash“</a>).</p>
</div>
<div class="section">
<div class="titlepage">
<div>
<div>
<h4 class="title"><a id="sec.branch-naming"></a>Konventionen zur Benennung von Branches</h4>
</div>
</div>
</div>
<p>Sie können Branches prinzipiell fast beliebig benennen. Ausnahmen sind
aber Leerzeichen, einige Sonderzeichen mit spezieller Bedeutung für Git
(z.B. <code class="literal">*</code>, <code class="literal">^</code>, <code class="literal">:</code>, <code class="literal">~</code>), sowie zwei aufeinanderfolgende Punkte
(<code class="literal">..</code>) oder ein Punkt am Anfang des Namens.<a href="#ftn.idm45240359083648" class="footnote" id="idm45240359083648"><sup class="footnote">[31]</sup></a></p>
<p>Sinnvollerweise sollten Sie Branch-Namen immer komplett in
Kleinbuchstaben angeben. Da Git Branch-Namen unter
<code class="literal">.git/refs/heads/</code> als Dateien verwaltet, ist die Groß- und
Kleinschreibung wesentlich.</p>
<p>Sie können Branches in „Namespaces“ gruppieren, indem Sie
als Separator einen <code class="literal">/</code> verwenden. Branches, die mit der
Übersetzung einer Software zu tun haben, können Sie dann z.B. <code class="literal">i18n/german</code>, <code class="literal">i18n/english</code> etc. nennen. Auch können
Sie, wenn sich mehrere Entwickler ein Repository teilen,
„private“ Branches unter <code class="literal"><username>/<topic></code>
anlegen. Diese Namespaces werden durch eine Verzeichnisstruktur
abgebildet, so dass dann unter <code class="literal">.git/refs/heads/</code> ein
Verzeichnis <code class="literal"><username>/</code> mit der Branch-Datei <code class="literal"><topic></code>
erstellt wird.</p>
<p>Der Hauptentwicklungszweig Ihres Projekts sollte immer <code class="literal">master</code>
heißen. Bugfixes werden häufig auf einem Branch <code class="literal">maint</code> (kurz
für „maintenance“) verwaltet. Das nächste Release wird
meist auf <code class="literal">next</code> vorbereitet. Features, die sich noch in einem
experimentellen Zustand befinden, sollten in <code class="literal">pu</code> (für
„proposed updates“) entwickelt werden oder in
<code class="literal">pu/<feature></code>. Eine detailliertere Beschreibung, wie Sie mit
Branches die Entwicklung strukturieren und Release-Zyklen
organisieren, finden Sie in <a class="xref" href="ch06.html" title="Kapitel 6. Workflows">Kapitel 6, <em>Workflows</em></a> über Workflows.</p>
</div>
<div class="section">
<div class="titlepage">
<div>
<div>
<h4 class="title"><a id="sec.no-ref-commits"></a>Gelöschte Branches und „verlorene“ Commits</h4>
</div>
</div>
</div>
<p>Commits kennen jeweils einen oder mehrere Vorgänger. Daher kann man
den Commit-Graphen „gerichtet“, d.h. von neueren zu
älteren Commits, durchlaufen, bis man an einem Wurzel-Commit ankommt.</p>
<p>Andersherum geht das nicht: Wenn ein Commit seinen Nachfolger kennen
würde, müsste diese Version irgendwo gespeichert werden. Dadurch würde
sich die SHA-1-Summe des Commits ändern, worauf der Nachfolger den
entsprechend neuen Commit referenzieren müsste, dadurch eine neue
SHA-1-Summe erhielte, so dass wiederum der Vorgänger geändert werden
müsste usw. Git kann also die Commits nur von einer benannten
Referenz aus (z.B. ein Branch oder <code class="literal">HEAD</code>) in Richtung
früherer Commits durchgehen.</p>
<p>Wenn daher die „Spitze“ eines Branches gelöscht wird, wird
der oberste Commit nicht mehr referenziert (im Git-Jargon:
<span class="emphasis"><em>unreachable</em></span>). Dadurch wird der Vorgänger nicht mehr
referenziert usw. – bis der nächste Commit auftaucht, der irgendwie
referenziert wird (sei es von einem Branch oder dadurch, dass er einen
Nachfolger hat, der wiederum von einem Branch referenziert wird).</p>
<p>Wenn Sie einen Branch löschen, werden die Commits auf diesem Branch
also nicht gelöscht, sie gehen nur „verloren“. Git findet
sie einfach nicht mehr.</p>
<p>In der Objektdatenbank sind sie allerdings noch eine Weile lang
vorhanden.<a href="#ftn.idm45240359063760" class="footnote" id="idm45240359063760"><sup class="footnote">[32]</sup></a> Sie können also
einen Branch ohne weiteres wiederherstellen, indem Sie den vorherigen
(und vermeintlich gelöschten) Commit explizit als Referenz angeben:</p>
<pre class="screen">$ <span class="strong"><strong>git branch -D test</strong></span>
Deleted branch test (was e32bf29).
$ <span class="strong"><strong>git branch test e32bf29</strong></span></pre>
<p>Eine weitere Möglichkeit, gelöschte Commits wiederzufinden, ist das
<span class="emphasis"><em>Reflog</em></span> (siehe dafür <a class="xref" href="ch03.html#sec.reflog" title="3.7. Reflog">Abschnitt 3.7, „Reflog“</a>).</p>
</div>
</div>
<div class="section">
<div class="titlepage">
<div>
<div>
<h3 class="title"><a id="sec.tags"></a>3.1.3. Tags – Wichtige Versionen markieren</h3>
</div>
</div>
</div>
<p>SHA-1-Summen sind zwar eine sehr elegante Lösung, um Versionen
dezentral zu beschreiben, aber semantikarm und für Menschen
unhandlich. Im Gegensatz zu linearen Revisionsnummern sagen uns
Commit-IDs allein nichts über die Reihenfolge der Versionen.</p>
<p>Während der Entwicklung von Softwareprojekten müssen
verschiedene „wichtige“ Versionen so markiert
werden, dass sie leicht in dem Repository zu finden sind. Die
wichtigsten sind meist solche, die veröffentlicht werden, die
sogenannten <span class="emphasis"><em>Releases</em></span>. Auch <span class="emphasis"><em>Release Candidates</em></span> werden
häufig auf diese Weise markiert, also Versionen, die die Basis für die
nächste Version bilden und im Zuge der Qualitätssicherung auf
kritische Fehler untersucht werden, ohne dass neue Features
hinzugefügt werden. Je nach Projekt und Entwicklungsmodell gibt es
verschiedene Konventionen, um Releases zu bezeichnen, und Abläufe, wie
sie vorbereitet und publiziert werden.</p>
<p>Im Open-Source-Bereich haben sich zwei Versionierungsschemata
durchgesetzt: die klassische <span class="emphasis"><em>Major/Minor/Micro-Versionierung</em></span>
und neuerdings auch die <span class="emphasis"><em>datumsbasierte Versionierung</em></span>. Bei der
Major/Minor/Micro-Versionierung, welche z.B. beim Linux-Kernel und
auch Git eingesetzt wird, ist eine Version durch drei (oft auch vier)
Zahlen gekennzeichnet: <code class="literal">2.6.39</code> oder <code class="literal">1.7.1</code>. Bei der
datumsbasierten Versionierung hingegen ist die Bezeichnung aus dem
Zeitpunkt des Releases abgeleitet, z.B.: <code class="literal">2011.05</code> oder
<code class="literal">2011-05-19</code>. Das hat den großen Vorteil, dass das Alter einer
Version leicht ersichtlich ist.<a href="#ftn.idm45240359049680" class="footnote" id="idm45240359049680"><sup class="footnote">[33]</sup></a></p>
<p>Git bietet Ihnen mit <span class="emphasis"><em>Tags</em></span> („Etiketten“) die Möglichkeit,
beliebige Git-Objekte – meist Commits – zu markieren, um markante
Zustände in der Entwicklungsgeschichte hervorzuheben. Tags sind, wie
Branches auch, als Referenzen auf Objekte implementiert. Im Gegensatz
zu Branches jedoch sind Tags statisch, das heißt, sie werden nicht
verschoben, wenn neue Commits hinzukommen, und zeigen stets auf
dasselbe Objekt. Es gibt zwei Arten von Tags: <span class="emphasis"><em>Annotated</em></span> (mit
Anmerkungen versehen) und <span class="emphasis"><em>Lightweight</em></span>
(„leichtgewichtig“, d.h. ohne Anmerkungen). Annotated
Tags sind mit Metadaten – z.B. Autor, Beschreibung oder
GPG-Signatur – versehen. Lightweight Tags zeigen hingegen
„einfach nur“ auf ein bestimmtes Git-Objekt. Für beide Arten
von Tags legt Git unter <code class="literal">.git/refs/tags/</code> bzw.
<code class="literal">.git/packed-refs</code> Referenzen an. Der Unterschied ist,
dass Git für jedes Annotated Tag ein spezielles Git-Objekt – und zwar
ein <span class="emphasis"><em>Tag-Objekt</em></span> – in der Objektdatenbank anlegt, um die
Metadaten sowie die SHA-1-Summe des markierten Objekts zu speichern,
während ein Lightweight Tag direkt auf das markierte Objekt zeigt.
<a class="xref" href="ch03.html#fig.tag-objekt" title="Abbildung 3.4. Das Tag-Objekt">Abbildung 3.4, „Das Tag-Objekt“</a> zeigt den Inhalt eines Tag-Objekts;
vergleichen Sie auch die anderen Git-Objekte, <a class="xref" href="ch02.html#fig.objekte" title="Abbildung 2.4. Git-Objekte">Abbildung 2.4, „Git-Objekte“</a>.</p>
<div class="figure">
<a id="fig.tag-objekt"></a>
<p class="title">
<strong>Abbildung 3.4. Das Tag-Objekt</strong>
</p>
<div class="figure-contents">
<div class="mediaobject">
<img src="bilder_ebook/tags.png" width="486" alt="bilder_ebook/tags.png" />
</div>
</div>
</div>
<br class="figure-break" />
<p>Das gezeigte Tag-Objekt hat sowohl eine Größe (158 Byte) als auch eine
SHA-1-Summe. Es enthält die Bezeichnung (<code class="literal">0.1</code>), den Objekt-Typ
und die SHA-1-Summe des referenzierten Objekts sowie den Namen und
E-Mail des Autors, der im Git-Jargon <span class="emphasis"><em>Tagger</em></span> heißt. Außerdem
enthält das Tag eine Tag-Message, die zum Beispiel die Version beschreibt,
sowie optional eine GPG-Signatur. Im Git-Projekt etwa besteht eine Tag-Message
aus der aktuellen Versionsbezeichnung und der Signatur des
Maintainers.</p>
<p>Schauen wir im Folgenden zunächst, wie Sie Tags lokal verwalten. Wie
Sie Tags zwischen Repositories austauschen, beschreibt <a class="xref" href="ch05.html#sec.remote-tags" title="5.8. Tags austauschen">Abschnitt 5.8, „Tags austauschen“</a>.</p>
<div class="section">
<div class="titlepage">
<div>
<div>
<h4 class="title"><a id="sec.tags-verwalten"></a>Tags verwalten</h4>
</div>
</div>
</div>
<p>Tags verwalten Sie mit dem Kommando <code class="literal">git tag</code>. Ohne Argumente
zeigt es alle vorhandenen Tags an. Je nach Projektgröße lohnt es sich,
die Ausgabe mit der Option <code class="literal">-l</code> und einem entsprechenden Muster
einzuschränken. Mit folgendem Befehl zeigen Sie alle Varianten der
Version <code class="literal">1.7.1</code> des Git-Projekts an, also sowohl die
Release-Candidates mit dem Zusatz <code class="literal">-rc*</code> sowie die
(vierstelligen) Maintenance-Releases:</p>
<pre class="screen">$ <span class="strong"><strong>git tag -l v1.7.1*</strong></span>
v1.7.1
v1.7.1-rc0
v1.7.1-rc1
v1.7.1-rc2