Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
Prev Previous commit
added convenience method: repository.rebaseBranches()
  • Loading branch information
jdgarcia committed May 14, 2015
commit 2ab75df99fc99d0867c62bd11ecaa7e68d1905d6
111 changes: 111 additions & 0 deletions lib/repository.js
Original file line number Diff line number Diff line change
Expand Up @@ -747,6 +747,117 @@ Repository.prototype.mergeBranches = function(to, from, signature) {
});
};

/**
* Goes through a rebase's rebase operations and commits them if there are
* no merge conflicts
*
* @param {Repository} repository The repository that the rebase is being
* performed in
* @param {Rebase} rebase The current rebase being performed
* @param {Signature} signature Identity of the one performing the rebase
* @return {Int|Index} An error code for an unsuccesful rebase or an index for
* a rebase with conflicts
*/
function performRebase(repository, rebase, signature) {
return rebase.next()
.then(function(rebaseOperation) {
return repository.openIndex()
.then(function(index) {
if (index.hasConflicts()) {
throw index;
}

if (rebaseOperation) {
rebase.commit(null, signature);

return performRebase(repository, rebase, signature);
}

return rebase.finish(signature);
});
});
}

/**
* Rebases a branch onto another branch
*
* @param {String} branch
* @param {String} upstream
* @param {String} onto
* @param {Signature} signature Identity of the one performing the rebase
* @return {Oid|Index} A commit id for a succesful merge or an index for a
* rebase with conflicts
*/
Repository.prototype.rebaseBranches = function(
branch,
upstream,
onto,
signature)
{
var repo = this;

signature = signature || repo.defaultSignature();

return Promise.all([
repo.getReference(branch),
upstream ? repo.getReference(upstream) : null,
onto ? repo.getReference(upstream) : null
])
.then(function(refs) {
return Promise.all([
NodeGit.AnnotatedCommit.fromRef(repo, refs[0]),
upstream ? NodeGit.AnnotatedCommit.fromRef(repo, refs[1]) : null,
onto ? NodeGit.AnnotatedCommit.fromRef(repo, refs[2]) : null
]);
})
.then(function(annotatedCommits) {
return NodeGit.Rebase.init(repo, annotatedCommits[0], annotatedCommits[1],
annotatedCommits[2], signature, null);
})
.then(function(rebase) {
return performRebase(repo, rebase, signature);
})
.then(function(error) {
if (error) {
throw error;
}

return repo.getBranchCommit("HEAD");
});
};

/**
* Continues an existing rebase
*
* @param {Signature} signature Identity of the one performing the rebase
* @return {Oid|Index} A commit id for a succesful merge or an index for a
* rebase with conflicts
*/
Repository.prototype.continueRebase = function(signature) {
var repo = this;

return repo.openIndex()
.then(function(index) {
if (index.hasConflicts()) {
throw index;
}

return NodeGit.Rebase.open(repo);
})
.then(function(rebase) {
rebase.commit(null, signature);

return performRebase(repo, rebase, signature);
})
.then(function(error) {
if (error) {
throw error;
}

return repo.getBranchCommit("HEAD");
});
};

// Override Repository.initExt to normalize initoptions
var initExt = Repository.initExt;
Repository.initExt = function(repo_path, opts) {
Expand Down
258 changes: 258 additions & 0 deletions test/tests/rebase.js
Original file line number Diff line number Diff line change
Expand Up @@ -706,4 +706,262 @@ describe("Rebase", function() {
"e7f37ee070837052937e24ad8ba66f6d83ae7941");
});
});

