|
| 1 | +var git = require('nodegit'); |
| 2 | + |
| 3 | +git.Repo.open('/opt/libgit2-test/.git', function(error, repo) { |
| 4 | + if (error) throw error; |
| 5 | + |
| 6 | + // ### SHA-1 Value Conversions |
| 7 | + |
| 8 | + // The `git_oid` is the structure that keeps the SHA value. We will use |
| 9 | + // this throughout the example for storing the value of the current SHA |
| 10 | + // key we're working with. |
| 11 | + var oid = git.Oid.fromString('fd6e612585290339ea8bf39c692a7ff6a29cb7c3'); |
| 12 | + |
| 13 | + // If you have a oid, you can easily get the hex value of the SHA as well. |
| 14 | + console.log(oid.sha()); |
| 15 | + |
| 16 | + // ### Working with the Object Database |
| 17 | + |
| 18 | + // **libgit2** provides [direct access][odb] to the object database. The |
| 19 | + // object database is where the actual objects are stored in Git. For |
| 20 | + // working with raw objects, we'll need to get this structure from the |
| 21 | + // repository. |
| 22 | + var odb = repo.odb(); |
| 23 | + |
| 24 | + // We can read raw objects directly from the object database if we have |
| 25 | + // the oid (SHA) of the object. This allows us to access objects without |
| 26 | + // knowing thier type and inspect the raw bytes unparsed. |
| 27 | + |
| 28 | + odb.read(oid, function(error, object) { |
| 29 | + if (error) throw error; |
| 30 | + |
| 31 | + // A raw object only has three properties - the type (commit, blob, tree |
| 32 | + // or tag), the size of the raw data and the raw, unparsed data itself. |
| 33 | + // For a commit or tag, that raw data is human readable plain ASCII |
| 34 | + // text. For a blob it is just file contents, so it could be text or |
| 35 | + // binary data. For a tree it is a special binary format, so it's unlikely |
| 36 | + // to be hugely helpful as a raw object. |
| 37 | + var data = object.data(), |
| 38 | + type = object.type(); |
| 39 | + |
| 40 | + console.log(object.size(), object.type()); |
| 41 | + }); |
| 42 | + |
| 43 | + // You can also write raw object data to Git. This is pretty cool because |
| 44 | + // it gives you direct access to the key/value properties of Git. Here |
| 45 | + // we'll write a new blob object that just contains a simple string. |
| 46 | + // Notice that we have to specify the object type as the `git_otype` enum. |
| 47 | + odb.write("test data", git.Object.Type.Blob, function(error, oid) { |
| 48 | + if (error) throw error; |
| 49 | + |
| 50 | + // Now that we've written the object, we can check out what SHA1 was |
| 51 | + // generated when the object was written to our database. |
| 52 | + console.log(oid.sha()); |
| 53 | + }); |
| 54 | + |
| 55 | + // ### Object Parsing |
| 56 | + |
| 57 | + // libgit2 has methods to parse every object type in Git so you don't have |
| 58 | + // to work directly with the raw data. This is much faster and simpler |
| 59 | + // than trying to deal with the raw data yourself. |
| 60 | + |
| 61 | + // #### Commit Parsing |
| 62 | + |
| 63 | + // [Parsing commit objects][pco] is simple and gives you access to all the |
| 64 | + // data in the commit - the author (name, email, datetime), committer |
| 65 | + // (same), tree, message, encoding and parent(s). |
| 66 | + |
| 67 | + oid = git.Oid.fromString("f0877d0b841d75172ec404fc9370173dfffc20d1"); |
| 68 | + repo.getCommit(oid, function(error, commit) { |
| 69 | + if (error) throw error; |
| 70 | + |
| 71 | + // Each of the properties of the commit object are accessible via methods, |
| 72 | + // including commonly needed variations, such as `git_commit_time` which |
| 73 | + // returns the author time and `git_commit_message` which gives you the |
| 74 | + // commit message (as a NUL-terminated string). |
| 75 | + console.log(commit.message(), commit.author(), commit.committer(), commit.time()); |
| 76 | + |
| 77 | + // Commits can have zero or more parents. The first (root) commit will |
| 78 | + // have no parents, most commits will have one (i.e. the commit it was |
| 79 | + // based on) and merge commits will have two or more. Commits can |
| 80 | + // technically have any number, though it's rare to have more than two. |
| 81 | + commit.getParents(function(error, parents) { |
| 82 | + parents.forEach(function(parent) { |
| 83 | + console.log(parent.oid()); |
| 84 | + }); |
| 85 | + }); |
| 86 | + }); |
| 87 | + |
| 88 | + // #### Writing Commits |
| 89 | + |
| 90 | + // libgit2 provides a couple of methods to create commit objects easily as |
| 91 | + // well. There are four different create signatures, we'll just show one |
| 92 | + // of them here. You can read about the other ones in the [commit API |
| 93 | + // docs][cd]. |
| 94 | + // |
| 95 | + // [cd]: http://libgit2.github.com/libgit2/#HEAD/group/commit |
| 96 | + |
| 97 | + var author = new git.Signature("Scott Chacon", "schacon@gmail.com", 123456789, 60); |
| 98 | + var committer = new git.Signature("Scott A Chacon", "scott@github.com", 987654321, 90); |
| 99 | + |
| 100 | + // Commit objects need a tree to point to and optionally one or more |
| 101 | + // parents. Here we're creating oid objects to create the commit with, |
| 102 | + // but you can also use existing ones: |
| 103 | + var treeId = git.Oid.fromString("28873d96b4e8f4e33ea30f4c682fd325f7ba56ac"); |
| 104 | + var parentId = git.Oid.fromString("f0877d0b841d75172ec404fc9370173dfffc20d1"); |
| 105 | + |
| 106 | + repo.getTree(treeId, function(error, tree) { |
| 107 | + repo.getCommit(parentId, function(error, parent) { |
| 108 | + |
| 109 | + // Here we actually create the commit object with a single call with all |
| 110 | + // the values we need to create the commit. The SHA key is written to the |
| 111 | + // `commit_id` variable here. |
| 112 | + repo.createCommit( |
| 113 | + null /* do not update the HEAD */, |
| 114 | + author, |
| 115 | + committer, |
| 116 | + null /* use default message encoding */, |
| 117 | + "example commit", |
| 118 | + tree, |
| 119 | + 1, parent, |
| 120 | + function (error, commitOid) { |
| 121 | + console.log(commitOid.sha()); |
| 122 | + }); |
| 123 | + }); |
| 124 | + }); |
| 125 | + |
| 126 | + // #### Tag Parsing |
| 127 | + |
| 128 | + // You can parse and create tags with the [tag management API][tm], which |
| 129 | + // functions very similarly to the commit lookup, parsing and creation |
| 130 | + // methods, since the objects themselves are very similar. |
| 131 | + |
| 132 | + var oid = git.Oid.fromString("bc422d45275aca289c51d79830b45cecebff7c3a"); |
| 133 | + repo.getTag(oid, function(error, tag) { |
| 134 | + if (error) throw error; |
| 135 | + |
| 136 | + // Now that we have the tag object, we can extract the information it |
| 137 | + // generally contains: the target (usually a commit object), the type of |
| 138 | + // the target object (usually 'commit'), the name ('v1.0'), the tagger (a |
| 139 | + // git_signature - name, email, timestamp), and the tag message. |
| 140 | + console.log(tag.name(), tag.type(), tag.message()); |
| 141 | + |
| 142 | + tag.getTarget(function (error, commit) { |
| 143 | + if (error) throw error; |
| 144 | + console.log(commit); |
| 145 | + }); |
| 146 | + }); |
| 147 | + |
| 148 | + // #### Tree Parsing |
| 149 | + |
| 150 | + // [Tree parsing][tp] is a bit different than the other objects, in that |
| 151 | + // we have a subtype which is the tree entry. This is not an actual |
| 152 | + // object type in Git, but a useful structure for parsing and traversing |
| 153 | + // tree entries. |
| 154 | + |
| 155 | + var oid = git.Oid.fromString("2a741c18ac5ff082a7caaec6e74db3075a1906b5"); |
| 156 | + repo.getTree(oid, function(error, tree) { |
| 157 | + if (error) throw error; |
| 158 | + |
| 159 | + console.log(tree.size()); |
| 160 | + tree.entries().forEach(function(entry) { |
| 161 | + console.log(entry.name()); |
| 162 | + |
| 163 | + if (entry.isDirectory()) { |
| 164 | + entry.getTree(function(error, tree) { |
| 165 | + if (error) throw error; |
| 166 | + |
| 167 | + console.log("Recursively got tree"); |
| 168 | + }); |
| 169 | + } else { |
| 170 | + entry.getBlob(function(error, blob) { |
| 171 | + console.log(blob.toString()); |
| 172 | + }); |
| 173 | + } |
| 174 | + }); |
| 175 | + |
| 176 | + // You can also access tree entries by path if you know the path of the |
| 177 | + // entry you're looking for. |
| 178 | + tree.getFile("/src/hello.c", function(error, entry) { |
| 179 | + entry.getBlob(function(error, blob) { |
| 180 | + console.log(blob.toString()); |
| 181 | + }); |
| 182 | + }); |
| 183 | + }); |
| 184 | + |
| 185 | + // #### Blob Parsing |
| 186 | + |
| 187 | + // The last object type is the simplest and requires the least parsing |
| 188 | + // help. Blobs are just file contents and can contain anything, there is |
| 189 | + // no structure to it. The main advantage to using the [simple blob |
| 190 | + // api][ba] is that when you're creating blobs you don't have to calculate |
| 191 | + // the size of the content. There is also a helper for reading a file |
| 192 | + // from disk and writing it to the db and getting the oid back so you |
| 193 | + // don't have to do all those steps yourself. |
| 194 | + |
| 195 | + var oid = git.Oid.fromString("af7574ea73f7b166f869ef1a39be126d9a186ae0"); |
| 196 | + repo.getBlob(oid, function(error, blob) { |
| 197 | + if (error) throw error; |
| 198 | + |
| 199 | + // You can access a buffer with the raw contents of the blob directly. |
| 200 | + // Note that this buffer may not be contain ASCII data for certain blobs |
| 201 | + // (e.g. binary files). |
| 202 | + |
| 203 | + var buffer = blob.content(); |
| 204 | + |
| 205 | + // If you know that the blob is UTF-8, however, |
| 206 | + |
| 207 | + console.log(blob.toString()); |
| 208 | + }); |
| 209 | + |
| 210 | + // ### Revwalking |
| 211 | + |
| 212 | + // The libgit2 [revision walking api][rw] provides methods to traverse the |
| 213 | + // directed graph created by the parent pointers of the commit objects. |
| 214 | + // Since all commits point back to the commit that came directly before |
| 215 | + // them, you can walk this parentage as a graph and find all the commits |
| 216 | + // that were ancestors of (reachable from) a given starting point. This |
| 217 | + // can allow you to create `git log` type functionality. |
| 218 | + |
| 219 | + var oid = git.Oid.fromString("f0877d0b841d75172ec404fc9370173dfffc20d1"); |
| 220 | + |
| 221 | + // To use the revwalker, create a new walker, tell it how you want to sort |
| 222 | + // the output and then push one or more starting points onto the walker. |
| 223 | + // If you want to emulate the output of `git log` you would push the SHA |
| 224 | + // of the commit that HEAD points to into the walker and then start |
| 225 | + // traversing them. You can also 'hide' commits that you want to stop at |
| 226 | + // or not see any of their ancestors. So if you want to emulate `git log |
| 227 | + // branch1..branch2`, you would push the oid of `branch2` and hide the oid |
| 228 | + // of `branch1`. |
| 229 | + var revWalk = repo.createRevWalk(); |
| 230 | + revWalk.sorting(git.RevWalk.Topological | git.RevWalkReverse); |
| 231 | + revWalk.push(oid); |
| 232 | + |
| 233 | + // Now that we have the starting point pushed onto the walker, we start |
| 234 | + // asking for ancestors. It will return them in the sorting order we asked |
| 235 | + // for as commit oids. We can then lookup and parse the commited pointed |
| 236 | + // at by the returned OID; note that this operation is specially fast |
| 237 | + // since the raw contents of the commit object will be cached in memory |
| 238 | + |
| 239 | + function walk() { |
| 240 | + revWalk.next(function(error, oid) { |
| 241 | + if (error) throw error; |
| 242 | + if (!oid) return; |
| 243 | + |
| 244 | + repo.getCommit(oid, function(error, commit) { |
| 245 | + if (error) throw error; |
| 246 | + |
| 247 | + console.log(commit.sha()); |
| 248 | + walk(); |
| 249 | + }); |
| 250 | + }); |
| 251 | + } |
| 252 | + walk(); |
| 253 | + |
| 254 | + // ### Index File Manipulation |
| 255 | + |
| 256 | + // The [index file API][gi] allows you to read, traverse, update and write |
| 257 | + // the Git index file (sometimes thought of as the staging area). |
| 258 | + repo.getIndex(function(error, index) { |
| 259 | + if (error) throw error; |
| 260 | + |
| 261 | + // For each entry in the index, you can get a bunch of information |
| 262 | + // including the SHA (oid), path and mode which map to the tree objects |
| 263 | + // that are written out. It also has filesystem properties to help |
| 264 | + // determine what to inspect for changes (ctime, mtime, dev, ino, uid, |
| 265 | + // gid, file_size and flags) All these properties are exported publicly in |
| 266 | + // the `git_index_entry` struct |
| 267 | + |
| 268 | + index.entries().forEach(function(entry) { |
| 269 | + console.log(entry.path(), entry.mtime(), entry.size()); |
| 270 | + }); |
| 271 | + }); |
| 272 | + |
| 273 | + // ### References |
| 274 | + |
| 275 | + // The [reference API][ref] allows you to list, resolve, create and update |
| 276 | + // references such as branches, tags and remote references (everything in |
| 277 | + // the .git/refs directory). |
| 278 | + |
| 279 | + repo.getReferences(function(error, references) { |
| 280 | + if (error) throw error; |
| 281 | + |
| 282 | + references.forEach(function(reference) { |
| 283 | + if (reference.type() == git.Reference.Oid) { |
| 284 | + console.log(oid.sha()); |
| 285 | + } else if (reference.type() == git.Reference.Symbolic) { |
| 286 | + console.log(reference.symbolicTarget()); |
| 287 | + } |
| 288 | + }); |
| 289 | + }); |
| 290 | +}); |
| 291 | + |
| 292 | + |
0 commit comments