Skip to content

Commit 186b428

Browse files
ARBhosaleaniket.bhosale
andauthored
fix: mergeTree handles modifications in both trees (#2122)
Co-authored-by: aniket.bhosale <aniket.bhosale@servicenow.com>
1 parent 77715e1 commit 186b428

File tree

2 files changed

+158
-1
lines changed

2 files changed

+158
-1
lines changed

__tests__/test-merge.js

Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1308,4 +1308,146 @@ describe('merge', () => {
13081308
)
13091309
expect(messages.join()).toEqual(['Add same.txt on master'].join())
13101310
})
1311+
1312+
it('merge two branches with unrelated histories where they add files in nested directories', async () => {
1313+
const { fs, dir, gitdir } = await makeFixture('test-empty')
1314+
1315+
const author = {
1316+
name: 'Mr. Test',
1317+
email: 'mrtest@example.com',
1318+
timestamp: 1262356920,
1319+
timezoneOffset: -0,
1320+
}
1321+
1322+
// First root commit on 'master' with nested directory
1323+
await fs.mkdir(`${dir}/dir1`)
1324+
await fs.mkdir(`${dir}/dir1/subdir1`)
1325+
await fs.write(`${dir}/dir1/subdir1/file1.txt`, 'content from master')
1326+
await add({ fs, dir, gitdir, filepath: 'dir1/subdir1/file1.txt' })
1327+
await gitCommit({
1328+
fs,
1329+
dir,
1330+
gitdir,
1331+
ref: 'master',
1332+
message: 'Add file in nested directory on master',
1333+
author,
1334+
})
1335+
1336+
// Second root commit on unrelated branch 'other' with different nested directory
1337+
await fs.mkdir(`${dir}/dir2`)
1338+
await fs.mkdir(`${dir}/dir2/subdir2`)
1339+
await fs.write(`${dir}/dir2/subdir2/file2.txt`, 'content from other')
1340+
await add({ fs, dir, gitdir, filepath: 'dir2/subdir2/file2.txt' })
1341+
await gitCommit({
1342+
fs,
1343+
dir,
1344+
gitdir,
1345+
ref: 'other',
1346+
message: 'Add file in different nested directory on other',
1347+
author,
1348+
})
1349+
1350+
const report = await merge({
1351+
fs,
1352+
gitdir,
1353+
ours: 'master',
1354+
theirs: 'other',
1355+
abortOnConflict: false,
1356+
allowUnrelatedHistories: true,
1357+
author,
1358+
})
1359+
1360+
expect(report).toBeTruthy()
1361+
expect(report.mergeCommit).toBeTruthy()
1362+
const mergeHead = (await log({ fs, gitdir, ref: 'master', depth: 1 }))[0]
1363+
.commit
1364+
expect(mergeHead.parent.length).toBe(2)
1365+
1366+
const matrix = await statusMatrix({ fs, dir, gitdir })
1367+
const trackedFiles = matrix.map(row => row[0])
1368+
expect(trackedFiles.join()).toEqual(
1369+
['dir1/subdir1/file1.txt', 'dir2/subdir2/file2.txt'].join()
1370+
)
1371+
1372+
const history = await log({ fs, gitdir, ref: 'master', depth: 3 })
1373+
const messages = history.map(entry =>
1374+
entry.commit.message.replace('\n', '')
1375+
)
1376+
expect(messages.join()).toEqual(
1377+
[
1378+
`Merge branch 'other' into master`,
1379+
'Add file in different nested directory on other',
1380+
'Add file in nested directory on master',
1381+
].join()
1382+
)
1383+
})
1384+
1385+
it('merge two branches with unrelated histories where they add files with same path in nested directories', async () => {
1386+
const { fs, dir, gitdir } = await makeFixture('test-empty')
1387+
const author = {
1388+
name: 'Mr. Test',
1389+
email: 'mrtest@example.com',
1390+
timestamp: 1262356920,
1391+
timezoneOffset: -0,
1392+
}
1393+
1394+
// First root commit on master adding nested file
1395+
await fs.mkdir(`${dir}/shared`)
1396+
await fs.mkdir(`${dir}/shared/path`)
1397+
await fs.write(`${dir}/shared/path/conflict.txt`, 'content from master')
1398+
await add({ fs, dir, gitdir, filepath: 'shared/path/conflict.txt' })
1399+
await gitCommit({
1400+
fs,
1401+
dir,
1402+
gitdir,
1403+
ref: 'master',
1404+
message: 'Add nested file on master',
1405+
author,
1406+
})
1407+
1408+
// Second unrelated root commit on branch 'other' adding same nested file with different content
1409+
await fs.mkdir(`${dir}/shared`)
1410+
await fs.mkdir(`${dir}/shared/path`)
1411+
await fs.write(`${dir}/shared/path/conflict.txt`, 'content from other')
1412+
await add({ fs, dir, gitdir, filepath: 'shared/path/conflict.txt' })
1413+
await gitCommit({
1414+
fs,
1415+
dir,
1416+
gitdir,
1417+
ref: 'other',
1418+
parent: [],
1419+
message: 'Add nested file on other',
1420+
author,
1421+
})
1422+
1423+
let error = null
1424+
try {
1425+
await merge({
1426+
fs,
1427+
dir,
1428+
gitdir,
1429+
ours: 'master',
1430+
theirs: 'other',
1431+
abortOnConflict: false,
1432+
allowUnrelatedHistories: true,
1433+
author,
1434+
})
1435+
} catch (e) {
1436+
error = e
1437+
}
1438+
expect(error).not.toBeNull()
1439+
expect(error.code).toBe(Errors.MergeConflictError.code)
1440+
const resultText = await fs.read(`${dir}/shared/path/conflict.txt`, 'utf8')
1441+
expect(resultText).toContain('<<<<<<<')
1442+
1443+
const matrix = await statusMatrix({ fs, dir, gitdir })
1444+
const trackedFiles = matrix.map(row => row[0])
1445+
expect(trackedFiles.join()).toEqual(['shared/path/conflict.txt'].join())
1446+
1447+
const history = await log({ fs, gitdir, ref: 'master', depth: 3 })
1448+
const messages = history.map(entry =>
1449+
entry.commit.message.replace('\n', '')
1450+
)
1451+
expect(messages.join()).toEqual(['Add nested file on master'].join())
1452+
})
13111453
})

src/utils/mergeTree.js

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,22 @@ export async function mergeTree({
120120
: undefined
121121
}
122122
case 'true-true': {
123-
// Modifications
123+
// Handle tree-tree merges (directories)
124+
if (
125+
ours &&
126+
theirs &&
127+
(await ours.type()) === 'tree' &&
128+
(await theirs.type()) === 'tree'
129+
) {
130+
return {
131+
mode: await ours.mode(),
132+
path,
133+
oid: await ours.oid(),
134+
type: 'tree',
135+
}
136+
}
137+
138+
// Modifications - both are blobs
124139
if (
125140
ours &&
126141
theirs &&

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy