Hou*_*ell 24 git git-stash githooks
我正在尝试使用一系列单元测试进行预提交钩子,我想确保我的工作目录是干净的.编译需要很长时间,所以我希望尽可能利用重用编译的二进制文件.我的脚本遵循我在网上看到的例子:
# Stash changes
git stash -q --keep-index
# Run tests
...
# Restore changes
git stash pop -q
Run Code Online (Sandbox Code Playgroud)
这会导致问题.这是repro:
// Step 1到a.javagit add .// Step 2到a.javagit commit
git stash -q --keep-index #存储更改git stash pop -q #恢复更改此时我遇到了问题.该git stash pop -q显然有冲突,a.java我有
// Step 1
<<<<<<< Updated upstream
=======
// Step 2
>>>>>>> Stashed changes
Run Code Online (Sandbox Code Playgroud)
有没有办法让这个流畅干净?
tor*_*rek 33
有 - 但让我们以略微迂回的方式到达那里.(另请参阅下面的警告:隐藏代码中存在一个我认为非常罕见的错误,但显然有更多人遇到此问题.)
git stash save(默认操作git stash)进行至少有两个父项的提交(请参阅这个关于存储的更基本问题的答案).该stash承诺是工作树的状态,而第二父提交stash^2是索引状态在藏匿的时间.
在保存之后(假设没有-p选项),脚本git stash是一个shell脚本 - 用于git reset --hard清除更改.
使用时--keep-index,脚本不会以任何方式更改已保存的存储.相反,在git reset --hard操作之后,脚本使用额外git read-tree --reset -u消除工作目录更改,将其替换为存储的"索引"部分.
换句话说,它几乎就像在做:
git reset --hard stash^2
Run Code Online (Sandbox Code Playgroud)
除了那git reset也会移动分支 - 根本不是你想要的,因此read-tree改为方法.
这是您的代码重新出现的地方.您现在可以# Run tests查看索引提交的内容.
假设一切顺利,我假设您希望将索引恢复到它执行时的状态git stash,并使工作树恢复到其状态.
使用git stash apply或者git stash pop,这样做的方法是使用--index(--keep-index不仅仅是为了存储创建时间,告诉存储脚本"在工作目录上打击").
只是使用--index仍然会失败,因为--keep-index重新将索引更改应用于工作目录.所以你必须首先摆脱所有这些变化......并且要做到这一点,你只需要(重新)运行git reset --hard,就像之前的存储脚本本身一样.(也许你也想要-q.)
所以,这是最后# Restore changes一步:
# Restore changes
git reset --hard -q
git stash pop --index -q
Run Code Online (Sandbox Code Playgroud)
(我将它们分开为:
git stash apply --index -q && git stash drop -q
Run Code Online (Sandbox Code Playgroud)
我自己,只是为了清晰,但pop意志做同样的事情).
如下面的评论所述,如果初始步骤没有找到保存更改,则最终会git stash pop --index -q抱怨(或者更糟糕的是,恢复旧存储)git stash save.因此,您应该通过测试来保护"恢复"步骤,以查看"保存"步骤是否实际隐藏了任何内容.
git stash --keep-index -q当它什么都不做的时候,最初只是静静地退出(状态为0),所以我们需要处理两种情况:在保存之前或之后不存在存储; 并且,在保存之前存在一些存储,并且保存没有做任何事情,因此旧的现有存储仍然是存储堆栈的顶部.
我认为最简单的方法是git rev-parse找出哪些refs/stash名称,如果有的话.所以我们应该让脚本读取更像这样的东西:
#! /bin/sh
# script to run tests on what is to be committed
# First, stash index and work dir, keeping only the
# to-be-committed changes in the working directory.
old_stash=$(git rev-parse -q --verify refs/stash)
git stash save -q --keep-index
new_stash=$(git rev-parse -q --verify refs/stash)
# If there were no changes (e.g., `--amend` or `--allow-empty`)
# then nothing was stashed, and we should skip everything,
# including the tests themselves. (Presumably the tests passed
# on the previous commit, so there is no need to re-run them.)
if [ "$old_stash" = "$new_stash" ]; then
echo "pre-commit script: no changes to test"
sleep 1 # XXX hack, editor may erase message
exit 0
fi
# Run tests
status=...
# Restore changes
git reset --hard -q && git stash apply --index -q && git stash drop -q
# Exit with status from test-run: nonzero prevents commit
exit $status
Run Code Online (Sandbox Code Playgroud)
git stash写"藏匿袋"的方式有一个小错误.索引状态存储是正确的,但假设您执行以下操作:
cp foo.txt /tmp/save # save original version
sed -i '' -e '1s/^/inserted/' foo.txt # insert a change
git add foo.txt # record it in the index
cp /tmp/save foo.txt # then undo the change
Run Code Online (Sandbox Code Playgroud)
git stash save在此之后运行时,index-commit(refs/stash^2)具有插入的文本foo.txt.工作树commit(refs/stash)应该foo.txt没有额外插入的东西的版本.但是,如果你看一下它,你会发现它有错误的(索引修改的)版本.
上面的脚本用于--keep-index将工作树设置为索引,这一切都非常好,并且正确运行测试.运行测试后,它用于git reset --hard返回HEAD提交状态(这仍然完全正常)...然后它用于git stash apply --index恢复索引(工作)和工作目录.
这是它出错的地方.从静默索引提交(正确)恢复索引,但是从存储工作目录提交恢复工作目录.此工作目录提交具有foo.txt索引中的版本.换句话说,最后一步cp /tmp/save foo.txt- 解除了变化,一直没有完成!
(stash脚本中的错误发生是因为脚本将工作树状态与HEAD提交进行比较,以便在创建stash-bag的特殊work-dir提交部分之前计算要在特殊临时索引中记录的文件集.foo.txt对于特殊的临时索引HEAD,它没有改变git add.特殊的工作树提交是用index-commit的版本进行的foo.txt.修复非常简单,但是没有人把它放到官方git中呢? ].
并不是说我想鼓励人们修改他们的git版本,但这是修复.)
| 归档时间: |
|
| 查看次数: |
5577 次 |
| 最近记录: |