Reputation: 1
I have a git hash from a few month ago (lets say xyz
) and would like to
see all the commits on the master branch before and after this hash up to today.
I know git checkout xyz~1
goes back 1 commit before that hash and git log
shows all the previous commits but I don't know how to go forward?
Is the --grep
feature of git usable in this case?
Upvotes: 0
Views: 2291
Reputation: 51780
to view the commits "up to xyz", simply use :
git log xyz
to view the commits "in master, which occured after xyz
", you can use :
git log xyz..master
technically, the second command will exlcude xyz
from the list, depending on your precise needs you may use xyz~1
instead of xyz
:
git log xyz~1..master
git log
also has a ton of options to format its output.
One useful set of options to view a big set of commits is :
git log --oneline --graph xyz
git log --oneline --graph xyz..master
Upvotes: 0
Reputation: 29536
It's difficult to give a one-shot answer because depends on what your tree looks like, where xyz is, and how commits are made or merged to master. This answer assumes you are only concerned with commits from xyz leading up to master.
Say we have this tree:
* f10abeb (HEAD -> master) Merge branch 'develop' into 'master'
|\
| * 3a7ed63 Merge branch 'feature/A' into 'develop'
| |\
| * | f3972b9 Update in develop 1
| | * f695720 Update in feature/A
| * | 20323a1 Update in develop 2
| * | 3e81e7a Update in develop 3
| * | 1e76a6c Update in develop 4
| * | d3bf88f Update in develop 5
| | * 205fc0e Update in feature/A
Say you only want to get the logs between 2 commits before 20323a1
(xyz
) and your local copy of master
(which I assume you mean by "up to today"). You don't care about the "inner" commits in feature/A
but you do want to see when it was merged. (I'm assuming quite a lot here).
First, you need to checkout 2 commits before 20323a1
:
git checkout 20323a1~2
That would bring you to 1e76a6c
.
Then you can do:
git log --ancestry-path @^..master
That would give you logs for:
(I removed some info like date and time, etc.)
commit f10abebbfa9bce8074e9a4854af4fc1a000b2f6a
Merge: 6011c88 3a7ed63
Merge branch 'develop' into 'master'
commit 3a7ed6334d492ebb7960c97c1c59c88d40c28108
Merge: f3972b9 f695720
Merge branch 'feature/A' into 'develop'
commit f3972b9ca16ff27914120de12105b8203a2682fa
Update in develop 1
commit 20323a1fc4c636b7e12650659ca049c2a1c497c4
Update in develop 2
commit 3e81e7a1624e6914dc152ca315c727e15ebf3300
Update in develop 3
commit 1e76a6cb326ffce64ff22480a71b49de4dbdff73
Update in develop 4
The --ancestry-path
option will "only display commits that exist directly on the ancestry chain between the commit1 and commit2" (in this example, the current commit and master).
The r1..r2
is a dotted-range notation meaning commits "commits that are reachable from r2 excluding those that are reachable from r1". Then we specify r1
to be the current commit (@
) and r2
to be master
.
Upvotes: 0
Reputation: 487725
Consider the following picture:
I <-J
/
... <-G <-H
\
K <-L
The above represent Git commits—H
stands in for some big ugly hash ID, and so do G
and I
and so on. (Note: the lines fromK
to H
and from I
to H
should be pointing left-ish / backwards like the others, but I don't have good arrow characters that work on everyone's system, and I'm drawing this with text instead of graphics.)
The reason you can easily go backwards is that commit H
contains the big ugly hash ID of commit G
. We say that H
points to G
. So if you're standing on H
and you run git log
, Git shows you H
, then G
, then whatever comes before G
(probably F
), and so on.
You want to go the other way. But ... which way is that? There are two paths forward, neither of which Git can easily find for you. One goes to I
and then J
. The other goes to K
and then L
.
What you can do is pick a later starting point—ending point?—anyway, a later commit like L
and tell Git to go backwards until it reaches H
. Git can do that, easily, because of the embedded arrows pointing backwards from each commit.
When you have Git work backwards like that, Git will eventually come to some commit whose parent is H
. That's the "forward" commit in the direction of the end-point you chose. It's not the other forward commit, of course.
The main problem here is that there can be lots of ending-points, of which only a few if any lead back to H
:
...--G--H--o <-- master
\
J--o--o <-- develop
\
o--o <-- feature
We call these ending-points branches, or more precisely, branch names. The name points to the tip commit. Every commit to the left—regardless of which line it's on—is on that branch, which means that in this graph, commit G
is on every branch. Commit J
is on both develop
and feature
.
Pick a branch name that you think will, eventually, lead you back to where you stand right now. Then ask Git to do:
git log --topo-order --ancestry-path HEAD..master
for instance, to have Git start at master
and work backwards. (HEAD
is the commit you're standing on right now, in this map of commits and their connections. It's the big red "you are here" dot, and it automatically moves with you as you move about.)
The last commit that comes out of this will be one just after your current commit, if your current commit is reachable from the tip of master
. If not, the last commit that comes out of this is some commit reachable from master
that's not on the same branch(es) that contain HEAD
. For instance, git log --ancestry-path HEAD..feature
will list commits starting from the one feature
points to, and working backwards until it reaches J
. From J
, git log
will step back to G
. That's not HEAD
/H
but it is reachable from H
, so that's where git log
will stop. That's not a commit after H
though.
What this means is that if you don't know for sure which branch(es) contain H
, you won't know where to start. So use:
git branch --contains HEAD
to get a list of branch names that, when Git starts at them and works backwards, those branches do contain commit H
/ HEAD
. You can then use the --ancestry-path
trick to go "forwards" in that direction (you're still really going backwards, you're just stopping just before you get all the way to H
).
If you hit a fork in the road, you'll take it. You'll take it in the direction of the ending-point you supplied. Note that in a few cases, that could skip some commits:
I--J
/ \
...--o--H M--N <-- branch
\ /
K--L
Moving "forward" from H
to N
, you'll either go I-J-M-N, or K-L-M-N. Either way you may forget to visit the two you skipped. So be careful with this.
git rev-list
Often, you don't really want to look through the entire git log
output here. There's a few short-cuts, but remember if/when you're using them that you could lose out on internal branch-and-merge structures like the ring drawn just above. Anyway, git rev-list
does the same thing as git log
except that it just prints the hash IDs. Using --topo-order --reverse | head -1
, you can have it print the list backwards and then drop all but the first; or use it without --reverse
and | tail -1
for the same effect. You can also omit the name HEAD
. So:
git checkout $(git rev-list --ancestry-path --topo-order ..branch | tail -1)
will move your detached HEAD one step in the direction towards branch
, if there is such a step.
Upvotes: 1