你可以在 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 adds,即使我实际上并没有在这里执行提交,文件也会不断增加。

[编辑 2021 年 8 月:我需要强调我推荐这种方法。请注意,使用git commit -agit commit --includegit 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 期间更改文件内容吗?的主要内容,如果未能解决你的问题,请参考以下文章

查看commit修改的内容

git 本地文件内容更改以后怎么同步到远程仓库

如何更改某个提交内容/如何把当前改动追加到某次commit上

Git 学习记录

git 修改已提交的 commit

是否可以更改 git 上的提交日期? [复制]