it("can rebase using the convenience method", function() {
var baseFileName = "baseNewFile.txt";
var ourFileName = "ourNewFile.txt";
var theirFileName = "theirNewFile.txt";

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

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 ourCommit;
var ourBranch;
var theirBranch;

return fse.writeFile(path.join(repository.workdir(), baseFileName),
baseFileContent)
// Load up the repository index and make our initial commit to HEAD
.then(function() {
return addFileToIndex(repository, baseFileName);
})
.then(function(oid) {
assert.equal(oid.toString(),
"b5cdc109d437c4541a13fb7509116b5f03d5039a");

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

return repository.getCommit(commitOid).then(function(commit) {
ourCommit = 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(), theirFileName),
theirFileContent);
})
.then(function() {
return addFileToIndex(repository, theirFileName);
})
.then(function(oid) {
assert.equal(oid.toString(),
"be5f0fd38a39a67135ad68921c93cd5c17fefb3d");

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

return removeFileFromIndex(repository, theirFileName);
})
.then(function() {
return fse.remove(path.join(repository.workdir(), theirFileName));
})
.then(function() {
return fse.writeFile(path.join(repository.workdir(), ourFileName),
ourFileContent);
})
.then(function() {
return addFileToIndex(repository, ourFileName);
})
.then(function(oid) {
assert.equal(oid.toString(),
"77867fc0bfeb3f80ab18a78c8d53aa3a06207047");

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

return removeFileFromIndex(repository, ourFileName);
})
.then(function() {
return fse.remove(path.join(repository.workdir(), ourFileName));
})
.then(function() {
return repository.checkoutBranch(ourBranchName);
})
.then(function() {
return repository.rebaseBranches(ourBranchName, theirBranchName,
null, ourSignature);
})
.then(function(commit) {
// verify that the "ours" branch has moved to the correct place
assert.equal(commit.id().toString(),
"b937100ee0ea17ef20525306763505a7fe2be29e");

return commit.parent(0);
})
.then(function(commit) {
// verify that we are on top of "their commit"
assert.equal(commit.id().toString(),
"e9ebd92f2f4778baf6fa8e92f0c68642f931a554");
});
});

it("can rebase with conflicts using the convenience methods", 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" +
"<<<<<<< theirs\n" +
"I'm skeptical about Toll Roads\n" +
"=======\n" +
"I like Toll Roads. I have an EZ-Pass!\n" +
">>>>>>> we made a commit\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 ourCommit;
var ourBranch;
var theirBranch;

return fse.writeFile(path.join(repository.workdir(), fileName),
baseFileContent)
.then(function() {
return addFileToIndex(repository, fileName);
})
.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) {
ourCommit = 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 addFileToIndex(repository, fileName);
})
.then(function(oid) {
assert.equal(oid.toString(),
"b826e989aca7647bea64810f0a2a38acbbdd4c1a");

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

return fse.writeFile(path.join(repository.workdir(), fileName),
baseFileContent + ourFileContent);
})
.then(function() {
return addFileToIndex(repository, fileName);
})
.then(function(oid) {
assert.equal(oid.toString(),
"e7fe41bf7c0c28766887a63ffe2f03f624276fbe");

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

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

return NodeGit.Checkout.head(repository, opts);
})
.then(function() {
return repository.rebaseBranches(ourBranchName, theirBranchName,
null, ourSignature)
.then(function(commit) {
assert.fail(commit, undefined,
"The index should have been thrown due to merge conflicts");
})
.catch(function(index) {
assert.ok(index);
assert.ok(index.hasConflicts());
});
})
.then(function() {
return fse.readFile(path.join(repository.workdir(), fileName), "utf8")
.then(function(fileContent) {
assert.equal(fileContent, expectedConflictedFileContent);

return fse.writeFile(path.join(repository.workdir(), fileName),
conflictSolvedFileContent);
});
})
.then(function() {
return addFileToIndex(repository, fileName);
})
.then(function(oid) {
return repository.openIndex()
.then(function(index) {
assert.ok(!index.hasConflicts());

return repository.continueRebase(ourSignature);
});
})
.then(function(commit) {
// verify that the "ours" branch has moved to the correct place
assert.equal(commit.id().toString(),
"ef6d0e95167435b3d58f51ab165948c72f6f94b6");

return commit.parent(0);
})
.then(function(commit) {
// verify that we are on top of "their commit"
assert.equal(commit.id().toString(),
"b3c355bb606ec7da87174dfa1a0b0c0e3dc97bc0");
});
});
});