├── .gitignore ├── .jshintignore ├── .jshintrc ├── .travis.yml ├── LICENSE.md ├── README.md ├── index.d.ts ├── index.js ├── package-lock.json ├── package.json └── tests ├── .jshintrc ├── fixtures ├── branch-with-slashes │ └── dot-git │ │ ├── HEAD │ │ └── refs │ │ └── heads │ │ ├── feature │ │ └── branch │ │ │ └── with │ │ │ └── slashes │ │ └── master ├── commit-packed │ └── dot-git │ │ ├── HEAD │ │ └── packed-refs ├── detached-head │ └── dot-git │ │ └── HEAD ├── linked-worktree │ ├── dot-git │ │ ├── HEAD │ │ └── worktrees │ │ │ └── linked │ │ │ ├── HEAD │ │ │ └── commondir │ └── linked │ │ └── dot-git ├── nested-repo │ ├── dot-git │ │ ├── .gitkeep │ │ ├── HEAD │ │ └── refs │ │ │ └── heads │ │ │ └── master │ └── foo │ │ └── bar │ │ └── .gitkeep ├── submodule │ ├── dot-git │ │ ├── HEAD │ │ └── modules │ │ │ └── my-submodule │ │ │ └── HEAD │ └── my-submodule │ │ └── dot-git ├── tag-on-parent-before-merge │ └── dot-git │ │ ├── HEAD │ │ ├── index │ │ ├── objects │ │ └── b6 │ │ │ └── 0d665ae0978a7b46e2447f4c13d7909997f56c │ │ └── refs │ │ ├── heads │ │ └── master │ │ └── tags │ │ └── magic-tag ├── tag-on-parent │ └── dot-git │ │ ├── HEAD │ │ ├── index │ │ ├── objects │ │ └── fb │ │ │ └── 26504da0ed5cd9ed366f7428c06a8433fd76e6 │ │ └── refs │ │ ├── heads │ │ └── master │ │ └── tags │ │ └── parent-magic-tag ├── tagged-annotated │ └── dot-git │ │ ├── COMMIT_EDITMSG │ │ ├── HEAD │ │ ├── config │ │ ├── description │ │ ├── hooks │ │ ├── applypatch-msg.sample │ │ ├── commit-msg.sample │ │ ├── post-update.sample │ │ ├── pre-applypatch.sample │ │ ├── pre-commit.sample │ │ ├── pre-push.sample │ │ ├── pre-rebase.sample │ │ ├── prepare-commit-msg.sample │ │ └── update.sample │ │ ├── index │ │ ├── info │ │ └── exclude │ │ ├── logs │ │ ├── HEAD │ │ └── refs │ │ │ └── heads │ │ │ └── master │ │ ├── objects │ │ ├── 54 │ │ │ └── 3b9bebdc6bd5c4b22136034a95dd097a57d3dd │ │ ├── c1 │ │ │ └── ee41c325d54f410b133e0018c7a6b1316f6cda │ │ ├── d3 │ │ │ └── 4ef562c5d670f49b5fdd85b633c469c71f0456 │ │ └── e6 │ │ │ └── 9de29bb2d1d6434b8b29ae775ad8c2e48c5391 │ │ └── refs │ │ ├── heads │ │ └── master │ │ └── tags │ │ └── awesome-tag ├── tagged-commit-mixed-packing │ └── dot-git │ │ ├── HEAD │ │ ├── objects │ │ ├── 37 │ │ │ └── ece7ad9ded5f2312bb6be8d0c21ecebca088ac │ │ ├── 90 │ │ │ └── 4de697a2c441e3db28f5c531ccfdab5f4435e3 │ │ ├── 95 │ │ │ └── 0a188f0a4224ce6a1ac710915113df972aeb2c │ │ └── e1 │ │ │ └── b209796f8918bf7ce1f00be1ea1923f5801339 │ │ ├── packed-refs │ │ └── refs │ │ ├── heads │ │ └── master │ │ └── tags │ │ ├── --lightweight-tag │ │ ├── 0-lightweight-tag │ │ └── e-annotated-tag ├── tagged-commit-packed-annotated │ └── dot-git │ │ ├── HEAD │ │ ├── packed-refs │ │ └── refs │ │ └── heads │ │ └── master ├── tagged-commit-packed │ └── dot-git │ │ ├── HEAD │ │ ├── packed-refs │ │ └── refs │ │ └── heads │ │ └── master ├── tagged-commit-unpacked-no-object │ └── dot-git │ │ ├── HEAD │ │ ├── objects │ │ ├── 54 │ │ │ └── 3b9bebdc6bd5c4b22136034a95dd097a57d3dd │ │ └── e6 │ │ │ └── 9de29bb2d1d6434b8b29ae775ad8c2e48c5391 │ │ └── refs │ │ ├── heads │ │ └── master │ │ └── tags │ │ └── awesome-tag └── tagged-commit-unpacked │ └── dot-git │ ├── COMMIT_EDITMSG │ ├── HEAD │ ├── config │ ├── description │ ├── hooks │ ├── applypatch-msg.sample │ ├── commit-msg.sample │ ├── post-update.sample │ ├── pre-applypatch.sample │ ├── pre-commit.sample │ ├── pre-push.sample │ ├── pre-rebase.sample │ ├── prepare-commit-msg.sample │ └── update.sample │ ├── index │ ├── info │ └── exclude │ ├── logs │ ├── HEAD │ └── refs │ │ └── heads │ │ └── master │ ├── objects │ ├── 54 │ │ └── 3b9bebdc6bd5c4b22136034a95dd097a57d3dd │ ├── c1 │ │ └── ee41c325d54f410b133e0018c7a6b1316f6cda │ └── e6 │ │ └── 9de29bb2d1d6434b8b29ae775ad8c2e48c5391 │ └── refs │ ├── heads │ └── master │ └── tags │ └── awesome-tag └── index.js /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | -------------------------------------------------------------------------------- /.jshintignore: -------------------------------------------------------------------------------- 1 | node_modules/* 2 | -------------------------------------------------------------------------------- /.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "predef": [ 3 | "console", 4 | "-Promise" 5 | ], 6 | "expr": true, 7 | "proto": true, 8 | "strict": true, 9 | "indent": 2, 10 | "camelcase": true, 11 | "node": true, 12 | "browser": false, 13 | "boss": true, 14 | "curly": true, 15 | "latedef": "nofunc", 16 | "debug": false, 17 | "devel": false, 18 | "eqeqeq": true, 19 | "evil": true, 20 | "forin": false, 21 | "immed": false, 22 | "laxbreak": false, 23 | "newcap": true, 24 | "noarg": true, 25 | "noempty": false, 26 | "quotmark": true, 27 | "nonew": false, 28 | "nomen": false, 29 | "onevar": false, 30 | "plusplus": false, 31 | "regexp": false, 32 | "undef": true, 33 | "unused": true, 34 | "sub": true, 35 | "trailing": true, 36 | "white": false, 37 | "eqnull": true, 38 | "esnext": true 39 | } 40 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - "4" 4 | - "6" 5 | - "8" 6 | - "9" 7 | - "10" 8 | - "12" 9 | - "14" 10 | 11 | sudo: false 12 | cache: 13 | directories: 14 | - node_modules 15 | 16 | branches: 17 | only: 18 | - master 19 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 rwjblue 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## git-repo-info 2 | 3 | Retrieves repo information without relying on the `git` command. 4 | 5 | ### Usage 6 | 7 | ```javascript 8 | var getRepoInfo = require('git-repo-info'); 9 | 10 | var info = getRepoInfo(); 11 | 12 | info.branch // current branch 13 | info.sha // current sha 14 | info.abbreviatedSha // first 10 chars of the current sha 15 | info.tag // tag for the current sha (or `null` if no tag exists) 16 | info.lastTag // tag for the closest tagged ancestor 17 | // (or `null` if no ancestor is tagged) 18 | info.commitsSinceLastTag // number of commits since the closest tagged ancestor 19 | // (`0` if this commit is tagged, or `Infinity` if no ancestor is tagged) 20 | info.committer           // committer for the current sha 21 | info.committerDate // commit date for the current sha 22 | info.author // author for the current sha 23 | info.authorDate // authored date for the current sha 24 | info.commitMessage // commit message for the current sha 25 | info.root // root directory for the Git repo or submodule 26 | // (if in a worktree, this is the directory containing the original copy) 27 | info.commonGitDir // directory containing Git metadata for this repo or submodule 28 | // (if in a worktree, this is the primary Git directory for the repo) 29 | info.worktreeGitDir // if in a worktree, the directory containing Git metadata specific to 30 | // this worktree; otherwise, this is the same as `commonGitDir`. 31 | ``` 32 | 33 | When called without any arguments, `git-repo-info` will automatically lookup upwards 34 | into parent directories to find the first match with a `.git` folder. 35 | 36 | If passed an argument, it will be assumed to be the path to the repo's `.git` folder 37 | to inspect. 38 | -------------------------------------------------------------------------------- /index.d.ts: -------------------------------------------------------------------------------- 1 | declare function gitRepoInfo(gitPath?: string): gitRepoInfo.GitRepoInfo; 2 | 3 | declare namespace gitRepoInfo { 4 | export interface GitRepoInfo { 5 | /** The current branch */ 6 | branch: string; 7 | /** SHA of the current commit */ 8 | sha: string; 9 | /** The first 10 chars of the current SHA */ 10 | abbreviatedSha: string; 11 | /** The tag for the current SHA (or `null` if no tag exists) */ 12 | tag: string | null; 13 | /** Tag for the closest tagged ancestor (or `null` if no ancestor is tagged) */ 14 | lastTag: string | null; 15 | /** 16 | * Number of commits since the closest tagged ancestor. 17 | * `0` if this commit is tagged, or `Infinity` if no ancestor is tagged. 18 | */ 19 | commitsSinceLastTag: number; 20 | /** The committer of the current SHA */ 21 | committer: string; 22 | /** The commit date of the current SHA */ 23 | committerDate: string; 24 | /** The author for the current SHA */ 25 | author: string; 26 | /** The authored date for the current SHA */ 27 | authorDate: string; 28 | /** The commit message for the current SHA */ 29 | commitMessage: string; 30 | /** 31 | * The root directory for the Git repo or submodule. 32 | * If in a worktree, this is the directory containing the original copy, not the worktree. 33 | */ 34 | root: string; 35 | /** 36 | * The directory containing Git metadata for this repo or submodule. 37 | * If in a worktree, this is the primary Git directory for the repo, not the worktree-specific one. 38 | */ 39 | commonGitDir: string; 40 | /** 41 | * If in a worktree, the directory containing Git metadata specific to this worktree. 42 | * Otherwise, this is the same as `commonGitDir`. 43 | */ 44 | worktreeGitDir: string; 45 | } 46 | } 47 | 48 | export = gitRepoInfo; 49 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var fs = require('fs'); 4 | var path = require('path'); 5 | var zlib = require('zlib'); 6 | 7 | var GIT_DIR = '.git'; 8 | 9 | function changeGitDir(newDirName) { 10 | GIT_DIR = newDirName; 11 | } 12 | 13 | function findRepoHandleLinkedWorktree(gitPath) { 14 | var stat = fs.statSync(gitPath); 15 | var root = path.dirname(path.resolve(gitPath)); 16 | if (stat.isDirectory()) { 17 | return { 18 | // for the base (non-linked) dir, there is no distinction between where we 19 | // find the HEAD file and where we find the rest of .git 20 | worktreeGitDir: gitPath, 21 | commonGitDir: gitPath, 22 | root: root, 23 | }; 24 | } else { 25 | // We have a file that tells us where to find the worktree git dir. Once we 26 | // look there we'll know how to find the common git dir, depending on 27 | // whether it's a linked worktree git dir, or a submodule dir 28 | 29 | var linkedGitDir = fs.readFileSync(gitPath).toString(); 30 | var absolutePath=path.resolve(path.dirname(gitPath)); 31 | var worktreeGitDirUnresolved = /gitdir: (.*)/.exec(linkedGitDir)[1]; 32 | var worktreeGitDir = path.resolve(absolutePath,worktreeGitDirUnresolved); 33 | var commonDirPath = path.join(worktreeGitDir, 'commondir'); 34 | if (fs.existsSync(commonDirPath)) { 35 | // this directory contains a `commondir` file; we're in a linked worktree 36 | 37 | var commonDirRelative = fs.readFileSync(commonDirPath).toString().replace(/\r?\n$/, ''); 38 | var commonDir = path.resolve(path.join(worktreeGitDir, commonDirRelative)); 39 | 40 | return { 41 | worktreeGitDir: worktreeGitDir, 42 | commonGitDir: commonDir, 43 | root: path.dirname(commonDir), 44 | }; 45 | } else { 46 | // there is no `commondir` file; we're in a submodule 47 | return { 48 | worktreeGitDir: worktreeGitDir, 49 | commonGitDir: worktreeGitDir, 50 | root: root, 51 | }; 52 | } 53 | } 54 | } 55 | 56 | function findRepo(startingPath) { 57 | var gitPath, lastPath; 58 | var currentPath = startingPath; 59 | 60 | if (!currentPath) { currentPath = process.cwd(); } 61 | 62 | do { 63 | gitPath = path.join(currentPath, GIT_DIR); 64 | 65 | if (fs.existsSync(gitPath)) { 66 | return findRepoHandleLinkedWorktree(gitPath); 67 | } 68 | 69 | lastPath = currentPath; 70 | currentPath = path.resolve(currentPath, '..'); 71 | } while (lastPath !== currentPath); 72 | 73 | return null; 74 | } 75 | 76 | function findPackedTags(gitPath, refPath) { 77 | return getPackedRefsForType(gitPath, refPath, 'tag'); 78 | } 79 | 80 | function findPackedCommit(gitPath, refPath) { 81 | return getPackedRefsForType(gitPath, refPath, 'commit')[0]; 82 | } 83 | 84 | function getPackedRefsForType(gitPath, refPath, type) { 85 | var packedRefsFile = getPackedRefsFile(gitPath); 86 | if (packedRefsFile) { 87 | return getLinesForRefPath(packedRefsFile, type, refPath).map(function(shaLine) { 88 | return getShaBasedOnType(type, shaLine); 89 | }); 90 | } 91 | return []; 92 | } 93 | 94 | function getPackedRefsFile(gitPath) { 95 | var packedRefsFilePath = path.join(gitPath, 'packed-refs'); 96 | return fs.existsSync(packedRefsFilePath) ? fs.readFileSync(packedRefsFilePath, { encoding: 'utf8' }) : false; 97 | } 98 | 99 | function getLinesForRefPath(packedRefsFile, type, refPath) { 100 | return packedRefsFile.split(/\r?\n/).reduce(function(acc, line, idx, arr) { 101 | var targetLine = line.indexOf('^') > -1 ? arr[idx-1] : line; 102 | return doesLineMatchRefPath(type, line, refPath) ? acc.concat(targetLine) : acc; 103 | }, []); 104 | } 105 | 106 | function doesLineMatchRefPath(type, line, refPath) { 107 | var refPrefix = type === 'tag' ? 'refs/tags' : 'refs/heads'; 108 | return (line.indexOf(refPrefix) > -1 || line.indexOf('^') > -1) && line.indexOf(refPath) > -1; 109 | } 110 | 111 | function getShaBasedOnType(type, shaLine) { 112 | var shaResult = ''; 113 | if (type === 'tag') { 114 | shaResult = shaLine.split('tags/')[1]; 115 | } else if (type === 'commit') { 116 | shaResult = shaLine.split(' ')[0]; 117 | } 118 | 119 | return shaResult; 120 | } 121 | 122 | function commitForTag(gitPath, tag) { 123 | var tagPath = path.join(gitPath, 'refs', 'tags', tag); 124 | var taggedObject = fs.readFileSync(tagPath, { encoding: 'utf8' }).trim(); 125 | var objectPath = path.join(gitPath, 'objects', taggedObject.slice(0, 2), taggedObject.slice(2)); 126 | 127 | if (!zlib.inflateSync || !fs.existsSync(objectPath)) { 128 | // we cannot support annotated tags on node v0.10 because 129 | // zlib does not allow sync access 130 | return taggedObject; 131 | } 132 | 133 | var objectContents = zlib.inflateSync(fs.readFileSync(objectPath)).toString(); 134 | 135 | // 'tag 172\u0000object c1ee41c325d54f410b133e0018c7a6b1316f6cda\ntype commit\ntag awesome-tag\ntagger Robert Jackson 136 | // 1429100021 -0400\n\nI am making an annotated tag.\n' 137 | if (objectContents.slice(0,3) === 'tag') { 138 | var sections = objectContents.split(/\0|\r?\n/); 139 | var sha = sections[1].slice(7); 140 | 141 | return sha; 142 | } else { 143 | // this will return the tag for lightweight tags 144 | return taggedObject; 145 | } 146 | } 147 | 148 | function findTag(gitPath, sha) { 149 | var tags = findPackedTags(gitPath, sha) 150 | .concat(findUnpackedTags(gitPath, sha)); 151 | tags.sort(); 152 | return tags.length ? tags[0] : false; 153 | } 154 | 155 | var LAST_TAG_CACHE = {}; 156 | 157 | function findLastTagCached(gitPath, sha) { 158 | if(!LAST_TAG_CACHE[gitPath]) { 159 | LAST_TAG_CACHE[gitPath] = {}; 160 | } 161 | 162 | if(!LAST_TAG_CACHE[gitPath][sha]) { 163 | LAST_TAG_CACHE[gitPath][sha] = findLastTag(gitPath, sha); 164 | } 165 | 166 | return LAST_TAG_CACHE[gitPath][sha]; 167 | } 168 | 169 | function findLastTag(gitPath, sha) { 170 | var queue = [{ sha: sha, depth: 0 }]; 171 | var seenCommits = new Set(); 172 | while (queue.length) { 173 | var element = queue.shift(); 174 | if (seenCommits.has(element.sha)) { 175 | continue; 176 | } 177 | seenCommits.add(element.sha); 178 | var tag = findTag(gitPath, element.sha); 179 | if (tag) { 180 | return { 181 | tag: tag, 182 | commitsSinceLastTag: element.depth 183 | }; 184 | } 185 | var commitData = getCommitData(gitPath, sha); 186 | if (commitData && commitData.parents) { 187 | for (var i = 0; i < commitData.parents.length; i++) { 188 | queue.push({ sha: commitData.parents[i], depth: element.depth + 1 }); 189 | } 190 | } 191 | } 192 | return { tag: null, commitsSinceLastTag: Infinity }; 193 | } 194 | 195 | function findUnpackedTags(gitPath, sha) { 196 | var unpackedTags = []; 197 | var tags = findLooseRefsForType(gitPath, 'tags'); 198 | for (var i = 0, l = tags.length; i < l; i++) { 199 | var commitAtTag = commitForTag(gitPath, tags[i]); 200 | if (commitAtTag === sha) { 201 | unpackedTags.push(tags[i]); 202 | } 203 | } 204 | return unpackedTags; 205 | } 206 | 207 | function findLooseRefsForType(gitPath, type) { 208 | var refsPath = path.join(gitPath, 'refs', type); 209 | return fs.existsSync(refsPath) ? fs.readdirSync(refsPath) : []; 210 | } 211 | 212 | module.exports = function(gitPath) { 213 | var gitPathInfo = findRepo(gitPath); 214 | 215 | var result = { 216 | sha: null, 217 | abbreviatedSha: null, 218 | branch: null, 219 | tag: null, 220 | committer: null, 221 | committerDate: null, 222 | author: null, 223 | authorDate: null, 224 | commitMessage: null, 225 | root: null, 226 | commonGitDir: null, 227 | worktreeGitDir: null, 228 | lastTag: null, 229 | commitsSinceLastTag: 0, 230 | }; 231 | 232 | if (!gitPathInfo) { return result; } 233 | 234 | try { 235 | result.root = gitPathInfo.root; 236 | result.commonGitDir = gitPathInfo.commonGitDir; 237 | result.worktreeGitDir = gitPathInfo.worktreeGitDir; 238 | 239 | var headFilePath = path.join(gitPathInfo.worktreeGitDir, 'HEAD'); 240 | 241 | if (fs.existsSync(headFilePath)) { 242 | var headFile = fs.readFileSync(headFilePath, {encoding: 'utf8'}); 243 | var branchName = headFile.split('/').slice(2).join('/').trim(); 244 | if (!branchName) { 245 | branchName = headFile.split('/').slice(-1)[0].trim(); 246 | } 247 | var refPath = headFile.split(' ')[1]; 248 | 249 | // Find branch and SHA 250 | if (refPath) { 251 | refPath = refPath.trim(); 252 | var branchPath = path.join(gitPathInfo.commonGitDir, refPath); 253 | 254 | result.branch = branchName; 255 | if (fs.existsSync(branchPath)) { 256 | result.sha = fs.readFileSync(branchPath, { encoding: 'utf8' }).trim(); 257 | } else { 258 | result.sha = findPackedCommit(gitPathInfo.commonGitDir, refPath); 259 | } 260 | } else { 261 | result.sha = branchName; 262 | } 263 | 264 | result.abbreviatedSha = result.sha.slice(0,10); 265 | 266 | // Find commit data 267 | var commitData = getCommitData(gitPathInfo.commonGitDir, result.sha); 268 | if (commitData) { 269 | result = Object.keys(commitData).reduce(function(r, key) { 270 | result[key] = commitData[key]; 271 | return result; 272 | }, result); 273 | } 274 | 275 | // Find tag 276 | var tag = findTag(gitPathInfo.commonGitDir, result.sha); 277 | if (tag) { 278 | result.tag = tag; 279 | } 280 | 281 | var lastTagInfo = findLastTagCached(gitPathInfo.commonGitDir, result.sha); 282 | result.lastTag = lastTagInfo.tag; 283 | result.commitsSinceLastTag = lastTagInfo.commitsSinceLastTag; 284 | } 285 | } catch (e) { 286 | if (!module.exports._suppressErrors) { 287 | throw e; // helps with testing and scenarios where we do not expect errors 288 | } else { 289 | // eat the error 290 | } 291 | } 292 | 293 | return result; 294 | }; 295 | 296 | module.exports._suppressErrors = true; 297 | module.exports._findRepo = findRepo; 298 | module.exports._changeGitDir = changeGitDir; 299 | 300 | function getCommitData(gitPath, sha) { 301 | var objectPath = path.join(gitPath, 'objects', sha.slice(0, 2), sha.slice(2)); 302 | 303 | if (zlib.inflateSync && fs.existsSync(objectPath)) { 304 | var objectContents = zlib.inflateSync(fs.readFileSync(objectPath)).toString(); 305 | 306 | return objectContents.split(/\0|\r?\n/) 307 | .filter(function(item) { 308 | return !!item; 309 | }) 310 | .reduce(function(data, section) { 311 | var part = section.slice(0, section.indexOf(' ')).trim(); 312 | 313 | switch(part) { 314 | case 'commit': 315 | case 'tag': 316 | case 'object': 317 | case 'type': 318 | case 'tree': 319 | //ignore these for now 320 | break; 321 | case 'author': 322 | case 'committer': 323 | var parts = section.match(/^(?:author|committer)\s(.+)\s(\d+\s(?:\+|\-)\d{4})$/); 324 | 325 | if (parts) { 326 | data[part] = parts[1]; 327 | data[part + 'Date'] = parseDate(parts[2]); 328 | } 329 | break; 330 | case 'parent': 331 | if (!data.parents) { 332 | data.parents = []; 333 | } 334 | data.parents.push(section.split(' ')[1]); 335 | break; 336 | default: 337 | //should just be the commit message left 338 | data.commitMessage = section; 339 | } 340 | 341 | return data; 342 | }, {}); 343 | } 344 | } 345 | 346 | function parseDate(d) { 347 | var epoch = d.split(' ')[0]; 348 | return new Date(epoch * 1000).toISOString(); 349 | } 350 | -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "git-repo-info", 3 | "version": "2.1.1", 4 | "lockfileVersion": 1, 5 | "requires": true, 6 | "dependencies": { 7 | "balanced-match": { 8 | "version": "1.0.0", 9 | "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", 10 | "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", 11 | "dev": true 12 | }, 13 | "brace-expansion": { 14 | "version": "1.1.11", 15 | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", 16 | "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", 17 | "dev": true, 18 | "requires": { 19 | "balanced-match": "^1.0.0", 20 | "concat-map": "0.0.1" 21 | } 22 | }, 23 | "browser-stdout": { 24 | "version": "1.3.0", 25 | "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.0.tgz", 26 | "integrity": "sha1-81HTKWnTL6XXpVZxVCY9korjvR8=", 27 | "dev": true 28 | }, 29 | "cli": { 30 | "version": "1.0.1", 31 | "resolved": "https://registry.npmjs.org/cli/-/cli-1.0.1.tgz", 32 | "integrity": "sha1-IoF1NPJL+klQw01TLUjsvGIbjBQ=", 33 | "dev": true, 34 | "requires": { 35 | "exit": "0.1.2", 36 | "glob": "^7.1.1" 37 | } 38 | }, 39 | "commander": { 40 | "version": "2.11.0", 41 | "resolved": "https://registry.npmjs.org/commander/-/commander-2.11.0.tgz", 42 | "integrity": "sha512-b0553uYA5YAEGgyYIGYROzKQ7X5RAqedkfjiZxwi0kL1g3bOaBNNZfYkzt/CL0umgD5wc9Jec2FbB98CjkMRvQ==", 43 | "dev": true 44 | }, 45 | "concat-map": { 46 | "version": "0.0.1", 47 | "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", 48 | "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", 49 | "dev": true 50 | }, 51 | "console-browserify": { 52 | "version": "1.1.0", 53 | "resolved": "https://registry.npmjs.org/console-browserify/-/console-browserify-1.1.0.tgz", 54 | "integrity": "sha1-8CQcRXMKn8YyOyBtvzjtx0HQuxA=", 55 | "dev": true, 56 | "requires": { 57 | "date-now": "^0.1.4" 58 | } 59 | }, 60 | "core-util-is": { 61 | "version": "1.0.2", 62 | "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", 63 | "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", 64 | "dev": true 65 | }, 66 | "date-now": { 67 | "version": "0.1.4", 68 | "resolved": "https://registry.npmjs.org/date-now/-/date-now-0.1.4.tgz", 69 | "integrity": "sha1-6vQ5/U1ISK105cx9vvIAZyueNFs=", 70 | "dev": true 71 | }, 72 | "debug": { 73 | "version": "3.1.0", 74 | "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", 75 | "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", 76 | "dev": true, 77 | "requires": { 78 | "ms": "2.0.0" 79 | } 80 | }, 81 | "diff": { 82 | "version": "3.3.1", 83 | "resolved": "https://registry.npmjs.org/diff/-/diff-3.3.1.tgz", 84 | "integrity": "sha512-MKPHZDMB0o6yHyDryUOScqZibp914ksXwAMYMTHj6KO8UeKsRYNJD3oNCKjTqZon+V488P7N/HzXF8t7ZR95ww==", 85 | "dev": true 86 | }, 87 | "dom-serializer": { 88 | "version": "0.1.0", 89 | "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.1.0.tgz", 90 | "integrity": "sha1-BzxpdUbOB4DOI75KKOKT5AvDDII=", 91 | "dev": true, 92 | "requires": { 93 | "domelementtype": "~1.1.1", 94 | "entities": "~1.1.1" 95 | }, 96 | "dependencies": { 97 | "domelementtype": { 98 | "version": "1.1.3", 99 | "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.1.3.tgz", 100 | "integrity": "sha1-vSh3PiZCiBrsUVRJJCmcXNgiGFs=", 101 | "dev": true 102 | }, 103 | "entities": { 104 | "version": "1.1.2", 105 | "resolved": "https://registry.npmjs.org/entities/-/entities-1.1.2.tgz", 106 | "integrity": "sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w==", 107 | "dev": true 108 | } 109 | } 110 | }, 111 | "domelementtype": { 112 | "version": "1.3.1", 113 | "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.1.tgz", 114 | "integrity": "sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w==", 115 | "dev": true 116 | }, 117 | "domhandler": { 118 | "version": "2.3.0", 119 | "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-2.3.0.tgz", 120 | "integrity": "sha1-LeWaCCLVAn+r/28DLCsloqir5zg=", 121 | "dev": true, 122 | "requires": { 123 | "domelementtype": "1" 124 | } 125 | }, 126 | "domutils": { 127 | "version": "1.5.1", 128 | "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.5.1.tgz", 129 | "integrity": "sha1-3NhIiib1Y9YQeeSMn3t+Mjc2gs8=", 130 | "dev": true, 131 | "requires": { 132 | "dom-serializer": "0", 133 | "domelementtype": "1" 134 | } 135 | }, 136 | "entities": { 137 | "version": "1.0.0", 138 | "resolved": "https://registry.npmjs.org/entities/-/entities-1.0.0.tgz", 139 | "integrity": "sha1-sph6o4ITR/zeZCsk/fyeT7cSvyY=", 140 | "dev": true 141 | }, 142 | "escape-string-regexp": { 143 | "version": "1.0.5", 144 | "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", 145 | "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", 146 | "dev": true 147 | }, 148 | "exit": { 149 | "version": "0.1.2", 150 | "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", 151 | "integrity": "sha1-BjJjj42HfMghB9MKD/8aF8uhzQw=", 152 | "dev": true 153 | }, 154 | "fs.realpath": { 155 | "version": "1.0.0", 156 | "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", 157 | "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", 158 | "dev": true 159 | }, 160 | "glob": { 161 | "version": "7.1.2", 162 | "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", 163 | "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", 164 | "dev": true, 165 | "requires": { 166 | "fs.realpath": "^1.0.0", 167 | "inflight": "^1.0.4", 168 | "inherits": "2", 169 | "minimatch": "^3.0.4", 170 | "once": "^1.3.0", 171 | "path-is-absolute": "^1.0.0" 172 | } 173 | }, 174 | "growl": { 175 | "version": "1.10.3", 176 | "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.3.tgz", 177 | "integrity": "sha512-hKlsbA5Vu3xsh1Cg3J7jSmX/WaW6A5oBeqzM88oNbCRQFz+zUaXm6yxS4RVytp1scBoJzSYl4YAEOQIt6O8V1Q==", 178 | "dev": true 179 | }, 180 | "has-flag": { 181 | "version": "2.0.0", 182 | "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-2.0.0.tgz", 183 | "integrity": "sha1-6CB68cx7MNRGzHC3NLXovhj4jVE=", 184 | "dev": true 185 | }, 186 | "he": { 187 | "version": "1.1.1", 188 | "resolved": "https://registry.npmjs.org/he/-/he-1.1.1.tgz", 189 | "integrity": "sha1-k0EP0hsAlzUVH4howvJx80J+I/0=", 190 | "dev": true 191 | }, 192 | "htmlparser2": { 193 | "version": "3.8.3", 194 | "resolved": "http://registry.npmjs.org/htmlparser2/-/htmlparser2-3.8.3.tgz", 195 | "integrity": "sha1-mWwosZFRaovoZQGn15dX5ccMEGg=", 196 | "dev": true, 197 | "requires": { 198 | "domelementtype": "1", 199 | "domhandler": "2.3", 200 | "domutils": "1.5", 201 | "entities": "1.0", 202 | "readable-stream": "1.1" 203 | } 204 | }, 205 | "inflight": { 206 | "version": "1.0.6", 207 | "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", 208 | "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", 209 | "dev": true, 210 | "requires": { 211 | "once": "^1.3.0", 212 | "wrappy": "1" 213 | } 214 | }, 215 | "inherits": { 216 | "version": "2.0.3", 217 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", 218 | "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", 219 | "dev": true 220 | }, 221 | "isarray": { 222 | "version": "0.0.1", 223 | "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", 224 | "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", 225 | "dev": true 226 | }, 227 | "jshint": { 228 | "version": "2.9.7", 229 | "resolved": "https://registry.npmjs.org/jshint/-/jshint-2.9.7.tgz", 230 | "integrity": "sha512-Q8XN38hGsVQhdlM+4gd1Xl7OB1VieSuCJf+fEJjpo59JH99bVJhXRXAh26qQ15wfdd1VPMuDWNeSWoNl53T4YA==", 231 | "dev": true, 232 | "requires": { 233 | "cli": "~1.0.0", 234 | "console-browserify": "1.1.x", 235 | "exit": "0.1.x", 236 | "htmlparser2": "3.8.x", 237 | "lodash": "~4.17.10", 238 | "minimatch": "~3.0.2", 239 | "shelljs": "0.3.x", 240 | "strip-json-comments": "1.0.x" 241 | }, 242 | "dependencies": { 243 | "shelljs": { 244 | "version": "0.3.0", 245 | "resolved": "http://registry.npmjs.org/shelljs/-/shelljs-0.3.0.tgz", 246 | "integrity": "sha1-NZbmMHp4FUT1kfN9phg2DzHbV7E=", 247 | "dev": true 248 | } 249 | } 250 | }, 251 | "lodash": { 252 | "version": "4.17.15", 253 | "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", 254 | "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==", 255 | "dev": true 256 | }, 257 | "minimatch": { 258 | "version": "3.0.4", 259 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", 260 | "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", 261 | "dev": true, 262 | "requires": { 263 | "brace-expansion": "^1.1.7" 264 | } 265 | }, 266 | "minimist": { 267 | "version": "0.0.8", 268 | "resolved": "http://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", 269 | "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", 270 | "dev": true 271 | }, 272 | "mkdirp": { 273 | "version": "0.5.1", 274 | "resolved": "http://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", 275 | "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", 276 | "dev": true, 277 | "requires": { 278 | "minimist": "0.0.8" 279 | } 280 | }, 281 | "mocha": { 282 | "version": "4.1.0", 283 | "resolved": "https://registry.npmjs.org/mocha/-/mocha-4.1.0.tgz", 284 | "integrity": "sha512-0RVnjg1HJsXY2YFDoTNzcc1NKhYuXKRrBAG2gDygmJJA136Cs2QlRliZG1mA0ap7cuaT30mw16luAeln+4RiNA==", 285 | "dev": true, 286 | "requires": { 287 | "browser-stdout": "1.3.0", 288 | "commander": "2.11.0", 289 | "debug": "3.1.0", 290 | "diff": "3.3.1", 291 | "escape-string-regexp": "1.0.5", 292 | "glob": "7.1.2", 293 | "growl": "1.10.3", 294 | "he": "1.1.1", 295 | "mkdirp": "0.5.1", 296 | "supports-color": "4.4.0" 297 | } 298 | }, 299 | "mocha-jshint": { 300 | "version": "2.3.1", 301 | "resolved": "https://registry.npmjs.org/mocha-jshint/-/mocha-jshint-2.3.1.tgz", 302 | "integrity": "sha1-MD8n5TOThVnSDyakEj1by1ZFpUY=", 303 | "dev": true, 304 | "requires": { 305 | "jshint": "^2.8.0", 306 | "minimatch": "^3.0.0", 307 | "shelljs": "^0.4.0", 308 | "uniq": "^1.0.1" 309 | } 310 | }, 311 | "ms": { 312 | "version": "2.0.0", 313 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", 314 | "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", 315 | "dev": true 316 | }, 317 | "once": { 318 | "version": "1.4.0", 319 | "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", 320 | "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", 321 | "dev": true, 322 | "requires": { 323 | "wrappy": "1" 324 | } 325 | }, 326 | "path-is-absolute": { 327 | "version": "1.0.1", 328 | "resolved": "http://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", 329 | "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", 330 | "dev": true 331 | }, 332 | "readable-stream": { 333 | "version": "1.1.14", 334 | "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", 335 | "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", 336 | "dev": true, 337 | "requires": { 338 | "core-util-is": "~1.0.0", 339 | "inherits": "~2.0.1", 340 | "isarray": "0.0.1", 341 | "string_decoder": "~0.10.x" 342 | } 343 | }, 344 | "shelljs": { 345 | "version": "0.4.0", 346 | "resolved": "http://registry.npmjs.org/shelljs/-/shelljs-0.4.0.tgz", 347 | "integrity": "sha1-GZ/p4t43nv0D00X/FAYlJeSzHsI=", 348 | "dev": true 349 | }, 350 | "string_decoder": { 351 | "version": "0.10.31", 352 | "resolved": "http://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", 353 | "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=", 354 | "dev": true 355 | }, 356 | "strip-json-comments": { 357 | "version": "1.0.4", 358 | "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-1.0.4.tgz", 359 | "integrity": "sha1-HhX7ysl9Pumb8tc7TGVrCCu6+5E=", 360 | "dev": true 361 | }, 362 | "supports-color": { 363 | "version": "4.4.0", 364 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.4.0.tgz", 365 | "integrity": "sha512-rKC3+DyXWgK0ZLKwmRsrkyHVZAjNkfzeehuFWdGGcqGDTZFH73+RH6S/RDAAxl9GusSjZSUWYLmT9N5pzXFOXQ==", 366 | "dev": true, 367 | "requires": { 368 | "has-flag": "^2.0.0" 369 | } 370 | }, 371 | "uniq": { 372 | "version": "1.0.1", 373 | "resolved": "https://registry.npmjs.org/uniq/-/uniq-1.0.1.tgz", 374 | "integrity": "sha1-sxxa6CVIRKOoKBVBzisEuGWnNP8=", 375 | "dev": true 376 | }, 377 | "wrappy": { 378 | "version": "1.0.2", 379 | "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", 380 | "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", 381 | "dev": true 382 | } 383 | } 384 | } 385 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "git-repo-info", 3 | "version": "2.1.1", 4 | "description": "Retrieve current sha and branch name from a git repo.", 5 | "main": "index.js", 6 | "types": "index.d.ts", 7 | "files": [ 8 | "index.js", 9 | "index.d.ts" 10 | ], 11 | "scripts": { 12 | "test": "mocha tests" 13 | }, 14 | "repository": { 15 | "type": "git", 16 | "url": "https://github.com/rwjblue/git-repo-info.git" 17 | }, 18 | "keywords": [ 19 | "git" 20 | ], 21 | "author": "Robert Jackson ", 22 | "license": "MIT", 23 | "bugs": { 24 | "url": "https://github.com/rwjblue/git-repo-info/issues" 25 | }, 26 | "homepage": "https://github.com/rwjblue/git-repo-info", 27 | "devDependencies": { 28 | "mocha": "^4.1.0", 29 | "mocha-jshint": "^2.3.1" 30 | }, 31 | "engines": { 32 | "node": ">= 4.0" 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /tests/.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "predef": [ 3 | "console", 4 | "it", 5 | "describe", 6 | "beforeEach", 7 | "afterEach", 8 | "before", 9 | "after", 10 | "-Promise" 11 | ], 12 | "expr": true, 13 | "proto": true, 14 | "strict": true, 15 | "indent": 2, 16 | "camelcase": true, 17 | "node": true, 18 | "browser": false, 19 | "boss": true, 20 | "curly": true, 21 | "latedef": "nofunc", 22 | "debug": false, 23 | "devel": false, 24 | "eqeqeq": true, 25 | "evil": true, 26 | "forin": false, 27 | "immed": false, 28 | "laxbreak": false, 29 | "newcap": true, 30 | "noarg": true, 31 | "noempty": false, 32 | "quotmark": true, 33 | "nonew": false, 34 | "nomen": false, 35 | "onevar": false, 36 | "plusplus": false, 37 | "regexp": false, 38 | "undef": true, 39 | "unused": true, 40 | "sub": true, 41 | "trailing": true, 42 | "white": false, 43 | "eqnull": true, 44 | "esnext": true 45 | } 46 | -------------------------------------------------------------------------------- /tests/fixtures/branch-with-slashes/dot-git/HEAD: -------------------------------------------------------------------------------- 1 | ref: refs/heads/feature/branch/with/slashes 2 | -------------------------------------------------------------------------------- /tests/fixtures/branch-with-slashes/dot-git/refs/heads/feature/branch/with/slashes: -------------------------------------------------------------------------------- 1 | 5359aabd3872d9ffd160712e9615c5592dfe6745 2 | -------------------------------------------------------------------------------- /tests/fixtures/branch-with-slashes/dot-git/refs/heads/master: -------------------------------------------------------------------------------- 1 | 5359aabd3872d9ffd160712e9615c5592dfe6745 2 | -------------------------------------------------------------------------------- /tests/fixtures/commit-packed/dot-git/HEAD: -------------------------------------------------------------------------------- 1 | ref: refs/heads/develop 2 | -------------------------------------------------------------------------------- /tests/fixtures/commit-packed/dot-git/packed-refs: -------------------------------------------------------------------------------- 1 | 5359aabd3872d9ffd160712e9615c5592dfe6745 refs/remotes/origin/master 2 | d670460b4b4aece5915caf5c68d12f560a9fe3e4 refs/heads/develop 3 | c76753aa8651471fe082a3ecd0790ec54f5ec673 refs/tags/v1.0.0 4 | 5359aabd3872d9ffd160712e9615c5592dfe6745 refs/tags/my-tag 5 | 6f2abfab299ad8e302f3a3023f88483f4be3b402 refs/tags/v1.0.1 6 | -------------------------------------------------------------------------------- /tests/fixtures/detached-head/dot-git/HEAD: -------------------------------------------------------------------------------- 1 | 9dac893d5a83c02344d91e79dad8904889aeacb1 2 | -------------------------------------------------------------------------------- /tests/fixtures/linked-worktree/dot-git/HEAD: -------------------------------------------------------------------------------- 1 | 9dac893d5a83c02344d91e79dad8904889aeacb1 2 | -------------------------------------------------------------------------------- /tests/fixtures/linked-worktree/dot-git/worktrees/linked/HEAD: -------------------------------------------------------------------------------- 1 | 409372f3bd07c11bfacee3963f48571d675268d7 2 | -------------------------------------------------------------------------------- /tests/fixtures/linked-worktree/dot-git/worktrees/linked/commondir: -------------------------------------------------------------------------------- 1 | ../.. 2 | -------------------------------------------------------------------------------- /tests/fixtures/linked-worktree/linked/dot-git: -------------------------------------------------------------------------------- 1 | gitdir: ../dot-git/worktrees/linked 2 | -------------------------------------------------------------------------------- /tests/fixtures/nested-repo/dot-git/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rwjblue/git-repo-info/189fe90639c83b03f6f701ac88e642b7237861db/tests/fixtures/nested-repo/dot-git/.gitkeep -------------------------------------------------------------------------------- /tests/fixtures/nested-repo/dot-git/HEAD: -------------------------------------------------------------------------------- 1 | ref: refs/heads/master 2 | -------------------------------------------------------------------------------- /tests/fixtures/nested-repo/dot-git/refs/heads/master: -------------------------------------------------------------------------------- 1 | 5359aabd3872d9ffd160712e9615c5592dfe6745 2 | -------------------------------------------------------------------------------- /tests/fixtures/nested-repo/foo/bar/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rwjblue/git-repo-info/189fe90639c83b03f6f701ac88e642b7237861db/tests/fixtures/nested-repo/foo/bar/.gitkeep -------------------------------------------------------------------------------- /tests/fixtures/submodule/dot-git/HEAD: -------------------------------------------------------------------------------- 1 | 9dac893d5a83c02344d91e79dad8904889aeacb1 2 | -------------------------------------------------------------------------------- /tests/fixtures/submodule/dot-git/modules/my-submodule/HEAD: -------------------------------------------------------------------------------- 1 | 409372f3bd07c11bfacee3963f48571d675268d7 2 | -------------------------------------------------------------------------------- /tests/fixtures/submodule/my-submodule/dot-git: -------------------------------------------------------------------------------- 1 | gitdir: ../dot-git/modules/my-submodule 2 | -------------------------------------------------------------------------------- /tests/fixtures/tag-on-parent-before-merge/dot-git/HEAD: -------------------------------------------------------------------------------- 1 | ref: refs/heads/master 2 | -------------------------------------------------------------------------------- /tests/fixtures/tag-on-parent-before-merge/dot-git/index: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rwjblue/git-repo-info/189fe90639c83b03f6f701ac88e642b7237861db/tests/fixtures/tag-on-parent-before-merge/dot-git/index -------------------------------------------------------------------------------- /tests/fixtures/tag-on-parent-before-merge/dot-git/objects/b6/0d665ae0978a7b46e2447f4c13d7909997f56c: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rwjblue/git-repo-info/189fe90639c83b03f6f701ac88e642b7237861db/tests/fixtures/tag-on-parent-before-merge/dot-git/objects/b6/0d665ae0978a7b46e2447f4c13d7909997f56c -------------------------------------------------------------------------------- /tests/fixtures/tag-on-parent-before-merge/dot-git/refs/heads/master: -------------------------------------------------------------------------------- 1 | b60d665ae0978a7b46e2447f4c13d7909997f56c 2 | -------------------------------------------------------------------------------- /tests/fixtures/tag-on-parent-before-merge/dot-git/refs/tags/magic-tag: -------------------------------------------------------------------------------- 1 | 4f5c726a1528fdfb1ec7c9537e4b1b2dbaacbcc4 2 | -------------------------------------------------------------------------------- /tests/fixtures/tag-on-parent/dot-git/HEAD: -------------------------------------------------------------------------------- 1 | ref: refs/heads/master 2 | -------------------------------------------------------------------------------- /tests/fixtures/tag-on-parent/dot-git/index: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rwjblue/git-repo-info/189fe90639c83b03f6f701ac88e642b7237861db/tests/fixtures/tag-on-parent/dot-git/index -------------------------------------------------------------------------------- /tests/fixtures/tag-on-parent/dot-git/objects/fb/26504da0ed5cd9ed366f7428c06a8433fd76e6: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rwjblue/git-repo-info/189fe90639c83b03f6f701ac88e642b7237861db/tests/fixtures/tag-on-parent/dot-git/objects/fb/26504da0ed5cd9ed366f7428c06a8433fd76e6 -------------------------------------------------------------------------------- /tests/fixtures/tag-on-parent/dot-git/refs/heads/master: -------------------------------------------------------------------------------- 1 | fb26504da0ed5cd9ed366f7428c06a8433fd76e6 2 | -------------------------------------------------------------------------------- /tests/fixtures/tag-on-parent/dot-git/refs/tags/parent-magic-tag: -------------------------------------------------------------------------------- 1 | e66f7ec2da3b5d06f0fe845c4fbc87247efacf62 2 | -------------------------------------------------------------------------------- /tests/fixtures/tagged-annotated/dot-git/COMMIT_EDITMSG: -------------------------------------------------------------------------------- 1 | Initial commit. 2 | # Please enter the commit message for your changes. Lines starting 3 | # with '#' will be ignored, and an empty message aborts the commit. 4 | # On branch master 5 | # 6 | # Initial commit 7 | # 8 | # Changes to be committed: 9 | # new file: README 10 | # 11 | # ------------------------ >8 ------------------------ 12 | # Do not touch the line above. 13 | # Everything below will be removed. 14 | diff --git a/README b/README 15 | new file mode 100644 16 | index 0000000..e69de29 17 | -------------------------------------------------------------------------------- /tests/fixtures/tagged-annotated/dot-git/HEAD: -------------------------------------------------------------------------------- 1 | ref: refs/heads/master 2 | -------------------------------------------------------------------------------- /tests/fixtures/tagged-annotated/dot-git/config: -------------------------------------------------------------------------------- 1 | [core] 2 | repositoryformatversion = 0 3 | filemode = true 4 | bare = false 5 | logallrefupdates = true 6 | ignorecase = true 7 | precomposeunicode = true 8 | -------------------------------------------------------------------------------- /tests/fixtures/tagged-annotated/dot-git/description: -------------------------------------------------------------------------------- 1 | Unnamed repository; edit this file 'description' to name the repository. 2 | -------------------------------------------------------------------------------- /tests/fixtures/tagged-annotated/dot-git/hooks/applypatch-msg.sample: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # An example hook script to check the commit log message taken by 4 | # applypatch from an e-mail message. 5 | # 6 | # The hook should exit with non-zero status after issuing an 7 | # appropriate message if it wants to stop the commit. The hook is 8 | # allowed to edit the commit message file. 9 | # 10 | # To enable this hook, rename this file to "applypatch-msg". 11 | 12 | . git-sh-setup 13 | test -x "$GIT_DIR/hooks/commit-msg" && 14 | exec "$GIT_DIR/hooks/commit-msg" ${1+"$@"} 15 | : 16 | -------------------------------------------------------------------------------- /tests/fixtures/tagged-annotated/dot-git/hooks/commit-msg.sample: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # An example hook script to check the commit log message. 4 | # Called by "git commit" with one argument, the name of the file 5 | # that has the commit message. The hook should exit with non-zero 6 | # status after issuing an appropriate message if it wants to stop the 7 | # commit. The hook is allowed to edit the commit message file. 8 | # 9 | # To enable this hook, rename this file to "commit-msg". 10 | 11 | # Uncomment the below to add a Signed-off-by line to the message. 12 | # Doing this in a hook is a bad idea in general, but the prepare-commit-msg 13 | # hook is more suited to it. 14 | # 15 | # SOB=$(git var GIT_AUTHOR_IDENT | sed -n 's/^\(.*>\).*$/Signed-off-by: \1/p') 16 | # grep -qs "^$SOB" "$1" || echo "$SOB" >> "$1" 17 | 18 | # This example catches duplicate Signed-off-by lines. 19 | 20 | test "" = "$(grep '^Signed-off-by: ' "$1" | 21 | sort | uniq -c | sed -e '/^[ ]*1[ ]/d')" || { 22 | echo >&2 Duplicate Signed-off-by lines. 23 | exit 1 24 | } 25 | -------------------------------------------------------------------------------- /tests/fixtures/tagged-annotated/dot-git/hooks/post-update.sample: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # An example hook script to prepare a packed repository for use over 4 | # dumb transports. 5 | # 6 | # To enable this hook, rename this file to "post-update". 7 | 8 | exec git update-server-info 9 | -------------------------------------------------------------------------------- /tests/fixtures/tagged-annotated/dot-git/hooks/pre-applypatch.sample: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # An example hook script to verify what is about to be committed 4 | # by applypatch from an e-mail message. 5 | # 6 | # The hook should exit with non-zero status after issuing an 7 | # appropriate message if it wants to stop the commit. 8 | # 9 | # To enable this hook, rename this file to "pre-applypatch". 10 | 11 | . git-sh-setup 12 | test -x "$GIT_DIR/hooks/pre-commit" && 13 | exec "$GIT_DIR/hooks/pre-commit" ${1+"$@"} 14 | : 15 | -------------------------------------------------------------------------------- /tests/fixtures/tagged-annotated/dot-git/hooks/pre-commit.sample: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # An example hook script to verify what is about to be committed. 4 | # Called by "git commit" with no arguments. The hook should 5 | # exit with non-zero status after issuing an appropriate message if 6 | # it wants to stop the commit. 7 | # 8 | # To enable this hook, rename this file to "pre-commit". 9 | 10 | if git rev-parse --verify HEAD >/dev/null 2>&1 11 | then 12 | against=HEAD 13 | else 14 | # Initial commit: diff against an empty tree object 15 | against=4b825dc642cb6eb9a060e54bf8d69288fbee4904 16 | fi 17 | 18 | # If you want to allow non-ASCII filenames set this variable to true. 19 | allownonascii=$(git config --bool hooks.allownonascii) 20 | 21 | # Redirect output to stderr. 22 | exec 1>&2 23 | 24 | # Cross platform projects tend to avoid non-ASCII filenames; prevent 25 | # them from being added to the repository. We exploit the fact that the 26 | # printable range starts at the space character and ends with tilde. 27 | if [ "$allownonascii" != "true" ] && 28 | # Note that the use of brackets around a tr range is ok here, (it's 29 | # even required, for portability to Solaris 10's /usr/bin/tr), since 30 | # the square bracket bytes happen to fall in the designated range. 31 | test $(git diff --cached --name-only --diff-filter=A -z $against | 32 | LC_ALL=C tr -d '[ -~]\0' | wc -c) != 0 33 | then 34 | cat <<\EOF 35 | Error: Attempt to add a non-ASCII file name. 36 | 37 | This can cause problems if you want to work with people on other platforms. 38 | 39 | To be portable it is advisable to rename the file. 40 | 41 | If you know what you are doing you can disable this check using: 42 | 43 | git config hooks.allownonascii true 44 | EOF 45 | exit 1 46 | fi 47 | 48 | # If there are whitespace errors, print the offending file names and fail. 49 | exec git diff-index --check --cached $against -- 50 | -------------------------------------------------------------------------------- /tests/fixtures/tagged-annotated/dot-git/hooks/pre-push.sample: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # An example hook script to verify what is about to be pushed. Called by "git 4 | # push" after it has checked the remote status, but before anything has been 5 | # pushed. If this script exits with a non-zero status nothing will be pushed. 6 | # 7 | # This hook is called with the following parameters: 8 | # 9 | # $1 -- Name of the remote to which the push is being done 10 | # $2 -- URL to which the push is being done 11 | # 12 | # If pushing without using a named remote those arguments will be equal. 13 | # 14 | # Information about the commits which are being pushed is supplied as lines to 15 | # the standard input in the form: 16 | # 17 | # 18 | # 19 | # This sample shows how to prevent push of commits where the log message starts 20 | # with "WIP" (work in progress). 21 | 22 | remote="$1" 23 | url="$2" 24 | 25 | z40=0000000000000000000000000000000000000000 26 | 27 | while read local_ref local_sha remote_ref remote_sha 28 | do 29 | if [ "$local_sha" = $z40 ] 30 | then 31 | # Handle delete 32 | : 33 | else 34 | if [ "$remote_sha" = $z40 ] 35 | then 36 | # New branch, examine all commits 37 | range="$local_sha" 38 | else 39 | # Update to existing branch, examine new commits 40 | range="$remote_sha..$local_sha" 41 | fi 42 | 43 | # Check for WIP commit 44 | commit=`git rev-list -n 1 --grep '^WIP' "$range"` 45 | if [ -n "$commit" ] 46 | then 47 | echo >&2 "Found WIP commit in $local_ref, not pushing" 48 | exit 1 49 | fi 50 | fi 51 | done 52 | 53 | exit 0 54 | -------------------------------------------------------------------------------- /tests/fixtures/tagged-annotated/dot-git/hooks/pre-rebase.sample: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # Copyright (c) 2006, 2008 Junio C Hamano 4 | # 5 | # The "pre-rebase" hook is run just before "git rebase" starts doing 6 | # its job, and can prevent the command from running by exiting with 7 | # non-zero status. 8 | # 9 | # The hook is called with the following parameters: 10 | # 11 | # $1 -- the upstream the series was forked from. 12 | # $2 -- the branch being rebased (or empty when rebasing the current branch). 13 | # 14 | # This sample shows how to prevent topic branches that are already 15 | # merged to 'next' branch from getting rebased, because allowing it 16 | # would result in rebasing already published history. 17 | 18 | publish=next 19 | basebranch="$1" 20 | if test "$#" = 2 21 | then 22 | topic="refs/heads/$2" 23 | else 24 | topic=`git symbolic-ref HEAD` || 25 | exit 0 ;# we do not interrupt rebasing detached HEAD 26 | fi 27 | 28 | case "$topic" in 29 | refs/heads/??/*) 30 | ;; 31 | *) 32 | exit 0 ;# we do not interrupt others. 33 | ;; 34 | esac 35 | 36 | # Now we are dealing with a topic branch being rebased 37 | # on top of master. Is it OK to rebase it? 38 | 39 | # Does the topic really exist? 40 | git show-ref -q "$topic" || { 41 | echo >&2 "No such branch $topic" 42 | exit 1 43 | } 44 | 45 | # Is topic fully merged to master? 46 | not_in_master=`git rev-list --pretty=oneline ^master "$topic"` 47 | if test -z "$not_in_master" 48 | then 49 | echo >&2 "$topic is fully merged to master; better remove it." 50 | exit 1 ;# we could allow it, but there is no point. 51 | fi 52 | 53 | # Is topic ever merged to next? If so you should not be rebasing it. 54 | only_next_1=`git rev-list ^master "^$topic" ${publish} | sort` 55 | only_next_2=`git rev-list ^master ${publish} | sort` 56 | if test "$only_next_1" = "$only_next_2" 57 | then 58 | not_in_topic=`git rev-list "^$topic" master` 59 | if test -z "$not_in_topic" 60 | then 61 | echo >&2 "$topic is already up-to-date with master" 62 | exit 1 ;# we could allow it, but there is no point. 63 | else 64 | exit 0 65 | fi 66 | else 67 | not_in_next=`git rev-list --pretty=oneline ^${publish} "$topic"` 68 | /usr/bin/perl -e ' 69 | my $topic = $ARGV[0]; 70 | my $msg = "* $topic has commits already merged to public branch:\n"; 71 | my (%not_in_next) = map { 72 | /^([0-9a-f]+) /; 73 | ($1 => 1); 74 | } split(/\n/, $ARGV[1]); 75 | for my $elem (map { 76 | /^([0-9a-f]+) (.*)$/; 77 | [$1 => $2]; 78 | } split(/\n/, $ARGV[2])) { 79 | if (!exists $not_in_next{$elem->[0]}) { 80 | if ($msg) { 81 | print STDERR $msg; 82 | undef $msg; 83 | } 84 | print STDERR " $elem->[1]\n"; 85 | } 86 | } 87 | ' "$topic" "$not_in_next" "$not_in_master" 88 | exit 1 89 | fi 90 | 91 | exit 0 92 | 93 | ################################################################ 94 | 95 | This sample hook safeguards topic branches that have been 96 | published from being rewound. 97 | 98 | The workflow assumed here is: 99 | 100 | * Once a topic branch forks from "master", "master" is never 101 | merged into it again (either directly or indirectly). 102 | 103 | * Once a topic branch is fully cooked and merged into "master", 104 | it is deleted. If you need to build on top of it to correct 105 | earlier mistakes, a new topic branch is created by forking at 106 | the tip of the "master". This is not strictly necessary, but 107 | it makes it easier to keep your history simple. 108 | 109 | * Whenever you need to test or publish your changes to topic 110 | branches, merge them into "next" branch. 111 | 112 | The script, being an example, hardcodes the publish branch name 113 | to be "next", but it is trivial to make it configurable via 114 | $GIT_DIR/config mechanism. 115 | 116 | With this workflow, you would want to know: 117 | 118 | (1) ... if a topic branch has ever been merged to "next". Young 119 | topic branches can have stupid mistakes you would rather 120 | clean up before publishing, and things that have not been 121 | merged into other branches can be easily rebased without 122 | affecting other people. But once it is published, you would 123 | not want to rewind it. 124 | 125 | (2) ... if a topic branch has been fully merged to "master". 126 | Then you can delete it. More importantly, you should not 127 | build on top of it -- other people may already want to 128 | change things related to the topic as patches against your 129 | "master", so if you need further changes, it is better to 130 | fork the topic (perhaps with the same name) afresh from the 131 | tip of "master". 132 | 133 | Let's look at this example: 134 | 135 | o---o---o---o---o---o---o---o---o---o "next" 136 | / / / / 137 | / a---a---b A / / 138 | / / / / 139 | / / c---c---c---c B / 140 | / / / \ / 141 | / / / b---b C \ / 142 | / / / / \ / 143 | ---o---o---o---o---o---o---o---o---o---o---o "master" 144 | 145 | 146 | A, B and C are topic branches. 147 | 148 | * A has one fix since it was merged up to "next". 149 | 150 | * B has finished. It has been fully merged up to "master" and "next", 151 | and is ready to be deleted. 152 | 153 | * C has not merged to "next" at all. 154 | 155 | We would want to allow C to be rebased, refuse A, and encourage 156 | B to be deleted. 157 | 158 | To compute (1): 159 | 160 | git rev-list ^master ^topic next 161 | git rev-list ^master next 162 | 163 | if these match, topic has not merged in next at all. 164 | 165 | To compute (2): 166 | 167 | git rev-list master..topic 168 | 169 | if this is empty, it is fully merged to "master". 170 | -------------------------------------------------------------------------------- /tests/fixtures/tagged-annotated/dot-git/hooks/prepare-commit-msg.sample: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # An example hook script to prepare the commit log message. 4 | # Called by "git commit" with the name of the file that has the 5 | # commit message, followed by the description of the commit 6 | # message's source. The hook's purpose is to edit the commit 7 | # message file. If the hook fails with a non-zero status, 8 | # the commit is aborted. 9 | # 10 | # To enable this hook, rename this file to "prepare-commit-msg". 11 | 12 | # This hook includes three examples. The first comments out the 13 | # "Conflicts:" part of a merge commit. 14 | # 15 | # The second includes the output of "git diff --name-status -r" 16 | # into the message, just before the "git status" output. It is 17 | # commented because it doesn't cope with --amend or with squashed 18 | # commits. 19 | # 20 | # The third example adds a Signed-off-by line to the message, that can 21 | # still be edited. This is rarely a good idea. 22 | 23 | case "$2,$3" in 24 | merge,) 25 | /usr/bin/perl -i.bak -ne 's/^/# /, s/^# #/#/ if /^Conflicts/ .. /#/; print' "$1" ;; 26 | 27 | # ,|template,) 28 | # /usr/bin/perl -i.bak -pe ' 29 | # print "\n" . `git diff --cached --name-status -r` 30 | # if /^#/ && $first++ == 0' "$1" ;; 31 | 32 | *) ;; 33 | esac 34 | 35 | # SOB=$(git var GIT_AUTHOR_IDENT | sed -n 's/^\(.*>\).*$/Signed-off-by: \1/p') 36 | # grep -qs "^$SOB" "$1" || echo "$SOB" >> "$1" 37 | -------------------------------------------------------------------------------- /tests/fixtures/tagged-annotated/dot-git/hooks/update.sample: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # An example hook script to blocks unannotated tags from entering. 4 | # Called by "git receive-pack" with arguments: refname sha1-old sha1-new 5 | # 6 | # To enable this hook, rename this file to "update". 7 | # 8 | # Config 9 | # ------ 10 | # hooks.allowunannotated 11 | # This boolean sets whether unannotated tags will be allowed into the 12 | # repository. By default they won't be. 13 | # hooks.allowdeletetag 14 | # This boolean sets whether deleting tags will be allowed in the 15 | # repository. By default they won't be. 16 | # hooks.allowmodifytag 17 | # This boolean sets whether a tag may be modified after creation. By default 18 | # it won't be. 19 | # hooks.allowdeletebranch 20 | # This boolean sets whether deleting branches will be allowed in the 21 | # repository. By default they won't be. 22 | # hooks.denycreatebranch 23 | # This boolean sets whether remotely creating branches will be denied 24 | # in the repository. By default this is allowed. 25 | # 26 | 27 | # --- Command line 28 | refname="$1" 29 | oldrev="$2" 30 | newrev="$3" 31 | 32 | # --- Safety check 33 | if [ -z "$GIT_DIR" ]; then 34 | echo "Don't run this script from the command line." >&2 35 | echo " (if you want, you could supply GIT_DIR then run" >&2 36 | echo " $0 )" >&2 37 | exit 1 38 | fi 39 | 40 | if [ -z "$refname" -o -z "$oldrev" -o -z "$newrev" ]; then 41 | echo "usage: $0 " >&2 42 | exit 1 43 | fi 44 | 45 | # --- Config 46 | allowunannotated=$(git config --bool hooks.allowunannotated) 47 | allowdeletebranch=$(git config --bool hooks.allowdeletebranch) 48 | denycreatebranch=$(git config --bool hooks.denycreatebranch) 49 | allowdeletetag=$(git config --bool hooks.allowdeletetag) 50 | allowmodifytag=$(git config --bool hooks.allowmodifytag) 51 | 52 | # check for no description 53 | projectdesc=$(sed -e '1q' "$GIT_DIR/description") 54 | case "$projectdesc" in 55 | "Unnamed repository"* | "") 56 | echo "*** Project description file hasn't been set" >&2 57 | exit 1 58 | ;; 59 | esac 60 | 61 | # --- Check types 62 | # if $newrev is 0000...0000, it's a commit to delete a ref. 63 | zero="0000000000000000000000000000000000000000" 64 | if [ "$newrev" = "$zero" ]; then 65 | newrev_type=delete 66 | else 67 | newrev_type=$(git cat-file -t $newrev) 68 | fi 69 | 70 | case "$refname","$newrev_type" in 71 | refs/tags/*,commit) 72 | # un-annotated tag 73 | short_refname=${refname##refs/tags/} 74 | if [ "$allowunannotated" != "true" ]; then 75 | echo "*** The un-annotated tag, $short_refname, is not allowed in this repository" >&2 76 | echo "*** Use 'git tag [ -a | -s ]' for tags you want to propagate." >&2 77 | exit 1 78 | fi 79 | ;; 80 | refs/tags/*,delete) 81 | # delete tag 82 | if [ "$allowdeletetag" != "true" ]; then 83 | echo "*** Deleting a tag is not allowed in this repository" >&2 84 | exit 1 85 | fi 86 | ;; 87 | refs/tags/*,tag) 88 | # annotated tag 89 | if [ "$allowmodifytag" != "true" ] && git rev-parse $refname > /dev/null 2>&1 90 | then 91 | echo "*** Tag '$refname' already exists." >&2 92 | echo "*** Modifying a tag is not allowed in this repository." >&2 93 | exit 1 94 | fi 95 | ;; 96 | refs/heads/*,commit) 97 | # branch 98 | if [ "$oldrev" = "$zero" -a "$denycreatebranch" = "true" ]; then 99 | echo "*** Creating a branch is not allowed in this repository" >&2 100 | exit 1 101 | fi 102 | ;; 103 | refs/heads/*,delete) 104 | # delete branch 105 | if [ "$allowdeletebranch" != "true" ]; then 106 | echo "*** Deleting a branch is not allowed in this repository" >&2 107 | exit 1 108 | fi 109 | ;; 110 | refs/remotes/*,commit) 111 | # tracking branch 112 | ;; 113 | refs/remotes/*,delete) 114 | # delete tracking branch 115 | if [ "$allowdeletebranch" != "true" ]; then 116 | echo "*** Deleting a tracking branch is not allowed in this repository" >&2 117 | exit 1 118 | fi 119 | ;; 120 | *) 121 | # Anything else (is there anything else?) 122 | echo "*** Update hook: unknown type of update to ref $refname of type $newrev_type" >&2 123 | exit 1 124 | ;; 125 | esac 126 | 127 | # --- Finished 128 | exit 0 129 | -------------------------------------------------------------------------------- /tests/fixtures/tagged-annotated/dot-git/index: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rwjblue/git-repo-info/189fe90639c83b03f6f701ac88e642b7237861db/tests/fixtures/tagged-annotated/dot-git/index -------------------------------------------------------------------------------- /tests/fixtures/tagged-annotated/dot-git/info/exclude: -------------------------------------------------------------------------------- 1 | # git ls-files --others --exclude-from=.git/info/exclude 2 | # Lines that start with '#' are comments. 3 | # For a project mostly in C, the following would be a good set of 4 | # exclude patterns (uncomment them if you want to use them): 5 | # *.[oa] 6 | # *~ 7 | -------------------------------------------------------------------------------- /tests/fixtures/tagged-annotated/dot-git/logs/HEAD: -------------------------------------------------------------------------------- 1 | 0000000000000000000000000000000000000000 c1ee41c325d54f410b133e0018c7a6b1316f6cda Robert Jackson 1429099806 -0400 commit (initial): Initial commit. 2 | -------------------------------------------------------------------------------- /tests/fixtures/tagged-annotated/dot-git/logs/refs/heads/master: -------------------------------------------------------------------------------- 1 | 0000000000000000000000000000000000000000 c1ee41c325d54f410b133e0018c7a6b1316f6cda Robert Jackson 1429099806 -0400 commit (initial): Initial commit. 2 | -------------------------------------------------------------------------------- /tests/fixtures/tagged-annotated/dot-git/objects/54/3b9bebdc6bd5c4b22136034a95dd097a57d3dd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rwjblue/git-repo-info/189fe90639c83b03f6f701ac88e642b7237861db/tests/fixtures/tagged-annotated/dot-git/objects/54/3b9bebdc6bd5c4b22136034a95dd097a57d3dd -------------------------------------------------------------------------------- /tests/fixtures/tagged-annotated/dot-git/objects/c1/ee41c325d54f410b133e0018c7a6b1316f6cda: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rwjblue/git-repo-info/189fe90639c83b03f6f701ac88e642b7237861db/tests/fixtures/tagged-annotated/dot-git/objects/c1/ee41c325d54f410b133e0018c7a6b1316f6cda -------------------------------------------------------------------------------- /tests/fixtures/tagged-annotated/dot-git/objects/d3/4ef562c5d670f49b5fdd85b633c469c71f0456: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rwjblue/git-repo-info/189fe90639c83b03f6f701ac88e642b7237861db/tests/fixtures/tagged-annotated/dot-git/objects/d3/4ef562c5d670f49b5fdd85b633c469c71f0456 -------------------------------------------------------------------------------- /tests/fixtures/tagged-annotated/dot-git/objects/e6/9de29bb2d1d6434b8b29ae775ad8c2e48c5391: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rwjblue/git-repo-info/189fe90639c83b03f6f701ac88e642b7237861db/tests/fixtures/tagged-annotated/dot-git/objects/e6/9de29bb2d1d6434b8b29ae775ad8c2e48c5391 -------------------------------------------------------------------------------- /tests/fixtures/tagged-annotated/dot-git/refs/heads/master: -------------------------------------------------------------------------------- 1 | c1ee41c325d54f410b133e0018c7a6b1316f6cda 2 | -------------------------------------------------------------------------------- /tests/fixtures/tagged-annotated/dot-git/refs/tags/awesome-tag: -------------------------------------------------------------------------------- 1 | d34ef562c5d670f49b5fdd85b633c469c71f0456 2 | -------------------------------------------------------------------------------- /tests/fixtures/tagged-commit-mixed-packing/dot-git/HEAD: -------------------------------------------------------------------------------- 1 | ref: refs/heads/master 2 | -------------------------------------------------------------------------------- /tests/fixtures/tagged-commit-mixed-packing/dot-git/objects/37/ece7ad9ded5f2312bb6be8d0c21ecebca088ac: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rwjblue/git-repo-info/189fe90639c83b03f6f701ac88e642b7237861db/tests/fixtures/tagged-commit-mixed-packing/dot-git/objects/37/ece7ad9ded5f2312bb6be8d0c21ecebca088ac -------------------------------------------------------------------------------- /tests/fixtures/tagged-commit-mixed-packing/dot-git/objects/90/4de697a2c441e3db28f5c531ccfdab5f4435e3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rwjblue/git-repo-info/189fe90639c83b03f6f701ac88e642b7237861db/tests/fixtures/tagged-commit-mixed-packing/dot-git/objects/90/4de697a2c441e3db28f5c531ccfdab5f4435e3 -------------------------------------------------------------------------------- /tests/fixtures/tagged-commit-mixed-packing/dot-git/objects/95/0a188f0a4224ce6a1ac710915113df972aeb2c: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rwjblue/git-repo-info/189fe90639c83b03f6f701ac88e642b7237861db/tests/fixtures/tagged-commit-mixed-packing/dot-git/objects/95/0a188f0a4224ce6a1ac710915113df972aeb2c -------------------------------------------------------------------------------- /tests/fixtures/tagged-commit-mixed-packing/dot-git/objects/e1/b209796f8918bf7ce1f00be1ea1923f5801339: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rwjblue/git-repo-info/189fe90639c83b03f6f701ac88e642b7237861db/tests/fixtures/tagged-commit-mixed-packing/dot-git/objects/e1/b209796f8918bf7ce1f00be1ea1923f5801339 -------------------------------------------------------------------------------- /tests/fixtures/tagged-commit-mixed-packing/dot-git/packed-refs: -------------------------------------------------------------------------------- 1 | 37ece7ad9ded5f2312bb6be8d0c21ecebca088ac refs/tags/b-lightweight-tag 2 | c1ee41c325d54f410b133e0018c7a6b1316f6cda refs/tags/-lightweight-tag -------------------------------------------------------------------------------- /tests/fixtures/tagged-commit-mixed-packing/dot-git/refs/heads/master: -------------------------------------------------------------------------------- 1 | 37ece7ad9ded5f2312bb6be8d0c21ecebca088ac 2 | -------------------------------------------------------------------------------- /tests/fixtures/tagged-commit-mixed-packing/dot-git/refs/tags/--lightweight-tag: -------------------------------------------------------------------------------- 1 | c1ee41c325d54f410b133e0018c7a6b1316f6cda -------------------------------------------------------------------------------- /tests/fixtures/tagged-commit-mixed-packing/dot-git/refs/tags/0-lightweight-tag: -------------------------------------------------------------------------------- 1 | 37ece7ad9ded5f2312bb6be8d0c21ecebca088ac 2 | -------------------------------------------------------------------------------- /tests/fixtures/tagged-commit-mixed-packing/dot-git/refs/tags/e-annotated-tag: -------------------------------------------------------------------------------- 1 | 904de697a2c441e3db28f5c531ccfdab5f4435e3 2 | -------------------------------------------------------------------------------- /tests/fixtures/tagged-commit-packed-annotated/dot-git/HEAD: -------------------------------------------------------------------------------- 1 | ref: refs/heads/master 2 | -------------------------------------------------------------------------------- /tests/fixtures/tagged-commit-packed-annotated/dot-git/packed-refs: -------------------------------------------------------------------------------- 1 | 5359aabd3872d9ffd160712e9615c5592dfe6745 refs/remotes/origin/master 2 | 456d170a0177147cf2f242c91f776037150b3d4b refs/tags/example-annotated-tag 3 | ^5359aabd3872d9ffd160712e9615c5592dfe6745 -------------------------------------------------------------------------------- /tests/fixtures/tagged-commit-packed-annotated/dot-git/refs/heads/master: -------------------------------------------------------------------------------- 1 | 5359aabd3872d9ffd160712e9615c5592dfe6745 2 | -------------------------------------------------------------------------------- /tests/fixtures/tagged-commit-packed/dot-git/HEAD: -------------------------------------------------------------------------------- 1 | ref: refs/heads/master 2 | -------------------------------------------------------------------------------- /tests/fixtures/tagged-commit-packed/dot-git/packed-refs: -------------------------------------------------------------------------------- 1 | 5359aabd3872d9ffd160712e9615c5592dfe6745 refs/remotes/origin/master 2 | c76753aa8651471fe082a3ecd0790ec54f5ec673 refs/tags/v1.0.0 3 | 5359aabd3872d9ffd160712e9615c5592dfe6745 refs/tags/my-tag 4 | 6f2abfab299ad8e302f3a3023f88483f4be3b402 refs/tags/v1.0.1 -------------------------------------------------------------------------------- /tests/fixtures/tagged-commit-packed/dot-git/refs/heads/master: -------------------------------------------------------------------------------- 1 | 5359aabd3872d9ffd160712e9615c5592dfe6745 2 | -------------------------------------------------------------------------------- /tests/fixtures/tagged-commit-unpacked-no-object/dot-git/HEAD: -------------------------------------------------------------------------------- 1 | ref: refs/heads/master 2 | -------------------------------------------------------------------------------- /tests/fixtures/tagged-commit-unpacked-no-object/dot-git/objects/54/3b9bebdc6bd5c4b22136034a95dd097a57d3dd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rwjblue/git-repo-info/189fe90639c83b03f6f701ac88e642b7237861db/tests/fixtures/tagged-commit-unpacked-no-object/dot-git/objects/54/3b9bebdc6bd5c4b22136034a95dd097a57d3dd -------------------------------------------------------------------------------- /tests/fixtures/tagged-commit-unpacked-no-object/dot-git/objects/e6/9de29bb2d1d6434b8b29ae775ad8c2e48c5391: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rwjblue/git-repo-info/189fe90639c83b03f6f701ac88e642b7237861db/tests/fixtures/tagged-commit-unpacked-no-object/dot-git/objects/e6/9de29bb2d1d6434b8b29ae775ad8c2e48c5391 -------------------------------------------------------------------------------- /tests/fixtures/tagged-commit-unpacked-no-object/dot-git/refs/heads/master: -------------------------------------------------------------------------------- 1 | c1ee41c325d54f410b133e0018c7a6b1316f6cda 2 | -------------------------------------------------------------------------------- /tests/fixtures/tagged-commit-unpacked-no-object/dot-git/refs/tags/awesome-tag: -------------------------------------------------------------------------------- 1 | c1ee41c325d54f410b133e0018c7a6b1316f6cda 2 | -------------------------------------------------------------------------------- /tests/fixtures/tagged-commit-unpacked/dot-git/COMMIT_EDITMSG: -------------------------------------------------------------------------------- 1 | Initial commit. 2 | # Please enter the commit message for your changes. Lines starting 3 | # with '#' will be ignored, and an empty message aborts the commit. 4 | # On branch master 5 | # 6 | # Initial commit 7 | # 8 | # Changes to be committed: 9 | # new file: README 10 | # 11 | # ------------------------ >8 ------------------------ 12 | # Do not touch the line above. 13 | # Everything below will be removed. 14 | diff --git a/README b/README 15 | new file mode 100644 16 | index 0000000..e69de29 17 | -------------------------------------------------------------------------------- /tests/fixtures/tagged-commit-unpacked/dot-git/HEAD: -------------------------------------------------------------------------------- 1 | ref: refs/heads/master 2 | -------------------------------------------------------------------------------- /tests/fixtures/tagged-commit-unpacked/dot-git/config: -------------------------------------------------------------------------------- 1 | [core] 2 | repositoryformatversion = 0 3 | filemode = true 4 | bare = false 5 | logallrefupdates = true 6 | ignorecase = true 7 | precomposeunicode = true 8 | -------------------------------------------------------------------------------- /tests/fixtures/tagged-commit-unpacked/dot-git/description: -------------------------------------------------------------------------------- 1 | Unnamed repository; edit this file 'description' to name the repository. 2 | -------------------------------------------------------------------------------- /tests/fixtures/tagged-commit-unpacked/dot-git/hooks/applypatch-msg.sample: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # An example hook script to check the commit log message taken by 4 | # applypatch from an e-mail message. 5 | # 6 | # The hook should exit with non-zero status after issuing an 7 | # appropriate message if it wants to stop the commit. The hook is 8 | # allowed to edit the commit message file. 9 | # 10 | # To enable this hook, rename this file to "applypatch-msg". 11 | 12 | . git-sh-setup 13 | test -x "$GIT_DIR/hooks/commit-msg" && 14 | exec "$GIT_DIR/hooks/commit-msg" ${1+"$@"} 15 | : 16 | -------------------------------------------------------------------------------- /tests/fixtures/tagged-commit-unpacked/dot-git/hooks/commit-msg.sample: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # An example hook script to check the commit log message. 4 | # Called by "git commit" with one argument, the name of the file 5 | # that has the commit message. The hook should exit with non-zero 6 | # status after issuing an appropriate message if it wants to stop the 7 | # commit. The hook is allowed to edit the commit message file. 8 | # 9 | # To enable this hook, rename this file to "commit-msg". 10 | 11 | # Uncomment the below to add a Signed-off-by line to the message. 12 | # Doing this in a hook is a bad idea in general, but the prepare-commit-msg 13 | # hook is more suited to it. 14 | # 15 | # SOB=$(git var GIT_AUTHOR_IDENT | sed -n 's/^\(.*>\).*$/Signed-off-by: \1/p') 16 | # grep -qs "^$SOB" "$1" || echo "$SOB" >> "$1" 17 | 18 | # This example catches duplicate Signed-off-by lines. 19 | 20 | test "" = "$(grep '^Signed-off-by: ' "$1" | 21 | sort | uniq -c | sed -e '/^[ ]*1[ ]/d')" || { 22 | echo >&2 Duplicate Signed-off-by lines. 23 | exit 1 24 | } 25 | -------------------------------------------------------------------------------- /tests/fixtures/tagged-commit-unpacked/dot-git/hooks/post-update.sample: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # An example hook script to prepare a packed repository for use over 4 | # dumb transports. 5 | # 6 | # To enable this hook, rename this file to "post-update". 7 | 8 | exec git update-server-info 9 | -------------------------------------------------------------------------------- /tests/fixtures/tagged-commit-unpacked/dot-git/hooks/pre-applypatch.sample: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # An example hook script to verify what is about to be committed 4 | # by applypatch from an e-mail message. 5 | # 6 | # The hook should exit with non-zero status after issuing an 7 | # appropriate message if it wants to stop the commit. 8 | # 9 | # To enable this hook, rename this file to "pre-applypatch". 10 | 11 | . git-sh-setup 12 | test -x "$GIT_DIR/hooks/pre-commit" && 13 | exec "$GIT_DIR/hooks/pre-commit" ${1+"$@"} 14 | : 15 | -------------------------------------------------------------------------------- /tests/fixtures/tagged-commit-unpacked/dot-git/hooks/pre-commit.sample: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # An example hook script to verify what is about to be committed. 4 | # Called by "git commit" with no arguments. The hook should 5 | # exit with non-zero status after issuing an appropriate message if 6 | # it wants to stop the commit. 7 | # 8 | # To enable this hook, rename this file to "pre-commit". 9 | 10 | if git rev-parse --verify HEAD >/dev/null 2>&1 11 | then 12 | against=HEAD 13 | else 14 | # Initial commit: diff against an empty tree object 15 | against=4b825dc642cb6eb9a060e54bf8d69288fbee4904 16 | fi 17 | 18 | # If you want to allow non-ASCII filenames set this variable to true. 19 | allownonascii=$(git config --bool hooks.allownonascii) 20 | 21 | # Redirect output to stderr. 22 | exec 1>&2 23 | 24 | # Cross platform projects tend to avoid non-ASCII filenames; prevent 25 | # them from being added to the repository. We exploit the fact that the 26 | # printable range starts at the space character and ends with tilde. 27 | if [ "$allownonascii" != "true" ] && 28 | # Note that the use of brackets around a tr range is ok here, (it's 29 | # even required, for portability to Solaris 10's /usr/bin/tr), since 30 | # the square bracket bytes happen to fall in the designated range. 31 | test $(git diff --cached --name-only --diff-filter=A -z $against | 32 | LC_ALL=C tr -d '[ -~]\0' | wc -c) != 0 33 | then 34 | cat <<\EOF 35 | Error: Attempt to add a non-ASCII file name. 36 | 37 | This can cause problems if you want to work with people on other platforms. 38 | 39 | To be portable it is advisable to rename the file. 40 | 41 | If you know what you are doing you can disable this check using: 42 | 43 | git config hooks.allownonascii true 44 | EOF 45 | exit 1 46 | fi 47 | 48 | # If there are whitespace errors, print the offending file names and fail. 49 | exec git diff-index --check --cached $against -- 50 | -------------------------------------------------------------------------------- /tests/fixtures/tagged-commit-unpacked/dot-git/hooks/pre-push.sample: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # An example hook script to verify what is about to be pushed. Called by "git 4 | # push" after it has checked the remote status, but before anything has been 5 | # pushed. If this script exits with a non-zero status nothing will be pushed. 6 | # 7 | # This hook is called with the following parameters: 8 | # 9 | # $1 -- Name of the remote to which the push is being done 10 | # $2 -- URL to which the push is being done 11 | # 12 | # If pushing without using a named remote those arguments will be equal. 13 | # 14 | # Information about the commits which are being pushed is supplied as lines to 15 | # the standard input in the form: 16 | # 17 | # 18 | # 19 | # This sample shows how to prevent push of commits where the log message starts 20 | # with "WIP" (work in progress). 21 | 22 | remote="$1" 23 | url="$2" 24 | 25 | z40=0000000000000000000000000000000000000000 26 | 27 | while read local_ref local_sha remote_ref remote_sha 28 | do 29 | if [ "$local_sha" = $z40 ] 30 | then 31 | # Handle delete 32 | : 33 | else 34 | if [ "$remote_sha" = $z40 ] 35 | then 36 | # New branch, examine all commits 37 | range="$local_sha" 38 | else 39 | # Update to existing branch, examine new commits 40 | range="$remote_sha..$local_sha" 41 | fi 42 | 43 | # Check for WIP commit 44 | commit=`git rev-list -n 1 --grep '^WIP' "$range"` 45 | if [ -n "$commit" ] 46 | then 47 | echo >&2 "Found WIP commit in $local_ref, not pushing" 48 | exit 1 49 | fi 50 | fi 51 | done 52 | 53 | exit 0 54 | -------------------------------------------------------------------------------- /tests/fixtures/tagged-commit-unpacked/dot-git/hooks/pre-rebase.sample: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # Copyright (c) 2006, 2008 Junio C Hamano 4 | # 5 | # The "pre-rebase" hook is run just before "git rebase" starts doing 6 | # its job, and can prevent the command from running by exiting with 7 | # non-zero status. 8 | # 9 | # The hook is called with the following parameters: 10 | # 11 | # $1 -- the upstream the series was forked from. 12 | # $2 -- the branch being rebased (or empty when rebasing the current branch). 13 | # 14 | # This sample shows how to prevent topic branches that are already 15 | # merged to 'next' branch from getting rebased, because allowing it 16 | # would result in rebasing already published history. 17 | 18 | publish=next 19 | basebranch="$1" 20 | if test "$#" = 2 21 | then 22 | topic="refs/heads/$2" 23 | else 24 | topic=`git symbolic-ref HEAD` || 25 | exit 0 ;# we do not interrupt rebasing detached HEAD 26 | fi 27 | 28 | case "$topic" in 29 | refs/heads/??/*) 30 | ;; 31 | *) 32 | exit 0 ;# we do not interrupt others. 33 | ;; 34 | esac 35 | 36 | # Now we are dealing with a topic branch being rebased 37 | # on top of master. Is it OK to rebase it? 38 | 39 | # Does the topic really exist? 40 | git show-ref -q "$topic" || { 41 | echo >&2 "No such branch $topic" 42 | exit 1 43 | } 44 | 45 | # Is topic fully merged to master? 46 | not_in_master=`git rev-list --pretty=oneline ^master "$topic"` 47 | if test -z "$not_in_master" 48 | then 49 | echo >&2 "$topic is fully merged to master; better remove it." 50 | exit 1 ;# we could allow it, but there is no point. 51 | fi 52 | 53 | # Is topic ever merged to next? If so you should not be rebasing it. 54 | only_next_1=`git rev-list ^master "^$topic" ${publish} | sort` 55 | only_next_2=`git rev-list ^master ${publish} | sort` 56 | if test "$only_next_1" = "$only_next_2" 57 | then 58 | not_in_topic=`git rev-list "^$topic" master` 59 | if test -z "$not_in_topic" 60 | then 61 | echo >&2 "$topic is already up-to-date with master" 62 | exit 1 ;# we could allow it, but there is no point. 63 | else 64 | exit 0 65 | fi 66 | else 67 | not_in_next=`git rev-list --pretty=oneline ^${publish} "$topic"` 68 | /usr/bin/perl -e ' 69 | my $topic = $ARGV[0]; 70 | my $msg = "* $topic has commits already merged to public branch:\n"; 71 | my (%not_in_next) = map { 72 | /^([0-9a-f]+) /; 73 | ($1 => 1); 74 | } split(/\n/, $ARGV[1]); 75 | for my $elem (map { 76 | /^([0-9a-f]+) (.*)$/; 77 | [$1 => $2]; 78 | } split(/\n/, $ARGV[2])) { 79 | if (!exists $not_in_next{$elem->[0]}) { 80 | if ($msg) { 81 | print STDERR $msg; 82 | undef $msg; 83 | } 84 | print STDERR " $elem->[1]\n"; 85 | } 86 | } 87 | ' "$topic" "$not_in_next" "$not_in_master" 88 | exit 1 89 | fi 90 | 91 | exit 0 92 | 93 | ################################################################ 94 | 95 | This sample hook safeguards topic branches that have been 96 | published from being rewound. 97 | 98 | The workflow assumed here is: 99 | 100 | * Once a topic branch forks from "master", "master" is never 101 | merged into it again (either directly or indirectly). 102 | 103 | * Once a topic branch is fully cooked and merged into "master", 104 | it is deleted. If you need to build on top of it to correct 105 | earlier mistakes, a new topic branch is created by forking at 106 | the tip of the "master". This is not strictly necessary, but 107 | it makes it easier to keep your history simple. 108 | 109 | * Whenever you need to test or publish your changes to topic 110 | branches, merge them into "next" branch. 111 | 112 | The script, being an example, hardcodes the publish branch name 113 | to be "next", but it is trivial to make it configurable via 114 | $GIT_DIR/config mechanism. 115 | 116 | With this workflow, you would want to know: 117 | 118 | (1) ... if a topic branch has ever been merged to "next". Young 119 | topic branches can have stupid mistakes you would rather 120 | clean up before publishing, and things that have not been 121 | merged into other branches can be easily rebased without 122 | affecting other people. But once it is published, you would 123 | not want to rewind it. 124 | 125 | (2) ... if a topic branch has been fully merged to "master". 126 | Then you can delete it. More importantly, you should not 127 | build on top of it -- other people may already want to 128 | change things related to the topic as patches against your 129 | "master", so if you need further changes, it is better to 130 | fork the topic (perhaps with the same name) afresh from the 131 | tip of "master". 132 | 133 | Let's look at this example: 134 | 135 | o---o---o---o---o---o---o---o---o---o "next" 136 | / / / / 137 | / a---a---b A / / 138 | / / / / 139 | / / c---c---c---c B / 140 | / / / \ / 141 | / / / b---b C \ / 142 | / / / / \ / 143 | ---o---o---o---o---o---o---o---o---o---o---o "master" 144 | 145 | 146 | A, B and C are topic branches. 147 | 148 | * A has one fix since it was merged up to "next". 149 | 150 | * B has finished. It has been fully merged up to "master" and "next", 151 | and is ready to be deleted. 152 | 153 | * C has not merged to "next" at all. 154 | 155 | We would want to allow C to be rebased, refuse A, and encourage 156 | B to be deleted. 157 | 158 | To compute (1): 159 | 160 | git rev-list ^master ^topic next 161 | git rev-list ^master next 162 | 163 | if these match, topic has not merged in next at all. 164 | 165 | To compute (2): 166 | 167 | git rev-list master..topic 168 | 169 | if this is empty, it is fully merged to "master". 170 | -------------------------------------------------------------------------------- /tests/fixtures/tagged-commit-unpacked/dot-git/hooks/prepare-commit-msg.sample: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # An example hook script to prepare the commit log message. 4 | # Called by "git commit" with the name of the file that has the 5 | # commit message, followed by the description of the commit 6 | # message's source. The hook's purpose is to edit the commit 7 | # message file. If the hook fails with a non-zero status, 8 | # the commit is aborted. 9 | # 10 | # To enable this hook, rename this file to "prepare-commit-msg". 11 | 12 | # This hook includes three examples. The first comments out the 13 | # "Conflicts:" part of a merge commit. 14 | # 15 | # The second includes the output of "git diff --name-status -r" 16 | # into the message, just before the "git status" output. It is 17 | # commented because it doesn't cope with --amend or with squashed 18 | # commits. 19 | # 20 | # The third example adds a Signed-off-by line to the message, that can 21 | # still be edited. This is rarely a good idea. 22 | 23 | case "$2,$3" in 24 | merge,) 25 | /usr/bin/perl -i.bak -ne 's/^/# /, s/^# #/#/ if /^Conflicts/ .. /#/; print' "$1" ;; 26 | 27 | # ,|template,) 28 | # /usr/bin/perl -i.bak -pe ' 29 | # print "\n" . `git diff --cached --name-status -r` 30 | # if /^#/ && $first++ == 0' "$1" ;; 31 | 32 | *) ;; 33 | esac 34 | 35 | # SOB=$(git var GIT_AUTHOR_IDENT | sed -n 's/^\(.*>\).*$/Signed-off-by: \1/p') 36 | # grep -qs "^$SOB" "$1" || echo "$SOB" >> "$1" 37 | -------------------------------------------------------------------------------- /tests/fixtures/tagged-commit-unpacked/dot-git/hooks/update.sample: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # An example hook script to blocks unannotated tags from entering. 4 | # Called by "git receive-pack" with arguments: refname sha1-old sha1-new 5 | # 6 | # To enable this hook, rename this file to "update". 7 | # 8 | # Config 9 | # ------ 10 | # hooks.allowunannotated 11 | # This boolean sets whether unannotated tags will be allowed into the 12 | # repository. By default they won't be. 13 | # hooks.allowdeletetag 14 | # This boolean sets whether deleting tags will be allowed in the 15 | # repository. By default they won't be. 16 | # hooks.allowmodifytag 17 | # This boolean sets whether a tag may be modified after creation. By default 18 | # it won't be. 19 | # hooks.allowdeletebranch 20 | # This boolean sets whether deleting branches will be allowed in the 21 | # repository. By default they won't be. 22 | # hooks.denycreatebranch 23 | # This boolean sets whether remotely creating branches will be denied 24 | # in the repository. By default this is allowed. 25 | # 26 | 27 | # --- Command line 28 | refname="$1" 29 | oldrev="$2" 30 | newrev="$3" 31 | 32 | # --- Safety check 33 | if [ -z "$GIT_DIR" ]; then 34 | echo "Don't run this script from the command line." >&2 35 | echo " (if you want, you could supply GIT_DIR then run" >&2 36 | echo " $0 )" >&2 37 | exit 1 38 | fi 39 | 40 | if [ -z "$refname" -o -z "$oldrev" -o -z "$newrev" ]; then 41 | echo "usage: $0 " >&2 42 | exit 1 43 | fi 44 | 45 | # --- Config 46 | allowunannotated=$(git config --bool hooks.allowunannotated) 47 | allowdeletebranch=$(git config --bool hooks.allowdeletebranch) 48 | denycreatebranch=$(git config --bool hooks.denycreatebranch) 49 | allowdeletetag=$(git config --bool hooks.allowdeletetag) 50 | allowmodifytag=$(git config --bool hooks.allowmodifytag) 51 | 52 | # check for no description 53 | projectdesc=$(sed -e '1q' "$GIT_DIR/description") 54 | case "$projectdesc" in 55 | "Unnamed repository"* | "") 56 | echo "*** Project description file hasn't been set" >&2 57 | exit 1 58 | ;; 59 | esac 60 | 61 | # --- Check types 62 | # if $newrev is 0000...0000, it's a commit to delete a ref. 63 | zero="0000000000000000000000000000000000000000" 64 | if [ "$newrev" = "$zero" ]; then 65 | newrev_type=delete 66 | else 67 | newrev_type=$(git cat-file -t $newrev) 68 | fi 69 | 70 | case "$refname","$newrev_type" in 71 | refs/tags/*,commit) 72 | # un-annotated tag 73 | short_refname=${refname##refs/tags/} 74 | if [ "$allowunannotated" != "true" ]; then 75 | echo "*** The un-annotated tag, $short_refname, is not allowed in this repository" >&2 76 | echo "*** Use 'git tag [ -a | -s ]' for tags you want to propagate." >&2 77 | exit 1 78 | fi 79 | ;; 80 | refs/tags/*,delete) 81 | # delete tag 82 | if [ "$allowdeletetag" != "true" ]; then 83 | echo "*** Deleting a tag is not allowed in this repository" >&2 84 | exit 1 85 | fi 86 | ;; 87 | refs/tags/*,tag) 88 | # annotated tag 89 | if [ "$allowmodifytag" != "true" ] && git rev-parse $refname > /dev/null 2>&1 90 | then 91 | echo "*** Tag '$refname' already exists." >&2 92 | echo "*** Modifying a tag is not allowed in this repository." >&2 93 | exit 1 94 | fi 95 | ;; 96 | refs/heads/*,commit) 97 | # branch 98 | if [ "$oldrev" = "$zero" -a "$denycreatebranch" = "true" ]; then 99 | echo "*** Creating a branch is not allowed in this repository" >&2 100 | exit 1 101 | fi 102 | ;; 103 | refs/heads/*,delete) 104 | # delete branch 105 | if [ "$allowdeletebranch" != "true" ]; then 106 | echo "*** Deleting a branch is not allowed in this repository" >&2 107 | exit 1 108 | fi 109 | ;; 110 | refs/remotes/*,commit) 111 | # tracking branch 112 | ;; 113 | refs/remotes/*,delete) 114 | # delete tracking branch 115 | if [ "$allowdeletebranch" != "true" ]; then 116 | echo "*** Deleting a tracking branch is not allowed in this repository" >&2 117 | exit 1 118 | fi 119 | ;; 120 | *) 121 | # Anything else (is there anything else?) 122 | echo "*** Update hook: unknown type of update to ref $refname of type $newrev_type" >&2 123 | exit 1 124 | ;; 125 | esac 126 | 127 | # --- Finished 128 | exit 0 129 | -------------------------------------------------------------------------------- /tests/fixtures/tagged-commit-unpacked/dot-git/index: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rwjblue/git-repo-info/189fe90639c83b03f6f701ac88e642b7237861db/tests/fixtures/tagged-commit-unpacked/dot-git/index -------------------------------------------------------------------------------- /tests/fixtures/tagged-commit-unpacked/dot-git/info/exclude: -------------------------------------------------------------------------------- 1 | # git ls-files --others --exclude-from=.git/info/exclude 2 | # Lines that start with '#' are comments. 3 | # For a project mostly in C, the following would be a good set of 4 | # exclude patterns (uncomment them if you want to use them): 5 | # *.[oa] 6 | # *~ 7 | -------------------------------------------------------------------------------- /tests/fixtures/tagged-commit-unpacked/dot-git/logs/HEAD: -------------------------------------------------------------------------------- 1 | 0000000000000000000000000000000000000000 c1ee41c325d54f410b133e0018c7a6b1316f6cda Robert Jackson 1429099806 -0400 commit (initial): Initial commit. 2 | -------------------------------------------------------------------------------- /tests/fixtures/tagged-commit-unpacked/dot-git/logs/refs/heads/master: -------------------------------------------------------------------------------- 1 | 0000000000000000000000000000000000000000 c1ee41c325d54f410b133e0018c7a6b1316f6cda Robert Jackson 1429099806 -0400 commit (initial): Initial commit. 2 | -------------------------------------------------------------------------------- /tests/fixtures/tagged-commit-unpacked/dot-git/objects/54/3b9bebdc6bd5c4b22136034a95dd097a57d3dd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rwjblue/git-repo-info/189fe90639c83b03f6f701ac88e642b7237861db/tests/fixtures/tagged-commit-unpacked/dot-git/objects/54/3b9bebdc6bd5c4b22136034a95dd097a57d3dd -------------------------------------------------------------------------------- /tests/fixtures/tagged-commit-unpacked/dot-git/objects/c1/ee41c325d54f410b133e0018c7a6b1316f6cda: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rwjblue/git-repo-info/189fe90639c83b03f6f701ac88e642b7237861db/tests/fixtures/tagged-commit-unpacked/dot-git/objects/c1/ee41c325d54f410b133e0018c7a6b1316f6cda -------------------------------------------------------------------------------- /tests/fixtures/tagged-commit-unpacked/dot-git/objects/e6/9de29bb2d1d6434b8b29ae775ad8c2e48c5391: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rwjblue/git-repo-info/189fe90639c83b03f6f701ac88e642b7237861db/tests/fixtures/tagged-commit-unpacked/dot-git/objects/e6/9de29bb2d1d6434b8b29ae775ad8c2e48c5391 -------------------------------------------------------------------------------- /tests/fixtures/tagged-commit-unpacked/dot-git/refs/heads/master: -------------------------------------------------------------------------------- 1 | c1ee41c325d54f410b133e0018c7a6b1316f6cda 2 | -------------------------------------------------------------------------------- /tests/fixtures/tagged-commit-unpacked/dot-git/refs/tags/awesome-tag: -------------------------------------------------------------------------------- 1 | c1ee41c325d54f410b133e0018c7a6b1316f6cda 2 | -------------------------------------------------------------------------------- /tests/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var assert = require('assert'); 4 | var path = require('path'); 5 | var repoInfo = require('../index'); 6 | var zlib = require('zlib'); 7 | 8 | require('mocha-jshint')(); 9 | 10 | var root = process.cwd(); 11 | var testFixturesPath = path.join(__dirname, 'fixtures'); 12 | var gitDir = 'dot-git'; 13 | 14 | repoInfo._suppressErrors = false; 15 | 16 | describe('git-repo-info', function() { 17 | before(function() { 18 | repoInfo._changeGitDir(gitDir); 19 | }); 20 | 21 | afterEach(function() { 22 | process.chdir(root); 23 | }); 24 | 25 | describe('repo lookup', function() { 26 | var repoRoot = path.join(testFixturesPath, 'nested-repo'); 27 | 28 | it('finds a repo in the current directory', function() { 29 | process.chdir(repoRoot); 30 | 31 | var foundPathInfo = repoInfo._findRepo(repoRoot); 32 | assert.deepEqual(foundPathInfo, { 33 | worktreeGitDir: path.join(repoRoot, gitDir), 34 | commonGitDir: path.join(repoRoot, gitDir), 35 | root: repoRoot, 36 | }); 37 | }); 38 | 39 | it('finds a repo in the parent directory', function() { 40 | process.chdir(path.join(repoRoot, 'foo')); 41 | 42 | var foundPathInfo = repoInfo._findRepo(repoRoot); 43 | assert.deepEqual(foundPathInfo, { 44 | worktreeGitDir: path.join(repoRoot, gitDir), 45 | commonGitDir: path.join(repoRoot, gitDir), 46 | root: repoRoot, 47 | }); 48 | }); 49 | 50 | it('finds a repo 2 levels up', function() { 51 | process.chdir(path.join(repoRoot, 'foo', 'bar')); 52 | 53 | var foundPathInfo = repoInfo._findRepo(repoRoot); 54 | assert.deepEqual(foundPathInfo, { 55 | worktreeGitDir: path.join(repoRoot, gitDir), 56 | commonGitDir: path.join(repoRoot, gitDir), 57 | root: repoRoot, 58 | }); 59 | }); 60 | 61 | it('finds a repo without an argument', function() { 62 | process.chdir(repoRoot); 63 | 64 | var foundPathInfo = repoInfo._findRepo(); 65 | assert.deepEqual(foundPathInfo, { 66 | worktreeGitDir: path.join(repoRoot, gitDir), 67 | commonGitDir: path.join(repoRoot, gitDir), 68 | root: repoRoot, 69 | }); 70 | }); 71 | 72 | it('finds a repo 2 levels up (without an argument)', function() { 73 | process.chdir(path.join(repoRoot, 'foo', 'bar')); 74 | 75 | var foundPathInfo = repoInfo._findRepo(); 76 | assert.deepEqual(foundPathInfo, { 77 | worktreeGitDir: path.join(repoRoot, gitDir), 78 | commonGitDir: path.join(repoRoot, gitDir), 79 | root: repoRoot, 80 | }); 81 | }); 82 | 83 | it('finds a repo via a linked worktree', function() { 84 | var worktreeRoot = path.join(testFixturesPath, 'linked-worktree', 'linked'); 85 | process.chdir(worktreeRoot); 86 | 87 | var foundPathInfo = repoInfo._findRepo(); 88 | assert.deepEqual(foundPathInfo, { 89 | worktreeGitDir: path.join(testFixturesPath, 'linked-worktree', 'dot-git', 'worktrees', 'linked'), 90 | commonGitDir: path.join(testFixturesPath, 'linked-worktree', 'dot-git'), 91 | root: path.join(testFixturesPath, 'linked-worktree'), 92 | }); 93 | }); 94 | 95 | it('finds a repo via a submodule', function() { 96 | process.chdir(path.join(testFixturesPath, 'submodule', 'my-submodule')); 97 | 98 | var foundPathInfo = repoInfo._findRepo(); 99 | assert.deepEqual(foundPathInfo, { 100 | worktreeGitDir: path.join(testFixturesPath, 'submodule', 'dot-git', 'modules', 'my-submodule'), 101 | commonGitDir: path.join(testFixturesPath, 'submodule', 'dot-git', 'modules', 'my-submodule'), 102 | root: path.join(testFixturesPath, 'submodule', 'my-submodule'), 103 | }); 104 | }); 105 | 106 | it('finds a repo via submodule on a specific path', function() { 107 | process.chdir(path.join(testFixturesPath, 'submodule')); 108 | 109 | var foundPathInfo = repoInfo._findRepo('my-submodule'); 110 | assert.deepEqual(foundPathInfo, { 111 | worktreeGitDir: path.join(testFixturesPath, 'submodule', 'dot-git', 'modules', 'my-submodule'), 112 | commonGitDir: path.join(testFixturesPath, 'submodule', 'dot-git', 'modules', 'my-submodule'), 113 | root: path.join(testFixturesPath, 'submodule', 'my-submodule'), 114 | }); 115 | }); 116 | }); 117 | 118 | describe('repoInfo', function() { 119 | it('returns an object with repo info', function() { 120 | var repoRoot = path.join(testFixturesPath, 'nested-repo'); 121 | var localGitDir = path.join(repoRoot, gitDir); 122 | var result = repoInfo(localGitDir); 123 | 124 | var expected = { 125 | branch: 'master', 126 | sha: '5359aabd3872d9ffd160712e9615c5592dfe6745', 127 | abbreviatedSha: '5359aabd38', 128 | tag: null, 129 | committer: null, 130 | committerDate: null, 131 | author: null, 132 | authorDate: null, 133 | commitMessage: null, 134 | root: repoRoot, 135 | commonGitDir: localGitDir, 136 | worktreeGitDir: localGitDir, 137 | lastTag: null, 138 | commitsSinceLastTag: Infinity 139 | }; 140 | 141 | assert.deepEqual(result, expected); 142 | }); 143 | 144 | it('returns an object with repo info including the parent tag', function() { 145 | var repoRoot = path.join(testFixturesPath, 'tag-on-parent'); 146 | var localGitDir = path.join(repoRoot, gitDir); 147 | var result = repoInfo(localGitDir); 148 | 149 | var expected = { 150 | branch: 'master', 151 | sha: 'fb26504da0ed5cd9ed366f7428c06a8433fd76e6', 152 | abbreviatedSha: 'fb26504da0', 153 | tag: null, 154 | committer: 'Lukas Kohler ', 155 | committerDate: '2017-10-14T02:02:43.000Z', 156 | author: 'Lukas Kohler ', 157 | authorDate: '2017-10-14T02:02:43.000Z', 158 | commitMessage: 'second commit without tag', 159 | root: repoRoot, 160 | commonGitDir: localGitDir, 161 | worktreeGitDir: localGitDir, 162 | parents: [ 163 | 'e66f7ec2da3b5d06f0fe845c4fbc87247efacf62' 164 | ], 165 | lastTag: 'parent-magic-tag', 166 | commitsSinceLastTag: 1 167 | }; 168 | 169 | assert.deepEqual(result, expected); 170 | }); 171 | 172 | it('returns an object with repo info including the parent tag before a merge commit', function() { 173 | var repoRoot = path.join(testFixturesPath, 'tag-on-parent-before-merge'); 174 | var localGitDir = path.join(repoRoot, gitDir); 175 | var result = repoInfo(localGitDir); 176 | 177 | var expected = { 178 | branch: 'master', 179 | sha: 'b60d665ae0978a7b46e2447f4c13d7909997f56c', 180 | abbreviatedSha: 'b60d665ae0', 181 | tag: null, 182 | committer: 'Lukas Kohler ', 183 | committerDate: '2017-11-13T14:54:49.000Z', 184 | author: 'Lukas Kohler ', 185 | authorDate: '2017-11-13T14:54:49.000Z', 186 | commitMessage: 'merge red and blue', 187 | root: repoRoot, 188 | commonGitDir: localGitDir, 189 | worktreeGitDir: localGitDir, 190 | parents: [ 191 | 'b0c8b86ee451a2f389eed64838449d9a00a0b45f', 192 | '4f5c726a1528fdfb1ec7c9537e4b1b2dbaacbcc4' 193 | ], 194 | lastTag: 'magic-tag', 195 | commitsSinceLastTag: 1 196 | }; 197 | 198 | assert.deepEqual(result, expected); 199 | }); 200 | 201 | it('returns an object with repo info', function() { 202 | var repoRoot = path.join(testFixturesPath, 'detached-head'); 203 | var localGitDir = path.join(repoRoot, gitDir); 204 | var result = repoInfo(localGitDir); 205 | 206 | var expected = { 207 | branch: null, 208 | sha: '9dac893d5a83c02344d91e79dad8904889aeacb1', 209 | abbreviatedSha: '9dac893d5a', 210 | tag: null, 211 | committer: null, 212 | committerDate: null, 213 | author: null, 214 | authorDate: null, 215 | commitMessage: null, 216 | root: repoRoot, 217 | commonGitDir: localGitDir, 218 | worktreeGitDir: localGitDir, 219 | lastTag: null, 220 | commitsSinceLastTag: Infinity 221 | }; 222 | 223 | assert.deepEqual(result, expected); 224 | }); 225 | 226 | it('returns an object with repo info (packed commit)', function() { 227 | var repoRoot = path.join(testFixturesPath, 'commit-packed'); 228 | var localGitDir = path.join(repoRoot, gitDir); 229 | var result = repoInfo(localGitDir); 230 | 231 | var expected = { 232 | branch: 'develop', 233 | sha: 'd670460b4b4aece5915caf5c68d12f560a9fe3e4', 234 | abbreviatedSha: 'd670460b4b', 235 | tag: null, 236 | committer: null, 237 | committerDate: null, 238 | author: null, 239 | authorDate: null, 240 | commitMessage: null, 241 | root: repoRoot, 242 | commonGitDir: localGitDir, 243 | worktreeGitDir: localGitDir, 244 | lastTag: null, 245 | commitsSinceLastTag: Infinity 246 | }; 247 | 248 | assert.deepEqual(result, expected); 249 | }); 250 | 251 | it('returns an object with repo info, including the tag (packed tags)', function() { 252 | var repoRoot = path.join(testFixturesPath, 'tagged-commit-packed'); 253 | var localGitDir = path.join(repoRoot, gitDir); 254 | var result = repoInfo(localGitDir); 255 | 256 | var expected = { 257 | branch: 'master', 258 | sha: '5359aabd3872d9ffd160712e9615c5592dfe6745', 259 | abbreviatedSha: '5359aabd38', 260 | tag: 'my-tag', 261 | committer: null, 262 | committerDate: null, 263 | author: null, 264 | authorDate: null, 265 | commitMessage: null, 266 | root: repoRoot, 267 | commonGitDir: localGitDir, 268 | worktreeGitDir: localGitDir, 269 | lastTag: 'my-tag', 270 | commitsSinceLastTag: 0 271 | }; 272 | 273 | assert.deepEqual(result, expected); 274 | }); 275 | 276 | it('returns an object with repo info, including the tag (packed annotated tag)', function() { 277 | var repoRoot = path.join(testFixturesPath, 'tagged-commit-packed-annotated'); 278 | var localGitDir = path.join(repoRoot, gitDir); 279 | var result = repoInfo(localGitDir); 280 | 281 | var expected = { 282 | branch: 'master', 283 | sha: '5359aabd3872d9ffd160712e9615c5592dfe6745', 284 | abbreviatedSha: '5359aabd38', 285 | tag: 'example-annotated-tag', 286 | committer: null, 287 | committerDate: null, 288 | author: null, 289 | authorDate: null, 290 | commitMessage: null, 291 | root: repoRoot, 292 | commonGitDir: localGitDir, 293 | worktreeGitDir: localGitDir, 294 | lastTag: 'example-annotated-tag', 295 | commitsSinceLastTag: 0 296 | }; 297 | 298 | assert.deepEqual(result, expected); 299 | }); 300 | 301 | if (zlib.inflateSync) { 302 | it('returns an object with repo info, including the tag (unpacked tags)', function() { 303 | var repoRoot = path.join(testFixturesPath, 'tagged-commit-unpacked'); 304 | var localGitDir = path.join(repoRoot, gitDir); 305 | var result = repoInfo(localGitDir); 306 | 307 | var expected = { 308 | branch: 'master', 309 | sha: 'c1ee41c325d54f410b133e0018c7a6b1316f6cda', 310 | abbreviatedSha: 'c1ee41c325', 311 | tag: 'awesome-tag', 312 | committer: 'Robert Jackson ', 313 | committerDate: '2015-04-15T12:10:06.000Z', 314 | author: 'Robert Jackson ', 315 | authorDate: '2015-04-15T12:10:06.000Z', 316 | commitMessage: 'Initial commit.', 317 | root: repoRoot, 318 | commonGitDir: localGitDir, 319 | worktreeGitDir: localGitDir, 320 | lastTag: 'awesome-tag', 321 | commitsSinceLastTag: 0 322 | }; 323 | 324 | assert.deepEqual(result, expected); 325 | }); 326 | } else { 327 | it('returns an object with repo info, including the tag (unpacked tags)', function() { 328 | var repoRoot = path.join(testFixturesPath, 'tagged-commit-unpacked'); 329 | var localGitDir = path.join(repoRoot, gitDir); 330 | var result = repoInfo(localGitDir); 331 | 332 | var expected = { 333 | branch: 'master', 334 | sha: 'c1ee41c325d54f410b133e0018c7a6b1316f6cda', 335 | abbreviatedSha: 'c1ee41c325', 336 | tag: 'awesome-tag', 337 | committer: null, 338 | committerDate: null, 339 | author: null, 340 | authorDate: null, 341 | commitMessage: null, 342 | root: repoRoot, 343 | commonGitDir: localGitDir, 344 | worktreeGitDir: localGitDir, 345 | lastTag: 'awesome-tag', 346 | commitsSinceLastTag: 0 347 | }; 348 | 349 | assert.deepEqual(result, expected); 350 | }); 351 | } 352 | 353 | it('returns an object with repo info, including the tag (unpacked tags) when a tag object does not exist', function() { 354 | var repoRoot = path.join(testFixturesPath, 'tagged-commit-unpacked-no-object'); 355 | var localGitDir = path.join(repoRoot, gitDir); 356 | var result = repoInfo(localGitDir); 357 | 358 | var expected = { 359 | branch: 'master', 360 | sha: 'c1ee41c325d54f410b133e0018c7a6b1316f6cda', 361 | abbreviatedSha: 'c1ee41c325', 362 | tag: 'awesome-tag', 363 | committer: null, 364 | committerDate: null, 365 | author: null, 366 | authorDate: null, 367 | commitMessage: null, 368 | root: repoRoot, 369 | commonGitDir: localGitDir, 370 | worktreeGitDir: localGitDir, 371 | lastTag: 'awesome-tag', 372 | commitsSinceLastTag: 0 373 | }; 374 | 375 | assert.deepEqual(result, expected); 376 | }); 377 | 378 | it('returns an object with repo info, including the tag (deterministic alpha sort)', function() { 379 | var repoRoot = path.join(testFixturesPath, 'tagged-commit-mixed-packing'); 380 | var result = repoInfo(path.join(repoRoot, gitDir)); 381 | 382 | var expected = { 383 | sha: '37ece7ad9ded5f2312bb6be8d0c21ecebca088ac', 384 | tag: '0-lightweight-tag', 385 | }; 386 | 387 | assert.deepEqual({ sha: result.sha, tag: result.tag }, expected); 388 | }); 389 | 390 | if (zlib.inflateSync) { 391 | it('returns an object with repo info, including the tag (annotated tags)', function() { 392 | var repoRoot = path.join(testFixturesPath, 'tagged-annotated'); 393 | var localGitDir = path.join(repoRoot, gitDir); 394 | var result = repoInfo(localGitDir); 395 | 396 | var expected = { 397 | branch: 'master', 398 | sha: 'c1ee41c325d54f410b133e0018c7a6b1316f6cda', 399 | abbreviatedSha: 'c1ee41c325', 400 | tag: 'awesome-tag', 401 | committer: 'Robert Jackson ', 402 | committerDate: '2015-04-15T12:10:06.000Z', 403 | author: 'Robert Jackson ', 404 | authorDate: '2015-04-15T12:10:06.000Z', 405 | commitMessage: 'Initial commit.', 406 | root: repoRoot, 407 | commonGitDir: localGitDir, 408 | worktreeGitDir: localGitDir, 409 | lastTag: 'awesome-tag', 410 | commitsSinceLastTag: 0 411 | }; 412 | 413 | assert.deepEqual(result, expected); 414 | }); 415 | } 416 | 417 | it('returns an object with repo info, including the full branch name, if the branch name includes any slashes', function() { 418 | var repoRoot = path.join(testFixturesPath, 'branch-with-slashes'); 419 | var localGitDir = path.join(repoRoot, gitDir); 420 | var result = repoInfo(localGitDir); 421 | 422 | var expected = { 423 | branch: 'feature/branch/with/slashes', 424 | sha: '5359aabd3872d9ffd160712e9615c5592dfe6745', 425 | abbreviatedSha: '5359aabd38', 426 | tag: null, 427 | committer: null, 428 | committerDate: null, 429 | author: null, 430 | authorDate: null, 431 | commitMessage: null, 432 | root: repoRoot, 433 | commonGitDir: localGitDir, 434 | worktreeGitDir: localGitDir, 435 | lastTag: null, 436 | commitsSinceLastTag: Infinity 437 | }; 438 | 439 | assert.deepEqual(result, expected); 440 | }); 441 | 442 | it('returns an object with repo info for linked worktrees', function() { 443 | var repoRoot = path.join(testFixturesPath, 'linked-worktree'); 444 | process.chdir(path.join(repoRoot, 'linked')); 445 | var result = repoInfo(); 446 | 447 | var expected = { 448 | branch: null, 449 | sha: '409372f3bd07c11bfacee3963f48571d675268d7', 450 | abbreviatedSha: '409372f3bd', 451 | tag: null, 452 | committer: null, 453 | committerDate: null, 454 | author: null, 455 | authorDate: null, 456 | commitMessage: null, 457 | root: repoRoot, 458 | commonGitDir: path.join(repoRoot, gitDir), 459 | worktreeGitDir: path.join(repoRoot, gitDir, 'worktrees', 'linked'), 460 | lastTag: null, 461 | commitsSinceLastTag: Infinity 462 | }; 463 | 464 | assert.deepEqual(result, expected); 465 | }); 466 | 467 | it('returns an object for repo info for submodules', function() { 468 | var parentRoot = path.join(testFixturesPath, 'submodule'); 469 | var moduleRoot = path.join(parentRoot, 'my-submodule'); 470 | var localGitDir = path.join(parentRoot, gitDir, 'modules', 'my-submodule'); 471 | process.chdir(moduleRoot); 472 | var result = repoInfo(); 473 | var expected = { 474 | branch: null, 475 | sha: '409372f3bd07c11bfacee3963f48571d675268d7', 476 | abbreviatedSha: '409372f3bd', 477 | tag: null, 478 | committer: null, 479 | committerDate: null, 480 | author: null, 481 | authorDate: null, 482 | commitMessage: null, 483 | root: moduleRoot, 484 | commonGitDir: localGitDir, 485 | worktreeGitDir: localGitDir, 486 | lastTag: null, 487 | commitsSinceLastTag: Infinity 488 | }; 489 | 490 | assert.deepEqual(result, expected); 491 | }); 492 | 493 | it('returns an object for repo info for submodule on a specific path', function() { 494 | var parentRoot = path.join(testFixturesPath, 'submodule'); 495 | var localGitDir = path.join(parentRoot, gitDir, 'modules', 'my-submodule'); 496 | process.chdir(parentRoot); 497 | var result = repoInfo('my-submodule'); 498 | 499 | var expected = { 500 | branch: null, 501 | sha: '409372f3bd07c11bfacee3963f48571d675268d7', 502 | abbreviatedSha: '409372f3bd', 503 | tag: null, 504 | committer: null, 505 | committerDate: null, 506 | author: null, 507 | authorDate: null, 508 | commitMessage: null, 509 | root: path.join(parentRoot, 'my-submodule'), 510 | commonGitDir: localGitDir, 511 | worktreeGitDir: localGitDir, 512 | lastTag: null, 513 | commitsSinceLastTag: Infinity 514 | }; 515 | 516 | assert.deepEqual(result, expected); 517 | }); 518 | }); 519 | 520 | describe('repoInfo().root', function() { 521 | var repoRoot = path.join(testFixturesPath, 'nested-repo'); 522 | 523 | it('finds a repo from cwd (2 levels up)', function() { 524 | process.chdir(path.join(repoRoot, 'foo', 'bar')); 525 | assert.equal(repoInfo().root, repoRoot); 526 | }); 527 | 528 | it('finds a repo with an argument', function() { 529 | assert.equal(repoInfo(path.join(repoRoot, 'foo', 'bar')).root, repoRoot); 530 | }); 531 | }); 532 | }); 533 | --------------------------------------------------------------------------------