I'm writing a simple pre-commit git hook that updates the year in copyright headers for files that are staged for commit.
After modifying the line with the copyright, I would like the hook to stage that line so that it is part of the commit. It can't just git add
the whole file, because there may be other pre-existing changes in there that shouldn't be staged.
I don't see any options in the git add
manual the let you stage specific lines.
I figure I could git stash save --keep-index
, apply my change, git add
the file, and then git stash pop
, but that seems rather crude. Any better approaches?
For those who use Git Extensions: In the Commit window, select the file you want to partially commit, then select the text you want to commit in the right pane, then right-click on the selection and choose 'Stage selected lines' from the context menu.
git add -p is basically "git add partial (or patch)" Patch mode allows you to stage parts of a changed file, instead of the entire file. This allows you to make concise, well-crafted commits that make for an easier to read history.
Here's another possible solution:
Before running your copyright-modification script, do a git status
to get a list of the files it's about to commit. Save the list of files. Do a commit.
Then, stash the rest of the (unrelated) changes, and apply your script to the list of files saved above. Use git commit --amend
to change the previous commit.
Finally, pop the stash to restore your index. Resolve conflicts if required.
I don't know of a way to tell git add
to add only specific lines. How would you describe the lines to add? By line number? It seems that might be possible in a narrow set of circumstances, and not generally useful.
You could patch the staged version of the file in a separate step, e.g.
blobid=$(git show :"$filepath" | copyright-filter | git hash-object -w --stdin)
if $? -eq 0; then
git update-index --cacheinfo 100644 "$blobid" "$filepath" &&
copyright-filter "$filepath"
fi
I've shamelessly assumed that your script is called copyright-filter
and works as a filter or in place, depending on its arguments.
Looking at the source to git add --interactive
it looks like the way it modifies the index is with git apply --cached
. Assuming your copyright is the first hunk of any diff, make the change and use:
git diff -- file |
awk 'second && /^@@/ {exit} /^@@/ {second=1} {print}' |
git apply --cached
Where that second line (the awk
script grabs only the first diff hunk). You could also construct the diff output by hand or use other rules to select the hunk.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With