Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion 9 generate/input/descriptor.json
Original file line number Diff line number Diff line change
Expand Up @@ -972,7 +972,14 @@
"merge": {
"functions": {
"git_merge": {
"ignore": true
"args": {
"their_heads": {
"cType": "const git_annotated_commit **",
"cppClassName": "Array",
"jsClassName": "Array",
"arrayElementCppClassName": "GitAnnotatedCommit"
}
}
},
"git_merge_analysis": {
"ignore": true
Expand Down
22 changes: 22 additions & 0 deletions 22 lib/merge.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ var Promise = require("nodegit-promise");

var Merge = NodeGit.Merge;
var mergeCommits = Merge.commits;
var mergeMerge = Merge.merge;

/**
* Merge 2 commits together and create an new index that can
Expand All @@ -24,3 +25,24 @@ Merge.commits = function(repo, ourCommit, theirCommit, options) {
return mergeCommits.call(this, repo, commits[0], commits[1], options);
});
};

/**
* Merge a commit into HEAD and writes the results to the working directory.
*
* @param {Repository} repo Repository that contains the given commits
* @param {Commit} theirHead The annotated to merge into HEAD
* @param {MergeOptions} [mergeOpts] The merge tree options (null for default)
* @param {CheckoutOptions} [checkoutOpts] The checkout options
* (null for default)
*/
Merge.merge = function(repo, theirHead, mergeOpts, checkoutOpts) {
mergeOpts = normalizeOptions(mergeOpts || {}, NodeGit.MergeOptions);
checkoutOpts = normalizeOptions(checkoutOpts || {}, NodeGit.CheckoutOptions);

// Even though git_merge takes an array of annotated_commits, it expects
// exactly one to have been passed in or it will throw an error... ¯\_(ツ)_/¯
var theirHeads = [theirHead];

return mergeMerge.call(this, repo, theirHeads, theirHeads.length,
mergeOpts, checkoutOpts);
};
208 changes: 208 additions & 0 deletions 208 test/tests/merge.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
var assert = require("assert");
var path = require("path");
var Promise = require("nodegit-promise");
var promisify = require("promisify-node");
var fse = promisify(require("fs-extra"));
var local = path.join.bind(path, __dirname);
Expand Down Expand Up @@ -524,4 +525,211 @@ describe("Merge", function() {
"49014ccabf5125f9b69316acde36f891dfdb8b5c");
});
});

