你可以在 git commit 期间更改文件内容吗?
Posted
技术标签:
【中文标题】你可以在 git commit 期间更改文件内容吗?【英文标题】:Can you change a file content during git commit? 【发布时间】:2013-05-25 18:07:21 【问题描述】:我在open novel in GitHub 中保留的内容之一是list of words 我想自动设置第一行,即字典中的单词数。我的第一个选择是编写一个预提交挂钩来读取文件、计算单词、重写第一行并再次将其写回。这是代码
PRE_COMMIT
my ($git) = @_;
my $branch = $git->command(qw/rev-parse --abbrev-ref HEAD/);
say "Pre-commit hook in $branch";
if ( $branch =~ /master/ )
my $changed = $git->command(qw/show --name-status/);
my @changed_files = ($changed =~ /\s\w\s+(\S+)/g);
if ( $words ~~ @changed_files )
my @words_content = read_file( $words );
say "I have $#words_content words";
$words_content[0] = "$#words_content\n";
write_file( $words, @words_content );
;
但是,由于文件已经暂存,我收到此错误
错误:您对以下文件的本地更改将被覆盖 通过结帐: 文本/words.dic 请提交您的更改或存储它们 在你可以切换分支之前。 中止
将其作为提交后挂钩并为下一次提交进行更改可能会更好吗?或者做一些完全不同的事情?一般的问题是:如果您想在提交期间处理和更改文件的内容,那么正确的做法是什么?
【问题讨论】:
提交日期见:***.com/questions/32699631/… 【参考方案1】:由git commit
卡住的实际提交是预提交挂钩完成后索引中的任何内容。这意味着您可以更改预提交挂钩中的文件,只要您也git add
他们。
这是我的预提交钩子示例,从 .sample 修改:
#!/bin/sh
#
# An example hook script to verify what is about to be committed.
# [snipped much of what used to be in it, added this --
# make sure you take out the exec of git diff-index!]
num=$(cat zorg)
num=$(expr 0$num + 1)
echo $num > zorg
git add zorg
echo "updated zorg to $num"
exit 0
然后:
$ git commit -m dink
updated zorg to 3
[master 76eeefc] dink
1 file changed, 1 insertion(+), 1 deletion(-)
但请注意一个小缺陷(不适用于您的情况):
$ git commit
git commit
updated zorg to 4
# On branch master
# Untracked files:
[snip]
nothing added to commit but untracked files present (use "git add" to track)
$ git commit
updated zorg to 5
# Please enter the commit message for your changes. Lines starting
[snip - I quit editor without changing anything]
Aborting commit due to empty commit message.
$ git commit
updated zorg to 6
# Please enter the commit message for your changes. Lines starting
基本上,因为预提交挂钩更新和git add
s,即使我实际上并没有在这里执行提交,文件也会不断增加。
[编辑 2021 年 8 月:我需要强调我不推荐这种方法。请注意,使用git commit -a
、git commit --include
和git commit --only
时可能会出现一些奇怪的情况,包括在命令行上命名文件时插入的隐含--only
。这是因为这种git commit
创建了第二个,有时甚至是第三个内部Git 索引。您在挂钩中执行的任何git add
操作只能影响这两个或三个索引文件中的一个。]
【讨论】:
所以基本上它是一个不同的黑客,对吧?以我的方式更改文件,但直到下一个文件才提交 是的。我不确定我对这两种方法是否真的很满意。我宁愿有像 Makefile 这样的东西来根据需要更新东西,还有一些更手动的东西。但它应该可以工作。 您可以在实际提交后让您的脚本执行commit -a --amend
。
这对我来说似乎不太安全。工作树与索引发生变化是可能的,而且并不少见。如果你使用 git add,你会将工作树中的任何状态添加到索引中,这是不可取的。
@toolforger:我已经在多个 SO 答案中详细描述了这一点:例如,here、here 和 here。 git commit
中的这段代码在过去十年中有所发展,细节没有记录,因此可能会发生变化,所以不要过分依赖任何一种特定的行为。【参考方案2】:
事实证明,您可以运行“钩子”——它们实际上是由另一种机制处理的——当 staging 文件时(git add
时间):
https://git-scm.com/book/en/v2/Customizing-Git-Git-Attributes#_keyword_expansion
(向下滚动到“涂抹”和“清洁”图表)
这是我的理解:
编辑.gitattributes
,并为应该触发字典更新的文件创建规则:
novel.txt filter=updateDict
然后,告诉 Git updateDict
过滤器对 smudge (git checkout) 和 clean (git add) 做了什么:
$ git config --global filter.updateDict.clean countWords.script
$ git config --global filter.updateDict.smudge cat
【讨论】:
以上是关于你可以在 git commit 期间更改文件内容吗?的主要内容,如果未能解决你的问题,请参考以下文章