git 多个中转区

ikfrs5lh  于 2023-02-28  发布在  Git
关注(0)|答案(2)|浏览(116)

我可以有多个暂存区或者使用git达到类似的效果吗?
我的典型工作流程沿着:

  • 工作,工作,工作
  • 现在我有了一个有用的想法,让我们提交它git add -pyy
  • 但首先是一些小的风格变化git reset HEAD .
  • 第一个四个一个x、第一个五个一个x、第一个六个一个x、第一个七个一个x、第一个八个一个x、第一个九个一个x
  • git add -p ..提交实际内容

有时候,我需要从一大堆修改中提交20个小的修改,如果我可以运行像git add -p这样的补丁,然后将每个补丁“分派”到它自己的暂存区,并分别提交每个区域,这将保存我一天的时间。

jm81lzqq

jm81lzqq1#

编辑,2020年5月30日:在Git 2.15或更高版本中,我建议使用git worktree,而不要尝试下面的操作。对于添加的工作树有一些限制,这使得它们在这种工作流中有点烦人,但它 * 可以 * 工作,并且内置在现代Git中。

请注意,如果你做了我下面描述的事情,git gc就不会知道要检查你的备用索引文件,事实上,从Git 2.5最初引入到Git 2.15中修复,git gc都忘记检查添加的工作树及其索引文件了!
更多信息请参见VonC's answer
事实上,在git中你可以有多个不同的暂存区(更确切地说,是多个索引文件),为了达到你想要的效果,无论如何你都必须编写自己的git add -p变体,所以我在这里要做的是勾画一个大纲,可以说是如何做到这一点。
默认的索引文件--如果你不把它指向其他索引文件,git会使用它--位于.git/index(或者,更准确地说,shell是$GIT_DIR/.index$GIT_DIR取自环境,如果没有设置,则取自git rev-parse --git-dir)。
但是如果你设置了环境变量GIT_INDEX_FILE,git会使用该文件作为索引,因此,你可以这样开始你的“分散修改到四个分支”过程:

GIT_DIR=${GIT_DIR:-$(git rev-parse --git-dir)} || exit 1
index_tmp_dir=$(mktemp -d) || exit 1
trap "rm -rf $index_tmp_dir" 0 1 2 3 15 # clean up on exit

# make four copies of initial staging area
for f in i1 i2 i3 i4; do
    cp $GIT_DIR/index $index_tmp_dir/$f
done

# THIS IS THE HARD PART:
# Now, using `git diff-files -p` or similar, get patches
# (diff hunks).
# Whenever you're ready to stage one, pick an index for it,
# then use:
GIT_INDEX_FILE=$index_tmp_dir/$which git apply --cached < diffhunk

# Once done, commit each index file separately with some
# variation on:
for f in i1 i2 i3 i4; do
    GIT_INDEX_FILE=$index_tmp_dir/$which git commit
done

对于标为“困难部分”的部分,你最好的选择是复制git的add-interactive perl脚本,在$(git --exec-path)/git-add--interactive中找到,然后修改它以适应.要移除“恰好四次提交”的限制,让这个修改过的interactive-add动态地创建一个新的索引文件(通过复制原始的,或者创建一个等于HEAD提交的“空”索引或其他什么;也参见X1 M11 N1 X)。
编辑:some variation on 部分几乎肯定应该使用git write-treegit commit-tree从这些提交中创建 new branches,使用当前提交的父提交作为它们的父提交,而不是允许git commit将这些提交串成一个线性链,这意味着还必须为这些新创建的分支选择一些命名方案。

63lcw9qa

63lcw9qa2#

