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 21:50:45 +00:00
|
|
|
#include "cache.h"
|
2017-06-14 18:07:36 +00:00
|
|
|
#include "config.h"
|
2014-10-01 10:28:42 +00:00
|
|
|
#include "lockfile.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 21:50:45 +00:00
|
|
|
#include "commit.h"
|
2005-12-27 22:36:49 +00:00
|
|
|
#include "tag.h"
|
builtin/describe.c: describe a blob
Sometimes users are given a hash of an object and they want to
identify it further (ex.: Use verify-pack to find the largest blobs,
but what are these? or [1])
When describing commits, we try to anchor them to tags or refs, as these
are conceptually on a higher level than the commit. And if there is no ref
or tag that matches exactly, we're out of luck. So we employ a heuristic
to make up a name for the commit. These names are ambiguous, there might
be different tags or refs to anchor to, and there might be different
path in the DAG to travel to arrive at the commit precisely.
When describing a blob, we want to describe the blob from a higher layer
as well, which is a tuple of (commit, deep/path) as the tree objects
involved are rather uninteresting. The same blob can be referenced by
multiple commits, so how we decide which commit to use? This patch
implements a rather naive approach on this: As there are no back pointers
from blobs to commits in which the blob occurs, we'll start walking from
any tips available, listing the blobs in-order of the commit and once we
found the blob, we'll take the first commit that listed the blob. For
example
git describe --tags v0.99:Makefile
conversion-901-g7672db20c2:Makefile
tells us the Makefile as it was in v0.99 was introduced in commit 7672db20.
The walking is performed in reverse order to show the introduction of a
blob rather than its last occurrence.
[1] https://stackoverflow.com/questions/223678/which-commit-has-this-blob
Signed-off-by: Stefan Beller <sbeller@google.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-11-16 02:00:39 +00:00
|
|
|
#include "blob.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 21:50:45 +00:00
|
|
|
#include "refs.h"
|
2007-01-10 11:36:36 +00:00
|
|
|
#include "builtin.h"
|
2007-05-21 07:20:25 +00:00
|
|
|
#include "exec_cmd.h"
|
2007-10-07 18:54:08 +00:00
|
|
|
#include "parse-options.h"
|
describe: do not use cmd_*() as a subroutine
The cmd_foo() function is a moral equivalent of 'main' for a Git
subcommand 'git foo', and as such, it is allowed to do many things
that make it unsuitable to be called as a subroutine, including
- call exit(3) to terminate the process;
- allocate resource held and used throughout its lifetime, without
releasing it upon return/exit;
- rely on global variables being initialized at program startup,
and update them as needed, making another clean invocation of the
function impossible.
The call to cmd_diff_index() "git describe" makes has been working
by accident that the function did not call exit(3); it sets a bad
precedent for people to cut and paste.
We could invoke it via the run_command() interface, but the diff
family of commands have helper functions in diff-lib.c that are
meant to be usable as subroutines, and using the latter does not
make the resulting code all that longer. Use it.
Note that there is also an invocation of cmd_name_rev() at the end;
"git describe --contains" massages its command line arguments to be
suitable for "git name-rev" invocation and jumps to it, never to
regain control. This call is left as-is as an exception to the
rule. When we start to allow calling name-rev repeatedly as a
helper function, we would be able to remove this call as well.
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-10-10 03:42:58 +00:00
|
|
|
#include "revision.h"
|
2009-10-21 13:35:22 +00:00
|
|
|
#include "diff.h"
|
2013-11-14 19:18:35 +00:00
|
|
|
#include "hashmap.h"
|
2013-07-07 21:42:23 +00:00
|
|
|
#include "argv-array.h"
|
2017-03-21 22:57:18 +00:00
|
|
|
#include "run-command.h"
|
builtin/describe.c: describe a blob
Sometimes users are given a hash of an object and they want to
identify it further (ex.: Use verify-pack to find the largest blobs,
but what are these? or [1])
When describing commits, we try to anchor them to tags or refs, as these
are conceptually on a higher level than the commit. And if there is no ref
or tag that matches exactly, we're out of luck. So we employ a heuristic
to make up a name for the commit. These names are ambiguous, there might
be different tags or refs to anchor to, and there might be different
path in the DAG to travel to arrive at the commit precisely.
When describing a blob, we want to describe the blob from a higher layer
as well, which is a tuple of (commit, deep/path) as the tree objects
involved are rather uninteresting. The same blob can be referenced by
multiple commits, so how we decide which commit to use? This patch
implements a rather naive approach on this: As there are no back pointers
from blobs to commits in which the blob occurs, we'll start walking from
any tips available, listing the blobs in-order of the commit and once we
found the blob, we'll take the first commit that listed the blob. For
example
git describe --tags v0.99:Makefile
conversion-901-g7672db20c2:Makefile
tells us the Makefile as it was in v0.99 was introduced in commit 7672db20.
The walking is performed in reverse order to show the introduction of a
blob rather than its last occurrence.
[1] https://stackoverflow.com/questions/223678/which-commit-has-this-blob
Signed-off-by: Stefan Beller <sbeller@google.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-11-16 02:00:39 +00:00
|
|
|
#include "revision.h"
|
|
|
|
#include "list-objects.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 21:50:45 +00:00
|
|
|
|
2007-01-13 22:30:53 +00:00
|
|
|
#define MAX_TAGS (FLAG_BITS - 1)
|
|
|
|
|
2007-10-07 18:54:08 +00:00
|
|
|
static const char * const describe_usage[] = {
|
2015-01-13 07:44:47 +00:00
|
|
|
N_("git describe [<options>] [<commit-ish>...]"),
|
|
|
|
N_("git describe [<options>] --dirty"),
|
2007-10-07 18:54:08 +00: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 21:50:45 +00:00
|
|
|
|
2007-01-13 22:30:53 +00:00
|
|
|
static int debug; /* Display lots of verbose info */
|
2008-10-13 14:39:46 +00:00
|
|
|
static int all; /* Any valid ref can be used */
|
|
|
|
static int tags; /* Allow lightweight tags */
|
2008-02-25 09:43:33 +00:00
|
|
|
static int longformat;
|
2013-05-17 20:56:18 +00:00
|
|
|
static int first_parent;
|
2010-10-28 18:28:04 +00:00
|
|
|
static int abbrev = -1; /* unspecified */
|
2007-01-13 22:30:53 +00:00
|
|
|
static int max_candidates = 10;
|
2013-11-14 19:18:35 +00:00
|
|
|
static struct hashmap names;
|
2010-12-09 06:47:29 +00:00
|
|
|
static int have_util;
|
2017-01-18 23:06:07 +00:00
|
|
|
static struct string_list patterns = STRING_LIST_INIT_NODUP;
|
2017-01-18 23:06:08 +00:00
|
|
|
static struct string_list exclude_patterns = STRING_LIST_INIT_NODUP;
|
2008-03-02 16:51:57 +00:00
|
|
|
static int always;
|
2017-03-21 22:57:18 +00:00
|
|
|
static const char *suffix, *dirty, *broken;
|
2009-10-21 13:35:22 +00:00
|
|
|
|
|
|
|
/* 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 03:16:55 +00:00
|
|
|
struct commit_name {
|
2013-11-14 19:18:35 +00:00
|
|
|
struct hashmap_entry entry;
|
2017-02-21 23:47:22 +00:00
|
|
|
struct object_id peeled;
|
2008-02-28 06:22:36 +00:00
|
|
|
struct tag *tag;
|
2010-04-12 23:25:29 +00:00
|
|
|
unsigned prio:2; /* annotated tag = 2, tag = 1, head = 0 */
|
|
|
|
unsigned name_checked:1;
|
2017-02-21 23:47:22 +00:00
|
|
|
struct object_id oid;
|
2013-05-25 09:08:00 +00:00
|
|
|
char *path;
|
2007-01-15 03:16:55 +00:00
|
|
|
};
|
2013-10-31 09:25:41 +00:00
|
|
|
|
2007-01-14 09:37:44 +00:00
|
|
|
static const char *prio_names[] = {
|
2017-03-27 16:50:05 +00:00
|
|
|
N_("head"), N_("lightweight"), N_("annotated"),
|
2007-01-14 09:37:44 +00:00
|
|
|
};
|
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 21:50:45 +00:00
|
|
|
|
2017-06-30 19:14:05 +00:00
|
|
|
static int commit_name_cmp(const void *unused_cmp_data,
|
2017-07-01 00:28:31 +00:00
|
|
|
const void *entry,
|
|
|
|
const void *entry_or_key,
|
2017-06-30 19:14:05 +00:00
|
|
|
const void *peeled)
|
2013-11-14 19:18:35 +00:00
|
|
|
{
|
2017-07-01 00:28:31 +00:00
|
|
|
const struct commit_name *cn1 = entry;
|
|
|
|
const struct commit_name *cn2 = entry_or_key;
|
|
|
|
|
2017-02-21 23:47:22 +00:00
|
|
|
return oidcmp(&cn1->peeled, peeled ? peeled : &cn2->peeled);
|
2013-11-14 19:18:35 +00:00
|
|
|
}
|
|
|
|
|
2017-02-21 23:47:22 +00:00
|
|
|
static inline struct commit_name *find_commit_name(const struct object_id *peeled)
|
2010-12-09 06:46:08 +00:00
|
|
|
{
|
2017-02-21 23:47:22 +00:00
|
|
|
return hashmap_get_from_hash(&names, sha1hash(peeled->hash), peeled->hash);
|
2010-12-09 06:47:29 +00:00
|
|
|
}
|
|
|
|
|
2010-04-12 23:25:29 +00:00
|
|
|
static int replace_name(struct commit_name *e,
|
|
|
|
int prio,
|
2017-02-21 23:47:22 +00:00
|
|
|
const struct object_id *oid,
|
2010-04-12 23:25:29 +00:00
|
|
|
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) {
|
2017-05-06 22:10:19 +00:00
|
|
|
t = lookup_tag(&e->oid);
|
2010-04-12 23:25:29 +00:00
|
|
|
if (!t || parse_tag(t))
|
|
|
|
return 1;
|
|
|
|
e->tag = t;
|
|
|
|
}
|
|
|
|
|
2017-05-06 22:10:19 +00:00
|
|
|
t = lookup_tag(oid);
|
2010-04-12 23:25:29 +00:00
|
|
|
if (!t || parse_tag(t))
|
|
|
|
return 0;
|
|
|
|
*tag = t;
|
|
|
|
|
|
|
|
if (e->tag->date < t->date)
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2005-12-28 00:09:37 +00:00
|
|
|
static void add_to_known_names(const char *path,
|
2017-02-21 23:47:22 +00:00
|
|
|
const struct object_id *peeled,
|
2008-02-28 06:22:36 +00:00
|
|
|
int prio,
|
2017-02-21 23:47:22 +00:00
|
|
|
const struct object_id *oid)
|
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 21:50:45 +00:00
|
|
|
{
|
2010-12-09 06:46:08 +00:00
|
|
|
struct commit_name *e = find_commit_name(peeled);
|
2010-04-12 23:25:29 +00:00
|
|
|
struct tag *tag = NULL;
|
2017-02-21 23:47:22 +00:00
|
|
|
if (replace_name(e, prio, oid, &tag)) {
|
2010-12-09 06:43:32 +00:00
|
|
|
if (!e) {
|
|
|
|
e = xmalloc(sizeof(struct commit_name));
|
2017-02-21 23:47:22 +00:00
|
|
|
oidcpy(&e->peeled, peeled);
|
|
|
|
hashmap_entry_init(e, sha1hash(peeled->hash));
|
2013-11-14 19:18:35 +00:00
|
|
|
hashmap_add(&names, e);
|
2013-05-25 09:08:00 +00:00
|
|
|
e->path = NULL;
|
2010-12-09 06:43:32 +00:00
|
|
|
}
|
2010-04-12 23:25:29 +00:00
|
|
|
e->tag = tag;
|
2007-01-15 03:16:55 +00:00
|
|
|
e->prio = prio;
|
2010-04-12 23:25:29 +00:00
|
|
|
e->name_checked = 0;
|
2017-02-21 23:47:22 +00:00
|
|
|
oidcpy(&e->oid, oid);
|
2013-05-25 09:08:00 +00: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 21:50:45 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-05-25 18:38:34 +00:00
|
|
|
static int get_name(const char *path, const struct object_id *oid, 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 21:50:45 +00:00
|
|
|
{
|
2017-09-20 01:10:10 +00:00
|
|
|
int is_tag = 0;
|
2015-05-25 18:38:34 +00:00
|
|
|
struct object_id peeled;
|
2013-02-28 21:53:00 +00:00
|
|
|
int is_annotated, prio;
|
2017-09-20 01:10:10 +00:00
|
|
|
const char *path_to_match = NULL;
|
|
|
|
|
|
|
|
if (skip_prefix(path, "refs/tags/", &path_to_match)) {
|
|
|
|
is_tag = 1;
|
|
|
|
} else if (all) {
|
|
|
|
if ((exclude_patterns.nr || patterns.nr) &&
|
|
|
|
!skip_prefix(path, "refs/heads/", &path_to_match) &&
|
|
|
|
!skip_prefix(path, "refs/remotes/", &path_to_match)) {
|
|
|
|
/* Only accept reference of known type if there are match/exclude patterns */
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
/* Reject anything outside refs/tags/ unless --all */
|
2008-02-24 08:07:28 +00:00
|
|
|
return 0;
|
2017-09-20 01:10:10 +00:00
|
|
|
}
|
2008-02-24 08:07:28 +00:00
|
|
|
|
2017-01-18 23:06:08 +00:00
|
|
|
/*
|
|
|
|
* If we're given exclude patterns, first exclude any tag which match
|
|
|
|
* any of the exclude pattern.
|
|
|
|
*/
|
|
|
|
if (exclude_patterns.nr) {
|
|
|
|
struct string_list_item *item;
|
|
|
|
|
|
|
|
for_each_string_list_item(item, &exclude_patterns) {
|
2017-09-20 01:10:10 +00:00
|
|
|
if (!wildmatch(item->string, path_to_match, 0))
|
2017-01-18 23:06:08 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-01-18 23:06:07 +00:00
|
|
|
/*
|
|
|
|
* If we're given patterns, accept only tags which match at least one
|
|
|
|
* pattern.
|
|
|
|
*/
|
|
|
|
if (patterns.nr) {
|
2017-09-16 05:53:44 +00:00
|
|
|
int found = 0;
|
2017-01-18 23:06:07 +00:00
|
|
|
struct string_list_item *item;
|
|
|
|
|
|
|
|
for_each_string_list_item(item, &patterns) {
|
2017-09-20 01:10:10 +00:00
|
|
|
if (!wildmatch(item->string, path_to_match, 0)) {
|
2017-09-16 05:53:44 +00:00
|
|
|
found = 1;
|
2017-01-18 23:06:07 +00:00
|
|
|
break;
|
2017-09-16 05:53:44 +00:00
|
|
|
}
|
|
|
|
}
|
2017-01-18 23:06:07 +00:00
|
|
|
|
2017-09-16 05:53:44 +00:00
|
|
|
if (!found)
|
2017-01-18 23:06:07 +00:00
|
|
|
return 0;
|
|
|
|
}
|
2013-02-28 21:53:00 +00:00
|
|
|
|
|
|
|
/* Is it annotated? */
|
2017-10-15 22:07:02 +00:00
|
|
|
if (!peel_ref(path, &peeled)) {
|
2015-05-25 18:38:34 +00:00
|
|
|
is_annotated = !!oidcmp(oid, &peeled);
|
2008-02-24 08:07:25 +00:00
|
|
|
} else {
|
2015-05-25 18:38:34 +00:00
|
|
|
oidcpy(&peeled, oid);
|
2013-02-28 21:53:00 +00:00
|
|
|
is_annotated = 0;
|
2008-02-24 08:07:25 +00:00
|
|
|
}
|
2005-12-28 00:09:37 +00:00
|
|
|
|
2013-02-28 21:53:00 +00: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 22:40:17 +00:00
|
|
|
*/
|
2013-02-28 21:53:00 +00:00
|
|
|
if (is_annotated)
|
|
|
|
prio = 2;
|
|
|
|
else if (is_tag)
|
|
|
|
prio = 1;
|
2005-12-28 00:09:37 +00:00
|
|
|
else
|
|
|
|
prio = 0;
|
|
|
|
|
2017-02-21 23:47:22 +00:00
|
|
|
add_to_known_names(all ? path + 5 : path + 10, &peeled, prio, oid);
|
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 21:50:45 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2007-01-10 11:39:47 +00:00
|
|
|
struct possible_tag {
|
|
|
|
struct commit_name *name;
|
2007-01-14 09:37:44 +00:00
|
|
|
int depth;
|
|
|
|
int found_order;
|
2007-01-13 22:30:53 +00:00
|
|
|
unsigned flag_within;
|
2007-01-10 11:39:47 +00:00
|
|
|
};
|
|
|
|
|
2007-01-14 09:37:44 +00: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 06:54:21 +00: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 01:58:14 +00:00
|
|
|
commit_list_insert_by_date(p, list);
|
2007-01-27 06:54:21 +00:00
|
|
|
p->object.flags |= c->object.flags;
|
|
|
|
parents = parents->next;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return seen_commits;
|
|
|
|
}
|
|
|
|
|
2017-11-16 02:00:38 +00:00
|
|
|
static void append_name(struct commit_name *n, struct strbuf *dst)
|
2008-02-28 06:22:36 +00:00
|
|
|
{
|
|
|
|
if (n->prio == 2 && !n->tag) {
|
2017-05-06 22:10:19 +00:00
|
|
|
n->tag = lookup_tag(&n->oid);
|
2010-04-12 23:25:29 +00:00
|
|
|
if (!n->tag || parse_tag(n->tag))
|
2011-02-22 23:42:23 +00:00
|
|
|
die(_("annotated tag %s not available"), n->path);
|
2010-04-12 23:25:29 +00:00
|
|
|
}
|
|
|
|
if (n->tag && !n->name_checked) {
|
|
|
|
if (!n->tag->tag)
|
2011-02-22 23:42:23 +00:00
|
|
|
die(_("annotated tag %s has no embedded name"), n->path);
|
2008-12-26 22:02:01 +00:00
|
|
|
if (strcmp(n->tag->tag, all ? n->path + 5 : n->path))
|
2011-02-22 23:42:23 +00:00
|
|
|
warning(_("tag '%s' is really '%s' here"), n->tag->tag, n->path);
|
2010-04-12 23:25:29 +00:00
|
|
|
n->name_checked = 1;
|
2008-02-28 06:22:36 +00:00
|
|
|
}
|
|
|
|
|
2017-12-11 17:24:54 +00:00
|
|
|
if (n->tag) {
|
|
|
|
if (all)
|
2018-01-23 21:16:28 +00:00
|
|
|
strbuf_addstr(dst, "tags/");
|
2017-11-16 02:00:38 +00:00
|
|
|
strbuf_addstr(dst, n->tag->tag);
|
2017-12-11 17:24:54 +00:00
|
|
|
} else {
|
2017-11-16 02:00:38 +00:00
|
|
|
strbuf_addstr(dst, n->path);
|
2017-12-11 17:24:54 +00:00
|
|
|
}
|
2008-03-03 21:08:26 +00:00
|
|
|
}
|
|
|
|
|
2017-11-16 02:00:38 +00:00
|
|
|
static void append_suffix(int depth, const struct object_id *oid, struct strbuf *dst)
|
2008-03-03 21:08:26 +00:00
|
|
|
{
|
2017-11-16 02:00:38 +00:00
|
|
|
strbuf_addf(dst, "-%d-g%s", depth, find_unique_abbrev(oid->hash, abbrev));
|
2008-02-28 06:22:36 +00:00
|
|
|
}
|
|
|
|
|
2017-11-16 02:00:38 +00:00
|
|
|
static void describe_commit(struct object_id *oid, struct strbuf *dst)
|
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 21:50:45 +00:00
|
|
|
{
|
2007-01-13 22:30:53 +00: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 21:50:45 +00:00
|
|
|
struct commit_list *list;
|
|
|
|
struct commit_name *n;
|
2007-01-14 09:37:44 +00:00
|
|
|
struct possible_tag all_matches[MAX_TAGS];
|
2007-01-13 22:30:53 +00:00
|
|
|
unsigned int match_cnt = 0, annotated_cnt = 0, cur_match;
|
|
|
|
unsigned long seen_commits = 0;
|
2009-10-28 22:10:06 +00: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 21:50:45 +00:00
|
|
|
|
2017-11-16 02:00:38 +00:00
|
|
|
cmit = lookup_commit_reference(oid);
|
2006-01-11 21:57:42 +00:00
|
|
|
|
2017-02-21 23:47:22 +00:00
|
|
|
n = find_commit_name(&cmit->object.oid);
|
2009-11-18 13:32:26 +00:00
|
|
|
if (n && (tags || all || n->prio == 2)) {
|
2008-03-03 21:08:26 +00:00
|
|
|
/*
|
|
|
|
* Exact match to an existing ref.
|
|
|
|
*/
|
2017-11-16 02:00:38 +00:00
|
|
|
append_name(n, dst);
|
2008-03-03 21:08:26 +00:00
|
|
|
if (longformat)
|
2017-11-16 02:00:38 +00:00
|
|
|
append_suffix(0, n->tag ? &n->tag->tagged->oid : oid, dst);
|
2017-03-21 22:57:18 +00:00
|
|
|
if (suffix)
|
2017-11-16 02:00:38 +00:00
|
|
|
strbuf_addstr(dst, suffix);
|
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 21:50:45 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2008-02-24 08:07:31 +00:00
|
|
|
if (!max_candidates)
|
2015-11-10 02:22:28 +00:00
|
|
|
die(_("no tag exactly matches '%s'"), oid_to_hex(&cmit->object.oid));
|
2007-01-13 22:30:53 +00:00
|
|
|
if (debug)
|
2017-11-16 02:00:37 +00:00
|
|
|
fprintf(stderr, _("No exact match on refs or tags, searching to describe\n"));
|
2007-01-13 22:30:53 +00:00
|
|
|
|
2010-12-09 06:47:29 +00:00
|
|
|
if (!have_util) {
|
2013-11-14 19:18:35 +00:00
|
|
|
struct hashmap_iter iter;
|
|
|
|
struct commit *c;
|
|
|
|
struct commit_name *n = hashmap_iter_first(&names, &iter);
|
|
|
|
for (; n; n = hashmap_iter_next(&iter)) {
|
Convert lookup_commit* to struct object_id
Convert lookup_commit, lookup_commit_or_die,
lookup_commit_reference, and lookup_commit_reference_gently to take
struct object_id arguments.
Introduce a temporary in parse_object buffer in order to convert this
function. This is required since in order to convert parse_object and
parse_object_buffer, lookup_commit_reference_gently and
lookup_commit_or_die would need to be converted. Not introducing a
temporary would therefore require that lookup_commit_or_die take a
struct object_id *, but lookup_commit would take unsigned char *,
leaving a confusing and hard-to-use interface.
parse_object_buffer will lose this temporary in a later patch.
This commit was created with manual changes to commit.c, commit.h, and
object.c, plus the following semantic patch:
@@
expression E1, E2;
@@
- lookup_commit_reference_gently(E1.hash, E2)
+ lookup_commit_reference_gently(&E1, E2)
@@
expression E1, E2;
@@
- lookup_commit_reference_gently(E1->hash, E2)
+ lookup_commit_reference_gently(E1, E2)
@@
expression E1;
@@
- lookup_commit_reference(E1.hash)
+ lookup_commit_reference(&E1)
@@
expression E1;
@@
- lookup_commit_reference(E1->hash)
+ lookup_commit_reference(E1)
@@
expression E1;
@@
- lookup_commit(E1.hash)
+ lookup_commit(&E1)
@@
expression E1;
@@
- lookup_commit(E1->hash)
+ lookup_commit(E1)
@@
expression E1, E2;
@@
- lookup_commit_or_die(E1.hash, E2)
+ lookup_commit_or_die(&E1, E2)
@@
expression E1, E2;
@@
- lookup_commit_or_die(E1->hash, E2)
+ lookup_commit_or_die(E1, E2)
Signed-off-by: brian m. carlson <sandals@crustytoothpaste.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-05-06 22:10:10 +00:00
|
|
|
c = lookup_commit_reference_gently(&n->peeled, 1);
|
2013-11-14 19:18:35 +00:00
|
|
|
if (c)
|
|
|
|
c->util = n;
|
|
|
|
}
|
2010-12-09 06:47:29 +00: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 21:50:45 +00:00
|
|
|
list = NULL;
|
2007-01-13 22:30:53 +00: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 21:50:45 +00:00
|
|
|
commit_list_insert(cmit, &list);
|
|
|
|
while (list) {
|
2007-01-10 11:39:47 +00:00
|
|
|
struct commit *c = pop_commit(&list);
|
2007-01-13 22:27:52 +00:00
|
|
|
struct commit_list *parents = c->parents;
|
2007-01-13 22:30:53 +00:00
|
|
|
seen_commits++;
|
2007-01-15 03:16:55 +00: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 21:50:45 +00:00
|
|
|
if (n) {
|
2009-10-28 22:10:06 +00:00
|
|
|
if (!tags && !all && n->prio < 2) {
|
|
|
|
unannotated_cnt++;
|
|
|
|
} else if (match_cnt < max_candidates) {
|
2007-01-13 22:30:53 +00: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 17:40:03 +00:00
|
|
|
t->found_order = match_cnt;
|
2007-01-13 22:30:53 +00: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-22 23:42:23 +00:00
|
|
|
fprintf(stderr, _("finished search at %s\n"),
|
2015-11-10 02:22:28 +00:00
|
|
|
oid_to_hex(&c->object.oid));
|
2007-01-13 22:30:53 +00:00
|
|
|
break;
|
2007-01-13 22:27:52 +00:00
|
|
|
}
|
|
|
|
while (parents) {
|
|
|
|
struct commit *p = parents->item;
|
|
|
|
parse_commit(p);
|
2007-01-13 22:30:53 +00:00
|
|
|
if (!(p->object.flags & SEEN))
|
2010-11-27 01:58:14 +00:00
|
|
|
commit_list_insert_by_date(p, &list);
|
2007-01-13 22:30:53 +00:00
|
|
|
p->object.flags |= c->object.flags;
|
2007-01-13 22:27:52 +00:00
|
|
|
parents = parents->next;
|
2013-05-17 20:56:18 +00:00
|
|
|
|
|
|
|
if (first_parent)
|
|
|
|
break;
|
2007-01-10 11:39:47 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-03-02 16:51:57 +00:00
|
|
|
if (!match_cnt) {
|
2017-11-16 02:00:36 +00:00
|
|
|
struct object_id *cmit_oid = &cmit->object.oid;
|
2008-03-02 16:51:57 +00:00
|
|
|
if (always) {
|
2018-01-15 17:10:32 +00:00
|
|
|
strbuf_add_unique_abbrev(dst, cmit_oid->hash, abbrev);
|
2017-03-21 22:57:18 +00:00
|
|
|
if (suffix)
|
2017-11-16 02:00:38 +00:00
|
|
|
strbuf_addstr(dst, suffix);
|
2008-03-02 16:51:57 +00:00
|
|
|
return;
|
|
|
|
}
|
2009-10-28 22:10:06 +00:00
|
|
|
if (unannotated_cnt)
|
2011-02-22 23:42:23 +00:00
|
|
|
die(_("No annotated tags can describe '%s'.\n"
|
|
|
|
"However, there were unannotated tags: try --tags."),
|
2017-11-16 02:00:36 +00:00
|
|
|
oid_to_hex(cmit_oid));
|
2009-10-28 22:10:06 +00:00
|
|
|
else
|
2011-02-22 23:42:23 +00:00
|
|
|
die(_("No tags can describe '%s'.\n"
|
|
|
|
"Try --always, or create some tags."),
|
2017-11-16 02:00:36 +00:00
|
|
|
oid_to_hex(cmit_oid));
|
2008-03-02 16:51:57 +00:00
|
|
|
}
|
2007-01-10 11:39:47 +00:00
|
|
|
|
2016-09-29 15:27:31 +00:00
|
|
|
QSORT(all_matches, match_cnt, compare_pt);
|
2007-01-27 06:54:21 +00:00
|
|
|
|
|
|
|
if (gave_up_on) {
|
2010-11-27 01:58:14 +00:00
|
|
|
commit_list_insert_by_date(gave_up_on, &list);
|
2007-01-27 06:54:21 +00:00
|
|
|
seen_commits--;
|
|
|
|
}
|
|
|
|
seen_commits += finish_depth_computation(&list, &all_matches[0]);
|
|
|
|
free_commit_list(list);
|
|
|
|
|
2007-01-13 22:30:53 +00:00
|
|
|
if (debug) {
|
2017-03-27 16:50:05 +00:00
|
|
|
static int label_width = -1;
|
|
|
|
if (label_width < 0) {
|
|
|
|
int i, w;
|
|
|
|
for (i = 0; i < ARRAY_SIZE(prio_names); i++) {
|
|
|
|
w = strlen(_(prio_names[i]));
|
|
|
|
if (label_width < w)
|
|
|
|
label_width = w;
|
|
|
|
}
|
|
|
|
}
|
2007-01-13 22:30:53 +00:00
|
|
|
for (cur_match = 0; cur_match < match_cnt; cur_match++) {
|
|
|
|
struct possible_tag *t = &all_matches[cur_match];
|
2017-03-27 16:50:05 +00:00
|
|
|
fprintf(stderr, " %-*s %8d %s\n",
|
|
|
|
label_width, _(prio_names[t->name->prio]),
|
2007-01-13 22:30:53 +00:00
|
|
|
t->depth, t->name->path);
|
|
|
|
}
|
2011-02-22 23:42:23 +00:00
|
|
|
fprintf(stderr, _("traversed %lu commits\n"), seen_commits);
|
2007-01-13 22:30:53 +00:00
|
|
|
if (gave_up_on) {
|
|
|
|
fprintf(stderr,
|
2011-02-22 23:42:23 +00:00
|
|
|
_("more than %i tags found; listed %i most recent\n"
|
|
|
|
"gave up search at %s\n"),
|
2007-01-13 22:30:53 +00:00
|
|
|
max_candidates, max_candidates,
|
2015-11-10 02:22:28 +00:00
|
|
|
oid_to_hex(&gave_up_on->object.oid));
|
2007-01-13 22:30:53 +00:00
|
|
|
}
|
2007-01-10 11:39:47 +00:00
|
|
|
}
|
2008-02-28 06:22:36 +00:00
|
|
|
|
2017-11-16 02:00:38 +00:00
|
|
|
append_name(all_matches[0].name, dst);
|
2008-02-28 06:22:36 +00:00
|
|
|
if (abbrev)
|
2017-11-16 02:00:38 +00:00
|
|
|
append_suffix(all_matches[0].depth, &cmit->object.oid, dst);
|
2017-03-21 22:57:18 +00:00
|
|
|
if (suffix)
|
2017-11-16 02:00:38 +00:00
|
|
|
strbuf_addstr(dst, suffix);
|
|
|
|
}
|
|
|
|
|
builtin/describe.c: describe a blob
Sometimes users are given a hash of an object and they want to
identify it further (ex.: Use verify-pack to find the largest blobs,
but what are these? or [1])
When describing commits, we try to anchor them to tags or refs, as these
are conceptually on a higher level than the commit. And if there is no ref
or tag that matches exactly, we're out of luck. So we employ a heuristic
to make up a name for the commit. These names are ambiguous, there might
be different tags or refs to anchor to, and there might be different
path in the DAG to travel to arrive at the commit precisely.
When describing a blob, we want to describe the blob from a higher layer
as well, which is a tuple of (commit, deep/path) as the tree objects
involved are rather uninteresting. The same blob can be referenced by
multiple commits, so how we decide which commit to use? This patch
implements a rather naive approach on this: As there are no back pointers
from blobs to commits in which the blob occurs, we'll start walking from
any tips available, listing the blobs in-order of the commit and once we
found the blob, we'll take the first commit that listed the blob. For
example
git describe --tags v0.99:Makefile
conversion-901-g7672db20c2:Makefile
tells us the Makefile as it was in v0.99 was introduced in commit 7672db20.
The walking is performed in reverse order to show the introduction of a
blob rather than its last occurrence.
[1] https://stackoverflow.com/questions/223678/which-commit-has-this-blob
Signed-off-by: Stefan Beller <sbeller@google.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-11-16 02:00:39 +00:00
|
|
|
struct process_commit_data {
|
|
|
|
struct object_id current_commit;
|
|
|
|
struct object_id looking_for;
|
|
|
|
struct strbuf *dst;
|
|
|
|
struct rev_info *revs;
|
|
|
|
};
|
|
|
|
|
|
|
|
static void process_commit(struct commit *commit, void *data)
|
|
|
|
{
|
|
|
|
struct process_commit_data *pcd = data;
|
|
|
|
pcd->current_commit = commit->object.oid;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void process_object(struct object *obj, const char *path, void *data)
|
|
|
|
{
|
|
|
|
struct process_commit_data *pcd = data;
|
|
|
|
|
|
|
|
if (!oidcmp(&pcd->looking_for, &obj->oid) && !pcd->dst->len) {
|
|
|
|
reset_revision_walk();
|
|
|
|
describe_commit(&pcd->current_commit, pcd->dst);
|
|
|
|
strbuf_addf(pcd->dst, ":%s", path);
|
|
|
|
free_commit_list(pcd->revs->commits);
|
|
|
|
pcd->revs->commits = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void describe_blob(struct object_id oid, struct strbuf *dst)
|
|
|
|
{
|
|
|
|
struct rev_info revs;
|
|
|
|
struct argv_array args = ARGV_ARRAY_INIT;
|
|
|
|
struct process_commit_data pcd = { null_oid, oid, dst, &revs};
|
|
|
|
|
|
|
|
argv_array_pushl(&args, "internal: The first arg is not parsed",
|
|
|
|
"--objects", "--in-commit-order", "--reverse", "HEAD",
|
|
|
|
NULL);
|
|
|
|
|
|
|
|
init_revisions(&revs, NULL);
|
|
|
|
if (setup_revisions(args.argc, args.argv, &revs, NULL) > 1)
|
|
|
|
BUG("setup_revisions could not handle all args?");
|
|
|
|
|
|
|
|
if (prepare_revision_walk(&revs))
|
|
|
|
die("revision walk setup failed");
|
|
|
|
|
|
|
|
traverse_commit_list(&revs, process_commit, process_object, &pcd);
|
|
|
|
reset_revision_walk();
|
|
|
|
}
|
|
|
|
|
2017-11-16 02:00:38 +00:00
|
|
|
static void describe(const char *arg, int last_one)
|
|
|
|
{
|
|
|
|
struct object_id oid;
|
|
|
|
struct commit *cmit;
|
|
|
|
struct strbuf sb = STRBUF_INIT;
|
|
|
|
|
|
|
|
if (debug)
|
|
|
|
fprintf(stderr, _("describe %s\n"), arg);
|
|
|
|
|
|
|
|
if (get_oid(arg, &oid))
|
|
|
|
die(_("Not a valid object name %s"), arg);
|
builtin/describe.c: describe a blob
Sometimes users are given a hash of an object and they want to
identify it further (ex.: Use verify-pack to find the largest blobs,
but what are these? or [1])
When describing commits, we try to anchor them to tags or refs, as these
are conceptually on a higher level than the commit. And if there is no ref
or tag that matches exactly, we're out of luck. So we employ a heuristic
to make up a name for the commit. These names are ambiguous, there might
be different tags or refs to anchor to, and there might be different
path in the DAG to travel to arrive at the commit precisely.
When describing a blob, we want to describe the blob from a higher layer
as well, which is a tuple of (commit, deep/path) as the tree objects
involved are rather uninteresting. The same blob can be referenced by
multiple commits, so how we decide which commit to use? This patch
implements a rather naive approach on this: As there are no back pointers
from blobs to commits in which the blob occurs, we'll start walking from
any tips available, listing the blobs in-order of the commit and once we
found the blob, we'll take the first commit that listed the blob. For
example
git describe --tags v0.99:Makefile
conversion-901-g7672db20c2:Makefile
tells us the Makefile as it was in v0.99 was introduced in commit 7672db20.
The walking is performed in reverse order to show the introduction of a
blob rather than its last occurrence.
[1] https://stackoverflow.com/questions/223678/which-commit-has-this-blob
Signed-off-by: Stefan Beller <sbeller@google.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-11-16 02:00:39 +00:00
|
|
|
cmit = lookup_commit_reference_gently(&oid, 1);
|
2017-11-16 02:00:38 +00:00
|
|
|
|
builtin/describe.c: describe a blob
Sometimes users are given a hash of an object and they want to
identify it further (ex.: Use verify-pack to find the largest blobs,
but what are these? or [1])
When describing commits, we try to anchor them to tags or refs, as these
are conceptually on a higher level than the commit. And if there is no ref
or tag that matches exactly, we're out of luck. So we employ a heuristic
to make up a name for the commit. These names are ambiguous, there might
be different tags or refs to anchor to, and there might be different
path in the DAG to travel to arrive at the commit precisely.
When describing a blob, we want to describe the blob from a higher layer
as well, which is a tuple of (commit, deep/path) as the tree objects
involved are rather uninteresting. The same blob can be referenced by
multiple commits, so how we decide which commit to use? This patch
implements a rather naive approach on this: As there are no back pointers
from blobs to commits in which the blob occurs, we'll start walking from
any tips available, listing the blobs in-order of the commit and once we
found the blob, we'll take the first commit that listed the blob. For
example
git describe --tags v0.99:Makefile
conversion-901-g7672db20c2:Makefile
tells us the Makefile as it was in v0.99 was introduced in commit 7672db20.
The walking is performed in reverse order to show the introduction of a
blob rather than its last occurrence.
[1] https://stackoverflow.com/questions/223678/which-commit-has-this-blob
Signed-off-by: Stefan Beller <sbeller@google.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-11-16 02:00:39 +00:00
|
|
|
if (cmit)
|
|
|
|
describe_commit(&oid, &sb);
|
describe: confirm that blobs actually exist
Prior to 644eb60bd0 (builtin/describe.c: describe a blob,
2017-11-15), we noticed and complained about missing
objects, since they were not valid commits:
$ git describe 0000000000000000000000000000000000000000
fatal: 0000000000000000000000000000000000000000 is not a valid 'commit' object
After that commit, we feed any non-commit to lookup_blob(),
and complain only if it returns NULL. But the lookup_*
functions do not actually look at the on-disk object
database at all. They return an entry from the in-memory
object hash if present (and if it matches the requested
type), and otherwise auto-create a "struct object" of the
requested type.
A missing object would hit that latter case: we create a
bogus blob struct, walk all of history looking for it, and
then exit successfully having produced no output.
One reason nobody may have noticed this is that some related
cases do still work OK:
1. If we ask for a tree by sha1, then the call to
lookup_commit_referecne_gently() would have parsed it,
and we would have its true type in the in-memory object
hash.
2. If we ask for a name that doesn't exist but isn't a
40-hex sha1, then get_oid() would complain before we
even look at the objects at all.
We can fix this by replacing the lookup_blob() call with a
check of the true type via sha1_object_info(). This is not
quite as efficient as we could possibly make this check. We
know in most cases that the object was already parsed in the
earlier commit lookup, so we could call lookup_object(),
which does auto-create, and check the resulting struct's
type (or NULL). However it's not worth the fragility nor
code complexity to save a single object lookup.
The new tests cover this case, as well as that of a
tree-by-sha1 (which does work as described above, but was
not explicitly tested).
Noticed-by: Michael Haggerty <mhagger@alum.mit.edu>
Signed-off-by: Jeff King <peff@peff.net>
Acked-by: Stefan Beller <sbeller@google.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2018-02-12 17:23:06 +00:00
|
|
|
else if (sha1_object_info(oid.hash, NULL) == OBJ_BLOB)
|
builtin/describe.c: describe a blob
Sometimes users are given a hash of an object and they want to
identify it further (ex.: Use verify-pack to find the largest blobs,
but what are these? or [1])
When describing commits, we try to anchor them to tags or refs, as these
are conceptually on a higher level than the commit. And if there is no ref
or tag that matches exactly, we're out of luck. So we employ a heuristic
to make up a name for the commit. These names are ambiguous, there might
be different tags or refs to anchor to, and there might be different
path in the DAG to travel to arrive at the commit precisely.
When describing a blob, we want to describe the blob from a higher layer
as well, which is a tuple of (commit, deep/path) as the tree objects
involved are rather uninteresting. The same blob can be referenced by
multiple commits, so how we decide which commit to use? This patch
implements a rather naive approach on this: As there are no back pointers
from blobs to commits in which the blob occurs, we'll start walking from
any tips available, listing the blobs in-order of the commit and once we
found the blob, we'll take the first commit that listed the blob. For
example
git describe --tags v0.99:Makefile
conversion-901-g7672db20c2:Makefile
tells us the Makefile as it was in v0.99 was introduced in commit 7672db20.
The walking is performed in reverse order to show the introduction of a
blob rather than its last occurrence.
[1] https://stackoverflow.com/questions/223678/which-commit-has-this-blob
Signed-off-by: Stefan Beller <sbeller@google.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-11-16 02:00:39 +00:00
|
|
|
describe_blob(oid, &sb);
|
|
|
|
else
|
|
|
|
die(_("%s is neither a commit nor blob"), arg);
|
2017-11-16 02:00:38 +00:00
|
|
|
|
|
|
|
puts(sb.buf);
|
2007-01-10 11:39:47 +00:00
|
|
|
|
2007-01-13 22:30:53 +00:00
|
|
|
if (!last_one)
|
|
|
|
clear_commit_marks(cmit, -1);
|
2017-11-16 02:00:38 +00:00
|
|
|
|
|
|
|
strbuf_release(&sb);
|
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 21:50:45 +00:00
|
|
|
}
|
|
|
|
|
2007-01-10 11:36:36 +00: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 21:50:45 +00:00
|
|
|
{
|
2007-05-21 07:20:25 +00:00
|
|
|
int contains = 0;
|
2007-10-07 18:54:08 +00:00
|
|
|
struct option options[] = {
|
2013-08-03 11:51:19 +00: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 18:54:08 +00:00
|
|
|
OPT__ABBREV(&abbrev),
|
2008-02-24 08:07:31 +00:00
|
|
|
OPT_SET_INT(0, "exact-match", &max_candidates,
|
2012-08-20 12:32:07 +00:00
|
|
|
N_("only output exact matches"), 0),
|
2007-10-07 18:54:08 +00:00
|
|
|
OPT_INTEGER(0, "candidates", &max_candidates,
|
2012-08-20 12:32:07 +00:00
|
|
|
N_("consider <n> most recent tags (default: 10)")),
|
2017-01-18 23:06:07 +00:00
|
|
|
OPT_STRING_LIST(0, "match", &patterns, N_("pattern"),
|
2012-08-20 12:32:07 +00:00
|
|
|
N_("only consider tags matching <pattern>")),
|
2017-01-18 23:06:08 +00:00
|
|
|
OPT_STRING_LIST(0, "exclude", &exclude_patterns, N_("pattern"),
|
|
|
|
N_("do not consider tags matching <pattern>")),
|
2013-08-03 11:51:19 +00:00
|
|
|
OPT_BOOL(0, "always", &always,
|
|
|
|
N_("show abbreviated commit object as fallback")),
|
2012-08-20 12:32:07 +00:00
|
|
|
{OPTION_STRING, 0, "dirty", &dirty, N_("mark"),
|
2013-08-03 11:51:19 +00:00
|
|
|
N_("append <mark> on dirty working tree (default: \"-dirty\")"),
|
|
|
|
PARSE_OPT_OPTARG, NULL, (intptr_t) "-dirty"},
|
2017-03-21 22:57:18 +00:00
|
|
|
{OPTION_STRING, 0, "broken", &broken, N_("mark"),
|
|
|
|
N_("append <mark> on broken working tree (default: \"-broken\")"),
|
|
|
|
PARSE_OPT_OPTARG, NULL, (intptr_t) "-broken"},
|
2007-10-07 18:54:08 +00: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 21:50:45 +00:00
|
|
|
|
2010-10-28 18:28:04 +00:00
|
|
|
git_config(git_default_config, NULL);
|
2009-05-23 18:53:12 +00:00
|
|
|
argc = parse_options(argc, argv, prefix, options, describe_usage, 0);
|
2010-10-28 18:28:04 +00:00
|
|
|
if (abbrev < 0)
|
|
|
|
abbrev = DEFAULT_ABBREV;
|
|
|
|
|
2008-02-24 08:07:31 +00:00
|
|
|
if (max_candidates < 0)
|
|
|
|
max_candidates = 0;
|
2007-10-07 18:54:08 +00:00
|
|
|
else if (max_candidates > MAX_TAGS)
|
|
|
|
max_candidates = MAX_TAGS;
|
2006-01-11 21:57:42 +00:00
|
|
|
|
2007-01-10 11:36:29 +00:00
|
|
|
save_commit_buffer = 0;
|
2006-09-14 01:03:59 +00:00
|
|
|
|
2008-02-25 09:43:33 +00:00
|
|
|
if (longformat && abbrev == 0)
|
2011-02-22 23:42:23 +00:00
|
|
|
die(_("--long is incompatible with --abbrev=0"));
|
2008-02-25 09:43:33 +00:00
|
|
|
|
2007-05-21 07:20:25 +00:00
|
|
|
if (contains) {
|
2017-01-18 23:06:07 +00:00
|
|
|
struct string_list_item *item;
|
2013-07-07 21:42:23 +00:00
|
|
|
struct argv_array args;
|
|
|
|
|
|
|
|
argv_array_init(&args);
|
2013-07-18 21:46:51 +00:00
|
|
|
argv_array_pushl(&args, "name-rev",
|
|
|
|
"--peel-tag", "--name-only", "--no-undefined",
|
2013-07-07 21:42:23 +00:00
|
|
|
NULL);
|
2008-03-02 16:51:57 +00:00
|
|
|
if (always)
|
2013-07-07 21:42:23 +00:00
|
|
|
argv_array_push(&args, "--always");
|
2007-12-21 21:49:54 +00:00
|
|
|
if (!all) {
|
2013-07-07 21:42:23 +00:00
|
|
|
argv_array_push(&args, "--tags");
|
2017-01-18 23:06:07 +00:00
|
|
|
for_each_string_list_item(item, &patterns)
|
|
|
|
argv_array_pushf(&args, "--refs=refs/tags/%s", item->string);
|
2017-01-18 23:06:08 +00:00
|
|
|
for_each_string_list_item(item, &exclude_patterns)
|
|
|
|
argv_array_pushf(&args, "--exclude=refs/tags/%s", item->string);
|
2013-07-07 21:42:23 +00:00
|
|
|
}
|
describe --contains: default to HEAD when no commit-ish is given
'git describe --contains' doesn't default to HEAD when no commit is
given, and it doesn't produce any output, not even an error:
~/src/git ((v2.5.0))$ ./git describe --contains
~/src/git ((v2.5.0))$ ./git describe --contains HEAD
v2.5.0^0
Unlike other 'git describe' options, the '--contains' code path is
implemented by calling 'name-rev' with a bunch of options plus all the
commit-ishes that were passed to 'git describe'. If no commit-ish was
present, then 'name-rev' got invoked with none, which then leads to the
behavior illustrated above.
Porcelain commands usually default to HEAD when no commit-ish is given,
and 'git describe' already does so in all other cases, so it should do
so with '--contains' as well.
Pass HEAD to 'name-rev' when no commit-ish is given on the command line
to make '--contains' behave consistently with other 'git describe'
options. While at it, use argv_array_pushv() instead of the loop to
pass commit-ishes to 'git name-rev'.
'git describe's short help already indicates that the commit-ish is
optional, but the synopsis in the man page doesn't, so update it
accordingly as well.
Signed-off-by: SZEDER Gábor <szeder@ira.uka.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2015-08-24 16:15:18 +00:00
|
|
|
if (argc)
|
|
|
|
argv_array_pushv(&args, argv);
|
|
|
|
else
|
|
|
|
argv_array_push(&args, "HEAD");
|
2013-07-07 21:42:23 +00:00
|
|
|
return cmd_name_rev(args.argc, args.argv, prefix);
|
2007-05-21 07:20:25 +00:00
|
|
|
}
|
|
|
|
|
2017-07-01 00:28:31 +00:00
|
|
|
hashmap_init(&names, commit_name_cmp, NULL, 0);
|
2015-05-25 18:38:34 +00:00
|
|
|
for_each_rawref(get_name, NULL);
|
2017-09-06 15:43:48 +00:00
|
|
|
if (!hashmap_get_size(&names) && !always)
|
2011-02-22 23:42:23 +00:00
|
|
|
die(_("No names found, cannot describe anything."));
|
2009-10-17 16:30:48 +00:00
|
|
|
|
2007-10-07 18:54:08 +00:00
|
|
|
if (argc == 0) {
|
2017-03-21 22:57:18 +00:00
|
|
|
if (broken) {
|
|
|
|
struct child_process cp = CHILD_PROCESS_INIT;
|
|
|
|
argv_array_pushv(&cp.args, diff_index_args);
|
|
|
|
cp.git_cmd = 1;
|
|
|
|
cp.no_stdin = 1;
|
|
|
|
cp.no_stdout = 1;
|
|
|
|
|
|
|
|
if (!dirty)
|
|
|
|
dirty = "-dirty";
|
|
|
|
|
|
|
|
switch (run_command(&cp)) {
|
|
|
|
case 0:
|
|
|
|
suffix = NULL;
|
|
|
|
break;
|
|
|
|
case 1:
|
|
|
|
suffix = dirty;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
/* diff-index aborted abnormally */
|
|
|
|
suffix = broken;
|
|
|
|
}
|
|
|
|
} else if (dirty) {
|
2011-08-01 01:52:41 +00:00
|
|
|
static struct lock_file index_lock;
|
describe: do not use cmd_*() as a subroutine
The cmd_foo() function is a moral equivalent of 'main' for a Git
subcommand 'git foo', and as such, it is allowed to do many things
that make it unsuitable to be called as a subroutine, including
- call exit(3) to terminate the process;
- allocate resource held and used throughout its lifetime, without
releasing it upon return/exit;
- rely on global variables being initialized at program startup,
and update them as needed, making another clean invocation of the
function impossible.
The call to cmd_diff_index() "git describe" makes has been working
by accident that the function did not call exit(3); it sets a bad
precedent for people to cut and paste.
We could invoke it via the run_command() interface, but the diff
family of commands have helper functions in diff-lib.c that are
meant to be usable as subroutines, and using the latter does not
make the resulting code all that longer. Use it.
Note that there is also an invocation of cmd_name_rev() at the end;
"git describe --contains" massages its command line arguments to be
suitable for "git name-rev" invocation and jumps to it, never to
regain control. This call is left as-is as an exception to the
rule. When we start to allow calling name-rev repeatedly as a
helper function, we would be able to remove this call as well.
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-10-10 03:42:58 +00:00
|
|
|
struct rev_info revs;
|
|
|
|
struct argv_array args = ARGV_ARRAY_INIT;
|
|
|
|
int fd, result;
|
2011-08-01 01:52:41 +00:00
|
|
|
|
|
|
|
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);
|
|
|
|
|
describe: do not use cmd_*() as a subroutine
The cmd_foo() function is a moral equivalent of 'main' for a Git
subcommand 'git foo', and as such, it is allowed to do many things
that make it unsuitable to be called as a subroutine, including
- call exit(3) to terminate the process;
- allocate resource held and used throughout its lifetime, without
releasing it upon return/exit;
- rely on global variables being initialized at program startup,
and update them as needed, making another clean invocation of the
function impossible.
The call to cmd_diff_index() "git describe" makes has been working
by accident that the function did not call exit(3); it sets a bad
precedent for people to cut and paste.
We could invoke it via the run_command() interface, but the diff
family of commands have helper functions in diff-lib.c that are
meant to be usable as subroutines, and using the latter does not
make the resulting code all that longer. Use it.
Note that there is also an invocation of cmd_name_rev() at the end;
"git describe --contains" massages its command line arguments to be
suitable for "git name-rev" invocation and jumps to it, never to
regain control. This call is left as-is as an exception to the
rule. When we start to allow calling name-rev repeatedly as a
helper function, we would be able to remove this call as well.
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-10-10 03:42:58 +00:00
|
|
|
init_revisions(&revs, prefix);
|
|
|
|
argv_array_pushv(&args, diff_index_args);
|
|
|
|
if (setup_revisions(args.argc, args.argv, &revs, NULL) != 1)
|
|
|
|
BUG("malformed internal diff-index command line");
|
|
|
|
result = run_diff_index(&revs, 0);
|
|
|
|
|
|
|
|
if (!diff_result_code(&revs.diffopt, result))
|
2017-03-21 22:57:18 +00:00
|
|
|
suffix = NULL;
|
|
|
|
else
|
|
|
|
suffix = dirty;
|
2011-08-01 01:52:41 +00:00
|
|
|
}
|
2006-01-16 06:25:35 +00:00
|
|
|
describe("HEAD", 1);
|
2009-10-21 13:35:22 +00:00
|
|
|
} else if (dirty) {
|
2013-09-04 19:04:31 +00:00
|
|
|
die(_("--dirty is incompatible with commit-ishes"));
|
2017-03-21 22:57:18 +00:00
|
|
|
} else if (broken) {
|
|
|
|
die(_("--broken is incompatible with commit-ishes"));
|
2007-10-07 18:54:08 +00:00
|
|
|
} else {
|
2013-10-31 09:25:41 +00:00
|
|
|
while (argc-- > 0)
|
2007-10-07 18:54:08 +00: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 21:50:45 +00:00
|
|
|
return 0;
|
|
|
|
}
|