1592 lines · 47.5 KB · JavaScript
RawDownload
(function () {    'use strict';    var debug = require('debug')('simple-git');   var deferred = require('./util/deferred');   var exists = require('./util/exists');   var NOOP = function () {};   var responses = require('./responses');    /**    * Git handling for node. All public functions can be chained and all `then` handlers are optional.    *    * @param {string} baseDir base directory for all processes to run    *    * @param {Object} ChildProcess The ChildProcess module    * @param {Function} Buffer The Buffer implementation to use    *    * @constructor    */   function Git (baseDir, ChildProcess, Buffer) {      this._baseDir = baseDir;      this._runCache = [];       this.ChildProcess = ChildProcess;      this.Buffer = Buffer;   }    /**    * @type {string} The command to use to reference the git binary    */   Git.prototype._command = 'git';    /**    * @type {[key: string]: string} An object of key=value pairs to be passed as environment variables to the    *                               spawned child process.    */   Git.prototype._env = null;    /**    * @type {Function} An optional handler to use when a child process is created    */   Git.prototype._outputHandler = null;    /**    * @type {boolean} Property showing whether logging will be silenced - defaults to true in a production environment    */   Git.prototype._silentLogging = /prod/.test(process.env.NODE_ENV);    /**    * Sets the path to a custom git binary, should either be `git` when there is an installation of git available on    * the system path, or a fully qualified path to the executable.    *    * @param {string} command    * @returns {Git}    */   Git.prototype.customBinary = function (command) {      this._command = command;      return this;   };    /**    * Sets an environment variable for the spawned child process, either supply both a name and value as strings or    * a single object to entirely replace the current environment variables.    *    * @param {string|Object} name    * @param {string} [value]    * @returns {Git}    */   Git.prototype.env = function (name, value) {      if (arguments.length === 1 && typeof name === 'object') {         this._env = name;      }      else {         (this._env = this._env || {})[name] = value;      }       return this;   };    /**    * Sets the working directory of the subsequent commands.    *    * @param {string} workingDirectory    * @param {Function} [then]    * @returns {Git}    */   Git.prototype.cwd = function (workingDirectory, then) {      var git = this;      var next = Git.trailingFunctionArgument(arguments);       return this.exec(function () {         git._baseDir = workingDirectory;         if (!exists(workingDirectory, exists.FOLDER)) {            Git.exception(git, 'Git.cwd: cannot change to non-directory "' + workingDirectory + '"', next);         }         else {            next && next(null, workingDirectory);         }      });   };    /**    * Sets a handler function to be called whenever a new child process is created, the handler function will be called    * with the name of the command being run and the stdout & stderr streams used by the ChildProcess.    *    * @example    * require('simple-git')    *    .outputHandler(function (command, stdout, stderr) {    *       stdout.pipe(process.stdout);    *    })    *    .checkout('https://github.com/user/repo.git');    *    * @see https://nodejs.org/api/child_process.html#child_process_class_childprocess    * @see https://nodejs.org/api/stream.html#stream_class_stream_readable    * @param {Function} outputHandler    * @returns {Git}    */   Git.prototype.outputHandler = function (outputHandler) {      this._outputHandler = outputHandler;      return this;   };    /**    * Initialize a git repo    *    * @param {Boolean} [bare=false]    * @param {Function} [then]    */   Git.prototype.init = function (bare, then) {      var commands = ['init'];      var next = Git.trailingFunctionArgument(arguments);       if (bare === true) {         commands.push('--bare');      }       return this._run(commands, function (err) {         next && next(err);      });   };    /**    * Check the status of the local repo    *    * @param {Function} [then]    */   Git.prototype.status = function (then) {      return this._run(         ['status', '--porcelain', '-b', '-u'],         Git._responseHandler(then, 'StatusSummary')      );   };    /**    * List the stash(s) of the local repo    *    * @param {Object|Array} [options]    * @param {Function} [then]    */   Git.prototype.stashList = function (options, then) {      var handler = Git.trailingFunctionArgument(arguments);      var opt = (handler === then ? options : null) || {};       var splitter = opt.splitter || requireResponseHandler('ListLogSummary').SPLITTER;      var command = ["stash", "list", "--pretty=format:"         + requireResponseHandler('ListLogSummary').START_BOUNDARY         + "%H %ai %s%d %aN %ae".replace(/\s+/g, splitter)         + requireResponseHandler('ListLogSummary').COMMIT_BOUNDARY      ];       if (Array.isArray(opt)) {         command = command.concat(opt);      }       return this._run(command,         Git._responseHandler(handler, 'ListLogSummary', splitter)      );   };    /**    * Stash the local repo    *    * @param {Object|Array} [options]    * @param {Function} [then]    */   Git.prototype.stash = function (options, then) {      var command = ['stash'];      Git._appendOptions(command, Git.trailingOptionsArgument(arguments));      command.push.apply(command, Git.trailingArrayArgument(arguments));       return this._run(command, Git._responseHandler(Git.trailingFunctionArgument(arguments)));   };    /**    * Clone a git repo    *    * @param {string} repoPath    * @param {string} localPath    * @param {String[]} [options] Optional array of options to pass through to the clone command    * @param {Function} [then]    */   Git.prototype.clone = function (repoPath, localPath, options, then) {      var next = Git.trailingFunctionArgument(arguments);      var command = ['clone'].concat(Git.trailingArrayArgument(arguments));       for (var i = 0, iMax = arguments.length; i < iMax; i++) {         if (typeof arguments[i] === 'string') {            command.push(arguments[i]);         }      }       return this._run(command, function (err, data) {         next && next(err, data);      });   };    /**    * Mirror a git repo    *    * @param {string} repoPath    * @param {string} localPath    * @param {Function} [then]    */   Git.prototype.mirror = function (repoPath, localPath, then) {      return this.clone(repoPath, localPath, ['--mirror'], then);   };    /**    * Moves one or more files to a new destination.    *    * @see https://git-scm.com/docs/git-mv    *    * @param {string|string[]} from    * @param {string} to    * @param {Function} [then]    */   Git.prototype.mv = function (from, to, then) {      var handler = Git.trailingFunctionArgument(arguments);       var command = [].concat(from);      command.unshift('mv', '-v');      command.push(to);       this._run(command, Git._responseHandler(handler, 'MoveSummary'))   };    /**    * Internally uses pull and tags to get the list of tags then checks out the latest tag.    *    * @param {Function} [then]    */   Git.prototype.checkoutLatestTag = function (then) {      var git = this;      return this.pull(function () {         git.tags(function (err, tags) {            git.checkout(tags.latest, then);         });      });   };    /**    * Adds one or more files to source control    *    * @param {string|string[]} files    * @param {Function} [then]    */   Git.prototype.add = function (files, then) {      return this._run(['add'].concat(files), function (err, data) {         then && then(err);      });   };    /**    * Commits changes in the current working directory - when specific file paths are supplied, only changes on those    * files will be committed.    *    * @param {string|string[]} message    * @param {string|string[]} [files]    * @param {Object} [options]    * @param {Function} [then]    */   Git.prototype.commit = function (message, files, options, then) {      var handler = Git.trailingFunctionArgument(arguments);       var command = ['commit'];       [].concat(message).forEach(function (message) {         command.push('-m', message);      });       [].push.apply(command, [].concat(typeof files === "string" || Array.isArray(files) ? files : []));       Git._appendOptions(command, Git.trailingOptionsArgument(arguments));       return this._run(         command,         Git._responseHandler(handler, 'CommitSummary')      );   };    /**    * Gets a function to be used for logging.    *    * @param {string} level    * @param {string} [message]    *    * @returns {Function}    * @private    */   Git.prototype._getLog = function (level, message) {      var log = this._silentLogging ? NOOP : console[level].bind(console);      if (arguments.length > 1) {         log(message);      }      return log;   };    /**    * Pull the updated contents of the current repo    *    * @param {string} [remote] When supplied must also include the branch    * @param {string} [branch] When supplied must also include the remote    * @param {Object} [options] Optionally include set of options to merge into the command    * @param {Function} [then]    */   Git.prototype.pull = function (remote, branch, options, then) {      var command = ["pull"];      var handler = Git.trailingFunctionArgument(arguments);       if (typeof remote === 'string' && typeof branch === 'string') {         command.push(remote, branch);      }       Git._appendOptions(command, Git.trailingOptionsArgument(arguments));       return this._run(command, Git._responseHandler(handler, 'PullSummary'));   };    /**    * Fetch the updated contents of the current repo.    *    * @example    *   .fetch('upstream', 'master') // fetches from master on remote named upstream    *   .fetch(function () {}) // runs fetch against default remote and branch and calls function    *    * @param {string} [remote]    * @param {string} [branch]    * @param {Function} [then]    */   Git.prototype.fetch = function (remote, branch, then) {      var command = ["fetch"];      var next = Git.trailingFunctionArgument(arguments);      Git._appendOptions(command, Git.trailingOptionsArgument(arguments));       if (typeof remote === 'string' && typeof branch === 'string') {         command.push(remote, branch);      }       if (Array.isArray(remote)) {         command = command.concat(remote);      }       return this._run(         command,         Git._responseHandler(next, 'FetchSummary'),         {            concatStdErr: true         }      );   };    /**    * Disables/enables the use of the console for printing warnings and errors, by default messages are not shown in    * a production environment.    *    * @param {boolean} silence    * @returns {Git}    */   Git.prototype.silent = function (silence) {      this._silentLogging = !!silence;      return this;   };    /**    * List all tags. When using git 2.7.0 or above, include an options object with `"--sort": "property-name"` to    * sort the tags by that property instead of using the default semantic versioning sort.    *    * Note, supplying this option when it is not supported by your Git version will cause the operation to fail.    *    * @param {Object} [options]    * @param {Function} [then]    */   Git.prototype.tags = function (options, then) {      var next = Git.trailingFunctionArgument(arguments);       var command = ['-l'];      Git._appendOptions(command, Git.trailingOptionsArgument(arguments));       var hasCustomSort = command.some(function (option) {         return /^--sort=/.test(option);      });       return this.tag(         command,         Git._responseHandler(next, 'TagList', [hasCustomSort])      );   };    /**    * Rebases the current working copy. Options can be supplied either as an array of string parameters    * to be sent to the `git rebase` command, or a standard options object.    *    * @param {Object|String[]} [options]    * @param {Function} [then]    * @returns {Git}    */   Git.prototype.rebase = function (options, then) {      var command = ['rebase'];      Git._appendOptions(command, Git.trailingOptionsArgument(arguments));      command.push.apply(command, Git.trailingArrayArgument(arguments));        return this._run(command, Git._responseHandler(Git.trailingFunctionArgument(arguments)));   };    /**    * Reset a repo    *    * @param {string|string[]} [mode=soft] Either an array of arguments supported by the 'git reset' command, or the    *                                        string value 'soft' or 'hard' to set the reset mode.    * @param {Function} [then]    */   Git.prototype.reset = function (mode, then) {      var command = ['reset'];      var next = Git.trailingFunctionArgument(arguments);      if (next === mode || typeof mode === 'string' || !mode) {         var modeStr = ['mixed', 'soft', 'hard'].includes(mode) ? mode : 'soft';         command.push('--' + modeStr);      }      else if (Array.isArray(mode)) {         command.push.apply(command, mode);      }       return this._run(command, function (err) {         next && next(err || null);      });   };    /**    * Revert one or more commits in the local working copy    *    * @param {string} commit The commit to revert. Can be any hash, offset (eg: `HEAD~2`) or range (eg: `master~5..master~2`)    * @param {Object} [options] Optional options object    * @param {Function} [then]    */   Git.prototype.revert = function (commit, options, then) {      var next = Git.trailingFunctionArgument(arguments);      var command = ['revert'];       Git._appendOptions(command, Git.trailingOptionsArgument(arguments));       if (typeof commit !== 'string') {         return this.exec(function () {            next && next(new TypeError("Commit must be a string"));         });      }       command.push(commit);      return this._run(command, function (err) {         next && next(err || null);      });   };    /**    * Add a lightweight tag to the head of the current branch    *    * @param {string} name    * @param {Function} [then]    */   Git.prototype.addTag = function (name, then) {      if (typeof name !== "string") {         return this.exec(function () {            then && then(new TypeError("Git.addTag requires a tag name"));         });      }       var command = [name];      return then ? this.tag(command, then) : this.tag(command);   };    /**    * Add an annotated tag to the head of the current branch    *    * @param {string} tagName    * @param {string} tagMessage    * @param {Function} [then]    */   Git.prototype.addAnnotatedTag = function (tagName, tagMessage, then) {      return this.tag(['-a', '-m', tagMessage, tagName], function (err) {

Lines 1–500 of 1592.