bash 用于检查 git 更改然后遍历更改的文件的 Shell 脚本?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 
原文地址: http://stackoverflow.com/questions/13715544/
Warning: these are provided under cc-by-sa 4.0 license.  You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Shell script to check git for changes and then loop through changed files?
提问by startupsmith
I am trying write a shell script that does the following:
我正在尝试编写一个执行以下操作的 shell 脚本:
- Checks the remote git repository for any changes to pull.
- If there are changes in the remote git repository pull those changes.
- Loops through the files that are new or have been modified.
- 检查远程 git 存储库是否有任何要拉取的更改。
- 如果远程 git 存储库中有更改,请拉取这些更改。
- 循环访问新的或已修改的文件。
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.
通过我的研究,我找到了一些必要的命令来执行这些操作,但我无法让它们在 shell 脚本中协同工作。
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:
我无法使用此脚本中的命令的事情是:
- The if statement to check if there are changes or not always is true. I have tried if statements with other git commands and they also are always true. It seems that git does not work like normal shell commands where you get a 0 or 1 response. How can I get a git command like this or other git commands to return the right responses in an if statement?
- How can I assign the variables output from the command to see the changed files to an array so that I can loop through them using a for?
- 用于检查是否有更改的 if 语句始终为真。我已经尝试过使用其他 git 命令的 if 语句,它们也总是正确的。似乎 git 不像普通的 shell 命令那样工作,你会得到 0 或 1 响应。如何获得这样的 git 命令或其他 git 命令以在 if 语句中返回正确的响应?
- 如何将命令的变量输出分配以查看更改的文件到数组,以便我可以使用 for 循环遍历它们?
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.
编辑:对不起,当我遍历更改的文件时应该更清楚我需要在遍历文件之前从远程存储库中提取更改,以便在处理这些文件时获得最新的更改。
采纳答案by Brian Campbell
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 --quietimplies --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:
对于您的第一个问题,您可以使用git diff --quiet(or git diff --exit-code,但通常当您将其用于退出代码时,您希望它无论如何都不要打印输出,并git diff --quiet暗示--exit-code) 来确定是否有任何更改。如果有更改,这将为您提供 1 值,如果没有,则为 0。因此,如果您希望代码仅在发生更改时运行:
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:
对于您的第二个问题,我建议使用while read ...循环从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 $srcmodewill have an extra :at the beginning, and $dstfilewill 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.
请注意,开头$srcmode会有一个额外的值:,并且$dstfile只有在文件被重命名时才会有一个值。如果您不想担心重命名,请传入--no-renames,而不是看到重命名,您只会看到添加和删除。
回答by RousseauAlexandre
You can simply use git diff --name-onlyto list all filenames of files changed.
您可以简单地使用git diff --name-only列出已更改文件的所有文件名。
For example, here a simple script to list all PHP files edited and test the syntax.
例如,这里有一个简单的脚本来列出所有编辑过的 PHP 文件并测试语法。
#!/bin/bash
files=`git diff --name-only | grep -E '.php$' `
for file in $files; do
  php -l $file
done
回答by Mark Reed
You're right, gitdoes 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:
你是对的,git除非出现错误,否则通常不会以非零状态退出。我发现检测未提交更改的最简单方法是这样的:
 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 --porcelainon 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.
一般来说,如果您要尝试从代码驱动 git,您应该使用--porcelain支持它的子命令,使其以更自动化友好的方式运行。您可能还想研究其他语言的库以与 git 交互,而无需构建自己的 shell 命令;例如,在 Ruby 中有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 diff-tree. 类似上面的逻辑:
 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
回答by Michael Cole
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:
如果您正在编写脚本并希望确保 repo 处于已提交状态(例如,没有新的、修改的或暂存的文件),请尝试以下操作:
``` bash
# 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.
这是我能找到的最简单的检查新文件、更改文件和暂存文件的方法。

