public static List <BatchArgumentItem> BuildBatchArgumentsForFiles(this ArgumentBuilder builder, IEnumerable <string> files)
 => builder.BuildBatchArguments(files.Select(f => f.ToPosixPath().QuoteNE()));
        /// <summary>
        /// Split arguments exceeding max length into multiple batches.
        /// Windows by default limit arguments length less than 32767 <see cref="short.MaxValue"/>.
        /// Implementation by <see cref="System.Diagnostics.Process"/> will have file path included in command line arguments,
        /// as well as added quotation and space characters, so we need base length to account for all these added characters
        /// <see href="https://referencesource.microsoft.com/#system/services/monitoring/system/diagnosticts/Process.cs,1944"/>
        /// </summary>
        /// <param name="builder">Argument builder instance.</param>
        /// <param name="arguments">Arguments.</param>
        /// <param name="baseLength">Base executable file and command line length.</param>
        /// <param name="maxLength">Command line max length. Default is 32767 - 1 on Windows.</param>
        /// <returns>Array of batch arguments split by max length.</returns>
        public static List <BatchArgumentItem> BuildBatchArguments(this ArgumentBuilder builder, IEnumerable <string> arguments, int?baseLength = null, int maxLength = short.MaxValue)
        {
            // 3: double quotes + ' '
            // '"git.exe" ' is always included in final command line arguments
            if (!baseLength.HasValue)
            {
                baseLength = AppSettings.GitCommand.Length + 3;
            }

            var baseArgument = builder.ToString();

            if (baseLength + baseArgument.Length >= maxLength)
            {
                throw new ArgumentException($"Git base command \"{baseArgument}\" always reached max length of {maxLength} characters.", nameof(baseArgument));
            }

            // Clone command as argument builder
            var batches = new List <BatchArgumentItem>();
            var currentBatchItemCount = 0;
            var currentArgumentLength = baseArgument.Length;
            var lastBatchBuilder      = arguments.Aggregate(builder, (currentBatchBuilder, argument) =>
            {
                // 1: ' ' space character length will be added
                // When enumeration is finished, no need to add ' ' to length calculcation
                if (baseLength + currentArgumentLength + 1 + argument.Length >= maxLength)
                {
                    // Handle abnormal case when base command and a single argument exceed max length
                    if (currentBatchItemCount == 0)
                    {
                        throw new ArgumentException($"Git command \"{currentBatchBuilder}\" always exceeded max length of {maxLength} characters.", nameof(arguments));
                    }

                    // Finish current command line
                    batches.Add(new BatchArgumentItem(currentBatchBuilder, currentBatchItemCount));

                    // Return new argument builder
                    currentBatchItemCount = 1;
                    currentArgumentLength = baseArgument.Length + 1 + argument.Length;
                    return(new ArgumentBuilder()
                    {
                        baseArgument, argument
                    });
                }

                currentBatchBuilder.Add(argument);
                currentArgumentLength += argument.Length + 1;
                currentBatchItemCount++;
                return(currentBatchBuilder);
            });

            // Handle rare case when last argument length exceed max length
            if (baseLength + currentArgumentLength >= maxLength)
            {
                throw new ArgumentException($"Git command \"{lastBatchBuilder}\" always exceeded max length of {maxLength} characters.", nameof(arguments));
            }

            // Add last commandline batch
            if (!lastBatchBuilder.IsEmpty)
            {
                batches.Add(new BatchArgumentItem(lastBatchBuilder, currentBatchItemCount));
            }

            return(batches);
        }