diff --git a/.npmignore b/.npmignore index db6d57ba3..b3d2f9d9d 100644 --- a/.npmignore +++ b/.npmignore @@ -1,5 +1,6 @@ /build/ /example/ +/examples/ /generate/ /test/ /vendor/libgit2/ diff --git a/TESTING.md b/TESTING.md index d7a981aad..282f61fd9 100644 --- a/TESTING.md +++ b/TESTING.md @@ -34,7 +34,7 @@ In the file each `{className}` corresponds to a file found at `test/tests/{class In the file that your test is going in you can just append it to the file inside of the `describe` function block. -It can be helpful to reference the [libgit2 API docs](https://libgit2.github.com/libgit2/#v0.21.2) to know what the field or function is doing inside of libgit2 and referencing the [NodeGit API docs](http://www.nodegit.org/) can also help. Looking at examples inside of `/example` can show you how we wrap the libgit2 library and how you can call into it from JavaScript. +It can be helpful to reference the [libgit2 API docs](https://libgit2.github.com/libgit2/#v0.21.2) to know what the field or function is doing inside of libgit2 and referencing the [NodeGit API docs](http://www.nodegit.org/) can also help. Looking at examples inside of `/examples` can show you how we wrap the libgit2 library and how you can call into it from JavaScript. The idea is to test the basic functionality of the field/function and to confirm that it's returning or setting the value(s) correctly. Bugs inside of libgit2 will have to either have a work-around or be ignored. diff --git a/example/details-for-tree-entry.js b/example/details-for-tree-entry.js deleted file mode 100644 index 2197fed6f..000000000 --- a/example/details-for-tree-entry.js +++ /dev/null @@ -1,28 +0,0 @@ -var nodegit = require('../'); -var path = require('path'); - -/** - * This shows how to get details from a tree entry or a blob -**/ - -nodegit.Repository.open(path.resolve(__dirname, '../.git')) -.then(function(repo) { - return repo.getTree("e1b0c7ea57bfc5e30ec279402a98168a27838ac9") - .then(function(tree) { - var treeEntry = tree.entryByIndex(0); - - // Tree entry doesn't have any data associated with the actual entry - // To get that we need to get the index entry that this points to - return repo.openIndex().then(function(index) { - var indexEntry = index.getByPath(treeEntry.path()); - - // With the index entry we can now view the details for the tree entry - console.log("Entry path: " + indexEntry.path()); - console.log("Entry time in seconds: " + indexEntry.mtime().seconds()); - console.log("Entry oid: " + indexEntry.id().toString()); - console.log("Entry size: " + indexEntry.fileSize()); - }); - }) -}).done(function() { - console.log("Done!"); -}); diff --git a/example/fetch.js b/example/fetch.js deleted file mode 100644 index 29bf0a454..000000000 --- a/example/fetch.js +++ /dev/null @@ -1,12 +0,0 @@ -var nodegit = require('../'); -var path = require('path'); - -nodegit.Repository.open(path.resolve(__dirname, '../.git')).then(function(repo) { - return repo.fetch("origin", { - credentials: function(url, userName) { - return nodegit.Cred.sshKeyFromAgent(userName); - } - }); -}).done(function() { - console.log("It worked!"); -}); diff --git a/example/general.js b/example/general.js deleted file mode 100644 index 94d60dd6e..000000000 --- a/example/general.js +++ /dev/null @@ -1,314 +0,0 @@ -var nodegit = require('../'); -var path = require('path'); -var Promise = require('nodegit-promise'); -var oid; -var odb; -var repo; - -// **nodegit** is a javascript library for node.js that wraps libgit2, a -// pure C implementation of the Git core. It provides an asynchronous -// interface around any functions that do I/O, and a sychronous interface -// around the rest. -// -// This file is an example of using that API in a real, JS file. -// -// **libgit2** (for the most part) only implements the core plumbing -// functions, not really the higher level porcelain stuff. For a primer on -// Git Internals that you will need to know to work with Git at this level, -// check out [Chapter 9][pg] of the Pro Git book. - -// Nearly, all git operations in the context of a repository. -// To open a repository, - -nodegit.Repository.open(path.resolve(__dirname, '../.git')) -.then(function(repoResult) { - repo = repoResult; - console.log("Opened repository."); - - // ### SHA-1 Value Conversions - - // Objects in git (commits, blobs, etc.) are referred to by their SHA value - // **nodegit** uses a simple wrapper around hash values called an `Oid`. - // The oid validates that the SHA is well-formed. - - oid = nodegit.Oid.fromString('c27d9c35e3715539d941254f2ce57042b978c49c'); - - // Most functions in in **nodegit** that take an oid will also take a - // string, so for example, you can look up a commit by a string SHA or - // an Oid, but but any functions that create new SHAs will always return - // an Oid. - - // If you have a oid, you can easily get the hex value of the SHA again. - console.log("Sha hex string:", oid.toString()); - - // ### Working with the Object Database - - // **libgit2** provides [direct access][odb] to the object database. The - // object database is where the actual objects are stored in Git. For - // working with raw objects, we'll need to get this structure from the - // repository. - return repo.odb(); -}).then(function(odbResult) { - odb = odbResult; - - // We can read raw objects directly from the object database if we have - // the oid (SHA) of the object. This allows us to access objects without - // knowing thier type and inspect the raw bytes unparsed. - - return odb.read(oid); -}).then(function(object) { - // A raw object only has three properties - the type (commit, blob, tree - // or tag), the size of the raw data and the raw, unparsed data itself. - // For a commit or tag, that raw data is human readable plain ASCII - // text. For a blob it is just file contents, so it could be text or - // binary data. For a tree it is a special binary format, so it's unlikely - // to be hugely helpful as a raw object. - var data = object.data(); - var type = object.type(); - var size = object.size(); - - console.log("Object size and type:", size, type); -}).then(function() { - // You can also write raw object data to Git. This is pretty cool because - // it gives you direct access to the key/value properties of Git. Here - // we'll write a new blob object that just contains a simple string. - // Notice that we have to specify the object type. - return odb.write("test data", "test data".length, nodegit.Object.TYPE.BLOB); -}).then(function(oid) { - // Now that we've written the object, we can check out what SHA1 was - // generated when the object was written to our database. - console.log("Written Object: ", oid.toString()); -}).then(function() { - // ### Object Parsing - - // libgit2 has methods to parse every object type in Git so you don't have - // to work directly with the raw data. This is much faster and simpler - // than trying to deal with the raw data yourself. - - // #### Commit Parsing - - // [Parsing commit objects][pco] is simple and gives you access to all the - // data in the commit - the author (name, email, datetime), committer - // (same), tree, message, encoding and parent(s). - - oid = nodegit.Oid.fromString("698c74e817243efe441a5d1f3cbaf3998282ca86"); - - // Many methods in **nodegit** are asynchronous, because they do file - // or network I/O. By convention, all asynchronous methods are named - // imperatively, like `getCommit`, `open`, `read`, `write`, etc., whereas - // synchronous methods are named nominatively, like `type`, `size`, `name`. - - return repo.getCommit(oid); -}).then(function(commit) { - // Each of the properties of the commit object are accessible via methods, - // including commonly needed variations, such as `git_commit_time` which - // returns the author time and `git_commit_message` which gives you the - // commit message. - console.log("Commit:", commit.message(), commit.author().name(), commit.date()); - - // Commits can have zero or more parents. The first (root) commit will - // have no parents, most commits will have one (i.e. the commit it was - // based on) and merge commits will have two or more. Commits can - // technically have any number, though it's rare to have more than two. - return commit.getParents(); -}).then(function(parents) { - parents.forEach(function(parent) { - console.log("Parent:", parent.toString()); - }); -}).then(function() { - // #### Writing Commits - - // nodegit provides a couple of methods to create commit objects easily as - // well. - var author = nodegit.Signature.create("Scott Chacon", "schacon@gmail.com", 123456789, 60); - var committer = nodegit.Signature.create("Scott A Chacon", "scott@github.com", 987654321, 90); - - // Commit objects need a tree to point to and optionally one or more - // parents. Here we're creating oid objects to create the commit with, - // but you can also use existing ones: - var treeId = nodegit.Oid.fromString("4170d10f19600b9cb086504e8e05fe7d863358a2"); - var parentId = nodegit.Oid.fromString("eebd0ead15d62eaf0ba276da53af43bbc3ce43ab"); - - return repo.getTree(treeId).then(function(tree) { - return repo.getCommit(parentId).then(function(parent) { - // Here we actually create the commit object with a single call with all - // the values we need to create the commit. The SHA key is written to the - // `commit_id` variable here. - return repo.createCommit( - null /* do not update the HEAD */, - author, - committer, - "example commit", - tree, - [parent]); - }).then(function(oid) { - console.log("New Commit:", oid.toString()); - }); - }); -}).then(function() { - // #### Tag Parsing - - // You can parse and create tags with the [tag management API][tm], which - // functions very similarly to the commit lookup, parsing and creation - // methods, since the objects themselves are very similar. - - oid = nodegit.Oid.fromString("dcc4aa9fcdaced037434cb149ed3b6eab4d0709d"); - return repo.getTag(oid); -}).then(function(tag) { - // Now that we have the tag object, we can extract the information it - // generally contains: the target (usually a commit object), the type of - // the target object (usually 'commit'), the name ('v1.0'), the tagger (a - // git_signature - name, email, timestamp), and the tag message. - console.log(tag.name(), tag.targetType(), tag.message()); - - return tag.target(); -}).then(function (target) { - console.log("Target is commit:", target.isCommit()); -}).then(function() { - // #### Tree Parsing - - // A Tree is how Git represents the state of the filesystem - // at a given revision. In general, a tree corresponds to a directory, - // and files in that directory are either files (blobs) or directories. - - // [Tree parsing][tp] is a bit different than the other objects, in that - // we have a subtype which is the tree entry. This is not an actual - // object type in Git, but a useful structure for parsing and traversing - // tree entries. - - oid = nodegit.Oid.fromString("e1b0c7ea57bfc5e30ec279402a98168a27838ac9"); - return repo.getTree(oid); -}).then(function(tree) { - console.log("Tree Size:", tree.entryCount()); - - function dfs(tree) { - var promises = []; - - tree.entries().forEach(function(entry) { - if (entry.isDirectory()) { - promises.push(entry.getTree().then(dfs)); - } else if (entry.isFile()) { - console.log("Tree Entry:", entry.filename()); - } - }); - - return Promise.all(promises); - } - - return dfs(tree).then(function() { - // You can also access tree entries by path if you know the path of the - // entry you're looking for. - return tree.getEntry("example/general.js").then(function(entry) { - // Entries which are files have blobs associated with them: - entry.getBlob(function(error, blob) { - console.log("Blob size:", blob.size()); - }); - }); - }); -}).then(function() { - // #### Blob Parsing - - // The last object type is the simplest and requires the least parsing - // help. Blobs are just file contents and can contain anything, there is - // no structure to it. The main advantage to using the [simple blob - // api][ba] is that when you're creating blobs you don't have to calculate - // the size of the content. There is also a helper for reading a file - // from disk and writing it to the db and getting the oid back so you - // don't have to do all those steps yourself. - - oid = nodegit.Oid.fromString("991c06b7b1ec6f939488427e4b41a4fa3e1edd5f"); - return repo.getBlob(oid); -}).then(function(blob) { - // You can access a node.js Buffer with the raw contents of the blob directly. - // Note that this buffer may not be contain ASCII data for certain blobs - // (e.g. binary files). - var buffer = blob.content(); - - // If you know that the blob is UTF-8, however, - console.log("Blob contents:", blob.toString().slice(0, 38)); -}).then(function() { - // ### Revwalking - - // The libgit2 [revision walking api][rw] provides methods to traverse the - // directed graph created by the parent pointers of the commit objects. - // Since all commits point back to the commit that came directly before - // them, you can walk this parentage as a graph and find all the commits - // that were ancestors of (reachable from) a given starting point. This - // can allow you to create `git log` type functionality. - - oid = nodegit.Oid.fromString("698c74e817243efe441a5d1f3cbaf3998282ca86"); - - // To use the revwalker, create a new walker, tell it how you want to sort - // the output and then push one or more starting points onto the walker. - // If you want to emulate the output of `git log` you would push the SHA - // of the commit that HEAD points to into the walker and then start - // traversing them. You can also 'hide' commits that you want to stop at - // or not see any of their ancestors. So if you want to emulate `git log - // branch1..branch2`, you would push the oid of `branch2` and hide the oid - // of `branch1`. - var revWalk = repo.createRevWalk(); - - revWalk.sorting(nodegit.Revwalk.SORT.TOPOLOGICAL, nodegit.Revwalk.SORT.REVERSE); - - revWalk.push(oid); - - // Now that we have the starting point pushed onto the walker, we start - // asking for ancestors. It will return them in the sorting order we asked - // for as commit oids. We can then lookup and parse the commited pointed - // at by the returned OID; note that this operation is specially fast - // since the raw contents of the commit object will be cached in memory - - function walk() { - return revWalk.next().then(function(oid) { - if (!oid) return; - - return repo.getCommit(oid).then(function(commit) { - console.log("Commit:", commit.toString()); - return walk(); - }); - }); - } - - return walk(); -}).then(function() { - // ### Index File Manipulation - - // The [index file API][gi] allows you to read, traverse, update and write - // the Git index file (sometimes thought of as the staging area). - return repo.openIndex(); -}).then(function(index) { - // For each entry in the index, you can get a bunch of information - // including the SHA (oid), path and mode which map to the tree objects - // that are written out. It also has filesystem properties to help - // determine what to inspect for changes (ctime, mtime, dev, ino, uid, - // gid, file_size and flags) All these properties are exported publicly in - // the `IndexEntry` class - - index.entries().forEach(function(entry) { - console.log("Index Entry:", entry.path(), entry.mtime().seconds()); - }); -}).then(function() { - // ### References - - // The [reference API][ref] allows you to list, resolve, create and update - // references such as branches, tags and remote references (everything in - // the .git/refs directory). - - return repo.getReferenceNames(nodegit.Reference.TYPE.ALL); -}).then(function(referenceNames) { - var promises = []; - - referenceNames.forEach(function(referenceName) { - promises.push(repo.getReference(referenceName).then(function(reference) { - if (reference.isConcrete()) { - console.log("Reference:", referenceName, reference.target()); - } else if (reference.isSymbolic()) { - console.log("Reference:", referenceName, reference.symbolicTarget()); - } - })); - }); - - return Promise.all(promises); -}).done(function() { - console.log("Done!"); -}); diff --git a/example/pull.js b/example/pull.js deleted file mode 100644 index 9999c7c55..000000000 --- a/example/pull.js +++ /dev/null @@ -1,26 +0,0 @@ -var nodegit = require('../'); -var path = require('path'); - -var repoDir = '../../test'; - -var repository; - -// Open a repository that needs to be fetched and fast-forwarded -nodegit.Repository.open(path.resolve(__dirname, repoDir)) -.then(function(repo) { - repository = repo; - - return repository.fetchAll({ - credentials: function(url, userName) { - return nodegit.Cred.sshKeyFromAgent(userName); - } - }, true); -}) -// Now that we're finished fetching, go ahead and merge our local branch -// with the new one -.then(function() { - repository.mergeBranches("master", "origin/master"); -}) -.done(function() { - console.log("Done!"); -}) diff --git a/example/push.js b/example/push.js deleted file mode 100644 index b902ffdbe..000000000 --- a/example/push.js +++ /dev/null @@ -1,77 +0,0 @@ -var nodegit = require('../'); -var path = require('path'); -var Promise = require('nodegit-promise'); -var promisify = require('promisify-node'); -var fse = promisify(require('fs-extra')); -fse.ensureDir = promisify(fse.ensureDir); - -var fileName = 'newFile.txt'; -var fileContent = 'hello world'; - -var repoDir = '../../newRepo'; - -var repository; - -var signature = nodegit.Signature.create("Foo bar", "foo@bar.com", 123456789, 60); - -// Create a new repository in a clean directory, and add our first file -fse.remove(path.resolve(__dirname, repoDir)) -.then(function() { - return fse.ensureDir(path.resolve(__dirname, repoDir)); -}) -.then(function() { - return nodegit.Repository.init(path.resolve(__dirname, repoDir), 0); -}) -.then(function(repo) { - repository = repo; - return fse.writeFile(path.join(repository.workdir(), fileName), fileContent); -}) - -// Load up the repository index and make our initial commit to HEAD -.then(function() { - return repository.openIndex(); -}) -.then(function(index) { - index.read(1); - index.addByPath(fileName); - index.write() - - return index.writeTree(); -}) -.then(function(oid) { - return repository.createCommit('HEAD', signature, signature, 'initial commit', oid, []); -}) - -// Add a new remote -.then(function() { - return nodegit.Remote.create(repository, "origin", "git@github.com:nodegit/push-example.git") - .then(function(remote) { - remote.connect(nodegit.Enums.DIRECTION.PUSH); - - var push; - - // We need to set the auth on the remote, not the push object - remote.setCallbacks({ - credentials: function(url, userName) { - return nodegit.Cred.sshKeyFromAgent(userName); - } - }); - - // Create the push object for this remote - return nodegit.Push.create(remote) - .then(function(pushResult) { - push = pushResult; - - // This just says what branch we're pushing onto what branch in the remote - return push.addRefspec("refs/heads/master:refs/heads/master"); - }).then(function() { - // This is the call that performs the actual push - return push.finish(); - }).then(function() { - // Check to see if the remote accepted our push request. - return push.unpackOk(); - }); - }); -}).done(function() { - console.log("Done!"); -}) diff --git a/example/read-file.js b/example/read-file.js deleted file mode 100644 index 9d2746670..000000000 --- a/example/read-file.js +++ /dev/null @@ -1,20 +0,0 @@ -var nodegit = require('../'), - path = require('path'); - -// This example opens a certain file, `README.md`, at a particular commit, -// and prints the first 10 lines as well as some metadata. -var _entry; -nodegit.Repository.open(path.resolve(__dirname, '../.git')).then(function(repo) { - return repo.getCommit('59b20b8d5c6ff8d09518454d4dd8b7b30f095ab5'); -}).then(function(commit) { - return commit.getEntry('README.md'); -}).then(function(entry) { - _entry = entry; - return _entry.getBlob(); -}).then(function(blob) { - console.log(_entry.filename(), _entry.sha(), blob.rawsize() + 'b'); - console.log('========================================================\n\n'); - var firstTenLines = blob.toString().split('\n').slice(0, 10).join('\n'); - console.log(firstTenLines); - console.log('...'); -}).done(); diff --git a/example/remove-and-commit.js b/example/remove-and-commit.js deleted file mode 100644 index 0bbf8273b..000000000 --- a/example/remove-and-commit.js +++ /dev/null @@ -1,42 +0,0 @@ -var nodegit = require('../'), - path = require('path'), - fileName = 'newfile.txt'; - -/** - * This example deletes a certain file `newfile.txt`, removes it from the git index and - * commits it to head. Similar to a `git rm newfile.txt` followed by a `git commit` - * Use add-and-commit.js to create the file first. -**/ - -var _repository; -var _index; -var _oid; - -//open a git repo -nodegit.Repository.open(path.resolve(__dirname, '../.git')).then(function(repo) { - _repository = repo; - return repo.openIndex(); -}).then(function(index){ - _index = index; - return _index.read(); -}).then(function() { - //remove the file from the index... - _index.removeByPath(fileName); - return _index.write(); -}).then(function() { - return _index.writeTree(); -}).then(function(oid) { - _oid = oid; - return nodegit.Reference.nameToId(_repository, "HEAD"); -}).then(function(head) { - return _repository.getCommit(head); -}).then(function(parent) { - var author = nodegit.Signature.create("Scott Chacon", "schacon@gmail.com", 123456789, 60); - var committer = nodegit.Signature.create("Scott A Chacon", "scott@github.com", 987654321, 90); - - return _repository.createCommit('HEAD', author, committer, "message", _oid, [parent]); -}).then(function(commitId) { - // the file is removed from the git repo, use fs.unlink now to remove it - // from the filesystem. - console.log("New Commit:", commitId.allocfmt()); -}).done(); diff --git a/example/walk-history.js b/example/walk-history.js deleted file mode 100644 index 42d3ccb44..000000000 --- a/example/walk-history.js +++ /dev/null @@ -1,23 +0,0 @@ -var nodegit = require('../'), - path = require('path'); - -// This code walks the history of the master branch and prints results -// that look very similar to calling `git log` from the command line - -nodegit.Repository.open(path.resolve(__dirname, '../.git')).then(function(repo) { - return repo.getMasterCommit(); -}).then(function(firstCommitOnMaster){ - // History returns an event. - var history = firstCommitOnMaster.history(nodegit.Revwalk.SORT.Time); - - // History emits 'commit' event for each commit in the branch's history - history.on('commit', function(commit) { - console.log('commit ' + commit.sha()); - console.log('Author:', commit.author().name() + ' <' + commit.author().email() + '>'); - console.log('Date:', commit.date()); - console.log('\n ' + commit.message()); - }); - - // Don't forget to call `start()`! - history.start(); -}).done(); diff --git a/example/walk-tree.js b/example/walk-tree.js deleted file mode 100644 index 9278eb345..000000000 --- a/example/walk-tree.js +++ /dev/null @@ -1,21 +0,0 @@ -var nodegit = require('../'), - path = require('path'); - -// A `tree` in git is typically a representation of the filesystem at -// a revision. A tree has a set of entries, each entry being either a -// tree (directory), or a file. - -nodegit.Repository.open(path.resolve(__dirname, '../.git')).then(function(repo) { - return repo.getMasterCommit(); -}).then(function(firstCommitOnMaster) { - return firstCommitOnMaster.getTree(); -}).then(function(tree) { - // `walk()` returns an event. - var walker = tree.walk(); - walker.on('entry', function(entry) { - console.log(entry.path()); - }); - - // Don't forget to call `start()`! - walker.start(); -}).done(); diff --git a/example/add-and-commit.js b/examples/add-and-commit.js similarity index 50% rename from example/add-and-commit.js rename to examples/add-and-commit.js index b1d4e31cd..5ead500fa 100644 --- a/example/add-and-commit.js +++ b/examples/add-and-commit.js @@ -1,27 +1,27 @@ -var nodegit = require('../'); -var path = require('path'); -var Promise = require('nodegit-promise'); -var promisify = require('promisify-node'); -var fse = promisify(require('fs-extra')); -var fileName = 'newfile.txt'; -var fileContent = 'hello world'; -var directoryName = 'salad/toast/strangerinastrangeland/theresnowaythisexists'; +var nodegit = require("../"); +var path = require("path"); +var promisify = require("promisify-node"); +var fse = promisify(require("fs-extra")); +var fileName = "newfile.txt"; +var fileContent = "hello world"; +var directoryName = "salad/toast/strangerinastrangeland/theresnowaythisexists"; // ensureDir is an alias to mkdirp, which has the callback with a weird name -// and in the 3rd position of 4 (the 4th being used for recursion). We have to force -// promisify it, because promisify-node won't detect it on its own and assumes sync +// and in the 3rd position of 4 (the 4th being used for recursion). We have to +// force promisify it, because promisify-node won't detect it on its +// own and assumes sync fse.ensureDir = promisify(fse.ensureDir); /** - * This example creates a certain file `newfile.txt`, adds it to the git index and - * commits it to head. Similar to a `git add newfile.txt` followed by a `git commit` + * This example creates a certain file `newfile.txt`, adds it to the git + * index and commits it to head. Similar to a `git add newfile.txt` + * followed by a `git commit` **/ var repo; var index; var oid; -var parent; -nodegit.Repository.open(path.resolve(__dirname, '../.git')) +nodegit.Repository.open(path.resolve(__dirname, "../.git")) .then(function(repoResult) { repo = repoResult; return fse.ensureDir(path.join(repo.workdir(), directoryName)); @@ -29,7 +29,10 @@ nodegit.Repository.open(path.resolve(__dirname, '../.git')) return fse.writeFile(path.join(repo.workdir(), fileName), fileContent); }) .then(function() { - return fse.writeFile(path.join(repo.workdir(), directoryName, fileName), fileContent); + return fse.writeFile( + path.join(repo.workdir(), directoryName, fileName), + fileContent + ); }) .then(function() { return repo.openIndex(); @@ -52,17 +55,19 @@ nodegit.Repository.open(path.resolve(__dirname, '../.git')) }) .then(function(oidResult) { oid = oidResult; - return nodegit.Reference.nameToId(repo, 'HEAD'); + return nodegit.Reference.nameToId(repo, "HEAD"); }) .then(function(head) { return repo.getCommit(head); }) .then(function(parent) { - var author = nodegit.Signature.create("Scott Chacon", "schacon@gmail.com", 123456789, 60); - var committer = nodegit.Signature.create("Scott A Chacon", "scott@github.com", 987654321, 90); + var author = nodegit.Signature.create("Scott Chacon", + "schacon@gmail.com", 123456789, 60); + var committer = nodegit.Signature.create("Scott A Chacon", + "scott@github.com", 987654321, 90); - return repo.createCommit('HEAD', author, committer, 'message', oid, [parent]); + return repo.createCommit("HEAD", author, committer, "message", oid, [parent]); }) .done(function(commitId) { - console.log('New Commit: ', commitId); + console.log("New Commit: ", commitId); }); diff --git a/example/apps/git_profanity_check.js b/examples/apps/git_profanity_check.js similarity index 67% rename from example/apps/git_profanity_check.js rename to examples/apps/git_profanity_check.js index ab38eb919..c4a839636 100644 --- a/example/apps/git_profanity_check.js +++ b/examples/apps/git_profanity_check.js @@ -10,16 +10,16 @@ // // node git_profanity_check some/repo/.git // -var git = require('../../'); +var git = require("../../"); -var curses = ['put', 'curse', 'words', 'here']; -var path = './.git'; -var branch = 'master'; -var reCurse = new RegExp('\\b(?:' + curses.join('|') + ')\\b', 'gi'); +var curses = ["put", "curse", "words", "here"]; +var path = "./.git"; +var branch = "master"; +var reCurse = new RegExp("\\b(?:" + curses.join("|") + ")\\b", "gi"); // Default path is `.git`. if (process.argv.length < 3) { - console.log('No path passed as argument, defaulting to .git.'); + console.log("No path passed as argument, defaulting to .git."); } // Otherwise defaults. else { @@ -27,7 +27,7 @@ else { // Set repo branch if (process.argv.length < 4) { - console.log('No branch passed as argument, defaulting to master.'); + console.log("No branch passed as argument, defaulting to master."); } else { branch = process.argv[3]; @@ -44,12 +44,12 @@ git.Repo.open(path) var history = firstCommit.history(); // Iterate over every commit message and test for words. - history.on('commit', function(commit) { + history.on("commit", function(commit) { var message = commit.message(); if (reCurse.test(message)) { - console.log('Curse detected in commit', commit.sha()); - console.log('=> ', message); + console.log("Curse detected in commit", commit.sha()); + console.log("=> ", message); return; } }); diff --git a/example/clone.js b/examples/clone.js similarity index 63% rename from example/clone.js rename to examples/clone.js index 479136c20..19ccea0b2 100644 --- a/example/clone.js +++ b/examples/clone.js @@ -1,4 +1,4 @@ -var nodegit = require('../'); +var nodegit = require("../"); var promisify = require("promisify-node"); var fse = promisify(require("fs-extra")); var path = "/tmp/nodegit-clone-demo"; @@ -11,20 +11,20 @@ fse.remove(path).then(function() { path, { ignoreCertErrors: 1}) .then(function(repo) { - return repo.getCommit('59b20b8d5c6ff8d09518454d4dd8b7b30f095ab5'); + return repo.getCommit("59b20b8d5c6ff8d09518454d4dd8b7b30f095ab5"); }) .then(function(commit) { - return commit.getEntry('README.md') + return commit.getEntry("README.md"); }) .then(function(entryResult) { entry = entryResult; return entry.getBlob(); }) .done(function(blob) { - console.log(entry.filename(), entry.sha(), blob.rawsize() + 'b'); - console.log('========================================================\n\n'); - var firstTenLines = blob.toString().split('\n').slice(0, 10).join('\n'); + console.log(entry.filename(), entry.sha(), blob.rawsize() + "b"); + console.log("========================================================\n\n"); + var firstTenLines = blob.toString().split("\n").slice(0, 10).join("\n"); console.log(firstTenLines); - console.log('...'); + console.log("..."); }); }); diff --git a/example/create-new-repo.js b/examples/create-new-repo.js similarity index 58% rename from example/create-new-repo.js rename to examples/create-new-repo.js index 91be1ea54..640bdc33a 100644 --- a/example/create-new-repo.js +++ b/examples/create-new-repo.js @@ -1,11 +1,10 @@ -var nodegit = require('../'); -var path = require('path'); -var Promise = require('nodegit-promise'); -var promisify = require('promisify-node'); -var fse = promisify(require('fs-extra')); -var fileName = 'newfile.txt'; -var fileContent = 'hello world'; -var repoDir = '../../newRepo'; +var nodegit = require("../"); +var path = require("path"); +var promisify = require("promisify-node"); +var fse = promisify(require("fs-extra")); +var fileName = "newfile.txt"; +var fileContent = "hello world"; +var repoDir = "../../newRepo"; fse.ensureDir = promisify(fse.ensureDir); @@ -37,13 +36,15 @@ fse.ensureDir(path.resolve(__dirname, repoDir)) return index.writeTree(); }) .then(function(oid) { - var author = nodegit.Signature.create("Scott Chacon", "schacon@gmail.com", 123456789, 60); - var committer = nodegit.Signature.create("Scott A Chacon", "scott@github.com", 987654321, 90); + var author = nodegit.Signature.create("Scott Chacon", + "schacon@gmail.com", 123456789, 60); + var committer = nodegit.Signature.create("Scott A Chacon", + "scott@github.com", 987654321, 90); // Since we're creating an inital commit, it has no parents. Note that unlike // normal we don't get the head either, because there isn't one yet. - return repository.createCommit('HEAD', author, committer, 'message', oid, []); + return repository.createCommit("HEAD", author, committer, "message", oid, []); }) .done(function(commitId) { - console.log('New Commit: ', commitId); + console.log("New Commit: ", commitId); }); diff --git a/examples/details-for-tree-entry.js b/examples/details-for-tree-entry.js new file mode 100644 index 000000000..405538389 --- /dev/null +++ b/examples/details-for-tree-entry.js @@ -0,0 +1,29 @@ +var nodegit = require("../"); +var path = require("path"); + +/** + * This shows how to get details from a tree entry or a blob +**/ + +nodegit.Repository.open(path.resolve(__dirname, "../.git")) + .then(function(repo) { + return repo.getTree("e1b0c7ea57bfc5e30ec279402a98168a27838ac9") + .then(function(tree) { + var treeEntry = tree.entryByIndex(0); + + // Tree entry doesn't have any data associated with the actual entry + // To get that we need to get the index entry that this points to + return repo.openIndex().then(function(index) { + var indexEntry = index.getByPath(treeEntry.path()); + + // With the index entry we can now view the details for the tree entry + console.log("Entry path: " + indexEntry.path()); + console.log("Entry time in seconds: " + indexEntry.mtime().seconds()); + console.log("Entry oid: " + indexEntry.id().toString()); + console.log("Entry size: " + indexEntry.fileSize()); + }); + }); + }) + .done(function() { + console.log("Done!"); + }); diff --git a/example/diff-commits.js b/examples/diff-commits.js similarity index 55% rename from example/diff-commits.js rename to examples/diff-commits.js index d6b2bd4c4..7d3153c1a 100644 --- a/example/diff-commits.js +++ b/examples/diff-commits.js @@ -1,19 +1,20 @@ -var nodegit = require('../'); -var path = require('path'); +var nodegit = require("../"); +var path = require("path"); // This code examines the diffs between a particular commit and all of its // parents. Since this commit is not a merge, it only has one parent. This is // similar to doing `git show`. -nodegit.Repository.open(path.resolve(__dirname, '../.git')) +nodegit.Repository.open(path.resolve(__dirname, "../.git")) .then(function(repo) { - return repo.getCommit('59b20b8d5c6ff8d09518454d4dd8b7b30f095ab5'); + return repo.getCommit("59b20b8d5c6ff8d09518454d4dd8b7b30f095ab5"); }) .then(function(commit) { - console.log('commit ' + commit.sha()); - console.log('Author:', commit.author().name() + ' <' + commit.author().email() + '>'); - console.log('Date:', commit.date()); - console.log('\n ' + commit.message()); + console.log("commit " + commit.sha()); + console.log("Author:", commit.author().name() + + " <" + commit.author().email() + ">"); + console.log("Date:", commit.date()); + console.log("\n " + commit.message()); return commit.getDiff(); }) @@ -24,7 +25,8 @@ nodegit.Repository.open(path.resolve(__dirname, '../.git')) patch.hunks().forEach(function(hunk) { console.log(hunk.header().trim()); hunk.lines().forEach(function(line) { - console.log(String.fromCharCode(line.origin()) + line.content().trim()); + console.log(String.fromCharCode(line.origin()) + + line.content().trim()); }); }); }); diff --git a/examples/fetch.js b/examples/fetch.js new file mode 100644 index 000000000..fce801ee0 --- /dev/null +++ b/examples/fetch.js @@ -0,0 +1,13 @@ +var nodegit = require("../"); +var path = require("path"); + +nodegit.Repository.open(path.resolve(__dirname, "../.git")) + .then(function(repo) { + return repo.fetch("origin", { + credentials: function(url, userName) { + return nodegit.Cred.sshKeyFromAgent(userName); + } + }); + }).done(function() { + console.log("It worked!"); + }); diff --git a/examples/general.js b/examples/general.js new file mode 100644 index 000000000..84c309c5a --- /dev/null +++ b/examples/general.js @@ -0,0 +1,367 @@ +var nodegit = require("../"); +var path = require("path"); +var Promise = require("nodegit-promise"); +var oid; +var odb; +var repo; + +// **nodegit** is a javascript library for node.js that wraps libgit2, a +// pure C implementation of the Git core. It provides an asynchronous +// interface around any functions that do I/O, and a sychronous interface +// around the rest. +// +// This file is an example of using that API in a real, JS file. +// +// **libgit2** (for the most part) only implements the core plumbing +// functions, not really the higher level porcelain stuff. For a primer on +// Git Internals that you will need to know to work with Git at this level, +// check out [Chapter 9][pg] of the Pro Git book. + +// Nearly, all git operations in the context of a repository. +// To open a repository, + +nodegit.Repository.open(path.resolve(__dirname, "../.git")) + .then(function(repoResult) { + repo = repoResult; + console.log("Opened repository."); + + // ### SHA-1 Value Conversions + + // Objects in git (commits, blobs, etc.) are referred to by their SHA value + // **nodegit** uses a simple wrapper around hash values called an `Oid`. + // The oid validates that the SHA is well-formed. + + oid = nodegit.Oid.fromString("c27d9c35e3715539d941254f2ce57042b978c49c"); + + // Most functions in in **nodegit** that take an oid will also take a + // string, so for example, you can look up a commit by a string SHA or + // an Oid, but but any functions that create new SHAs will always return + // an Oid. + + // If you have a oid, you can easily get the hex value of the SHA again. + console.log("Sha hex string:", oid.toString()); + + // ### Working with the Object Database + + // **libgit2** provides [direct access][odb] to the object database. The + // object database is where the actual objects are stored in Git. For + // working with raw objects, we'll need to get this structure from the + // repository. + return repo.odb(); + }) + + .then(function(odbResult) { + odb = odbResult; + + // We can read raw objects directly from the object database if we have + // the oid (SHA) of the object. This allows us to access objects without + // knowing thier type and inspect the raw bytes unparsed. + + return odb.read(oid); + }) + + .then(function(object) { + // A raw object only has three properties - the type (commit, blob, tree + // or tag), the size of the raw data and the raw, unparsed data itself. + // For a commit or tag, that raw data is human readable plain ASCII + // text. For a blob it is just file contents, so it could be text or + // binary data. For a tree it is a special binary format, so it's unlikely + // to be hugely helpful as a raw object. + var data = object.data(); + var type = object.type(); + var size = object.size(); + + console.log("Object size and type:", size, type); + console.log("Raw data: ", data.toString().substring(100), "..."); + + }) + + .then(function() { + // You can also write raw object data to Git. This is pretty cool because + // it gives you direct access to the key/value properties of Git. Here + // we'll write a new blob object that just contains a simple string. + // Notice that we have to specify the object type. + return odb.write("test data", "test data".length, nodegit.Object.TYPE.BLOB); + }) + + .then(function(oid) { + // Now that we've written the object, we can check out what SHA1 was + // generated when the object was written to our database. + console.log("Written Object: ", oid.toString()); + }) + + .then(function() { + // ### Object Parsing + + // libgit2 has methods to parse every object type in Git so you don't have + // to work directly with the raw data. This is much faster and simpler + // than trying to deal with the raw data yourself. + + // #### Commit Parsing + + // [Parsing commit objects][pco] is simple and gives you access to all the + // data in the commit - the author (name, email, datetime), committer + // (same), tree, message, encoding and parent(s). + + oid = nodegit.Oid.fromString("698c74e817243efe441a5d1f3cbaf3998282ca86"); + + // Many methods in **nodegit** are asynchronous, because they do file + // or network I/O. By convention, all asynchronous methods are named + // imperatively, like `getCommit`, `open`, `read`, `write`, etc., whereas + // synchronous methods are named nominatively, like `type`, `size`, `name`. + + return repo.getCommit(oid); + }) + + .then(function(commit) { + // Each of the properties of the commit object are accessible via methods, + // including commonly needed variations, such as `git_commit_time` which + // returns the author time and `git_commit_message` which gives you the + // commit message. + console.log("Commit:", commit.message(), + commit.author().name(), commit.date()); + + // Commits can have zero or more parents. The first (root) commit will + // have no parents, most commits will have one (i.e. the commit it was + // based on) and merge commits will have two or more. Commits can + // technically have any number, though it's rare to have more than two. + return commit.getParents(); + }) + + .then(function(parents) { + parents.forEach(function(parent) { + console.log("Parent:", parent.toString()); + }); + }) + + .then(function() { + // #### Writing Commits + + // nodegit provides a couple of methods to create commit objects easily as + // well. + var author = nodegit.Signature.create("Scott Chacon", + "schacon@gmail.com", 123456789, 60); + var committer = nodegit.Signature.create("Scott A Chacon", + "scott@github.com", 987654321, 90); + + // Commit objects need a tree to point to and optionally one or more + // parents. Here we're creating oid objects to create the commit with, + // but you can also use existing ones: + var treeId = nodegit.Oid.fromString( + "4170d10f19600b9cb086504e8e05fe7d863358a2"); + var parentId = nodegit.Oid.fromString( + "eebd0ead15d62eaf0ba276da53af43bbc3ce43ab"); + + return repo.getTree(treeId).then(function(tree) { + return repo.getCommit(parentId).then(function(parent) { + // Here we actually create the commit object with a single call with all + // the values we need to create the commit. The SHA key is written to + // the `commit_id` variable here. + return repo.createCommit( + null /* do not update the HEAD */, + author, + committer, + "example commit", + tree, + [parent]); + }).then(function(oid) { + console.log("New Commit:", oid.toString()); + }); + }); + }) + + .then(function() { + // #### Tag Parsing + + // You can parse and create tags with the [tag management API][tm], which + // functions very similarly to the commit lookup, parsing and creation + // methods, since the objects themselves are very similar. + + oid = nodegit.Oid.fromString("dcc4aa9fcdaced037434cb149ed3b6eab4d0709d"); + return repo.getTag(oid); + }) + + .then(function(tag) { + // Now that we have the tag object, we can extract the information it + // generally contains: the target (usually a commit object), the type of + // the target object (usually "commit"), the name ("v1.0"), the tagger (a + // git_signature - name, email, timestamp), and the tag message. + console.log(tag.name(), tag.targetType(), tag.message()); + + return tag.target(); + }) + + .then(function (target) { + console.log("Target is commit:", target.isCommit()); + }) + + .then(function() { + // #### Tree Parsing + + // A Tree is how Git represents the state of the filesystem + // at a given revision. In general, a tree corresponds to a directory, + // and files in that directory are either files (blobs) or directories. + + // [Tree parsing][tp] is a bit different than the other objects, in that + // we have a subtype which is the tree entry. This is not an actual + // object type in Git, but a useful structure for parsing and traversing + // tree entries. + + oid = nodegit.Oid.fromString("e1b0c7ea57bfc5e30ec279402a98168a27838ac9"); + return repo.getTree(oid); + }) + + .then(function(tree) { + console.log("Tree Size:", tree.entryCount()); + + function dfs(tree) { + var promises = []; + + tree.entries().forEach(function(entry) { + if (entry.isDirectory()) { + promises.push(entry.getTree().then(dfs)); + } else if (entry.isFile()) { + console.log("Tree Entry:", entry.filename()); + } + }); + + return Promise.all(promises); + } + + return dfs(tree).then(function() { + // You can also access tree entries by path if you know the path of the + // entry you're looking for. + return tree.getEntry("example/general.js").then(function(entry) { + // Entries which are files have blobs associated with them: + entry.getBlob(function(error, blob) { + console.log("Blob size:", blob.size()); + }); + }); + }); + }) + + .then(function() { + // #### Blob Parsing + + // The last object type is the simplest and requires the least parsing + // help. Blobs are just file contents and can contain anything, there is + // no structure to it. The main advantage to using the [simple blob + // api][ba] is that when you're creating blobs you don't have to calculate + // the size of the content. There is also a helper for reading a file + // from disk and writing it to the db and getting the oid back so you + // don't have to do all those steps yourself. + + oid = nodegit.Oid.fromString("991c06b7b1ec6f939488427e4b41a4fa3e1edd5f"); + return repo.getBlob(oid); + }) + + .then(function(blob) { + // You can access a node.js Buffer with the raw contents + // of the blob directly. Note that this buffer may not + // contain ASCII data for certain blobs (e.g. binary files). + var buffer = blob.content(); + + // If you know that the blob is UTF-8, however, + console.log("Blob contents:", blob.toString().slice(0, 38)); + console.log("Buffer:", buffer.toString().substring(100), "..."); + }) + + .then(function() { + // ### Revwalking + + // The libgit2 [revision walking api][rw] provides methods to traverse the + // directed graph created by the parent pointers of the commit objects. + // Since all commits point back to the commit that came directly before + // them, you can walk this parentage as a graph and find all the commits + // that were ancestors of (reachable from) a given starting point. This + // can allow you to create `git log` type functionality. + + oid = nodegit.Oid.fromString("698c74e817243efe441a5d1f3cbaf3998282ca86"); + + // To use the revwalker, create a new walker, tell it how you want to sort + // the output and then push one or more starting points onto the walker. + // If you want to emulate the output of `git log` you would push the SHA + // of the commit that HEAD points to into the walker and then start + // traversing them. You can also "hide" commits that you want to stop at + // or not see any of their ancestors. So if you want to emulate `git log + // branch1..branch2`, you would push the oid of `branch2` and hide the oid + // of `branch1`. + var revWalk = repo.createRevWalk(); + + revWalk.sorting(nodegit.Revwalk.SORT.TOPOLOGICAL, + nodegit.Revwalk.SORT.REVERSE); + + revWalk.push(oid); + + // Now that we have the starting point pushed onto the walker, we start + // asking for ancestors. It will return them in the sorting order we asked + // for as commit oids. We can then lookup and parse the commited pointed + // at by the returned OID; note that this operation is specially fast + // since the raw contents of the commit object will be cached in memory + + function walk() { + return revWalk.next().then(function(oid) { + if (!oid) { + return; + } + + return repo.getCommit(oid).then(function(commit) { + console.log("Commit:", commit.toString()); + return walk(); + }); + }); + } + + return walk(); + }) + + .then(function() { + // ### Index File Manipulation + + // The [index file API][gi] allows you to read, traverse, update and write + // the Git index file (sometimes thought of as the staging area). + return repo.openIndex(); + }) + + .then(function(index) { + // For each entry in the index, you can get a bunch of information + // including the SHA (oid), path and mode which map to the tree objects + // that are written out. It also has filesystem properties to help + // determine what to inspect for changes (ctime, mtime, dev, ino, uid, + // gid, file_size and flags) All these properties are exported publicly in + // the `IndexEntry` class + + index.entries().forEach(function(entry) { + console.log("Index Entry:", entry.path(), entry.mtime().seconds()); + }); + }) + + .then(function() { + // ### References + + // The [reference API][ref] allows you to list, resolve, create and update + // references such as branches, tags and remote references (everything in + // the .git/refs directory). + + return repo.getReferenceNames(nodegit.Reference.TYPE.ALL); + }) + + .then(function(referenceNames) { + var promises = []; + + referenceNames.forEach(function(referenceName) { + promises.push(repo.getReference(referenceName).then(function(reference) { + if (reference.isConcrete()) { + console.log("Reference:", referenceName, reference.target()); + } else if (reference.isSymbolic()) { + console.log("Reference:", referenceName, reference.symbolicTarget()); + } + })); + }); + + return Promise.all(promises); + }) + + .done(function() { + console.log("Done!"); + }); diff --git a/example/merge-cleanly.js b/examples/merge-cleanly.js similarity index 60% rename from example/merge-cleanly.js rename to examples/merge-cleanly.js index 6fabc672d..096714e8e 100644 --- a/example/merge-cleanly.js +++ b/examples/merge-cleanly.js @@ -1,19 +1,18 @@ -var nodegit = require('../'); -var path = require('path'); -var Promise = require('nodegit-promise'); -var promisify = require('promisify-node'); -var fse = promisify(require('fs-extra')); +var nodegit = require("../"); +var path = require("path"); +var promisify = require("promisify-node"); +var fse = promisify(require("fs-extra")); fse.ensureDir = promisify(fse.ensureDir); -var ourFileName = 'ourNewFile.txt'; -var ourFileContent = 'I like Toll Roads. I have an EZ-Pass!'; +var ourFileName = "ourNewFile.txt"; +var ourFileContent = "I like Toll Roads. I have an EZ-Pass!"; var ourBranchName = "ours"; -var theirFileName = 'theirNewFile.txt'; +var theirFileName = "theirNewFile.txt"; var theirFileContent = "I'm skeptical about Toll Roads"; var theirBranchName = "theirs"; -var repoDir = '../../newRepo'; +var repoDir = "../../newRepo"; var repository; var ourCommit; @@ -21,8 +20,10 @@ var theirCommit; var ourBranch; var theirBranch; -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 ourSignature = nodegit.Signature.create("Ron Paul", + "RonPaul@TollRoadsRBest.info", 123456789, 60); +var theirSignature = nodegit.Signature.create("Greg Abbott", + "Gregggg@IllTollYourFace.us", 123456789, 60); // Create a new repository in a clean directory, and add our first file fse.remove(path.resolve(__dirname, repoDir)) @@ -34,7 +35,10 @@ fse.remove(path.resolve(__dirname, repoDir)) }) .then(function(repo) { repository = repo; - return fse.writeFile(path.join(repository.workdir(), ourFileName), ourFileContent); + return fse.writeFile( + path.join(repository.workdir(), ourFileName), + ourFileContent + ); }) // Load up the repository index and make our initial commit to HEAD @@ -44,12 +48,13 @@ fse.remove(path.resolve(__dirname, repoDir)) .then(function(index) { index.read(1); index.addByPath(ourFileName); - index.write() + index.write(); return index.writeTree(); }) .then(function(oid) { - return repository.createCommit('HEAD', ourSignature, ourSignature, 'we made a commit', oid, []); + return repository.createCommit("HEAD", ourSignature, + ourSignature, "we made a commit", oid, []); }) // Get commit object from the oid, and create our new branches at that position @@ -57,17 +62,21 @@ fse.remove(path.resolve(__dirname, repoDir)) 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); - }); + return repository.createBranch(ourBranchName, commitOid) + .then(function(branch) { + ourBranch = branch; + return repository.createBranch(theirBranchName, commitOid); + }); }); }) // Create a new file, stage it and commit it to our second branch .then(function(branch) { theirBranch = branch; - return fse.writeFile(path.join(repository.workdir(), theirFileName), theirFileContent); + return fse.writeFile( + path.join(repository.workdir(), theirFileName), + theirFileContent + ); }) .then(function() { return repository.openIndex(); @@ -75,13 +84,14 @@ fse.remove(path.resolve(__dirname, repoDir)) .then(function(index) { index.read(1); index.addByPath(theirFileName); - index.write() + index.write(); return index.writeTree(); }) .then(function(oid) { - // You don't have to change head to make a commit to a different branch. - return repository.createCommit(theirBranch.name(), theirSignature, theirSignature, 'they made a commit', oid, [ourCommit]); + // You don"t have to change head to make a commit to a different branch. + return repository.createCommit(theirBranch.name(), theirSignature, + theirSignature, "they made a commit", oid, [ourCommit]); }) .then(function(commitOid) { return repository.getCommit(commitOid).then(function(commit) { @@ -102,7 +112,7 @@ fse.remove(path.resolve(__dirname, repoDir)) // the repository instead of just writing it. .then(function(index) { if (!index.hasConflicts()) { - index.write() + index.write(); return index.writeTreeTo(repository); } }) @@ -110,9 +120,11 @@ fse.remove(path.resolve(__dirname, repoDir)) // Create our merge commit back on our branch .then(function(oid) { - return repository.createCommit(ourBranch.name(), ourSignature, ourSignature, 'we merged their commit', oid, [ourCommit, theirCommit]); + return repository.createCommit(ourBranch.name(), ourSignature, + ourSignature, "we merged their commit", oid, [ourCommit, theirCommit]); }) .done(function(commitId) { - // We never changed the HEAD after the initial commit; it should still be the same as master. - console.log('New Commit: ', commitId); + // We never changed the HEAD after the initial commit; + // it should still be the same as master. + console.log("New Commit: ", commitId); }); diff --git a/example/merge-with-conflicts.js b/examples/merge-with-conflicts.js similarity index 57% rename from example/merge-with-conflicts.js rename to examples/merge-with-conflicts.js index 652198b77..b1f8e95ba 100644 --- a/example/merge-with-conflicts.js +++ b/examples/merge-with-conflicts.js @@ -1,21 +1,23 @@ -var nodegit = require('../'); -var path = require('path'); -var Promise = require('nodegit-promise'); -var promisify = require('promisify-node'); -var fse = promisify(require('fs-extra')); +var nodegit = require("../"); +var path = require("path"); +var promisify = require("promisify-node"); +var fse = promisify(require("fs-extra")); fse.ensureDir = promisify(fse.ensureDir); -var repoDir = '../../newRepo'; -var fileName = 'newFile.txt'; +var repoDir = "../../newRepo"; +var fileName = "newFile.txt"; -var baseFileContent = 'All Bobs are created equal. ish.\n'; +var baseFileContent = "All Bobs are created equal. ish.\n"; var ourFileContent = "Big Bobs are best, IMHO.\n"; var theirFileContent = "Nobody expects the small Bobquisition!\n"; -var finalFileContent = "Big Bobs are beautiful, and the small are unexpected!\n"; +var finalFileContent = "Big Bobs are beautiful and the small are unexpected!\n"; -var baseSignature = nodegit.Signature.create("Peaceful Bob", "justchill@bob.net", 123456789, 60); -var ourSignature = nodegit.Signature.create("Big Bob", "impressive@bob.net", 123456789, 60); -var theirSignature = nodegit.Signature.create("Small Bob", "underestimated@bob.net", 123456789, 60); +var baseSignature = nodegit.Signature.create("Peaceful Bob", + "justchill@bob.net", 123456789, 60); +var ourSignature = nodegit.Signature.create("Big Bob", + "impressive@bob.net", 123456789, 60); +var theirSignature = nodegit.Signature.create("Small Bob", + "underestimated@bob.net", 123456789, 60); var ourBranchName = "ours"; var theirBranchName = "theirs"; @@ -38,7 +40,10 @@ fse.remove(path.resolve(__dirname, repoDir)) }) .then(function(repo) { repository = repo; - return fse.writeFile(path.join(repository.workdir(), fileName), baseFileContent); + return fse.writeFile( + path.join(repository.workdir(), fileName), + baseFileContent + ); }) @@ -49,49 +54,58 @@ fse.remove(path.resolve(__dirname, repoDir)) .then(function(index) { index.read(1); index.addByPath(fileName); - index.write() + index.write(); return index.writeTree(); }) .then(function(oid) { - return repository.createCommit('HEAD', baseSignature, baseSignature, 'bobs are all ok', oid, []); + return repository.createCommit("HEAD", baseSignature, + baseSignature, "bobs are all ok", oid, []); }) .then(function(commitOid) { baseCommitOid = commitOid; - return repository.getCommit(commitOid).then(function(commit) { - baseCommit = commit; - }); + return repository.getCommit(commitOid) + .then(function(commit) { + baseCommit = commit; + }); }) // create our branches .then(function() { - return repository.createBranch(ourBranchName, baseCommitOid).then(function(branch) { - ourBranch = branch; - }); + return repository.createBranch(ourBranchName, baseCommitOid) + .then(function(branch) { + ourBranch = branch; + }); }) .then(function() { - return repository.createBranch(theirBranchName, baseCommitOid).then(function(branch) { - theirBranch = branch; - }); + return repository.createBranch(theirBranchName, baseCommitOid) + .then(function(branch) { + theirBranch = branch; + }); }) // Write and commit our version of the file .then(function() { - return fse.writeFile(path.join(repository.workdir(), fileName), ourFileContent); + return fse.writeFile( + path.join(repository.workdir(), fileName), + ourFileContent + ); }) .then(function() { - return repository.openIndex().then(function(index) { - index.read(1); - index.addByPath(fileName); - index.write() + return repository.openIndex() + .then(function(index) { + index.read(1); + index.addByPath(fileName); + index.write(); - return index.writeTree(); - }); + return index.writeTree(); + }); }) .then(function(oid) { - return repository.createCommit(ourBranch.name(), ourSignature, ourSignature, 'lol big bobs :yesway:', oid, [baseCommit]); + return repository.createCommit(ourBranch.name(), ourSignature, + ourSignature, "lol big bobs :yesway:", oid, [baseCommit]); }) .then(function(commitOid) { return repository.getCommit(commitOid).then(function(commit) { @@ -102,19 +116,23 @@ fse.remove(path.resolve(__dirname, repoDir)) // Write and commit their version of the file .then(function() { - return fse.writeFile(path.join(repository.workdir(), fileName), theirFileContent); + return fse.writeFile( + path.join(repository.workdir(), fileName), + theirFileContent + ); }) .then(function() { return repository.openIndex().then(function(index) { index.read(1); index.addByPath(fileName); - index.write() + index.write(); return index.writeTree(); }); }) .then(function(oid) { - return repository.createCommit(theirBranch.name(), theirSignature, theirSignature, 'lol big bobs :poop:', oid, [baseCommit]); + return repository.createCommit(theirBranch.name(), theirSignature, + theirSignature, "lol big bobs :poop:", oid, [baseCommit]); }) .then(function(commitOid) { return repository.getCommit(commitOid).then(function(commit) { @@ -125,9 +143,10 @@ fse.remove(path.resolve(__dirname, repoDir)) // move the head to our branch, just to keep things tidy .then(function() { - return nodegit.Reference.lookup(repository, 'HEAD').then(function(head) { - return head.symbolicSetTarget(ourBranch.name(), ourSignature, ""); - }) + return nodegit.Reference.lookup(repository, "HEAD"); +}) +.then(function(head) { + return head.symbolicSetTarget(ourBranch.name(), ourSignature, ""); }) @@ -140,11 +159,14 @@ fse.remove(path.resolve(__dirname, repoDir)) // You have to write it to the repository instead of just writing it. .then(function(index) { if (index.hasConflicts()) { - console.log('Conflict time!'); + console.log("Conflict time!"); // if the merge had comflicts, solve them // (in this case, we simply overwrite the file) - fse.writeFileSync(path.join(repository.workdir(), fileName), finalFileContent); + fse.writeFileSync( + path.join(repository.workdir(), fileName), + finalFileContent + ); } }) @@ -162,8 +184,9 @@ fse.remove(path.resolve(__dirname, repoDir)) }) .then(function(oid) { // create the new merge commit on our branch - return repository.createCommit(ourBranch.name(), baseSignature, baseSignature, 'Stop this bob sized fued', oid, [ourCommit, theirCommit]); + return repository.createCommit(ourBranch.name(), baseSignature, + baseSignature, "Stop this bob sized fued", oid, [ourCommit, theirCommit]); }) .done(function(commitId) { - console.log('New Commit: ', commitId); + console.log("New Commit: ", commitId); }); diff --git a/examples/pull.js b/examples/pull.js new file mode 100644 index 000000000..5501535d2 --- /dev/null +++ b/examples/pull.js @@ -0,0 +1,26 @@ +var nodegit = require("../"); +var path = require("path"); + +var repoDir = "../../test"; + +var repository; + +// Open a repository that needs to be fetched and fast-forwarded +nodegit.Repository.open(path.resolve(__dirname, repoDir)) + .then(function(repo) { + repository = repo; + + return repository.fetchAll({ + credentials: function(url, userName) { + return nodegit.Cred.sshKeyFromAgent(userName); + } + }, true); + }) + // Now that we're finished fetching, go ahead and merge our local branch + // with the new one + .then(function() { + repository.mergeBranches("master", "origin/master"); + }) + .done(function() { + console.log("Done!"); + }); diff --git a/examples/push.js b/examples/push.js new file mode 100644 index 000000000..fbc43985c --- /dev/null +++ b/examples/push.js @@ -0,0 +1,79 @@ +var nodegit = require("../"); +var path = require("path"); +var promisify = require("promisify-node"); +var fse = promisify(require("fs-extra")); +fse.ensureDir = promisify(fse.ensureDir); + +var fileName = "newFile.txt"; +var fileContent = "hello world"; + +var repoDir = "../../newRepo"; + +var repository; + +var signature = nodegit.Signature.create("Foo bar", + "foo@bar.com", 123456789, 60); + +// Create a new repository in a clean directory, and add our first file +fse.remove(path.resolve(__dirname, repoDir)) +.then(function() { + return fse.ensureDir(path.resolve(__dirname, repoDir)); +}) +.then(function() { + return nodegit.Repository.init(path.resolve(__dirname, repoDir), 0); +}) +.then(function(repo) { + repository = repo; + return fse.writeFile(path.join(repository.workdir(), fileName), fileContent); +}) + +// Load up the repository index and make our initial commit to HEAD +.then(function() { + return repository.openIndex(); +}) +.then(function(index) { + index.read(1); + index.addByPath(fileName); + index.write(); + + return index.writeTree(); +}) +.then(function(oid) { + return repository.createCommit("HEAD", signature, signature, + "initial commit", oid, []); +}) + +// Add a new remote +.then(function() { + return nodegit.Remote.create(repository, "origin", + "git@github.com:nodegit/push-example.git") + .then(function(remote) { + remote.connect(nodegit.Enums.DIRECTION.PUSH); + + var push; + + // We need to set the auth on the remote, not the push object + remote.setCallbacks({ + credentials: function(url, userName) { + return nodegit.Cred.sshKeyFromAgent(userName); + } + }); + + // Create the push object for this remote + return nodegit.Push.create(remote) + .then(function(pushResult) { + push = pushResult; + + // This just says what branch we're pushing onto what remote branch + return push.addRefspec("refs/heads/master:refs/heads/master"); + }).then(function() { + // This is the call that performs the actual push + return push.finish(); + }).then(function() { + // Check to see if the remote accepted our push request. + return push.unpackOk(); + }); + }); +}).done(function() { + console.log("Done!"); +}); diff --git a/examples/read-file.js b/examples/read-file.js new file mode 100644 index 000000000..4203a5cf4 --- /dev/null +++ b/examples/read-file.js @@ -0,0 +1,25 @@ +var nodegit = require("../"), + path = require("path"); + +// This example opens a certain file, `README.md`, at a particular commit, +// and prints the first 10 lines as well as some metadata. +var _entry; +nodegit.Repository.open(path.resolve(__dirname, "../.git")) + .then(function(repo) { + return repo.getCommit("59b20b8d5c6ff8d09518454d4dd8b7b30f095ab5"); + }) + .then(function(commit) { + return commit.getEntry("README.md"); + }) + .then(function(entry) { + _entry = entry; + return _entry.getBlob(); + }) + .then(function(blob) { + console.log(_entry.filename(), _entry.sha(), blob.rawsize() + "b"); + console.log("========================================================\n\n"); + var firstTenLines = blob.toString().split("\n").slice(0, 10).join("\n"); + console.log(firstTenLines); + console.log("..."); + }) + .done(); diff --git a/examples/remove-and-commit.js b/examples/remove-and-commit.js new file mode 100644 index 000000000..fd6ddc6b8 --- /dev/null +++ b/examples/remove-and-commit.js @@ -0,0 +1,55 @@ +var nodegit = require("../"), + path = require("path"), + fileName = "newfile.txt"; + +/** + * This example deletes a certain file `newfile.txt`, + * removes it from the git index and commits it to head. Similar to a + * `git rm newfile.txt` followed by a `git commit`. Use add-and-commit.js + * to create the file first. +**/ + +var _repository; +var _index; +var _oid; + +//open a git repo +nodegit.Repository.open(path.resolve(__dirname, "../.git")) + .then(function(repo) { + _repository = repo; + return repo.openIndex(); + }) + .then(function(index){ + _index = index; + return _index.read(); + }) + .then(function() { + //remove the file from the index... + _index.removeByPath(fileName); + return _index.write(); + }) + .then(function() { + return _index.writeTree(); + }) + .then(function(oid) { + _oid = oid; + return nodegit.Reference.nameToId(_repository, "HEAD"); + }) + .then(function(head) { + return _repository.getCommit(head); + }) + .then(function(parent) { + var author = nodegit.Signature.create("Scott Chacon", + "schacon@gmail.com", 123456789, 60); + var committer = nodegit.Signature.create("Scott A Chacon", + "scott@github.com", 987654321, 90); + + return _repository.createCommit("HEAD", author, committer, + "message", _oid, [parent]); + }) + .then(function(commitId) { + // the file is removed from the git repo, use fs.unlink now to remove it + // from the filesystem. + console.log("New Commit:", commitId.allocfmt()); + }) + .done(); diff --git a/examples/walk-history.js b/examples/walk-history.js new file mode 100644 index 000000000..2e41ce2da --- /dev/null +++ b/examples/walk-history.js @@ -0,0 +1,27 @@ +var nodegit = require("../"), + path = require("path"); + +// This code walks the history of the master branch and prints results +// that look very similar to calling `git log` from the command line + +nodegit.Repository.open(path.resolve(__dirname, "../.git")) + .then(function(repo) { + return repo.getMasterCommit(); + }) + .then(function(firstCommitOnMaster){ + // History returns an event. + var history = firstCommitOnMaster.history(nodegit.Revwalk.SORT.Time); + + // History emits "commit" event for each commit in the branch's history + history.on("commit", function(commit) { + console.log("commit " + commit.sha()); + console.log("Author:", commit.author().name() + + " <" + commit.author().email() + ">"); + console.log("Date:", commit.date()); + console.log("\n " + commit.message()); + }); + + // Don't forget to call `start()`! + history.start(); + }) + .done(); diff --git a/examples/walk-tree.js b/examples/walk-tree.js new file mode 100644 index 000000000..6c564acb6 --- /dev/null +++ b/examples/walk-tree.js @@ -0,0 +1,25 @@ +var nodegit = require("../"), + path = require("path"); + +// A `tree` in git is typically a representation of the filesystem at +// a revision. A tree has a set of entries, each entry being either a +// tree (directory), or a file. + +nodegit.Repository.open(path.resolve(__dirname, "../.git")) + .then(function(repo) { + return repo.getMasterCommit(); + }) + .then(function(firstCommitOnMaster) { + return firstCommitOnMaster.getTree(); + }) + .then(function(tree) { + // `walk()` returns an event. + var walker = tree.walk(); + walker.on("entry", function(entry) { + console.log(entry.path()); + }); + + // Don't forget to call `start()`! + walker.start(); + }) + .done(); diff --git a/package.json b/package.json index 4f7f3c067..66dec164d 100644 --- a/package.json +++ b/package.json @@ -85,7 +85,7 @@ "host": "https://s3.amazonaws.com/nodegit/nodegit/" }, "scripts": { - "lint": "jshint lib test/tests", + "lint": "jshint lib test/tests examples", "cov": "node test", "mocha": "mocha test/runner test/tests", "mochaDebug": "mocha --debug-brk test/runner test/tests",