在 Git 中引用提交的子项
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1761825/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Referencing the child of a commit in Git
提问by AttishOculus
If you want to move the HEAD
to the parent of the current HEAD
, that's easy:
如果您想将 移动HEAD
到当前 的父级HEAD
,这很简单:
git reset --hard HEAD^
But is there any simple way to do the exact opposite of this operation, that is, set the head to the current head's first child commit?
但是有没有什么简单的方法可以做与这个操作完全相反的操作,即将头部设置为当前头部的第一个子提交?
Right now, I use gitk as a workaround (alt-tab, up-arrow, alt-tab, middle-click), but I would like a more elegant solution, one that can also be used when gitk is not available.
现在,我使用 gitk 作为一种解决方法(alt-tab、向上箭头、alt-tab、中键单击),但我想要一个更优雅的解决方案,当 gitk 不可用时也可以使用该解决方案。
采纳答案by AttishOculus
Very probably not the fastest possible solution, but it does what I need:
很可能不是最快的解决方案,但它可以满足我的需求:
#!/bin/bash REV= if [[ -z "$REV" ]]; then echo "Usage: git-get-child []" exit fi HASH=$(git rev-parse $REV) NUM= if [[ -z "$NUM" ]]; then NUM=1 fi git rev-list --all --parents | grep " $HASH" | sed -n "${NUM}s/\([^ ]*\) .*$/\1/p"
The git rev-list --all --parents
does exactly what I need: it iterates over all reachable commits, and prints the following line for each:
这git rev-list --all --parents
正是我所需要的:它遍历所有可到达的提交,并为每个提交打印以下行:
SHA1_commit SHA1_parent1 SHA1_parent2
etc.
SHA1_commit SHA1_parent1 SHA1_parent2
等等。
The space in the grep expression ensures that only those lines are found where the SHA1 in question is a parent. Then we get the nth line for the nth child and get the child's SHA1.
grep 表达式中的空格确保只找到相关 SHA1 是父级的那些行。然后我们得到第n个孩子的第n行并得到孩子的SHA1。
回答by Rainer Blome
The above methodusing git rev-list --all
considers all available commits, which can be a lot and is often not necessary. If the interesting child commits are reachable from somebranch, the number of commits that a script interested in child commits needs to process can be reduced:
在上述方法中使用git rev-list --all
考虑了所有可用的提交,它可以有很多,并且通常不是必需的。如果可以从某个分支访问有趣的子提交,则可以减少对子提交感兴趣的脚本需要处理的提交数量:
branches=$(git branch --contains $commit| grep -v '[*] ('| sed -e 's+^..++')
will determine the set of branches that $commit is an ancestor of.
With a modern git, at least version 2.21+, this should do the same without the need for sed
(untested):
将确定 $commit 是其祖先的一组分支。使用现代 git,至少是 2.21+ 版本,这应该可以在不需要sed
(未经测试)的情况下执行相同的操作:
branches=$(git branch --format='%(refname:short)' --contains $commit| grep -v '[*] (')
Using this set, git rev-list --parents ^$commit $branches
should yield exactly the set of all parent-child relationships between $commit and all branch heads that it is an ancestor of.
使用这个集合,git rev-list --parents ^$commit $branches
应该准确地产生 $commit 和它是其祖先的所有分支头之间的所有父子关系的集合。
回答by Michael - Where's Clay Shirky
Based partly on Paul Wagland's answerand partly on his source, I am using the following:
部分基于Paul Wagland 的回答,部分基于他的来源,我使用以下内容:
git log --ancestry-path --format=%H ${commit}..master | tail -1
I found that Paul's answer gave me the wrong output for older commits (possibly due to merging?), where the primary difference is the --ancestry-path
flag.
我发现保罗的回答给了我旧提交的错误输出(可能是由于合并?),主要区别在于--ancestry-path
标志。
回答by Tom Hale
To just move HEAD (as asked - this doesn't update the index or working tree), use:
要移动 HEAD(如所问 - 这不会更新索引或工作树),请使用:
git reset --soft $(git child)
git reset --soft $(git child)
You'll need to use the configuration listed below.
您需要使用下面列出的配置。
Explanation
解释
Based on @Michael's answer, I hacked up the child
alias in my .gitconfig
.
根据@Michael 的回答,我child
在我的.gitconfig
.
It works as expected in the default case, and is also versatile.
它在默认情况下按预期工作,而且用途广泛。
# Get the child commit of the current commit.
# Use instead of 'HEAD' if given. Use instead of curent branch if given.
child = "!bash -c 'git log --format=%H --reverse --ancestry-path ${1:-HEAD}..${2:\"$(git rev-parse --abbrev-ref HEAD)\"} | head -1' -"
It defaults to giving the child of HEAD (unless another commit-ish argument is given) by following the ancestry one step toward the tip of the current branch (unless another commit-ish is given as second argument).
它默认为 HEAD 的子级(除非给出另一个 commit-ish 参数)通过跟随祖先朝着当前分支的尖端一步(除非另一个 commit-ish 作为第二个参数给出)。
Use %h
instead of %H
if you want the short hash form.
如果您想要短散列形式,请使用%h
代替%H
。
With a detached head, there is no branch, but getting the first child can still be achieved with this alias:
使用分离头,没有分支,但是使用这个别名仍然可以实现第一个孩子:
# For the current (or specified) commit-ish, get the all children, print the first child
children = "!bash -c 'c=${1:-HEAD}; set -- $(git rev-list --all --not \"$c\"^@ --children | grep $(git rev-parse \"$c\") ); shift; echo ' -"
Change the $1
to $*
to print all the children
改变$1
以$*
打印所有的孩子
回答by tanascius
You can use gitk
... since there can be more than one child there is probably no easy way like HEAD^
.
您可以使用gitk
... 因为可能有多个孩子,所以可能没有像HEAD^
.
If you want to undo your whole operation you can use the reflog, too. Use git reflog
to find your commit's pointer, which you can use for the reset
command. See here.
如果您想撤消整个操作,也可以使用 reflog。使用git reflog
找到你的提交的指针,你可以使用的reset
命令。见这里。
回答by Paul Wagland
Based on the answer given in How do I find the next commit in git?, I have another solution that works for me.
基于如何在 git 中找到下一个提交中给出的答案?,我有另一个适合我的解决方案。
Assuming that you want to find the next revision on the "master" branch, then you can do:
假设您想在“master”分支上找到下一个修订版,那么您可以执行以下操作:
git log --reverse ${commit}..master | sed 's/commit //; q'
This also assumes that there is onenext revision, but that is kind of assumed by the question anyway.
这还假定有一个下一个版本,但是这是一种对这个问题无论如何假设。
回答by Dustin
It depends on what you're asking. There could be an infinite number of children of the current head in an infinite number of branches, some local, some remote, and many that have been rebased away and are in your repository, but not part of a history you intend to publish.
这取决于你要问什么。在无数个分支中可能有无数个当前 head 的子节点,一些是本地的,一些是远程的,还有许多已经被重新定位并在您的存储库中,但不是您打算发布的历史的一部分。
For a simple case, if you have just done a reset to HEAD^
, you can get back the child you just threw away as HEAD@{1}
.
举个简单的例子,如果你刚刚重置了HEAD^
,你可以找回你刚刚扔掉的孩子作为HEAD@{1}
。
回答by VonC
You can use the gist of the creator for Hudson (now Jenkins) Kohsuke Kawaguchi(November 2013):kohsuke / git-children-of
:
您可以使用 Hudson(现为 Jenkins)Kohsuke Kawaguchi(2013 年 11 月)的创作者的要点kohsuke / git-children-of
:
Given a commit, find immediate children of that commit.
给定一个提交,找到该提交的直接子项。
#!/bin/bash -e
# given a commit, find immediate children of that commit.
for arg in "$@"; do
for commit in $(git rev-parse $arg^0); do
for child in $(git log --format='%H %P' --all | grep -F " $commit" | cut -f1 -d' '); do
git describe $child
done
done
done
Put that script in a folder referenced by your $PATH
, and simply type:
将该脚本放在您的 引用的文件夹中$PATH
,然后只需键入:
git children-of <a-commit>
回答by Alex Dresko
This post (http://www.jayway.com/2015/03/30/using-git-commits-to-drive-a-live-coding-session/#comment-282667) shows a neat way if doing it if you can create a well defined tag at the end of your commit stack. Essentially
git config --global alias.next '!git checkout `git rev-list HEAD..demo-end | tail -1`'
where "demo-end" is the last tag.
这篇文章(http://www.jayway.com/2015/03/30/using-git-commits-to-drive-a-live-coding-session/#comment-282667)展示了一个巧妙的方法,如果这样做的话您可以在提交堆栈的末尾创建一个定义明确的标签。本质上
git config --global alias.next '!git checkout `git rev-list HEAD..demo-end | tail -1`'
,“演示结束”是最后一个标签。
回答by u0b34a0f6ae
It is strictly not possible to give a good answer -- since git is distributed, most of the children of the commit you ask about might be in repositories that you don't have on your local machine! That's of course a silly answer, but something to think about. Git rarely implements operations that it can't implement correctly.
给出一个好的答案是绝对不可能的——因为 git 是分布式的,你询问的提交的大多数子项可能都在你本地机器上没有的存储库中!这当然是一个愚蠢的答案,但值得思考。Git 很少实现它不能正确实现的操作。