Linux evo.fastest-server.com 5.14.0-284.1101.el9.tuxcare.11.els11.x86_64 #1 SMP PREEMPT_DYNAMIC Fri Aug 14 13:30:35 UTC 2026 x86_64
LiteSpeed
Server IP : 103.249.112.113 & Your IP : 216.73.217.135
Domains : 988 Domain
User : tanishks
Terminal
Auto Root
Create File
Create Folder
Localroot Suggester
Backdoor Destroyer
Readme
/
usr /
share /
doc /
git /
technical /
Delete
Unzip
Name
Size
Permission
Date
Action
api-error-handling.adoc
3.73
KB
-rw-r--r--
2025-11-17 16:38
api-error-handling.html
35.21
KB
-rw-r--r--
2026-04-05 23:58
api-index-skel.adoc
432
B
-rw-r--r--
2025-11-17 16:38
api-index.adoc
689
B
-rw-r--r--
2026-04-05 23:58
api-index.html
30.43
KB
-rw-r--r--
2026-04-05 23:59
api-index.sh
714
B
-rw-r--r--
2025-11-17 16:38
api-merge.adoc
1.06
KB
-rw-r--r--
2025-11-17 16:38
api-merge.html
31.51
KB
-rw-r--r--
2026-04-05 23:58
api-parse-options.adoc
13.01
KB
-rw-r--r--
2025-11-17 16:38
api-parse-options.html
49.44
KB
-rw-r--r--
2026-04-05 23:58
api-path-walk.adoc
3.27
KB
-rw-r--r--
2025-11-17 16:38
api-path-walk.html
34.28
KB
-rw-r--r--
2026-04-05 23:58
api-simple-ipc.adoc
4.74
KB
-rw-r--r--
2025-11-17 16:38
api-simple-ipc.html
35.49
KB
-rw-r--r--
2026-04-05 23:58
api-trace2.adoc
43.45
KB
-rw-r--r--
2025-11-17 16:38
api-trace2.html
86.12
KB
-rw-r--r--
2026-04-05 23:58
bitmap-format.adoc
14.66
KB
-rw-r--r--
2025-11-17 16:38
bitmap-format.html
49.31
KB
-rw-r--r--
2026-04-05 23:58
build-systems.adoc
7.96
KB
-rw-r--r--
2025-11-17 16:38
build-systems.html
41.02
KB
-rw-r--r--
2026-04-05 23:58
bundle-uri.adoc
26.12
KB
-rw-r--r--
2025-11-17 16:38
bundle-uri.html
63.08
KB
-rw-r--r--
2026-04-05 23:58
commit-graph.adoc
17.7
KB
-rw-r--r--
2025-11-17 16:38
commit-graph.html
52.61
KB
-rw-r--r--
2026-04-05 23:58
directory-rename-detection.adoc
5.08
KB
-rw-r--r--
2025-11-17 16:38
directory-rename-detection.html
36.33
KB
-rw-r--r--
2026-04-05 23:58
hash-function-transition.adoc
35.45
KB
-rw-r--r--
2025-11-17 16:38
hash-function-transition.html
75.42
KB
-rw-r--r--
2026-04-05 23:58
large-object-promisors.adoc
26.59
KB
-rw-r--r--
2025-11-17 16:38
large-object-promisors.html
62.72
KB
-rw-r--r--
2026-04-05 23:58
long-running-process-protocol.adoc
1.88
KB
-rw-r--r--
2025-11-17 16:38
long-running-process-protocol.html
32.18
KB
-rw-r--r--
2026-04-05 23:58
meson.build
1.49
KB
-rw-r--r--
2025-11-17 16:38
multi-pack-index.adoc
11.31
KB
-rw-r--r--
2025-11-17 16:38
multi-pack-index.html
44.62
KB
-rw-r--r--
2026-04-05 23:58
pack-heuristics.adoc
17.62
KB
-rw-r--r--
2025-11-17 16:38
pack-heuristics.html
54.83
KB
-rw-r--r--
2026-04-05 23:58
packfile-uri.adoc
3.66
KB
-rw-r--r--
2025-11-17 16:38
packfile-uri.html
34.64
KB
-rw-r--r--
2026-04-05 23:58
parallel-checkout.adoc
12.01
KB
-rw-r--r--
2025-11-17 16:38
parallel-checkout.html
44.27
KB
-rw-r--r--
2026-04-05 23:58
partial-clone.adoc
14.59
KB
-rw-r--r--
2025-11-17 16:38
partial-clone.html
48.96
KB
-rw-r--r--
2026-04-05 23:58
platform-support.adoc
8.95
KB
-rw-r--r--
2025-11-17 16:38
platform-support.html
40.71
KB
-rw-r--r--
2026-04-05 23:58
racy-git.adoc
8.91
KB
-rw-r--r--
2025-11-17 16:38
racy-git.html
41.04
KB
-rw-r--r--
2026-04-05 23:58
reftable.adoc
36.65
KB
-rw-r--r--
2025-11-17 16:38
reftable.html
86.46
KB
-rw-r--r--
2026-04-05 23:58
remembering-renames.adoc
29.71
KB
-rw-r--r--
2025-11-17 16:38
remembering-renames.html
65.78
KB
-rw-r--r--
2026-04-05 23:58
repository-version.adoc
3.19
KB
-rw-r--r--
2025-11-17 16:38
repository-version.html
33.92
KB
-rw-r--r--
2026-04-05 23:58
rerere.adoc
6.36
KB
-rw-r--r--
2025-11-17 16:38
rerere.html
38.33
KB
-rw-r--r--
2026-04-05 23:58
scalar.adoc
2.87
KB
-rw-r--r--
2025-11-17 16:38
scalar.html
33.61
KB
-rw-r--r--
2026-04-05 23:58
send-pack-pipeline.adoc
1.92
KB
-rw-r--r--
2025-11-17 16:38
send-pack-pipeline.html
32.41
KB
-rw-r--r--
2026-04-05 23:58
shallow.adoc
2.49
KB
-rw-r--r--
2025-11-17 16:38
shallow.html
32.77
KB
-rw-r--r--
2026-04-05 23:58
sparse-checkout.adoc
46.68
KB
-rw-r--r--
2025-11-17 16:38
sparse-checkout.html
92.36
KB
-rw-r--r--
2026-04-05 23:58
sparse-index.adoc
9.28
KB
-rw-r--r--
2025-11-17 16:38
sparse-index.html
41.79
KB
-rw-r--r--
2026-04-05 23:58
trivial-merge.adoc
4.16
KB
-rw-r--r--
2025-11-17 16:38
trivial-merge.html
35.33
KB
-rw-r--r--
2026-04-05 23:58
unit-tests.adoc
9.8
KB
-rw-r--r--
2025-11-17 16:38
unit-tests.html
50.73
KB
-rw-r--r--
2026-04-05 23:58
Save
Rename
<!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml" lang="en"> <head> <meta charset="UTF-8"/> <meta http-equiv="X-UA-Compatible" content="IE=edge"/> <meta name="viewport" content="width=device-width, initial-scale=1.0"/> <meta name="generator" content="Asciidoctor 2.0.12"/> <title>1. Assumptions</title> <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"/> <style> /* Asciidoctor default stylesheet | MIT License | https://asciidoctor.org */ /* Uncomment @import statement to use as custom stylesheet */ /*@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";*/ article,aside,details,figcaption,figure,footer,header,hgroup,main,nav,section{display:block} audio,video{display:inline-block} audio:not([controls]){display:none;height:0} html{font-family:sans-serif;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%} a{background:none} a:focus{outline:thin dotted} a:active,a:hover{outline:0} h1{font-size:2em;margin:.67em 0} abbr[title]{border-bottom:1px dotted} b,strong{font-weight:bold} dfn{font-style:italic} hr{-moz-box-sizing:content-box;box-sizing:content-box;height:0} mark{background:#ff0;color:#000} code,kbd,pre,samp{font-family:monospace;font-size:1em} pre{white-space:pre-wrap} q{quotes:"\201C" "\201D" "\2018" "\2019"} small{font-size:80%} sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline} sup{top:-.5em} sub{bottom:-.25em} img{border:0} svg:not(:root){overflow:hidden} figure{margin:0} fieldset{border:1px solid silver;margin:0 2px;padding:.35em .625em .75em} legend{border:0;padding:0} button,input,select,textarea{font-family:inherit;font-size:100%;margin:0} button,input{line-height:normal} button,select{text-transform:none} button,html input[type="button"],input[type="reset"],input[type="submit"]{-webkit-appearance:button;cursor:pointer} button[disabled],html input[disabled]{cursor:default} input[type="checkbox"],input[type="radio"]{box-sizing:border-box;padding:0} button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0} textarea{overflow:auto;vertical-align:top} table{border-collapse:collapse;border-spacing:0} *,*::before,*::after{-moz-box-sizing:border-box;-webkit-box-sizing:border-box;box-sizing:border-box} html,body{font-size:100%} body{background:#fff;color:rgba(0,0,0,.8);padding:0;margin:0;font-family:"Noto Serif","DejaVu Serif",serif;font-weight:400;font-style:normal;line-height:1;position:relative;cursor:auto;tab-size:4;word-wrap:anywhere;-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased} a:hover{cursor:pointer} img,object,embed{max-width:100%;height:auto} object,embed{height:100%} img{-ms-interpolation-mode:bicubic} .left{float:left!important} .right{float:right!important} .text-left{text-align:left!important} .text-right{text-align:right!important} .text-center{text-align:center!important} .text-justify{text-align:justify!important} .hide{display:none} img,object,svg{display:inline-block;vertical-align:middle} textarea{height:auto;min-height:50px} select{width:100%} .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} 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} a{color:#2156a5;text-decoration:underline;line-height:inherit} a:hover,a:focus{color:#1d4b8f} a img{border:0} p{font-family:inherit;font-weight:400;font-size:1em;line-height:1.6;margin-bottom:1.25em;text-rendering:optimizeLegibility} p aside{font-size:.875em;line-height:1.35;font-style:italic} 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} 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} h1{font-size:2.125em} h2{font-size:1.6875em} h3,#toctitle,.sidebarblock>.content>.title{font-size:1.375em} h4,h5{font-size:1.125em} h6{font-size:1em} hr{border:solid #dddddf;border-width:1px 0 0;clear:both;margin:1.25em 0 1.1875em;height:0} em,i{font-style:italic;line-height:inherit} strong,b{font-weight:bold;line-height:inherit} small{font-size:60%;line-height:inherit} code{font-family:"Droid Sans Mono","DejaVu Sans Mono",monospace;font-weight:400;color:rgba(0,0,0,.9)} ul,ol,dl{font-size:1em;line-height:1.6;margin-bottom:1.25em;list-style-position:outside;font-family:inherit} ul,ol{margin-left:1.5em} ul li ul,ul li ol{margin-left:1.25em;margin-bottom:0;font-size:1em} ul.square li ul,ul.circle li ul,ul.disc li ul{list-style:inherit} ul.square{list-style-type:square} ul.circle{list-style-type:circle} ul.disc{list-style-type:disc} ol li ul,ol li ol{margin-left:1.25em;margin-bottom:0} dl dt{margin-bottom:.3125em;font-weight:bold} dl dd{margin-bottom:1.25em} abbr,acronym{text-transform:uppercase;font-size:90%;color:rgba(0,0,0,.8);border-bottom:1px dotted #ddd;cursor:help} abbr{text-transform:none} blockquote{margin:0 0 1.25em;padding:.5625em 1.25em 0 1.1875em;border-left:1px solid #ddd} blockquote cite{display:block;font-size:.9375em;color:rgba(0,0,0,.6)} blockquote cite::before{content:"\2014 \0020"} blockquote cite a,blockquote cite a:visited{color:rgba(0,0,0,.6)} blockquote,blockquote p{line-height:1.6;color:rgba(0,0,0,.85)} @media screen and (min-width:768px){h1,h2,h3,#toctitle,.sidebarblock>.content>.title,h4,h5,h6{line-height:1.2} h1{font-size:2.75em} h2{font-size:2.3125em} h3,#toctitle,.sidebarblock>.content>.title{font-size:1.6875em} h4{font-size:1.4375em}} table{background:#fff;margin-bottom:1.25em;border:solid 1px #dedede;word-wrap:normal} table thead,table tfoot{background:#f7f8f7} 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} table tr th,table tr td{padding:.5625em .625em;font-size:inherit;color:rgba(0,0,0,.8)} table tr.even,table tr.alt{background:#f8f8f7} table thead tr th,table tfoot tr th,table tbody tr td,table tr td,table tfoot tr td{line-height:1.6} h1,h2,h3,#toctitle,.sidebarblock>.content>.title,h4,h5,h6{line-height:1.2;word-spacing:-.05em} h1 strong,h2 strong,h3 strong,#toctitle strong,.sidebarblock>.content>.title strong,h4 strong,h5 strong,h6 strong{font-weight:400} .center{margin-left:auto;margin-right:auto} .stretch{width:100%} .clearfix::before,.clearfix::after,.float-group::before,.float-group::after{content:" ";display:table} .clearfix::after,.float-group::after{clear:both} :not(pre).nobreak{word-wrap:normal} :not(pre).nowrap{white-space:nowrap} :not(pre).pre-wrap{white-space:pre-wrap} :not(pre):not([class^=L])>code{font-size:.9375em;font-style:normal!important;letter-spacing:0;padding:.1em .5ex;word-spacing:-.15em;background:#f7f7f8;-webkit-border-radius:4px;border-radius:4px;line-height:1.45;text-rendering:optimizeSpeed} pre{color:rgba(0,0,0,.9);font-family:"Droid Sans Mono","DejaVu Sans Mono",monospace;line-height:1.45;text-rendering:optimizeSpeed} pre code,pre pre{color:inherit;font-size:inherit;line-height:inherit} pre>code{display:block} pre.nowrap,pre.nowrap pre{white-space:pre;word-wrap:normal} em em{font-style:normal} strong strong{font-weight:400} .keyseq{color:rgba(51,51,51,.8)} 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;-webkit-border-radius:3px;border-radius:3px;-webkit-box-shadow:0 1px 0 rgba(0,0,0,.2),0 0 0 .1em white inset;box-shadow:0 1px 0 rgba(0,0,0,.2),0 0 0 .1em #fff inset;margin:0 .15em;padding:.2em .5em;vertical-align:middle;position:relative;top:-.1em;white-space:nowrap} .keyseq kbd:first-child{margin-left:0} .keyseq kbd:last-child{margin-right:0} .menuseq,.menuref{color:#000} .menuseq b:not(.caret),.menuref{font-weight:inherit} .menuseq{word-spacing:-.02em} .menuseq b.caret{font-size:1.25em;line-height:.8} .menuseq i.caret{font-weight:bold;text-align:center;width:.45em} b.button::before,b.button::after{position:relative;top:-1px;font-weight:400} b.button::before{content:"[";padding:0 3px 0 2px} b.button::after{content:"]";padding:0 2px 0 3px} p a>code:hover{color:rgba(0,0,0,.9)} #header,#content,#footnotes,#footer{width:100%;margin-left:auto;margin-right:auto;margin-top:0;margin-bottom:0;max-width:62.5em;*zoom:1;position:relative;padding-left:.9375em;padding-right:.9375em} #header::before,#header::after,#content::before,#content::after,#footnotes::before,#footnotes::after,#footer::before,#footer::after{content:" ";display:table} #header::after,#content::after,#footnotes::after,#footer::after{clear:both} #content{margin-top:1.25em} #content::before{content:none} #header>h1:first-child{color:rgba(0,0,0,.85);margin-top:2.25rem;margin-bottom:0} #header>h1:first-child+#toc{margin-top:8px;border-top:1px solid #dddddf} #header>h1:only-child,body.toc2 #header>h1:nth-last-child(2){border-bottom:1px solid #dddddf;padding-bottom:8px} #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:-ms-flexbox;display:-webkit-flex;display:flex;-ms-flex-flow:row wrap;-webkit-flex-flow:row wrap;flex-flow:row wrap} #header .details span:first-child{margin-left:-.125em} #header .details span.email a{color:rgba(0,0,0,.85)} #header .details br{display:none} #header .details br+span::before{content:"\00a0\2013\00a0"} #header .details br+span.author::before{content:"\00a0\22c5\00a0";color:rgba(0,0,0,.85)} #header .details br+span#revremark::before{content:"\00a0|\00a0"} #header #revnumber{text-transform:capitalize} #header #revnumber::after{content:"\00a0"} #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} #toc{border-bottom:1px solid #e7e7e9;padding-bottom:.5em} #toc>ul{margin-left:.125em} #toc ul.sectlevel0>li>a{font-style:italic} #toc ul.sectlevel0 ul.sectlevel1{margin:.5em 0} #toc ul{font-family:"Open Sans","DejaVu Sans",sans-serif;list-style-type:none} #toc li{line-height:1.3334;margin-top:.3334em} #toc a{text-decoration:none} #toc a:active{text-decoration:underline} #toctitle{color:#7a2518;font-size:1.2em} @media screen and (min-width:768px){#toctitle{font-size:1.375em} body.toc2{padding-left:15em;padding-right:0} #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} #toc.toc2 #toctitle{margin-top:0;margin-bottom:.8rem;font-size:1.2em} #toc.toc2>ul{font-size:.9em;margin-bottom:0} #toc.toc2 ul ul{margin-left:0;padding-left:1em} #toc.toc2 ul.sectlevel0 ul.sectlevel1{padding-left:0;margin-top:.5em;margin-bottom:.5em} body.toc2.toc-right{padding-left:0;padding-right:15em} body.toc2.toc-right #toc.toc2{border-right-width:0;border-left:1px solid #e7e7e9;left:auto;right:0}} @media screen and (min-width:1280px){body.toc2{padding-left:20em;padding-right:0} #toc.toc2{width:20em} #toc.toc2 #toctitle{font-size:1.375em} #toc.toc2>ul{font-size:.95em} #toc.toc2 ul ul{padding-left:1.25em} body.toc2.toc-right{padding-left:0;padding-right:20em}} #content #toc{border-style:solid;border-width:1px;border-color:#e0e0dc;margin-bottom:1.25em;padding:1.25em;background:#f8f8f7;-webkit-border-radius:4px;border-radius:4px} #content #toc>:first-child{margin-top:0} #content #toc>:last-child{margin-bottom:0} #footer{max-width:none;background:rgba(0,0,0,.8);padding:1.25em} #footer-text{color:rgba(255,255,255,.8);line-height:1.44} #content{margin-bottom:.625em} .sect1{padding-bottom:.625em} @media screen and (min-width:768px){#content{margin-bottom:1.25em} .sect1{padding-bottom:1.25em}} .sect1:last-child{padding-bottom:0} .sect1+.sect1{border-top:1px solid #e7e7e9} #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} #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} #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} #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} #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} details,.audioblock,.imageblock,.literalblock,.listingblock,.stemblock,.videoblock{margin-bottom:1.25em} details>summary:first-of-type{cursor:pointer;display:list-item;outline:none;margin-bottom:.75em} .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} table.tableblock.fit-content>caption.title{white-space:nowrap;width:0} .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)} table.tableblock #preamble>.sectionbody>[class="paragraph"]:first-of-type p{font-size:inherit} .admonitionblock>table{border-collapse:separate;border:0;background:none;width:100%} .admonitionblock>table td.icon{text-align:center;width:80px} .admonitionblock>table td.icon img{max-width:none} .admonitionblock>table td.icon .title{font-weight:bold;font-family:"Open Sans","DejaVu Sans",sans-serif;text-transform:uppercase} .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} .admonitionblock>table td.content>:last-child>:last-child{margin-bottom:0} .exampleblock>.content{border-style:solid;border-width:1px;border-color:#e6e6e6;margin-bottom:1.25em;padding:1.25em;background:#fff;-webkit-border-radius:4px;border-radius:4px} .exampleblock>.content>:first-child{margin-top:0} .exampleblock>.content>:last-child{margin-bottom:0} .sidebarblock{border-style:solid;border-width:1px;border-color:#dbdbd6;margin-bottom:1.25em;padding:1.25em;background:#f3f3f2;-webkit-border-radius:4px;border-radius:4px} .sidebarblock>:first-child{margin-top:0} .sidebarblock>:last-child{margin-bottom:0} .sidebarblock>.content>.title{color:#7a2518;margin-top:0;text-align:center} .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>: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} .literalblock pre,.listingblock>.content>pre{-webkit-border-radius:4px;border-radius:4px;overflow-x:auto;padding:1em;font-size:.8125em} @media screen and (min-width:768px){.literalblock pre,.listingblock>.content>pre{font-size:.90625em}} @media screen and (min-width:1280px){.literalblock pre,.listingblock>.content>pre{font-size:1em}} .literalblock pre,.listingblock>.content>pre:not(.highlight),.listingblock>.content>pre[class="highlight"],.listingblock>.content>pre[class^="highlight "]{background:#f7f7f8} .literalblock.output pre{color:#f7f7f8;background:rgba(0,0,0,.9)} .listingblock>.content{position:relative} .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} .listingblock:hover code[data-lang]::before{display:block} .listingblock.terminal pre .command::before{content:attr(data-prompt);padding-right:.5em;color:inherit;opacity:.5} .listingblock.terminal pre .command:not([data-prompt])::before{content:"$"} .listingblock pre.highlightjs{padding:0} .listingblock pre.highlightjs>code{padding:1em;-webkit-border-radius:4px;border-radius:4px} .listingblock pre.prettyprint{border-width:0} .prettyprint{background:#f7f7f8} pre.prettyprint .linenums{line-height:1.45;margin-left:2em} pre.prettyprint li{background:none;list-style-type:inherit;padding-left:0} pre.prettyprint li code[data-lang]::before{opacity:1} pre.prettyprint li:not(:first-child) code[data-lang]::before{display:none} table.linenotable{border-collapse:separate;border:0;margin-bottom:0;background:none} table.linenotable td[class]{color:inherit;vertical-align:top;padding:0;line-height:inherit;white-space:normal} table.linenotable td.code{padding-left:.75em} table.linenotable td.linenos{border-right:1px solid currentColor;opacity:.35;padding-right:.5em} pre.pygments .lineno{border-right:1px solid currentColor;opacity:.35;display:inline-block;margin-right:.75em} pre.pygments .lineno::before{content:"";margin-right:-.125em} .quoteblock{margin:0 1em 1.25em 1.5em;display:table} .quoteblock:not(.excerpt)>.title{margin-left:-1.5em;margin-bottom:.75em} .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} .quoteblock blockquote{margin:0;padding:0;border:0} .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)} .quoteblock blockquote>.paragraph:last-child p{margin-bottom:0} .quoteblock .attribution{margin-top:.75em;margin-right:.5ex;text-align:right} .verseblock{margin:0 1em 1.25em} .verseblock pre{font-family:"Open Sans","DejaVu Sans",sans;font-size:1.15rem;color:rgba(0,0,0,.85);font-weight:300;text-rendering:optimizeLegibility} .verseblock pre strong{font-weight:400} .verseblock .attribution{margin-top:1.25rem;margin-left:.5ex} .quoteblock .attribution,.verseblock .attribution{font-size:.9375em;line-height:1.45;font-style:italic} .quoteblock .attribution br,.verseblock .attribution br{display:none} .quoteblock .attribution cite,.verseblock .attribution cite{display:block;letter-spacing:-.025em;color:rgba(0,0,0,.6)} .quoteblock.abstract blockquote::before,.quoteblock.excerpt blockquote::before,.quoteblock .quoteblock blockquote::before{display:none} .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} .quoteblock.abstract{margin:0 1em 1.25em;display:block} .quoteblock.abstract>.title{margin:0 0 .375em;font-size:1.15em;text-align:center} .quoteblock.excerpt>blockquote,.quoteblock .quoteblock{padding:0 0 .25em 1em;border-left:.25em solid #dddddf} .quoteblock.excerpt,.quoteblock .quoteblock{margin-left:0} .quoteblock.excerpt blockquote,.quoteblock.excerpt p,.quoteblock .quoteblock blockquote,.quoteblock .quoteblock p{color:inherit;font-size:1.0625rem} .quoteblock.excerpt .attribution,.quoteblock .quoteblock .attribution{color:inherit;text-align:left;margin-right:0} p.tableblock:last-child{margin-bottom:0} td.tableblock>.content{margin-bottom:1.25em;word-wrap:anywhere} td.tableblock>.content>:last-child{margin-bottom:-1.25em} table.tableblock,th.tableblock,td.tableblock{border:0 solid #dedede} table.grid-all>*>tr>*{border-width:1px} table.grid-cols>*>tr>*{border-width:0 1px} table.grid-rows>*>tr>*{border-width:1px 0} table.frame-all{border-width:1px} table.frame-ends{border-width:1px 0} table.frame-sides{border-width:0 1px} table.frame-none>colgroup+*>:first-child>*,table.frame-sides>colgroup+*>:first-child>*{border-top-width:0} table.frame-none>:last-child>:last-child>*,table.frame-sides>:last-child>:last-child>*{border-bottom-width:0} table.frame-none>*>tr>:first-child,table.frame-ends>*>tr>:first-child{border-left-width:0} table.frame-none>*>tr>:last-child,table.frame-ends>*>tr>:last-child{border-right-width:0} 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} th.halign-left,td.halign-left{text-align:left} th.halign-right,td.halign-right{text-align:right} th.halign-center,td.halign-center{text-align:center} th.valign-top,td.valign-top{vertical-align:top} th.valign-bottom,td.valign-bottom{vertical-align:bottom} th.valign-middle,td.valign-middle{vertical-align:middle} table thead th,table tfoot th{font-weight:bold} tbody tr th{background:#f7f8f7} tbody tr th,tbody tr th p,tfoot tr th,tfoot tr th p{color:rgba(0,0,0,.8);font-weight:bold} p.tableblock>code:only-child{background:none;padding:0} p.tableblock{font-size:1em} ol{margin-left:1.75em} ul li ol{margin-left:1.5em} dl dd{margin-left:1.125em} dl dd:last-child,dl dd:last-child>:last-child{margin-bottom:0} ol>li p,ul>li p,ul dd,ol dd,.olist .olist,.ulist .ulist,.ulist .olist,.olist .ulist{margin-bottom:.625em} ul.checklist,ul.none,ol.none,ul.no-bullet,ol.no-bullet,ol.unnumbered,ul.unstyled,ol.unstyled{list-style-type:none} ul.no-bullet,ol.no-bullet,ol.unnumbered{margin-left:.625em} ul.unstyled,ol.unstyled{margin-left:0} ul.checklist{margin-left:.625em} 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} ul.checklist li>p:first-child>input[type="checkbox"]:first-child{margin-right:.25em} ul.inline{display:-ms-flexbox;display:-webkit-box;display:flex;-ms-flex-flow:row wrap;-webkit-flex-flow:row wrap;flex-flow:row wrap;list-style:none;margin:0 0 .625em -1.25em} ul.inline>li{margin-left:1.25em} .unstyled dl dt{font-weight:400;font-style:normal} ol.arabic{list-style-type:decimal} ol.decimal{list-style-type:decimal-leading-zero} ol.loweralpha{list-style-type:lower-alpha} ol.upperalpha{list-style-type:upper-alpha} ol.lowerroman{list-style-type:lower-roman} ol.upperroman{list-style-type:upper-roman} ol.lowergreek{list-style-type:lower-greek} .hdlist>table,.colist>table{border:0;background:none} .hdlist>table>tbody>tr,.colist>table>tbody>tr{background:none} td.hdlist1,td.hdlist2{vertical-align:top;padding:0 .625em} td.hdlist1{font-weight:bold;padding-bottom:1.25em} td.hdlist2{word-wrap:anywhere} .literalblock+.colist,.listingblock+.colist{margin-top:-.5em} .colist td:not([class]):first-child{padding:.4em .75em 0;line-height:1;vertical-align:top} .colist td:not([class]):first-child img{max-width:none} .colist td:not([class]):last-child{padding:.25em 0} .thumb,.th{line-height:0;display:inline-block;border:solid 4px #fff;-webkit-box-shadow:0 0 0 1px #ddd;box-shadow:0 0 0 1px #ddd} .imageblock.left{margin:.25em .625em 1.25em 0} .imageblock.right{margin:.25em 0 1.25em .625em} .imageblock>.title{margin-bottom:0} .imageblock.thumb,.imageblock.th{border-width:6px} .imageblock.thumb>.title,.imageblock.th>.title{padding:0 .125em} .image.left,.image.right{margin-top:.25em;margin-bottom:.25em;display:inline-block;line-height:0} .image.left{margin-right:.625em} .image.right{margin-left:.625em} a.image{text-decoration:none;display:inline-block} a.image object{pointer-events:none} sup.footnote,sup.footnoteref{font-size:.875em;position:static;vertical-align:super} sup.footnote a,sup.footnoteref a{text-decoration:none} sup.footnote a:active,sup.footnoteref a:active{text-decoration:underline} #footnotes{padding-top:.75em;padding-bottom:.75em;margin-bottom:.625em} #footnotes hr{width:20%;min-width:6.25em;margin:-.25em 0 .75em;border-width:1px 0 0} #footnotes .footnote{padding:0 .375em 0 .225em;line-height:1.3334;font-size:.875em;margin-left:1.2em;margin-bottom:.2em} #footnotes .footnote a:first-of-type{font-weight:bold;text-decoration:none;margin-left:-1.05em} #footnotes .footnote:last-of-type{margin-bottom:0} #content #footnotes{margin-top:-.625em;margin-bottom:0;padding:.75em 0} .gist .file-data>table{border:0;background:#fff;width:100%;margin-bottom:0} .gist .file-data>table td.line-data{width:99%} div.unbreakable{page-break-inside:avoid} .big{font-size:larger} .small{font-size:smaller} .underline{text-decoration:underline} .overline{text-decoration:overline} .line-through{text-decoration:line-through} .aqua{color:#00bfbf} .aqua-background{background:#00fafa} .black{color:#000} .black-background{background:#000} .blue{color:#0000bf} .blue-background{background:#0000fa} .fuchsia{color:#bf00bf} .fuchsia-background{background:#fa00fa} .gray{color:#606060} .gray-background{background:#7d7d7d} .green{color:#006000} .green-background{background:#007d00} .lime{color:#00bf00} .lime-background{background:#00fa00} .maroon{color:#600000} .maroon-background{background:#7d0000} .navy{color:#000060} .navy-background{background:#00007d} .olive{color:#606000} .olive-background{background:#7d7d00} .purple{color:#600060} .purple-background{background:#7d007d} .red{color:#bf0000} .red-background{background:#fa0000} .silver{color:#909090} .silver-background{background:#bcbcbc} .teal{color:#006060} .teal-background{background:#007d7d} .white{color:#bfbfbf} .white-background{background:#fafafa} .yellow{color:#bfbf00} .yellow-background{background:#fafa00} span.icon>.fa{cursor:default} a span.icon>.fa{cursor:inherit} .admonitionblock td.icon [class^="fa icon-"]{font-size:2.5em;text-shadow:1px 1px 2px rgba(0,0,0,.5);cursor:default} .admonitionblock td.icon .icon-note::before{content:"\f05a";color:#19407c} .admonitionblock td.icon .icon-tip::before{content:"\f0eb";text-shadow:1px 1px 2px rgba(155,155,0,.8);color:#111} .admonitionblock td.icon .icon-warning::before{content:"\f071";color:#bf6900} .admonitionblock td.icon .icon-caution::before{content:"\f06d";color:#bf3400} .admonitionblock td.icon .icon-important::before{content:"\f06a";color:#bf0000} .conum[data-value]{display:inline-block;color:#fff!important;background:rgba(0,0,0,.8);-webkit-border-radius:50%;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} .conum[data-value] *{color:#fff!important} .conum[data-value]+b{display:none} .conum[data-value]::after{content:attr(data-value)} pre .conum[data-value]{position:relative;top:-.125em} b.conum *{color:inherit!important} .conum:not([data-value]):empty{display:none} dt,th.tableblock,td.content,div.footnote{text-rendering:optimizeLegibility} h1,h2,p,td.content,span.alt{letter-spacing:-.01em} p strong,td.content strong,div.footnote strong{letter-spacing:-.005em} p,blockquote,dt,td.content,span.alt{font-size:1.0625rem} p{margin-bottom:1.25rem} .sidebarblock p,.sidebarblock dt,.sidebarblock td.content,p.tableblock{font-size:1em} .exampleblock>.content{background:#fffef7;border-color:#e0e0dc;-webkit-box-shadow:0 1px 4px #e0e0dc;box-shadow:0 1px 4px #e0e0dc} .print-only{display:none!important} @page{margin:1.25cm .75cm} @media print{*{-webkit-box-shadow:none!important;box-shadow:none!important;text-shadow:none!important} html{font-size:80%} a{color:inherit!important;text-decoration:underline!important} a.bare,a[href^="#"],a[href^="mailto:"]{text-decoration:none!important} a[href^="http:"]:not(.bare)::after,a[href^="https:"]:not(.bare)::after{content:"(" attr(href) ")";display:inline-block;font-size:.875em;padding-left:.25em} abbr[title]::after{content:" (" attr(title) ")"} pre,blockquote,tr,img,object,svg{page-break-inside:avoid} thead{display:table-header-group} svg{max-width:100%} p,blockquote,dt,td.content{font-size:1em;orphans:3;widows:3} h2,h3,#toctitle,.sidebarblock>.content>.title{page-break-after:avoid} #header,#content,#footnotes,#footer{max-width:none} #toc,.sidebarblock,.exampleblock>.content{background:none!important} #toc{border-bottom:1px solid #dddddf!important;padding-bottom:0!important} body.book #header{text-align:center} body.book #header>h1:first-child{border:0!important;margin:2.5em 0 1em} body.book #header .details{border:0!important;display:block;padding:0!important} body.book #header .details span:first-child{margin-left:0!important} body.book #header .details br{display:block} body.book #header .details br+span::before{content:none!important} body.book #toc{border:0!important;text-align:left!important;padding:0!important;margin:0!important} body.book #toc,body.book #preamble,body.book h1.sect0,body.book .sect1>h2{page-break-before:always} .listingblock code[data-lang]::before{display:block} #footer{padding:0 .9375em} .hide-on-print{display:none!important} .print-only{display:block!important} .hide-for-print{display:none!important} .show-for-print{display:inherit!important}} @media print,amzn-kf8{#header>h1:first-child{margin-top:1.25rem} .sect1{padding:0!important} .sect1+.sect1{border:0} #footer{background:none} #footer-text{color:rgba(0,0,0,.6);font-size:.9em}} @media amzn-kf8{#header,#content,#footnotes,#footer{padding:0}} </style> </head> <body class="article"> <div id="header"> </div> <div id="content"> <div class="paragraph"> <p>Rebases and cherry-picks involve a sequence of merges whose results are recorded as new single-parent commits. The first parent side of those merges represent the "upstream" side, and often include a far larger set of changes than the second parent side. Traditionally, the renames on the first-parent side of that sequence of merges were repeatedly re-detected for every merge. This file explains why it is safe and effective during rebases and cherry-picks to remember renames on the upstream side of history as an optimization, assuming all merges are automatic and clean (i.e. no conflicts and not interrupted for user input or editing).</p> </div> <div class="paragraph"> <p>Outline:</p> </div> <div class="olist arabic"> <ol class="arabic"> <li> <p>Assumptions</p> </li> <li> <p>How rebasing and cherry-picking work</p> </li> <li> <p>Why the renames on MERGE_SIDE1 in any given pick are <strong>always</strong> a superset of the renames on MERGE_SIDE1 for the next pick.</p> </li> <li> <p>Why any rename on MERGE_SIDE1 in any given pick is <em>almost</em> always also a rename on MERGE_SIDE1 for the next pick</p> </li> <li> <p>A detailed description of the counter-examples to #4.</p> </li> <li> <p>Why the special cases in #5 are still fully reasonable to use to pair up files for three-way content merging in the merge machinery, and why they do not affect the correctness of the merge.</p> </li> <li> <p>Interaction with skipping of "irrelevant" renames</p> </li> <li> <p>Additional items that need to be cached</p> </li> <li> <p>How directory rename detection interacts with the above and why this optimization is still safe even if merge.directoryRenames is set to "true".</p> </li> </ol> </div> <div class="sect1"> <h2 id="_1_assumptions">1. Assumptions</h2> <div class="sectionbody"> <div class="paragraph"> <p>There are two assumptions that will hold throughout this document:</p> </div> <div class="ulist"> <ul> <li> <p>The upstream side where commits are transplanted to is treated as the first parent side when rebase/cherry-pick call the merge machinery</p> </li> <li> <p>All merges are fully automatic</p> </li> </ul> </div> <div class="paragraph"> <p>and a third that will hold in sections 3-6 for simplicity, that I’ll later address in section 9:</p> </div> <div class="ulist"> <ul> <li> <p>No directory renames occur</p> </li> </ul> </div> <div class="paragraph"> <p>Let me explain more about each assumption and why I include it:</p> </div> <div class="paragraph"> <p>The first assumption is merely for the purposes of making this document clearer; the optimization implementation does not actually depend upon it. However, the assumption does hold in all cases because it reflects the way that both rebase and cherry-pick were implemented; and the implementation of cherry-pick and rebase are not readily changeable for backwards compatibility reasons (see for example the discussion of the --ours and --theirs flag in the documentation of <code>git</code> <code>checkout</code>, particularly the comments about how they behave with rebase). The optimization avoids checking first-parent-ness, though. It checks the conditions that make the optimization valid instead, so it would still continue working if someone changed the parent ordering that cherry-pick and rebase use. But making this assumption does make this document much clearer and prevents me from having to repeat every example twice.</p> </div> <div class="paragraph"> <p>If the second assumption is violated, then the optimization simply is turned off and thus isn’t relevant to consider. The second assumption can also be stated as "there is no interruption for a user to resolve conflicts or to just further edit or tweak files". While real rebases and cherry-picks are often interrupted (either because it’s an interactive rebase where the user requested to stop and edit, or because there were conflicts that the user needs to resolve), the cache of renames is not stored on disk, and thus is thrown away as soon as the rebase or cherry pick stops for the user to resolve the operation.</p> </div> <div class="paragraph"> <p>The third assumption makes sections 3-6 simpler, and allows people to understand the basics of why this optimization is safe and effective, and then I can go back and address the specifics in section 9. It is probably also worth noting that if directory renames do occur, then the default of merge.directoryRenames being set to "conflict" means that the operation will stop for users to resolve the conflicts and the cache will be thrown away, and thus that there won’t be an optimization to apply. So, the only reason we need to address directory renames specifically, is that some users will have set merge.directoryRenames to "true" to allow the merges to continue to proceed automatically. The optimization is still safe with this config setting, but we have to discuss a few more cases to show why; this discussion is deferred until section 9.</p> </div> </div> </div> <div class="sect1"> <h2 id="_2_how_rebasing_and_cherry_picking_work">2. How rebasing and cherry-picking work</h2> <div class="sectionbody"> <div class="paragraph"> <p>Consider the following setup (from the git-rebase manpage):</p> </div> <div class="listingblock"> <div class="content"> <pre> A---B---C topic / D---E---F---G main</pre> </div> </div> <div class="paragraph"> <p>After rebasing or cherry-picking topic onto main, this will appear as:</p> </div> <div class="listingblock"> <div class="content"> <pre> A'--B'--C' topic / D---E---F---G main</pre> </div> </div> <div class="paragraph"> <p>The way the commits A', B', and C' are created is through a series of merges, where rebase or cherry-pick sequentially uses each of the three A-B-C commits in a special merge operation. Let’s label the three commits in the merge operation as MERGE_BASE, MERGE_SIDE1, and MERGE_SIDE2. For this picture, the three commits for each of the three merges would be:</p> </div> <div class="literalblock"> <div class="content"> <pre>To create A': MERGE_BASE: E MERGE_SIDE1: G MERGE_SIDE2: A To create B': MERGE_BASE: A MERGE_SIDE1: A' MERGE_SIDE2: B To create C': MERGE_BASE: B MERGE_SIDE1: B' MERGE_SIDE2: C</pre> </div> </div> <div class="paragraph"> <p>Sometimes, folks are surprised that these three-way merges are done. It can be useful in understanding these three-way merges to view them in a slightly different light. For example, in creating C', you can view it as either:</p> </div> <div class="ulist"> <ul> <li> <p>Apply the changes between B & C to B'</p> </li> <li> <p>Apply the changes between B & B' to C</p> </li> </ul> </div> <div class="paragraph"> <p>Conceptually the two statements above are the same as a three-way merge of B, B', and C, at least the parts before you decide to record a commit.</p> </div> </div> </div> <div class="sect1"> <h2 id="_3_why_the_renames_on_merge_side1_in_any_given_pick_are_always_a_superset_of_the_renames_on_merge_side1_for_the_next_pick">3. Why the renames on MERGE_SIDE1 in any given pick are always a superset of the renames on MERGE_SIDE1 for the next pick.</h2> <div class="sectionbody"> <div class="paragraph"> <p>The merge machinery uses the filenames it is fed from MERGE_BASE, MERGE_SIDE1, and MERGE_SIDE2. It will only move content to a different filename under one of three conditions:</p> </div> <div class="ulist"> <ul> <li> <p>To make both pieces of a conflict available to a user during conflict resolution (examples: directory/file conflict, add/add type conflict such as symlink vs. regular file)</p> </li> <li> <p>When MERGE_SIDE1 renames the file.</p> </li> <li> <p>When MERGE_SIDE2 renames the file.</p> </li> </ul> </div> <div class="paragraph"> <p>First, let’s remember what commits are involved in the first and second picks of the cherry-pick or rebase sequence:</p> </div> <div class="literalblock"> <div class="content"> <pre>To create A': MERGE_BASE: E MERGE_SIDE1: G MERGE_SIDE2: A To create B': MERGE_BASE: A MERGE_SIDE1: A' MERGE_SIDE2: B</pre> </div> </div> <div class="paragraph"> <p>So, in particular, we need to show that the renames between E and G are a superset of those between A and A'.</p> </div> <div class="paragraph"> <p>A' is created by the first merge. A' will only have renames for one of the three reasons listed above. The first case, a conflict, results in a situation where the cache is dropped and thus this optimization doesn’t take effect, so we need not consider that case. The third case, a rename on MERGE_SIDE2 (i.e. from G to A), will show up in A' but it also shows up in A — therefore when diffing A and A' that path does not show up as a rename. The only remaining way for renames to show up in A' is for the rename to come from MERGE_SIDE1. Therefore, all renames between A and A' are a subset of those between E and G. Equivalently, all renames between E and G are a superset of those between A and A'.</p> </div> </div> </div> <div class="sect1"> <h2 id="_4_why_any_rename_on_merge_side1_in_any_given_pick_is_almost_always_also_a_rename_on_merge_side1_for_the_next_pick">4. Why any rename on MERGE_SIDE1 in any given pick is <em>almost</em> always also a rename on MERGE_SIDE1 for the next pick.</h2> <div class="sectionbody"> <div class="paragraph"> <p>Let’s again look at the first two picks:</p> </div> <div class="literalblock"> <div class="content"> <pre>To create A': MERGE_BASE: E MERGE_SIDE1: G MERGE_SIDE2: A To create B': MERGE_BASE: A MERGE_SIDE1: A' MERGE_SIDE2: B</pre> </div> </div> <div class="paragraph"> <p>Now let’s look at any given rename from MERGE_SIDE1 of the first pick, i.e. any given rename from E to G. Let’s use the filenames <em>oldfile</em> and <em>newfile</em> for demonstration purposes. That first pick will function as follows; when the rename is detected, the merge machinery will do a three-way content merge of the following:</p> </div> <div class="literalblock"> <div class="content"> <pre> E:oldfile G:newfile A:oldfile</pre> </div> </div> <div class="paragraph"> <p>and produce a new result:</p> </div> <div class="literalblock"> <div class="content"> <pre> A':newfile</pre> </div> </div> <div class="paragraph"> <p>Note above that I’ve assumed that E→A did not rename oldfile. If that side did rename, then we most likely have a rename/rename(1to2) conflict that will cause the rebase or cherry-pick operation to halt and drop the in-memory cache of renames and thus doesn’t need to be considered further. In the special case that E→A does rename the file but also renames it to newfile, then there is no conflict from the renaming and the merge can succeed. In this special case, the rename is not valid to cache because the second merge will find A:newfile in the MERGE_BASE (see also the new testcases in t6429 with "rename same file identically" in their description). So a rename/rename(1to1) needs to be specially handled by pruning renames from the cache and decrementing the dir_rename_counts in the current and leading directories associated with those renames. Or, since these are really rare, one could just take the easy way out and disable the remembering renames optimization when a rename/rename(1to1) happens.</p> </div> <div class="paragraph"> <p>The previous paragraph handled the cases for E→A renaming oldfile, let’s continue assuming that oldfile is not renamed in A.</p> </div> <div class="paragraph"> <p>As per the diagram for creating B', MERGE_SIDE1 involves the changes from A to A'. So, we are curious whether A:oldfile and A':newfile will be viewed as renames. Note that:</p> </div> <div class="ulist"> <ul> <li> <p>There will be no A':oldfile (because there could not have been a G:oldfile as we do not do break detection in the merge machinery and G:newfile was detected as a rename, and by the construction of the rename above that merged cleanly, the merge machinery will ensure there is no <em>oldfile</em> in the result).</p> </li> <li> <p>There will be no A:newfile (if there had been, we would have had a rename/add conflict).</p> </li> <li> <p>Clearly A:oldfile and A':newfile are "related" (A':newfile came from a clean three-way content merge involving A:oldfile).</p> </li> </ul> </div> <div class="paragraph"> <p>We can also expound on the third point above, by noting that three-way content merges can also be viewed as applying the differences between the base and one side to the other side. Thus we can view A':newfile as having been created by taking the changes between E:oldfile and G:newfile (which were detected as being related, i.e. <50% changed) to A:oldfile.</p> </div> <div class="paragraph"> <p>Thus A:oldfile and A':newfile are just as related as E:oldfile and G:newfile are — they have exactly identical differences. Since the latter were detected as renames, A:oldfile and A':newfile should also be detectable as renames almost always.</p> </div> </div> </div> <div class="sect1"> <h2 id="_5_a_detailed_description_of_the_counter_examples_to_4">5. A detailed description of the counter-examples to #4.</h2> <div class="sectionbody"> <div class="paragraph"> <p>We already noted in section 4 that rename/rename(1to1) (i.e. both sides renaming a file the same way) was one counter-example. The more interesting bit, though, is why did we need to use the "almost" qualifier when stating that A:oldfile and A':newfile are "almost" always detectable as renames?</p> </div> <div class="paragraph"> <p>Let’s repeat an earlier point that section 4 made:</p> </div> <div class="literalblock"> <div class="content"> <pre> A':newfile was created by applying the changes between E:oldfile and G:newfile to A:oldfile. The changes between E:oldfile and G:newfile were <50% of the size of E:oldfile.</pre> </div> </div> <div class="paragraph"> <p>If those changes that were <50% of the size of E:oldfile are also <50% of the size of A:oldfile, then A:oldfile and A':newfile will be detectable as renames. However, if there is a dramatic size reduction between E:oldfile and A:oldfile (but the changes between E:oldfile, G:newfile, and A:oldfile still somehow merge cleanly), then traditional rename detection would not detect A:oldfile and A':newfile as renames.</p> </div> <div class="paragraph"> <p>Here’s an example where that can happen:</p> </div> <div class="ulist"> <ul> <li> <p>E:oldfile had 20 lines</p> </li> <li> <p>G:newfile added 10 new lines at the beginning of the file</p> </li> <li> <p>A:oldfile kept the first 3 lines of the file, and deleted all the rest</p> </li> </ul> </div> <div class="paragraph"> <p>then</p> </div> <div class="literalblock"> <div class="content"> <pre> => A':newfile would have 13 lines, 3 of which matches those in A:oldfile. E:oldfile -> G:newfile would be detected as a rename, but A:oldfile and A':newfile would not be.</pre> </div> </div> </div> </div> <div class="sect1"> <h2 id="_6_why_the_special_cases_in_5_are_still_fully_reasonable_to_use_to_pair_up_files_for_three_way_content_merging_in_the_merge_machinery_and_why_they_do_not_affect_the_correctness_of_the_merge">6. Why the special cases in #5 are still fully reasonable to use to pair up files for three-way content merging in the merge machinery, and why they do not affect the correctness of the merge.</h2> <div class="sectionbody"> <div class="paragraph"> <p>In the rename/rename(1to1) case, A:newfile and A':newfile are not renames since they use the <strong>same</strong> filename. However, files with the same filename are obviously fine to pair up for three-way content merging (the merge machinery has never employed break detection). The interesting counter-example case is thus not the rename/rename(1to1) case, but the case where A did not rename oldfile. That was the case that we spent most of the time discussing in sections 4 and 5. The remainder of this section will be devoted to that case as well.</p> </div> <div class="paragraph"> <p>So, even if A:oldfile and A':newfile aren’t detectable as renames, why is it still reasonable to pair them up for three-way content merging in the merge machinery? There are multiple reasons:</p> </div> <div class="ulist"> <ul> <li> <p>As noted in sections 4 and 5, the diff between A:oldfile and A':newfile is <strong>exactly</strong> the same as the diff between E:oldfile and G:newfile. The latter pair were detected as renames, so it seems unlikely to surprise users for us to treat A:oldfile and A':newfile as renames.</p> </li> <li> <p>In fact, "oldfile" and "newfile" were at one point detected as renames due to how they were constructed in the E..G chain. And we used that information once already in this rebase/cherry-pick. I think users would be unlikely to be surprised at us continuing to treat the files as renames and would quickly understand why we had done so.</p> </li> <li> <p>Marking or declaring files as renames is <strong>not</strong> the end goal for merges. Merges use renames to determine which files make sense to be paired up for three-way content merges.</p> </li> <li> <p>A:oldfile and A':newfile were <em>already</em> paired up in a three-way content merge; that is how A':newfile was created. In fact, that three-way content merge was clean. So using them again in a later three-way content merge seems very reasonable.</p> </li> </ul> </div> <div class="paragraph"> <p>However, the above is focusing on the common scenarios. Let’s try to look at all possible unusual scenarios and compare without the optimization to with the optimization. Consider the following theoretical cases; we will then dive into each to determine which of them are possible, and if so, what they mean:</p> </div> <div class="olist arabic"> <ol class="arabic"> <li> <p>Without the optimization, the second merge results in a conflict. With the optimization, the second merge also results in a conflict. Questions: Are the conflicts confusingly different? Better in one case?</p> </li> <li> <p>Without the optimization, the second merge results in NO conflict. With the optimization, the second merge also results in NO conflict. Questions: Are the merges the same?</p> </li> <li> <p>Without the optimization, the second merge results in a conflict. With the optimization, the second merge results in NO conflict. Questions: Possible? Bug, bugfix, or something else?</p> </li> <li> <p>Without the optimization, the second merge results in NO conflict. With the optimization, the second merge results in a conflict. Questions: Possible? Bug, bugfix, or something else?</p> </li> </ol> </div> <div class="paragraph"> <p>I’ll consider all four cases, but out of order.</p> </div> <div class="paragraph"> <p>The fourth case is impossible. For the code without the remembering renames optimization to not get a conflict, B:oldfile would need to exactly match A:oldfile — if it doesn’t, there would be a modify/delete conflict. If A:oldfile matches B:oldfile exactly, then a three-way content merge between A:oldfile, A':newfile, and B:oldfile would have no conflict and just give us the version of newfile from A' as the result.</p> </div> <div class="paragraph"> <p>From the same logic as the above paragraph, the second case would indeed result in identical merges. When A:oldfile exactly matches B:oldfile, an undetected rename would say, "Oh, I see one side didn’t modify <em>oldfile</em> and the other side deleted it. I’ll delete it. And I see you have this brand new file named <em>newfile</em> in A', so I’ll keep it." That gives the same results as three-way content merging A:oldfile, A':newfile, and B:oldfile — a removal of oldfile with the version of newfile from A' showing up in the result.</p> </div> <div class="paragraph"> <p>The third case is interesting. It means that A:oldfile and A':newfile were not just similar enough, but that the changes between them did not conflict with the changes between A:oldfile and B:oldfile. This would validate our hunch that the files were similar enough to be used in a three-way content merge, and thus seems entirely correct for us to have used them that way. (Sidenote: One particular example here may be enlightening. Let’s say that B was an immediate revert of A. B clearly would have been a clean revert of A, since A was B’s immediate parent. One would assume that if you can pick a commit, you should also be able to cherry-pick its immediate revert. However, this is one of those funny corner cases; without this optimization, we just successfully picked a commit cleanly, but we are unable to cherry-pick its immediate revert due to the size differences between E:oldfile and A:oldfile.)</p> </div> <div class="paragraph"> <p>That leaves only the first case to consider — when we get conflicts both with or without the optimization. Without the optimization, we’ll have a modify/delete conflict, where both A':newfile and B:oldfile are left in the tree for the user to deal with and no hints about the potential similarity between the two. With the optimization, we’ll have a three-way content merged A:oldfile, A':newfile, and B:oldfile with conflict markers suggesting we thought the files were related but giving the user the chance to resolve. As noted above, I don’t think users will find us treating <em>oldfile</em> and <em>newfile</em> as related as a surprise since they were between E and G. In any event, though, this case shouldn’t be concerning since we hit a conflict in both cases, told the user what we know, and asked them to resolve it.</p> </div> <div class="paragraph"> <p>So, in summary, case 4 is impossible, case 2 yields the same behavior, and cases 1 and 3 seem to provide as good or better behavior with the optimization than without.</p> </div> </div> </div> <div class="sect1"> <h2 id="_7_interaction_with_skipping_of_irrelevant_renames">7. Interaction with skipping of "irrelevant" renames</h2> <div class="sectionbody"> <div class="paragraph"> <p>Previous optimizations involved skipping rename detection for paths considered to be "irrelevant". See for example the following commits:</p> </div> <div class="ulist"> <ul> <li> <p>32a56dfb99 ("merge-ort: precompute subset of sources for which we need rename detection", 2021-03-11)</p> </li> <li> <p>2fd9eda462 ("merge-ort: precompute whether directory rename detection is needed", 2021-03-11)</p> </li> <li> <p>9bd342137e ("diffcore-rename: determine which relevant_sources are no longer relevant", 2021-03-13)</p> </li> </ul> </div> <div class="paragraph"> <p>Relevance is always determined by what the <em>other</em> side of history has done, in terms of modifying a file that our side renamed, or adding a file to a directory which our side renamed. This means that a path that is "irrelevant" when picking the first commit of a series in a rebase or cherry-pick, may suddenly become "relevant" when picking the next commit.</p> </div> <div class="paragraph"> <p>The upshot of this is that we can only cache rename detection results for relevant paths, and need to re-check relevance in subsequent commits. If those subsequent commits have additional paths that are relevant for rename detection, then we will need to redo rename detection — though we can limit it to the paths for which we have not already detected renames.</p> </div> </div> </div> <div class="sect1"> <h2 id="_8_additional_items_that_need_to_be_cached">8. Additional items that need to be cached</h2> <div class="sectionbody"> <div class="paragraph"> <p>It turns out we have to cache more than just renames; we also cache:</p> </div> <div class="literalblock"> <div class="content"> <pre> A) non-renames (i.e. unpaired deletes) B) counts of renames within directories C) sources that were marked as RELEVANT_LOCATION, but which were downgraded to RELEVANT_NO_MORE D) the toplevel trees involved in the merge</pre> </div> </div> <div class="paragraph"> <p>These are all stored in struct rename_info, and respectively appear in</p> </div> <div class="ulist"> <ul> <li> <p>cached_pairs (along side actual renames, just with a value of NULL)</p> </li> <li> <p>dir_rename_counts</p> </li> <li> <p>cached_irrelevant</p> </li> <li> <p>merge_trees</p> </li> </ul> </div> <div class="paragraph"> <p>The reason for (<code>A</code>) comes from the irrelevant renames skipping optimization discussed in section 7. The fact that irrelevant renames are skipped means we only get a subset of the potential renames detected and subsequent commits may need to run rename detection on the upstream side on a subset of the remaining renames (to get the renames that are relevant for that later commit). Since unpaired deletes are involved in rename detection too, we don’t want to repeatedly check that those paths remain unpaired on the upstream side with every commit we are transplanting.</p> </div> <div class="paragraph"> <p>The reason for (<code>B</code>) is that diffcore_rename_extended() is what generates the counts of renames by directory which is needed in directory rename detection, and if we don’t run diffcore_rename_extended() again then we need to have the output from it, including dir_rename_counts, from the previous run.</p> </div> <div class="paragraph"> <p>The reason for (<code>C</code>) is that merge-ort’s tree traversal will again think those paths are relevant (marking them as RELEVANT_LOCATION), but the fact that they were downgraded to RELEVANT_NO_MORE means that dir_rename_counts already has the information we need for directory rename detection. (A path which becomes RELEVANT_CONTENT in a subsequent commit will be removed from cached_irrelevant.)</p> </div> <div class="paragraph"> <p>The reason for (<code>D</code>) is that is how we determine whether the remember renames optimization can be used. In particular, remembering that our sequence of merges looks like:</p> </div> <div class="literalblock"> <div class="content"> <pre> Merge 1: MERGE_BASE: E MERGE_SIDE1: G MERGE_SIDE2: A => Creates A' Merge 2: MERGE_BASE: A MERGE_SIDE1: A' MERGE_SIDE2: B => Creates B'</pre> </div> </div> <div class="paragraph"> <p>It is the fact that the trees A and A' appear both in Merge 1 and in Merge 2, with A as a parent of A' that allows this optimization. So we store the trees to compare with what we are asked to merge next time.</p> </div> </div> </div> <div class="sect1"> <h2 id="_9_how_directory_rename_detection_interacts_with_the_above_and_why_this_optimization_is_still_safe_even_if_merge_directoryrenames_is_set_to_true">9. How directory rename detection interacts with the above and why this optimization is still safe even if merge.directoryRenames is set to "true".</h2> <div class="sectionbody"> <div class="paragraph"> <p>As noted in the assumptions section:</p> </div> <div class="literalblock"> <div class="content"> <pre> """ ...if directory renames do occur, then the default of merge.directoryRenames being set to "conflict" means that the operation will stop for users to resolve the conflicts and the cache will be thrown away, and thus that there won't be an optimization to apply. So, the only reason we need to address directory renames specifically, is that some users will have set merge.directoryRenames to "true" to allow the merges to continue to proceed automatically. """</pre> </div> </div> <div class="paragraph"> <p>Let’s remember that we need to look at how any given pick affects the next one. So let’s again use the first two picks from the diagram in section one:</p> </div> <div class="literalblock"> <div class="content"> <pre> First pick does this three-way merge: MERGE_BASE: E MERGE_SIDE1: G MERGE_SIDE2: A => creates A' Second pick does this three-way merge: MERGE_BASE: A MERGE_SIDE1: A' MERGE_SIDE2: B => creates B'</pre> </div> </div> <div class="paragraph"> <p>Now, directory rename detection exists so that if one side of history renames a directory, and the other side adds a new file to the old directory, then the merge (with merge.directoryRenames=true) can move the file into the new directory. There are two qualitatively different ways to add a new file to an old directory: create a new file, or rename a file into that directory. Also, directory renames can be done on either side of history, so there are four cases to consider:</p> </div> <div class="ulist"> <ul> <li> <p>MERGE_SIDE1 renames old dir, MERGE_SIDE2 adds new file to old dir</p> </li> <li> <p>MERGE_SIDE1 renames old dir, MERGE_SIDE2 renames file into old dir</p> </li> <li> <p>MERGE_SIDE1 adds new file to old dir, MERGE_SIDE2 renames old dir</p> </li> <li> <p>MERGE_SIDE1 renames file into old dir, MERGE_SIDE2 renames old dir</p> </li> </ul> </div> <div class="paragraph"> <p>One last note before we consider these four cases: There are some important properties about how we implement this optimization with respect to directory rename detection that we need to bear in mind while considering all of these cases:</p> </div> <div class="ulist"> <ul> <li> <p>rename caching occurs <strong>after</strong> applying directory renames</p> </li> <li> <p>a rename created by directory rename detection is recorded for the side of history that did the directory rename.</p> </li> <li> <p>dir_rename_counts, the nested map of {oldname ⇒ {newname ⇒ count}}, is cached between runs as well. This basically means that directory rename detection is also cached, though only on the side of history that we cache renames for (MERGE_SIDE1 as far as this document is concerned; see the assumptions section). Two interesting sub-notes about these counts:</p> <div class="ulist"> <ul> <li> <p>If we need to perform rename-detection again on the given side (e.g. some paths are relevant for rename detection that weren’t before), then we clear dir_rename_counts and recompute it, making use of cached_pairs. The reason it is important to do this is optimizations around RELEVANT_LOCATION exist to prevent us from computing unnecessary renames for directory rename detection and from computing dir_rename_counts for irrelevant directories; but those same renames or directories may become necessary for subsequent merges. The easiest way to "fix up" dir_rename_counts in such cases is to just recompute it.</p> </li> <li> <p>If we prune rename/rename(1to1) entries from the cache, then we also need to update dir_rename_counts to decrement the counts for the involved directory and any relevant parent directories (to undo what update_dir_rename_counts() in diffcore-rename.c incremented when the rename was initially found). If we instead just disable the remembering renames optimization when the exceedingly rare rename/rename(1to1) cases occur, then dir_rename_counts will get re-computed the next time rename detection occurs, as noted above.</p> </li> </ul> </div> </li> <li> <p>the side with multiple commits to pick, is the side of history that we do NOT cache renames for. Thus, there are no additional commits to change the number of renames in a directory, except for those done by directory rename detection (which always pad the majority).</p> </li> <li> <p>the "renames" we cache are modified slightly by any directory rename, as noted below.</p> </li> </ul> </div> <div class="paragraph"> <p>Now, with those notes out of the way, let’s go through the four cases in order:</p> </div> <div class="paragraph"> <p>Case 1: MERGE_SIDE1 renames old dir, MERGE_SIDE2 adds new file to old dir</p> </div> <div class="literalblock"> <div class="content"> <pre> This case looks like this: MERGE_BASE: E, Has olddir/ MERGE_SIDE1: G, Renames olddir/ -> newdir/ MERGE_SIDE2: A, Adds olddir/newfile => creates A', With newdir/newfile MERGE_BASE: A, Has olddir/newfile MERGE_SIDE1: A', Has newdir/newfile MERGE_SIDE2: B, Modifies olddir/newfile => expected B', with threeway-merged newdir/newfile from above In this case, with the optimization, note that after the first commit: * MERGE_SIDE1 remembers olddir/ -> newdir/ * MERGE_SIDE1 has cached olddir/newfile -> newdir/newfile Given the cached rename noted above, the second merge can proceed as expected without needing to perform rename detection from A -> A'.</pre> </div> </div> <div class="paragraph"> <p>Case 2: MERGE_SIDE1 renames old dir, MERGE_SIDE2 renames file into old dir</p> </div> <div class="literalblock"> <div class="content"> <pre> This case looks like this: MERGE_BASE: E oldfile, olddir/ MERGE_SIDE1: G oldfile, olddir/ -> newdir/ MERGE_SIDE2: A oldfile -> olddir/newfile => creates A', With newdir/newfile representing original oldfile MERGE_BASE: A olddir/newfile MERGE_SIDE1: A' newdir/newfile MERGE_SIDE2: B modify olddir/newfile => expected B', with threeway-merged newdir/newfile from above In this case, with the optimization, note that after the first commit: * MERGE_SIDE1 remembers olddir/ -> newdir/ * MERGE_SIDE1 has cached olddir/newfile -> newdir/newfile (NOT oldfile -> newdir/newfile; compare to case with (p->status == 'R' && new_path) in possibly_cache_new_pair()) Given the cached rename noted above, the second merge can proceed as expected without needing to perform rename detection from A -> A'.</pre> </div> </div> <div class="paragraph"> <p>Case 3: MERGE_SIDE1 adds new file to old dir, MERGE_SIDE2 renames old dir</p> </div> <div class="literalblock"> <div class="content"> <pre> This case looks like this: MERGE_BASE: E, Has olddir/ MERGE_SIDE1: G, Adds olddir/newfile MERGE_SIDE2: A, Renames olddir/ -> newdir/ => creates A', With newdir/newfile MERGE_BASE: A, Has newdir/, but no notion of newdir/newfile MERGE_SIDE1: A', Has newdir/newfile MERGE_SIDE2: B, Has newdir/, but no notion of newdir/newfile => expected B', with newdir/newfile from A' In this case, with the optimization, note that after the first commit there were no renames on MERGE_SIDE1, and any renames on MERGE_SIDE2 are tossed. But the second merge didn't need any renames so this is fine.</pre> </div> </div> <div class="paragraph"> <p>Case 4: MERGE_SIDE1 renames file into old dir, MERGE_SIDE2 renames old dir</p> </div> <div class="literalblock"> <div class="content"> <pre> This case looks like this: MERGE_BASE: E, Has olddir/ MERGE_SIDE1: G, Renames oldfile -> olddir/newfile MERGE_SIDE2: A, Renames olddir/ -> newdir/ => creates A', With newdir/newfile representing original oldfile MERGE_BASE: A, Has oldfile MERGE_SIDE1: A', Has newdir/newfile MERGE_SIDE2: B, Modifies oldfile => expected B', with threeway-merged newdir/newfile from above In this case, with the optimization, note that after the first commit: * MERGE_SIDE1 remembers oldfile -> newdir/newfile (NOT oldfile -> olddir/newfile; compare to case of second block under p->status == 'R' in possibly_cache_new_pair()) * MERGE_SIDE2 renames are tossed because only MERGE_SIDE1 is remembered Given the cached rename noted above, the second merge can proceed as expected without needing to perform rename detection from A -> A'.</pre> </div> </div> <div class="paragraph"> <p>Finally, I’ll just note here that interactions with the skip-irrelevant-renames optimization means we sometimes don’t detect renames for any files within a directory that was renamed, in which case we will not have been able to detect any rename for the directory itself. In such a case, we do not know whether the directory was renamed; we want to be careful to avoid caching some kind of "this directory was not renamed" statement. If we did, then a subsequent commit being rebased could add a file to the old directory, and the user would expect it to end up in the correct directory — something our erroneous "this directory was not renamed" cache would preclude.</p> </div> </div> </div> </div> <div id="footer"> <div id="footer-text"> Last updated 2025-11-17 16:38:17 UTC </div> </div> </body> </html>