diff --git a/README.md b/README.md index 941847d24..fed19d049 100644 --- a/README.md +++ b/README.md @@ -134,12 +134,12 @@ var open = require("nodegit").Repository.open; open("tmp") // Open the master branch. .then(function(repo) { - return repo.getMaster(); + return repo.getMasterCommit(); }) // Display information about commits on master. - .then(function(branch) { + .then(function(firstCommitOnMaster) { // Create a new history event emitter. - var history = branch.history(); + var history = firstCommitOnMaster.history(); // Create a counter to only show up to 9 entries. var count = 0; diff --git a/example/apps/git_profanity_check.js b/example/apps/git_profanity_check.js index 7f0674849..ab38eb919 100644 --- a/example/apps/git_profanity_check.js +++ b/example/apps/git_profanity_check.js @@ -35,32 +35,25 @@ else { } // Open repository. -git.Repo.open(path, function(err, repo) { - if (err) { - throw new Error(err); - } - +git.Repo.open(path) +.then(function(repo) { // Open branch, default to master. - repo.getBranch(branch, function(err, branch) { - if (err) { - throw new Error(err); + return repo.getBranchCommit(branch); +}).then(function(firstCommit) { + // Iterate history + var history = firstCommit.history(); + + // Iterate over every commit message and test for words. + history.on('commit', function(commit) { + var message = commit.message(); + + if (reCurse.test(message)) { + console.log('Curse detected in commit', commit.sha()); + console.log('=> ', message); + return; } - - // Iterate history - var history = branch.history(); - - // Iterate over every commit message and test for words. - history.on('commit', function(commit) { - var message = commit.message(); - - if (reCurse.test(message)) { - console.log('Curse detected in commit', commit.sha()); - console.log('=> ', message); - return; - } - }); - - // Start history iteration. - history.start(); }); + + // Start history iteration. + history.start(); }); diff --git a/example/walk-history.js b/example/walk-history.js index 7f6824a8a..f12e6503f 100644 --- a/example/walk-history.js +++ b/example/walk-history.js @@ -6,10 +6,10 @@ var nodegit = require('../'), // that look very similar to calling `git log` from the command line nodegit.Repository.open(path.resolve(__dirname, '../.git')).then(function(repo) { - return repo.getMaster(); -}).then(function(branch){ + return repo.getMasterCommit(); +}).then(function(firstCommitOnMaster){ // History returns an event. - var history = branch.history(sort.Time); + var history = firstCommitOnMaster.history(sort.Time); // History emits 'commit' event for each commit in the branch's history history.on('commit', function(commit) { diff --git a/example/walk-tree.js b/example/walk-tree.js index 3f2454849..9278eb345 100644 --- a/example/walk-tree.js +++ b/example/walk-tree.js @@ -6,9 +6,9 @@ var nodegit = require('../'), // tree (directory), or a file. nodegit.Repository.open(path.resolve(__dirname, '../.git')).then(function(repo) { - return repo.getMaster(); -}).then(function(branch) { - return branch.getTree(); + return repo.getMasterCommit(); +}).then(function(firstCommitOnMaster) { + return firstCommitOnMaster.getTree(); }).then(function(tree) { // `walk()` returns an event. var walker = tree.walk(); diff --git a/generate/descriptor.json b/generate/descriptor.json index 426c6e63c..eb55e625d 100644 --- a/generate/descriptor.json +++ b/generate/descriptor.json @@ -85,8 +85,32 @@ }, "branch": { "functions": { + "git_branch_create": { + "args": { + "force": { + "isOptional": true + }, + "signature": { + "isOptional": true + }, + "log_message": { + "isOptional": true + } + } + }, "git_branch_next": { "ignore": true + }, + "git_branch_set_upstream": { + "isAsync": false, + "args": { + "upstream_name": { + "isOptional": true + } + } + }, + "git_branch_upstream": { + "isAsync": false } } }, diff --git a/lib/branch.js b/lib/branch.js new file mode 100644 index 000000000..a437f1de6 --- /dev/null +++ b/lib/branch.js @@ -0,0 +1,5 @@ +var NodeGit = require("../"); + +var Branch = NodeGit.Branch; + +module.exports = Branch; diff --git a/lib/refs.js b/lib/refs.js index ee7d60c41..c6775d58d 100644 --- a/lib/refs.js +++ b/lib/refs.js @@ -1,6 +1,7 @@ var NodeGit = require("../"); var Reference = NodeGit.Refs; +var Branch = NodeGit.Branch; Reference.Type = { Oid: 1, @@ -32,4 +33,12 @@ Reference.prototype.toString = function() { return this.name(); }; +/** + * Returns if the ref is pointed at by HEAD + * @return {bool} + */ +Reference.prototype.isHead = function() { + return Branch.isHead(this); +}; + module.exports = Reference; diff --git a/lib/repository.js b/lib/repository.js index 2ee9ee71a..bd6a9c0bf 100644 --- a/lib/repository.js +++ b/lib/repository.js @@ -18,16 +18,71 @@ Object.defineProperty(Repository.prototype, "openIndex", { }); /** - * Look up a branch"s most recent commit. + * Creates a branch with the passed in name pointing to the commit + * + * @param {String} name Branch name, e.g. "master" + * @param {Commit|String|Oid} commit The commit the branch will point to + * @param {bool} force Overwrite branch if it exists + * @param {Signature} signature Identity to use to populate reflog + * @param {String} logMessage One line message to be appended to the reflog + * @return {Ref} + */ +Repository.prototype.createBranch = +function(name, commit, force, signature, logMessage) { + var repo = this; + + if (commit instanceof Commit) { + return NodeGit.Branch.create( + repo, + name, + commit, + force ? 1 : 0, + signature, + logMessage); + } + else { + return repo.getCommit(commit).then(function(commit) { + return NodeGit.Branch.create( + repo, + name, + commit, + force ? 1 : 0, + signature, + logMessage); + }); + } +}; + +/** + * Look up a branch * * @param {String} name Branch name, e.g. "master" * @param {Function} callback - * @return {Branch} + * @return {Ref} */ Repository.prototype.getBranch = function(name, callback) { + name = ~name.indexOf("refs/heads/") ? name : "refs/heads/" + name; + + return this.getReference(name).then(function(reference) { + if (typeof callback === "function") { + callback(null, reference); + } + + return reference; + }, callback); +}; + +/** + * Look up a branch's most recent commit. + * + * @param {String} name Branch name, e.g. "master" + * @param {Function} callback + * @return {Commit} + */ +Repository.prototype.getBranchCommit = function(name, callback) { var repository = this; - return this.getReference("refs/heads/" + name).then(function(reference) { + return this.getBranch(name).then(function(reference) { return repository.getCommit(reference.target()).then(function(commit) { if (typeof callback === "function") { callback(null, commit); @@ -262,13 +317,13 @@ Repository.prototype.createRevWalk = function() { }; /** - * Retrieve the master branch. + * Retrieve the master branch commit. * * @param {Function} callback - * @return {Branch} + * @return {Commit} */ -Repository.prototype.getMaster = function(callback) { - return this.getBranch("master", callback); +Repository.prototype.getMasterCommit = function(callback) { + return this.getBranchCommit("master", callback); }; /** diff --git a/test/tests/branch.js b/test/tests/branch.js new file mode 100644 index 000000000..6b717e476 --- /dev/null +++ b/test/tests/branch.js @@ -0,0 +1,63 @@ +var assert = require("assert"); +var path = require("path"); + +describe("Branch", function() { + var reposPath = path.resolve("test/repos/workdir/.git"); + + var Repository = require("../../lib/repository"); + var Branch = require("../../lib/branch"); + var branchName = "test-branch"; + var fullBranchName = "refs/heads/" + branchName; + + before(function() { + var test = this; + + return Repository.open(reposPath).then(function(repository) { + test.repo = repository; + }); + }); + + beforeEach(function() { + var test = this; + var repo = test.repo; + + return repo.getMasterCommit().then(function(masterCommit) { + test.masterCommit = masterCommit; + + return repo.createBranch(branchName, masterCommit, true) + .then(function(branch) { + test.branch = branch; + }); + }); + }); + + it("can create a branch", function() { + var branch = this.branch; + var masterCommit = this.masterCommit; + + assert.equal(branch.name(), fullBranchName); + assert.equal(branch.target().toString(), masterCommit.sha()); + }); + + it("can delete a branch", function() { + var repo = this.repo; + + Branch.delete(this.branch); + + return repo.getBranch(branchName).then(function() { + // branch wasn't deleted + assert.ok(false); + }, function() { + // branch was deleted! + assert.ok(true); + }); + }); + + it("can see if the branch is pointed to by head", function() { + var repo = this.repo; + + return repo.getBranch("master").then(function(branch) { + assert.ok(branch.isHead()); + }); + }); +}); diff --git a/test/tests/commit.js b/test/tests/commit.js index d76e38dde..61b847cd8 100644 --- a/test/tests/commit.js +++ b/test/tests/commit.js @@ -177,8 +177,8 @@ describe("Commit", function() { it("can fetch the master branch HEAD", function() { var repository = this.repository; - return repository.getBranch("master").then(function(branch) { - return repository.getCommit(branch.sha()); + return repository.getBranchCommit("master").then(function(commit) { + return repository.getCommit(commit.sha()); }); }); diff --git a/test/tests/revwalk.js b/test/tests/revwalk.js index a8aea1b20..21e10a172 100644 --- a/test/tests/revwalk.js +++ b/test/tests/revwalk.js @@ -12,8 +12,8 @@ describe("Revwalk", function() { var test = this; return Repository.open(reposPath).then(function(repository) { test.repository = repository; - return test.repository.getBranch("rev-walk").then(function(branch) { - test.branch = branch; + return test.repository.getBranchCommit("rev-walk").then(function(commit) { + test.commit = commit; done(); }); }); @@ -21,7 +21,7 @@ describe("Revwalk", function() { beforeEach(function() { this.walker = this.repository.createRevWalk(); - this.walker.push(this.branch.id()); + this.walker.push(this.commit.id()); }); it("can create a walker", function() { @@ -29,7 +29,7 @@ describe("Revwalk", function() { }); it("can push an object", function() { - var sha = this.branch.sha(); + var sha = this.commit.sha(); return this.walker.next().then(function(commit) { assert.equal(sha, commit); @@ -49,7 +49,7 @@ describe("Revwalk", function() { assert.equal(commit.toString(), "b8a94aefb22d0534cc0e5acf533989c13d8725dc"); test.walker = test.repository.createRevWalk(); - test.walker.push(test.branch.id()); + test.walker.push(test.commit.id()); test.walker.hide( Oid.fromString("b8a94aefb22d0534cc0e5acf533989c13d8725dc")); @@ -89,9 +89,9 @@ describe("Revwalk", function() { this.timeout(10000); return Repository.open(reposPath).then(function(repository) { var walker = repository.createRevWalk(); - return repository.getMaster().then(function(master) { + return repository.getMasterCommit().then(function(firstCommitOnMaster) { var did = false; - walker.walk(master, function(error, commit) { + walker.walk(firstCommitOnMaster, function(error, commit) { for (var i = 0; i < 1000; i++) { if (true) { commit.author().name();