git - git 提交分阶段更改的子集(按文件名)
问题描述
我有以下情况:
$ git status --porcelain
M A
M B
A C
D D
AM E
MM F
MM G
我只想提交F
和的分阶段更改G
。我不想为F
and提交未暂存的更改G
,我也不想为A
->提交任何更改E
。
不起作用的事情:
# commits all staged and F, G unstaged
git commit F G
# same as above
git commit -o F G
# commits all staged + unstaged F, G (basically same as above)
git commit -i F G
# interactively add more to the index, keeps all already staged
git commit -p
# as above but limits interactive choices to F, G unstaged changes
git commit -p F G
# almost, but stash pop results in merge conflicts for F, G
git stash -k
git commit F G
git stash pop
更新:我知道这可以通过额外的直接文件副本来完成。但我想要一些不那么手动的东西。
解决方案
您在这里所做的大多数事情都是相当手动的,包括所有git stash
方法,实际上只是从当前索引和当前工作树进行两次提交,然后使用git reset --hard
或等效将所有内容恢复到它在HEAD
. 来自的两个提交git stash
不在分支上,但可以稍后使用git stash apply
. 不过,这不是我会在这里做的。考虑首先手动执行此操作,然后(如果您经常执行此操作)将手动过程转换为脚本(参见下面的示例)。
一个关键是要注意只有一个可分辨索引(“the”索引),但您可以拥有其他索引文件。您可以拥有任意数量的临时索引文件。将环境变量设置为GIT_INDEX_FILE
不存在的文件名,例如:
export GIT_INDEX_FILE=$(realpath $(git rev-parse --git-dir))/index$$
(这取决于你的 shell 的 PID 创建一个唯一的文件名)或者:
tf=$(mktemp); rm -f $tf; export GIT_INDEX_FILE="$tf"
您现在在这个临时索引中没有任何内容。从当前提交填充它,使其与当前提交匹配:
git read-tree HEAD
所有文件现在都重新设置为匹配HEAD
. 现在是困难的部分:
I want to commit only the staged changes for F and G
这些是存储库中的 blob 和/或(主)索引中的模式更改。我们必须取消设置 GIT_INDEX_FILE 才能读取它们。我们可以在创建临时索引之前执行此操作,但现在执行此操作,我们可以使用取消设置环境变量的子 shell:
(unset GIT_INDEX_FILE && git ls-file --staged F G) | git update-index --index-info
现在,我们的临时索引中有文件F
和G
临时索引,为提交而暂存,我们可以在git commit
没有选项的情况下运行,或者使用-m
或类似的选项从这个临时索引提交。
做出新的提交后,您只需要取消设置GIT_INDEX_FILE
(尽管要清理,您还应该删除临时索引,rm -f $GIT_INDEX_FILE
)。如果您在脚本中执行所有这些操作,退出脚本(删除任何临时文件后)就足够了。
一个骨架脚本,未经测试,但考虑到可能的极端情况,如下所示:
#! /bin/sh
case $# in
0) echo "usage: git onlycommit file1 ... fileN"; exit 1;;
esac
# exit (and clean up) on error
set -e
tf=$(mktemp)
rm -f "$tf"
trap "rm -f \"$tf\"" 0 1 2 3 15
# if GIT_INDEX_FILE is already set, make our reset use that value;
# otherwise, make our reset just unset it
if [ "${GIT_INDEX_FILE+true}" = true ]; then
reset_index="export GIT_INDEX_FILE=\"${GIT_INDEX_FILE}"\"
else
reset_index="unset GIT_INDEX_FILE"
fi
export GIT_INDEX_FILE="$tf"
git read-tree HEAD
(eval $reset_index; git ls-files --staged "$@") | git update-index --index-info
git commit
这应该被测试,并且可能也很有趣,例如,它可能应该首先测试所有参数文件是否标记为“暂存提交”,即当前索引条目与HEAD
. 它可能还应该确保您没有处于冲突合并的中间,或者至少,所选文件不是。
如果您调用它git-onlycommit
并将其放入您的文件中,$PATH
您应该可以将其作为git onlycommit F G
.
推荐阅读
- flutter - 如何在所有页面中显示当前播放的视频,例如 udemy in flutter?
- reactjs - 使用 dockerised 前端和 dockerise 后端图像部署应用程序
- android - 在 .gradlew 命令行构建中找不到 dokka?
- time-complexity - 对于代码中的多个参数,O(M+N) 比 O(2N) 更正确的混淆
- c++ - 通过递归将两个数字相乘
- php - 如何在不使用内置函数的情况下反转 PHP 中的字符串?
- macos - 如何在 MacOS 上通过 ANGLE 使用集成显卡?
- c++ - 对作为数组给出的两个集合实现联合操作
- reactjs - componentDidUpdate 无法识别状态变化
- go - 如何更新 many2many 连接表中的自定义字段?