Skip to content

Commit 2ab75df

Browse files
committed
added convenience method: repository.rebaseBranches()
1 parent ab50c82 commit 2ab75df

2 files changed

Lines changed: 369 additions & 0 deletions

File tree

lib/repository.js

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -747,6 +747,117 @@ Repository.prototype.mergeBranches = function(to, from, signature) {
747747
});
748748
};
749749

750+
/**
751+
* Goes through a rebase's rebase operations and commits them if there are
752+
* no merge conflicts
753+
*
754+
* @param {Repository} repository The repository that the rebase is being
755+
* performed in
756+
* @param {Rebase} rebase The current rebase being performed
757+
* @param {Signature} signature Identity of the one performing the rebase
758+
* @return {Int|Index} An error code for an unsuccesful rebase or an index for
759+
* a rebase with conflicts
760+
*/
761+
function performRebase(repository, rebase, signature) {
762+
return rebase.next()
763+
.then(function(rebaseOperation) {
764+
return repository.openIndex()
765+
.then(function(index) {
766+
if (index.hasConflicts()) {
767+
throw index;
768+
}
769+
770+
if (rebaseOperation) {
771+
rebase.commit(null, signature);
772+
773+
return performRebase(repository, rebase, signature);
774+
}
775+
776+
return rebase.finish(signature);
777+
});
778+
});
779+
}
780+
781+
/**
782+
* Rebases a branch onto another branch
783+
*
784+
* @param {String} branch
785+
* @param {String} upstream
786+
* @param {String} onto
787+
* @param {Signature} signature Identity of the one performing the rebase
788+
* @return {Oid|Index} A commit id for a succesful merge or an index for a
789+
* rebase with conflicts
790+
*/
791+
Repository.prototype.rebaseBranches = function(
792+
branch,
793+
upstream,
794+
onto,
795+
signature)
796+
{
797+
var repo = this;
798+
799+
signature = signature || repo.defaultSignature();
800+
801+
return Promise.all([
802+
repo.getReference(branch),
803+
upstream ? repo.getReference(upstream) : null,
804+
onto ? repo.getReference(upstream) : null
805+
])
806+
.then(function(refs) {
807+
return Promise.all([
808+
NodeGit.AnnotatedCommit.fromRef(repo, refs[0]),
809+
upstream ? NodeGit.AnnotatedCommit.fromRef(repo, refs[1]) : null,
810+
onto ? NodeGit.AnnotatedCommit.fromRef(repo, refs[2]) : null
811+
]);
812+
})
813+
.then(function(annotatedCommits) {
814+
return NodeGit.Rebase.init(repo, annotatedCommits[0], annotatedCommits[1],
815+
annotatedCommits[2], signature, null);
816+
})
817+
.then(function(rebase) {
818+
return performRebase(repo, rebase, signature);
819+
})
820+
.then(function(error) {
821+
if (error) {
822+
throw error;
823+
}
824+
825+
return repo.getBranchCommit("HEAD");
826+
});
827+
};
828+
829+
/**
830+
* Continues an existing rebase
831+
*
832+
* @param {Signature} signature Identity of the one performing the rebase
833+
* @return {Oid|Index} A commit id for a succesful merge or an index for a
834+
* rebase with conflicts
835+
*/
836+
Repository.prototype.continueRebase = function(signature) {
837+
var repo = this;
838+
839+
return repo.openIndex()
840+
.then(function(index) {
841+
if (index.hasConflicts()) {
842+
throw index;
843+
}
844+
845+
return NodeGit.Rebase.open(repo);
846+
})
847+
.then(function(rebase) {
848+
rebase.commit(null, signature);
849+
850+
return performRebase(repo, rebase, signature);
851+
})
852+
.then(function(error) {
853+
if (error) {
854+
throw error;
855+
}
856+
857+
return repo.getBranchCommit("HEAD");
858+
});
859+
};
860+
750861
// Override Repository.initExt to normalize initoptions
751862
var initExt = Repository.initExt;
752863
Repository.initExt = function(repo_path, opts) {

test/tests/rebase.js

Lines changed: 258 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -706,4 +706,262 @@ describe("Rebase", function() {
706706
"e7f37ee070837052937e24ad8ba66f6d83ae7941");
707707
});
708708
});
709+
710+
it("can rebase using the convenience method", function() {
711+
var baseFileName = "baseNewFile.txt";
712+
var ourFileName = "ourNewFile.txt";
713+
var theirFileName = "theirNewFile.txt";
714+
715+
var baseFileContent = "How do you feel about Toll Roads?";
716+
var ourFileContent = "I like Toll Roads. I have an EZ-Pass!";
717+
var theirFileContent = "I'm skeptical about Toll Roads";
718+
719+
var ourSignature = NodeGit.Signature.create
720+
("Ron Paul", "RonPaul@TollRoadsRBest.info", 123456789, 60);
721+
var theirSignature = NodeGit.Signature.create
722+
("Greg Abbott", "Gregggg@IllTollYourFace.us", 123456789, 60);
723+
724+
var repository = this.repository;
725+
var ourCommit;
726+
var ourBranch;
727+
var theirBranch;
728+
729+
return fse.writeFile(path.join(repository.workdir(), baseFileName),
730+
baseFileContent)
731+
// Load up the repository index and make our initial commit to HEAD
732+
.then(function() {
733+
return addFileToIndex(repository, baseFileName);
734+
})
735+
.then(function(oid) {
736+
assert.equal(oid.toString(),
737+
"b5cdc109d437c4541a13fb7509116b5f03d5039a");
738+
739+
return repository.createCommit("HEAD", ourSignature,
740+
ourSignature, "initial commit", oid, []);
741+
})
742+
.then(function(commitOid) {
743+
assert.equal(commitOid.toString(),
744+
"be03abdf0353d05924c53bebeb0e5bb129cda44a");
745+
746+
return repository.getCommit(commitOid).then(function(commit) {
747+
ourCommit = commit;
748+
}).then(function() {
749+
return repository.createBranch(ourBranchName, commitOid)
750+
.then(function(branch) {
751+
ourBranch = branch;
752+
return repository.createBranch(theirBranchName, commitOid);
753+
});
754+
});
755+
})
756+
.then(function(branch) {
757+
theirBranch = branch;
758+
return fse.writeFile(path.join(repository.workdir(), theirFileName),
759+
theirFileContent);
760+
})
761+
.then(function() {
762+
return addFileToIndex(repository, theirFileName);
763+
})
764+
.then(function(oid) {
765+
assert.equal(oid.toString(),
766+
"be5f0fd38a39a67135ad68921c93cd5c17fefb3d");
767+
768+
return repository.createCommit(theirBranch.name(), theirSignature,
769+
theirSignature, "they made a commit", oid, [ourCommit]);
770+
})
771+
.then(function(commitOid) {
772+
assert.equal(commitOid.toString(),
773+
"e9ebd92f2f4778baf6fa8e92f0c68642f931a554");
774+
775+
return removeFileFromIndex(repository, theirFileName);
776+
})
777+
.then(function() {
778+
return fse.remove(path.join(repository.workdir(), theirFileName));
779+
})
780+
.then(function() {
781+
return fse.writeFile(path.join(repository.workdir(), ourFileName),
782+
ourFileContent);
783+
})
784+
.then(function() {
785+
return addFileToIndex(repository, ourFileName);
786+
})
787+
.then(function(oid) {
788+
assert.equal(oid.toString(),
789+
"77867fc0bfeb3f80ab18a78c8d53aa3a06207047");
790+
791+
return repository.createCommit(ourBranch.name(), ourSignature,
792+
ourSignature, "we made a commit", oid, [ourCommit]);
793+
})
794+
.then(function(commitOid) {
795+
assert.equal(commitOid.toString(),
796+
"e7f37ee070837052937e24ad8ba66f6d83ae7941");
797+
798+
return removeFileFromIndex(repository, ourFileName);
799+
})
800+
.then(function() {
801+
return fse.remove(path.join(repository.workdir(), ourFileName));
802+
})
803+
.then(function() {
804+
return repository.checkoutBranch(ourBranchName);
805+
})
806+
.then(function() {
807+
return repository.rebaseBranches(ourBranchName, theirBranchName,
808+
null, ourSignature);
809+
})
810+
.then(function(commit) {
811+
// verify that the "ours" branch has moved to the correct place
812+
assert.equal(commit.id().toString(),
813+
"b937100ee0ea17ef20525306763505a7fe2be29e");
814+
815+
return commit.parent(0);
816+
})
817+
.then(function(commit) {
818+
// verify that we are on top of "their commit"
819+
assert.equal(commit.id().toString(),
820+
"e9ebd92f2f4778baf6fa8e92f0c68642f931a554");
821+
});
822+
});
823+
824+
it("can rebase with conflicts using the convenience methods", function() {
825+
var fileName = "everyonesFile.txt";
826+
827+
var baseFileContent = "How do you feel about Toll Roads?\n";
828+
var ourFileContent = "I like Toll Roads. I have an EZ-Pass!\n";
829+
var theirFileContent = "I'm skeptical about Toll Roads\n";
830+
831+
var expectedConflictedFileContent =
832+
"How do you feel about Toll Roads?\n" +
833+
"<<<<<<< theirs\n" +
834+
"I'm skeptical about Toll Roads\n" +
835+
"=======\n" +
836+
"I like Toll Roads. I have an EZ-Pass!\n" +
837+
">>>>>>> we made a commit\n";
838+
839+
var conflictSolvedFileContent =
840+
"How do you feel about Toll Roads?\n" +
841+
"He's skeptical about Toll Roads,\n" +
842+
"but I like Toll Roads. I have an EZ-Pass!\n";
843+
844+
var ourSignature = NodeGit.Signature.create
845+
("Ron Paul", "RonPaul@TollRoadsRBest.info", 123456789, 60);
846+
var theirSignature = NodeGit.Signature.create
847+
("Greg Abbott", "Gregggg@IllTollYourFace.us", 123456789, 60);
848+
849+
var repository = this.repository;
850+
var ourCommit;
851+
var ourBranch;
852+
var theirBranch;
853+
854+
return fse.writeFile(path.join(repository.workdir(), fileName),
855+
baseFileContent)
856+
.then(function() {
857+
return addFileToIndex(repository, fileName);
858+
})
859+
.then(function(oid) {
860+
assert.equal(oid.toString(),
861+
"044704f62399fecbe22da6d7d47b14e52625630e");
862+
863+
return repository.createCommit("HEAD", ourSignature,
864+
ourSignature, "initial commit", oid, []);
865+
})
866+
.then(function(commitOid) {
867+
assert.equal(commitOid.toString(),
868+
"80111c46ac73b857a3493b24c81df08639b5de99");
869+
870+
return repository.getCommit(commitOid).then(function(commit) {
871+
ourCommit = commit;
872+
}).then(function() {
873+
return repository.createBranch(ourBranchName, commitOid)
874+
.then(function(branch) {
875+
ourBranch = branch;
876+
return repository.createBranch(theirBranchName, commitOid);
877+
});
878+
});
879+
})
880+
.then(function(branch) {
881+
theirBranch = branch;
882+
return fse.writeFile(path.join(repository.workdir(), fileName),
883+
baseFileContent + theirFileContent);
884+
})
885+
.then(function() {
886+
return addFileToIndex(repository, fileName);
887+
})
888+
.then(function(oid) {
889+
assert.equal(oid.toString(),
890+
"b826e989aca7647bea64810f0a2a38acbbdd4c1a");
891+
892+
return repository.createCommit(theirBranch.name(), theirSignature,
893+
theirSignature, "they made a commit", oid, [ourCommit]);
894+
})
895+
.then(function(commitOid) {
896+
assert.equal(commitOid.toString(),
897+
"b3c355bb606ec7da87174dfa1a0b0c0e3dc97bc0");
898+
899+
return fse.writeFile(path.join(repository.workdir(), fileName),
900+
baseFileContent + ourFileContent);
901+
})
902+
.then(function() {
903+
return addFileToIndex(repository, fileName);
904+
})
905+
.then(function(oid) {
906+
assert.equal(oid.toString(),
907+
"e7fe41bf7c0c28766887a63ffe2f03f624276fbe");
908+
909+
return repository.createCommit(ourBranch.name(), ourSignature,
910+
ourSignature, "we made a commit", oid, [ourCommit]);
911+
})
912+
.then(function(commitOid) {
913+
assert.equal(commitOid.toString(),
914+
"28cfeb17f66132edb3c4dacb7ff38e8dd48a1844");
915+
916+
var opts = {
917+
checkoutStrategy: NodeGit.Checkout.STRATEGY.FORCE
918+
};
919+
920+
return NodeGit.Checkout.head(repository, opts);
921+
})
922+
.then(function() {
923+
return repository.rebaseBranches(ourBranchName, theirBranchName,
924+
null, ourSignature)
925+
.then(function(commit) {
926+
assert.fail(commit, undefined,
927+
"The index should have been thrown due to merge conflicts");
928+
})
929+
.catch(function(index) {
930+
assert.ok(index);
931+
assert.ok(index.hasConflicts());
932+
});
933+
})
934+
.then(function() {
935+
return fse.readFile(path.join(repository.workdir(), fileName), "utf8")
936+
.then(function(fileContent) {
937+
assert.equal(fileContent, expectedConflictedFileContent);
938+
939+
return fse.writeFile(path.join(repository.workdir(), fileName),
940+
conflictSolvedFileContent);
941+
});
942+
})
943+
.then(function() {
944+
return addFileToIndex(repository, fileName);
945+
})
946+
.then(function(oid) {
947+
return repository.openIndex()
948+
.then(function(index) {
949+
assert.ok(!index.hasConflicts());
950+
951+
return repository.continueRebase(ourSignature);
952+
});
953+
})
954+
.then(function(commit) {
955+
// verify that the "ours" branch has moved to the correct place
956+
assert.equal(commit.id().toString(),
957+
"ef6d0e95167435b3d58f51ab165948c72f6f94b6");
958+
959+
return commit.parent(0);
960+
})
961+
.then(function(commit) {
962+
// verify that we are on top of "their commit"
963+
assert.equal(commit.id().toString(),
964+
"b3c355bb606ec7da87174dfa1a0b0c0e3dc97bc0");
965+
});
966+
});
709967
});

0 commit comments

Comments
 (0)