tags:

views:

262

answers:

5

If you want to move the HEAD to the parent of the current HEAD, that's easy:

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.

+1  A: 

You can use gitk ... since there can be more than one child there is probably no easy way like 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.

tanascius
+1  A: 

I don't think that is possible. The commit graph is strictly one-way, from child to parent.

At the very least, it would depend on you having other "heads" pointing to the descendants of the parent commit. Otherwise it would be very difficult to even find them.

Also, I do not think there is a definition of what constitutes the "first" child commit. I suppose you want to go by timestamp.

Graphical tools might help.

Thilo
You can refer to the second parent easily by `commit^2`. The second child could be defined just like this. The order is irrelevant as I want to use it on a long, straight line (so only one parent and one child per commit).
AttishOculus
The second parent is defined in the child commit. Like I said, the commit graph is one-way, from child to parent.
Thilo
Good point. But this doesn't mean that it can't be done, only that you don't know where to look for the answer. What I need is probably to iterate over all known commits (that is, commits reachable from any ref), and see if the comment in question is one of its parents.
AttishOculus
Yes, that is what you (or the tool) needs to do.
Thilo
+5  A: 

Very probably not the fastest possible solution, but it does what I need:

#!/bin/bash

REV=$1

if [ x$REV == x ]; then
    echo "Usage: git-get-child  []"
    exit
fi

HASH=$(git-rev-parse $REV)

NUM=$2

if [ x$NUM == x ]; 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:

SHA1_commit SHA1_parent1 SHA1_parent2 etc.

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.

AttishOculus
I believe it should be `git rev-list --all --parents | grep -m 1 -B $(($NUM-1)) " $HASH" | head -1 | sed 's/ .*//'` else it doesn't quite work when $NUM != 1
Schwern
A: 

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.

kaizer.se
Of course I only need the children from the current repository.
AttishOculus
A: 

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.

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}.

Dustin