How do I find the next commit in git? (child/child

2019-01-02 20:01发布

ref^ refers to the commit before ref, what about getting the commit after ref?

For example, if I git checkout 12345 how do I check out the next commit?

Thanks.

PS Yes, git's a DAG node pointer struct tree whatever. How do I find the commit after this one?

14条回答
梦寄多情
2楼-- · 2019-01-02 20:08

Two practical answers:

One Child

Based on @Michael's answer, I hacked up the child alias in my .gitconfig.

It works as expected in the default case, and is also versatile.

# Get the child commit of the current commit.
# Use $1 instead of 'HEAD' if given. Use $2 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).

Use %h instead of %H if you want the short hash form.

Multiple children

With a detached HEAD (there is no branch) or to get all children regardless of branches:

# 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 $1' -"

Change the $1 to $* to print all the children.

You can also change --all to a commit-ish to display only the children which are ancestors of that commit—in other words, to display only the children “in the direction of” the given commit. This may help you narrow the output down from many children to just one.

查看更多
忆尘夕之涩
3楼-- · 2019-01-02 20:11

I have this alias in ~/.gitconfig

first-child = "!f() { git log  --reverse --ancestry-path --pretty=%H $1..${2:-HEAD} | head -1; }; f"
查看更多
千与千寻千般痛.
4楼-- · 2019-01-02 20:13

In the case where you don't have a particular "destination" commit in mind, but instead want to see child commits that might be on any branch, you can use this command:

git rev-list --children --all | grep ^${COMMIT}

If you want to see all children and grand-children, you have to use rev-list --children recursively, like so:

git rev-list --children --all | \
egrep ^\($(git rev-list --children --all | \
           grep ^${COMMIT} | \
           sed 's/ /|/g')\)

(The version that gives only grand-children would use a more complex sed and/or cut.)

Finally, you can feed that into a log --graph command to see the tree structure, like so:

git log --graph --oneline --decorate \
\^${COMMIT}^@ \
$(git rev-list --children --all | \
  egrep ^\($(git rev-list --children --all | \
             grep ^${COMMIT} | \
             sed 's/ /|/g')\))
查看更多
谁念西风独自凉
5楼-- · 2019-01-02 20:16

The creator for Hudson (now Jenkins) Kohsuke Kawaguchi just published (November 2013):
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

As illustrated by this thread, in a VCS based on history represented by a DAG (Directed Acyclic Graph), there is not "one parent" or "one child".

        C1 -> C2 -> C3
      /               \
A -> B                  E -> F
      \               /
        D1 -> D2 ----/

The ordering of commits is done by "topo-order" or "date-order" (see GitPro book)

But since Git1.6.0, you can list the children of a commit.

git rev-list --children
git log --children

Note: for parent commits, you have the same issue, with the suffix ^ to a revision parameter meaning the first parent of that commit object. ^<n> means the <n>th parent (i.e. rev^ is equivalent to rev^1).

If you are on branch foo and issue "git merge bar" then foo will be the first parent.
I.e: The first parent is the branch you were on when you merged, and the second is the commit on the branch that you merged in.

查看更多
谁念西风独自凉
6楼-- · 2019-01-02 20:16

I've tried many different solutions and none worked for me. Had to come up with my own.

find next commit

function n() {
    git log --reverse --pretty=%H master | grep -A 1 $(git rev-parse HEAD) | tail -n1 | xargs git checkout
}

find previous commit

function p() {
    git checkout HEAD^1
}
查看更多
唯独是你
7楼-- · 2019-01-02 20:17

I managed to find the next child the following way:

git log --reverse --children -n1 HEAD (where 'n' is the number of children to show)
查看更多
登录 后发表回答