问题
I'm writting a git pre-commit hook.
The script could reformat some code, so it could modify the staged files.
How can I re-stage all files that are already staged ?
回答1:
Without the pre-commit hook
context, you can get a list of the staged files with the following command:
git diff --name-only --cached
So if you want to re-index the staged files, you can use:
git diff --name-only --cached | xargs -l git add
In the pre-commit hook
context, you should follow the advices of David Winterbottom and stash unstaged changes before anything else.
This technique allows you not to be worry about indexing, or alterate, a change that was not staged. So you don't have to stage all the staged files, but all the updated files:
# Stash unstaged changes
git stash -q --keep-index
# Edit your project files here
...
# Stage updated files
git add -u
# Re-apply original unstaged changes
git stash pop -q
回答2:
I liked @tzi's answer; however, in David Winterbottom's quoted article there is a edge case concern raised in the comments in which you will lose some commit history. Though, it's not as doom and gloom as the commenter makes it sound, and again is an edge case for people with problematic practices. It happens when
- You stage a file (version A)
- Edit the same file before committing (version B)
- Wished to commit the originally staged file (version A) and not the modified one (version B)
If your commit fails, or succeeds and pops the stash before a committing, you lose your originally staged file (v. A), as it was never commit and is overwritten (with v. B). Obviously not catastrophic, and you still have the latest edit (v. B), but it might hamper some people's workflows and (suboptimal) committing practices. To avoid this you just check the exit of your script and work some stashing tricks to revert to the original state (index has v. A and WD has v. B).
pre-commit
#!/bin/sh
... # other pre-commit tasks
## Stash unstaged changes, but keep the current index
### Modified files in WD should be those of INDEX (v. A), everything else HEAD
### Stashed was the WD of the original state (v. B)
git stash save -q --keep-index "current wd"
## script for editing project files
### This is editing your original staged files version (v. A), since this is your WD
### (call changed files v. A')
./your_script.sh
## Check for exit errors of your_script.sh; on errors revert to original state
## (index has v. A and WD has v. B)
RESULT=$?
if [ $RESULT -ne 0 ]; then
git stash save -q "original index"
git stash apply -q --index stash@{1}
git stash drop -q; git stash drop -q
fi
[ $RESULT -ne 0 ] && exit 1
## Stage your_script.sh modified files (v. A')
git add -u
You should also move the git stash pop
to the post-commit hook, as this is what overwrite the staged file (v. A) with the modified file (v. B) prior to committing. In practice mostly likely your script doesn't fail, but even so your git stash pop
in the pre-commit hook creates a merge conflict with your script modified files (v . A') and your unstaged modifications (v. B). This then prevents the file from being committed at all, but you do have your script modified originally staged file (v. A') and your unstaged post-staging modified file(v. B) (arguably not losing any significant history assuming your_script.sh
only does stuff such as indenting so v. A and v. A' are pretty much the same).
Summary: If you use best practices and commit staged files before modifying them again, the original answer is easiest and great. If you have, in my opinion, bad habits of not doing so and wanting both versions (staged and modified) in your history, you need to be careful (an argument for why this is a bad practice)! In any case, this could be a possible safety net.
来源:https://stackoverflow.com/questions/26886363/git-how-to-re-stage-the-staged-files-in-a-pre-commit-hook