I'd just like to note another possible approach - and that is by using git
git-notes(1), in existence since v 1.6.6 (Note to Self - Git) (I'm using git
version 1.7.9.5).
Basically, I used git svn
to clone an SVN repository with linear history (no standard layout, no branches, no tags), and I wanted to compare revision numbers in the cloned git
repository. This git clone doesn't have tags by default, so I cannot use git describe
. The strategy here likely would work only for linear history - not sure how it would turn out with merges etc.; but here is the basic strategy:
- Ask
git rev-list
for list of all commit history
- Since
rev-list
is by default in "reverse chronological order", we'd use its --reverse
switch to get list of commits sorted by oldest first
- Use
bash
shell to
- increase a counter variable on each commit as a revision counter,
- generate and add a "temporary" git note for each commit
- Then, browse the log by using
git log
with --notes
, which will also dump a commit's note, which in this case would be the "revision number"
- When done, erase the temporary notes (NB: I'm not sure if these notes are committed or not; they don't really show in
git status
)
First, let's note that git
has a default location of notes - but you can also specify a ref
(erence) for notes - which would store them in a different directory under .git
; for instance, while in a git
repo folder, you can call git notes get-ref
to see what directory that will be:
$ git notes get-ref
refs/notes/commits
$ git notes --ref=whatever get-ref
refs/notes/whatever
The thing to be noted is that if you notes add
with a --ref
, you must also afterwards use that reference again - otherwise you may get errors like "No note found for object XXX...".
For this example, I have chosen to call the ref
of the notes "linrev" (for linear revision) - this also means it is not likely the procedure will interfere with already existing notes. I am also using the --git-dir
switch, since being a git
newbie, I had some problems understanding it - so I'd like to "remember for later" :)
; and I also use --no-pager
to suppress spawning of less
when using git log
.
So, assuming you're in a directory, with a subfolder myrepo_git
which is a git
repository; one could do:
### check for already existing notes:
$ git --git-dir=./myrepo_git/.git notes show
# error: No note found for object 04051f98ece25cff67e62d13c548dacbee6c1e33.
$ git --git-dir=./myrepo_git/.git notes --ref=linrev show
# error: No note found for object 04051f98ece25cff67e62d13c548dacbee6c1e33.
### iterate through rev-list three, oldest first,
### create a cmdline adding a revision count as note to each revision
$ ix=0; for ih in $(git --git-dir=./myrepo_git/.git rev-list --reverse HEAD); do \
TCMD="git --git-dir=./myrepo_git/.git notes --ref linrev"; \
TCMD="$TCMD add $ih -m \"(r$((++ix)))\""; \
echo "$TCMD"; \
eval "$TCMD"; \
done
# git --git-dir=./myrepo_git/.git notes --ref linrev add 6886bbb7be18e63fc4be68ba41917b48f02e09d7 -m "(r1)"
# git --git-dir=./myrepo_git/.git notes --ref linrev add f34910dbeeee33a40806d29dd956062d6ab3ad97 -m "(r2)"
# ...
# git --git-dir=./myrepo_git/.git notes --ref linrev add 04051f98ece25cff67e62d13c548dacbee6c1e33 -m "(r15)"
### check status - adding notes seem to not affect it:
$ cd myrepo_git/
$ git status
# # On branch master
# nothing to commit (working directory clean)
$ cd ../
### check notes again:
$ git --git-dir=./myrepo_git/.git notes show
# error: No note found for object 04051f98ece25cff67e62d13c548dacbee6c1e33.
$ git --git-dir=./myrepo_git/.git notes --ref=linrev show
# (r15)
### note is saved - now let's issue a `git log` command, using a format string and notes:
$ git --git-dir=./myrepo_git/.git --no-pager log --notes=linrev --format=format:"%h: %an: %ad: >>%s<< %N" HEAD
# 04051f9: _user_: Sun Apr 21 18:29:02 2013 +0000: >>test message 15 << (r15)
# 77f3902: _user_: Sun Apr 21 18:29:00 2013 +0000: >>test message 14<< (r14)
# ...
# 6886bbb: _user_: Sun Apr 21 17:11:52 2013 +0000: >>initial test message 1<< (r1)
### test git log with range:
$ git --git-dir=./myrepo_git/.git --no-pager log --notes=linrev --format=format:"%h: %an: %ad: >>%s<< %N" HEAD^..HEAD
# 04051f9: _user_: Sun Apr 21 18:29:02 2013 +0000: >>test message 15 << (r15)
### erase notes - again must iterate through rev-list
$ ix=0; for ih in $(git --git-dir=./myrepo_git/.git rev-list --reverse HEAD); do \
TCMD="git --git-dir=./myrepo_git/.git notes --ref linrev"; \
TCMD="$TCMD remove $ih"; \
echo "$TCMD"; \
eval "$TCMD"; \
done
# git --git-dir=./myrepo_git/.git notes --ref linrev remove 6886bbb7be18e63fc4be68ba41917b48f02e09d7
# Removing note for object 6886bbb7be18e63fc4be68ba41917b48f02e09d7
# git --git-dir=./myrepo_git/.git notes --ref linrev remove f34910dbeeee33a40806d29dd956062d6ab3ad97
# Removing note for object f34910dbeeee33a40806d29dd956062d6ab3ad97
# ...
# git --git-dir=./myrepo_git/.git notes --ref linrev remove 04051f98ece25cff67e62d13c548dacbee6c1e33
# Removing note for object 04051f98ece25cff67e62d13c548dacbee6c1e33
### check notes again:
$ git --git-dir=./myrepo_git/.git notes show
# error: No note found for object 04051f98ece25cff67e62d13c548dacbee6c1e33.
$ git --git-dir=./myrepo_git/.git notes --ref=linrev show
# error: No note found for object 04051f98ece25cff67e62d13c548dacbee6c1e33.
So, at least in my specific case of fully linear history with no branches, the revision numbers seem to match with this approach - and additionally, it seems that this approach will allow using git log
with revision ranges, while still getting the right revision numbers - YMMV with a different context, though...
Hope this helps someone,
Cheers!
EDIT: Ok, here it is a bit easier, with git
aliases for the above loops, called setlinrev
and unsetlinrev
; when in your git repository folder, do (Note the nasty bash
escaping, see also #16136745 - Add a Git alias containing a semicolon):
cat >> .git/config <<"EOF"
[alias]
setlinrev = "!bash -c 'ix=0; for ih in $(git rev-list --reverse HEAD); do \n\
TCMD=\"git notes --ref linrev\"; \n\
TCMD=\"$TCMD add $ih -m \\\"(r\\$((++ix)))\\\"\"; \n\
#echo \"$TCMD\"; \n\
eval \"$TCMD\"; \n\
done; \n\
echo \"Linear revision notes are set.\" '"
unsetlinrev = "!bash -c 'ix=0; for ih in $(git rev-list --reverse HEAD); do \n\
TCMD=\"git notes --ref linrev\"; \n\
TCMD=\"$TCMD remove $ih\"; \n\
#echo \"$TCMD\"; \n\
eval \"$TCMD 2>/dev/null\"; \n\
done; \n\
echo \"Linear revision notes are unset.\" '"
EOF
... so you can simply invoke git setlinrev
before trying to do log involving linear revision notes; and git unsetlinrev
to delete those notes when you're done; an example from inside the git repo directory:
$ git log --notes=linrev --format=format:"%h: %an: %ad: >>%s<< %N" HEAD^..HEAD
04051f9: _user_: Sun Apr 21 18:29:02 2013 +0000: >>test message 15 <<
$ git setlinrev
Linear revision notes are set.
$ git log --notes=linrev --format=format:"%h: %an: %ad: >>%s<< %N" HEAD^..HEAD
04051f9: _user_: Sun Apr 21 18:29:02 2013 +0000: >>test message 15 << (r15)
$ git unsetlinrev
Linear revision notes are unset.
$ git log --notes=linrev --format=format:"%h: %an: %ad: >>%s<< %N" HEAD^..HEAD
04051f9: _user_: Sun Apr 21 18:29:02 2013 +0000: >>test message 15 <<
The time it would take the shell to complete these aliases, would depend on the size of the repository history.