Git:如何在预提交挂钩中重新启动暂存文件

时间:2014-11-12 11:53:51

标签: git githooks git-stage

编写一个git pre-commit hook 该脚本可以重新格式化一些代码,因此它可以修改分阶段文件。

如何重新暂存已暂存的所有文件?

3 个答案:

答案 0 :(得分:7)

如果没有pre-commit hook上下文,您可以get a list of the staged files使用以下命令:

git diff --name-only --cached

因此,如果要重新索引已暂存的文件,可以使用:

git diff --name-only --cached | xargs -l git add

pre-commit hook上下文中,您应该关注the advices of David Winterbottom并将其他任何内容更改存储在其他内容之前。

此技术可让您不必担心索引或更改未暂存的更改。 因此,您不必播放所有已暂存的文件,而是所有已更新的文件:

# 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

答案 1 :(得分:6)

我喜欢@ tzi的回答;然而,在David Winterbottom的引文中,comments中出现了一个 edge 案例问题,您将失去一些提交历史记录。尽管如此,它并不像评论者所说的那样悲惨和悲观,对于有问题的人来说,这又是一个边缘案例。它发生在

  1. 您暂存文件(版本A)
  2. 在提交(版本B)
  3. 之前编辑同一文件
  4. 希望提交原始暂存文件(版本A)而不是修改后的文件(版本B)
  5. 如果您的提交失败,或者在提交之前成功并弹出存储,则会丢失原始暂存的文件(v.A),因为它从未提交并被覆盖(使用v.B)。显然不是灾难性的,你仍然有最新的编辑(v.B),但它可能会妨碍一些人的工作流程和(次优的)提交实践。为了避免这种情况,您只需检查脚本的退出并使用一些存储技巧恢复到原始状态(索引具有v.A且WD具有v.B)。

      

    预提交

    #!/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
    

    您还应该将git stash pop移动到提交后挂钩,因为这是在提交之前用修改后的文件(v.B)覆盖暂存文件(v.A)的内容。在实践中,您的脚本很可能不会失败,但即使如此,预提交挂钩中的git stash pop也会与脚本修改后的文件(v.A')和未分阶段的修改(v.B)产生合并冲突。这样就可以防止文件被提交了,但是你确实已经修改了你的脚本最初的暂存文件(v.A')和你的非暂存的分段后修改文件(v.B)(假设没有丢失任何重要的历史假设{{ 1}}只做诸如缩进之类的东西,所以v.A和v.A'几乎相同。)

    摘要:如果您在再次修改之前使用最佳做法并提交暂存文件,则原始答案最简单,最好。在我看来,如果你有不这样做的坏习惯,并且想要你的历史中的两个版本(分阶段和修改过),你需要小心(为什么这是一个不好的做法的争论)!无论如何,这可能是一个可能的安全网。

答案 2 :(得分:0)

可悲的是,我认为@NearHuscarl 上面的回答并没有完全削减它。这是我见过的最接近的,但是当您在提交后挂钩中弹出存储时,您仍然会引入合并冲突。这是因为隐藏的内容(即使带有 --keep-index 标志)既是未暂存的更改(我们想要的),也是在对它们运行自动格式化程序之前暂存的更改(我们不想要的)。这将在提交的自动格式化更改和原始尚未格式化的隐藏更改之间产生合并冲突。据我了解,没有简单的方法可以告诉 git 仅存储未暂存的更改。 --keep-index 标志隐藏未暂存的更改和暂存的更改,同时保留暂存的更改。这与默认行为的不同之处在于,分阶段的更改通常也会与未分阶段的更改一起隐藏。但它不会专门存储未暂存的更改,而这正是我们所需要的。

我很想犯错,但我很确定在 bash 中没有快速实施的解决方案。像任何问题一样,它当然是可以解决的,但它需要相当多的跑腿工作。 lint-staged 实际上非常优雅地处理了这个问题,但并非没有投入工作。 Here 是他们介绍此功能的 PR,here 是有关该问题的相应讨论。即使完成了所有这些工作,仍然存在一些边缘情况,即它们明确地使挂钩失败并将 WD 重置为其原始状态。他们不能总是保证他们不会引入冲突。

我的结论是:如果您正在处理一个 javascript 项目,请使用 lint-staged。如果您像我一样并且真的想坚持使用一个简单的 bash 脚本,那么在做任何其他事情之前检查是否有任何部分暂存的文件可能是值得的,并中止一条消息,告诉用户修复他们的部分暂存文件。在 lefthook 之类的东西引入此功能之前(问题 here),您的其他选择都非常令人发指。

但我希望有人证明我是错的。