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>
447 <h2 id=
"_whats_an_object_walk">What
’s an Object Walk?
</h2>
448 <div class=
"sectionbody">
449 <div class=
"paragraph">
450 <p>The object walk is a key concept in Git - this is the process that underpins
451 operations like object transfer and fsck. Beginning from a given commit, the
452 list of objects is found by walking parent relationships between commits (commit
453 X based on commit W) and containment relationships between objects (tree Y is
454 contained within commit X, and blob Z is located within tree Y, giving our
455 working tree for commit X something like
<code>y/z.txt
</code>).
</p>
457 <div class=
"paragraph">
458 <p>A related concept is the revision walk, which is focused on commit objects and
459 their parent relationships and does not delve into other object types. The
460 revision walk is used for operations like
<code>git
</code> <code>log
</code>.
</p>
463 <h3 id=
"_related_reading">Related Reading
</h3>
467 <p><code>Documentation/user-manual.txt
</code> under
"Hacking Git" contains some coverage of
468 the revision walker in its various incarnations.
</p>
471 <p><code>revision.h
</code></p>
474 <p><a href=
"https://eagain.net/articles/git-for-computer-scientists/">Git for Computer Scientists
</a>
475 gives a good overview of the types of objects in Git and what your object
476 walk is really describing.
</p>
484 <h2 id=
"_setting_up">Setting Up
</h2>
485 <div class=
"sectionbody">
486 <div class=
"paragraph">
487 <p>Create a new branch from
<code>master
</code>.
</p>
489 <div class=
"listingblock">
490 <div class=
"content">
491 <pre>git checkout -b revwalk origin/master
</pre>
494 <div class=
"paragraph">
495 <p>We
’ll put our fiddling into a new command. For fun, let
’s name it
<code>git
</code> <code>walken
</code>.
496 Open up a new file
<code>builtin/walken.c
</code> and set up the command handler:
</p>
498 <div class=
"listingblock">
499 <div class=
"content">
503 * Part of the
"My First Object Walk" tutorial.
509 int cmd_walken(int argc, const char **argv, const char *prefix)
511 trace_printf(_(
"cmd_walken incoming...\n"));
516 <div class=
"admonitionblock note">
520 <div class=
"title">Note
</div>
523 <code>trace_printf
</code>(), defined in
<code>trace.h
</code>, differs from
<code>printf
</code>() in
524 that it can be turned on or off at runtime. For the purposes of this
525 tutorial, we will write
<code>walken
</code> as though it is intended for use as
526 a
"plumbing" command: that is, a command which is used primarily in
527 scripts, rather than interactively by humans (a
"porcelain" command).
528 So we will send our debug output to
<code>trace_printf
</code>() instead.
529 When running, enable trace output by setting the environment variable
<code>GIT_TRACE
</code>.
534 <div class=
"paragraph">
535 <p>Add usage text and
<code>-h
</code> handling, like all subcommands should consistently do
536 (our test suite will notice and complain if you fail to do so).
537 We
’ll need to include the
<code>parse-options.h
</code> header.
</p>
539 <div class=
"listingblock">
540 <div class=
"content">
541 <pre>#include
"parse-options.h"
545 int cmd_walken(int argc, const char **argv, const char *prefix)
547 const char * const walken_usage[] = {
551 struct option options[] = {
555 argc = parse_options(argc, argv, prefix, options, walken_usage,
0);
561 <div class=
"paragraph">
562 <p>Also add the relevant line in
<code>builtin.h
</code> near
<code>cmd_whatchanged
</code>():
</p>
564 <div class=
"listingblock">
565 <div class=
"content">
566 <pre>int cmd_walken(int argc, const char **argv, const char *prefix);
</pre>
569 <div class=
"paragraph">
570 <p>Include the command in
<code>git.c
</code> in
<code>commands
</code>[] near the entry for
<code>whatchanged
</code>,
571 maintaining alphabetical ordering:
</p>
573 <div class=
"listingblock">
574 <div class=
"content">
575 <pre>{
"walken", cmd_walken, RUN_SETUP },
</pre>
578 <div class=
"paragraph">
579 <p>Add it to the
<code>Makefile
</code> near the line for
<code>builtin/worktree.o
</code>:
</p>
581 <div class=
"listingblock">
582 <div class=
"content">
583 <pre>BUILTIN_OBJS += builtin/walken.o
</pre>
586 <div class=
"paragraph">
587 <p>Build and test out your command, without forgetting to ensure the
<code>DEVELOPER
</code>
588 flag is set, and with
<code>GIT_TRACE
</code> enabled so the debug output can be seen:
</p>
590 <div class=
"listingblock">
591 <div class=
"content">
592 <pre>$ echo DEVELOPER=
1 >>config.mak
594 $ GIT_TRACE=
1 ./bin-wrappers/git walken
</pre>
597 <div class=
"admonitionblock note">
601 <div class=
"title">Note
</div>
604 For a more exhaustive overview of the new command process, take a look at
605 <code>Documentation/MyFirstContribution.txt
</code>.
610 <div class=
"admonitionblock note">
614 <div class=
"title">Note
</div>
617 A reference implementation can be found at
618 <a href=
"https://github.com/nasamuffin/git/tree/revwalk" class=
"bare">https://github.com/nasamuffin/git/tree/revwalk
</a>.
624 <h3 id=
"_struct_rev_cmdline_info"><code>struct
</code> <code>rev_cmdline_info
</code></h3>
625 <div class=
"paragraph">
626 <p>The definition of
<code>struct
</code> <code>rev_cmdline_info
</code> can be found in
<code>revision.h
</code>.
</p>
628 <div class=
"paragraph">
629 <p>This struct is contained within the
<code>rev_info
</code> struct and is used to reflect
630 parameters provided by the user over the CLI.
</p>
632 <div class=
"paragraph">
633 <p><code>nr
</code> represents the number of
<code>rev_cmdline_entry
</code> present in the array.
</p>
635 <div class=
"paragraph">
636 <p><code>alloc
</code> is used by the
<code>ALLOC_GROW
</code> macro. Check
<code>alloc.h
</code> - this variable is
637 used to track the allocated size of the list.
</p>
639 <div class=
"paragraph">
640 <p>Per entry, we find:
</p>
642 <div class=
"paragraph">
643 <p><code>item
</code> is the object provided upon which to base the object walk. Items in Git
644 can be blobs, trees, commits, or tags. (See
<code>Documentation/gittutorial-
2.txt
</code>.)
</p>
646 <div class=
"paragraph">
647 <p><code>name
</code> is the object ID (OID) of the object - a hex string you may be familiar
648 with from using Git to organize your source in the past. Check the tutorial
649 mentioned above towards the top for a discussion of where the OID can come
652 <div class=
"paragraph">
653 <p><code>whence
</code> indicates some information about what to do with the parents of the
654 specified object. We
’ll explore this flag more later on; take a look at
655 <code>Documentation/revisions.txt
</code> to get an idea of what could set the
<code>whence
</code>
658 <div class=
"paragraph">
659 <p><code>flags
</code> are used to hint the beginning of the revision walk and are the first
660 block under the #include`s
<code>in
</code> `revision.
<code>h
</code>. The most likely ones to be set in
661 the
<code>rev_cmdline_info
</code> are
<code>UNINTERESTING
</code> and
<code>BOTTOM
</code>, but these same flags
662 can be used during the walk, as well.
</p>
666 <h3 id=
"_struct_rev_info"><code>struct
</code> <code>rev_info
</code></h3>
667 <div class=
"paragraph">
668 <p>This one is quite a bit longer, and many fields are only used during the walk
669 by
<code>revision.c
</code> - not configuration options. Most of the configurable flags in
670 <code>struct
</code> <code>rev_info
</code> have a mirror in
<code>Documentation/rev-list-options.txt
</code>. It
’s a
671 good idea to take some time and read through that document.
</p>
677 <h2 id=
"_basic_commit_walk">Basic Commit Walk
</h2>
678 <div class=
"sectionbody">
679 <div class=
"paragraph">
680 <p>First, let
’s see if we can replicate the output of
<code>git
</code> <code>log
</code> <code>--oneline
</code>. We
’ll
681 refer back to the implementation frequently to discover norms when performing
682 an object walk of our own.
</p>
684 <div class=
"paragraph">
685 <p>To do so, we
’ll first find all the commits, in order, which preceded the current
686 commit. We
’ll extract the name and subject of the commit from each.
</p>
688 <div class=
"paragraph">
689 <p>Ideally, we will also be able to find out which ones are currently at the tip of
690 various branches.
</p>
693 <h3 id=
"_setting_up_2">Setting Up
</h3>
694 <div class=
"paragraph">
695 <p>Preparing for your object walk has some distinct stages.
</p>
697 <div class=
"olist arabic">
700 <p>Perform default setup for this mode, and others which may be invoked.
</p>
703 <p>Check configuration files for relevant settings.
</p>
706 <p>Set up the
<code>rev_info
</code> struct.
</p>
709 <p>Tweak the initialized
<code>rev_info
</code> to suit the current walk.
</p>
712 <p>Prepare the
<code>rev_info
</code> for the walk.
</p>
715 <p>Iterate over the objects, processing each one.
</p>
720 <h4 id=
"_default_setups">Default Setups
</h4>
721 <div class=
"paragraph">
722 <p>Before examining configuration files which may modify command behavior, set up
723 default state for switches or options your command may have. If your command
724 utilizes other Git components, ask them to set up their default states as well.
725 For instance,
<code>git
</code> <code>log
</code> takes advantage of
<code>grep
</code> and
<code>diff
</code> functionality, so
726 its
<code>init_log_defaults
</code>() sets its own state (
<code>decoration_style
</code>) and asks
727 <code>grep
</code> and
<code>diff
</code> to initialize themselves by calling each of their
728 initialization functions.
</p>
732 <h4 id=
"_configuring_from_gitconfig">Configuring From .
<code>gitconfig
</code></h4>
733 <div class=
"paragraph">
734 <p>Next, we should have a look at any relevant configuration settings (i.e.,
735 settings readable and settable from
<code>git
</code> <code>config
</code>). This is done by providing a
736 callback to
<code>git_config
</code>(); within that callback, you can also invoke methods
737 from other components you may need that need to intercept these options. Your
738 callback will be invoked once per each configuration value which Git knows about
739 (global, local, worktree, etc.).
</p>
741 <div class=
"paragraph">
742 <p>Similarly to the default values, we don
’t have anything to do here yet
743 ourselves; however, we should call
<code>git_default_config
</code>() if we aren
’t calling
744 any other existing config callbacks.
</p>
746 <div class=
"paragraph">
747 <p>Add a new function to
<code>builtin/walken.c
</code>.
748 We
’ll also need to include the
<code>config.h
</code> header:
</p>
750 <div class=
"listingblock">
751 <div class=
"content">
752 <pre>#include
"config.h"
756 static int git_walken_config(const char *var, const char *value,
757 const struct config_context *ctx, void *cb)
760 * For now, we don't have any custom configuration, so fall back to
761 * the default config.
763 return git_default_config(var, value, ctx, cb);
767 <div class=
"paragraph">
768 <p>Make sure to invoke
<code>git_config
</code>() with it in your
<code>cmd_walken
</code>():
</p>
770 <div class=
"listingblock">
771 <div class=
"content">
772 <pre>int cmd_walken(int argc, const char **argv, const char *prefix)
776 git_config(git_walken_config, NULL);
784 <h4 id=
"_setting_up_rev_info">Setting Up
<code>rev_info
</code></h4>
785 <div class=
"paragraph">
786 <p>Now that we
’ve gathered external configuration and options, it
’s time to
787 initialize the
<code>rev_info
</code> object which we will use to perform the walk. This is
788 typically done by calling
<code>repo_init_revisions
</code>() with the repository you intend
789 to target, as well as the
<code>prefix
</code> argument of
<code>cmd_walken
</code> and your
<code>rev_info
</code>
792 <div class=
"paragraph">
793 <p>Add the
<code>struct
</code> <code>rev_info
</code> and the
<code>repo_init_revisions
</code>() call.
794 We
’ll also need to include the
<code>revision.h
</code> header:
</p>
796 <div class=
"listingblock">
797 <div class=
"content">
798 <pre>#include
"revision.h"
802 int cmd_walken(int argc, const char **argv, const char *prefix)
804 /* This can go wherever you like in your declarations.*/
808 /* This should go after the git_config() call. */
809 repo_init_revisions(the_repository,
&rev, prefix);
817 <h4 id=
"_tweaking_rev_info_for_the_walk">Tweaking
<code>rev_info
</code> For the Walk
</h4>
818 <div class=
"paragraph">
819 <p>We
’re getting close, but we
’re still not quite ready to go. Now that
<code>rev
</code> is
820 initialized, we can modify it to fit our needs. This is usually done within a
821 helper for clarity, so let
’s add one:
</p>
823 <div class=
"listingblock">
824 <div class=
"content">
825 <pre>static void final_rev_info_setup(struct rev_info *rev)
828 * We want to mimic the appearance of `git log --oneline`, so let's
829 * force oneline format.
831 get_commit_format(
"oneline", rev);
833 /* Start our object walk at HEAD. */
834 add_head_to_pending(rev);
838 <div class=
"admonitionblock note">
842 <div class=
"title">Note
</div>
845 <div class=
"paragraph">
846 <p>Instead of using the shorthand
<code>add_head_to_pending
</code>(), you could do
847 something like this:
</p>
849 <div class=
"listingblock">
850 <div class=
"content">
851 <pre> struct setup_revision_opt opt;
853 memset(
&opt,
0, sizeof(opt));
855 opt.revarg_opt = REVARG_COMMITTISH;
856 setup_revisions(argc, argv, rev,
&opt);
</pre>
859 <div class=
"paragraph">
860 <p>Using a
<code>setup_revision_opt
</code> gives you finer control over your walk
’s starting
867 <div class=
"paragraph">
868 <p>Then let
’s invoke
<code>final_rev_info_setup
</code>() after the call to
869 <code>repo_init_revisions
</code>():
</p>
871 <div class=
"listingblock">
872 <div class=
"content">
873 <pre>int cmd_walken(int argc, const char **argv, const char *prefix)
877 final_rev_info_setup(
&rev);
883 <div class=
"paragraph">
884 <p>Later, we may wish to add more arguments to
<code>final_rev_info_setup
</code>(). But for
885 now, this is all we need.
</p>
889 <h4 id=
"_preparing_rev_info_for_the_walk">Preparing
<code>rev_info
</code> For the Walk
</h4>
890 <div class=
"paragraph">
891 <p>Now that
<code>rev
</code> is all initialized and configured, we
’ve got one more setup step
892 before we get rolling. We can do this in a helper, which will both prepare the
893 <code>rev_info
</code> for the walk, and perform the walk itself. Let
’s start the helper
894 with the call to
<code>prepare_revision_walk
</code>(), which can return an error without
895 dying on its own:
</p>
897 <div class=
"listingblock">
898 <div class=
"content">
899 <pre>static void walken_commit_walk(struct rev_info *rev)
901 if (prepare_revision_walk(rev))
902 die(_(
"revision walk setup failed"));
906 <div class=
"admonitionblock note">
910 <div class=
"title">Note
</div>
913 <code>die
</code>() prints to
<code>stderr
</code> and exits the program. Since it will print to
914 <code>stderr
</code> it
’s likely to be seen by a human, so we will localize it.
921 <h4 id=
"_performing_the_walk">Performing the Walk!
</h4>
922 <div class=
"paragraph">
923 <p>Finally! We are ready to begin the walk itself. Now we can see that
<code>rev_info
</code>
924 can also be used as an iterator; we move to the next item in the walk by using
925 <code>get_revision
</code>() repeatedly. Add the listed variable declarations at the top and
926 the walk loop below the
<code>prepare_revision_walk
</code>() call within your
927 <code>walken_commit_walk
</code>():
</p>
929 <div class=
"listingblock">
930 <div class=
"content">
931 <pre>#include
"pretty.h"
935 static void walken_commit_walk(struct rev_info *rev)
937 struct commit *commit;
938 struct strbuf prettybuf = STRBUF_INIT;
942 while ((commit = get_revision(rev))) {
943 strbuf_reset(
&prettybuf);
944 pp_commit_easy(CMIT_FMT_ONELINE, commit,
&prettybuf);
947 strbuf_release(
&prettybuf);
951 <div class=
"admonitionblock note">
955 <div class=
"title">Note
</div>
958 <code>puts
</code>() prints a
<code>char
</code>* to
<code>stdout
</code>. Since this is the part of the
959 command we expect to be machine-parsed, we
’re sending it directly to stdout.
964 <div class=
"paragraph">
965 <p>Give it a shot.
</p>
967 <div class=
"listingblock">
968 <div class=
"content">
970 $ ./bin-wrappers/git walken
</pre>
973 <div class=
"paragraph">
974 <p>You should see all of the subject lines of all the commits in
975 your tree
’s history, in order, ending with the initial commit,
"Initial revision
976 of "git
", the information manager from hell". Congratulations! You
’ve written
977 your first revision walk. You can play with printing some additional fields
978 from each commit if you
’re curious; have a look at the functions available in
979 <code>commit.h
</code>.
</p>
984 <h3 id=
"_adding_a_filter">Adding a Filter
</h3>
985 <div class=
"paragraph">
986 <p>Next, let
’s try to filter the commits we see based on their author. This is
987 equivalent to running
<code>git
</code> <code>log
</code> <code>--author=
</code><em><pattern
></em>. We can add a filter by
988 modifying
<code>rev_info.grep_filter
</code>, which is a
<code>struct
</code> <code>grep_opt
</code>.
</p>
990 <div class=
"paragraph">
991 <p>First some setup. Add
<code>grep_config
</code>() to
<code>git_walken_config
</code>():
</p>
993 <div class=
"listingblock">
994 <div class=
"content">
995 <pre>static int git_walken_config(const char *var, const char *value,
996 const struct config_context *ctx, void *cb)
998 grep_config(var, value, ctx, cb);
999 return git_default_config(var, value, ctx, cb);
1003 <div class=
"paragraph">
1004 <p>Next, we can modify the
<code>grep_filter
</code>. This is done with convenience functions
1005 found in
<code>grep.h
</code>. For fun, we
’re filtering to only commits from folks using a
1006 <code>gmail.com
</code> email address - a not-very-precise guess at who may be working on
1007 Git as a hobby. Since we
’re checking the author, which is a specific line in the
1008 header, we
’ll use the
<code>append_header_grep_pattern
</code>() helper. We can use
1009 the
<code>enum
</code> <code>grep_header_field
</code> to indicate which part of the commit header we want
1012 <div class=
"paragraph">
1013 <p>In
<code>final_rev_info_setup
</code>(), add your filter line:
</p>
1015 <div class=
"listingblock">
1016 <div class=
"content">
1017 <pre>static void final_rev_info_setup(int argc, const char **argv,
1018 const char *prefix, struct rev_info *rev)
1022 append_header_grep_pattern(
&rev-
>grep_filter, GREP_HEADER_AUTHOR,
1024 compile_grep_patterns(
&rev-
>grep_filter);
1030 <div class=
"paragraph">
1031 <p><code>append_header_grep_pattern
</code>() adds your new
"gmail" pattern to
<code>rev_info
</code>, but
1032 it won
’t work unless we compile it with
<code>compile_grep_patterns
</code>().
</p>
1034 <div class=
"admonitionblock note">
1038 <div class=
"title">Note
</div>
1040 <td class=
"content">
1041 If you are using
<code>setup_revisions
</code>() (for example, if you are passing a
1042 <code>setup_revision_opt
</code> instead of using
<code>add_head_to_pending
</code>()), you don
’t need
1043 to call
<code>compile_grep_patterns
</code>() because
<code>setup_revisions
</code>() calls it for you.
1048 <div class=
"admonitionblock note">
1052 <div class=
"title">Note
</div>
1054 <td class=
"content">
1055 We could add the same filter via the
<code>append_grep_pattern
</code>() helper if we
1056 wanted to, but
<code>append_header_grep_pattern
</code>() adds the
<code>enum
</code> <code>grep_context
</code> and
1057 <code>enum
</code> <code>grep_pat_token
</code> for us.
1064 <h3 id=
"_changing_the_order">Changing the Order
</h3>
1065 <div class=
"paragraph">
1066 <p>There are a few ways that we can change the order of the commits during a
1067 revision walk. Firstly, we can use the
<code>enum
</code> <code>rev_sort_order
</code> to choose from some
1068 typical orderings.
</p>
1070 <div class=
"paragraph">
1071 <p><code>topo_order
</code> is the same as
<code>git
</code> <code>log
</code> <code>--topo-order
</code>: we avoid showing a parent
1072 before all of its children have been shown, and we avoid mixing commits which
1073 are in different lines of history. (
<code>git
</code> <code>help
</code> <code>log
</code>'s section on
<code>--topo-order
</code>
1074 has a very nice diagram to illustrate this.)
</p>
1076 <div class=
"paragraph">
1077 <p>Let
’s see what happens when we run with
<code>REV_SORT_BY_COMMIT_DATE
</code> as opposed to
1078 <code>REV_SORT_BY_AUTHOR_DATE
</code>. Add the following:
</p>
1080 <div class=
"listingblock">
1081 <div class=
"content">
1082 <pre>static void final_rev_info_setup(int argc, const char **argv,
1083 const char *prefix, struct rev_info *rev)
1087 rev-
>topo_order =
1;
1088 rev-
>sort_order = REV_SORT_BY_COMMIT_DATE;
1094 <div class=
"paragraph">
1095 <p>Let
’s output this into a file so we can easily diff it with the walk sorted by
1098 <div class=
"listingblock">
1099 <div class=
"content">
1101 $ ./bin-wrappers/git walken
> commit-date.txt
</pre>
1104 <div class=
"paragraph">
1105 <p>Then, let
’s sort by author date and run it again.
</p>
1107 <div class=
"listingblock">
1108 <div class=
"content">
1109 <pre>static void final_rev_info_setup(int argc, const char **argv,
1110 const char *prefix, struct rev_info *rev)
1114 rev-
>topo_order =
1;
1115 rev-
>sort_order = REV_SORT_BY_AUTHOR_DATE;
1121 <div class=
"listingblock">
1122 <div class=
"content">
1124 $ ./bin-wrappers/git walken
> author-date.txt
</pre>
1127 <div class=
"paragraph">
1128 <p>Finally, compare the two. This is a little less helpful without object names or
1129 dates, but hopefully we get the idea.
</p>
1131 <div class=
"listingblock">
1132 <div class=
"content">
1133 <pre>$ diff -u commit-date.txt author-date.txt
</pre>
1136 <div class=
"paragraph">
1137 <p>This display indicates that commits can be reordered after they
’re written, for
1138 example with
<code>git
</code> <code>rebase
</code>.
</p>
1140 <div class=
"paragraph">
1141 <p>Let
’s try one more reordering of commits.
<code>rev_info
</code> exposes a
<code>reverse
</code> flag.
1142 Set that flag somewhere inside of
<code>final_rev_info_setup
</code>():
</p>
1144 <div class=
"listingblock">
1145 <div class=
"content">
1146 <pre>static void final_rev_info_setup(int argc, const char **argv, const char *prefix,
1147 struct rev_info *rev)
1151 rev-
>reverse =
1;
1157 <div class=
"paragraph">
1158 <p>Run your walk again and note the difference in order. (If you remove the grep
1159 pattern, you should see the last commit this call gives you as your current
1166 <h2 id=
"_basic_object_walk">Basic Object Walk
</h2>
1167 <div class=
"sectionbody">
1168 <div class=
"paragraph">
1169 <p>So far we
’ve been walking only commits. But Git has more types of objects than
1170 that! Let
’s see if we can walk
<em>all
</em> objects, and find out some information
1173 <div class=
"paragraph">
1174 <p>We can base our work on an example.
<code>git
</code> <code>pack-objects
</code> prepares all kinds of
1175 objects for packing into a bitmap or packfile. The work we are interested in
1176 resides in
<code>builtin/pack-objects.c:get_object_list
</code>(); examination of that
1177 function shows that the all-object walk is being performed by
1178 <code>traverse_commit_list
</code>() or
<code>traverse_commit_list_filtered
</code>(). Those two
1179 functions reside in
<code>list-objects.c
</code>; examining the source shows that, despite
1180 the name, these functions traverse all kinds of objects. Let
’s have a look at
1181 the arguments to
<code>traverse_commit_list
</code>().
</p>
1186 <p><code>struct
</code> <code>rev_info
</code> *revs: This is the
<code>rev_info
</code> used for the walk. If
1187 its
<code>filter
</code> member is not
<code>NULL
</code>, then
<code>filter
</code> contains information for
1188 how to filter the object list.
</p>
1191 <p><code>show_commit_fn
</code> <code>show_commit
</code>: A callback which will be used to handle each
1192 individual commit object.
</p>
1195 <p><code>show_object_fn
</code> <code>show_object
</code>: A callback which will be used to handle each
1196 non-commit object (so each blob, tree, or tag).
</p>
1199 <p><code>void
</code> *show_data: A context buffer which is passed in turn to
<code>show_commit
</code>
1200 and
<code>show_object
</code>.
</p>
1204 <div class=
"paragraph">
1205 <p>In addition,
<code>traverse_commit_list_filtered
</code>() has an additional parameter:
</p>
1210 <p><code>struct
</code> <code>oidset
</code> *omitted: A linked-list of object IDs which the provided
1211 filter caused to be omitted.
</p>
1215 <div class=
"paragraph">
1216 <p>It looks like these methods use callbacks we provide instead of needing us
1217 to call it repeatedly ourselves. Cool! Let
’s add the callbacks first.
</p>
1219 <div class=
"paragraph">
1220 <p>For the sake of this tutorial, we
’ll simply keep track of how many of each kind
1221 of object we find. At file scope in
<code>builtin/walken.c
</code> add the following
1222 tracking variables:
</p>
1224 <div class=
"listingblock">
1225 <div class=
"content">
1226 <pre>static int commit_count;
1227 static int tag_count;
1228 static int blob_count;
1229 static int tree_count;
</pre>
1232 <div class=
"paragraph">
1233 <p>Commits are handled by a different callback than other objects; let
’s do that
1236 <div class=
"listingblock">
1237 <div class=
"content">
1238 <pre>static void walken_show_commit(struct commit *cmt, void *buf)
1244 <div class=
"paragraph">
1245 <p>The
<code>cmt
</code> argument is fairly self-explanatory. But it
’s worth mentioning that
1246 the
<code>buf
</code> argument is actually the context buffer that we can provide to the
1247 traversal calls -
<code>show_data
</code>, which we mentioned a moment ago.
</p>
1249 <div class=
"paragraph">
1250 <p>Since we have the
<code>struct
</code> <code>commit
</code> object, we can look at all the same parts that
1251 we looked at in our earlier commit-only walk. For the sake of this tutorial,
1252 though, we
’ll just increment the commit counter and move on.
</p>
1254 <div class=
"paragraph">
1255 <p>The callback for non-commits is a little different, as we
’ll need to check
1256 which kind of object we
’re dealing with:
</p>
1258 <div class=
"listingblock">
1259 <div class=
"content">
1260 <pre>static void walken_show_object(struct object *obj, const char *str, void *buf)
1262 switch (obj-
>type) {
1273 BUG(
"unexpected commit object in walken_show_object\n");
1275 BUG(
"unexpected object type %s in walken_show_object\n",
1276 type_name(obj-
>type));
1281 <div class=
"paragraph">
1282 <p>Again,
<code>obj
</code> is fairly self-explanatory, and we can guess that
<code>buf
</code> is the same
1283 context pointer that
<code>walken_show_commit
</code>() receives: the
<code>show_data
</code> argument
1284 to
<code>traverse_commit_list
</code>() and
<code>traverse_commit_list_filtered
</code>(). Finally,
1285 <code>str
</code> contains the name of the object, which ends up being something like
1286 <code>foo.txt
</code> (blob),
<code>bar/baz
</code> (tree), or
<code>v1.2
.3</code> (tag).
</p>
1288 <div class=
"paragraph">
1289 <p>To help assure us that we aren
’t double-counting commits, we
’ll include some
1290 complaining if a commit object is routed through our non-commit callback; we
’ll
1291 also complain if we see an invalid object type. Since those two cases should be
1292 unreachable, and would only change in the event of a semantic change to the Git
1293 codebase, we complain by using
<code>BUG
</code>() - which is a signal to a developer that
1294 the change they made caused unintended consequences, and the rest of the
1295 codebase needs to be updated to understand that change.
<code>BUG
</code>() is not intended
1296 to be seen by the public, so it is not localized.
</p>
1298 <div class=
"paragraph">
1299 <p>Our main object walk implementation is substantially different from our commit
1300 walk implementation, so let
’s make a new function to perform the object walk. We
1301 can perform setup which is applicable to all objects here, too, to keep separate
1302 from setup which is applicable to commit-only walks.
</p>
1304 <div class=
"paragraph">
1305 <p>We
’ll start by enabling all types of objects in the
<code>struct
</code> <code>rev_info
</code>. We
’ll
1306 also turn on
<code>tree_blobs_in_commit_order
</code>, which means that we will walk a
1307 commit
’s tree and everything it points to immediately after we find each commit,
1308 as opposed to waiting for the end and walking through all trees after the commit
1309 history has been discovered. With the appropriate settings configured, we are
1310 ready to call
<code>prepare_revision_walk
</code>().
</p>
1312 <div class=
"listingblock">
1313 <div class=
"content">
1314 <pre>static void walken_object_walk(struct rev_info *rev)
1316 rev-
>tree_objects =
1;
1317 rev-
>blob_objects =
1;
1318 rev-
>tag_objects =
1;
1319 rev-
>tree_blobs_in_commit_order =
1;
1321 if (prepare_revision_walk(rev))
1322 die(_(
"revision walk setup failed"));
1327 tree_count =
0;
</pre>
1330 <div class=
"paragraph">
1331 <p>Let
’s start by calling just the unfiltered walk and reporting our counts.
1332 Complete your implementation of
<code>walken_object_walk
</code>().
1333 We
’ll also need to include the
<code>list-objects.h
</code> header.
</p>
1335 <div class=
"listingblock">
1336 <div class=
"content">
1337 <pre>#include
"list-objects.h"
1341 traverse_commit_list(rev, walken_show_commit, walken_show_object, NULL);
1343 printf(
"commits %d\nblobs %d\ntags %d\ntrees %d\n", commit_count,
1344 blob_count, tag_count, tree_count);
1348 <div class=
"admonitionblock note">
1352 <div class=
"title">Note
</div>
1354 <td class=
"content">
1355 This output is intended to be machine-parsed. Therefore, we are not
1356 sending it to
<code>trace_printf
</code>(), and we are not localizing it - we need scripts
1357 to be able to count on the formatting to be exactly the way it is shown here.
1358 If we were intending this output to be read by humans, we would need to localize
1359 it with
<code>_
</code>().
1364 <div class=
"paragraph">
1365 <p>Finally, we
’ll ask
<code>cmd_walken
</code>() to use the object walk instead. Discussing
1366 command line options is out of scope for this tutorial, so we
’ll just hardcode
1367 a branch we can change at compile time. Where you call
<code>final_rev_info_setup
</code>()
1368 and
<code>walken_commit_walk
</code>(), instead branch like so:
</p>
1370 <div class=
"listingblock">
1371 <div class=
"content">
1373 add_head_to_pending(
&rev);
1374 walken_object_walk(
&rev);
1376 final_rev_info_setup(argc, argv, prefix,
&rev);
1377 walken_commit_walk(
&rev);
1381 <div class=
"admonitionblock note">
1385 <div class=
"title">Note
</div>
1387 <td class=
"content">
1388 For simplicity, we
’ve avoided all the filters and sorts we applied in
1389 <code>final_rev_info_setup
</code>() and simply added
<code>HEAD
</code> to our pending queue. If you
1390 want, you can certainly use the filters we added before by moving
1391 <code>final_rev_info_setup
</code>() out of the conditional and removing the call to
1392 <code>add_head_to_pending
</code>().
1397 <div class=
"paragraph">
1398 <p>Now we can try to run our command! It should take noticeably longer than the
1399 commit walk, but an examination of the output will give you an idea why. Your
1400 output should look similar to this example, but with different counts:
</p>
1402 <div class=
"listingblock">
1403 <div class=
"content">
1404 <pre>Object walk completed. Found
55733 commits,
100274 blobs,
0 tags, and
104210 trees.
</pre>
1407 <div class=
"paragraph">
1408 <p>This makes sense. We have more trees than commits because the Git project has
1409 lots of subdirectories which can change, plus at least one tree per commit. We
1410 have no tags because we started on a commit (
<code>HEAD
</code>) and while tags can point to
1411 commits, commits can
’t point to tags.
</p>
1413 <div class=
"admonitionblock note">
1417 <div class=
"title">Note
</div>
1419 <td class=
"content">
1420 You will have different counts when you run this yourself! The number of
1421 objects grows along with the Git project.
1427 <h3 id=
"_adding_a_filter_2">Adding a Filter
</h3>
1428 <div class=
"paragraph">
1429 <p>There are a handful of filters that we can apply to the object walk laid out in
1430 <code>Documentation/rev-list-options.txt
</code>. These filters are typically useful for
1431 operations such as creating packfiles or performing a partial clone. They are
1432 defined in
<code>list-objects-filter-options.h
</code>. For the purposes of this tutorial we
1433 will use the
"tree:1" filter, which causes the walk to omit all trees and blobs
1434 which are not directly referenced by commits reachable from the commit in
1435 <code>pending
</code> when the walk begins. (
<code>pending
</code> is the list of objects which need to
1436 be traversed during a walk; you can imagine a breadth-first tree traversal to
1437 help understand. In our case, that means we omit trees and blobs not directly
1438 referenced by
<code>HEAD
</code> or
<code>HEAD
</code>'s history, because we begin the walk with only
1439 <code>HEAD
</code> in the
<code>pending
</code> list.)
</p>
1441 <div class=
"paragraph">
1442 <p>For now, we are not going to track the omitted objects, so we
’ll replace those
1443 parameters with
<code>NULL
</code>. For the sake of simplicity, we
’ll add a simple
1444 build-time branch to use our filter or not. Preface the line calling
1445 <code>traverse_commit_list
</code>() with the following, which will remind us which kind of
1446 walk we
’ve just performed:
</p>
1448 <div class=
"listingblock">
1449 <div class=
"content">
1452 trace_printf(_(
"Unfiltered object walk.\n"));
1455 _(
"Filtered object walk with filterspec 'tree:1'.\n"));
1457 parse_list_objects_filter(
&rev-
>filter,
"tree:1");
1459 traverse_commit_list(rev, walken_show_commit,
1460 walken_show_object, NULL);
</pre>
1463 <div class=
"paragraph">
1464 <p>The
<code>rev-
</code>><code>filter
</code> member is usually built directly from a command
1465 line argument, so the module provides an easy way to build one from a string.
1466 Even though we aren
’t taking user input right now, we can still build one with
1467 a hardcoded string using
<code>parse_list_objects_filter
</code>().
</p>
1469 <div class=
"paragraph">
1470 <p>With the filter spec
"tree:1", we are expecting to see
<em>only
</em> the root tree for
1471 each commit; therefore, the tree object count should be less than or equal to
1472 the number of commits. (For an example of why that
’s true:
<code>git
</code> <code>commit
</code> <code>--revert
</code>
1473 points to the same tree object as its grandparent.)
</p>
1477 <h3 id=
"_counting_omitted_objects">Counting Omitted Objects
</h3>
1478 <div class=
"paragraph">
1479 <p>We also have the capability to enumerate all objects which were omitted by a
1480 filter, like with
<code>git
</code> <code>log
</code> <code>--filter=
</code><em><spec
></em> <code>--filter-print-omitted
</code>. To do this,
1481 change
<code>traverse_commit_list
</code>() to
<code>traverse_commit_list_filtered
</code>(), which is
1482 able to populate an
<code>omitted
</code> list. Asking for this list of filtered objects
1483 may cause performance degradations, however, because in this case, despite
1484 filtering objects, the possibly much larger set of all reachable objects must
1485 be processed in order to populate that list.
</p>
1487 <div class=
"paragraph">
1488 <p>First, add the
<code>struct
</code> <code>oidset
</code> and related items we will use to iterate it:
</p>
1490 <div class=
"listingblock">
1491 <div class=
"content">
1492 <pre>#include
"oidset.h"
1496 static void walken_object_walk(
1499 struct oidset omitted;
1500 struct oidset_iter oit;
1501 struct object_id *oid = NULL;
1502 int omitted_count =
0;
1503 oidset_init(
&omitted,
0);
1508 <div class=
"paragraph">
1509 <p>Replace the call to
<code>traverse_commit_list
</code>() with
1510 <code>traverse_commit_list_filtered
</code>() and pass a pointer to the
<code>omitted
</code> oidset
1511 defined and initialized above:
</p>
1513 <div class=
"listingblock">
1514 <div class=
"content">
1517 traverse_commit_list_filtered(rev,
1518 walken_show_commit, walken_show_object, NULL,
&omitted);
1523 <div class=
"paragraph">
1524 <p>Then, after your traversal, the
<code>oidset
</code> traversal is pretty straightforward.
1525 Count all the objects within and modify the print statement:
</p>
1527 <div class=
"listingblock">
1528 <div class=
"content">
1529 <pre> /* Count the omitted objects. */
1530 oidset_iter_init(
&omitted,
&oit);
1532 while ((oid = oidset_iter_next(
&oit)))
1535 printf(
"commits %d\nblobs %d\ntags %d\ntrees %d\nomitted %d\n",
1536 commit_count, blob_count, tag_count, tree_count, omitted_count);
</pre>
1539 <div class=
"paragraph">
1540 <p>By running your walk with and without the filter, you should find that the total
1541 object count in each case is identical. You can also time each invocation of
1542 the
<code>walken
</code> subcommand, with and without
<code>omitted
</code> being passed in, to confirm
1543 to yourself the runtime impact of tracking all omitted objects.
</p>
1547 <h3 id=
"_changing_the_order_2">Changing the Order
</h3>
1548 <div class=
"paragraph">
1549 <p>Finally, let
’s demonstrate that you can also reorder walks of all objects, not
1550 just walks of commits. First, we
’ll make our handlers chattier - modify
1551 <code>walken_show_commit
</code>() and
<code>walken_show_object
</code>() to print the object as they
1554 <div class=
"listingblock">
1555 <div class=
"content">
1556 <pre>#include
"hex.h"
1560 static void walken_show_commit(struct commit *cmt, void *buf)
1562 trace_printf(
"commit: %s\n", oid_to_hex(
&cmt-
>object.oid));
1566 static void walken_show_object(struct object *obj, const char *str, void *buf)
1568 trace_printf(
"%s: %s\n", type_name(obj-
>type), oid_to_hex(
&obj-
>oid));
1574 <div class=
"admonitionblock note">
1578 <div class=
"title">Note
</div>
1580 <td class=
"content">
1581 Since we will be examining this output directly as humans, we
’ll use
1582 <code>trace_printf
</code>() here. Additionally, since this change introduces a significant
1583 number of printed lines, using
<code>trace_printf
</code>() will allow us to easily silence
1584 those lines without having to recompile.
1589 <div class=
"paragraph">
1590 <p>(Leave the counter increment logic in place.)
</p>
1592 <div class=
"paragraph">
1593 <p>With only that change, run again (but save yourself some scrollback):
</p>
1595 <div class=
"listingblock">
1596 <div class=
"content">
1597 <pre>$ GIT_TRACE=
1 ./bin-wrappers/git walken
2>&1 | head -n
10</pre>
1600 <div class=
"paragraph">
1601 <p>Take a look at the top commit with
<code>git
</code> <code>show
</code> and the object ID you printed; it
1602 should be the same as the output of
<code>git
</code> <code>show
</code> <code>HEAD
</code>.
</p>
1604 <div class=
"paragraph">
1605 <p>Next, let
’s change a setting on our
<code>struct
</code> <code>rev_info
</code> within
1606 <code>walken_object_walk
</code>(). Find where you
’re changing the other settings on
<code>rev
</code>,
1607 such as
<code>rev-
</code>><code>tree_objects
</code> and
<code>rev-
</code>><code>tree_blobs_in_commit_order
</code>, and add the
1608 <code>reverse
</code> setting at the bottom:
</p>
1610 <div class=
"listingblock">
1611 <div class=
"content">
1614 rev-
>tree_objects =
1;
1615 rev-
>blob_objects =
1;
1616 rev-
>tag_objects =
1;
1617 rev-
>tree_blobs_in_commit_order =
1;
1618 rev-
>reverse =
1;
1623 <div class=
"paragraph">
1624 <p>Now, run again, but this time, let
’s grab the last handful of objects instead
1625 of the first handful:
</p>
1627 <div class=
"listingblock">
1628 <div class=
"content">
1630 $ GIT_TRACE=
1 ./bin-wrappers/git walken
2>&1 | tail -n
10</pre>
1633 <div class=
"paragraph">
1634 <p>The last commit object given should have the same OID as the one we saw at the
1635 top before, and running
<code>git
</code> <code>show
</code> <em><oid
></em> with that OID should give you again
1636 the same results as
<code>git
</code> <code>show
</code> <code>HEAD
</code>. Furthermore, if you run and examine the
1637 first ten lines again (with
<code>head
</code> instead of
<code>tail
</code> like we did before applying
1638 the
<code>reverse
</code> setting), you should see that now the first commit printed is the
1639 initial commit,
<code>e83c5163
</code>.
</p>
1645 <h2 id=
"_wrapping_up">Wrapping Up
</h2>
1646 <div class=
"sectionbody">
1647 <div class=
"paragraph">
1648 <p>Let
’s review. In this tutorial, we:
</p>
1653 <p>Built a commit walk from the ground up
</p>
1656 <p>Enabled a grep filter for that commit walk
</p>
1659 <p>Changed the sort order of that filtered commit walk
</p>
1662 <p>Built an object walk (tags, commits, trees, and blobs) from the ground up
</p>
1665 <p>Learned how to add a filter-spec to an object walk
</p>
1668 <p>Changed the display order of the filtered object walk
</p>
1676 <div id=
"footer-text">
1677 Last updated
2024-
04-
09 14:
45:
01 -
0700