2 <html xmlns=
"http://www.w3.org/1999/xhtml" lang=
"en">
4 <meta charset=
"UTF-8"/>
5 <meta http-equiv=
"X-UA-Compatible" content=
"IE=edge"/>
6 <meta name=
"viewport" content=
"width=device-width, initial-scale=1.0"/>
7 <meta name=
"generator" content=
"Asciidoctor 2.0.20"/>
8 <title>My First Object Walk
</title>
9 <link rel=
"stylesheet" href=
"https://fonts.googleapis.com/css?family=Open+Sans:300,300italic,400,400italic,600,600italic%7CNoto+Serif:400,400italic,700,700italic%7CDroid+Sans+Mono:400,700"/>
11 /*! Asciidoctor default stylesheet | MIT License | https://asciidoctor.org */
12 /* Uncomment the following line when using as a custom stylesheet */
13 /* @import
"https://fonts.googleapis.com/css?family=Open+Sans:300,300italic,400,400italic,600,600italic%7CNoto+Serif:400,400italic,700,700italic%7CDroid+Sans+Mono:400,700"; */
14 html{font-family:sans-serif;-webkit-text-size-adjust:
100%}
16 a:focus{outline:thin dotted}
17 a:active,a:hover{outline:
0}
18 h1{font-size:
2em;margin:
.67em
0}
19 b,strong{font-weight:bold}
21 abbr[title]{cursor:help;border-bottom:
1px dotted #dddddf;text-decoration:none}
22 dfn{font-style:italic}
24 mark{background:#ff0;color:#
000}
25 code,kbd,pre,samp{font-family:monospace;font-size:
1em}
26 pre{white-space:pre-wrap}
27 q{quotes:
"\201C" "\201D" "\2018" "\2019"}
29 sub,sup{font-size:
75%;line-height:
0;position:relative;vertical-align:baseline}
33 svg:not(:root){overflow:hidden}
35 audio,video{display:inline-block}
36 audio:not([controls]){display:none;height:
0}
37 fieldset{border:
1px solid silver;margin:
0 2px;padding:
.35em
.625em
.75em}
38 legend{border:
0;padding:
0}
39 button,input,select,textarea{font-family:inherit;font-size:
100%;margin:
0}
40 button,input{line-height:normal}
41 button,select{text-transform:none}
42 button,html input[type=button],input[type=reset],input[type=submit]{-webkit-appearance:button;cursor:pointer}
43 button[disabled],html input[disabled]{cursor:default}
44 input[type=checkbox],input[type=radio]{padding:
0}
45 button::-moz-focus-inner,input::-moz-focus-inner{border:
0;padding:
0}
46 textarea{overflow:auto;vertical-align:top}
47 table{border-collapse:collapse;border-spacing:
0}
48 *,::before,::after{box-sizing:border-box}
49 html,body{font-size:
100%}
50 body{background:#fff;color:rgba(
0,
0,
0,
.8);padding:
0;margin:
0;font-family:
"Noto Serif",
"DejaVu Serif",serif;line-height:
1;position:relative;cursor:auto;-moz-tab-size:
4;-o-tab-size:
4;tab-size:
4;word-wrap:anywhere;-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased}
51 a:hover{cursor:pointer}
52 img,object,embed{max-width:
100%;height:auto}
53 object,embed{height:
100%}
54 img{-ms-interpolation-mode:bicubic}
55 .left{float:left!important}
56 .right{float:right!important}
57 .text-left{text-align:left!important}
58 .text-right{text-align:right!important}
59 .text-center{text-align:center!important}
60 .text-justify{text-align:justify!important}
62 img,object,svg{display:inline-block;vertical-align:middle}
63 textarea{height:auto;min-height:
50px}
65 .subheader,.admonitionblock td.content
>.title,.audioblock
>.title,.exampleblock
>.title,.imageblock
>.title,.listingblock
>.title,.literalblock
>.title,.stemblock
>.title,.openblock
>.title,.paragraph
>.title,.quoteblock
>.title,table.tableblock
>.title,.verseblock
>.title,.videoblock
>.title,.dlist
>.title,.olist
>.title,.ulist
>.title,.qlist
>.title,.hdlist
>.title{line-height:
1.45;color:#
7a2518;font-weight:
400;margin-top:
0;margin-bottom:
.25em}
66 div,dl,dt,dd,ul,ol,li,h1,h2,h3,#toctitle,.sidebarblock
>.content
>.title,h4,h5,h6,pre,form,p,blockquote,th,td{margin:
0;padding:
0}
67 a{color:#
2156a5;text-decoration:underline;line-height:inherit}
68 a:hover,a:focus{color:#
1d4b8f}
70 p{line-height:
1.6;margin-bottom:
1.25em;text-rendering:optimizeLegibility}
71 p aside{font-size:
.875em;line-height:
1.35;font-style:italic}
72 h1,h2,h3,#toctitle,.sidebarblock
>.content
>.title,h4,h5,h6{font-family:
"Open Sans",
"DejaVu Sans",sans-serif;font-weight:
300;font-style:normal;color:#ba3925;text-rendering:optimizeLegibility;margin-top:
1em;margin-bottom:
.5em;line-height:
1.0125em}
73 h1 small,h2 small,h3 small,#toctitle small,.sidebarblock
>.content
>.title small,h4 small,h5 small,h6 small{font-size:
60%;color:#e99b8f;line-height:
0}
75 h2{font-size:
1.6875em}
76 h3,#toctitle,.sidebarblock
>.content
>.title{font-size:
1.375em}
77 h4,h5{font-size:
1.125em}
79 hr{border:solid #dddddf;border-width:
1px
0 0;clear:both;margin:
1.25em
0 1.1875em}
80 em,i{font-style:italic;line-height:inherit}
81 strong,b{font-weight:bold;line-height:inherit}
82 small{font-size:
60%;line-height:inherit}
83 code{font-family:
"Droid Sans Mono",
"DejaVu Sans Mono",monospace;font-weight:
400;color:rgba(
0,
0,
0,
.9)}
84 ul,ol,dl{line-height:
1.6;margin-bottom:
1.25em;list-style-position:outside;font-family:inherit}
85 ul,ol{margin-left:
1.5em}
86 ul li ul,ul li ol{margin-left:
1.25em;margin-bottom:
0}
87 ul.circle{list-style-type:circle}
88 ul.disc{list-style-type:disc}
89 ul.square{list-style-type:square}
90 ul.circle ul:not([class]),ul.disc ul:not([class]),ul.square ul:not([class]){list-style:inherit}
91 ol li ul,ol li ol{margin-left:
1.25em;margin-bottom:
0}
92 dl dt{margin-bottom:
.3125em;font-weight:bold}
93 dl dd{margin-bottom:
1.25em}
94 blockquote{margin:
0 0 1.25em;padding:
.5625em
1.25em
0 1.1875em;border-left:
1px solid #ddd}
95 blockquote,blockquote p{line-height:
1.6;color:rgba(
0,
0,
0,
.85)}
96 @media screen and (min-width:
768px){h1,h2,h3,#toctitle,.sidebarblock
>.content
>.title,h4,h5,h6{line-height:
1.2}
98 h2{font-size:
2.3125em}
99 h3,#toctitle,.sidebarblock
>.content
>.title{font-size:
1.6875em}
100 h4{font-size:
1.4375em}}
101 table{background:#fff;margin-bottom:
1.25em;border:
1px solid #dedede;word-wrap:normal}
102 table thead,table tfoot{background:#f7f8f7}
103 table thead tr th,table thead tr td,table tfoot tr th,table tfoot tr td{padding:
.5em
.625em
.625em;font-size:inherit;color:rgba(
0,
0,
0,
.8);text-align:left}
104 table tr th,table tr td{padding:
.5625em
.625em;font-size:inherit;color:rgba(
0,
0,
0,
.8)}
105 table tr.even,table tr.alt{background:#f8f8f7}
106 table thead tr th,table tfoot tr th,table tbody tr td,table tr td,table tfoot tr td{line-height:
1.6}
107 h1,h2,h3,#toctitle,.sidebarblock
>.content
>.title,h4,h5,h6{line-height:
1.2;word-spacing:-
.05em}
108 h1 strong,h2 strong,h3 strong,#toctitle strong,.sidebarblock
>.content
>.title strong,h4 strong,h5 strong,h6 strong{font-weight:
400}
109 .center{margin-left:auto;margin-right:auto}
111 .clearfix::before,.clearfix::after,.float-group::before,.float-group::after{content:
" ";display:table}
112 .clearfix::after,.float-group::after{clear:both}
113 :not(pre).nobreak{word-wrap:normal}
114 :not(pre).nowrap{white-space:nowrap}
115 :not(pre).pre-wrap{white-space:pre-wrap}
116 :not(pre):not([class^=L])
>code{font-size:
.9375em;font-style:normal!important;letter-spacing:
0;padding:
.1em
.5ex;word-spacing:-
.15em;background:#f7f7f8;border-radius:
4px;line-height:
1.45;text-rendering:optimizeSpeed}
117 pre{color:rgba(
0,
0,
0,
.9);font-family:
"Droid Sans Mono",
"DejaVu Sans Mono",monospace;line-height:
1.45;text-rendering:optimizeSpeed}
118 pre code,pre pre{color:inherit;font-size:inherit;line-height:inherit}
119 pre
>code{display:block}
120 pre.nowrap,pre.nowrap pre{white-space:pre;word-wrap:normal}
121 em em{font-style:normal}
122 strong strong{font-weight:
400}
123 .keyseq{color:rgba(
51,
51,
51,
.8)}
124 kbd{font-family:
"Droid Sans Mono",
"DejaVu Sans Mono",monospace;display:inline-block;color:rgba(
0,
0,
0,
.8);font-size:
.65em;line-height:
1.45;background:#f7f7f7;border:
1px solid #ccc;border-radius:
3px;box-shadow:
0 1px
0 rgba(
0,
0,
0,
.2),inset
0 0 0 .1em #fff;margin:
0 .15em;padding:
.2em
.5em;vertical-align:middle;position:relative;top:-
.1em;white-space:nowrap}
125 .keyseq kbd:first-child{margin-left:
0}
126 .keyseq kbd:last-child{margin-right:
0}
127 .menuseq,.menuref{color:#
000}
128 .menuseq b:not(.caret),.menuref{font-weight:inherit}
129 .menuseq{word-spacing:-
.02em}
130 .menuseq b.caret{font-size:
1.25em;line-height:
.8}
131 .menuseq i.caret{font-weight:bold;text-align:center;width:
.45em}
132 b.button::before,b.button::after{position:relative;top:-
1px;font-weight:
400}
133 b.button::before{content:
"[";padding:
0 3px
0 2px}
134 b.button::after{content:
"]";padding:
0 2px
0 3px}
135 p a
>code:hover{color:rgba(
0,
0,
0,
.9)}
136 #header,#content,#footnotes,#footer{width:
100%;margin:
0 auto;max-width:
62.5em;*zoom:
1;position:relative;padding-left:
.9375em;padding-right:
.9375em}
137 #header::before,#header::after,#content::before,#content::after,#footnotes::before,#footnotes::after,#footer::before,#footer::after{content:
" ";display:table}
138 #header::after,#content::after,#footnotes::after,#footer::after{clear:both}
139 #content{margin-top:
1.25em}
140 #content::before{content:none}
141 #header
>h1:first-child{color:rgba(
0,
0,
0,
.85);margin-top:
2.25rem;margin-bottom:
0}
142 #header
>h1:first-child+#toc{margin-top:
8px;border-top:
1px solid #dddddf}
143 #header
>h1:only-child,body.toc2 #header
>h1:nth-last-child(
2){border-bottom:
1px solid #dddddf;padding-bottom:
8px}
144 #header .details{border-bottom:
1px solid #dddddf;line-height:
1.45;padding-top:
.25em;padding-bottom:
.25em;padding-left:
.25em;color:rgba(
0,
0,
0,
.6);display:flex;flex-flow:row wrap}
145 #header .details span:first-child{margin-left:-
.125em}
146 #header .details span.email a{color:rgba(
0,
0,
0,
.85)}
147 #header .details br{display:none}
148 #header .details br+span::before{content:
"\00a0\2013\00a0"}
149 #header .details br+span.author::before{content:
"\00a0\22c5\00a0";color:rgba(
0,
0,
0,
.85)}
150 #header .details br+span#revremark::before{content:
"\00a0|\00a0"}
151 #header #revnumber{text-transform:capitalize}
152 #header #revnumber::after{content:
"\00a0"}
153 #content
>h1:first-child:not([class]){color:rgba(
0,
0,
0,
.85);border-bottom:
1px solid #dddddf;padding-bottom:
8px;margin-top:
0;padding-top:
1rem;margin-bottom:
1.25rem}
154 #toc{border-bottom:
1px solid #e7e7e9;padding-bottom:
.5em}
155 #toc
>ul{margin-left:
.125em}
156 #toc ul.sectlevel0
>li
>a{font-style:italic}
157 #toc ul.sectlevel0 ul.sectlevel1{margin:
.5em
0}
158 #toc ul{font-family:
"Open Sans",
"DejaVu Sans",sans-serif;list-style-type:none}
159 #toc li{line-height:
1.3334;margin-top:
.3334em}
160 #toc a{text-decoration:none}
161 #toc a:active{text-decoration:underline}
162 #toctitle{color:#
7a2518;font-size:
1.2em}
163 @media screen and (min-width:
768px){#toctitle{font-size:
1.375em}
164 body.toc2{padding-left:
15em;padding-right:
0}
165 #toc.toc2{margin-top:
0!important;background:#f8f8f7;position:fixed;width:
15em;left:
0;top:
0;border-right:
1px solid #e7e7e9;border-top-width:
0!important;border-bottom-width:
0!important;z-index:
1000;padding:
1.25em
1em;height:
100%;overflow:auto}
166 #toc.toc2 #toctitle{margin-top:
0;margin-bottom:
.8rem;font-size:
1.2em}
167 #toc.toc2
>ul{font-size:
.9em;margin-bottom:
0}
168 #toc.toc2 ul ul{margin-left:
0;padding-left:
1em}
169 #toc.toc2 ul.sectlevel0 ul.sectlevel1{padding-left:
0;margin-top:
.5em;margin-bottom:
.5em}
170 body.toc2.toc-right{padding-left:
0;padding-right:
15em}
171 body.toc2.toc-right #toc.toc2{border-right-width:
0;border-left:
1px solid #e7e7e9;left:auto;right:
0}}
172 @media screen and (min-width:
1280px){body.toc2{padding-left:
20em;padding-right:
0}
173 #toc.toc2{width:
20em}
174 #toc.toc2 #toctitle{font-size:
1.375em}
175 #toc.toc2
>ul{font-size:
.95em}
176 #toc.toc2 ul ul{padding-left:
1.25em}
177 body.toc2.toc-right{padding-left:
0;padding-right:
20em}}
178 #content #toc{border:
1px solid #e0e0dc;margin-bottom:
1.25em;padding:
1.25em;background:#f8f8f7;border-radius:
4px}
179 #content #toc
>:first-child{margin-top:
0}
180 #content #toc
>:last-child{margin-bottom:
0}
181 #footer{max-width:none;background:rgba(
0,
0,
0,
.8);padding:
1.25em}
182 #footer-text{color:hsla(
0,
0%,
100%,
.8);line-height:
1.44}
183 #content{margin-bottom:
.625em}
184 .sect1{padding-bottom:
.625em}
185 @media screen and (min-width:
768px){#content{margin-bottom:
1.25em}
186 .sect1{padding-bottom:
1.25em}}
187 .sect1:last-child{padding-bottom:
0}
188 .sect1+.sect1{border-top:
1px solid #e7e7e9}
189 #content h1
>a.anchor,h2
>a.anchor,h3
>a.anchor,#toctitle
>a.anchor,.sidebarblock
>.content
>.title
>a.anchor,h4
>a.anchor,h5
>a.anchor,h6
>a.anchor{position:absolute;z-index:
1001;width:
1.5ex;margin-left:-
1.5ex;display:block;text-decoration:none!important;visibility:hidden;text-align:center;font-weight:
400}
190 #content h1
>a.anchor::before,h2
>a.anchor::before,h3
>a.anchor::before,#toctitle
>a.anchor::before,.sidebarblock
>.content
>.title
>a.anchor::before,h4
>a.anchor::before,h5
>a.anchor::before,h6
>a.anchor::before{content:
"\00A7";font-size:
.85em;display:block;padding-top:
.1em}
191 #content h1:hover
>a.anchor,#content h1
>a.anchor:hover,h2:hover
>a.anchor,h2
>a.anchor:hover,h3:hover
>a.anchor,#toctitle:hover
>a.anchor,.sidebarblock
>.content
>.title:hover
>a.anchor,h3
>a.anchor:hover,#toctitle
>a.anchor:hover,.sidebarblock
>.content
>.title
>a.anchor:hover,h4:hover
>a.anchor,h4
>a.anchor:hover,h5:hover
>a.anchor,h5
>a.anchor:hover,h6:hover
>a.anchor,h6
>a.anchor:hover{visibility:visible}
192 #content h1
>a.link,h2
>a.link,h3
>a.link,#toctitle
>a.link,.sidebarblock
>.content
>.title
>a.link,h4
>a.link,h5
>a.link,h6
>a.link{color:#ba3925;text-decoration:none}
193 #content h1
>a.link:hover,h2
>a.link:hover,h3
>a.link:hover,#toctitle
>a.link:hover,.sidebarblock
>.content
>.title
>a.link:hover,h4
>a.link:hover,h5
>a.link:hover,h6
>a.link:hover{color:#a53221}
194 details,.audioblock,.imageblock,.literalblock,.listingblock,.stemblock,.videoblock{margin-bottom:
1.25em}
195 details{margin-left:
1.25rem}
196 details
>summary{cursor:pointer;display:block;position:relative;line-height:
1.6;margin-bottom:
.625rem;outline:none;-webkit-tap-highlight-color:transparent}
197 details
>summary::-webkit-details-marker{display:none}
198 details
>summary::before{content:
"";border:solid transparent;border-left:solid;border-width:
.3em
0 .3em
.5em;position:absolute;top:
.5em;left:-
1.25rem;transform:translateX(
15%)}
199 details[open]
>summary::before{border:solid transparent;border-top:solid;border-width:
.5em
.3em
0;transform:translateY(
15%)}
200 details
>summary::after{content:
"";width:
1.25rem;height:
1em;position:absolute;top:
.3em;left:-
1.25rem}
201 .admonitionblock td.content
>.title,.audioblock
>.title,.exampleblock
>.title,.imageblock
>.title,.listingblock
>.title,.literalblock
>.title,.stemblock
>.title,.openblock
>.title,.paragraph
>.title,.quoteblock
>.title,table.tableblock
>.title,.verseblock
>.title,.videoblock
>.title,.dlist
>.title,.olist
>.title,.ulist
>.title,.qlist
>.title,.hdlist
>.title{text-rendering:optimizeLegibility;text-align:left;font-family:
"Noto Serif",
"DejaVu Serif",serif;font-size:
1rem;font-style:italic}
202 table.tableblock.fit-content
>caption.title{white-space:nowrap;width:
0}
203 .paragraph.lead
>p,#preamble
>.sectionbody
>[class=paragraph]:first-of-type p{font-size:
1.21875em;line-height:
1.6;color:rgba(
0,
0,
0,
.85)}
204 .admonitionblock
>table{border-collapse:separate;border:
0;background:none;width:
100%}
205 .admonitionblock
>table td.icon{text-align:center;width:
80px}
206 .admonitionblock
>table td.icon img{max-width:none}
207 .admonitionblock
>table td.icon .title{font-weight:bold;font-family:
"Open Sans",
"DejaVu Sans",sans-serif;text-transform:uppercase}
208 .admonitionblock
>table td.content{padding-left:
1.125em;padding-right:
1.25em;border-left:
1px solid #dddddf;color:rgba(
0,
0,
0,
.6);word-wrap:anywhere}
209 .admonitionblock
>table td.content
>:last-child
>:last-child{margin-bottom:
0}
210 .exampleblock
>.content{border:
1px solid #e6e6e6;margin-bottom:
1.25em;padding:
1.25em;background:#fff;border-radius:
4px}
211 .sidebarblock{border:
1px solid #dbdbd6;margin-bottom:
1.25em;padding:
1.25em;background:#f3f3f2;border-radius:
4px}
212 .sidebarblock
>.content
>.title{color:#
7a2518;margin-top:
0;text-align:center}
213 .exampleblock
>.content
>:first-child,.sidebarblock
>.content
>:first-child{margin-top:
0}
214 .exampleblock
>.content
>:last-child,.exampleblock
>.content
>:last-child
>:last-child,.exampleblock
>.content .olist
>ol
>li:last-child
>:last-child,.exampleblock
>.content .ulist
>ul
>li:last-child
>:last-child,.exampleblock
>.content .qlist
>ol
>li:last-child
>:last-child,.sidebarblock
>.content
>:last-child,.sidebarblock
>.content
>:last-child
>:last-child,.sidebarblock
>.content .olist
>ol
>li:last-child
>:last-child,.sidebarblock
>.content .ulist
>ul
>li:last-child
>:last-child,.sidebarblock
>.content .qlist
>ol
>li:last-child
>:last-child{margin-bottom:
0}
215 .literalblock pre,.listingblock
>.content
>pre{border-radius:
4px;overflow-x:auto;padding:
1em;font-size:
.8125em}
216 @media screen and (min-width:
768px){.literalblock pre,.listingblock
>.content
>pre{font-size:
.90625em}}
217 @media screen and (min-width:
1280px){.literalblock pre,.listingblock
>.content
>pre{font-size:
1em}}
218 .literalblock pre,.listingblock
>.content
>pre:not(.highlight),.listingblock
>.content
>pre[class=highlight],.listingblock
>.content
>pre[class^=
"highlight "]{background:#f7f7f8}
219 .literalblock.output pre{color:#f7f7f8;background:rgba(
0,
0,
0,
.9)}
220 .listingblock
>.content{position:relative}
221 .listingblock code[data-lang]::before{display:none;content:attr(data-lang);position:absolute;font-size:
.75em;top:
.425rem;right:
.5rem;line-height:
1;text-transform:uppercase;color:inherit;opacity:
.5}
222 .listingblock:hover code[data-lang]::before{display:block}
223 .listingblock.terminal pre .command::before{content:attr(data-prompt);padding-right:
.5em;color:inherit;opacity:
.5}
224 .listingblock.terminal pre .command:not([data-prompt])::before{content:
"$"}
225 .listingblock pre.highlightjs{padding:
0}
226 .listingblock pre.highlightjs
>code{padding:
1em;border-radius:
4px}
227 .listingblock pre.prettyprint{border-width:
0}
228 .prettyprint{background:#f7f7f8}
229 pre.prettyprint .linenums{line-height:
1.45;margin-left:
2em}
230 pre.prettyprint li{background:none;list-style-type:inherit;padding-left:
0}
231 pre.prettyprint li code[data-lang]::before{opacity:
1}
232 pre.prettyprint li:not(:first-child) code[data-lang]::before{display:none}
233 table.linenotable{border-collapse:separate;border:
0;margin-bottom:
0;background:none}
234 table.linenotable td[class]{color:inherit;vertical-align:top;padding:
0;line-height:inherit;white-space:normal}
235 table.linenotable td.code{padding-left:
.75em}
236 table.linenotable td.linenos,pre.pygments .linenos{border-right:
1px solid;opacity:
.35;padding-right:
.5em;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}
237 pre.pygments span.linenos{display:inline-block;margin-right:
.75em}
238 .quoteblock{margin:
0 1em
1.25em
1.5em;display:table}
239 .quoteblock:not(.excerpt)
>.title{margin-left:-
1.5em;margin-bottom:
.75em}
240 .quoteblock blockquote,.quoteblock p{color:rgba(
0,
0,
0,
.85);font-size:
1.15rem;line-height:
1.75;word-spacing:
.1em;letter-spacing:
0;font-style:italic;text-align:justify}
241 .quoteblock blockquote{margin:
0;padding:
0;border:
0}
242 .quoteblock blockquote::before{content:
"\201c";float:left;font-size:
2.75em;font-weight:bold;line-height:
.6em;margin-left:-
.6em;color:#
7a2518;text-shadow:
0 1px
2px rgba(
0,
0,
0,
.1)}
243 .quoteblock blockquote
>.paragraph:last-child p{margin-bottom:
0}
244 .quoteblock .attribution{margin-top:
.75em;margin-right:
.5ex;text-align:right}
245 .verseblock{margin:
0 1em
1.25em}
246 .verseblock pre{font-family:
"Open Sans",
"DejaVu Sans",sans-serif;font-size:
1.15rem;color:rgba(
0,
0,
0,
.85);font-weight:
300;text-rendering:optimizeLegibility}
247 .verseblock pre strong{font-weight:
400}
248 .verseblock .attribution{margin-top:
1.25rem;margin-left:
.5ex}
249 .quoteblock .attribution,.verseblock .attribution{font-size:
.9375em;line-height:
1.45;font-style:italic}
250 .quoteblock .attribution br,.verseblock .attribution br{display:none}
251 .quoteblock .attribution cite,.verseblock .attribution cite{display:block;letter-spacing:-
.025em;color:rgba(
0,
0,
0,
.6)}
252 .quoteblock.abstract blockquote::before,.quoteblock.excerpt blockquote::before,.quoteblock .quoteblock blockquote::before{display:none}
253 .quoteblock.abstract blockquote,.quoteblock.abstract p,.quoteblock.excerpt blockquote,.quoteblock.excerpt p,.quoteblock .quoteblock blockquote,.quoteblock .quoteblock p{line-height:
1.6;word-spacing:
0}
254 .quoteblock.abstract{margin:
0 1em
1.25em;display:block}
255 .quoteblock.abstract
>.title{margin:
0 0 .375em;font-size:
1.15em;text-align:center}
256 .quoteblock.excerpt
>blockquote,.quoteblock .quoteblock{padding:
0 0 .25em
1em;border-left:
.25em solid #dddddf}
257 .quoteblock.excerpt,.quoteblock .quoteblock{margin-left:
0}
258 .quoteblock.excerpt blockquote,.quoteblock.excerpt p,.quoteblock .quoteblock blockquote,.quoteblock .quoteblock p{color:inherit;font-size:
1.0625rem}
259 .quoteblock.excerpt .attribution,.quoteblock .quoteblock .attribution{color:inherit;font-size:
.85rem;text-align:left;margin-right:
0}
260 p.tableblock:last-child{margin-bottom:
0}
261 td.tableblock
>.content{margin-bottom:
1.25em;word-wrap:anywhere}
262 td.tableblock
>.content
>:last-child{margin-bottom:-
1.25em}
263 table.tableblock,th.tableblock,td.tableblock{border:
0 solid #dedede}
264 table.grid-all
>*
>tr
>*{border-width:
1px}
265 table.grid-cols
>*
>tr
>*{border-width:
0 1px}
266 table.grid-rows
>*
>tr
>*{border-width:
1px
0}
267 table.frame-all{border-width:
1px}
268 table.frame-ends{border-width:
1px
0}
269 table.frame-sides{border-width:
0 1px}
270 table.frame-none
>colgroup+*
>:first-child
>*,table.frame-sides
>colgroup+*
>:first-child
>*{border-top-width:
0}
271 table.frame-none
>:last-child
>:last-child
>*,table.frame-sides
>:last-child
>:last-child
>*{border-bottom-width:
0}
272 table.frame-none
>*
>tr
>:first-child,table.frame-ends
>*
>tr
>:first-child{border-left-width:
0}
273 table.frame-none
>*
>tr
>:last-child,table.frame-ends
>*
>tr
>:last-child{border-right-width:
0}
274 table.stripes-all
>*
>tr,table.stripes-odd
>*
>tr:nth-of-type(odd),table.stripes-even
>*
>tr:nth-of-type(even),table.stripes-hover
>*
>tr:hover{background:#f8f8f7}
275 th.halign-left,td.halign-left{text-align:left}
276 th.halign-right,td.halign-right{text-align:right}
277 th.halign-center,td.halign-center{text-align:center}
278 th.valign-top,td.valign-top{vertical-align:top}
279 th.valign-bottom,td.valign-bottom{vertical-align:bottom}
280 th.valign-middle,td.valign-middle{vertical-align:middle}
281 table thead th,table tfoot th{font-weight:bold}
282 tbody tr th{background:#f7f8f7}
283 tbody tr th,tbody tr th p,tfoot tr th,tfoot tr th p{color:rgba(
0,
0,
0,
.8);font-weight:bold}
284 p.tableblock
>code:only-child{background:none;padding:
0}
285 p.tableblock{font-size:
1em}
286 ol{margin-left:
1.75em}
287 ul li ol{margin-left:
1.5em}
288 dl dd{margin-left:
1.125em}
289 dl dd:last-child,dl dd:last-child
>:last-child{margin-bottom:
0}
290 li p,ul dd,ol dd,.olist .olist,.ulist .ulist,.ulist .olist,.olist .ulist{margin-bottom:
.625em}
291 ul.checklist,ul.none,ol.none,ul.no-bullet,ol.no-bullet,ol.unnumbered,ul.unstyled,ol.unstyled{list-style-type:none}
292 ul.no-bullet,ol.no-bullet,ol.unnumbered{margin-left:
.625em}
293 ul.unstyled,ol.unstyled{margin-left:
0}
294 li
>p:empty:only-child::before{content:
"";display:inline-block}
295 ul.checklist
>li
>p:first-child{margin-left:-
1em}
296 ul.checklist
>li
>p:first-child
>.fa-square-o:first-child,ul.checklist
>li
>p:first-child
>.fa-check-square-o:first-child{width:
1.25em;font-size:
.8em;position:relative;bottom:
.125em}
297 ul.checklist
>li
>p:first-child
>input[type=checkbox]:first-child{margin-right:
.25em}
298 ul.inline{display:flex;flex-flow:row wrap;list-style:none;margin:
0 0 .625em -
1.25em}
299 ul.inline
>li{margin-left:
1.25em}
300 .unstyled dl dt{font-weight:
400;font-style:normal}
301 ol.arabic{list-style-type:decimal}
302 ol.decimal{list-style-type:decimal-leading-zero}
303 ol.loweralpha{list-style-type:lower-alpha}
304 ol.upperalpha{list-style-type:upper-alpha}
305 ol.lowerroman{list-style-type:lower-roman}
306 ol.upperroman{list-style-type:upper-roman}
307 ol.lowergreek{list-style-type:lower-greek}
308 .hdlist
>table,.colist
>table{border:
0;background:none}
309 .hdlist
>table
>tbody
>tr,.colist
>table
>tbody
>tr{background:none}
310 td.hdlist1,td.hdlist2{vertical-align:top;padding:
0 .625em}
311 td.hdlist1{font-weight:bold;padding-bottom:
1.25em}
312 td.hdlist2{word-wrap:anywhere}
313 .literalblock+.colist,.listingblock+.colist{margin-top:-
.5em}
314 .colist td:not([class]):first-child{padding:
.4em
.75em
0;line-height:
1;vertical-align:top}
315 .colist td:not([class]):first-child img{max-width:none}
316 .colist td:not([class]):last-child{padding:
.25em
0}
317 .thumb,.th{line-height:
0;display:inline-block;border:
4px solid #fff;box-shadow:
0 0 0 1px #ddd}
318 .imageblock.left{margin:
.25em
.625em
1.25em
0}
319 .imageblock.right{margin:
.25em
0 1.25em
.625em}
320 .imageblock
>.title{margin-bottom:
0}
321 .imageblock.thumb,.imageblock.th{border-width:
6px}
322 .imageblock.thumb
>.title,.imageblock.th
>.title{padding:
0 .125em}
323 .image.left,.image.right{margin-top:
.25em;margin-bottom:
.25em;display:inline-block;line-height:
0}
324 .image.left{margin-right:
.625em}
325 .image.right{margin-left:
.625em}
326 a.image{text-decoration:none;display:inline-block}
327 a.image object{pointer-events:none}
328 sup.footnote,sup.footnoteref{font-size:
.875em;position:static;vertical-align:super}
329 sup.footnote a,sup.footnoteref a{text-decoration:none}
330 sup.footnote a:active,sup.footnoteref a:active{text-decoration:underline}
331 #footnotes{padding-top:
.75em;padding-bottom:
.75em;margin-bottom:
.625em}
332 #footnotes hr{width:
20%;min-width:
6.25em;margin:-
.25em
0 .75em;border-width:
1px
0 0}
333 #footnotes .footnote{padding:
0 .375em
0 .225em;line-height:
1.3334;font-size:
.875em;margin-left:
1.2em;margin-bottom:
.2em}
334 #footnotes .footnote a:first-of-type{font-weight:bold;text-decoration:none;margin-left:-
1.05em}
335 #footnotes .footnote:last-of-type{margin-bottom:
0}
336 #content #footnotes{margin-top:-
.625em;margin-bottom:
0;padding:
.75em
0}
337 div.unbreakable{page-break-inside:avoid}
338 .big{font-size:larger}
339 .small{font-size:smaller}
340 .underline{text-decoration:underline}
341 .overline{text-decoration:overline}
342 .line-through{text-decoration:line-through}
344 .aqua-background{background:#
00fafa}
346 .black-background{background:#
000}
348 .blue-background{background:#
0000fa}
349 .fuchsia{color:#bf00bf}
350 .fuchsia-background{background:#fa00fa}
352 .gray-background{background:#
7d7d7d}
353 .green{color:#
006000}
354 .green-background{background:#
007d00}
356 .lime-background{background:#
00fa00}
357 .maroon{color:#
600000}
358 .maroon-background{background:#
7d0000}
360 .navy-background{background:#
00007d}
361 .olive{color:#
606000}
362 .olive-background{background:#
7d7d00}
363 .purple{color:#
600060}
364 .purple-background{background:#
7d007d}
366 .red-background{background:#fa0000}
367 .silver{color:#
909090}
368 .silver-background{background:#bcbcbc}
370 .teal-background{background:#
007d7d}
371 .white{color:#bfbfbf}
372 .white-background{background:#fafafa}
373 .yellow{color:#bfbf00}
374 .yellow-background{background:#fafa00}
375 span.icon
>.fa{cursor:default}
376 a span.icon
>.fa{cursor:inherit}
377 .admonitionblock td.icon [class^=
"fa icon-"]{font-size:
2.5em;text-shadow:
1px
1px
2px rgba(
0,
0,
0,
.5);cursor:default}
378 .admonitionblock td.icon .icon-note::before{content:
"\f05a";color:#
19407c}
379 .admonitionblock td.icon .icon-tip::before{content:
"\f0eb";text-shadow:
1px
1px
2px rgba(
155,
155,
0,
.8);color:#
111}
380 .admonitionblock td.icon .icon-warning::before{content:
"\f071";color:#bf6900}
381 .admonitionblock td.icon .icon-caution::before{content:
"\f06d";color:#bf3400}
382 .admonitionblock td.icon .icon-important::before{content:
"\f06a";color:#bf0000}
383 .conum[data-value]{display:inline-block;color:#fff!important;background:rgba(
0,
0,
0,
.8);border-radius:
50%;text-align:center;font-size:
.75em;width:
1.67em;height:
1.67em;line-height:
1.67em;font-family:
"Open Sans",
"DejaVu Sans",sans-serif;font-style:normal;font-weight:bold}
384 .conum[data-value] *{color:#fff!important}
385 .conum[data-value]+b{display:none}
386 .conum[data-value]::after{content:attr(data-value)}
387 pre .conum[data-value]{position:relative;top:-
.125em}
388 b.conum *{color:inherit!important}
389 .conum:not([data-value]):empty{display:none}
390 dt,th.tableblock,td.content,div.footnote{text-rendering:optimizeLegibility}
391 h1,h2,p,td.content,span.alt,summary{letter-spacing:-
.01em}
392 p strong,td.content strong,div.footnote strong{letter-spacing:-
.005em}
393 p,blockquote,dt,td.content,td.hdlist1,span.alt,summary{font-size:
1.0625rem}
394 p{margin-bottom:
1.25rem}
395 .sidebarblock p,.sidebarblock dt,.sidebarblock td.content,p.tableblock{font-size:
1em}
396 .exampleblock
>.content{background:#fffef7;border-color:#e0e0dc;box-shadow:
0 1px
4px #e0e0dc}
397 .print-only{display:none!important}
398 @page{margin:
1.25cm
.75cm}
399 @media print{*{box-shadow:none!important;text-shadow:none!important}
401 a{color:inherit!important;text-decoration:underline!important}
402 a.bare,a[href^=
"#"],a[href^=
"mailto:"]{text-decoration:none!important}
403 a[href^=
"http:"]:not(.bare)::after,a[href^=
"https:"]:not(.bare)::after{content:
"(" attr(href)
")";display:inline-block;font-size:
.875em;padding-left:
.25em}
404 abbr[title]{border-bottom:
1px dotted}
405 abbr[title]::after{content:
" (" attr(title)
")"}
406 pre,blockquote,tr,img,object,svg{page-break-inside:avoid}
407 thead{display:table-header-group}
409 p,blockquote,dt,td.content{font-size:
1em;orphans:
3;widows:
3}
410 h2,h3,#toctitle,.sidebarblock
>.content
>.title{page-break-after:avoid}
411 #header,#content,#footnotes,#footer{max-width:none}
412 #toc,.sidebarblock,.exampleblock
>.content{background:none!important}
413 #toc{border-bottom:
1px solid #dddddf!important;padding-bottom:
0!important}
414 body.book #header{text-align:center}
415 body.book #header
>h1:first-child{border:
0!important;margin:
2.5em
0 1em}
416 body.book #header .details{border:
0!important;display:block;padding:
0!important}
417 body.book #header .details span:first-child{margin-left:
0!important}
418 body.book #header .details br{display:block}
419 body.book #header .details br+span::before{content:none!important}
420 body.book #toc{border:
0!important;text-align:left!important;padding:
0!important;margin:
0!important}
421 body.book #toc,body.book #preamble,body.book h1.sect0,body.book .sect1
>h2{page-break-before:always}
422 .listingblock code[data-lang]::before{display:block}
423 #footer{padding:
0 .9375em}
424 .hide-on-print{display:none!important}
425 .print-only{display:block!important}
426 .hide-for-print{display:none!important}
427 .show-for-print{display:inherit!important}}
428 @media amzn-kf8,print{#header
>h1:first-child{margin-top:
1.25rem}
429 .sect1{padding:
0!important}
430 .sect1+.sect1{border:
0}
431 #footer{background:none}
432 #footer-text{color:rgba(
0,
0,
0,
.6);font-size:
.9em}}
433 @media amzn-kf8{#header,#content,#footnotes,#footer{padding:
0}}
441 <body class=
"article">
443 <h1>My First Object Walk
</h1>
444 <div class=
"details">
445 <span id=
"revdate">2024-
11-
22</span>
450 <h2 id=
"_whats_an_object_walk">What
’s an Object Walk?
</h2>
451 <div class=
"sectionbody">
452 <div class=
"paragraph">
453 <p>The object walk is a key concept in Git - this is the process that underpins
454 operations like object transfer and fsck. Beginning from a given commit, the
455 list of objects is found by walking parent relationships between commits (commit
456 X based on commit W) and containment relationships between objects (tree Y is
457 contained within commit X, and blob Z is located within tree Y, giving our
458 working tree for commit X something like
<code>y/z.txt
</code>).
</p>
460 <div class=
"paragraph">
461 <p>A related concept is the revision walk, which is focused on commit objects and
462 their parent relationships and does not delve into other object types. The
463 revision walk is used for operations like
<code>git
</code> <code>log
</code>.
</p>
466 <h3 id=
"_related_reading">Related Reading
</h3>
470 <p><code>Documentation/user-manual.txt
</code> under
"Hacking Git" contains some coverage of
471 the revision walker in its various incarnations.
</p>
474 <p><code>revision.h
</code></p>
477 <p><a href=
"https://eagain.net/articles/git-for-computer-scientists/">Git for Computer Scientists
</a>
478 gives a good overview of the types of objects in Git and what your object
479 walk is really describing.
</p>
487 <h2 id=
"_setting_up">Setting Up
</h2>
488 <div class=
"sectionbody">
489 <div class=
"paragraph">
490 <p>Create a new branch from
<code>master
</code>.
</p>
492 <div class=
"listingblock">
493 <div class=
"content">
494 <pre>git checkout -b revwalk origin/master
</pre>
497 <div class=
"paragraph">
498 <p>We
’ll put our fiddling into a new command. For fun, let
’s name it
<code>git
</code> <code>walken
</code>.
499 Open up a new file
<code>builtin/walken.c
</code> and set up the command handler:
</p>
501 <div class=
"listingblock">
502 <div class=
"content">
506 * Part of the
"My First Object Walk" tutorial.
512 int cmd_walken(int argc, const char **argv, const char *prefix)
514 trace_printf(_(
"cmd_walken incoming...\n"));
519 <div class=
"admonitionblock note">
523 <div class=
"title">Note
</div>
526 <code>trace_printf
</code>(), defined in
<code>trace.h
</code>, differs from
<code>printf
</code>() in
527 that it can be turned on or off at runtime. For the purposes of this
528 tutorial, we will write
<code>walken
</code> as though it is intended for use as
529 a
"plumbing" command: that is, a command which is used primarily in
530 scripts, rather than interactively by humans (a
"porcelain" command).
531 So we will send our debug output to
<code>trace_printf
</code>() instead.
532 When running, enable trace output by setting the environment variable
<code>GIT_TRACE
</code>.
537 <div class=
"paragraph">
538 <p>Add usage text and
<code>-h
</code> handling, like all subcommands should consistently do
539 (our test suite will notice and complain if you fail to do so).
540 We
’ll need to include the
<code>parse-options.h
</code> header.
</p>
542 <div class=
"listingblock">
543 <div class=
"content">
544 <pre>#include
"parse-options.h"
548 int cmd_walken(int argc, const char **argv, const char *prefix)
550 const char * const walken_usage[] = {
554 struct option options[] = {
558 argc = parse_options(argc, argv, prefix, options, walken_usage,
0);
564 <div class=
"paragraph">
565 <p>Also add the relevant line in
<code>builtin.h
</code> near
<code>cmd_whatchanged
</code>():
</p>
567 <div class=
"listingblock">
568 <div class=
"content">
569 <pre>int cmd_walken(int argc, const char **argv, const char *prefix);
</pre>
572 <div class=
"paragraph">
573 <p>Include the command in
<code>git.c
</code> in
<code>commands
</code>[] near the entry for
<code>whatchanged
</code>,
574 maintaining alphabetical ordering:
</p>
576 <div class=
"listingblock">
577 <div class=
"content">
578 <pre>{
"walken", cmd_walken, RUN_SETUP },
</pre>
581 <div class=
"paragraph">
582 <p>Add it to the
<code>Makefile
</code> near the line for
<code>builtin/worktree.o
</code>:
</p>
584 <div class=
"listingblock">
585 <div class=
"content">
586 <pre>BUILTIN_OBJS += builtin/walken.o
</pre>
589 <div class=
"paragraph">
590 <p>Build and test out your command, without forgetting to ensure the
<code>DEVELOPER
</code>
591 flag is set, and with
<code>GIT_TRACE
</code> enabled so the debug output can be seen:
</p>
593 <div class=
"listingblock">
594 <div class=
"content">
595 <pre>$ echo DEVELOPER=
1 >>config.mak
597 $ GIT_TRACE=
1 ./bin-wrappers/git walken
</pre>
600 <div class=
"admonitionblock note">
604 <div class=
"title">Note
</div>
607 For a more exhaustive overview of the new command process, take a look at
608 <code>Documentation/MyFirstContribution.txt
</code>.
613 <div class=
"admonitionblock note">
617 <div class=
"title">Note
</div>
620 A reference implementation can be found at
621 <a href=
"https://github.com/nasamuffin/git/tree/revwalk" class=
"bare">https://github.com/nasamuffin/git/tree/revwalk
</a>.
627 <h3 id=
"_struct_rev_cmdline_info"><code>struct
</code> <code>rev_cmdline_info
</code></h3>
628 <div class=
"paragraph">
629 <p>The definition of
<code>struct
</code> <code>rev_cmdline_info
</code> can be found in
<code>revision.h
</code>.
</p>
631 <div class=
"paragraph">
632 <p>This struct is contained within the
<code>rev_info
</code> struct and is used to reflect
633 parameters provided by the user over the CLI.
</p>
635 <div class=
"paragraph">
636 <p><code>nr
</code> represents the number of
<code>rev_cmdline_entry
</code> present in the array.
</p>
638 <div class=
"paragraph">
639 <p><code>alloc
</code> is used by the
<code>ALLOC_GROW
</code> macro. Check
<code>alloc.h
</code> - this variable is
640 used to track the allocated size of the list.
</p>
642 <div class=
"paragraph">
643 <p>Per entry, we find:
</p>
645 <div class=
"paragraph">
646 <p><code>item
</code> is the object provided upon which to base the object walk. Items in Git
647 can be blobs, trees, commits, or tags. (See
<code>Documentation/gittutorial-
2.txt
</code>.)
</p>
649 <div class=
"paragraph">
650 <p><code>name
</code> is the object ID (OID) of the object - a hex string you may be familiar
651 with from using Git to organize your source in the past. Check the tutorial
652 mentioned above towards the top for a discussion of where the OID can come
655 <div class=
"paragraph">
656 <p><code>whence
</code> indicates some information about what to do with the parents of the
657 specified object. We
’ll explore this flag more later on; take a look at
658 <code>Documentation/revisions.txt
</code> to get an idea of what could set the
<code>whence
</code>
661 <div class=
"paragraph">
662 <p><code>flags
</code> are used to hint the beginning of the revision walk and are the first
663 block under the #include`s
<code>in
</code> `revision.
<code>h
</code>. The most likely ones to be set in
664 the
<code>rev_cmdline_info
</code> are
<code>UNINTERESTING
</code> and
<code>BOTTOM
</code>, but these same flags
665 can be used during the walk, as well.
</p>
669 <h3 id=
"_struct_rev_info"><code>struct
</code> <code>rev_info
</code></h3>
670 <div class=
"paragraph">
671 <p>This one is quite a bit longer, and many fields are only used during the walk
672 by
<code>revision.c
</code> - not configuration options. Most of the configurable flags in
673 <code>struct
</code> <code>rev_info
</code> have a mirror in
<code>Documentation/rev-list-options.txt
</code>. It
’s a
674 good idea to take some time and read through that document.
</p>
680 <h2 id=
"_basic_commit_walk">Basic Commit Walk
</h2>
681 <div class=
"sectionbody">
682 <div class=
"paragraph">
683 <p>First, let
’s see if we can replicate the output of
<code>git
</code> <code>log
</code> <code>--oneline
</code>. We
’ll
684 refer back to the implementation frequently to discover norms when performing
685 an object walk of our own.
</p>
687 <div class=
"paragraph">
688 <p>To do so, we
’ll first find all the commits, in order, which preceded the current
689 commit. We
’ll extract the name and subject of the commit from each.
</p>
691 <div class=
"paragraph">
692 <p>Ideally, we will also be able to find out which ones are currently at the tip of
693 various branches.
</p>
696 <h3 id=
"_setting_up_2">Setting Up
</h3>
697 <div class=
"paragraph">
698 <p>Preparing for your object walk has some distinct stages.
</p>
700 <div class=
"olist arabic">
703 <p>Perform default setup for this mode, and others which may be invoked.
</p>
706 <p>Check configuration files for relevant settings.
</p>
709 <p>Set up the
<code>rev_info
</code> struct.
</p>
712 <p>Tweak the initialized
<code>rev_info
</code> to suit the current walk.
</p>
715 <p>Prepare the
<code>rev_info
</code> for the walk.
</p>
718 <p>Iterate over the objects, processing each one.
</p>
723 <h4 id=
"_default_setups">Default Setups
</h4>
724 <div class=
"paragraph">
725 <p>Before examining configuration files which may modify command behavior, set up
726 default state for switches or options your command may have. If your command
727 utilizes other Git components, ask them to set up their default states as well.
728 For instance,
<code>git
</code> <code>log
</code> takes advantage of
<code>grep
</code> and
<code>diff
</code> functionality, so
729 its
<code>init_log_defaults
</code>() sets its own state (
<code>decoration_style
</code>) and asks
730 <code>grep
</code> and
<code>diff
</code> to initialize themselves by calling each of their
731 initialization functions.
</p>
735 <h4 id=
"_configuring_from_gitconfig">Configuring From .
<code>gitconfig
</code></h4>
736 <div class=
"paragraph">
737 <p>Next, we should have a look at any relevant configuration settings (i.e.,
738 settings readable and settable from
<code>git
</code> <code>config
</code>). This is done by providing a
739 callback to
<code>git_config
</code>(); within that callback, you can also invoke methods
740 from other components you may need that need to intercept these options. Your
741 callback will be invoked once per each configuration value which Git knows about
742 (global, local, worktree, etc.).
</p>
744 <div class=
"paragraph">
745 <p>Similarly to the default values, we don
’t have anything to do here yet
746 ourselves; however, we should call
<code>git_default_config
</code>() if we aren
’t calling
747 any other existing config callbacks.
</p>
749 <div class=
"paragraph">
750 <p>Add a new function to
<code>builtin/walken.c
</code>.
751 We
’ll also need to include the
<code>config.h
</code> header:
</p>
753 <div class=
"listingblock">
754 <div class=
"content">
755 <pre>#include
"config.h"
759 static int git_walken_config(const char *var, const char *value,
760 const struct config_context *ctx, void *cb)
763 * For now, we don't have any custom configuration, so fall back to
764 * the default config.
766 return git_default_config(var, value, ctx, cb);
770 <div class=
"paragraph">
771 <p>Make sure to invoke
<code>git_config
</code>() with it in your
<code>cmd_walken
</code>():
</p>
773 <div class=
"listingblock">
774 <div class=
"content">
775 <pre>int cmd_walken(int argc, const char **argv, const char *prefix)
779 git_config(git_walken_config, NULL);
787 <h4 id=
"_setting_up_rev_info">Setting Up
<code>rev_info
</code></h4>
788 <div class=
"paragraph">
789 <p>Now that we
’ve gathered external configuration and options, it
’s time to
790 initialize the
<code>rev_info
</code> object which we will use to perform the walk. This is
791 typically done by calling
<code>repo_init_revisions
</code>() with the repository you intend
792 to target, as well as the
<code>prefix
</code> argument of
<code>cmd_walken
</code> and your
<code>rev_info
</code>
795 <div class=
"paragraph">
796 <p>Add the
<code>struct
</code> <code>rev_info
</code> and the
<code>repo_init_revisions
</code>() call.
797 We
’ll also need to include the
<code>revision.h
</code> header:
</p>
799 <div class=
"listingblock">
800 <div class=
"content">
801 <pre>#include
"revision.h"
805 int cmd_walken(int argc, const char **argv, const char *prefix)
807 /* This can go wherever you like in your declarations.*/
811 /* This should go after the git_config() call. */
812 repo_init_revisions(the_repository,
&rev, prefix);
820 <h4 id=
"_tweaking_rev_info_for_the_walk">Tweaking
<code>rev_info
</code> For the Walk
</h4>
821 <div class=
"paragraph">
822 <p>We
’re getting close, but we
’re still not quite ready to go. Now that
<code>rev
</code> is
823 initialized, we can modify it to fit our needs. This is usually done within a
824 helper for clarity, so let
’s add one:
</p>
826 <div class=
"listingblock">
827 <div class=
"content">
828 <pre>static void final_rev_info_setup(struct rev_info *rev)
831 * We want to mimic the appearance of `git log --oneline`, so let's
832 * force oneline format.
834 get_commit_format(
"oneline", rev);
836 /* Start our object walk at HEAD. */
837 add_head_to_pending(rev);
841 <div class=
"admonitionblock note">
845 <div class=
"title">Note
</div>
848 <div class=
"paragraph">
849 <p>Instead of using the shorthand
<code>add_head_to_pending
</code>(), you could do
850 something like this:
</p>
852 <div class=
"listingblock">
853 <div class=
"content">
854 <pre> struct setup_revision_opt opt;
856 memset(
&opt,
0, sizeof(opt));
858 opt.revarg_opt = REVARG_COMMITTISH;
859 setup_revisions(argc, argv, rev,
&opt);
</pre>
862 <div class=
"paragraph">
863 <p>Using a
<code>setup_revision_opt
</code> gives you finer control over your walk
’s starting
870 <div class=
"paragraph">
871 <p>Then let
’s invoke
<code>final_rev_info_setup
</code>() after the call to
872 <code>repo_init_revisions
</code>():
</p>
874 <div class=
"listingblock">
875 <div class=
"content">
876 <pre>int cmd_walken(int argc, const char **argv, const char *prefix)
880 final_rev_info_setup(
&rev);
886 <div class=
"paragraph">
887 <p>Later, we may wish to add more arguments to
<code>final_rev_info_setup
</code>(). But for
888 now, this is all we need.
</p>
892 <h4 id=
"_preparing_rev_info_for_the_walk">Preparing
<code>rev_info
</code> For the Walk
</h4>
893 <div class=
"paragraph">
894 <p>Now that
<code>rev
</code> is all initialized and configured, we
’ve got one more setup step
895 before we get rolling. We can do this in a helper, which will both prepare the
896 <code>rev_info
</code> for the walk, and perform the walk itself. Let
’s start the helper
897 with the call to
<code>prepare_revision_walk
</code>(), which can return an error without
898 dying on its own:
</p>
900 <div class=
"listingblock">
901 <div class=
"content">
902 <pre>static void walken_commit_walk(struct rev_info *rev)
904 if (prepare_revision_walk(rev))
905 die(_(
"revision walk setup failed"));
909 <div class=
"admonitionblock note">
913 <div class=
"title">Note
</div>
916 <code>die
</code>() prints to
<code>stderr
</code> and exits the program. Since it will print to
917 <code>stderr
</code> it
’s likely to be seen by a human, so we will localize it.
924 <h4 id=
"_performing_the_walk">Performing the Walk!
</h4>
925 <div class=
"paragraph">
926 <p>Finally! We are ready to begin the walk itself. Now we can see that
<code>rev_info
</code>
927 can also be used as an iterator; we move to the next item in the walk by using
928 <code>get_revision
</code>() repeatedly. Add the listed variable declarations at the top and
929 the walk loop below the
<code>prepare_revision_walk
</code>() call within your
930 <code>walken_commit_walk
</code>():
</p>
932 <div class=
"listingblock">
933 <div class=
"content">
934 <pre>#include
"pretty.h"
938 static void walken_commit_walk(struct rev_info *rev)
940 struct commit *commit;
941 struct strbuf prettybuf = STRBUF_INIT;
945 while ((commit = get_revision(rev))) {
946 strbuf_reset(
&prettybuf);
947 pp_commit_easy(CMIT_FMT_ONELINE, commit,
&prettybuf);
950 strbuf_release(
&prettybuf);
954 <div class=
"admonitionblock note">
958 <div class=
"title">Note
</div>
961 <code>puts
</code>() prints a
<code>char
</code>* to
<code>stdout
</code>. Since this is the part of the
962 command we expect to be machine-parsed, we
’re sending it directly to stdout.
967 <div class=
"paragraph">
968 <p>Give it a shot.
</p>
970 <div class=
"listingblock">
971 <div class=
"content">
973 $ ./bin-wrappers/git walken
</pre>
976 <div class=
"paragraph">
977 <p>You should see all of the subject lines of all the commits in
978 your tree
’s history, in order, ending with the initial commit,
"Initial revision
979 of "git
", the information manager from hell". Congratulations! You
’ve written
980 your first revision walk. You can play with printing some additional fields
981 from each commit if you
’re curious; have a look at the functions available in
982 <code>commit.h
</code>.
</p>
987 <h3 id=
"_adding_a_filter">Adding a Filter
</h3>
988 <div class=
"paragraph">
989 <p>Next, let
’s try to filter the commits we see based on their author. This is
990 equivalent to running
<code>git
</code> <code>log
</code> <code>--author=
</code><em><pattern
></em>. We can add a filter by
991 modifying
<code>rev_info.grep_filter
</code>, which is a
<code>struct
</code> <code>grep_opt
</code>.
</p>
993 <div class=
"paragraph">
994 <p>First some setup. Add
<code>grep_config
</code>() to
<code>git_walken_config
</code>():
</p>
996 <div class=
"listingblock">
997 <div class=
"content">
998 <pre>static int git_walken_config(const char *var, const char *value,
999 const struct config_context *ctx, void *cb)
1001 grep_config(var, value, ctx, cb);
1002 return git_default_config(var, value, ctx, cb);
1006 <div class=
"paragraph">
1007 <p>Next, we can modify the
<code>grep_filter
</code>. This is done with convenience functions
1008 found in
<code>grep.h
</code>. For fun, we
’re filtering to only commits from folks using a
1009 <code>gmail.com
</code> email address - a not-very-precise guess at who may be working on
1010 Git as a hobby. Since we
’re checking the author, which is a specific line in the
1011 header, we
’ll use the
<code>append_header_grep_pattern
</code>() helper. We can use
1012 the
<code>enum
</code> <code>grep_header_field
</code> to indicate which part of the commit header we want
1015 <div class=
"paragraph">
1016 <p>In
<code>final_rev_info_setup
</code>(), add your filter line:
</p>
1018 <div class=
"listingblock">
1019 <div class=
"content">
1020 <pre>static void final_rev_info_setup(int argc, const char **argv,
1021 const char *prefix, struct rev_info *rev)
1025 append_header_grep_pattern(
&rev-
>grep_filter, GREP_HEADER_AUTHOR,
1027 compile_grep_patterns(
&rev-
>grep_filter);
1033 <div class=
"paragraph">
1034 <p><code>append_header_grep_pattern
</code>() adds your new
"gmail" pattern to
<code>rev_info
</code>, but
1035 it won
’t work unless we compile it with
<code>compile_grep_patterns
</code>().
</p>
1037 <div class=
"admonitionblock note">
1041 <div class=
"title">Note
</div>
1043 <td class=
"content">
1044 If you are using
<code>setup_revisions
</code>() (for example, if you are passing a
1045 <code>setup_revision_opt
</code> instead of using
<code>add_head_to_pending
</code>()), you don
’t need
1046 to call
<code>compile_grep_patterns
</code>() because
<code>setup_revisions
</code>() calls it for you.
1051 <div class=
"admonitionblock note">
1055 <div class=
"title">Note
</div>
1057 <td class=
"content">
1058 We could add the same filter via the
<code>append_grep_pattern
</code>() helper if we
1059 wanted to, but
<code>append_header_grep_pattern
</code>() adds the
<code>enum
</code> <code>grep_context
</code> and
1060 <code>enum
</code> <code>grep_pat_token
</code> for us.
1067 <h3 id=
"_changing_the_order">Changing the Order
</h3>
1068 <div class=
"paragraph">
1069 <p>There are a few ways that we can change the order of the commits during a
1070 revision walk. Firstly, we can use the
<code>enum
</code> <code>rev_sort_order
</code> to choose from some
1071 typical orderings.
</p>
1073 <div class=
"paragraph">
1074 <p><code>topo_order
</code> is the same as
<code>git
</code> <code>log
</code> <code>--topo-order
</code>: we avoid showing a parent
1075 before all of its children have been shown, and we avoid mixing commits which
1076 are in different lines of history. (
<code>git
</code> <code>help
</code> <code>log
</code>'s section on
<code>--topo-order
</code>
1077 has a very nice diagram to illustrate this.)
</p>
1079 <div class=
"paragraph">
1080 <p>Let
’s see what happens when we run with
<code>REV_SORT_BY_COMMIT_DATE
</code> as opposed to
1081 <code>REV_SORT_BY_AUTHOR_DATE
</code>. Add the following:
</p>
1083 <div class=
"listingblock">
1084 <div class=
"content">
1085 <pre>static void final_rev_info_setup(int argc, const char **argv,
1086 const char *prefix, struct rev_info *rev)
1090 rev-
>topo_order =
1;
1091 rev-
>sort_order = REV_SORT_BY_COMMIT_DATE;
1097 <div class=
"paragraph">
1098 <p>Let
’s output this into a file so we can easily diff it with the walk sorted by
1101 <div class=
"listingblock">
1102 <div class=
"content">
1104 $ ./bin-wrappers/git walken
> commit-date.txt
</pre>
1107 <div class=
"paragraph">
1108 <p>Then, let
’s sort by author date and run it again.
</p>
1110 <div class=
"listingblock">
1111 <div class=
"content">
1112 <pre>static void final_rev_info_setup(int argc, const char **argv,
1113 const char *prefix, struct rev_info *rev)
1117 rev-
>topo_order =
1;
1118 rev-
>sort_order = REV_SORT_BY_AUTHOR_DATE;
1124 <div class=
"listingblock">
1125 <div class=
"content">
1127 $ ./bin-wrappers/git walken
> author-date.txt
</pre>
1130 <div class=
"paragraph">
1131 <p>Finally, compare the two. This is a little less helpful without object names or
1132 dates, but hopefully we get the idea.
</p>
1134 <div class=
"listingblock">
1135 <div class=
"content">
1136 <pre>$ diff -u commit-date.txt author-date.txt
</pre>
1139 <div class=
"paragraph">
1140 <p>This display indicates that commits can be reordered after they
’re written, for
1141 example with
<code>git
</code> <code>rebase
</code>.
</p>
1143 <div class=
"paragraph">
1144 <p>Let
’s try one more reordering of commits.
<code>rev_info
</code> exposes a
<code>reverse
</code> flag.
1145 Set that flag somewhere inside of
<code>final_rev_info_setup
</code>():
</p>
1147 <div class=
"listingblock">
1148 <div class=
"content">
1149 <pre>static void final_rev_info_setup(int argc, const char **argv, const char *prefix,
1150 struct rev_info *rev)
1154 rev-
>reverse =
1;
1160 <div class=
"paragraph">
1161 <p>Run your walk again and note the difference in order. (If you remove the grep
1162 pattern, you should see the last commit this call gives you as your current
1169 <h2 id=
"_basic_object_walk">Basic Object Walk
</h2>
1170 <div class=
"sectionbody">
1171 <div class=
"paragraph">
1172 <p>So far we
’ve been walking only commits. But Git has more types of objects than
1173 that! Let
’s see if we can walk
<em>all
</em> objects, and find out some information
1176 <div class=
"paragraph">
1177 <p>We can base our work on an example.
<code>git
</code> <code>pack-objects
</code> prepares all kinds of
1178 objects for packing into a bitmap or packfile. The work we are interested in
1179 resides in
<code>builtin/pack-objects.c:get_object_list
</code>(); examination of that
1180 function shows that the all-object walk is being performed by
1181 <code>traverse_commit_list
</code>() or
<code>traverse_commit_list_filtered
</code>(). Those two
1182 functions reside in
<code>list-objects.c
</code>; examining the source shows that, despite
1183 the name, these functions traverse all kinds of objects. Let
’s have a look at
1184 the arguments to
<code>traverse_commit_list
</code>().
</p>
1189 <p><code>struct
</code> <code>rev_info
</code> *revs: This is the
<code>rev_info
</code> used for the walk. If
1190 its
<code>filter
</code> member is not
<code>NULL
</code>, then
<code>filter
</code> contains information for
1191 how to filter the object list.
</p>
1194 <p><code>show_commit_fn
</code> <code>show_commit
</code>: A callback which will be used to handle each
1195 individual commit object.
</p>
1198 <p><code>show_object_fn
</code> <code>show_object
</code>: A callback which will be used to handle each
1199 non-commit object (so each blob, tree, or tag).
</p>
1202 <p><code>void
</code> *show_data: A context buffer which is passed in turn to
<code>show_commit
</code>
1203 and
<code>show_object
</code>.
</p>
1207 <div class=
"paragraph">
1208 <p>In addition,
<code>traverse_commit_list_filtered
</code>() has an additional parameter:
</p>
1213 <p><code>struct
</code> <code>oidset
</code> *omitted: A linked-list of object IDs which the provided
1214 filter caused to be omitted.
</p>
1218 <div class=
"paragraph">
1219 <p>It looks like these methods use callbacks we provide instead of needing us
1220 to call it repeatedly ourselves. Cool! Let
’s add the callbacks first.
</p>
1222 <div class=
"paragraph">
1223 <p>For the sake of this tutorial, we
’ll simply keep track of how many of each kind
1224 of object we find. At file scope in
<code>builtin/walken.c
</code> add the following
1225 tracking variables:
</p>
1227 <div class=
"listingblock">
1228 <div class=
"content">
1229 <pre>static int commit_count;
1230 static int tag_count;
1231 static int blob_count;
1232 static int tree_count;
</pre>
1235 <div class=
"paragraph">
1236 <p>Commits are handled by a different callback than other objects; let
’s do that
1239 <div class=
"listingblock">
1240 <div class=
"content">
1241 <pre>static void walken_show_commit(struct commit *cmt, void *buf)
1247 <div class=
"paragraph">
1248 <p>The
<code>cmt
</code> argument is fairly self-explanatory. But it
’s worth mentioning that
1249 the
<code>buf
</code> argument is actually the context buffer that we can provide to the
1250 traversal calls -
<code>show_data
</code>, which we mentioned a moment ago.
</p>
1252 <div class=
"paragraph">
1253 <p>Since we have the
<code>struct
</code> <code>commit
</code> object, we can look at all the same parts that
1254 we looked at in our earlier commit-only walk. For the sake of this tutorial,
1255 though, we
’ll just increment the commit counter and move on.
</p>
1257 <div class=
"paragraph">
1258 <p>The callback for non-commits is a little different, as we
’ll need to check
1259 which kind of object we
’re dealing with:
</p>
1261 <div class=
"listingblock">
1262 <div class=
"content">
1263 <pre>static void walken_show_object(struct object *obj, const char *str, void *buf)
1265 switch (obj-
>type) {
1276 BUG(
"unexpected commit object in walken_show_object\n");
1278 BUG(
"unexpected object type %s in walken_show_object\n",
1279 type_name(obj-
>type));
1284 <div class=
"paragraph">
1285 <p>Again,
<code>obj
</code> is fairly self-explanatory, and we can guess that
<code>buf
</code> is the same
1286 context pointer that
<code>walken_show_commit
</code>() receives: the
<code>show_data
</code> argument
1287 to
<code>traverse_commit_list
</code>() and
<code>traverse_commit_list_filtered
</code>(). Finally,
1288 <code>str
</code> contains the name of the object, which ends up being something like
1289 <code>foo.txt
</code> (blob),
<code>bar/baz
</code> (tree), or
<code>v1.2
.3</code> (tag).
</p>
1291 <div class=
"paragraph">
1292 <p>To help assure us that we aren
’t double-counting commits, we
’ll include some
1293 complaining if a commit object is routed through our non-commit callback; we
’ll
1294 also complain if we see an invalid object type. Since those two cases should be
1295 unreachable, and would only change in the event of a semantic change to the Git
1296 codebase, we complain by using
<code>BUG
</code>() - which is a signal to a developer that
1297 the change they made caused unintended consequences, and the rest of the
1298 codebase needs to be updated to understand that change.
<code>BUG
</code>() is not intended
1299 to be seen by the public, so it is not localized.
</p>
1301 <div class=
"paragraph">
1302 <p>Our main object walk implementation is substantially different from our commit
1303 walk implementation, so let
’s make a new function to perform the object walk. We
1304 can perform setup which is applicable to all objects here, too, to keep separate
1305 from setup which is applicable to commit-only walks.
</p>
1307 <div class=
"paragraph">
1308 <p>We
’ll start by enabling all types of objects in the
<code>struct
</code> <code>rev_info
</code>. We
’ll
1309 also turn on
<code>tree_blobs_in_commit_order
</code>, which means that we will walk a
1310 commit
’s tree and everything it points to immediately after we find each commit,
1311 as opposed to waiting for the end and walking through all trees after the commit
1312 history has been discovered. With the appropriate settings configured, we are
1313 ready to call
<code>prepare_revision_walk
</code>().
</p>
1315 <div class=
"listingblock">
1316 <div class=
"content">
1317 <pre>static void walken_object_walk(struct rev_info *rev)
1319 rev-
>tree_objects =
1;
1320 rev-
>blob_objects =
1;
1321 rev-
>tag_objects =
1;
1322 rev-
>tree_blobs_in_commit_order =
1;
1324 if (prepare_revision_walk(rev))
1325 die(_(
"revision walk setup failed"));
1330 tree_count =
0;
</pre>
1333 <div class=
"paragraph">
1334 <p>Let
’s start by calling just the unfiltered walk and reporting our counts.
1335 Complete your implementation of
<code>walken_object_walk
</code>().
1336 We
’ll also need to include the
<code>list-objects.h
</code> header.
</p>
1338 <div class=
"listingblock">
1339 <div class=
"content">
1340 <pre>#include
"list-objects.h"
1344 traverse_commit_list(rev, walken_show_commit, walken_show_object, NULL);
1346 printf(
"commits %d\nblobs %d\ntags %d\ntrees %d\n", commit_count,
1347 blob_count, tag_count, tree_count);
1351 <div class=
"admonitionblock note">
1355 <div class=
"title">Note
</div>
1357 <td class=
"content">
1358 This output is intended to be machine-parsed. Therefore, we are not
1359 sending it to
<code>trace_printf
</code>(), and we are not localizing it - we need scripts
1360 to be able to count on the formatting to be exactly the way it is shown here.
1361 If we were intending this output to be read by humans, we would need to localize
1362 it with
<code>_
</code>().
1367 <div class=
"paragraph">
1368 <p>Finally, we
’ll ask
<code>cmd_walken
</code>() to use the object walk instead. Discussing
1369 command line options is out of scope for this tutorial, so we
’ll just hardcode
1370 a branch we can change at compile time. Where you call
<code>final_rev_info_setup
</code>()
1371 and
<code>walken_commit_walk
</code>(), instead branch like so:
</p>
1373 <div class=
"listingblock">
1374 <div class=
"content">
1376 add_head_to_pending(
&rev);
1377 walken_object_walk(
&rev);
1379 final_rev_info_setup(argc, argv, prefix,
&rev);
1380 walken_commit_walk(
&rev);
1384 <div class=
"admonitionblock note">
1388 <div class=
"title">Note
</div>
1390 <td class=
"content">
1391 For simplicity, we
’ve avoided all the filters and sorts we applied in
1392 <code>final_rev_info_setup
</code>() and simply added
<code>HEAD
</code> to our pending queue. If you
1393 want, you can certainly use the filters we added before by moving
1394 <code>final_rev_info_setup
</code>() out of the conditional and removing the call to
1395 <code>add_head_to_pending
</code>().
1400 <div class=
"paragraph">
1401 <p>Now we can try to run our command! It should take noticeably longer than the
1402 commit walk, but an examination of the output will give you an idea why. Your
1403 output should look similar to this example, but with different counts:
</p>
1405 <div class=
"listingblock">
1406 <div class=
"content">
1407 <pre>Object walk completed. Found
55733 commits,
100274 blobs,
0 tags, and
104210 trees.
</pre>
1410 <div class=
"paragraph">
1411 <p>This makes sense. We have more trees than commits because the Git project has
1412 lots of subdirectories which can change, plus at least one tree per commit. We
1413 have no tags because we started on a commit (
<code>HEAD
</code>) and while tags can point to
1414 commits, commits can
’t point to tags.
</p>
1416 <div class=
"admonitionblock note">
1420 <div class=
"title">Note
</div>
1422 <td class=
"content">
1423 You will have different counts when you run this yourself! The number of
1424 objects grows along with the Git project.
1430 <h3 id=
"_adding_a_filter_2">Adding a Filter
</h3>
1431 <div class=
"paragraph">
1432 <p>There are a handful of filters that we can apply to the object walk laid out in
1433 <code>Documentation/rev-list-options.txt
</code>. These filters are typically useful for
1434 operations such as creating packfiles or performing a partial clone. They are
1435 defined in
<code>list-objects-filter-options.h
</code>. For the purposes of this tutorial we
1436 will use the
"tree:1" filter, which causes the walk to omit all trees and blobs
1437 which are not directly referenced by commits reachable from the commit in
1438 <code>pending
</code> when the walk begins. (
<code>pending
</code> is the list of objects which need to
1439 be traversed during a walk; you can imagine a breadth-first tree traversal to
1440 help understand. In our case, that means we omit trees and blobs not directly
1441 referenced by
<code>HEAD
</code> or
<code>HEAD
</code>'s history, because we begin the walk with only
1442 <code>HEAD
</code> in the
<code>pending
</code> list.)
</p>
1444 <div class=
"paragraph">
1445 <p>For now, we are not going to track the omitted objects, so we
’ll replace those
1446 parameters with
<code>NULL
</code>. For the sake of simplicity, we
’ll add a simple
1447 build-time branch to use our filter or not. Preface the line calling
1448 <code>traverse_commit_list
</code>() with the following, which will remind us which kind of
1449 walk we
’ve just performed:
</p>
1451 <div class=
"listingblock">
1452 <div class=
"content">
1455 trace_printf(_(
"Unfiltered object walk.\n"));
1458 _(
"Filtered object walk with filterspec 'tree:1'.\n"));
1460 parse_list_objects_filter(
&rev-
>filter,
"tree:1");
1462 traverse_commit_list(rev, walken_show_commit,
1463 walken_show_object, NULL);
</pre>
1466 <div class=
"paragraph">
1467 <p>The
<code>rev-
</code>><code>filter
</code> member is usually built directly from a command
1468 line argument, so the module provides an easy way to build one from a string.
1469 Even though we aren
’t taking user input right now, we can still build one with
1470 a hardcoded string using
<code>parse_list_objects_filter
</code>().
</p>
1472 <div class=
"paragraph">
1473 <p>With the filter spec
"tree:1", we are expecting to see
<em>only
</em> the root tree for
1474 each commit; therefore, the tree object count should be less than or equal to
1475 the number of commits. (For an example of why that
’s true:
<code>git
</code> <code>commit
</code> <code>--revert
</code>
1476 points to the same tree object as its grandparent.)
</p>
1480 <h3 id=
"_counting_omitted_objects">Counting Omitted Objects
</h3>
1481 <div class=
"paragraph">
1482 <p>We also have the capability to enumerate all objects which were omitted by a
1483 filter, like with
<code>git
</code> <code>log
</code> <code>--filter=
</code><em><spec
></em> <code>--filter-print-omitted
</code>. To do this,
1484 change
<code>traverse_commit_list
</code>() to
<code>traverse_commit_list_filtered
</code>(), which is
1485 able to populate an
<code>omitted
</code> list. Asking for this list of filtered objects
1486 may cause performance degradations, however, because in this case, despite
1487 filtering objects, the possibly much larger set of all reachable objects must
1488 be processed in order to populate that list.
</p>
1490 <div class=
"paragraph">
1491 <p>First, add the
<code>struct
</code> <code>oidset
</code> and related items we will use to iterate it:
</p>
1493 <div class=
"listingblock">
1494 <div class=
"content">
1495 <pre>#include
"oidset.h"
1499 static void walken_object_walk(
1502 struct oidset omitted;
1503 struct oidset_iter oit;
1504 struct object_id *oid = NULL;
1505 int omitted_count =
0;
1506 oidset_init(
&omitted,
0);
1511 <div class=
"paragraph">
1512 <p>Replace the call to
<code>traverse_commit_list
</code>() with
1513 <code>traverse_commit_list_filtered
</code>() and pass a pointer to the
<code>omitted
</code> oidset
1514 defined and initialized above:
</p>
1516 <div class=
"listingblock">
1517 <div class=
"content">
1520 traverse_commit_list_filtered(rev,
1521 walken_show_commit, walken_show_object, NULL,
&omitted);
1526 <div class=
"paragraph">
1527 <p>Then, after your traversal, the
<code>oidset
</code> traversal is pretty straightforward.
1528 Count all the objects within and modify the print statement:
</p>
1530 <div class=
"listingblock">
1531 <div class=
"content">
1532 <pre> /* Count the omitted objects. */
1533 oidset_iter_init(
&omitted,
&oit);
1535 while ((oid = oidset_iter_next(
&oit)))
1538 printf(
"commits %d\nblobs %d\ntags %d\ntrees %d\nomitted %d\n",
1539 commit_count, blob_count, tag_count, tree_count, omitted_count);
</pre>
1542 <div class=
"paragraph">
1543 <p>By running your walk with and without the filter, you should find that the total
1544 object count in each case is identical. You can also time each invocation of
1545 the
<code>walken
</code> subcommand, with and without
<code>omitted
</code> being passed in, to confirm
1546 to yourself the runtime impact of tracking all omitted objects.
</p>
1550 <h3 id=
"_changing_the_order_2">Changing the Order
</h3>
1551 <div class=
"paragraph">
1552 <p>Finally, let
’s demonstrate that you can also reorder walks of all objects, not
1553 just walks of commits. First, we
’ll make our handlers chattier - modify
1554 <code>walken_show_commit
</code>() and
<code>walken_show_object
</code>() to print the object as they
1557 <div class=
"listingblock">
1558 <div class=
"content">
1559 <pre>#include
"hex.h"
1563 static void walken_show_commit(struct commit *cmt, void *buf)
1565 trace_printf(
"commit: %s\n", oid_to_hex(
&cmt-
>object.oid));
1569 static void walken_show_object(struct object *obj, const char *str, void *buf)
1571 trace_printf(
"%s: %s\n", type_name(obj-
>type), oid_to_hex(
&obj-
>oid));
1577 <div class=
"admonitionblock note">
1581 <div class=
"title">Note
</div>
1583 <td class=
"content">
1584 Since we will be examining this output directly as humans, we
’ll use
1585 <code>trace_printf
</code>() here. Additionally, since this change introduces a significant
1586 number of printed lines, using
<code>trace_printf
</code>() will allow us to easily silence
1587 those lines without having to recompile.
1592 <div class=
"paragraph">
1593 <p>(Leave the counter increment logic in place.)
</p>
1595 <div class=
"paragraph">
1596 <p>With only that change, run again (but save yourself some scrollback):
</p>
1598 <div class=
"listingblock">
1599 <div class=
"content">
1600 <pre>$ GIT_TRACE=
1 ./bin-wrappers/git walken
2>&1 | head -n
10</pre>
1603 <div class=
"paragraph">
1604 <p>Take a look at the top commit with
<code>git
</code> <code>show
</code> and the object ID you printed; it
1605 should be the same as the output of
<code>git
</code> <code>show
</code> <code>HEAD
</code>.
</p>
1607 <div class=
"paragraph">
1608 <p>Next, let
’s change a setting on our
<code>struct
</code> <code>rev_info
</code> within
1609 <code>walken_object_walk
</code>(). Find where you
’re changing the other settings on
<code>rev
</code>,
1610 such as
<code>rev-
</code>><code>tree_objects
</code> and
<code>rev-
</code>><code>tree_blobs_in_commit_order
</code>, and add the
1611 <code>reverse
</code> setting at the bottom:
</p>
1613 <div class=
"listingblock">
1614 <div class=
"content">
1617 rev-
>tree_objects =
1;
1618 rev-
>blob_objects =
1;
1619 rev-
>tag_objects =
1;
1620 rev-
>tree_blobs_in_commit_order =
1;
1621 rev-
>reverse =
1;
1626 <div class=
"paragraph">
1627 <p>Now, run again, but this time, let
’s grab the last handful of objects instead
1628 of the first handful:
</p>
1630 <div class=
"listingblock">
1631 <div class=
"content">
1633 $ GIT_TRACE=
1 ./bin-wrappers/git walken
2>&1 | tail -n
10</pre>
1636 <div class=
"paragraph">
1637 <p>The last commit object given should have the same OID as the one we saw at the
1638 top before, and running
<code>git
</code> <code>show
</code> <em><oid
></em> with that OID should give you again
1639 the same results as
<code>git
</code> <code>show
</code> <code>HEAD
</code>. Furthermore, if you run and examine the
1640 first ten lines again (with
<code>head
</code> instead of
<code>tail
</code> like we did before applying
1641 the
<code>reverse
</code> setting), you should see that now the first commit printed is the
1642 initial commit,
<code>e83c5163
</code>.
</p>
1648 <h2 id=
"_wrapping_up">Wrapping Up
</h2>
1649 <div class=
"sectionbody">
1650 <div class=
"paragraph">
1651 <p>Let
’s review. In this tutorial, we:
</p>
1656 <p>Built a commit walk from the ground up
</p>
1659 <p>Enabled a grep filter for that commit walk
</p>
1662 <p>Changed the sort order of that filtered commit walk
</p>
1665 <p>Built an object walk (tags, commits, trees, and blobs) from the ground up
</p>
1668 <p>Learned how to add a filter-spec to an object walk
</p>
1671 <p>Changed the display order of the filtered object walk
</p>
1679 <div id=
"footer-text">
1680 Last updated
2024-
04-
10 06:
45:
01 +
0900