git/builtin/describe.c

564 lines
14 KiB
C
Raw Normal View History

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"
#include "config.h"
#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"
#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 21:50:45 +00:00
#include "refs.h"
#include "builtin.h"
#include "exec_cmd.h"
#include "parse-options.h"
Teach "git describe" --dirty option With the --dirty option, git describe works on HEAD but append s"-dirty" iff the contents of the work tree differs from HEAD. E.g. $ git describe --dirty v1.6.5-15-gc274db7 $ echo >> Makefile $ git describe --dirty v1.6.5-15-gc274db7-dirty The --dirty option can also be used to specify what is appended, instead of the default string "-dirty". $ git describe --dirty=.mod v1.6.5-15-gc274db7.mod Many build scripts use `git describe` to produce a version number based on the description of HEAD (on which the work tree is based) + saying that if the build contains uncommitted changes. This patch helps the writing of such scripts since `git describe --dirty` does directly the intended thing. Three possiblities were considered while discussing this new feature: 1. Describe the work tree by default and describe HEAD only if "HEAD" is explicitly specified Pro: does the right thing by default (both for users and for scripts) Pro: other git commands that works on the work tree by default Con: breaks existing scripts used by the Linux kernel and other projects 2. Use --worktree instead of --dirty Pro: does what it says: "git describe --worktree" describes the work tree Con: other commands do not require a --worktree option when working on the work tree (it often is the default mode for them) Con: unusable with an optional value: "git describe --worktree=.mod" is quite unintuitive. 3. Use --dirty as in this patch Pro: makes sense to specify an optional value (what the dirty mark is) Pro: does not have any of the big cons of previous alternatives * does not break scripts * is not inconsistent with other git commands This patch takes the third approach. Signed-off-by: Jean Privat <jean@pryen.org> Acked-by: Shawn O. Pearce <spearce@spearce.org> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2009-10-21 13:35:22 +00:00
#include "diff.h"
#include "hashmap.h"
#include "argv-array.h"
#include "run-command.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
#define SEEN (1u << 0)
Improve git-describe performance by reducing revision listing. My prior version of git-describe ran very slowly on even reasonably sized projects like git.git and linux.git as it tended to identify a large number of possible tags and then needed to generate the revision list for each of those tags to sort them and select the best tag to describe the input commit. All we really need is the number of commits in the input revision which are not in the tag. We can generate these counts during the revision walking and tag matching loop by assigning a color to each tag and coloring the commits as we walk them. This limits us to identifying no more than 26 possible tags, as there is limited space available within the flags field of struct commit. The limitation of 26 possible tags is hopefully not going to be a problem in real usage, as most projects won't create 26 maintenance releases and merge them back into a development trunk after the development trunk was tagged with a release candidate tag. If that does occur git-describe will start to revert to its old behavior of using the newer maintenance release tag to describe the development trunk, rather than the development trunk's own tag. The suggested workaround would be to retag the development trunk's tip. However since even 26 possible tags can take a while to generate a description for on some projects I'm defaulting the limit to 10 but offering the user --candidates to increase the number of possible matches if they need a more accurate result. I specifically chose 10 for the default as it seems unlikely projects will have more than 10 maintenance releases merged into a development trunk before retagging the development trunk, and it seems to perform about the same on linux.git as v1.4.4.4 git-describe. A large amount of debugging information was also added during the development of this change, so I've left it in to be toggled on with --debug. It may be useful to the end user to help them understand why git-describe took one particular tag over another. Signed-off-by: Shawn O. Pearce <spearce@spearce.org> Signed-off-by: Junio C Hamano <junkio@cox.net>
2007-01-13 22:30:53 +00:00
#define MAX_TAGS (FLAG_BITS - 1)
static const char * const describe_usage[] = {
N_("git describe [<options>] [<commit-ish>...]"),
N_("git describe [<options>] --dirty"),
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
Improve git-describe performance by reducing revision listing. My prior version of git-describe ran very slowly on even reasonably sized projects like git.git and linux.git as it tended to identify a large number of possible tags and then needed to generate the revision list for each of those tags to sort them and select the best tag to describe the input commit. All we really need is the number of commits in the input revision which are not in the tag. We can generate these counts during the revision walking and tag matching loop by assigning a color to each tag and coloring the commits as we walk them. This limits us to identifying no more than 26 possible tags, as there is limited space available within the flags field of struct commit. The limitation of 26 possible tags is hopefully not going to be a problem in real usage, as most projects won't create 26 maintenance releases and merge them back into a development trunk after the development trunk was tagged with a release candidate tag. If that does occur git-describe will start to revert to its old behavior of using the newer maintenance release tag to describe the development trunk, rather than the development trunk's own tag. The suggested workaround would be to retag the development trunk's tip. However since even 26 possible tags can take a while to generate a description for on some projects I'm defaulting the limit to 10 but offering the user --candidates to increase the number of possible matches if they need a more accurate result. I specifically chose 10 for the default as it seems unlikely projects will have more than 10 maintenance releases merged into a development trunk before retagging the development trunk, and it seems to perform about the same on linux.git as v1.4.4.4 git-describe. A large amount of debugging information was also added during the development of this change, so I've left it in to be toggled on with --debug. It may be useful to the end user to help them understand why git-describe took one particular tag over another. Signed-off-by: Shawn O. Pearce <spearce@spearce.org> Signed-off-by: Junio C Hamano <junkio@cox.net>
2007-01-13 22:30:53 +00:00
static int debug; /* Display lots of verbose info */
static int all; /* Any valid ref can be used */
static int tags; /* Allow lightweight tags */
static int longformat;
static int first_parent;
static int abbrev = -1; /* unspecified */
Improve git-describe performance by reducing revision listing. My prior version of git-describe ran very slowly on even reasonably sized projects like git.git and linux.git as it tended to identify a large number of possible tags and then needed to generate the revision list for each of those tags to sort them and select the best tag to describe the input commit. All we really need is the number of commits in the input revision which are not in the tag. We can generate these counts during the revision walking and tag matching loop by assigning a color to each tag and coloring the commits as we walk them. This limits us to identifying no more than 26 possible tags, as there is limited space available within the flags field of struct commit. The limitation of 26 possible tags is hopefully not going to be a problem in real usage, as most projects won't create 26 maintenance releases and merge them back into a development trunk after the development trunk was tagged with a release candidate tag. If that does occur git-describe will start to revert to its old behavior of using the newer maintenance release tag to describe the development trunk, rather than the development trunk's own tag. The suggested workaround would be to retag the development trunk's tip. However since even 26 possible tags can take a while to generate a description for on some projects I'm defaulting the limit to 10 but offering the user --candidates to increase the number of possible matches if they need a more accurate result. I specifically chose 10 for the default as it seems unlikely projects will have more than 10 maintenance releases merged into a development trunk before retagging the development trunk, and it seems to perform about the same on linux.git as v1.4.4.4 git-describe. A large amount of debugging information was also added during the development of this change, so I've left it in to be toggled on with --debug. It may be useful to the end user to help them understand why git-describe took one particular tag over another. Signed-off-by: Shawn O. Pearce <spearce@spearce.org> Signed-off-by: Junio C Hamano <junkio@cox.net>
2007-01-13 22:30:53 +00:00
static int max_candidates = 10;
static struct hashmap names;
static int have_util;
static struct string_list patterns = STRING_LIST_INIT_NODUP;
static struct string_list exclude_patterns = STRING_LIST_INIT_NODUP;
static int always;
static const char *suffix, *dirty, *broken;
Teach "git describe" --dirty option With the --dirty option, git describe works on HEAD but append s"-dirty" iff the contents of the work tree differs from HEAD. E.g. $ git describe --dirty v1.6.5-15-gc274db7 $ echo >> Makefile $ git describe --dirty v1.6.5-15-gc274db7-dirty The --dirty option can also be used to specify what is appended, instead of the default string "-dirty". $ git describe --dirty=.mod v1.6.5-15-gc274db7.mod Many build scripts use `git describe` to produce a version number based on the description of HEAD (on which the work tree is based) + saying that if the build contains uncommitted changes. This patch helps the writing of such scripts since `git describe --dirty` does directly the intended thing. Three possiblities were considered while discussing this new feature: 1. Describe the work tree by default and describe HEAD only if "HEAD" is explicitly specified Pro: does the right thing by default (both for users and for scripts) Pro: other git commands that works on the work tree by default Con: breaks existing scripts used by the Linux kernel and other projects 2. Use --worktree instead of --dirty Pro: does what it says: "git describe --worktree" describes the work tree Con: other commands do not require a --worktree option when working on the work tree (it often is the default mode for them) Con: unusable with an optional value: "git describe --worktree=.mod" is quite unintuitive. 3. Use --dirty as in this patch Pro: makes sense to specify an optional value (what the dirty mark is) Pro: does not have any of the big cons of previous alternatives * does not break scripts * is not inconsistent with other git commands This patch takes the third approach. Signed-off-by: Jean Privat <jean@pryen.org> Acked-by: Shawn O. Pearce <spearce@spearce.org> Signed-off-by: Junio C Hamano <gitster@pobox.com>
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
};
struct commit_name {
struct hashmap_entry entry;
struct object_id peeled;
struct tag *tag;
unsigned prio:2; /* annotated tag = 2, tag = 1, head = 0 */
unsigned name_checked:1;
struct object_id oid;
char *path;
};
static const char *prio_names[] = {
N_("head"), N_("lightweight"), N_("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 21:50:45 +00:00
static int commit_name_cmp(const void *unused_cmp_data,
const void *entry,
const void *entry_or_key,
const void *peeled)
{
const struct commit_name *cn1 = entry;
const struct commit_name *cn2 = entry_or_key;
return oidcmp(&cn1->peeled, peeled ? peeled : &cn2->peeled);
}
static inline struct commit_name *find_commit_name(const struct object_id *peeled)
{
return hashmap_get_from_hash(&names, sha1hash(peeled->hash), peeled->hash);
}
static int replace_name(struct commit_name *e,
int prio,
const struct object_id *oid,
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->oid);
if (!t || parse_tag(t))
return 1;
e->tag = t;
}
t = lookup_tag(oid);
if (!t || parse_tag(t))
return 0;
*tag = t;
if (e->tag->date < t->date)
return 1;
}
return 0;
}
static void add_to_known_names(const char *path,
const struct object_id *peeled,
int prio,
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
{
struct commit_name *e = find_commit_name(peeled);
struct tag *tag = NULL;
if (replace_name(e, prio, oid, &tag)) {
if (!e) {
e = xmalloc(sizeof(struct commit_name));
oidcpy(&e->peeled, peeled);
hashmap_entry_init(e, sha1hash(peeled->hash));
hashmap_add(&names, e);
e->path = NULL;
}
e->tag = tag;
e->prio = prio;
e->name_checked = 0;
oidcpy(&e->oid, oid);
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
}
}
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
{
int is_tag = starts_with(path, "refs/tags/");
struct object_id peeled;
int is_annotated, prio;
/* Reject anything outside refs/tags/ unless --all */
if (!all && !is_tag)
return 0;
/*
* 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;
if (!is_tag)
return 0;
for_each_string_list_item(item, &exclude_patterns) {
if (!wildmatch(item->string, path + 10, 0))
return 0;
}
}
/*
* If we're given patterns, accept only tags which match at least one
* pattern.
*/
if (patterns.nr) {
struct string_list_item *item;
if (!is_tag)
return 0;
for_each_string_list_item(item, &patterns) {
if (!wildmatch(item->string, path + 10, 0))
break;
/* If we get here, no pattern matched. */
return 0;
}
}
/* Is it annotated? */
if (!peel_ref(path, peeled.hash)) {
is_annotated = !!oidcmp(oid, &peeled);
} else {
oidcpy(&peeled, oid);
is_annotated = 0;
}
/*
* 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.
*/
if (is_annotated)
prio = 2;
else if (is_tag)
prio = 1;
else
prio = 0;
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;
}
Chose better tag names in git-describe after merges. Recently git.git itself encountered a situation on its master and next branches where git-describe stopped reporting 'v1.5.0-rc0-gN' and instead started reporting 'v1.4.4.4-gN'. This appeared to be a backward jump in version numbering. maint o-------------------4 \ \ master o-o-o-o-o-o-o-5-o-C-o-W The issue is that commit C in the diagram claims it is version 1.5.0, as the tag v1.5.0 is placed on commit 5. Yet commit W claims it is version 1.4.4.4 as the tag v1.5.0 has an older tag date than the v1.4.4.4 tag. As it turns out this situation is very common. A bug fix applied to maint and later merged into master occurs frequently enough that it should Just Work Right(tm). Rather than taking the first tag that gets found git-describe will now generate a list of all possible tags and select the one which has the most number of commits in common with HEAD (or whatever revision the user requested the description of). This rule is based on the principle shown in the diagram above. There are a large number of commits on the primary development branch 'master' which do not appear in the 'maint' branch, and many of these are already tagged as part of v1.5.0-rc0. Additionally these commits are not in v1.4.4.4, as they are part of the v1.5.0 release still being developed. The v1.5.0-rc0 tag is more descriptive of W than v1.4.4.4 is, and therefore should be used. Signed-off-by: Shawn O. Pearce <spearce@spearce.org> Signed-off-by: Junio C Hamano <junkio@cox.net>
2007-01-10 11:39:47 +00:00
struct possible_tag {
struct commit_name *name;
int depth;
int found_order;
Improve git-describe performance by reducing revision listing. My prior version of git-describe ran very slowly on even reasonably sized projects like git.git and linux.git as it tended to identify a large number of possible tags and then needed to generate the revision list for each of those tags to sort them and select the best tag to describe the input commit. All we really need is the number of commits in the input revision which are not in the tag. We can generate these counts during the revision walking and tag matching loop by assigning a color to each tag and coloring the commits as we walk them. This limits us to identifying no more than 26 possible tags, as there is limited space available within the flags field of struct commit. The limitation of 26 possible tags is hopefully not going to be a problem in real usage, as most projects won't create 26 maintenance releases and merge them back into a development trunk after the development trunk was tagged with a release candidate tag. If that does occur git-describe will start to revert to its old behavior of using the newer maintenance release tag to describe the development trunk, rather than the development trunk's own tag. The suggested workaround would be to retag the development trunk's tip. However since even 26 possible tags can take a while to generate a description for on some projects I'm defaulting the limit to 10 but offering the user --candidates to increase the number of possible matches if they need a more accurate result. I specifically chose 10 for the default as it seems unlikely projects will have more than 10 maintenance releases merged into a development trunk before retagging the development trunk, and it seems to perform about the same on linux.git as v1.4.4.4 git-describe. A large amount of debugging information was also added during the development of this change, so I've left it in to be toggled on with --debug. It may be useful to the end user to help them understand why git-describe took one particular tag over another. Signed-off-by: Shawn O. Pearce <spearce@spearce.org> Signed-off-by: Junio C Hamano <junkio@cox.net>
2007-01-13 22:30:53 +00:00
unsigned flag_within;
Chose better tag names in git-describe after merges. Recently git.git itself encountered a situation on its master and next branches where git-describe stopped reporting 'v1.5.0-rc0-gN' and instead started reporting 'v1.4.4.4-gN'. This appeared to be a backward jump in version numbering. maint o-------------------4 \ \ master o-o-o-o-o-o-o-5-o-C-o-W The issue is that commit C in the diagram claims it is version 1.5.0, as the tag v1.5.0 is placed on commit 5. Yet commit W claims it is version 1.4.4.4 as the tag v1.5.0 has an older tag date than the v1.4.4.4 tag. As it turns out this situation is very common. A bug fix applied to maint and later merged into master occurs frequently enough that it should Just Work Right(tm). Rather than taking the first tag that gets found git-describe will now generate a list of all possible tags and select the one which has the most number of commits in common with HEAD (or whatever revision the user requested the description of). This rule is based on the principle shown in the diagram above. There are a large number of commits on the primary development branch 'master' which do not appear in the 'maint' branch, and many of these are already tagged as part of v1.5.0-rc0. Additionally these commits are not in v1.4.4.4, as they are part of the v1.5.0 release still being developed. The v1.5.0-rc0 tag is more descriptive of W than v1.4.4.4 is, and therefore should be used. Signed-off-by: Shawn O. Pearce <spearce@spearce.org> Signed-off-by: Junio C Hamano <junkio@cox.net>
2007-01-10 11:39:47 +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;
}
Compute accurate distances in git-describe before output. My prior change to git-describe attempts to print the distance between the input commit and the best matching tag, but this distance was usually only an estimate as we always aborted revision walking as soon as we overflowed the configured limit on the number of possible tags (as set by --candidates). Displaying an estimated distance is not very useful and can just be downright confusing. Most users (heck, most Git developers) don't immediately understand why this distance differs from the output of common tools such as `git rev-list | wc -l`. Even worse, the estimated distance could change in the future (including decreasing despite no rebase occuring) if we find more possible tags earlier on during traversal. (This could happen if more tags are merged into the branch between queries.) These factors basically make an estimated distance useless. Fortunately we are usually most of the way through an accurate distance computation by the time we abort (due to reaching the current --candidates limit). This means we can simply finish counting out the revisions still in our commit queue to present the accurate distance at the end. The number of commits remaining in the commit queue is probably less than the number of commits already traversed, so finishing out the count is not likely to take very long. This final distance will then always match the output of `git rev-list | wc -l`. We can easily reduce the total number of commits that need to be walked at the end by stopping as soon as all of the commits in the commit queue are flagged as being merged into the already selected best possible tag. If that's true then there are no remaining unseen commits which can contribute to our best possible tag's depth counter, so further traversal is useless. Basic testing on my Mac OS X system shows there is no noticable performance difference between this accurate distance counting version of git-describe and the prior version of git-describe, at least when run on git.git. Signed-off-by: Shawn O. Pearce <spearce@spearce.org> Signed-off-by: Junio C Hamano <junkio@cox.net>
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))
commit_list_insert_by_date(p, list);
Compute accurate distances in git-describe before output. My prior change to git-describe attempts to print the distance between the input commit and the best matching tag, but this distance was usually only an estimate as we always aborted revision walking as soon as we overflowed the configured limit on the number of possible tags (as set by --candidates). Displaying an estimated distance is not very useful and can just be downright confusing. Most users (heck, most Git developers) don't immediately understand why this distance differs from the output of common tools such as `git rev-list | wc -l`. Even worse, the estimated distance could change in the future (including decreasing despite no rebase occuring) if we find more possible tags earlier on during traversal. (This could happen if more tags are merged into the branch between queries.) These factors basically make an estimated distance useless. Fortunately we are usually most of the way through an accurate distance computation by the time we abort (due to reaching the current --candidates limit). This means we can simply finish counting out the revisions still in our commit queue to present the accurate distance at the end. The number of commits remaining in the commit queue is probably less than the number of commits already traversed, so finishing out the count is not likely to take very long. This final distance will then always match the output of `git rev-list | wc -l`. We can easily reduce the total number of commits that need to be walked at the end by stopping as soon as all of the commits in the commit queue are flagged as being merged into the already selected best possible tag. If that's true then there are no remaining unseen commits which can contribute to our best possible tag's depth counter, so further traversal is useless. Basic testing on my Mac OS X system shows there is no noticable performance difference between this accurate distance counting version of git-describe and the prior version of git-describe, at least when run on git.git. Signed-off-by: Shawn O. Pearce <spearce@spearce.org> Signed-off-by: Junio C Hamano <junkio@cox.net>
2007-01-27 06:54:21 +00:00
p->object.flags |= c->object.flags;
parents = parents->next;
}
}
return seen_commits;
}
static void display_name(struct commit_name *n)
{
if (n->prio == 2 && !n->tag) {
n->tag = lookup_tag(&n->oid);
if (!n->tag || parse_tag(n->tag))
die(_("annotated tag %s not available"), n->path);
}
if (n->tag && !n->name_checked) {
if (!n->tag->tag)
die(_("annotated tag %s has no embedded name"), n->path);
if (strcmp(n->tag->tag, all ? n->path + 5 : n->path))
warning(_("tag '%s' is really '%s' here"), n->tag->tag, n->path);
n->name_checked = 1;
}
if (n->tag)
printf("%s", n->tag->tag);
else
printf("%s", n->path);
}
static void show_suffix(int depth, const struct object_id *oid)
{
printf("-%d-g%s", depth, find_unique_abbrev(oid->hash, abbrev));
}
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 21:50:45 +00:00
{
struct object_id oid;
Improve git-describe performance by reducing revision listing. My prior version of git-describe ran very slowly on even reasonably sized projects like git.git and linux.git as it tended to identify a large number of possible tags and then needed to generate the revision list for each of those tags to sort them and select the best tag to describe the input commit. All we really need is the number of commits in the input revision which are not in the tag. We can generate these counts during the revision walking and tag matching loop by assigning a color to each tag and coloring the commits as we walk them. This limits us to identifying no more than 26 possible tags, as there is limited space available within the flags field of struct commit. The limitation of 26 possible tags is hopefully not going to be a problem in real usage, as most projects won't create 26 maintenance releases and merge them back into a development trunk after the development trunk was tagged with a release candidate tag. If that does occur git-describe will start to revert to its old behavior of using the newer maintenance release tag to describe the development trunk, rather than the development trunk's own tag. The suggested workaround would be to retag the development trunk's tip. However since even 26 possible tags can take a while to generate a description for on some projects I'm defaulting the limit to 10 but offering the user --candidates to increase the number of possible matches if they need a more accurate result. I specifically chose 10 for the default as it seems unlikely projects will have more than 10 maintenance releases merged into a development trunk before retagging the development trunk, and it seems to perform about the same on linux.git as v1.4.4.4 git-describe. A large amount of debugging information was also added during the development of this change, so I've left it in to be toggled on with --debug. It may be useful to the end user to help them understand why git-describe took one particular tag over another. Signed-off-by: Shawn O. Pearce <spearce@spearce.org> Signed-off-by: Junio C Hamano <junkio@cox.net>
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;
struct possible_tag all_matches[MAX_TAGS];
Improve git-describe performance by reducing revision listing. My prior version of git-describe ran very slowly on even reasonably sized projects like git.git and linux.git as it tended to identify a large number of possible tags and then needed to generate the revision list for each of those tags to sort them and select the best tag to describe the input commit. All we really need is the number of commits in the input revision which are not in the tag. We can generate these counts during the revision walking and tag matching loop by assigning a color to each tag and coloring the commits as we walk them. This limits us to identifying no more than 26 possible tags, as there is limited space available within the flags field of struct commit. The limitation of 26 possible tags is hopefully not going to be a problem in real usage, as most projects won't create 26 maintenance releases and merge them back into a development trunk after the development trunk was tagged with a release candidate tag. If that does occur git-describe will start to revert to its old behavior of using the newer maintenance release tag to describe the development trunk, rather than the development trunk's own tag. The suggested workaround would be to retag the development trunk's tip. However since even 26 possible tags can take a while to generate a description for on some projects I'm defaulting the limit to 10 but offering the user --candidates to increase the number of possible matches if they need a more accurate result. I specifically chose 10 for the default as it seems unlikely projects will have more than 10 maintenance releases merged into a development trunk before retagging the development trunk, and it seems to perform about the same on linux.git as v1.4.4.4 git-describe. A large amount of debugging information was also added during the development of this change, so I've left it in to be toggled on with --debug. It may be useful to the end user to help them understand why git-describe took one particular tag over another. Signed-off-by: Shawn O. Pearce <spearce@spearce.org> Signed-off-by: Junio C Hamano <junkio@cox.net>
2007-01-13 22:30:53 +00:00
unsigned int match_cnt = 0, annotated_cnt = 0, cur_match;
unsigned long seen_commits = 0;
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
if (get_oid(arg, &oid))
die(_("Not a valid object name %s"), arg);
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
cmit = lookup_commit_reference(&oid);
if (!cmit)
die(_("%s is not a valid '%s' object"), arg, commit_type);
n = find_commit_name(&cmit->object.oid);
if (n && (tags || all || n->prio == 2)) {
/*
* Exact match to an existing ref.
*/
display_name(n);
if (longformat)
show_suffix(0, n->tag ? &n->tag->tagged->oid : &oid);
if (suffix)
printf("%s", suffix);
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 21:50:45 +00:00
return;
}
if (!max_candidates)
die(_("no tag exactly matches '%s'"), oid_to_hex(&cmit->object.oid));
Improve git-describe performance by reducing revision listing. My prior version of git-describe ran very slowly on even reasonably sized projects like git.git and linux.git as it tended to identify a large number of possible tags and then needed to generate the revision list for each of those tags to sort them and select the best tag to describe the input commit. All we really need is the number of commits in the input revision which are not in the tag. We can generate these counts during the revision walking and tag matching loop by assigning a color to each tag and coloring the commits as we walk them. This limits us to identifying no more than 26 possible tags, as there is limited space available within the flags field of struct commit. The limitation of 26 possible tags is hopefully not going to be a problem in real usage, as most projects won't create 26 maintenance releases and merge them back into a development trunk after the development trunk was tagged with a release candidate tag. If that does occur git-describe will start to revert to its old behavior of using the newer maintenance release tag to describe the development trunk, rather than the development trunk's own tag. The suggested workaround would be to retag the development trunk's tip. However since even 26 possible tags can take a while to generate a description for on some projects I'm defaulting the limit to 10 but offering the user --candidates to increase the number of possible matches if they need a more accurate result. I specifically chose 10 for the default as it seems unlikely projects will have more than 10 maintenance releases merged into a development trunk before retagging the development trunk, and it seems to perform about the same on linux.git as v1.4.4.4 git-describe. A large amount of debugging information was also added during the development of this change, so I've left it in to be toggled on with --debug. It may be useful to the end user to help them understand why git-describe took one particular tag over another. Signed-off-by: Shawn O. Pearce <spearce@spearce.org> Signed-off-by: Junio C Hamano <junkio@cox.net>
2007-01-13 22:30:53 +00:00
if (debug)
fprintf(stderr, _("searching to describe %s\n"), arg);
Improve git-describe performance by reducing revision listing. My prior version of git-describe ran very slowly on even reasonably sized projects like git.git and linux.git as it tended to identify a large number of possible tags and then needed to generate the revision list for each of those tags to sort them and select the best tag to describe the input commit. All we really need is the number of commits in the input revision which are not in the tag. We can generate these counts during the revision walking and tag matching loop by assigning a color to each tag and coloring the commits as we walk them. This limits us to identifying no more than 26 possible tags, as there is limited space available within the flags field of struct commit. The limitation of 26 possible tags is hopefully not going to be a problem in real usage, as most projects won't create 26 maintenance releases and merge them back into a development trunk after the development trunk was tagged with a release candidate tag. If that does occur git-describe will start to revert to its old behavior of using the newer maintenance release tag to describe the development trunk, rather than the development trunk's own tag. The suggested workaround would be to retag the development trunk's tip. However since even 26 possible tags can take a while to generate a description for on some projects I'm defaulting the limit to 10 but offering the user --candidates to increase the number of possible matches if they need a more accurate result. I specifically chose 10 for the default as it seems unlikely projects will have more than 10 maintenance releases merged into a development trunk before retagging the development trunk, and it seems to perform about the same on linux.git as v1.4.4.4 git-describe. A large amount of debugging information was also added during the development of this change, so I've left it in to be toggled on with --debug. It may be useful to the end user to help them understand why git-describe took one particular tag over another. Signed-off-by: Shawn O. Pearce <spearce@spearce.org> Signed-off-by: Junio C Hamano <junkio@cox.net>
2007-01-13 22:30:53 +00:00
if (!have_util) {
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);
if (c)
c->util = n;
}
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;
Improve git-describe performance by reducing revision listing. My prior version of git-describe ran very slowly on even reasonably sized projects like git.git and linux.git as it tended to identify a large number of possible tags and then needed to generate the revision list for each of those tags to sort them and select the best tag to describe the input commit. All we really need is the number of commits in the input revision which are not in the tag. We can generate these counts during the revision walking and tag matching loop by assigning a color to each tag and coloring the commits as we walk them. This limits us to identifying no more than 26 possible tags, as there is limited space available within the flags field of struct commit. The limitation of 26 possible tags is hopefully not going to be a problem in real usage, as most projects won't create 26 maintenance releases and merge them back into a development trunk after the development trunk was tagged with a release candidate tag. If that does occur git-describe will start to revert to its old behavior of using the newer maintenance release tag to describe the development trunk, rather than the development trunk's own tag. The suggested workaround would be to retag the development trunk's tip. However since even 26 possible tags can take a while to generate a description for on some projects I'm defaulting the limit to 10 but offering the user --candidates to increase the number of possible matches if they need a more accurate result. I specifically chose 10 for the default as it seems unlikely projects will have more than 10 maintenance releases merged into a development trunk before retagging the development trunk, and it seems to perform about the same on linux.git as v1.4.4.4 git-describe. A large amount of debugging information was also added during the development of this change, so I've left it in to be toggled on with --debug. It may be useful to the end user to help them understand why git-describe took one particular tag over another. Signed-off-by: Shawn O. Pearce <spearce@spearce.org> Signed-off-by: Junio C Hamano <junkio@cox.net>
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) {
Chose better tag names in git-describe after merges. Recently git.git itself encountered a situation on its master and next branches where git-describe stopped reporting 'v1.5.0-rc0-gN' and instead started reporting 'v1.4.4.4-gN'. This appeared to be a backward jump in version numbering. maint o-------------------4 \ \ master o-o-o-o-o-o-o-5-o-C-o-W The issue is that commit C in the diagram claims it is version 1.5.0, as the tag v1.5.0 is placed on commit 5. Yet commit W claims it is version 1.4.4.4 as the tag v1.5.0 has an older tag date than the v1.4.4.4 tag. As it turns out this situation is very common. A bug fix applied to maint and later merged into master occurs frequently enough that it should Just Work Right(tm). Rather than taking the first tag that gets found git-describe will now generate a list of all possible tags and select the one which has the most number of commits in common with HEAD (or whatever revision the user requested the description of). This rule is based on the principle shown in the diagram above. There are a large number of commits on the primary development branch 'master' which do not appear in the 'maint' branch, and many of these are already tagged as part of v1.5.0-rc0. Additionally these commits are not in v1.4.4.4, as they are part of the v1.5.0 release still being developed. The v1.5.0-rc0 tag is more descriptive of W than v1.4.4.4 is, and therefore should be used. Signed-off-by: Shawn O. Pearce <spearce@spearce.org> Signed-off-by: Junio C Hamano <junkio@cox.net>
2007-01-10 11:39:47 +00:00
struct commit *c = pop_commit(&list);
struct commit_list *parents = c->parents;
Improve git-describe performance by reducing revision listing. My prior version of git-describe ran very slowly on even reasonably sized projects like git.git and linux.git as it tended to identify a large number of possible tags and then needed to generate the revision list for each of those tags to sort them and select the best tag to describe the input commit. All we really need is the number of commits in the input revision which are not in the tag. We can generate these counts during the revision walking and tag matching loop by assigning a color to each tag and coloring the commits as we walk them. This limits us to identifying no more than 26 possible tags, as there is limited space available within the flags field of struct commit. The limitation of 26 possible tags is hopefully not going to be a problem in real usage, as most projects won't create 26 maintenance releases and merge them back into a development trunk after the development trunk was tagged with a release candidate tag. If that does occur git-describe will start to revert to its old behavior of using the newer maintenance release tag to describe the development trunk, rather than the development trunk's own tag. The suggested workaround would be to retag the development trunk's tip. However since even 26 possible tags can take a while to generate a description for on some projects I'm defaulting the limit to 10 but offering the user --candidates to increase the number of possible matches if they need a more accurate result. I specifically chose 10 for the default as it seems unlikely projects will have more than 10 maintenance releases merged into a development trunk before retagging the development trunk, and it seems to perform about the same on linux.git as v1.4.4.4 git-describe. A large amount of debugging information was also added during the development of this change, so I've left it in to be toggled on with --debug. It may be useful to the end user to help them understand why git-describe took one particular tag over another. Signed-off-by: Shawn O. Pearce <spearce@spearce.org> Signed-off-by: Junio C Hamano <junkio@cox.net>
2007-01-13 22:30:53 +00:00
seen_commits++;
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) {
if (!tags && !all && n->prio < 2) {
unannotated_cnt++;
} else if (match_cnt < max_candidates) {
Improve git-describe performance by reducing revision listing. My prior version of git-describe ran very slowly on even reasonably sized projects like git.git and linux.git as it tended to identify a large number of possible tags and then needed to generate the revision list for each of those tags to sort them and select the best tag to describe the input commit. All we really need is the number of commits in the input revision which are not in the tag. We can generate these counts during the revision walking and tag matching loop by assigning a color to each tag and coloring the commits as we walk them. This limits us to identifying no more than 26 possible tags, as there is limited space available within the flags field of struct commit. The limitation of 26 possible tags is hopefully not going to be a problem in real usage, as most projects won't create 26 maintenance releases and merge them back into a development trunk after the development trunk was tagged with a release candidate tag. If that does occur git-describe will start to revert to its old behavior of using the newer maintenance release tag to describe the development trunk, rather than the development trunk's own tag. The suggested workaround would be to retag the development trunk's tip. However since even 26 possible tags can take a while to generate a description for on some projects I'm defaulting the limit to 10 but offering the user --candidates to increase the number of possible matches if they need a more accurate result. I specifically chose 10 for the default as it seems unlikely projects will have more than 10 maintenance releases merged into a development trunk before retagging the development trunk, and it seems to perform about the same on linux.git as v1.4.4.4 git-describe. A large amount of debugging information was also added during the development of this change, so I've left it in to be toggled on with --debug. It may be useful to the end user to help them understand why git-describe took one particular tag over another. Signed-off-by: Shawn O. Pearce <spearce@spearce.org> Signed-off-by: Junio C Hamano <junkio@cox.net>
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;
t->found_order = match_cnt;
Improve git-describe performance by reducing revision listing. My prior version of git-describe ran very slowly on even reasonably sized projects like git.git and linux.git as it tended to identify a large number of possible tags and then needed to generate the revision list for each of those tags to sort them and select the best tag to describe the input commit. All we really need is the number of commits in the input revision which are not in the tag. We can generate these counts during the revision walking and tag matching loop by assigning a color to each tag and coloring the commits as we walk them. This limits us to identifying no more than 26 possible tags, as there is limited space available within the flags field of struct commit. The limitation of 26 possible tags is hopefully not going to be a problem in real usage, as most projects won't create 26 maintenance releases and merge them back into a development trunk after the development trunk was tagged with a release candidate tag. If that does occur git-describe will start to revert to its old behavior of using the newer maintenance release tag to describe the development trunk, rather than the development trunk's own tag. The suggested workaround would be to retag the development trunk's tip. However since even 26 possible tags can take a while to generate a description for on some projects I'm defaulting the limit to 10 but offering the user --candidates to increase the number of possible matches if they need a more accurate result. I specifically chose 10 for the default as it seems unlikely projects will have more than 10 maintenance releases merged into a development trunk before retagging the development trunk, and it seems to perform about the same on linux.git as v1.4.4.4 git-describe. A large amount of debugging information was also added during the development of this change, so I've left it in to be toggled on with --debug. It may be useful to the end user to help them understand why git-describe took one particular tag over another. Signed-off-by: Shawn O. Pearce <spearce@spearce.org> Signed-off-by: Junio C Hamano <junkio@cox.net>
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)
fprintf(stderr, _("finished search at %s\n"),
oid_to_hex(&c->object.oid));
Improve git-describe performance by reducing revision listing. My prior version of git-describe ran very slowly on even reasonably sized projects like git.git and linux.git as it tended to identify a large number of possible tags and then needed to generate the revision list for each of those tags to sort them and select the best tag to describe the input commit. All we really need is the number of commits in the input revision which are not in the tag. We can generate these counts during the revision walking and tag matching loop by assigning a color to each tag and coloring the commits as we walk them. This limits us to identifying no more than 26 possible tags, as there is limited space available within the flags field of struct commit. The limitation of 26 possible tags is hopefully not going to be a problem in real usage, as most projects won't create 26 maintenance releases and merge them back into a development trunk after the development trunk was tagged with a release candidate tag. If that does occur git-describe will start to revert to its old behavior of using the newer maintenance release tag to describe the development trunk, rather than the development trunk's own tag. The suggested workaround would be to retag the development trunk's tip. However since even 26 possible tags can take a while to generate a description for on some projects I'm defaulting the limit to 10 but offering the user --candidates to increase the number of possible matches if they need a more accurate result. I specifically chose 10 for the default as it seems unlikely projects will have more than 10 maintenance releases merged into a development trunk before retagging the development trunk, and it seems to perform about the same on linux.git as v1.4.4.4 git-describe. A large amount of debugging information was also added during the development of this change, so I've left it in to be toggled on with --debug. It may be useful to the end user to help them understand why git-describe took one particular tag over another. Signed-off-by: Shawn O. Pearce <spearce@spearce.org> Signed-off-by: Junio C Hamano <junkio@cox.net>
2007-01-13 22:30:53 +00:00
break;
}
while (parents) {
struct commit *p = parents->item;
parse_commit(p);
Improve git-describe performance by reducing revision listing. My prior version of git-describe ran very slowly on even reasonably sized projects like git.git and linux.git as it tended to identify a large number of possible tags and then needed to generate the revision list for each of those tags to sort them and select the best tag to describe the input commit. All we really need is the number of commits in the input revision which are not in the tag. We can generate these counts during the revision walking and tag matching loop by assigning a color to each tag and coloring the commits as we walk them. This limits us to identifying no more than 26 possible tags, as there is limited space available within the flags field of struct commit. The limitation of 26 possible tags is hopefully not going to be a problem in real usage, as most projects won't create 26 maintenance releases and merge them back into a development trunk after the development trunk was tagged with a release candidate tag. If that does occur git-describe will start to revert to its old behavior of using the newer maintenance release tag to describe the development trunk, rather than the development trunk's own tag. The suggested workaround would be to retag the development trunk's tip. However since even 26 possible tags can take a while to generate a description for on some projects I'm defaulting the limit to 10 but offering the user --candidates to increase the number of possible matches if they need a more accurate result. I specifically chose 10 for the default as it seems unlikely projects will have more than 10 maintenance releases merged into a development trunk before retagging the development trunk, and it seems to perform about the same on linux.git as v1.4.4.4 git-describe. A large amount of debugging information was also added during the development of this change, so I've left it in to be toggled on with --debug. It may be useful to the end user to help them understand why git-describe took one particular tag over another. Signed-off-by: Shawn O. Pearce <spearce@spearce.org> Signed-off-by: Junio C Hamano <junkio@cox.net>
2007-01-13 22:30:53 +00:00
if (!(p->object.flags & SEEN))
commit_list_insert_by_date(p, &list);
Improve git-describe performance by reducing revision listing. My prior version of git-describe ran very slowly on even reasonably sized projects like git.git and linux.git as it tended to identify a large number of possible tags and then needed to generate the revision list for each of those tags to sort them and select the best tag to describe the input commit. All we really need is the number of commits in the input revision which are not in the tag. We can generate these counts during the revision walking and tag matching loop by assigning a color to each tag and coloring the commits as we walk them. This limits us to identifying no more than 26 possible tags, as there is limited space available within the flags field of struct commit. The limitation of 26 possible tags is hopefully not going to be a problem in real usage, as most projects won't create 26 maintenance releases and merge them back into a development trunk after the development trunk was tagged with a release candidate tag. If that does occur git-describe will start to revert to its old behavior of using the newer maintenance release tag to describe the development trunk, rather than the development trunk's own tag. The suggested workaround would be to retag the development trunk's tip. However since even 26 possible tags can take a while to generate a description for on some projects I'm defaulting the limit to 10 but offering the user --candidates to increase the number of possible matches if they need a more accurate result. I specifically chose 10 for the default as it seems unlikely projects will have more than 10 maintenance releases merged into a development trunk before retagging the development trunk, and it seems to perform about the same on linux.git as v1.4.4.4 git-describe. A large amount of debugging information was also added during the development of this change, so I've left it in to be toggled on with --debug. It may be useful to the end user to help them understand why git-describe took one particular tag over another. Signed-off-by: Shawn O. Pearce <spearce@spearce.org> Signed-off-by: Junio C Hamano <junkio@cox.net>
2007-01-13 22:30:53 +00:00
p->object.flags |= c->object.flags;
parents = parents->next;
if (first_parent)
break;
Chose better tag names in git-describe after merges. Recently git.git itself encountered a situation on its master and next branches where git-describe stopped reporting 'v1.5.0-rc0-gN' and instead started reporting 'v1.4.4.4-gN'. This appeared to be a backward jump in version numbering. maint o-------------------4 \ \ master o-o-o-o-o-o-o-5-o-C-o-W The issue is that commit C in the diagram claims it is version 1.5.0, as the tag v1.5.0 is placed on commit 5. Yet commit W claims it is version 1.4.4.4 as the tag v1.5.0 has an older tag date than the v1.4.4.4 tag. As it turns out this situation is very common. A bug fix applied to maint and later merged into master occurs frequently enough that it should Just Work Right(tm). Rather than taking the first tag that gets found git-describe will now generate a list of all possible tags and select the one which has the most number of commits in common with HEAD (or whatever revision the user requested the description of). This rule is based on the principle shown in the diagram above. There are a large number of commits on the primary development branch 'master' which do not appear in the 'maint' branch, and many of these are already tagged as part of v1.5.0-rc0. Additionally these commits are not in v1.4.4.4, as they are part of the v1.5.0 release still being developed. The v1.5.0-rc0 tag is more descriptive of W than v1.4.4.4 is, and therefore should be used. Signed-off-by: Shawn O. Pearce <spearce@spearce.org> Signed-off-by: Junio C Hamano <junkio@cox.net>
2007-01-10 11:39:47 +00:00
}
}
if (!match_cnt) {
struct object_id *oid = &cmit->object.oid;
if (always) {
printf("%s", find_unique_abbrev(oid->hash, abbrev));
if (suffix)
printf("%s", suffix);
Teach "git describe" --dirty option With the --dirty option, git describe works on HEAD but append s"-dirty" iff the contents of the work tree differs from HEAD. E.g. $ git describe --dirty v1.6.5-15-gc274db7 $ echo >> Makefile $ git describe --dirty v1.6.5-15-gc274db7-dirty The --dirty option can also be used to specify what is appended, instead of the default string "-dirty". $ git describe --dirty=.mod v1.6.5-15-gc274db7.mod Many build scripts use `git describe` to produce a version number based on the description of HEAD (on which the work tree is based) + saying that if the build contains uncommitted changes. This patch helps the writing of such scripts since `git describe --dirty` does directly the intended thing. Three possiblities were considered while discussing this new feature: 1. Describe the work tree by default and describe HEAD only if "HEAD" is explicitly specified Pro: does the right thing by default (both for users and for scripts) Pro: other git commands that works on the work tree by default Con: breaks existing scripts used by the Linux kernel and other projects 2. Use --worktree instead of --dirty Pro: does what it says: "git describe --worktree" describes the work tree Con: other commands do not require a --worktree option when working on the work tree (it often is the default mode for them) Con: unusable with an optional value: "git describe --worktree=.mod" is quite unintuitive. 3. Use --dirty as in this patch Pro: makes sense to specify an optional value (what the dirty mark is) Pro: does not have any of the big cons of previous alternatives * does not break scripts * is not inconsistent with other git commands This patch takes the third approach. Signed-off-by: Jean Privat <jean@pryen.org> Acked-by: Shawn O. Pearce <spearce@spearce.org> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2009-10-21 13:35:22 +00:00
printf("\n");
return;
}
if (unannotated_cnt)
die(_("No annotated tags can describe '%s'.\n"
"However, there were unannotated tags: try --tags."),
oid_to_hex(oid));
else
die(_("No tags can describe '%s'.\n"
"Try --always, or create some tags."),
oid_to_hex(oid));
}
Chose better tag names in git-describe after merges. Recently git.git itself encountered a situation on its master and next branches where git-describe stopped reporting 'v1.5.0-rc0-gN' and instead started reporting 'v1.4.4.4-gN'. This appeared to be a backward jump in version numbering. maint o-------------------4 \ \ master o-o-o-o-o-o-o-5-o-C-o-W The issue is that commit C in the diagram claims it is version 1.5.0, as the tag v1.5.0 is placed on commit 5. Yet commit W claims it is version 1.4.4.4 as the tag v1.5.0 has an older tag date than the v1.4.4.4 tag. As it turns out this situation is very common. A bug fix applied to maint and later merged into master occurs frequently enough that it should Just Work Right(tm). Rather than taking the first tag that gets found git-describe will now generate a list of all possible tags and select the one which has the most number of commits in common with HEAD (or whatever revision the user requested the description of). This rule is based on the principle shown in the diagram above. There are a large number of commits on the primary development branch 'master' which do not appear in the 'maint' branch, and many of these are already tagged as part of v1.5.0-rc0. Additionally these commits are not in v1.4.4.4, as they are part of the v1.5.0 release still being developed. The v1.5.0-rc0 tag is more descriptive of W than v1.4.4.4 is, and therefore should be used. Signed-off-by: Shawn O. Pearce <spearce@spearce.org> Signed-off-by: Junio C Hamano <junkio@cox.net>
2007-01-10 11:39:47 +00:00
QSORT(all_matches, match_cnt, compare_pt);
Compute accurate distances in git-describe before output. My prior change to git-describe attempts to print the distance between the input commit and the best matching tag, but this distance was usually only an estimate as we always aborted revision walking as soon as we overflowed the configured limit on the number of possible tags (as set by --candidates). Displaying an estimated distance is not very useful and can just be downright confusing. Most users (heck, most Git developers) don't immediately understand why this distance differs from the output of common tools such as `git rev-list | wc -l`. Even worse, the estimated distance could change in the future (including decreasing despite no rebase occuring) if we find more possible tags earlier on during traversal. (This could happen if more tags are merged into the branch between queries.) These factors basically make an estimated distance useless. Fortunately we are usually most of the way through an accurate distance computation by the time we abort (due to reaching the current --candidates limit). This means we can simply finish counting out the revisions still in our commit queue to present the accurate distance at the end. The number of commits remaining in the commit queue is probably less than the number of commits already traversed, so finishing out the count is not likely to take very long. This final distance will then always match the output of `git rev-list | wc -l`. We can easily reduce the total number of commits that need to be walked at the end by stopping as soon as all of the commits in the commit queue are flagged as being merged into the already selected best possible tag. If that's true then there are no remaining unseen commits which can contribute to our best possible tag's depth counter, so further traversal is useless. Basic testing on my Mac OS X system shows there is no noticable performance difference between this accurate distance counting version of git-describe and the prior version of git-describe, at least when run on git.git. Signed-off-by: Shawn O. Pearce <spearce@spearce.org> Signed-off-by: Junio C Hamano <junkio@cox.net>
2007-01-27 06:54:21 +00:00
if (gave_up_on) {
commit_list_insert_by_date(gave_up_on, &list);
Compute accurate distances in git-describe before output. My prior change to git-describe attempts to print the distance between the input commit and the best matching tag, but this distance was usually only an estimate as we always aborted revision walking as soon as we overflowed the configured limit on the number of possible tags (as set by --candidates). Displaying an estimated distance is not very useful and can just be downright confusing. Most users (heck, most Git developers) don't immediately understand why this distance differs from the output of common tools such as `git rev-list | wc -l`. Even worse, the estimated distance could change in the future (including decreasing despite no rebase occuring) if we find more possible tags earlier on during traversal. (This could happen if more tags are merged into the branch between queries.) These factors basically make an estimated distance useless. Fortunately we are usually most of the way through an accurate distance computation by the time we abort (due to reaching the current --candidates limit). This means we can simply finish counting out the revisions still in our commit queue to present the accurate distance at the end. The number of commits remaining in the commit queue is probably less than the number of commits already traversed, so finishing out the count is not likely to take very long. This final distance will then always match the output of `git rev-list | wc -l`. We can easily reduce the total number of commits that need to be walked at the end by stopping as soon as all of the commits in the commit queue are flagged as being merged into the already selected best possible tag. If that's true then there are no remaining unseen commits which can contribute to our best possible tag's depth counter, so further traversal is useless. Basic testing on my Mac OS X system shows there is no noticable performance difference between this accurate distance counting version of git-describe and the prior version of git-describe, at least when run on git.git. Signed-off-by: Shawn O. Pearce <spearce@spearce.org> Signed-off-by: Junio C Hamano <junkio@cox.net>
2007-01-27 06:54:21 +00:00
seen_commits--;
}
seen_commits += finish_depth_computation(&list, &all_matches[0]);
free_commit_list(list);
Improve git-describe performance by reducing revision listing. My prior version of git-describe ran very slowly on even reasonably sized projects like git.git and linux.git as it tended to identify a large number of possible tags and then needed to generate the revision list for each of those tags to sort them and select the best tag to describe the input commit. All we really need is the number of commits in the input revision which are not in the tag. We can generate these counts during the revision walking and tag matching loop by assigning a color to each tag and coloring the commits as we walk them. This limits us to identifying no more than 26 possible tags, as there is limited space available within the flags field of struct commit. The limitation of 26 possible tags is hopefully not going to be a problem in real usage, as most projects won't create 26 maintenance releases and merge them back into a development trunk after the development trunk was tagged with a release candidate tag. If that does occur git-describe will start to revert to its old behavior of using the newer maintenance release tag to describe the development trunk, rather than the development trunk's own tag. The suggested workaround would be to retag the development trunk's tip. However since even 26 possible tags can take a while to generate a description for on some projects I'm defaulting the limit to 10 but offering the user --candidates to increase the number of possible matches if they need a more accurate result. I specifically chose 10 for the default as it seems unlikely projects will have more than 10 maintenance releases merged into a development trunk before retagging the development trunk, and it seems to perform about the same on linux.git as v1.4.4.4 git-describe. A large amount of debugging information was also added during the development of this change, so I've left it in to be toggled on with --debug. It may be useful to the end user to help them understand why git-describe took one particular tag over another. Signed-off-by: Shawn O. Pearce <spearce@spearce.org> Signed-off-by: Junio C Hamano <junkio@cox.net>
2007-01-13 22:30:53 +00:00
if (debug) {
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;
}
}
Improve git-describe performance by reducing revision listing. My prior version of git-describe ran very slowly on even reasonably sized projects like git.git and linux.git as it tended to identify a large number of possible tags and then needed to generate the revision list for each of those tags to sort them and select the best tag to describe the input commit. All we really need is the number of commits in the input revision which are not in the tag. We can generate these counts during the revision walking and tag matching loop by assigning a color to each tag and coloring the commits as we walk them. This limits us to identifying no more than 26 possible tags, as there is limited space available within the flags field of struct commit. The limitation of 26 possible tags is hopefully not going to be a problem in real usage, as most projects won't create 26 maintenance releases and merge them back into a development trunk after the development trunk was tagged with a release candidate tag. If that does occur git-describe will start to revert to its old behavior of using the newer maintenance release tag to describe the development trunk, rather than the development trunk's own tag. The suggested workaround would be to retag the development trunk's tip. However since even 26 possible tags can take a while to generate a description for on some projects I'm defaulting the limit to 10 but offering the user --candidates to increase the number of possible matches if they need a more accurate result. I specifically chose 10 for the default as it seems unlikely projects will have more than 10 maintenance releases merged into a development trunk before retagging the development trunk, and it seems to perform about the same on linux.git as v1.4.4.4 git-describe. A large amount of debugging information was also added during the development of this change, so I've left it in to be toggled on with --debug. It may be useful to the end user to help them understand why git-describe took one particular tag over another. Signed-off-by: Shawn O. Pearce <spearce@spearce.org> Signed-off-by: Junio C Hamano <junkio@cox.net>
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];
fprintf(stderr, " %-*s %8d %s\n",
label_width, _(prio_names[t->name->prio]),
Improve git-describe performance by reducing revision listing. My prior version of git-describe ran very slowly on even reasonably sized projects like git.git and linux.git as it tended to identify a large number of possible tags and then needed to generate the revision list for each of those tags to sort them and select the best tag to describe the input commit. All we really need is the number of commits in the input revision which are not in the tag. We can generate these counts during the revision walking and tag matching loop by assigning a color to each tag and coloring the commits as we walk them. This limits us to identifying no more than 26 possible tags, as there is limited space available within the flags field of struct commit. The limitation of 26 possible tags is hopefully not going to be a problem in real usage, as most projects won't create 26 maintenance releases and merge them back into a development trunk after the development trunk was tagged with a release candidate tag. If that does occur git-describe will start to revert to its old behavior of using the newer maintenance release tag to describe the development trunk, rather than the development trunk's own tag. The suggested workaround would be to retag the development trunk's tip. However since even 26 possible tags can take a while to generate a description for on some projects I'm defaulting the limit to 10 but offering the user --candidates to increase the number of possible matches if they need a more accurate result. I specifically chose 10 for the default as it seems unlikely projects will have more than 10 maintenance releases merged into a development trunk before retagging the development trunk, and it seems to perform about the same on linux.git as v1.4.4.4 git-describe. A large amount of debugging information was also added during the development of this change, so I've left it in to be toggled on with --debug. It may be useful to the end user to help them understand why git-describe took one particular tag over another. Signed-off-by: Shawn O. Pearce <spearce@spearce.org> Signed-off-by: Junio C Hamano <junkio@cox.net>
2007-01-13 22:30:53 +00:00
t->depth, t->name->path);
}
fprintf(stderr, _("traversed %lu commits\n"), seen_commits);
Improve git-describe performance by reducing revision listing. My prior version of git-describe ran very slowly on even reasonably sized projects like git.git and linux.git as it tended to identify a large number of possible tags and then needed to generate the revision list for each of those tags to sort them and select the best tag to describe the input commit. All we really need is the number of commits in the input revision which are not in the tag. We can generate these counts during the revision walking and tag matching loop by assigning a color to each tag and coloring the commits as we walk them. This limits us to identifying no more than 26 possible tags, as there is limited space available within the flags field of struct commit. The limitation of 26 possible tags is hopefully not going to be a problem in real usage, as most projects won't create 26 maintenance releases and merge them back into a development trunk after the development trunk was tagged with a release candidate tag. If that does occur git-describe will start to revert to its old behavior of using the newer maintenance release tag to describe the development trunk, rather than the development trunk's own tag. The suggested workaround would be to retag the development trunk's tip. However since even 26 possible tags can take a while to generate a description for on some projects I'm defaulting the limit to 10 but offering the user --candidates to increase the number of possible matches if they need a more accurate result. I specifically chose 10 for the default as it seems unlikely projects will have more than 10 maintenance releases merged into a development trunk before retagging the development trunk, and it seems to perform about the same on linux.git as v1.4.4.4 git-describe. A large amount of debugging information was also added during the development of this change, so I've left it in to be toggled on with --debug. It may be useful to the end user to help them understand why git-describe took one particular tag over another. Signed-off-by: Shawn O. Pearce <spearce@spearce.org> Signed-off-by: Junio C Hamano <junkio@cox.net>
2007-01-13 22:30:53 +00:00
if (gave_up_on) {
fprintf(stderr,
_("more than %i tags found; listed %i most recent\n"
"gave up search at %s\n"),
Improve git-describe performance by reducing revision listing. My prior version of git-describe ran very slowly on even reasonably sized projects like git.git and linux.git as it tended to identify a large number of possible tags and then needed to generate the revision list for each of those tags to sort them and select the best tag to describe the input commit. All we really need is the number of commits in the input revision which are not in the tag. We can generate these counts during the revision walking and tag matching loop by assigning a color to each tag and coloring the commits as we walk them. This limits us to identifying no more than 26 possible tags, as there is limited space available within the flags field of struct commit. The limitation of 26 possible tags is hopefully not going to be a problem in real usage, as most projects won't create 26 maintenance releases and merge them back into a development trunk after the development trunk was tagged with a release candidate tag. If that does occur git-describe will start to revert to its old behavior of using the newer maintenance release tag to describe the development trunk, rather than the development trunk's own tag. The suggested workaround would be to retag the development trunk's tip. However since even 26 possible tags can take a while to generate a description for on some projects I'm defaulting the limit to 10 but offering the user --candidates to increase the number of possible matches if they need a more accurate result. I specifically chose 10 for the default as it seems unlikely projects will have more than 10 maintenance releases merged into a development trunk before retagging the development trunk, and it seems to perform about the same on linux.git as v1.4.4.4 git-describe. A large amount of debugging information was also added during the development of this change, so I've left it in to be toggled on with --debug. It may be useful to the end user to help them understand why git-describe took one particular tag over another. Signed-off-by: Shawn O. Pearce <spearce@spearce.org> Signed-off-by: Junio C Hamano <junkio@cox.net>
2007-01-13 22:30:53 +00:00
max_candidates, max_candidates,
oid_to_hex(&gave_up_on->object.oid));
Improve git-describe performance by reducing revision listing. My prior version of git-describe ran very slowly on even reasonably sized projects like git.git and linux.git as it tended to identify a large number of possible tags and then needed to generate the revision list for each of those tags to sort them and select the best tag to describe the input commit. All we really need is the number of commits in the input revision which are not in the tag. We can generate these counts during the revision walking and tag matching loop by assigning a color to each tag and coloring the commits as we walk them. This limits us to identifying no more than 26 possible tags, as there is limited space available within the flags field of struct commit. The limitation of 26 possible tags is hopefully not going to be a problem in real usage, as most projects won't create 26 maintenance releases and merge them back into a development trunk after the development trunk was tagged with a release candidate tag. If that does occur git-describe will start to revert to its old behavior of using the newer maintenance release tag to describe the development trunk, rather than the development trunk's own tag. The suggested workaround would be to retag the development trunk's tip. However since even 26 possible tags can take a while to generate a description for on some projects I'm defaulting the limit to 10 but offering the user --candidates to increase the number of possible matches if they need a more accurate result. I specifically chose 10 for the default as it seems unlikely projects will have more than 10 maintenance releases merged into a development trunk before retagging the development trunk, and it seems to perform about the same on linux.git as v1.4.4.4 git-describe. A large amount of debugging information was also added during the development of this change, so I've left it in to be toggled on with --debug. It may be useful to the end user to help them understand why git-describe took one particular tag over another. Signed-off-by: Shawn O. Pearce <spearce@spearce.org> Signed-off-by: Junio C Hamano <junkio@cox.net>
2007-01-13 22:30:53 +00:00
}
Chose better tag names in git-describe after merges. Recently git.git itself encountered a situation on its master and next branches where git-describe stopped reporting 'v1.5.0-rc0-gN' and instead started reporting 'v1.4.4.4-gN'. This appeared to be a backward jump in version numbering. maint o-------------------4 \ \ master o-o-o-o-o-o-o-5-o-C-o-W The issue is that commit C in the diagram claims it is version 1.5.0, as the tag v1.5.0 is placed on commit 5. Yet commit W claims it is version 1.4.4.4 as the tag v1.5.0 has an older tag date than the v1.4.4.4 tag. As it turns out this situation is very common. A bug fix applied to maint and later merged into master occurs frequently enough that it should Just Work Right(tm). Rather than taking the first tag that gets found git-describe will now generate a list of all possible tags and select the one which has the most number of commits in common with HEAD (or whatever revision the user requested the description of). This rule is based on the principle shown in the diagram above. There are a large number of commits on the primary development branch 'master' which do not appear in the 'maint' branch, and many of these are already tagged as part of v1.5.0-rc0. Additionally these commits are not in v1.4.4.4, as they are part of the v1.5.0 release still being developed. The v1.5.0-rc0 tag is more descriptive of W than v1.4.4.4 is, and therefore should be used. Signed-off-by: Shawn O. Pearce <spearce@spearce.org> Signed-off-by: Junio C Hamano <junkio@cox.net>
2007-01-10 11:39:47 +00:00
}
display_name(all_matches[0].name);
if (abbrev)
show_suffix(all_matches[0].depth, &cmit->object.oid);
if (suffix)
printf("%s", suffix);
printf("\n");
Chose better tag names in git-describe after merges. Recently git.git itself encountered a situation on its master and next branches where git-describe stopped reporting 'v1.5.0-rc0-gN' and instead started reporting 'v1.4.4.4-gN'. This appeared to be a backward jump in version numbering. maint o-------------------4 \ \ master o-o-o-o-o-o-o-5-o-C-o-W The issue is that commit C in the diagram claims it is version 1.5.0, as the tag v1.5.0 is placed on commit 5. Yet commit W claims it is version 1.4.4.4 as the tag v1.5.0 has an older tag date than the v1.4.4.4 tag. As it turns out this situation is very common. A bug fix applied to maint and later merged into master occurs frequently enough that it should Just Work Right(tm). Rather than taking the first tag that gets found git-describe will now generate a list of all possible tags and select the one which has the most number of commits in common with HEAD (or whatever revision the user requested the description of). This rule is based on the principle shown in the diagram above. There are a large number of commits on the primary development branch 'master' which do not appear in the 'maint' branch, and many of these are already tagged as part of v1.5.0-rc0. Additionally these commits are not in v1.4.4.4, as they are part of the v1.5.0 release still being developed. The v1.5.0-rc0 tag is more descriptive of W than v1.4.4.4 is, and therefore should be used. Signed-off-by: Shawn O. Pearce <spearce@spearce.org> Signed-off-by: Junio C Hamano <junkio@cox.net>
2007-01-10 11:39:47 +00:00
Improve git-describe performance by reducing revision listing. My prior version of git-describe ran very slowly on even reasonably sized projects like git.git and linux.git as it tended to identify a large number of possible tags and then needed to generate the revision list for each of those tags to sort them and select the best tag to describe the input commit. All we really need is the number of commits in the input revision which are not in the tag. We can generate these counts during the revision walking and tag matching loop by assigning a color to each tag and coloring the commits as we walk them. This limits us to identifying no more than 26 possible tags, as there is limited space available within the flags field of struct commit. The limitation of 26 possible tags is hopefully not going to be a problem in real usage, as most projects won't create 26 maintenance releases and merge them back into a development trunk after the development trunk was tagged with a release candidate tag. If that does occur git-describe will start to revert to its old behavior of using the newer maintenance release tag to describe the development trunk, rather than the development trunk's own tag. The suggested workaround would be to retag the development trunk's tip. However since even 26 possible tags can take a while to generate a description for on some projects I'm defaulting the limit to 10 but offering the user --candidates to increase the number of possible matches if they need a more accurate result. I specifically chose 10 for the default as it seems unlikely projects will have more than 10 maintenance releases merged into a development trunk before retagging the development trunk, and it seems to perform about the same on linux.git as v1.4.4.4 git-describe. A large amount of debugging information was also added during the development of this change, so I've left it in to be toggled on with --debug. It may be useful to the end user to help them understand why git-describe took one particular tag over another. Signed-off-by: Shawn O. Pearce <spearce@spearce.org> Signed-off-by: Junio C Hamano <junkio@cox.net>
2007-01-13 22:30:53 +00: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 21:50:45 +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
{
int contains = 0;
struct option options[] = {
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")),
OPT__ABBREV(&abbrev),
OPT_SET_INT(0, "exact-match", &max_candidates,
N_("only output exact matches"), 0),
OPT_INTEGER(0, "candidates", &max_candidates,
N_("consider <n> most recent tags (default: 10)")),
OPT_STRING_LIST(0, "match", &patterns, N_("pattern"),
N_("only consider tags matching <pattern>")),
OPT_STRING_LIST(0, "exclude", &exclude_patterns, N_("pattern"),
N_("do not consider tags matching <pattern>")),
OPT_BOOL(0, "always", &always,
N_("show abbreviated commit object as fallback")),
{OPTION_STRING, 0, "dirty", &dirty, N_("mark"),
N_("append <mark> on dirty working tree (default: \"-dirty\")"),
PARSE_OPT_OPTARG, NULL, (intptr_t) "-dirty"},
{OPTION_STRING, 0, "broken", &broken, N_("mark"),
N_("append <mark> on broken working tree (default: \"-broken\")"),
PARSE_OPT_OPTARG, NULL, (intptr_t) "-broken"},
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
git_config(git_default_config, NULL);
argc = parse_options(argc, argv, prefix, options, describe_usage, 0);
if (abbrev < 0)
abbrev = DEFAULT_ABBREV;
if (max_candidates < 0)
max_candidates = 0;
else if (max_candidates > MAX_TAGS)
max_candidates = MAX_TAGS;
save_commit_buffer = 0;
if (longformat && abbrev == 0)
die(_("--long is incompatible with --abbrev=0"));
if (contains) {
struct string_list_item *item;
struct argv_array args;
argv_array_init(&args);
argv_array_pushl(&args, "name-rev",
"--peel-tag", "--name-only", "--no-undefined",
NULL);
if (always)
argv_array_push(&args, "--always");
if (!all) {
argv_array_push(&args, "--tags");
for_each_string_list_item(item, &patterns)
argv_array_pushf(&args, "--refs=refs/tags/%s", item->string);
for_each_string_list_item(item, &exclude_patterns)
argv_array_pushf(&args, "--exclude=refs/tags/%s", item->string);
}
if (argc)
argv_array_pushv(&args, argv);
else
argv_array_push(&args, "HEAD");
return cmd_name_rev(args.argc, args.argv, prefix);
}
hashmap_init(&names, commit_name_cmp, NULL, 0);
for_each_rawref(get_name, NULL);
if (!names.size && !always)
die(_("No names found, cannot describe anything."));
if (argc == 0) {
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) {
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))
suffix = NULL;
else
suffix = dirty;
}
2006-01-16 06:25:35 +00:00
describe("HEAD", 1);
Teach "git describe" --dirty option With the --dirty option, git describe works on HEAD but append s"-dirty" iff the contents of the work tree differs from HEAD. E.g. $ git describe --dirty v1.6.5-15-gc274db7 $ echo >> Makefile $ git describe --dirty v1.6.5-15-gc274db7-dirty The --dirty option can also be used to specify what is appended, instead of the default string "-dirty". $ git describe --dirty=.mod v1.6.5-15-gc274db7.mod Many build scripts use `git describe` to produce a version number based on the description of HEAD (on which the work tree is based) + saying that if the build contains uncommitted changes. This patch helps the writing of such scripts since `git describe --dirty` does directly the intended thing. Three possiblities were considered while discussing this new feature: 1. Describe the work tree by default and describe HEAD only if "HEAD" is explicitly specified Pro: does the right thing by default (both for users and for scripts) Pro: other git commands that works on the work tree by default Con: breaks existing scripts used by the Linux kernel and other projects 2. Use --worktree instead of --dirty Pro: does what it says: "git describe --worktree" describes the work tree Con: other commands do not require a --worktree option when working on the work tree (it often is the default mode for them) Con: unusable with an optional value: "git describe --worktree=.mod" is quite unintuitive. 3. Use --dirty as in this patch Pro: makes sense to specify an optional value (what the dirty mark is) Pro: does not have any of the big cons of previous alternatives * does not break scripts * is not inconsistent with other git commands This patch takes the third approach. Signed-off-by: Jean Privat <jean@pryen.org> Acked-by: Shawn O. Pearce <spearce@spearce.org> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2009-10-21 13:35:22 +00:00
} else if (dirty) {
die(_("--dirty is incompatible with commit-ishes"));
} else if (broken) {
die(_("--broken is incompatible with commit-ishes"));
} else {
while (argc-- > 0)
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;
}