Functions/GenXdev.Coding.Git/Get-GitChangedFiles.cs
// ################################################################################
// Part of PowerShell module : GenXdev.Coding.Git // Original cmdlet filename : Get-GitChangedFiles.cs // Original author : René Vaessen / GenXdev // Version : 1.302.2025 // ################################################################################ // Copyright (c) René Vaessen / GenXdev // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // ################################################################################ using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Management.Automation; namespace GenXdev.Coding.Git { /// <summary> /// <para type="synopsis"> /// Get the list of changed files in a Git repository. /// </para> /// /// <para type="description"> /// This function retrieves the list of files that have been changed in the current Git repository. /// It can be used to identify which files have been modified, added, or deleted. /// By default, returns relative paths with .\ prefix. Use -PassThru to get FileInfo objects. /// </para> /// /// <para type="description"> /// PARAMETERS /// </para> /// /// <para type="description"> /// -PassThru <SwitchParameter><br/> /// Returns FileInfo objects (like Get-ChildItem) instead of path strings.<br/> /// - <b>Aliases</b>: None<br/> /// - <b>Position</b>: Named<br/> /// - <b>Default</b>: False<br/> /// </para> /// /// <example> /// <para>Get changed files as relative paths</para> /// <para>Returns relative paths like ".\Modules\GenXdev.AI\1.302.2025\README.md"</para> /// <code> /// Get-GitChangedFiles /// </code> /// </example> /// /// <example> /// <para>Get changed files as FileInfo objects</para> /// <para>Returns FileInfo objects for each changed file</para> /// <code> /// Get-GitChangedFiles -PassThru /// </code> /// </example> /// </summary> [Cmdlet(VerbsCommon.Get, "GitChangedFiles")] [OutputType(typeof(string), typeof(PSObject))] [Alias("gitchanged")] public class GetGitChangedFilesCommand : PSGenXdevCmdlet { /// <summary> /// Returns FileInfo objects (like Get-ChildItem) instead of path strings. /// </summary> [Parameter( Mandatory = false, HelpMessage = "Returns FileInfo objects (like Get-ChildItem) instead of path strings.")] public SwitchParameter PassThru { get; set; } /// <summary> /// Begin processing - initialization logic /// </summary> protected override void BeginProcessing() { } /// <summary> /// Process record - main cmdlet logic /// </summary> protected override void ProcessRecord() { // Ensure the current directory is a Git repository var isGitRepoResult = InvokeCommand.InvokeScript("git rev-parse --is-inside-work-tree"); if (isGitRepoResult == null || !isGitRepoResult.Any() || !"true".Equals(isGitRepoResult.First().ToString().Trim(), StringComparison.OrdinalIgnoreCase)) { WriteError(new ErrorRecord( new InvalidOperationException("This command must be run inside a Git repository."), "NotInGitRepository", ErrorCategory.InvalidOperation, null)); return; } // Get the list of changed files var changedFilesResult = InvokeCommand.InvokeScript("git diff --name-only HEAD"); if (changedFilesResult == null || !changedFilesResult.Any()) { WriteObject("No changed files found."); return; } var changedFiles = changedFilesResult .Select(obj => obj.ToString().Trim()) .Where(file => !string.IsNullOrEmpty(file)) .ToList(); foreach (var file in changedFiles) { if (PassThru) { // Return FileInfo object like Get-ChildItem would var fileExistsResult = InvokeCommand.InvokeScript($"Test-Path -LiteralPath '{file}'"); if (fileExistsResult != null && fileExistsResult.Any() && "True".Equals(fileExistsResult.First().ToString(), StringComparison.OrdinalIgnoreCase)) { var fileInfoResult = InvokeCommand.InvokeScript($"Get-Item -LiteralPath '{file}'"); if (fileInfoResult != null && fileInfoResult.Any()) { WriteObject(fileInfoResult.First()); } } else { // For deleted files, we can't get FileInfo, so return a custom object var customObject = new PSObject(); customObject.Properties.Add(new PSNoteProperty("Name", Path.GetFileName(file))); customObject.Properties.Add(new PSNoteProperty("FullName", null)); customObject.Properties.Add(new PSNoteProperty("RelativePath", file)); customObject.Properties.Add(new PSNoteProperty("Exists", false)); WriteObject(customObject); } } else { // Return relative path with .\ prefix var relativePath = ".\\" + file.Replace('/', '\\'); WriteObject(relativePath); } } } /// <summary> /// End processing - cleanup logic /// </summary> protected override void EndProcessing() { } } } |