Reputation: 5764
I am trying write a shell script that does the following:
Through my research I have found some of the necessary commands to do these things but I haven't been able to get them to work together in a shell script.
Here is a script with some of the commands that I have:
#!/bin/sh
#Check if there are any changed files
git --git-dir="/dir/.git" fetch origin
if git --git-dir="/dir/.git" log HEAD..origin/master --oneline
then
#Output the modified files from the last pull
git --git-dir="/dir/.git" diff --name-status ORIG_HEAD..
fi
The things that I have not been able to get working with the commands in this script are:
If the commands in my script won't really work in this case what is a better way to do this?
Edit: Sorry should have been more clear when I loop through the changed files I need to pull the changes from the remote repository before I loop through the files so that when I work with these files I have the latest changes.
Upvotes: 23
Views: 34319
Reputation: 16257
If you're scripting and want to make sure the repo is in a committed state (e.g. no new, modified, or staged files), try this:
# Get to code. Exit if unsaved changes in repo
if `git status | grep -q "nothing to commit"`; then
git checkout --quiet $BRANCH || exit 1
else
echo "ERROR: repo has unsaved changes"
exit 1
fi
This is the simplest thing I could find that checked for new, changed, and staged files.
Upvotes: 3
Reputation: 2860
You can simply use git diff --name-only
to list all filenames of files changed.
For example, here a simple script to list all PHP files edited and test the syntax.
#!/bin/bash
files=`git diff --name-only | grep -E '.php$' `
for file in $files; do
php -l $file
done
Upvotes: 13
Reputation: 95385
You're right, git
does not normally exit with nonzero status unless there's an error. The easiest way I've found to detect uncommitted changes is something like this:
let changes=0
while read status filename; do
let changes=1
# do something with this filename/status
done < <(git status --porcelain)
if (( ! changes )); then
echo "No changes."
fi
In general, if you're going to try to drive git from code, you should use --porcelain
on those subcommands which support it, to make it act in a more automation-friendly fashion. You may also want to investigate libraries for other languages to interact with git without constructing your own shell commands; for instance, in Ruby there's grit.
Now, in your case, you want to detect what changed upstream. For that, you probably want to use git diff-tree
. Similar logic to the above:
git fetch # not pull
while read filename; do
# do something with filename
done < <(git diff-tree --name-only origin/master master) # or whatever branch you're using
Upvotes: 3
Reputation: 333314
For your first question, you can use git diff --quiet
(or git diff --exit-code
, but generally when you're using it for its exit code you want it not to print output anyhow, and git diff --quiet
implies --exit-code
) to determine if there have been any changes. That will give you a 1 value if there are changes, and a 0 if there are not. So if you want to have code that will run only if there are changes:
if ! git --git-dir="/dir/.git" diff --quiet
then
# do stuff...
fi
For your second question, I'd recommend a while read ...
loop to read lines from git diff-tree
:
git --git-dir="/dir/.git" diff-tree ORIG_HEAD.. | \
while read srcmode dstmode srcsha dstsha status srcfile dstfile
do
# do something with $srcfile and $dstfile
done
Note that $srcmode
will have an extra :
at the beginning, and $dstfile
will only have a value if the file was renamed. If you don't want to worry about renames, pass in --no-renames
, and instead of seeing renames you'll see just the adds and deletes.
Upvotes: 18