Git Tip: Find All Changed Files

One way to speed VI Analyzer or Blue is to only run it on changed files. Here is a way to do that.

Git Tip: Find All Changed Files

Here is a little quick Git Tip for you all. You might find it useful for CI/CD workflows or for running things like VI Analyzer or Blue. Hope you enjoy it.

The Problem We Are Trying To Solve

Tools like VI Analyzer or Blue can be quite useful. However, they take time to run and that scales with the number of files you analyze. Also in the context of using Git, you don't want to just change an entire directory of files. While it can be tempting to run VI Analyzer or Blue on your entire codebase, changing a large number of files increases the risk of merge conflicts. A better strategy is to only run it on files you have already changed, so you aren't adding any new conflicts that don't already exist. Running on just the changed files increases the speed of feedback and avoids unnecessary merge conflicts.

The Solution

The solution is to get a list of files that have changed either in your working copy or since you diverged from a particular branch and then use xargs to pass that to either Blue or VIAN.

Here are some bash commands to help with that. Add this function to your .bashrc file or ci script.

# Add this to your .bashrc or a script
function git_changed() {(git diff --name-only --diff-filter=MA $(git merge-base --fork-point $1); git ls-files --others --exclude-standard)}

# now you can do the following
# this will run blue on all changed files in your working directory

 git_changed HEAD | xargs -rd '\n' g-cli blue --

 # If you were on the main branch and wanted to run it on all files that have changed since the last time you had pushed, you can use this

 git_changed origin/main | xargs -rd '\n' g-cli blue --

Explanations

function git_changed() { "some code" }

This line creates a function called git_changed that when called executes "some code". In this particular case, you pass the function the name of a branch or HEAD and it returns a list of all files that have changed since you diverged from that branch or in the case of HEAD just the changes in your working copy. If you define this in your bashrc file then any time you open a new terminal you have access to that function. If you define it inside a shell script, then you can call it from anywhere below that in the file.

$(git merge-base --fork-point $1)

This returns the last commit in common with $1. $1 is the first argument passed to the git_changed function. Say you are on a feature branch and pass in "develop" as the argument, you'll get the last commit on develop before you went off on your feature branch.

git diff --name-only --diff-filter=MA SOMECOMMIT

This lists the names of all the files that have changed (M) or been added (A) since SOMECOMMIT. It lists one relative path per line.

git ls-files --others --exclude-standard

This grabs new files that have not yet been added to Git. ie. You've created a new subVI and saved it but have not added it to Git yet. Exclude standard tells Git to ignore anything in the ignore file like it normally would. Again you get 1 relative path per line.

( command1; command2;)

This construct concatenates the outputs of command1 and command2. In this case it concatenates the results of the git diff with the results of the git ls-files This results in a list of relative paths to each file that has either changed or been newly created.

| xargs -rd '\n' COMMAND

This part takes the output of the command before the pipe - in this case, the list of changed files and uses xargs to pass each file as an argument to COMMAND. In this case the command is g-cli blue -- You can add g-cli or blue options there if you want, or call a completely different g-cli command or even a non-g-cli command. The -rd '\n' is needed to get the formatting right - this accounts for potential spaces in the filenames.

NOTE

Sometimes you'll get line ending warnings from Git if you have autocrlf on. If so, the following command will turn those off.

git config --global core.safecrlf false

Conclusion

This may be down in the weeds, but hopefully there is at least one person out there who will benefit from this. If nothing else I'll benefit from it next time I want to run Blue or VIAN on just the changed files.