/* source: C:\Program Files\msysgit\doc\git\html\git-status.html */ public static List<GitItemStatus> GetAllChangedFilesFromString(GitModule module, string statusString, bool fromDiff = false) { var diffFiles = new List<GitItemStatus>(); if (string.IsNullOrEmpty(statusString)) return diffFiles; /*The status string can show warnings. This is a text block at the start or at the beginning of the file status. Strip it. Example: warning: LF will be replaced by CRLF in CustomDictionary.xml. The file will have its original line endings in your working directory. warning: LF will be replaced by CRLF in FxCop.targets. The file will have its original line endings in your working directory.*/ var nl = new[] { '\n', '\r' }; string trimmedStatus = statusString.Trim(nl); int lastNewLinePos = trimmedStatus.LastIndexOfAny(nl); if (lastNewLinePos > 0) { int ind = trimmedStatus.LastIndexOf('\0'); if (ind < lastNewLinePos) //Warning at end { lastNewLinePos = trimmedStatus.IndexOfAny(nl, ind >= 0 ? ind : 0); trimmedStatus = trimmedStatus.Substring(0, lastNewLinePos).Trim(nl); } else //Warning at beginning trimmedStatus = trimmedStatus.Substring(lastNewLinePos).Trim(nl); } // Doesn't work with removed submodules IList<string> Submodules = module.GetSubmodulesLocalPathes(); //Split all files on '\0' (WE NEED ALL COMMANDS TO BE RUN WITH -z! THIS IS ALSO IMPORTANT FOR ENCODING ISSUES!) var files = trimmedStatus.Split(new char[] { '\0' }, StringSplitOptions.RemoveEmptyEntries); for (int n = 0; n < files.Length; n++) { if (string.IsNullOrEmpty(files[n])) continue; int splitIndex = files[n].IndexOfAny(new char[] { '\0', '\t', ' ' }, 1); string status = string.Empty; string fileName = string.Empty; if (splitIndex < 0) { status = files[n]; fileName = files[n + 1]; n++; } else { status = files[n].Substring(0, splitIndex); fileName = files[n].Substring(splitIndex); } char x = status[0]; char y = status.Length > 1 ? status[1] : ' '; if (x != '?' && x != '!' && x != ' ') { GitItemStatus gitItemStatusX = null; if (x == 'R' || x == 'C') // Find renamed files... { string nextfile = n + 1 < files.Length ? files[n + 1] : ""; gitItemStatusX = GitItemStatusFromCopyRename(fromDiff, nextfile, fileName, x, status); n++; } else gitItemStatusX = GitItemStatusFromStatusCharacter(fileName, x); gitItemStatusX.IsStaged = true; if (Submodules.Contains(gitItemStatusX.Name)) gitItemStatusX.IsSubmodule = true; diffFiles.Add(gitItemStatusX); } if (fromDiff || y == ' ') continue; GitItemStatus gitItemStatusY; if (y == 'R' || y == 'C') // Find renamed files... { string nextfile = n + 1 < files.Length ? files[n + 1] : ""; gitItemStatusY = GitItemStatusFromCopyRename(false, nextfile, fileName, y, status); n++; } else gitItemStatusY = GitItemStatusFromStatusCharacter(fileName, y); gitItemStatusY.IsStaged = false; if (Submodules.Contains(gitItemStatusY.Name)) gitItemStatusY.IsSubmodule = true; diffFiles.Add(gitItemStatusY); } return diffFiles; }