Chois@Chois-MacPro book-example $git config --global alias.next 'checkout `git log --reverse --ancestry-path HEAD..master | head -n 1 | cut -d \ -f 2`'
Chois@Chois-MacPro book-example $git next
error: unknown option `reverse'
usage: git checkout [<options>] <branch>
or: git checkout [<options>] [<branch>] -- <file>...
-q, --quiet suppress progress reporting
-b <branch> create and checkout a new branch
-B <branch> create/reset and checkout a branch
-l create reflog for new branch
--detach detach the HEAD at named commit
-t, --track set upstream info for new branch
--orphan <new-branch>
new unparented branch
-2, --ours checkout our version for unmerged files
-3, --theirs checkout their version for unmerged files
-f, --force force checkout (throw away local modifications)
-m, --merge perform a 3-way merge with the new branch
--overwrite-ignore update ignored files (default)
--conflict <style> conflict style (merge or diff3)
-p, --patch select hunks interactively
--ignore-skip-worktree-bits
do not limit pathspecs to sparse entries only
--ignore-other-worktrees
do not check if another worktree is holding the given ref
--progress force progress reporting
需要你的帮助。
很抱歉附加图片而不是真正的命令,但我无法表达符号`本身。
答案 0 :(得分:1)
如果Git别名没有感叹号!
作为前缀,Git会尝试在其自身内运行别名,这要求它不使用任何特殊的shell功能。
您正在使用的shell功能是反引号扩展 1 和管道(cmd1 | cmd2
)。因此,您的特定别名需要!
表单。
我看到了别名背后的想法;你可以简化这个别名。但是你可能还想让它更健壮一些,这需要一个小的shell脚本(它可以嵌入到别名中,尽管这会使它更难阅读)。
next
做了什么,以及它的轻微缺陷(如果你已经知道的话,请跳到最后) rev-spec HEAD..master
表示master
无法从HEAD
访问的提交。例如,给出一个相当复杂的图表:
o--o--o--o <-- brA
/ / \
...--o--o--o--o---o--o <-- master
\
o--o--o <-- brB
\
o--o--o <-- brC
序列brA..master
为您提供此子集(采用提交*
- ed,not-taken commit x
- ed,无聊无关提交左o
):
x--x--x--x <-- brA
/ / \
...--x--x--x--*---*--* <-- master
\
o--o--o <-- brB
\
o--o--o <-- brC
和brB..master
为您提供以下信息:
*--*--*--* <-- brA
/ / \
...--x--*--*--*---*--* <-- master
\
x--x--x <-- brB
\
o--o--o <-- brC
使用--ancestry-path
将所选提交的列表修剪为仅由左侧名称标识的提交的后代(它们必须已经是右手名称的祖先,因此此约束无效)。对于第一种情况brA..master
,这会丢弃一个*
- 提交,我将在此处标记!
:
x--x--x--x <-- brA
/ / \
...--x--x--x--!---*--* <-- master
\
o--o--o <-- brB
\
o--o--o <-- brC
而且,确实会带你到&#34; next&#34;向master
方向提交。
但是对于brB..master
情况,--ancestry-path
删除所有提交,并且该集合变为空,因为{{1}没有 {{1} } commit是*
:
brB
当然,我们只使用 !--!--!--! <-- brA
/ / \
...--x--!--!--!---!--! <-- master
\
x--x--x <-- brB
\
o--o--o <-- brC
而不是分支名称,这样所有这些都适用于分离的HEAD案例。但是也要考虑这个图表,这是一种苯环提交。我会使用HEAD
标记当前的HEAD
提交:
H
在这种情况下, o--o
/ \
...--H o--o <-- master
\ /
o--o
是&#34;苯环&#34;的左边缘。然后HEAD
选择所有的响铃以及最右边的HEAD..master
:
o
同时, *--*
/ \
...--H *--* <-- master
\ /
*--*
根本不删除任何内容:每个--ancestry-path
- ed提交实际上都是*
的后代。 H
别名将在半随机选择其中一个假设它选择顶部 - 然后移动到它:
next
此时 H--o
/ \
...--o o--o <-- master
\ /
o--o
永远不会遍历环的下半部分,因为这两个提交不再是next
的后代。
换句话说,轻微的缺陷是假设在HEAD
和HEAD
的尖端之间没有内部分支和合并序列。如果有这样的序列,并且我们希望访问它们,我们必须 2 一次,预先记录原始的master
提交ID集,然后遍历它们(以任何顺序)我们喜欢,可能是一种反向拓扑排序,它允许我们在经过&#34;上半部分&#34;之后跳回到苯环的下半部分,在我们的特定例子中)。
--ancestry-path
做的是生成提交ID和日志消息的列表,只提取第一行(读取git log ... | head -1 | cut ...
,并从中提取ID。
我们可以使用commit <id>
更简单地做同样的事情。我们仍然需要git rev-list
(或等效的),因为head -1
或--no-walk
为我们提供了-n 1
本身的提交ID,而不是下一次提交:
master
(我们也省略了git rev-list --reverse --ancestry-path ..master | head -1
这个词,因为那是默认的。)
如果这会产生 no 输出,我们可能不应该运行HEAD
。因此:
git checkout
这是一个双行脚本。将其嵌入别名有点棘手,因为需要引用所有内容。相反,我只是使它成为一个双行shell脚本;但如果你想把它作为别名:
id=$(git rev-list --reverse --ancestry-path ..master | head -1)
test -n "$id" && git checkout "$id" || echo 'no more commits'
这两个都可以取目标的名称,而不是硬编码[alias]
next = "!f() { id=$(git rev-list --reverse --ancestry-path ..master | head -1); \
test -n \"$id\" && git checkout $id || echo 'no more commits'; }; f"
。 (但我再次将所有提交ID转储到一个文件中并逐步执行该文件,然后使用&#34; next&#34;&#34; prev&#34;别名。)
1 这通常更好地写为master
而不是$(command)
,因为带括号的形式嵌套并且更容易理解。无论哪种方式,它都需要shell。
2 可以只记录起点和终点,并使用更复杂的算法根据`command`
现在和我们已知的位置选择下一个节点遍历顺序。例如,假设我们有起点和终点。我们可以将完整列表生成到文件中,然后HEAD
并找到它在文件中的位置,然后跳到文件中的下一个文件并删除文件,这是我们不需要的文件,直到我们去再次前进但实际上,将列表一次性转储到文件中要容易得多,然后一次访问一个条目,而不是在每一步重新生成此文件。
答案 1 :(得分:0)
尝试使用$()
语法(easier to parse)
git config --global alias.next 'checkout $(git log --reverse --ancestry-path HEAD..master |head -n 1 | cut -d \ -f 2)'