Add a "git-describe" command
It shows you the most recent tag that is reachable from a particular
commit is.
Maybe this is something that "git-name-rev" should be taught to do,
instead of having a separate command for it. Regardless, I find it useful.
What it does is to take any random commit, and "name" it by looking up the
most recent commit that is tagged and reachable from that commit. If the
match is exact, it will just print out that ref-name directly. Otherwise
it will print out the ref-name, followed by the 8-character "short SHA".
IOW, with something like Junios current tree, I get:
[torvalds@g5 git]$ git-describe parent
refs/tags/v1.0.4-g2414721b
ie the current head of my "parent" branch (ie Junio) is based on v1.0.4,
but since it has a few commits on top of that, it has added the git hash
of the thing to the end: "-g" + 8-char shorthand for the commit
2414721b194453f058079d897d13c4e377f92dc6.
Doing a "git-describe" on a tag-name will just show the full tag path:
[torvalds@g5 git]$ git-describe v1.0.4
refs/tags/v1.0.4
unless there are _other_ tags pointing to that commit, in which case it
will just choose one at random.
This is useful for two things:
- automatic version naming in Makefiles, for example. We could use it in
git itself: when doing "git --version", we could use this to give a
much more useful description of exactly what version was installed.
- for any random commit (say, you use "gitk <pathname>" or
"git-whatchanged" to look at what has changed in some file), you can
figure out what the last version of the repo was. Ie, say I find a bug
in commit 39ca371c45b04cd50d0974030ae051906fc516b6, I just do:
[torvalds@g5 linux]$ git-describe 39ca371c45b04cd50d0974030ae051906fc516b6
refs/tags/v2.6.14-rc4-g39ca371c
and I now know that it was _not_ in v2.6.14-rc4, but was presumably in
v2.6.14-rc5.
The latter is useful when you want to see what "version timeframe" a
commit happened in.
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2005-12-24 22:50:45 +01:00
|
|
|
#include "cache.h"
|
|
|
|
#include "commit.h"
|
2005-12-27 23:36:49 +01:00
|
|
|
#include "tag.h"
|
Add a "git-describe" command
It shows you the most recent tag that is reachable from a particular
commit is.
Maybe this is something that "git-name-rev" should be taught to do,
instead of having a separate command for it. Regardless, I find it useful.
What it does is to take any random commit, and "name" it by looking up the
most recent commit that is tagged and reachable from that commit. If the
match is exact, it will just print out that ref-name directly. Otherwise
it will print out the ref-name, followed by the 8-character "short SHA".
IOW, with something like Junios current tree, I get:
[torvalds@g5 git]$ git-describe parent
refs/tags/v1.0.4-g2414721b
ie the current head of my "parent" branch (ie Junio) is based on v1.0.4,
but since it has a few commits on top of that, it has added the git hash
of the thing to the end: "-g" + 8-char shorthand for the commit
2414721b194453f058079d897d13c4e377f92dc6.
Doing a "git-describe" on a tag-name will just show the full tag path:
[torvalds@g5 git]$ git-describe v1.0.4
refs/tags/v1.0.4
unless there are _other_ tags pointing to that commit, in which case it
will just choose one at random.
This is useful for two things:
- automatic version naming in Makefiles, for example. We could use it in
git itself: when doing "git --version", we could use this to give a
much more useful description of exactly what version was installed.
- for any random commit (say, you use "gitk <pathname>" or
"git-whatchanged" to look at what has changed in some file), you can
figure out what the last version of the repo was. Ie, say I find a bug
in commit 39ca371c45b04cd50d0974030ae051906fc516b6, I just do:
[torvalds@g5 linux]$ git-describe 39ca371c45b04cd50d0974030ae051906fc516b6
refs/tags/v2.6.14-rc4-g39ca371c
and I now know that it was _not_ in v2.6.14-rc4, but was presumably in
v2.6.14-rc5.
The latter is useful when you want to see what "version timeframe" a
commit happened in.
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2005-12-24 22:50:45 +01:00
|
|
|
#include "refs.h"
|
2007-01-10 12:36:36 +01:00
|
|
|
#include "builtin.h"
|
2007-05-21 09:20:25 +02:00
|
|
|
#include "exec_cmd.h"
|
2007-10-07 20:54:08 +02:00
|
|
|
#include "parse-options.h"
|
2009-10-21 15:35:22 +02:00
|
|
|
#include "diff.h"
|
2013-11-14 20:18:35 +01:00
|
|
|
#include "hashmap.h"
|
2013-07-07 23:42:23 +02:00
|
|
|
#include "argv-array.h"
|
Add a "git-describe" command
It shows you the most recent tag that is reachable from a particular
commit is.
Maybe this is something that "git-name-rev" should be taught to do,
instead of having a separate command for it. Regardless, I find it useful.
What it does is to take any random commit, and "name" it by looking up the
most recent commit that is tagged and reachable from that commit. If the
match is exact, it will just print out that ref-name directly. Otherwise
it will print out the ref-name, followed by the 8-character "short SHA".
IOW, with something like Junios current tree, I get:
[torvalds@g5 git]$ git-describe parent
refs/tags/v1.0.4-g2414721b
ie the current head of my "parent" branch (ie Junio) is based on v1.0.4,
but since it has a few commits on top of that, it has added the git hash
of the thing to the end: "-g" + 8-char shorthand for the commit
2414721b194453f058079d897d13c4e377f92dc6.
Doing a "git-describe" on a tag-name will just show the full tag path:
[torvalds@g5 git]$ git-describe v1.0.4
refs/tags/v1.0.4
unless there are _other_ tags pointing to that commit, in which case it
will just choose one at random.
This is useful for two things:
- automatic version naming in Makefiles, for example. We could use it in
git itself: when doing "git --version", we could use this to give a
much more useful description of exactly what version was installed.
- for any random commit (say, you use "gitk <pathname>" or
"git-whatchanged" to look at what has changed in some file), you can
figure out what the last version of the repo was. Ie, say I find a bug
in commit 39ca371c45b04cd50d0974030ae051906fc516b6, I just do:
[torvalds@g5 linux]$ git-describe 39ca371c45b04cd50d0974030ae051906fc516b6
refs/tags/v2.6.14-rc4-g39ca371c
and I now know that it was _not_ in v2.6.14-rc4, but was presumably in
v2.6.14-rc5.
The latter is useful when you want to see what "version timeframe" a
commit happened in.
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2005-12-24 22:50:45 +01:00
|
|
|
|
2013-10-31 10:25:41 +01:00
|
|
|
#define SEEN (1u << 0)
|
2007-01-13 23:30:53 +01:00
|
|
|
#define MAX_TAGS (FLAG_BITS - 1)
|
|
|
|
|
2007-10-07 20:54:08 +02:00
|
|
|
static const char * const describe_usage[] = {
|
2013-09-04 21:04:31 +02:00
|
|
|
N_("git describe [options] <commit-ish>*"),
|
2012-08-20 14:32:07 +02:00
|
|
|
N_("git describe [options] --dirty"),
|
2007-10-07 20:54:08 +02:00
|
|
|
NULL
|
|
|
|
};
|
Add a "git-describe" command
It shows you the most recent tag that is reachable from a particular
commit is.
Maybe this is something that "git-name-rev" should be taught to do,
instead of having a separate command for it. Regardless, I find it useful.
What it does is to take any random commit, and "name" it by looking up the
most recent commit that is tagged and reachable from that commit. If the
match is exact, it will just print out that ref-name directly. Otherwise
it will print out the ref-name, followed by the 8-character "short SHA".
IOW, with something like Junios current tree, I get:
[torvalds@g5 git]$ git-describe parent
refs/tags/v1.0.4-g2414721b
ie the current head of my "parent" branch (ie Junio) is based on v1.0.4,
but since it has a few commits on top of that, it has added the git hash
of the thing to the end: "-g" + 8-char shorthand for the commit
2414721b194453f058079d897d13c4e377f92dc6.
Doing a "git-describe" on a tag-name will just show the full tag path:
[torvalds@g5 git]$ git-describe v1.0.4
refs/tags/v1.0.4
unless there are _other_ tags pointing to that commit, in which case it
will just choose one at random.
This is useful for two things:
- automatic version naming in Makefiles, for example. We could use it in
git itself: when doing "git --version", we could use this to give a
much more useful description of exactly what version was installed.
- for any random commit (say, you use "gitk <pathname>" or
"git-whatchanged" to look at what has changed in some file), you can
figure out what the last version of the repo was. Ie, say I find a bug
in commit 39ca371c45b04cd50d0974030ae051906fc516b6, I just do:
[torvalds@g5 linux]$ git-describe 39ca371c45b04cd50d0974030ae051906fc516b6
refs/tags/v2.6.14-rc4-g39ca371c
and I now know that it was _not_ in v2.6.14-rc4, but was presumably in
v2.6.14-rc5.
The latter is useful when you want to see what "version timeframe" a
commit happened in.
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2005-12-24 22:50:45 +01:00
|
|
|
|
2007-01-13 23:30:53 +01:00
|
|
|
static int debug; /* Display lots of verbose info */
|
2008-10-13 16:39:46 +02:00
|
|
|
static int all; /* Any valid ref can be used */
|
|
|
|
static int tags; /* Allow lightweight tags */
|
2008-02-25 10:43:33 +01:00
|
|
|
static int longformat;
|
2013-05-17 22:56:18 +02:00
|
|
|
static int first_parent;
|
2010-10-28 20:28:04 +02:00
|
|
|
static int abbrev = -1; /* unspecified */
|
2007-01-13 23:30:53 +01:00
|
|
|
static int max_candidates = 10;
|
2013-11-14 20:18:35 +01:00
|
|
|
static struct hashmap names;
|
2010-12-09 07:47:29 +01:00
|
|
|
static int have_util;
|
2008-07-16 12:42:14 +02:00
|
|
|
static const char *pattern;
|
2008-03-02 17:51:57 +01:00
|
|
|
static int always;
|
2009-10-21 15:35:22 +02:00
|
|
|
static const char *dirty;
|
|
|
|
|
|
|
|
/* diff-index command arguments to check if working tree is dirty. */
|
|
|
|
static const char *diff_index_args[] = {
|
|
|
|
"diff-index", "--quiet", "HEAD", "--", NULL
|
|
|
|
};
|
|
|
|
|
2007-01-15 04:16:55 +01:00
|
|
|
struct commit_name {
|
2013-11-14 20:18:35 +01:00
|
|
|
struct hashmap_entry entry;
|
2010-12-09 07:46:08 +01:00
|
|
|
unsigned char peeled[20];
|
2008-02-28 07:22:36 +01:00
|
|
|
struct tag *tag;
|
2010-04-13 01:25:29 +02:00
|
|
|
unsigned prio:2; /* annotated tag = 2, tag = 1, head = 0 */
|
|
|
|
unsigned name_checked:1;
|
2008-02-28 07:22:36 +01:00
|
|
|
unsigned char sha1[20];
|
2013-05-25 11:08:00 +02:00
|
|
|
char *path;
|
2007-01-15 04:16:55 +01:00
|
|
|
};
|
2013-10-31 10:25:41 +01:00
|
|
|
|
2007-01-14 10:37:44 +01:00
|
|
|
static const char *prio_names[] = {
|
|
|
|
"head", "lightweight", "annotated",
|
|
|
|
};
|
Add a "git-describe" command
It shows you the most recent tag that is reachable from a particular
commit is.
Maybe this is something that "git-name-rev" should be taught to do,
instead of having a separate command for it. Regardless, I find it useful.
What it does is to take any random commit, and "name" it by looking up the
most recent commit that is tagged and reachable from that commit. If the
match is exact, it will just print out that ref-name directly. Otherwise
it will print out the ref-name, followed by the 8-character "short SHA".
IOW, with something like Junios current tree, I get:
[torvalds@g5 git]$ git-describe parent
refs/tags/v1.0.4-g2414721b
ie the current head of my "parent" branch (ie Junio) is based on v1.0.4,
but since it has a few commits on top of that, it has added the git hash
of the thing to the end: "-g" + 8-char shorthand for the commit
2414721b194453f058079d897d13c4e377f92dc6.
Doing a "git-describe" on a tag-name will just show the full tag path:
[torvalds@g5 git]$ git-describe v1.0.4
refs/tags/v1.0.4
unless there are _other_ tags pointing to that commit, in which case it
will just choose one at random.
This is useful for two things:
- automatic version naming in Makefiles, for example. We could use it in
git itself: when doing "git --version", we could use this to give a
much more useful description of exactly what version was installed.
- for any random commit (say, you use "gitk <pathname>" or
"git-whatchanged" to look at what has changed in some file), you can
figure out what the last version of the repo was. Ie, say I find a bug
in commit 39ca371c45b04cd50d0974030ae051906fc516b6, I just do:
[torvalds@g5 linux]$ git-describe 39ca371c45b04cd50d0974030ae051906fc516b6
refs/tags/v2.6.14-rc4-g39ca371c
and I now know that it was _not_ in v2.6.14-rc4, but was presumably in
v2.6.14-rc5.
The latter is useful when you want to see what "version timeframe" a
commit happened in.
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2005-12-24 22:50:45 +01:00
|
|
|
|
2013-11-14 20:18:35 +01:00
|
|
|
static int commit_name_cmp(const struct commit_name *cn1,
|
|
|
|
const struct commit_name *cn2, const void *peeled)
|
|
|
|
{
|
|
|
|
return hashcmp(cn1->peeled, peeled ? peeled : cn2->peeled);
|
|
|
|
}
|
|
|
|
|
2010-12-09 07:46:08 +01:00
|
|
|
static inline struct commit_name *find_commit_name(const unsigned char *peeled)
|
|
|
|
{
|
2014-07-03 00:22:11 +02:00
|
|
|
return hashmap_get_from_hash(&names, sha1hash(peeled), peeled);
|
2010-12-09 07:47:29 +01:00
|
|
|
}
|
|
|
|
|
2010-04-13 01:25:29 +02:00
|
|
|
static int replace_name(struct commit_name *e,
|
|
|
|
int prio,
|
|
|
|
const unsigned char *sha1,
|
|
|
|
struct tag **tag)
|
|
|
|
{
|
|
|
|
if (!e || e->prio < prio)
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
if (e->prio == 2 && prio == 2) {
|
|
|
|
/* Multiple annotated tags point to the same commit.
|
|
|
|
* Select one to keep based upon their tagger date.
|
|
|
|
*/
|
|
|
|
struct tag *t;
|
|
|
|
|
|
|
|
if (!e->tag) {
|
|
|
|
t = lookup_tag(e->sha1);
|
|
|
|
if (!t || parse_tag(t))
|
|
|
|
return 1;
|
|
|
|
e->tag = t;
|
|
|
|
}
|
|
|
|
|
|
|
|
t = lookup_tag(sha1);
|
|
|
|
if (!t || parse_tag(t))
|
|
|
|
return 0;
|
|
|
|
*tag = t;
|
|
|
|
|
|
|
|
if (e->tag->date < t->date)
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2005-12-28 01:09:37 +01:00
|
|
|
static void add_to_known_names(const char *path,
|
2010-12-09 07:47:29 +01:00
|
|
|
const unsigned char *peeled,
|
2008-02-28 07:22:36 +01:00
|
|
|
int prio,
|
|
|
|
const unsigned char *sha1)
|
Add a "git-describe" command
It shows you the most recent tag that is reachable from a particular
commit is.
Maybe this is something that "git-name-rev" should be taught to do,
instead of having a separate command for it. Regardless, I find it useful.
What it does is to take any random commit, and "name" it by looking up the
most recent commit that is tagged and reachable from that commit. If the
match is exact, it will just print out that ref-name directly. Otherwise
it will print out the ref-name, followed by the 8-character "short SHA".
IOW, with something like Junios current tree, I get:
[torvalds@g5 git]$ git-describe parent
refs/tags/v1.0.4-g2414721b
ie the current head of my "parent" branch (ie Junio) is based on v1.0.4,
but since it has a few commits on top of that, it has added the git hash
of the thing to the end: "-g" + 8-char shorthand for the commit
2414721b194453f058079d897d13c4e377f92dc6.
Doing a "git-describe" on a tag-name will just show the full tag path:
[torvalds@g5 git]$ git-describe v1.0.4
refs/tags/v1.0.4
unless there are _other_ tags pointing to that commit, in which case it
will just choose one at random.
This is useful for two things:
- automatic version naming in Makefiles, for example. We could use it in
git itself: when doing "git --version", we could use this to give a
much more useful description of exactly what version was installed.
- for any random commit (say, you use "gitk <pathname>" or
"git-whatchanged" to look at what has changed in some file), you can
figure out what the last version of the repo was. Ie, say I find a bug
in commit 39ca371c45b04cd50d0974030ae051906fc516b6, I just do:
[torvalds@g5 linux]$ git-describe 39ca371c45b04cd50d0974030ae051906fc516b6
refs/tags/v2.6.14-rc4-g39ca371c
and I now know that it was _not_ in v2.6.14-rc4, but was presumably in
v2.6.14-rc5.
The latter is useful when you want to see what "version timeframe" a
commit happened in.
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2005-12-24 22:50:45 +01:00
|
|
|
{
|
2010-12-09 07:46:08 +01:00
|
|
|
struct commit_name *e = find_commit_name(peeled);
|
2010-04-13 01:25:29 +02:00
|
|
|
struct tag *tag = NULL;
|
|
|
|
if (replace_name(e, prio, sha1, &tag)) {
|
2010-12-09 07:43:32 +01:00
|
|
|
if (!e) {
|
|
|
|
e = xmalloc(sizeof(struct commit_name));
|
2010-12-09 07:46:08 +01:00
|
|
|
hashcpy(e->peeled, peeled);
|
2014-07-03 00:20:20 +02:00
|
|
|
hashmap_entry_init(e, sha1hash(peeled));
|
2013-11-14 20:18:35 +01:00
|
|
|
hashmap_add(&names, e);
|
2013-05-25 11:08:00 +02:00
|
|
|
e->path = NULL;
|
2010-12-09 07:43:32 +01:00
|
|
|
}
|
2010-04-13 01:25:29 +02:00
|
|
|
e->tag = tag;
|
2007-01-15 04:16:55 +01:00
|
|
|
e->prio = prio;
|
2010-04-13 01:25:29 +02:00
|
|
|
e->name_checked = 0;
|
2008-02-28 07:22:36 +01:00
|
|
|
hashcpy(e->sha1, sha1);
|
2013-05-25 11:08:00 +02:00
|
|
|
free(e->path);
|
|
|
|
e->path = xstrdup(path);
|
Add a "git-describe" command
It shows you the most recent tag that is reachable from a particular
commit is.
Maybe this is something that "git-name-rev" should be taught to do,
instead of having a separate command for it. Regardless, I find it useful.
What it does is to take any random commit, and "name" it by looking up the
most recent commit that is tagged and reachable from that commit. If the
match is exact, it will just print out that ref-name directly. Otherwise
it will print out the ref-name, followed by the 8-character "short SHA".
IOW, with something like Junios current tree, I get:
[torvalds@g5 git]$ git-describe parent
refs/tags/v1.0.4-g2414721b
ie the current head of my "parent" branch (ie Junio) is based on v1.0.4,
but since it has a few commits on top of that, it has added the git hash
of the thing to the end: "-g" + 8-char shorthand for the commit
2414721b194453f058079d897d13c4e377f92dc6.
Doing a "git-describe" on a tag-name will just show the full tag path:
[torvalds@g5 git]$ git-describe v1.0.4
refs/tags/v1.0.4
unless there are _other_ tags pointing to that commit, in which case it
will just choose one at random.
This is useful for two things:
- automatic version naming in Makefiles, for example. We could use it in
git itself: when doing "git --version", we could use this to give a
much more useful description of exactly what version was installed.
- for any random commit (say, you use "gitk <pathname>" or
"git-whatchanged" to look at what has changed in some file), you can
figure out what the last version of the repo was. Ie, say I find a bug
in commit 39ca371c45b04cd50d0974030ae051906fc516b6, I just do:
[torvalds@g5 linux]$ git-describe 39ca371c45b04cd50d0974030ae051906fc516b6
refs/tags/v2.6.14-rc4-g39ca371c
and I now know that it was _not_ in v2.6.14-rc4, but was presumably in
v2.6.14-rc5.
The latter is useful when you want to see what "version timeframe" a
commit happened in.
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2005-12-24 22:50:45 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-09-21 07:02:01 +02:00
|
|
|
static int get_name(const char *path, const unsigned char *sha1, int flag, void *cb_data)
|
Add a "git-describe" command
It shows you the most recent tag that is reachable from a particular
commit is.
Maybe this is something that "git-name-rev" should be taught to do,
instead of having a separate command for it. Regardless, I find it useful.
What it does is to take any random commit, and "name" it by looking up the
most recent commit that is tagged and reachable from that commit. If the
match is exact, it will just print out that ref-name directly. Otherwise
it will print out the ref-name, followed by the 8-character "short SHA".
IOW, with something like Junios current tree, I get:
[torvalds@g5 git]$ git-describe parent
refs/tags/v1.0.4-g2414721b
ie the current head of my "parent" branch (ie Junio) is based on v1.0.4,
but since it has a few commits on top of that, it has added the git hash
of the thing to the end: "-g" + 8-char shorthand for the commit
2414721b194453f058079d897d13c4e377f92dc6.
Doing a "git-describe" on a tag-name will just show the full tag path:
[torvalds@g5 git]$ git-describe v1.0.4
refs/tags/v1.0.4
unless there are _other_ tags pointing to that commit, in which case it
will just choose one at random.
This is useful for two things:
- automatic version naming in Makefiles, for example. We could use it in
git itself: when doing "git --version", we could use this to give a
much more useful description of exactly what version was installed.
- for any random commit (say, you use "gitk <pathname>" or
"git-whatchanged" to look at what has changed in some file), you can
figure out what the last version of the repo was. Ie, say I find a bug
in commit 39ca371c45b04cd50d0974030ae051906fc516b6, I just do:
[torvalds@g5 linux]$ git-describe 39ca371c45b04cd50d0974030ae051906fc516b6
refs/tags/v2.6.14-rc4-g39ca371c
and I now know that it was _not_ in v2.6.14-rc4, but was presumably in
v2.6.14-rc5.
The latter is useful when you want to see what "version timeframe" a
commit happened in.
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2005-12-24 22:50:45 +01:00
|
|
|
{
|
2013-11-30 21:55:40 +01:00
|
|
|
int is_tag = starts_with(path, "refs/tags/");
|
2008-02-24 09:07:25 +01:00
|
|
|
unsigned char peeled[20];
|
2013-02-28 22:53:00 +01:00
|
|
|
int is_annotated, prio;
|
2008-02-24 09:07:25 +01:00
|
|
|
|
2013-02-28 22:53:00 +01:00
|
|
|
/* Reject anything outside refs/tags/ unless --all */
|
|
|
|
if (!all && !is_tag)
|
2008-02-24 09:07:28 +01:00
|
|
|
return 0;
|
|
|
|
|
2013-02-28 22:53:00 +01:00
|
|
|
/* Accept only tags that match the pattern, if given */
|
2014-02-15 03:01:46 +01:00
|
|
|
if (pattern && (!is_tag || wildmatch(pattern, path + 10, 0, NULL)))
|
2013-02-28 22:53:00 +01:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
/* Is it annotated? */
|
peel_ref: do not return a null sha1
The idea of the peel_ref function is to dereference tag
objects recursively until we hit a non-tag, and return the
sha1. Conceptually, it should return 0 if it is successful
(and fill in the sha1), or -1 if there was nothing to peel.
However, the current behavior is much more confusing. For a
regular loose ref, the behavior is as described above. But
there is an optimization to reuse the peeled-ref value for a
ref that came from a packed-refs file. If we have such a
ref, we return its peeled value, even if that peeled value
is null (indicating that we know the ref definitely does
_not_ peel).
It might seem like such information is useful to the caller,
who would then know not to bother loading and trying to peel
the object. Except that they should not bother loading and
trying to peel the object _anyway_, because that fallback is
already handled by peel_ref. In other words, the whole point
of calling this function is that it handles those details
internally, and you either get a sha1, or you know that it
is not peel-able.
This patch catches the null sha1 case internally and
converts it into a -1 return value (i.e., there is nothing
to peel). This simplifies callers, which do not need to
bother checking themselves.
Two callers are worth noting:
- in pack-objects, a comment indicates that there is a
difference between non-peelable tags and unannotated
tags. But that is not the case (before or after this
patch). Whether you get a null sha1 has to do with
internal details of how peel_ref operated.
- in show-ref, if peel_ref returns a failure, the caller
tries to decide whether to try peeling manually based on
whether the REF_ISPACKED flag is set. But this doesn't
make any sense. If the flag is set, that does not
necessarily mean the ref came from a packed-refs file
with the "peeled" extension. But it doesn't matter,
because even if it didn't, there's no point in trying to
peel it ourselves, as peel_ref would already have done
so. In other words, the fallback peeling is guaranteed
to fail.
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2012-10-04 10:00:19 +02:00
|
|
|
if (!peel_ref(path, peeled)) {
|
2013-02-28 22:53:00 +01:00
|
|
|
is_annotated = !!hashcmp(sha1, peeled);
|
2008-02-24 09:07:25 +01:00
|
|
|
} else {
|
2010-12-09 07:47:29 +01:00
|
|
|
hashcpy(peeled, sha1);
|
2013-02-28 22:53:00 +01:00
|
|
|
is_annotated = 0;
|
2008-02-24 09:07:25 +01:00
|
|
|
}
|
2005-12-28 01:09:37 +01:00
|
|
|
|
2013-02-28 22:53:00 +01:00
|
|
|
/*
|
|
|
|
* By default, we only use annotated tags, but with --tags
|
|
|
|
* we fall back to lightweight ones (even without --tags,
|
|
|
|
* we still remember lightweight ones, only to give hints
|
|
|
|
* in an error message). --all allows any refs to be used.
|
2005-12-27 23:40:17 +01:00
|
|
|
*/
|
2013-02-28 22:53:00 +01:00
|
|
|
if (is_annotated)
|
|
|
|
prio = 2;
|
|
|
|
else if (is_tag)
|
|
|
|
prio = 1;
|
2005-12-28 01:09:37 +01:00
|
|
|
else
|
|
|
|
prio = 0;
|
|
|
|
|
2010-12-09 07:47:29 +01:00
|
|
|
add_to_known_names(all ? path + 5 : path + 10, peeled, prio, sha1);
|
Add a "git-describe" command
It shows you the most recent tag that is reachable from a particular
commit is.
Maybe this is something that "git-name-rev" should be taught to do,
instead of having a separate command for it. Regardless, I find it useful.
What it does is to take any random commit, and "name" it by looking up the
most recent commit that is tagged and reachable from that commit. If the
match is exact, it will just print out that ref-name directly. Otherwise
it will print out the ref-name, followed by the 8-character "short SHA".
IOW, with something like Junios current tree, I get:
[torvalds@g5 git]$ git-describe parent
refs/tags/v1.0.4-g2414721b
ie the current head of my "parent" branch (ie Junio) is based on v1.0.4,
but since it has a few commits on top of that, it has added the git hash
of the thing to the end: "-g" + 8-char shorthand for the commit
2414721b194453f058079d897d13c4e377f92dc6.
Doing a "git-describe" on a tag-name will just show the full tag path:
[torvalds@g5 git]$ git-describe v1.0.4
refs/tags/v1.0.4
unless there are _other_ tags pointing to that commit, in which case it
will just choose one at random.
This is useful for two things:
- automatic version naming in Makefiles, for example. We could use it in
git itself: when doing "git --version", we could use this to give a
much more useful description of exactly what version was installed.
- for any random commit (say, you use "gitk <pathname>" or
"git-whatchanged" to look at what has changed in some file), you can
figure out what the last version of the repo was. Ie, say I find a bug
in commit 39ca371c45b04cd50d0974030ae051906fc516b6, I just do:
[torvalds@g5 linux]$ git-describe 39ca371c45b04cd50d0974030ae051906fc516b6
refs/tags/v2.6.14-rc4-g39ca371c
and I now know that it was _not_ in v2.6.14-rc4, but was presumably in
v2.6.14-rc5.
The latter is useful when you want to see what "version timeframe" a
commit happened in.
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2005-12-24 22:50:45 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2007-01-10 12:39:47 +01:00
|
|
|
struct possible_tag {
|
|
|
|
struct commit_name *name;
|
2007-01-14 10:37:44 +01:00
|
|
|
int depth;
|
|
|
|
int found_order;
|
2007-01-13 23:30:53 +01:00
|
|
|
unsigned flag_within;
|
2007-01-10 12:39:47 +01:00
|
|
|
};
|
|
|
|
|
2007-01-14 10:37:44 +01:00
|
|
|
static int compare_pt(const void *a_, const void *b_)
|
|
|
|
{
|
|
|
|
struct possible_tag *a = (struct possible_tag *)a_;
|
|
|
|
struct possible_tag *b = (struct possible_tag *)b_;
|
|
|
|
if (a->depth != b->depth)
|
|
|
|
return a->depth - b->depth;
|
|
|
|
if (a->found_order != b->found_order)
|
|
|
|
return a->found_order - b->found_order;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2007-01-27 07:54:21 +01:00
|
|
|
static unsigned long finish_depth_computation(
|
|
|
|
struct commit_list **list,
|
|
|
|
struct possible_tag *best)
|
|
|
|
{
|
|
|
|
unsigned long seen_commits = 0;
|
|
|
|
while (*list) {
|
|
|
|
struct commit *c = pop_commit(list);
|
|
|
|
struct commit_list *parents = c->parents;
|
|
|
|
seen_commits++;
|
|
|
|
if (c->object.flags & best->flag_within) {
|
|
|
|
struct commit_list *a = *list;
|
|
|
|
while (a) {
|
|
|
|
struct commit *i = a->item;
|
|
|
|
if (!(i->object.flags & best->flag_within))
|
|
|
|
break;
|
|
|
|
a = a->next;
|
|
|
|
}
|
|
|
|
if (!a)
|
|
|
|
break;
|
|
|
|
} else
|
|
|
|
best->depth++;
|
|
|
|
while (parents) {
|
|
|
|
struct commit *p = parents->item;
|
|
|
|
parse_commit(p);
|
|
|
|
if (!(p->object.flags & SEEN))
|
2010-11-27 02:58:14 +01:00
|
|
|
commit_list_insert_by_date(p, list);
|
2007-01-27 07:54:21 +01:00
|
|
|
p->object.flags |= c->object.flags;
|
|
|
|
parents = parents->next;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return seen_commits;
|
|
|
|
}
|
|
|
|
|
2008-02-28 07:22:36 +01:00
|
|
|
static void display_name(struct commit_name *n)
|
|
|
|
{
|
|
|
|
if (n->prio == 2 && !n->tag) {
|
|
|
|
n->tag = lookup_tag(n->sha1);
|
2010-04-13 01:25:29 +02:00
|
|
|
if (!n->tag || parse_tag(n->tag))
|
2011-02-23 00:42:23 +01:00
|
|
|
die(_("annotated tag %s not available"), n->path);
|
2010-04-13 01:25:29 +02:00
|
|
|
}
|
|
|
|
if (n->tag && !n->name_checked) {
|
|
|
|
if (!n->tag->tag)
|
2011-02-23 00:42:23 +01:00
|
|
|
die(_("annotated tag %s has no embedded name"), n->path);
|
2008-12-26 23:02:01 +01:00
|
|
|
if (strcmp(n->tag->tag, all ? n->path + 5 : n->path))
|
2011-02-23 00:42:23 +01:00
|
|
|
warning(_("tag '%s' is really '%s' here"), n->tag->tag, n->path);
|
2010-04-13 01:25:29 +02:00
|
|
|
n->name_checked = 1;
|
2008-02-28 07:22:36 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
if (n->tag)
|
|
|
|
printf("%s", n->tag->tag);
|
|
|
|
else
|
|
|
|
printf("%s", n->path);
|
2008-03-03 22:08:26 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static void show_suffix(int depth, const unsigned char *sha1)
|
|
|
|
{
|
|
|
|
printf("-%d-g%s", depth, find_unique_abbrev(sha1, abbrev));
|
2008-02-28 07:22:36 +01:00
|
|
|
}
|
|
|
|
|
2006-06-28 11:04:39 +02:00
|
|
|
static void describe(const char *arg, int last_one)
|
Add a "git-describe" command
It shows you the most recent tag that is reachable from a particular
commit is.
Maybe this is something that "git-name-rev" should be taught to do,
instead of having a separate command for it. Regardless, I find it useful.
What it does is to take any random commit, and "name" it by looking up the
most recent commit that is tagged and reachable from that commit. If the
match is exact, it will just print out that ref-name directly. Otherwise
it will print out the ref-name, followed by the 8-character "short SHA".
IOW, with something like Junios current tree, I get:
[torvalds@g5 git]$ git-describe parent
refs/tags/v1.0.4-g2414721b
ie the current head of my "parent" branch (ie Junio) is based on v1.0.4,
but since it has a few commits on top of that, it has added the git hash
of the thing to the end: "-g" + 8-char shorthand for the commit
2414721b194453f058079d897d13c4e377f92dc6.
Doing a "git-describe" on a tag-name will just show the full tag path:
[torvalds@g5 git]$ git-describe v1.0.4
refs/tags/v1.0.4
unless there are _other_ tags pointing to that commit, in which case it
will just choose one at random.
This is useful for two things:
- automatic version naming in Makefiles, for example. We could use it in
git itself: when doing "git --version", we could use this to give a
much more useful description of exactly what version was installed.
- for any random commit (say, you use "gitk <pathname>" or
"git-whatchanged" to look at what has changed in some file), you can
figure out what the last version of the repo was. Ie, say I find a bug
in commit 39ca371c45b04cd50d0974030ae051906fc516b6, I just do:
[torvalds@g5 linux]$ git-describe 39ca371c45b04cd50d0974030ae051906fc516b6
refs/tags/v2.6.14-rc4-g39ca371c
and I now know that it was _not_ in v2.6.14-rc4, but was presumably in
v2.6.14-rc5.
The latter is useful when you want to see what "version timeframe" a
commit happened in.
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2005-12-24 22:50:45 +01:00
|
|
|
{
|
2006-01-11 22:57:42 +01:00
|
|
|
unsigned char sha1[20];
|
2007-01-13 23:30:53 +01:00
|
|
|
struct commit *cmit, *gave_up_on = NULL;
|
Add a "git-describe" command
It shows you the most recent tag that is reachable from a particular
commit is.
Maybe this is something that "git-name-rev" should be taught to do,
instead of having a separate command for it. Regardless, I find it useful.
What it does is to take any random commit, and "name" it by looking up the
most recent commit that is tagged and reachable from that commit. If the
match is exact, it will just print out that ref-name directly. Otherwise
it will print out the ref-name, followed by the 8-character "short SHA".
IOW, with something like Junios current tree, I get:
[torvalds@g5 git]$ git-describe parent
refs/tags/v1.0.4-g2414721b
ie the current head of my "parent" branch (ie Junio) is based on v1.0.4,
but since it has a few commits on top of that, it has added the git hash
of the thing to the end: "-g" + 8-char shorthand for the commit
2414721b194453f058079d897d13c4e377f92dc6.
Doing a "git-describe" on a tag-name will just show the full tag path:
[torvalds@g5 git]$ git-describe v1.0.4
refs/tags/v1.0.4
unless there are _other_ tags pointing to that commit, in which case it
will just choose one at random.
This is useful for two things:
- automatic version naming in Makefiles, for example. We could use it in
git itself: when doing "git --version", we could use this to give a
much more useful description of exactly what version was installed.
- for any random commit (say, you use "gitk <pathname>" or
"git-whatchanged" to look at what has changed in some file), you can
figure out what the last version of the repo was. Ie, say I find a bug
in commit 39ca371c45b04cd50d0974030ae051906fc516b6, I just do:
[torvalds@g5 linux]$ git-describe 39ca371c45b04cd50d0974030ae051906fc516b6
refs/tags/v2.6.14-rc4-g39ca371c
and I now know that it was _not_ in v2.6.14-rc4, but was presumably in
v2.6.14-rc5.
The latter is useful when you want to see what "version timeframe" a
commit happened in.
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2005-12-24 22:50:45 +01:00
|
|
|
struct commit_list *list;
|
|
|
|
struct commit_name *n;
|
2007-01-14 10:37:44 +01:00
|
|
|
struct possible_tag all_matches[MAX_TAGS];
|
2007-01-13 23:30:53 +01:00
|
|
|
unsigned int match_cnt = 0, annotated_cnt = 0, cur_match;
|
|
|
|
unsigned long seen_commits = 0;
|
2009-10-28 23:10:06 +01:00
|
|
|
unsigned int unannotated_cnt = 0;
|
Add a "git-describe" command
It shows you the most recent tag that is reachable from a particular
commit is.
Maybe this is something that "git-name-rev" should be taught to do,
instead of having a separate command for it. Regardless, I find it useful.
What it does is to take any random commit, and "name" it by looking up the
most recent commit that is tagged and reachable from that commit. If the
match is exact, it will just print out that ref-name directly. Otherwise
it will print out the ref-name, followed by the 8-character "short SHA".
IOW, with something like Junios current tree, I get:
[torvalds@g5 git]$ git-describe parent
refs/tags/v1.0.4-g2414721b
ie the current head of my "parent" branch (ie Junio) is based on v1.0.4,
but since it has a few commits on top of that, it has added the git hash
of the thing to the end: "-g" + 8-char shorthand for the commit
2414721b194453f058079d897d13c4e377f92dc6.
Doing a "git-describe" on a tag-name will just show the full tag path:
[torvalds@g5 git]$ git-describe v1.0.4
refs/tags/v1.0.4
unless there are _other_ tags pointing to that commit, in which case it
will just choose one at random.
This is useful for two things:
- automatic version naming in Makefiles, for example. We could use it in
git itself: when doing "git --version", we could use this to give a
much more useful description of exactly what version was installed.
- for any random commit (say, you use "gitk <pathname>" or
"git-whatchanged" to look at what has changed in some file), you can
figure out what the last version of the repo was. Ie, say I find a bug
in commit 39ca371c45b04cd50d0974030ae051906fc516b6, I just do:
[torvalds@g5 linux]$ git-describe 39ca371c45b04cd50d0974030ae051906fc516b6
refs/tags/v2.6.14-rc4-g39ca371c
and I now know that it was _not_ in v2.6.14-rc4, but was presumably in
v2.6.14-rc5.
The latter is useful when you want to see what "version timeframe" a
commit happened in.
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2005-12-24 22:50:45 +01:00
|
|
|
|
2006-05-08 23:43:38 +02:00
|
|
|
if (get_sha1(arg, sha1))
|
2011-02-23 00:42:23 +01:00
|
|
|
die(_("Not a valid object name %s"), arg);
|
2006-01-11 22:57:42 +01:00
|
|
|
cmit = lookup_commit_reference(sha1);
|
|
|
|
if (!cmit)
|
2011-02-23 00:42:23 +01:00
|
|
|
die(_("%s is not a valid '%s' object"), arg, commit_type);
|
2006-01-11 22:57:42 +01:00
|
|
|
|
2010-12-09 07:46:08 +01:00
|
|
|
n = find_commit_name(cmit->object.sha1);
|
2009-11-18 14:32:26 +01:00
|
|
|
if (n && (tags || all || n->prio == 2)) {
|
2008-03-03 22:08:26 +01:00
|
|
|
/*
|
|
|
|
* Exact match to an existing ref.
|
|
|
|
*/
|
2008-02-28 07:22:36 +01:00
|
|
|
display_name(n);
|
2008-03-03 22:08:26 +01:00
|
|
|
if (longformat)
|
2008-07-03 04:32:45 +02:00
|
|
|
show_suffix(0, n->tag ? n->tag->tagged->sha1 : sha1);
|
2009-10-21 15:35:22 +02:00
|
|
|
if (dirty)
|
|
|
|
printf("%s", dirty);
|
2008-02-28 07:22:36 +01:00
|
|
|
printf("\n");
|
Add a "git-describe" command
It shows you the most recent tag that is reachable from a particular
commit is.
Maybe this is something that "git-name-rev" should be taught to do,
instead of having a separate command for it. Regardless, I find it useful.
What it does is to take any random commit, and "name" it by looking up the
most recent commit that is tagged and reachable from that commit. If the
match is exact, it will just print out that ref-name directly. Otherwise
it will print out the ref-name, followed by the 8-character "short SHA".
IOW, with something like Junios current tree, I get:
[torvalds@g5 git]$ git-describe parent
refs/tags/v1.0.4-g2414721b
ie the current head of my "parent" branch (ie Junio) is based on v1.0.4,
but since it has a few commits on top of that, it has added the git hash
of the thing to the end: "-g" + 8-char shorthand for the commit
2414721b194453f058079d897d13c4e377f92dc6.
Doing a "git-describe" on a tag-name will just show the full tag path:
[torvalds@g5 git]$ git-describe v1.0.4
refs/tags/v1.0.4
unless there are _other_ tags pointing to that commit, in which case it
will just choose one at random.
This is useful for two things:
- automatic version naming in Makefiles, for example. We could use it in
git itself: when doing "git --version", we could use this to give a
much more useful description of exactly what version was installed.
- for any random commit (say, you use "gitk <pathname>" or
"git-whatchanged" to look at what has changed in some file), you can
figure out what the last version of the repo was. Ie, say I find a bug
in commit 39ca371c45b04cd50d0974030ae051906fc516b6, I just do:
[torvalds@g5 linux]$ git-describe 39ca371c45b04cd50d0974030ae051906fc516b6
refs/tags/v2.6.14-rc4-g39ca371c
and I now know that it was _not_ in v2.6.14-rc4, but was presumably in
v2.6.14-rc5.
The latter is useful when you want to see what "version timeframe" a
commit happened in.
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2005-12-24 22:50:45 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2008-02-24 09:07:31 +01:00
|
|
|
if (!max_candidates)
|
2011-02-23 00:42:23 +01:00
|
|
|
die(_("no tag exactly matches '%s'"), sha1_to_hex(cmit->object.sha1));
|
2007-01-13 23:30:53 +01:00
|
|
|
if (debug)
|
2011-02-23 00:42:23 +01:00
|
|
|
fprintf(stderr, _("searching to describe %s\n"), arg);
|
2007-01-13 23:30:53 +01:00
|
|
|
|
2010-12-09 07:47:29 +01:00
|
|
|
if (!have_util) {
|
2013-11-14 20:18:35 +01:00
|
|
|
struct hashmap_iter iter;
|
|
|
|
struct commit *c;
|
|
|
|
struct commit_name *n = hashmap_iter_first(&names, &iter);
|
|
|
|
for (; n; n = hashmap_iter_next(&iter)) {
|
|
|
|
c = lookup_commit_reference_gently(n->peeled, 1);
|
|
|
|
if (c)
|
|
|
|
c->util = n;
|
|
|
|
}
|
2010-12-09 07:47:29 +01:00
|
|
|
have_util = 1;
|
|
|
|
}
|
|
|
|
|
Add a "git-describe" command
It shows you the most recent tag that is reachable from a particular
commit is.
Maybe this is something that "git-name-rev" should be taught to do,
instead of having a separate command for it. Regardless, I find it useful.
What it does is to take any random commit, and "name" it by looking up the
most recent commit that is tagged and reachable from that commit. If the
match is exact, it will just print out that ref-name directly. Otherwise
it will print out the ref-name, followed by the 8-character "short SHA".
IOW, with something like Junios current tree, I get:
[torvalds@g5 git]$ git-describe parent
refs/tags/v1.0.4-g2414721b
ie the current head of my "parent" branch (ie Junio) is based on v1.0.4,
but since it has a few commits on top of that, it has added the git hash
of the thing to the end: "-g" + 8-char shorthand for the commit
2414721b194453f058079d897d13c4e377f92dc6.
Doing a "git-describe" on a tag-name will just show the full tag path:
[torvalds@g5 git]$ git-describe v1.0.4
refs/tags/v1.0.4
unless there are _other_ tags pointing to that commit, in which case it
will just choose one at random.
This is useful for two things:
- automatic version naming in Makefiles, for example. We could use it in
git itself: when doing "git --version", we could use this to give a
much more useful description of exactly what version was installed.
- for any random commit (say, you use "gitk <pathname>" or
"git-whatchanged" to look at what has changed in some file), you can
figure out what the last version of the repo was. Ie, say I find a bug
in commit 39ca371c45b04cd50d0974030ae051906fc516b6, I just do:
[torvalds@g5 linux]$ git-describe 39ca371c45b04cd50d0974030ae051906fc516b6
refs/tags/v2.6.14-rc4-g39ca371c
and I now know that it was _not_ in v2.6.14-rc4, but was presumably in
v2.6.14-rc5.
The latter is useful when you want to see what "version timeframe" a
commit happened in.
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2005-12-24 22:50:45 +01:00
|
|
|
list = NULL;
|
2007-01-13 23:30:53 +01:00
|
|
|
cmit->object.flags = SEEN;
|
Add a "git-describe" command
It shows you the most recent tag that is reachable from a particular
commit is.
Maybe this is something that "git-name-rev" should be taught to do,
instead of having a separate command for it. Regardless, I find it useful.
What it does is to take any random commit, and "name" it by looking up the
most recent commit that is tagged and reachable from that commit. If the
match is exact, it will just print out that ref-name directly. Otherwise
it will print out the ref-name, followed by the 8-character "short SHA".
IOW, with something like Junios current tree, I get:
[torvalds@g5 git]$ git-describe parent
refs/tags/v1.0.4-g2414721b
ie the current head of my "parent" branch (ie Junio) is based on v1.0.4,
but since it has a few commits on top of that, it has added the git hash
of the thing to the end: "-g" + 8-char shorthand for the commit
2414721b194453f058079d897d13c4e377f92dc6.
Doing a "git-describe" on a tag-name will just show the full tag path:
[torvalds@g5 git]$ git-describe v1.0.4
refs/tags/v1.0.4
unless there are _other_ tags pointing to that commit, in which case it
will just choose one at random.
This is useful for two things:
- automatic version naming in Makefiles, for example. We could use it in
git itself: when doing "git --version", we could use this to give a
much more useful description of exactly what version was installed.
- for any random commit (say, you use "gitk <pathname>" or
"git-whatchanged" to look at what has changed in some file), you can
figure out what the last version of the repo was. Ie, say I find a bug
in commit 39ca371c45b04cd50d0974030ae051906fc516b6, I just do:
[torvalds@g5 linux]$ git-describe 39ca371c45b04cd50d0974030ae051906fc516b6
refs/tags/v2.6.14-rc4-g39ca371c
and I now know that it was _not_ in v2.6.14-rc4, but was presumably in
v2.6.14-rc5.
The latter is useful when you want to see what "version timeframe" a
commit happened in.
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2005-12-24 22:50:45 +01:00
|
|
|
commit_list_insert(cmit, &list);
|
|
|
|
while (list) {
|
2007-01-10 12:39:47 +01:00
|
|
|
struct commit *c = pop_commit(&list);
|
2007-01-13 23:27:52 +01:00
|
|
|
struct commit_list *parents = c->parents;
|
2007-01-13 23:30:53 +01:00
|
|
|
seen_commits++;
|
2007-01-15 04:16:55 +01:00
|
|
|
n = c->util;
|
Add a "git-describe" command
It shows you the most recent tag that is reachable from a particular
commit is.
Maybe this is something that "git-name-rev" should be taught to do,
instead of having a separate command for it. Regardless, I find it useful.
What it does is to take any random commit, and "name" it by looking up the
most recent commit that is tagged and reachable from that commit. If the
match is exact, it will just print out that ref-name directly. Otherwise
it will print out the ref-name, followed by the 8-character "short SHA".
IOW, with something like Junios current tree, I get:
[torvalds@g5 git]$ git-describe parent
refs/tags/v1.0.4-g2414721b
ie the current head of my "parent" branch (ie Junio) is based on v1.0.4,
but since it has a few commits on top of that, it has added the git hash
of the thing to the end: "-g" + 8-char shorthand for the commit
2414721b194453f058079d897d13c4e377f92dc6.
Doing a "git-describe" on a tag-name will just show the full tag path:
[torvalds@g5 git]$ git-describe v1.0.4
refs/tags/v1.0.4
unless there are _other_ tags pointing to that commit, in which case it
will just choose one at random.
This is useful for two things:
- automatic version naming in Makefiles, for example. We could use it in
git itself: when doing "git --version", we could use this to give a
much more useful description of exactly what version was installed.
- for any random commit (say, you use "gitk <pathname>" or
"git-whatchanged" to look at what has changed in some file), you can
figure out what the last version of the repo was. Ie, say I find a bug
in commit 39ca371c45b04cd50d0974030ae051906fc516b6, I just do:
[torvalds@g5 linux]$ git-describe 39ca371c45b04cd50d0974030ae051906fc516b6
refs/tags/v2.6.14-rc4-g39ca371c
and I now know that it was _not_ in v2.6.14-rc4, but was presumably in
v2.6.14-rc5.
The latter is useful when you want to see what "version timeframe" a
commit happened in.
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2005-12-24 22:50:45 +01:00
|
|
|
if (n) {
|
2009-10-28 23:10:06 +01:00
|
|
|
if (!tags && !all && n->prio < 2) {
|
|
|
|
unannotated_cnt++;
|
|
|
|
} else if (match_cnt < max_candidates) {
|
2007-01-13 23:30:53 +01:00
|
|
|
struct possible_tag *t = &all_matches[match_cnt++];
|
|
|
|
t->name = n;
|
|
|
|
t->depth = seen_commits - 1;
|
|
|
|
t->flag_within = 1u << match_cnt;
|
2007-01-25 18:40:03 +01:00
|
|
|
t->found_order = match_cnt;
|
2007-01-13 23:30:53 +01:00
|
|
|
c->object.flags |= t->flag_within;
|
|
|
|
if (n->prio == 2)
|
|
|
|
annotated_cnt++;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
gave_up_on = c;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
for (cur_match = 0; cur_match < match_cnt; cur_match++) {
|
|
|
|
struct possible_tag *t = &all_matches[cur_match];
|
|
|
|
if (!(c->object.flags & t->flag_within))
|
|
|
|
t->depth++;
|
|
|
|
}
|
|
|
|
if (annotated_cnt && !list) {
|
|
|
|
if (debug)
|
2011-02-23 00:42:23 +01:00
|
|
|
fprintf(stderr, _("finished search at %s\n"),
|
2007-01-13 23:30:53 +01:00
|
|
|
sha1_to_hex(c->object.sha1));
|
|
|
|
break;
|
2007-01-13 23:27:52 +01:00
|
|
|
}
|
|
|
|
while (parents) {
|
|
|
|
struct commit *p = parents->item;
|
|
|
|
parse_commit(p);
|
2007-01-13 23:30:53 +01:00
|
|
|
if (!(p->object.flags & SEEN))
|
2010-11-27 02:58:14 +01:00
|
|
|
commit_list_insert_by_date(p, &list);
|
2007-01-13 23:30:53 +01:00
|
|
|
p->object.flags |= c->object.flags;
|
2007-01-13 23:27:52 +01:00
|
|
|
parents = parents->next;
|
2013-05-17 22:56:18 +02:00
|
|
|
|
|
|
|
if (first_parent)
|
|
|
|
break;
|
2007-01-10 12:39:47 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-03-02 17:51:57 +01:00
|
|
|
if (!match_cnt) {
|
|
|
|
const unsigned char *sha1 = cmit->object.sha1;
|
|
|
|
if (always) {
|
2009-10-21 15:35:22 +02:00
|
|
|
printf("%s", find_unique_abbrev(sha1, abbrev));
|
|
|
|
if (dirty)
|
|
|
|
printf("%s", dirty);
|
|
|
|
printf("\n");
|
2008-03-02 17:51:57 +01:00
|
|
|
return;
|
|
|
|
}
|
2009-10-28 23:10:06 +01:00
|
|
|
if (unannotated_cnt)
|
2011-02-23 00:42:23 +01:00
|
|
|
die(_("No annotated tags can describe '%s'.\n"
|
|
|
|
"However, there were unannotated tags: try --tags."),
|
2009-10-28 23:10:06 +01:00
|
|
|
sha1_to_hex(sha1));
|
|
|
|
else
|
2011-02-23 00:42:23 +01:00
|
|
|
die(_("No tags can describe '%s'.\n"
|
|
|
|
"Try --always, or create some tags."),
|
2009-10-28 23:10:06 +01:00
|
|
|
sha1_to_hex(sha1));
|
2008-03-02 17:51:57 +01:00
|
|
|
}
|
2007-01-10 12:39:47 +01:00
|
|
|
|
2007-01-14 10:37:44 +01:00
|
|
|
qsort(all_matches, match_cnt, sizeof(all_matches[0]), compare_pt);
|
2007-01-27 07:54:21 +01:00
|
|
|
|
|
|
|
if (gave_up_on) {
|
2010-11-27 02:58:14 +01:00
|
|
|
commit_list_insert_by_date(gave_up_on, &list);
|
2007-01-27 07:54:21 +01:00
|
|
|
seen_commits--;
|
|
|
|
}
|
|
|
|
seen_commits += finish_depth_computation(&list, &all_matches[0]);
|
|
|
|
free_commit_list(list);
|
|
|
|
|
2007-01-13 23:30:53 +01:00
|
|
|
if (debug) {
|
|
|
|
for (cur_match = 0; cur_match < match_cnt; cur_match++) {
|
|
|
|
struct possible_tag *t = &all_matches[cur_match];
|
2007-01-14 10:37:44 +01:00
|
|
|
fprintf(stderr, " %-11s %8d %s\n",
|
|
|
|
prio_names[t->name->prio],
|
2007-01-13 23:30:53 +01:00
|
|
|
t->depth, t->name->path);
|
|
|
|
}
|
2011-02-23 00:42:23 +01:00
|
|
|
fprintf(stderr, _("traversed %lu commits\n"), seen_commits);
|
2007-01-13 23:30:53 +01:00
|
|
|
if (gave_up_on) {
|
|
|
|
fprintf(stderr,
|
2011-02-23 00:42:23 +01:00
|
|
|
_("more than %i tags found; listed %i most recent\n"
|
|
|
|
"gave up search at %s\n"),
|
2007-01-13 23:30:53 +01:00
|
|
|
max_candidates, max_candidates,
|
|
|
|
sha1_to_hex(gave_up_on->object.sha1));
|
|
|
|
}
|
2007-01-10 12:39:47 +01:00
|
|
|
}
|
2008-02-28 07:22:36 +01:00
|
|
|
|
|
|
|
display_name(all_matches[0].name);
|
|
|
|
if (abbrev)
|
2008-03-03 22:08:26 +01:00
|
|
|
show_suffix(all_matches[0].depth, cmit->object.sha1);
|
2009-10-21 15:35:22 +02:00
|
|
|
if (dirty)
|
|
|
|
printf("%s", dirty);
|
2008-02-28 07:22:36 +01:00
|
|
|
printf("\n");
|
2007-01-10 12:39:47 +01:00
|
|
|
|
2007-01-13 23:30:53 +01:00
|
|
|
if (!last_one)
|
|
|
|
clear_commit_marks(cmit, -1);
|
Add a "git-describe" command
It shows you the most recent tag that is reachable from a particular
commit is.
Maybe this is something that "git-name-rev" should be taught to do,
instead of having a separate command for it. Regardless, I find it useful.
What it does is to take any random commit, and "name" it by looking up the
most recent commit that is tagged and reachable from that commit. If the
match is exact, it will just print out that ref-name directly. Otherwise
it will print out the ref-name, followed by the 8-character "short SHA".
IOW, with something like Junios current tree, I get:
[torvalds@g5 git]$ git-describe parent
refs/tags/v1.0.4-g2414721b
ie the current head of my "parent" branch (ie Junio) is based on v1.0.4,
but since it has a few commits on top of that, it has added the git hash
of the thing to the end: "-g" + 8-char shorthand for the commit
2414721b194453f058079d897d13c4e377f92dc6.
Doing a "git-describe" on a tag-name will just show the full tag path:
[torvalds@g5 git]$ git-describe v1.0.4
refs/tags/v1.0.4
unless there are _other_ tags pointing to that commit, in which case it
will just choose one at random.
This is useful for two things:
- automatic version naming in Makefiles, for example. We could use it in
git itself: when doing "git --version", we could use this to give a
much more useful description of exactly what version was installed.
- for any random commit (say, you use "gitk <pathname>" or
"git-whatchanged" to look at what has changed in some file), you can
figure out what the last version of the repo was. Ie, say I find a bug
in commit 39ca371c45b04cd50d0974030ae051906fc516b6, I just do:
[torvalds@g5 linux]$ git-describe 39ca371c45b04cd50d0974030ae051906fc516b6
refs/tags/v2.6.14-rc4-g39ca371c
and I now know that it was _not_ in v2.6.14-rc4, but was presumably in
v2.6.14-rc5.
The latter is useful when you want to see what "version timeframe" a
commit happened in.
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2005-12-24 22:50:45 +01:00
|
|
|
}
|
|
|
|
|
2007-01-10 12:36:36 +01:00
|
|
|
int cmd_describe(int argc, const char **argv, const char *prefix)
|
Add a "git-describe" command
It shows you the most recent tag that is reachable from a particular
commit is.
Maybe this is something that "git-name-rev" should be taught to do,
instead of having a separate command for it. Regardless, I find it useful.
What it does is to take any random commit, and "name" it by looking up the
most recent commit that is tagged and reachable from that commit. If the
match is exact, it will just print out that ref-name directly. Otherwise
it will print out the ref-name, followed by the 8-character "short SHA".
IOW, with something like Junios current tree, I get:
[torvalds@g5 git]$ git-describe parent
refs/tags/v1.0.4-g2414721b
ie the current head of my "parent" branch (ie Junio) is based on v1.0.4,
but since it has a few commits on top of that, it has added the git hash
of the thing to the end: "-g" + 8-char shorthand for the commit
2414721b194453f058079d897d13c4e377f92dc6.
Doing a "git-describe" on a tag-name will just show the full tag path:
[torvalds@g5 git]$ git-describe v1.0.4
refs/tags/v1.0.4
unless there are _other_ tags pointing to that commit, in which case it
will just choose one at random.
This is useful for two things:
- automatic version naming in Makefiles, for example. We could use it in
git itself: when doing "git --version", we could use this to give a
much more useful description of exactly what version was installed.
- for any random commit (say, you use "gitk <pathname>" or
"git-whatchanged" to look at what has changed in some file), you can
figure out what the last version of the repo was. Ie, say I find a bug
in commit 39ca371c45b04cd50d0974030ae051906fc516b6, I just do:
[torvalds@g5 linux]$ git-describe 39ca371c45b04cd50d0974030ae051906fc516b6
refs/tags/v2.6.14-rc4-g39ca371c
and I now know that it was _not_ in v2.6.14-rc4, but was presumably in
v2.6.14-rc5.
The latter is useful when you want to see what "version timeframe" a
commit happened in.
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2005-12-24 22:50:45 +01:00
|
|
|
{
|
2007-05-21 09:20:25 +02:00
|
|
|
int contains = 0;
|
2007-10-07 20:54:08 +02:00
|
|
|
struct option options[] = {
|
2013-08-03 13:51:19 +02:00
|
|
|
OPT_BOOL(0, "contains", &contains, N_("find the tag that comes after the commit")),
|
|
|
|
OPT_BOOL(0, "debug", &debug, N_("debug search strategy on stderr")),
|
|
|
|
OPT_BOOL(0, "all", &all, N_("use any ref")),
|
|
|
|
OPT_BOOL(0, "tags", &tags, N_("use any tag, even unannotated")),
|
|
|
|
OPT_BOOL(0, "long", &longformat, N_("always use long format")),
|
|
|
|
OPT_BOOL(0, "first-parent", &first_parent, N_("only follow first parent")),
|
2007-10-07 20:54:08 +02:00
|
|
|
OPT__ABBREV(&abbrev),
|
2008-02-24 09:07:31 +01:00
|
|
|
OPT_SET_INT(0, "exact-match", &max_candidates,
|
2012-08-20 14:32:07 +02:00
|
|
|
N_("only output exact matches"), 0),
|
2007-10-07 20:54:08 +02:00
|
|
|
OPT_INTEGER(0, "candidates", &max_candidates,
|
2012-08-20 14:32:07 +02:00
|
|
|
N_("consider <n> most recent tags (default: 10)")),
|
|
|
|
OPT_STRING(0, "match", &pattern, N_("pattern"),
|
|
|
|
N_("only consider tags matching <pattern>")),
|
2013-08-03 13:51:19 +02:00
|
|
|
OPT_BOOL(0, "always", &always,
|
|
|
|
N_("show abbreviated commit object as fallback")),
|
2012-08-20 14:32:07 +02:00
|
|
|
{OPTION_STRING, 0, "dirty", &dirty, N_("mark"),
|
2013-08-03 13:51:19 +02:00
|
|
|
N_("append <mark> on dirty working tree (default: \"-dirty\")"),
|
|
|
|
PARSE_OPT_OPTARG, NULL, (intptr_t) "-dirty"},
|
2007-10-07 20:54:08 +02:00
|
|
|
OPT_END(),
|
|
|
|
};
|
Add a "git-describe" command
It shows you the most recent tag that is reachable from a particular
commit is.
Maybe this is something that "git-name-rev" should be taught to do,
instead of having a separate command for it. Regardless, I find it useful.
What it does is to take any random commit, and "name" it by looking up the
most recent commit that is tagged and reachable from that commit. If the
match is exact, it will just print out that ref-name directly. Otherwise
it will print out the ref-name, followed by the 8-character "short SHA".
IOW, with something like Junios current tree, I get:
[torvalds@g5 git]$ git-describe parent
refs/tags/v1.0.4-g2414721b
ie the current head of my "parent" branch (ie Junio) is based on v1.0.4,
but since it has a few commits on top of that, it has added the git hash
of the thing to the end: "-g" + 8-char shorthand for the commit
2414721b194453f058079d897d13c4e377f92dc6.
Doing a "git-describe" on a tag-name will just show the full tag path:
[torvalds@g5 git]$ git-describe v1.0.4
refs/tags/v1.0.4
unless there are _other_ tags pointing to that commit, in which case it
will just choose one at random.
This is useful for two things:
- automatic version naming in Makefiles, for example. We could use it in
git itself: when doing "git --version", we could use this to give a
much more useful description of exactly what version was installed.
- for any random commit (say, you use "gitk <pathname>" or
"git-whatchanged" to look at what has changed in some file), you can
figure out what the last version of the repo was. Ie, say I find a bug
in commit 39ca371c45b04cd50d0974030ae051906fc516b6, I just do:
[torvalds@g5 linux]$ git-describe 39ca371c45b04cd50d0974030ae051906fc516b6
refs/tags/v2.6.14-rc4-g39ca371c
and I now know that it was _not_ in v2.6.14-rc4, but was presumably in
v2.6.14-rc5.
The latter is useful when you want to see what "version timeframe" a
commit happened in.
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2005-12-24 22:50:45 +01:00
|
|
|
|
2010-10-28 20:28:04 +02:00
|
|
|
git_config(git_default_config, NULL);
|
2009-05-23 20:53:12 +02:00
|
|
|
argc = parse_options(argc, argv, prefix, options, describe_usage, 0);
|
2010-10-28 20:28:04 +02:00
|
|
|
if (abbrev < 0)
|
|
|
|
abbrev = DEFAULT_ABBREV;
|
|
|
|
|
2008-02-24 09:07:31 +01:00
|
|
|
if (max_candidates < 0)
|
|
|
|
max_candidates = 0;
|
2007-10-07 20:54:08 +02:00
|
|
|
else if (max_candidates > MAX_TAGS)
|
|
|
|
max_candidates = MAX_TAGS;
|
2006-01-11 22:57:42 +01:00
|
|
|
|
2007-01-10 12:36:29 +01:00
|
|
|
save_commit_buffer = 0;
|
2006-09-14 03:03:59 +02:00
|
|
|
|
2008-02-25 10:43:33 +01:00
|
|
|
if (longformat && abbrev == 0)
|
2011-02-23 00:42:23 +01:00
|
|
|
die(_("--long is incompatible with --abbrev=0"));
|
2008-02-25 10:43:33 +01:00
|
|
|
|
2007-05-21 09:20:25 +02:00
|
|
|
if (contains) {
|
2013-07-07 23:42:23 +02:00
|
|
|
struct argv_array args;
|
|
|
|
|
|
|
|
argv_array_init(&args);
|
2013-07-18 23:46:51 +02:00
|
|
|
argv_array_pushl(&args, "name-rev",
|
|
|
|
"--peel-tag", "--name-only", "--no-undefined",
|
2013-07-07 23:42:23 +02:00
|
|
|
NULL);
|
2008-03-02 17:51:57 +01:00
|
|
|
if (always)
|
2013-07-07 23:42:23 +02:00
|
|
|
argv_array_push(&args, "--always");
|
2007-12-21 22:49:54 +01:00
|
|
|
if (!all) {
|
2013-07-07 23:42:23 +02:00
|
|
|
argv_array_push(&args, "--tags");
|
|
|
|
if (pattern)
|
|
|
|
argv_array_pushf(&args, "--refs=refs/tags/%s", pattern);
|
|
|
|
}
|
|
|
|
while (*argv) {
|
|
|
|
argv_array_push(&args, *argv);
|
|
|
|
argv++;
|
2007-12-21 22:49:54 +01:00
|
|
|
}
|
2013-07-07 23:42:23 +02:00
|
|
|
return cmd_name_rev(args.argc, args.argv, prefix);
|
2007-05-21 09:20:25 +02:00
|
|
|
}
|
|
|
|
|
2013-11-14 20:18:35 +01:00
|
|
|
hashmap_init(&names, (hashmap_cmp_fn) commit_name_cmp, 0);
|
2010-12-09 07:42:25 +01:00
|
|
|
for_each_rawref(get_name, NULL);
|
2013-11-14 20:18:35 +01:00
|
|
|
if (!names.size && !always)
|
2011-02-23 00:42:23 +01:00
|
|
|
die(_("No names found, cannot describe anything."));
|
2009-10-17 18:30:48 +02:00
|
|
|
|
2007-10-07 20:54:08 +02:00
|
|
|
if (argc == 0) {
|
2011-08-01 03:52:41 +02:00
|
|
|
if (dirty) {
|
|
|
|
static struct lock_file index_lock;
|
|
|
|
int fd;
|
|
|
|
|
|
|
|
read_cache_preload(NULL);
|
|
|
|
refresh_index(&the_index, REFRESH_QUIET|REFRESH_UNMERGED,
|
|
|
|
NULL, NULL, NULL);
|
|
|
|
fd = hold_locked_index(&index_lock, 0);
|
|
|
|
if (0 <= fd)
|
|
|
|
update_index_if_able(&the_index, &index_lock);
|
|
|
|
|
|
|
|
if (!cmd_diff_index(ARRAY_SIZE(diff_index_args) - 1,
|
|
|
|
diff_index_args, prefix))
|
|
|
|
dirty = NULL;
|
|
|
|
}
|
2006-01-16 07:25:35 +01:00
|
|
|
describe("HEAD", 1);
|
2009-10-21 15:35:22 +02:00
|
|
|
} else if (dirty) {
|
2013-09-04 21:04:31 +02:00
|
|
|
die(_("--dirty is incompatible with commit-ishes"));
|
2007-10-07 20:54:08 +02:00
|
|
|
} else {
|
2013-10-31 10:25:41 +01:00
|
|
|
while (argc-- > 0)
|
2007-10-07 20:54:08 +02:00
|
|
|
describe(*argv++, argc == 0);
|
|
|
|
}
|
Add a "git-describe" command
It shows you the most recent tag that is reachable from a particular
commit is.
Maybe this is something that "git-name-rev" should be taught to do,
instead of having a separate command for it. Regardless, I find it useful.
What it does is to take any random commit, and "name" it by looking up the
most recent commit that is tagged and reachable from that commit. If the
match is exact, it will just print out that ref-name directly. Otherwise
it will print out the ref-name, followed by the 8-character "short SHA".
IOW, with something like Junios current tree, I get:
[torvalds@g5 git]$ git-describe parent
refs/tags/v1.0.4-g2414721b
ie the current head of my "parent" branch (ie Junio) is based on v1.0.4,
but since it has a few commits on top of that, it has added the git hash
of the thing to the end: "-g" + 8-char shorthand for the commit
2414721b194453f058079d897d13c4e377f92dc6.
Doing a "git-describe" on a tag-name will just show the full tag path:
[torvalds@g5 git]$ git-describe v1.0.4
refs/tags/v1.0.4
unless there are _other_ tags pointing to that commit, in which case it
will just choose one at random.
This is useful for two things:
- automatic version naming in Makefiles, for example. We could use it in
git itself: when doing "git --version", we could use this to give a
much more useful description of exactly what version was installed.
- for any random commit (say, you use "gitk <pathname>" or
"git-whatchanged" to look at what has changed in some file), you can
figure out what the last version of the repo was. Ie, say I find a bug
in commit 39ca371c45b04cd50d0974030ae051906fc516b6, I just do:
[torvalds@g5 linux]$ git-describe 39ca371c45b04cd50d0974030ae051906fc516b6
refs/tags/v2.6.14-rc4-g39ca371c
and I now know that it was _not_ in v2.6.14-rc4, but was presumably in
v2.6.14-rc5.
The latter is useful when you want to see what "version timeframe" a
commit happened in.
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2005-12-24 22:50:45 +01:00
|
|
|
return 0;
|
|
|
|
}
|