it("leaves repo in MERGE state after a standard merge with conflicts fails",
function() {
var fileName = "everyonesFile.txt";

var baseFileContent = "How do you feel about Toll Roads?\n";
var ourFileContent = "I like Toll Roads. I have an EZ-Pass!\n";
var theirFileContent = "I'm skeptical about Toll Roads\n";

var expectedConflictedFileContent =
"How do you feel about Toll Roads?\n" +
"<<<<<<< HEAD\n" +
"I like Toll Roads. I have an EZ-Pass!\n" +
"=======\n" +
"I'm skeptical about Toll Roads\n" +
">>>>>>> theirs\n";

var conflictSolvedFileContent =
"How do you feel about Toll Roads?\n" +
"He's skeptical about Toll Roads,\n" +
"but I like Toll Roads. I have an EZ-Pass!\n";

var ourSignature = NodeGit.Signature.create
("Ron Paul", "RonPaul@TollRoadsRBest.info", 123456789, 60);
var theirSignature = NodeGit.Signature.create
("Greg Abbott", "Gregggg@IllTollYourFace.us", 123456789, 60);

var repository = this.repository;
var initialCommit;
var ourBranch;
var theirBranch;

var repoGitPath = repository.path();
if (!~repoGitPath.indexOf("/.git")) {
repoGitPath = path.join(repoGitPath, ".git");
}

return fse.writeFile(path.join(repository.workdir(), fileName),
baseFileContent)
.then(function() {
return repository.openIndex().then(function(index) {
index.read(1);
index.addByPath(fileName);
index.write();

return index.writeTree();
});
})
.then(function(oid) {
assert.equal(oid.toString(),
"044704f62399fecbe22da6d7d47b14e52625630e");

return repository.createCommit("HEAD", ourSignature,
ourSignature, "initial commit", oid, []);
})
.then(function(commitOid) {
assert.equal(commitOid.toString(),
"80111c46ac73b857a3493b24c81df08639b5de99");

return repository.getCommit(commitOid).then(function(commit) {
initialCommit = commit;
}).then(function() {
return repository.createBranch(ourBranchName, commitOid)
.then(function(branch) {
ourBranch = branch;
return repository.createBranch(theirBranchName, commitOid);
});
});
})
.then(function(branch) {
theirBranch = branch;
return fse.writeFile(path.join(repository.workdir(), fileName),
baseFileContent + theirFileContent);
})
.then(function() {
return repository.openIndex().then(function(index) {
index.read(1);
index.addByPath(fileName);
index.write();

return index.writeTree();
});
})
.then(function(oid) {
assert.equal(oid.toString(),
"b826e989aca7647bea64810f0a2a38acbbdd4c1a");

return repository.createCommit(theirBranch.name(), theirSignature,
theirSignature, "they made a commit", oid, [initialCommit]);
})
.then(function(commitOid) {
assert.equal(commitOid.toString(),
"b3c355bb606ec7da87174dfa1a0b0c0e3dc97bc0");

return fse.writeFile(path.join(repository.workdir(), fileName),
baseFileContent + ourFileContent);
})
.then(function() {
return repository.openIndex().then(function(index) {
index.read(1);
index.addByPath(fileName);
index.write();

return index.writeTree();
});
})
.then(function(oid) {
assert.equal(oid.toString(),
"e7fe41bf7c0c28766887a63ffe2f03f624276fbe");

return repository.createCommit(ourBranch.name(), ourSignature,
ourSignature, "we made a commit", oid, [initialCommit]);
})
.then(function(commitOid) {
assert.equal(commitOid.toString(),
"28cfeb17f66132edb3c4dacb7ff38e8dd48a1844");

//return repository.getCommit(commitOid)

var opts = {
checkoutStrategy: NodeGit.Checkout.STRATEGY.FORCE
};

return repository.checkoutBranch(ourBranchName, opts);
})
.then(function() {
return repository.getHeadCommit();
})
.then(function(commit) {
assert.equal(commit.id().toString(),
"28cfeb17f66132edb3c4dacb7ff38e8dd48a1844");

return repository.getReference(theirBranchName);
})
.then(function(theirRef) {
return NodeGit.AnnotatedCommit.fromRef(repository, theirRef);
})
.then(function(theirAnnotatedCommit) {
return NodeGit.Merge(repository, theirAnnotatedCommit);
})
.then(function(result) {
assert.equal(result, 0);

assert.equal(repository.state(),
NodeGit.Repository.STATE.MERGE);

assert.ok(fse.existsSync(path.join(repoGitPath, "MERGE_HEAD")));
assert.ok(fse.existsSync(path.join(repoGitPath, "MERGE_MSG")));
assert.ok(fse.existsSync(path.join(repoGitPath, "MERGE_MODE")));

return fse.readFile(path.join(repoGitPath, "MERGE_HEAD"), "utf-8");
})
.then(function(mergeHeadContents) {
assert.equal(mergeHeadContents,
"b3c355bb606ec7da87174dfa1a0b0c0e3dc97bc0\n");

return fse.readFile(path.join(repository.workdir(), fileName), "utf-8");
})
.then(function(fileContent) {
assert.equal(fileContent, expectedConflictedFileContent);

return fse.writeFile(path.join(repository.workdir(), fileName),
conflictSolvedFileContent);
})
.then(function() {
return repository.openIndex()
.then(function(index) {
index.read(1);
index.addByPath(fileName);
index.write();

return index.writeTree();
});
})
.then(function(oid) {
return Promise.all([
repository.getBranchCommit(ourBranchName),
repository.getBranchCommit("MERGE_HEAD")
])
.then(function(commits) {
var msg = fse.readFileSync(path.join(repoGitPath, "MERGE_MSG"),
"utf-8");
assert.ok(msg);

return repository.createCommit(ourBranch.name(), ourSignature,
ourSignature, msg, oid, [commits[0], commits[1]]);
});
})
.then(function(commitOid) {
assert.equal(commitOid.toString(),
"03ba156a7a1660f179b6b2dbc6a542fcf88d022d");

// merge isn't cleaned up automatically
assert.ok(fse.existsSync(path.join(repoGitPath, "MERGE_HEAD")));
assert.ok(fse.existsSync(path.join(repoGitPath, "MERGE_MSG")));
assert.ok(fse.existsSync(path.join(repoGitPath, "MERGE_MODE")));

assert.equal(repository.stateCleanup(), 0);

assert.ok(!fse.existsSync(path.join(repoGitPath, "MERGE_HEAD")));
assert.ok(!fse.existsSync(path.join(repoGitPath, "MERGE_MSG")));
assert.ok(!fse.existsSync(path.join(repoGitPath, "MERGE_MODE")));

assert.equal(repository.state(),
NodeGit.Repository.STATE.NONE);
});
});
});
Morty Proxy This is a proxified and sanitized view of the page, visit original site.