Git 2.5 introduced git worktree,它允许一个克隆,多个工作树,在其中您可以隔离您的各种修改。
但是现在(2019年第四季度),你不能再修改git-add--interactive.perl了,因为在Git 2.25(2020年第一季度)中,"git add -i"已经被扩展到了"patch"之外的子命令。
(That重写在Git 2.37,Q3 2022中正式完成并设置为默认值(见上一节)。
请参见第Johannes Schindelin ( dscho )页的第commit 2e697ce页、第commit d763357页、第commit 8746e07页、第commit ab1e1cc页、第commit c54ef5e页、第commit a8c45be页、第commit f37c226页、第commit c08171d页、第commit 0c3944a页(2019年11月29日)。
(由Junio C Hamano -- gitster --合并至commit 3beff38,2019年12月16日)

built-in add -i:执行patch命令

签署人:约翰内斯·申德林
当然,它还不是一个完整的实现,为了使它易于检查(并且易于防止bug),我们仍然将实际工作交给Perl脚本。
patch的功能实际上占了git-add--interactive.perl的1,800多行代码的一半以上,稍后将逐步从Perl移植到C。
还是在用C语言重写git add的上下文中:更多测试覆盖率更新,为"git add -i"的进一步工作做准备。
请参见第一版第十四页、第一版第十五页、第一版第十六页、第一版第十七页、第一版第十八页、第一版第十九页、第一版第二十页(2019年12月6日)。
(由Junio C Hamano -- gitster --合并至commit 011fc2e,2019年12月16日)

git add -p:当diff生成失败时使用非零退出代码

签署人:约翰内斯·申德林
git add -p做的第一件事是生成一个diff,如果不能生成这个diff,git add -p就不应该像什么都没发生一样继续,而是失败。
我们在这里 * 实际 * 做的事情要广泛得多:我们现在针对 * 每个 * run_cmd_pipe()调用验证所产生的进程实际上成功。
请注意,我们必须更改此补丁中的两个调用程序,因为我们需要将派生进程的输出存储在一个局部变量中,这意味着调用程序无法再决定是在数组还是标量上下文中解释return <$fh>
在为diff. algorithm特性编写测试用例时注意到了这个bug,我们也将该测试用例作为这个已修复bug的回归测试。
随着Git 2.25(2020年第一季度)的发布,将"git-add--interactive"迁移到C语言的努力仍在继续。
请参见commit 2e40831commit 54d9d9bcommit ade246ecommit d6cf873commit 9254bdfcommit bcdd297commit b38dd9ecommit 11f2c0dcommit 510aecacommit 0ecd9d2commit 5906d5dcommit 47dc4fdcommit 80399aecommit 7584dd3commit 12c24cfcommit 25ea47acommit e3bd11b、第一年第四十二次、第一年第四十三次(2019年12月13日)和第一年第四十四次。
(由Junio C Hamano -- gitster --合并至commit 45b96a6,2019年12月25日)

built-in add -p:实现块编辑

签署人:约翰内斯·申德林
就像git add --edit允许用户在应用到索引之前编辑diff一样,这个特性允许用户编辑diff * hunk *。
当然,这里会变得有点复杂,因为结果必须与整个diff的剩余块很好地匹配。因此,我们必须做一个循环,让用户编辑块,然后测试结果是否有效,如果无效,则放弃编辑,让用户决定是否再次尝试编辑块。
注:与Perl版本不同,我们也使用相同的diff "coalescing"(即将重叠的块合并为一个)来进行编辑后的检查,并且我们为此引入了一个新的标志,要求reassemble_patch()函数假装所有块都被选中使用。
这允许我们继续运行git apply * 而不使用 * --allow-overlap选项(与Perl版本不同),并且它还修复了t3701-add-interactive.sh中的两个已知的损坏(到目前为止,我们还不能将其标记为已解决,因为Perl脚本版本仍然是默认版本,并且仍然存在这些损坏)。
以及:

built-in add -p:分裂后合并块

签署人:约翰内斯·申德林
这被认为是"正确的做法",根据933e44d3a0("add -p":解决一个老的懒惰,不合并大块,2011 - 04 - 06,Git v1.7.5.2).
注意:我们不能在合并的时候简单地修改块;一旦我们实现了块体编辑,每当块体被编辑时,我们将调用reassemble_patch(),因此我们不能修改块体(因为用户可能会点击K并改变他们是否暂存前一个块体的想法)。
以及:

built-in add -i:开始在C中实现patch功能

签署人:约翰内斯·申德林
在前面的步骤中,我们用C语言重新实现了git add -i的主循环以及大多数命令。
值得注意的是,我们忽略了patch的实际功能,因为相关代码占git-add--interactive.perl的一半以上,并且实际上与其余命令非常独立。
有了这个提交,我们开始处理patch部分。为了更好地分离关注点,我们将代码保存在一个单独的文件add-patch.c中。新代码仍然被保护在add.interactive.useBuiltin配置设置后面,目前,它只能通过git add -p调用。

实际功能遵循5cde71d64aff的原始实现("git add --interactive",2006年12月10日,Git v1.5.0-rc0--merge),但不要太接近(例如,我们使用字符串偏移而不是到处复制字符串,并且在查看kj命令是否适用之后,在C版本中,我们会记住前一个/下一个块未决定,并使用它,而不是在用户要求跳转时再次查看)。
作为对该提交的进一步改进,我们还使用逗号而不是斜杠来分隔提示符中的可用命令,正如Perl脚本的当前版本所做的那样,并且我们还在帮助文本中添加了一行关于问号的内容("print help")。
虽然很容易将git add -p的这种转换用作在apply_all_patches()上工作的借口,以便它 * 不 * 希望从stdin或从文件读取文件,而是接受(比如说)strbuf,但我们将在此阶段避免这种特殊的兔子洞。
重写工作的结论可以在Git 2.29(Q4 2020)中找到:"add -i/-p"机制已用C编写,但尚未默认使用。
默认为参与**feature.experimental**实验的人员。
参见Junio C Hamano ( gitster )(2020年9月8日)。
(由Junio C Hamano -- gitster --合并至commit e96b271,2020年9月18日)

add -i:当设置feature.experimental时使用内置版本

确认人:Johannes Schindelin
我们从2.25开始就有了"add -i/-p"的并行实现,并且从2.26开始就在各种代码路径中使用它们,但是从来没有把内置版本作为默认版本。
我们已经发现并修复了内置版本中的一些极端错误,现在可能是开始将用户群从脚本版本切换到内置版本的好时机。
让我们为那些选择加入feature.experimental guinea-pig计划的人启用内置版本,以获得更广泛的曝光。
而且,在Git 2.29(2020年第四季度)中,仍然有一个"add -i/-p"修复:
参见commit 1c6ffb5commit dc62641(2020年9月7日)。
(由Junio C Hamano -- gitster --合并至commit 694e517,2020年9月18日)

add-patch:修复了repo_read_index()的反向返回代码

签署人:杰夫·金
确认人:Johannes Schindelin
在将块应用到带有"add -p"的文件之后,Cpatch_update_file()函数尝试刷新索引(就像Perl版本所做的那样)。
我们只能在能够读入索引的情况下刷新索引,因此我们首先检查repo_read_index()的返回值。
但与许多函数不同的是,"0"表示成功,该函数被记录为返回索引中的条目数。
因此,我们应该用一个非负的返回值来检查是否成功。
测试和任何用户似乎都没有注意到这一点,可能是由于以下因素的组合:

  • 这只影响C版本,它还不是默认版本
  • 在它之后跟随任何陶瓷命令,如"git diff"(man)或"git commit",将自动刷新索引。

但是您可以通过在"add -p"暂存所有块之后立即运行管道"git diff-files"(man)来查看问题。使用GIT_TEST_ADD_I_USE_BUILTIN=1运行新测试失败,没有匹配的代码更改。
在Git 2.37(2022年第三季度)中,"git add -i"(man)在一段时间前用C重写,并一直在测试中;重新实现现在默认情况下向公众公开
参见Johannes Schindelin ( dscho )commit 0527ccbcommit ed922dc(2021年11月30日)。
(2022年5月30日由Junio C Hamano -- gitster --合并到commit 1fc1879

add -i:默认为内置实现

签署人:约翰内斯·申德林
9a5315e中("合并分支'js/patch-mode-in-others-in-c'",2020 - 02 - 05,Git v2.26.0-rc0--merge,列在batch #3中),Git获得了git addman)交互模式的内置实现,可以通过配置选项add.interactive.useBuiltin打开。
第一个支持这个旋钮的官方Git版本是v2.26.0。
2df2d81("添加-i:设置了feature. experimental时使用内置版本",2020年9月8日,Git v2.29.0-rc0--merge列于batch #15中),此内置实现也通过feature.experimental启用。
包含此变更的第一个版本是v2.29.0。
一年多以后(很少有bug报告),是时候宣布内置实现成熟并默认打开它了。
我们特意保留了add.interactive.useBuiltin配置,以便用户在意外情况下遇到以前未检测到的bug时可以使用"逃生出口"。
git config现在在其手册页中包括:
设置为false将回退到交互式版本git add的原始Perl实现,而不是内置版本。

    • 默认为true**。

随着Git 2.40(2023年第一季度)的发布,最终淘汰了脚本化的"git add"(man)-p/- i实现,让大家使用用C重新实现的那个。
参见Ævar Arnfjörð Bjarmason ( avar )commit 5a7d41dcommit d21878fcommit 20b813d(2023年2月6日)。
(由Junio C Hamano -- gitster --合并到commit 06bca97,2023年2月15日)

add:删除"添加.交互. useBuiltin"& Perl "git添加--交互"

签署人:埃瓦尔·阿恩菲约德·比亚尔马森

由于commit 0527ccbadd -i:默认为内置实现,2021年11月30日,Git v2.37.0-rc0--batch #5中列出的merge)(add -i:默认为内置实现,Git v2.37.0首次发布时,默认为内置版本"add -i"。
该内置实现被添加到commit f83dff6中(开始实现git add --interactive的内置版本,2019 - 11 - 13,Git v2.25.0-rc0--merge列在batch #3中)(开始实现git add的内置版本(man),首次随Git v2.25.0发布。
现在已经有足够的时间来查找这个新实现中的任何剩余bug,所以让我们删除后备代码。
git config现在在其手册页中包括:

add.interactive.useBuiltin

未使用的配置变量。
在Git v2.25.0到v2.36.0版本中使用,以启用内置版本git add的交互模式,该模式随后成为Git v2.37.0到v2.39.0版本的默认模式。

相关问题