A while ago, my friend and coworker Matt pinged me with a Git question. He was looking into an issue with a GitHub Actions workflow that only runs on files that changed in a given pull request, and a user reported that it was running against way too many files - so many, in fact, that the workflow was failing because it was exceeding the maximum command line length!
Now, the set of files changed by a pull request is determined by the merge base between the commits at the tips of the source and target branches - it’s basically their most common ancestor. Matt showed me the logs from the workflow, which was logging the commit ID for the merge base - but when we ran the exact same git merge-base command locally, we got a different commit back! The only real difference between our…
A while ago, my friend and coworker Matt pinged me with a Git question. He was looking into an issue with a GitHub Actions workflow that only runs on files that changed in a given pull request, and a user reported that it was running against way too many files - so many, in fact, that the workflow was failing because it was exceeding the maximum command line length!
Now, the set of files changed by a pull request is determined by the merge base between the commits at the tips of the source and target branches - it’s basically their most common ancestor. Matt showed me the logs from the workflow, which was logging the commit ID for the merge base - but when we ran the exact same git merge-base command locally, we got a different commit back! The only real difference between our local repositories and the ones used by our workflows is that the latter use shallow clones and fetches, so we figured that that had something to do with it - and sure enough, when we increased the fetch depth for the action, we saw the correct commit ID for the merge base in the logs.
So "problem solved" - but needless to say, we were both still very confused, and I decided to dig into it further.
Deepening Our Understanding
My big shock was that you can get a different result for a merge base as you deepen - I had assumed that either the correct one would be found, or none at all. The way merge base works, conceptually, is that given commits L and R, it finds a commit C that L and R share as a common ancestor, with the added condition that there’s no other commit that both meets these criteria and also has C as an ancestor (eg. there is no "closer" commit).
So what we’re looking for is a situation where:
- We fetch up to depth
D - There’s a commit
B(forBad merge base) that’s withinDsteps of our target commit - There’s a commit
G(forGood merge base) that’s not withinDsteps of our target commit Bis an ancestor ofG
This sounds...kind of impossible at first - after all, how could B be closer than G if B is G’s ancestor - but I suspected that merges might be the culprit here. I started wondering how fetch depth interacts with merges, so here’s a pop quiz for you: if I have a merge commit with 5 commits on each side’s branch, does git fetch --depth=5:
- ...fetch the merge commit and the first two ancestors on each side, in a sort of breadth-first fashion?
- ...fetch the merge commit and the first four ancestors on one of the left or right, in a sort of depth-first fashion?
- ...fetch the merge commit and the first four ancestors on both sides, considering they are within 5 steps of what we’re fetching?
The answer is: the last one! It fetches all commits that are within 5 steps of the target commit. And therein lies the trick - if there’s a short path to B from both sides of the merge commit, but the path to G from one of the sides of the merge commit is long, that results in a situation where the merge base can change as you deepen!
This is kind of hard to wrap your head around with just words, so here is a diagram. It’s a little weird to look at at first, but we’ll go through it step-by-step - I just wanted to provide the full context to start:
Now that we have the full commit graph for reference, let’s walk through what we see as we deepen. At depths 1 and 2, we just see the merge commit M and then its immediate parents L and R - nothing interesting. So let’s look at the commit graph at depth 3:
--depth=3
%3B%20%7D%3C%2Fstyle%3E%3C%2Fdefs%3E%3Crect%20x%3D%220%22%20y%3D%220%22%20width%3D%221417.7777777777774%22%20height%3D%22855.0555555555555%22%20fill%3D%22%23ffffff%22%3E%3C%2Frect%3E%3Cg%20stroke-linecap%3D%22round%22%20transform%3D%22translate(458.1167081703336%20149.52777777777783)%20rotate(0%2088.99999999999994%2076.5)%22%3E%3Cpath%20d%3D%22M32%200%20C74.73%20-1.39%2C%20122.52%20-2.06%2C%20146%200%20M32%200%20C71.97%20-0.02%2C%20110.6%20-1.56%2C%20146%200%20M146%200%20C167.01%20-1.9%2C%20179.94%2011.26%2C%20178%2032%20M146%200%20C166.05%20-1.25%2C%20176.82%2010.93%2C%20178%2032%20M178%2032%20C177.23%2067.81%2C%20177.75%20103.52%2C%20178%20121%20M178%2032%20C179.68%2061.39%2C%20179.75%2090.24%2C%20178%20121%20M178%20121%20C178.35%20141.01%2C%20166.82%20152.33%2C%20146%20153%20M178%20121%20C180.04%20140.55%2C%20165.38%20153.5%2C%20146%20153%20M146%20153%20C108.1%20155.81%2C%2068.15%20154.2%2C%2032%20153%20M146%20153%20C108.95%20154.17%2C%2069.9%20153.02%2C%2032%20153%20M32%20153%20C11.96%20154.5%2C%20-0.43%20142.5%2C%200%20121%20M32%20153%20C12.42%20152.82%2C%20-0.08%20143.53%2C%200%20121%20M0%20121%20C-1.71%2087.66%2C%20-1.21%2051.8%2C%200%2032%20M0%20121%20C-1.03%2092.01%2C%200.28%2061.71%2C%200%2032%20M0%2032%20C0.64%209.07%2C%2011.17%200.06%2C%2032%200%20M0%2032%20C-1.18%2011.61%2C%2012.55%200.2%2C%2032%200%22%20stroke%3D%22%231e1e1e%22%20stroke-width%3D%222%22%20fill%3D%22none%22%3E%3C%2Fpath%3E%3C%2Fg%3E%3Cg%20transform%3D%22translate(533.3250411857754%20203.52777777777783)%20rotate(0%2013.791666984558105%2022.5)%22%3E%3Ctext%20x%3D%2213.791666984558105%22%20y%3D%2231.716%22%20font-family%3D%22Excalifont%2C%20Xiaolai%2C%20Segoe%20UI%20Emoji%22%20font-size%3D%2236px%22%20fill%3D%22%231e1e1e%22%20text-anchor%3D%22middle%22%20style%3D%22white-space%3A%20pre%3B%22%20direction%3D%22ltr%22%20dominant-baseline%3D%22alphabetic%22%3EM%3C%2Ftext%3E%3C%2Fg%3E%3Cg%20stroke-linecap%3D%22round%22%20transform%3D%22translate(246.99999999999966%20421.09586010044325)%20rotate(0%2089%2076.5)%22%3E%3Cpath%20d%3D%22M32%200%20C63.52%20-0.3%2C%20100.14%200.04%2C%20146%200%20M32%200%20C57.36%200.25%2C%2081.46%200.05%2C%20146%200%20M146%200%20C166.57%200.15%2C%20176.77%209.65%2C%20178%2032%20M146%200%20C165.98%202.13%2C%20178.18%2012.22%2C%20178%2032%20M178%2032%20C177.55%2050.6%2C%20177.47%2071.3%2C%20178%20121%20M178%2032%20C177.13%2051.88%2C%20177.17%2071.88%2C%20178%20121%20M178%20121%20C177.47%20141.46%2C%20168.18%20153.75%2C%20146%20153%20M178%20121%20C179.7%20141.6%2C%20168.02%20151.75%2C%20146%20153%20M146%20153%20C100.87%20154.51%2C%2060.61%20154.35%2C%2032%20153%20M146%20153%20C110.91%20152.88%2C%2074.4%20153.23%2C%2032%20153%20M32%20153%20C12.65%20153.97%2C%201.38%20141.85%2C%200%20121%20M32%20153%20C12.32%20152.17%2C%20-1.2%20140.54%2C%200%20121%20M0%20121%20C1.05%2093.96%2C%20-1.04%2063.26%2C%200%2032%20M0%20121%20C-0.85%2087.7%2C%20-0.05%2054.96%2C%200%2032%20M0%2032%20C-1.64%2010.77%2C%2011.69%20-0.06%2C%2032%200%20M0%2032%20C-1.4%2010.85%2C%2011.95%200.02%2C%2032%200%22%20stroke%3D%22%231e1e1e%22%20stroke-width%3D%222%22%20fill%3D%22none%22%3E%3C%2Fpath%3E%3C%2Fg%3E%3Cg%20transform%3D%22translate(326.2250003814694%20475.09586010044325)%20rotate(0%209.774999618530273%2022.5)%22%3E%3Ctext%20x%3D%229.774999618530273%22%20y%3D%2231.716%22%20font-family%3D%22Excalifont%2C%20Xiaolai%2C%20Segoe%20UI%20Emoji%22%20font-size%3D%2236px%22%20fill%3D%22%231e1e1e%22%20text-anchor%3D%22middle%22%20style%3D%22white-space%3A%20pre%3B%22%20direction%3D%22ltr%22%20dominant-baseline%3D%22alphabetic%22%3EL%3C%2Ftext%3E%3C%2Fg%3E%3Cg%20stroke-linecap%3D%22round%22%20transform%3D%22translate(687.2222222222218%20423.7625267671099)%20rotate(0%2089%2076.5)%22%3E%3Cpath%20d%3D%22M32%200%20C68.22%200.25%2C%20108.82%20-0.17%2C%20146%200%20M32%200%20C76.48%20-0.76%2C%20121.11%20-1.35%2C%20146%200%20M146%200%20C166.16%201.85%2C%20178.16%2012.02%2C%20178%2032%20M146%200%20C165.48%200.72%2C%20178.13%209.83%2C%20178%2032%20M178%2032%20C176.13%2054.67%2C%20178.97%2075.49%2C%20178%20121%20M178%2032%20C176.98%2057.45%2C%20177.66%2084.15%2C%20178%20121%20M178%20121%20C179.48%20141.7%2C%20167.93%20151.91%2C%20146%20153%20M178%20121%20C179.88%20140.63%2C%20167.82%20151.15%2C%20146%20153%20M146%20153%20C104.86%20155.28%2C%2064.06%20155.04%2C%2032%20153%20M146%20153%20C120%20153.17%2C%2092.71%20152.43%2C%2032%20153%20M32%20153%20C12.11%20152.28%2C%20-1.04%20140.77%2C%200%20121%20M32%20153%20C11.05%20151.84%2C%201.98%20143.02%2C%200%20121%20M0%20121%20C2.08%2089.5%2C%201.98%2055.95%2C%200%2032%20M0%20121%20C-0.89%2097.03%2C%200.44%2072.93%2C%200%2032%20M0%2032%20C-1.22%2010.82%2C%2011.79%200.02%2C%2032%200%20M0%2032%20C0.61%209.8%2C%2011.39%20-0.15%2C%2032%200%22%20stroke%3D%22%231e1e1e%22%20stroke-width%3D%222%22%20fill%3D%22none%22%3E%3C%2Fpath%3E%3C%2Fg%3E%3Cg%20transform%3D%22translate(762.9722222222218%20477.7625267671099)%20rotate(0%2013.25%2022.5)%22%3E%3Ctext%20x%3D%2213.25%22%20y%3D%2231.716%22%20font-family%3D%22Excalifont%2C%20Xiaolai%2C%20Segoe%20UI%20Emoji%22%20font-size%3D%2236px%22%20fill%3D%22%231e1e1e%22%20text-anchor%3D%22middle%22%20style%3D%22white-space%3A%20pre%3B%22%20direction%3D%22ltr%22%20dominant-baseline%3D%22alphabetic%22%3ER%3C%2Ftext%3E%3C%2Fg%3E%3Cg%20stroke-linecap%3D%22round%22%3E%3Cg%20transform%3D%22translate(484.7276766670533%20302.7661919591148)%20rotate(0%20-45.319602561862155%2057.86503626175829)%22%3E%3Cpath%20d%3D%22M0.23%201.12%20C-15.13%2020.44%2C%20-76.47%2097.5%2C%20-91.7%20116.61%20M-1.1%200.67%20C-16.15%2019.59%2C%20-74.37%2095.54%2C%20-89.54%20114.96%22%20stroke%3D%22%231e1e1e%22%20stroke-width%3D%222%22%20fill%3D%22none%22%3E%3C%2Fpath%3E%3C%2Fg%3E%3Cg%20transform%3D%22translate(484.7276766670533%20302.7661919591148)%20rotate(0%20-45.319602561862155%2057.86503626175829)%22%3E%3Cpath%20d%3D%22M-81.93%2091.14%20C-82.51%2097.5%2C%20-85.49%20106.6%2C%20-89.54%20114.96%20M-81.93%2091.14%20C-85.01%2099.35%2C%20-86.68%20106.43%2C%20-89.54%20114.96%22%20stroke%3D%22%231e1e1e%22%20stroke-width%3D%222%22%20fill%3D%22none%22%3E%3C%2Fpath%3E%3C%2Fg%3E%3Cg%20transform%3D%22translate(484.7276766670533%20302.7661919591148)%20rotate(0%20-45.319602561862155%2057.86503626175829)%22%3E%3Cpath%20d%3D%22M-68.4%20101.6%20C-73.64%20104.42%2C%20-81.23%20109.97%2C%20-89.54%20114.96%20M-68.4%20101.6%20C-75.57%20106.53%2C%20-81.41%20110.38%2C%20-89.54%20114.96%22%20stroke%3D%22%231e1e1e%22%20stroke-width%3D%222%22%20fill%3D%22none%22%3E%3C%2Fpath%3E%3C%2Fg%3E%3C%2Fg%3E%3Cmask%3E%3C%2Fmask%3E%3Cg%20stroke-linecap%3D%22round%22%3E%3Cg%20transform%3D%22translate(614.6456731449579%20302.71740387973176)%20rotate(0%2040.11660904643156%2063.43966028296492)%22%3E%3Cpath%20d%3D%22M-1.06%200.88%20C12.2%2021.86%2C%2066.35%20106.07%2C%2079.78%20126.97%20M0.59%200.3%20C13.63%2022%2C%2065.02%20107.4%2C%2078.59%20128.56%22%20stroke%3D%22%231e1e1e%22%20stroke-width%3D%222%22%20fill%3D%22none%22%3E%3C%2Fpath%3E%3C%2Fg%3E%3Cg%20transform%3D%22translate(614.6456731449579%20302.71740387973176)%20rotate(0%2040.11660904643156%2063.43966028296492)%22%3E%3Cpath%20d%3D%22M58.96%20113.07%20C66.85%20117.43%2C%2071.8%20121.9%2C%2078.59%20128.56%20M58.96%20113.07%20C63.84%20117.42%2C%2067.84%20120.91%2C%2078.59%20128.56%22%20stroke%3D%22%231e1e1e%22%20stroke-width%3D%222%22%20fill%3D%22none%22%3E%3C%2Fpath%3E%3C%2Fg%3E%3Cg%20transform%3D%22translate(614.6456731449579%20302.71740387973176)%20rotate(0%2040.11660904643156%2063.43966028296492)%22%3E%3Cpath%20d%3D%22M73.5%20104.08%20C76.83%20111.18%2C%2077.13%20118.53%2C%2078.59%20128.56%20M73.5%20104.08%20C74.71%20110.8%2C%2075.09%20116.53%2C%2078.59%20128.56%22%20stroke%3D%22%231e1e1e%22%20stroke-width%3D%222%22%20fill%3D%22none%22%3E%3C%2Fpath%3E%3C%2Fg%3E%3C%2Fg%3E%3Cmask%3E%3C%2Fmask%3E%3Cg%20stroke-linecap%3D%22round%22%20transform%3D%22translate(700.8888888888886%20689.2777777777777)%20rotate(0%2089%2076.5)%22%3E%3Cpath%20d%3D%22M32%200%20C54.45%20-2.42%2C%2080.57%200.67%2C%20146%200%20M32%200%20C59.11%201.63%2C%2086.11%200.8%2C%20146%200%20M146%200%20C167.91%20-0.52%2C%20177.49%2011.42%2C%20178%2032%20M146%200%20C169.07%20-2.09%2C%20178.47%2011.84%2C%20178%2032%20M178%2032%20C176.34%2058.72%2C%20177.77%2091.09%2C%20178%20121%20M178%2032%20C178.06%2059.53%2C%20177.88%2086.14%2C%20178%20121%20M178%20121%20C177.39%20141.09%2C%20165.68%20154.09%2C%20146%20153%20M178%20121%20C179.92%20140.72%2C%20168.99%20155.3%2C%20146%20153%20M146%20153%20C101.73%20151.14%2C%2060.88%20152.91%2C%2032%20153%20M146%20153%20C112.84%20152.66%2C%2081.83%20151.3%2C%2032%20153%20M32%20153%20C12.54%20154.73%2C%201.74%20141.11%2C%200%20121%20M32%20153%20C11.24%20153.75%2C%20-0.37%20140.56%2C%200%20121%20M0%20121%20C-1.59%20101.54%2C%20-2.14%2086.51%2C%200%2032%20M0%20121%20C0.32%2099.77%2C%201.3%2077.95%2C%200%2032%20M0%2032%20C-0.63%209.83%2C%209.59%20-0.05%2C%2032%200%20M0%2032%20C-0.52%2012.41%2C%209.93%20-2.07%2C%2032%200%22%20stroke%3D%22%231e1e1e%22%20stroke-width%3D%222%22%20fill%3D%22none%22%3E%3C%2Fpath%3E%3C%2Fg%3E%3Cg%20transform%3D%22translate(775.8472219043305%20743.2777777777777)%20rotate(0%2014.041666984558105%2022.5)%22%3E%3Ctext%20x%3D%2214.041666984558105%22%20y%3D%2231.716%22%20font-family%3D%22Excalifont%2C%20Xiaolai%2C%20Segoe%20UI%20Emoji%22%20font-size%3D%2236px%22%20fill%3D%22%231e1e1e%22%20text-anchor%3D%22middle%22%20style%3D%22white-space%3A%20pre%3B%22%20direction%3D%22ltr%22%20dominant-baseline%3D%22alphabetic%22%3EG%3C%2Ftext%3E%3C%2Fg%3E%3Cg%20stroke-linecap%3D%22round%22%20transform%3D%22translate(389.77777777777726%20692.0555555555555)%20rotate(0%2089%2076.5)%22%3E%3Cpath%20d%3D%22M32%200%20C54.59%20-0.96%2C%2078.54%200.07%2C%20146%200%20M32%200%20C76.82%20-0.36%2C%20120.8%200.28%2C%20146%200%20M146%200%20C168.85%20-1.82%2C%20178.41%2011.69%2C%20178%2032%20M146%200%20C167.83%20-0.6%2C%20178.52%209.02%2C%20178%2032%20M178%2032%20C178.06%2049.47%2C%20177.44%2069.3%2C%20178%20121%20M178%2032%20C177.89%2063.36%2C%20177.37%2096.52%2C%20178%20121%20M178%20121%20C179.67%20140.93%2C%20168.77%20155%2C%20146%20153%20M178%20121%20C179.87%20141.89%2C%20165.24%20152.06%2C%20146%20153%20M146%20153%20C116.13%20153.74%2C%2085.08%20151.64%2C%2032%20153%20M146%20153%20C104.43%20153.14%2C%2061.86%20151.67%2C%2032%20153%20M32%20153%20C11.16%20153.65%2C%20-0.32%20140.79%2C%200%20121%20M32%20153%20C8.47%20154.7%2C%20-0.12%20141.26%2C%200%20121%20M0%20121%20C-0.4%2098.35%2C%201.8%2078.02%2C%200%2032%20M0%20121%20C-0.87%2087.29%2C%20-1.09%2054.38%2C%200%2032%20M0%2032%20C-0.45%2012.19%2C%2010.03%20-1.8%2C%2032%200%20M0%2032%20C-1.02%209.67%2C%208.72%20-2.12%2C%2032%200%22%20stroke%3D%22%231e1e1e%22%20stroke-width%3D%222%22%20fill%3D%22none%22%3E%3C%2Fpath%3E%3C%2Fg%3E%3Cg%20transform%3D%22translate(467.40277777777726%20746.0555555555555)%20rotate(0%2011.375%2022.5)%22%3E%3Ctext%20x%3D%2211.375%22%20y%3D%2231.716%22%20font-family%3D%22Excalifont%2C%20Xiaolai%2C%20Segoe%20UI%20Emoji%22%20font-size%3D%2236px%22%20fill%3D%22%231e1e1e%22%20text-anchor%3D%22middle%22%20style%3D%22white-space%3A%20pre%3B%22%20direction%3D%22ltr%22%20dominant-baseline%3D%22alphabetic%22%3EN%3C%2Ftext%3E%3C%2Fg%3E%3Cg%20stroke-linecap%3D%22round%22%20transform%3D%22translate(10%20678.2777777777777)%20rotate(0%2089%2076.5)%22%3E%3Cpath%20d%3D%22M32%200%20C66.72%200.94%2C%2097.97%200.12%2C%20146%200%20M32%200%20C63.97%20-1.34%2C%2094.64%200.08%2C%20146%200%20M146%200%20C167.76%20-0.52%2C%20178.45%209.24%2C%20178%2032%20M146%200%20C