UNPKG

9.88 kBJavaScriptView Raw
1"use strict";
2var __assign = (this && this.__assign) || function () {
3 __assign = Object.assign || function(t) {
4 for (var s, i = 1, n = arguments.length; i < n; i++) {
5 s = arguments[i];
6 for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
7 t[p] = s[p];
8 }
9 return t;
10 };
11 return __assign.apply(this, arguments);
12};
13Object.defineProperty(exports, "__esModule", { value: true });
14var Fs = require("fs-extra");
15var Tmp = require("tmp");
16var paths_1 = require("./paths");
17var utils_1 = require("./utils");
18/**
19 Contains general git utilities.
20 */
21var exec = utils_1.Utils.exec;
22// This RegExp will help us pluck the versions in a conflict and solve it
23var conflict = /\n\s*<<<<<<< [^\n]+(\n(?:.|\n)+?)\n\s*=======(\n(?:.|\n)+?)\n\s*>>>>>>> [^\n]+/;
24function git(argv, options) {
25 return gitBody(utils_1.Utils.git, argv, options);
26}
27var gitPrint = git.print = function (argv, options) {
28 if (options === void 0) { options = {}; }
29 return gitBody(utils_1.Utils.git.print, argv, options);
30};
31// Push a tutorial based on the provided branch.
32// e.g. given 'master' then 'master-history', 'master-root', 'master@0.1.0', etc, will be pushed.
33// Note that everything will be pushed by FORCE and will override existing refs within the remote
34function pushTutorial(remote, baseBranch) {
35 var relatedBranches = git(['branch', '-l']).split('\n').map(function (branch) {
36 if (!branch) {
37 return null;
38 }
39 branch = branch.split(/\*?\s+/)[1];
40 if (branch === baseBranch) {
41 return branch;
42 }
43 if (branch === baseBranch + "-history") {
44 return branch;
45 }
46 if (branch === baseBranch + "-root") {
47 return branch;
48 }
49 if (new RegExp("^" + baseBranch + "-step\\d+$").test(branch)) {
50 return branch;
51 }
52 }).filter(Boolean);
53 var relatedTags = git(['tag', '-l']).split('\n').map(function (tag) {
54 if (!tag) {
55 return null;
56 }
57 if (new RegExp("^" + baseBranch + "@(\\d+\\.\\d+\\.\\d+|next)$").test(tag)) {
58 return tag;
59 }
60 if (new RegExp("^" + baseBranch + "@root@(\\d+\\.\\d+\\.\\d+|next)$").test(tag)) {
61 return tag;
62 }
63 if (new RegExp("^" + baseBranch + "@step\\d+@(\\d+\\.\\d+\\.\\d+|next)$").test(tag)) {
64 return tag;
65 }
66 }).filter(Boolean);
67 var refs = relatedBranches.concat(relatedTags);
68 return gitPrint(['push', '-f', remote].concat(refs));
69}
70// Pull a tutorial based on the provided branch. e.g. given 'master' then 'master-history',
71// 'master-root', 'master@0.1.0', etc, will be pulled.
72function pullTutorial(remote, baseBranch) {
73 var relatedBranches = [];
74 var relatedTags = [];
75 git(['ls-remote', '--tags', '--heads', remote]).split('\n').forEach(function (line) {
76 if (!line) {
77 return;
78 }
79 var _a = line.split(/\s+/), ref = _a[1];
80 if (new RegExp("^refs/tags/" + baseBranch + "@(root|step-\\d+@)?(\\d+\\.\\d+\\.\\d+|next)$").test(ref)) {
81 relatedTags.push(ref.split('/').slice(2).join('/'));
82 }
83 if (new RegExp("^refs/heads/" + baseBranch + "(-root|-history|-step\\d+)?$").test(ref)) {
84 relatedBranches.push(ref.split('/').slice(2).join('/'));
85 }
86 });
87 var refs = relatedBranches.concat(relatedTags);
88 var activeBranchName = exports.Git.activeBranchName();
89 try {
90 var sha1 = exports.Git(['rev-parse', activeBranchName]);
91 // Detach HEAD so we can change the reference of the branch
92 exports.Git(['checkout', sha1]);
93 // --tags flag will overwrite tags
94 gitPrint(['fetch', '--tags', '-f', remote].concat(refs));
95 // Make sure that all local branches track the right remote branches
96 relatedBranches.forEach(function (branch) {
97 try {
98 exports.Git(['branch', '-D', branch]);
99 }
100 catch (e) {
101 // Branch doesn't exist
102 }
103 exports.Git.print(['branch', '--track', branch, "remotes/" + remote + "/" + branch]);
104 });
105 }
106 finally {
107 // Get back to where we were, regardless of the outcome
108 exports.Git(['checkout', activeBranchName]);
109 }
110}
111// The body of the git execution function, useful since we use the same logic both for
112// exec and spawn
113function gitBody(handler, argv, options) {
114 options = __assign({ env: {} }, options);
115 // Zeroing environment vars which might affect other executions
116 options.env = __assign({ GIT_DIR: null, GIT_WORK_TREE: null }, options.env);
117 return handler(argv, options);
118}
119// Tells if rebasing or not
120function isRebasing(path) {
121 if (path === void 0) { path = null; }
122 var paths = path ? paths_1.resolveProject(path).git : paths_1.Paths.git;
123 return utils_1.Utils.exists(paths.rebaseMerge) || utils_1.Utils.exists(paths.rebaseApply);
124}
125// Tells if cherry-picking or not
126function isCherryPicking() {
127 return utils_1.Utils.exists(paths_1.Paths.git.heads.cherryPick) || utils_1.Utils.exists(paths_1.Paths.git.heads.revert);
128}
129// Tells if going to amend or not
130function gonnaAmend() {
131 return utils_1.Utils.childProcessOf('git', ['commit', '--amend']);
132}
133// Tells if a tag exists or not
134function tagExists(tag) {
135 try {
136 git(['rev-parse', tag]);
137 return true;
138 }
139 catch (err) {
140 return false;
141 }
142}
143// Get the recent commit by the provided arguments. An offset can be specified which
144// means that the recent commit from several times back can be fetched as well
145function getRecentCommit(offset, argv, options, path) {
146 if (path === void 0) { path = null; }
147 if (offset instanceof Array) {
148 options = argv;
149 argv = offset;
150 offset = 0;
151 }
152 else {
153 argv = argv || [];
154 offset = offset || 0;
155 }
156 var hash = typeof offset === 'string' ? offset : ("HEAD~" + offset);
157 argv = ['log', hash, '-1'].concat(argv);
158 return git(argv, path ? __assign({}, options, { cwd: path }) : options);
159}
160// Gets a list of the modified files reported by git matching the provided pattern.
161// This includes untracked files, changed files and deleted files
162function getStagedFiles(pattern) {
163 var stagedFiles = git(['diff', '--name-only', '--cached'])
164 .split('\n')
165 .filter(Boolean);
166 return utils_1.Utils.filterMatches(stagedFiles, pattern);
167}
168// Gets active branch name
169function getActiveBranchName(path) {
170 if (path === void 0) { path = null; }
171 if (!isRebasing(path)) {
172 return git(['rev-parse', '--abbrev-ref', 'HEAD'], path ? { cwd: path } : null);
173 }
174 // Getting a reference for the hash of which the rebase have started
175 var branchHash = git(['reflog', '--format=%gd %gs'], path ? { cwd: path } : null)
176 .split('\n')
177 .filter(Boolean)
178 .map(function (line) { return line.split(' '); })
179 .map(function (split) { return [split.shift(), split.join(' ')]; })
180 .find(function (_a) {
181 var ref = _a[0], msg = _a[1];
182 return msg.match(/^rebase -i \(start\)/);
183 })
184 .shift()
185 .match(/^HEAD@\{(\d+)\}$/)
186 .slice(1)
187 .map(function (i) { return "HEAD@{" + ++i + "}"; })
188 .map(function (ref) { return git(['rev-parse', ref]); })
189 .pop();
190 // Comparing the found hash to each of the branches' hashes
191 return Fs.readdirSync(paths_1.Paths.git.refs.heads).find(function (branchName) {
192 return git(['rev-parse', branchName], path ? { cwd: path } : null) === branchHash;
193 });
194}
195// Gets the root hash of HEAD
196function getRootHash(head) {
197 if (head === void 0) { head = 'HEAD'; }
198 return git(['rev-list', '--max-parents=0', head]);
199}
200function getRoot() {
201 try {
202 return git(['rev-parse', '--show-toplevel']);
203 // Not a git project
204 }
205 catch (e) {
206 return '';
207 }
208}
209function edit(initialContent) {
210 var editor = getEditor();
211 var file = Tmp.fileSync({ unsafeCleanup: true });
212 Fs.writeFileSync(file.name, initialContent);
213 exec.print('sh', ['-c', editor + " " + file.name]);
214 var content = Fs.readFileSync(file.name).toString();
215 file.removeCallback();
216 return content;
217}
218// https://github.com/git/git/blob/master/git-rebase--interactive.sh#L257
219function getEditor() {
220 var editor = process.env.GIT_EDITOR;
221 if (!editor) {
222 try {
223 editor = git(['config', 'core.editor']);
224 }
225 catch (e) {
226 // Ignore
227 }
228 }
229 if (!editor) {
230 try {
231 editor = git(['var', 'GIT_EDITOR']);
232 }
233 catch (e) {
234 // Ignore
235 }
236 }
237 if (!editor) {
238 throw Error('Git editor could not be found');
239 }
240 return editor;
241}
242// Commander will split equal signs e.g. `--format=%H` which is is not the desired
243// behavior for git. This puts the everything back together when necessary
244function normalizeArgv(argv) {
245 argv = argv.slice();
246 {
247 var i = argv.indexOf('--format');
248 if (i !== -1) {
249 argv.splice(i, 2, "--format=" + argv[i + 1]);
250 }
251 }
252 return argv;
253}
254function getRevisionIdFromObject(object) {
255 return git(['rev-list', '-n', '1', object]);
256}
257exports.Git = utils_1.Utils.extend(git.bind(null), git, {
258 pushTutorial: pushTutorial,
259 pullTutorial: pullTutorial,
260 conflict: conflict,
261 rebasing: isRebasing,
262 cherryPicking: isCherryPicking,
263 gonnaAmend: gonnaAmend,
264 tagExists: tagExists,
265 recentCommit: getRecentCommit,
266 stagedFiles: getStagedFiles,
267 activeBranchName: getActiveBranchName,
268 rootHash: getRootHash,
269 root: getRoot,
270 edit: edit,
271 editor: getEditor,
272 normalizeArgv: normalizeArgv,
273 getRevisionIdFromObject: getRevisionIdFromObject,
274});
275//# sourceMappingURL=git.js.map
\No newline at end of file