20

Mercurial has a domain-specific language called revsets that allows users to specify sets of revisions.

For example, you might want to list patches that haven't yet been merged into the branch default:

hg log -r "all() - ancestors('default')"

As a more complex example, the link above gives the example of listing changesets between the revision tagged 1.3 and the revision tagged 1.5 which mention "bug" and affect a file in the directory hgext:

hg log -r "1.3::1.5 and keyword(bug) and file('hgext/*')"

The revset language is quite rich, allowing selection of changesets based on dates, username, commit message, whether the commit exists at a particular remote location, and so on.

Does git have an equivalent mechanism for querying changesets, either in the core program or available as an extension?

davidg
  • 5,868
  • 2
  • 33
  • 51
  • 4
    The languages are quite different but the general command in git for generating revision-lists is `git rev-list`. Most git commands use it (either directly via compiled-in access, or by invoking it as a command because they are shell scripts themselves). In cases where `git rev-list` alone is not sufficient, you can write shell scripts that read its output, feed it input, and so on. – torek Mar 20 '14 at 00:09
  • 1
    @torek: The point of using `revsets` is because I got tired of writing shell scripts `:)`. `git rev-list` looks like it provides at least some of the functionality of `revsets`. Would you consider putting you comment as an answer, perhaps with a quick comparison of the two? – davidg Mar 20 '14 at 00:51
  • I'm afraid the comparison will get really long *and* I'm much less familiar with the behaviors of hg revsets (I keep being surprised by boundary condition differences between hg and git for instance), so I'm a bit hesitant :-) – torek Mar 20 '14 at 00:56
  • Is there something specific you want help cooking up a script for? – jthill Mar 20 '14 at 07:07
  • @jthill: No. I am moving over to git, and rely heavily on Mercurial revsets for day-to-day work. I have so far only encountered basic revision ranges, and was trying to establish if git was lacking something similar, or if I was just not looking in the right place. – davidg Mar 20 '14 at 09:40
  • Please see the [`gitrevisions(7)`](https://www.kernel.org/pub/software/scm/git/docs/gitrevisions.html) manual page. – kostix Mar 20 '14 at 17:25
  • @kostix: The [gitrevisions(7)](https://www.kernel.org/pub/software/scm/git/docs/gitrevisions.html) man page only talks about basic methods of specifying revisions. For example, how would I specify all commits older than two weeks with "bug" in their commit message not a descendant from the current checkout? In `revsets`, it would be `not date(-14) & desc("bug") & not ancestors(.)`. – davidg Mar 20 '14 at 23:10
  • @davidg, Git implements a different approach: revision ranges in it operate only on commit names (SHA-1 or symbolic) and log limiting in `git log` and friends is done using command-line options such as `--grep`. Note that selecting commits by date is still done when specifying revisions -- see the manual page I referred to. – kostix Mar 23 '14 at 13:08
  • @kostix: `gitrevisions` and `git rev-list` appear to a be figurative `grep`, when what I really want (and what Mercurial revsets provide) is a figurative `SQL`. It is looking increasingly like I will need to find either a git extension, or roll up my sleeves and write something myself. – davidg Mar 23 '14 at 22:55
  • 2
    @davidg, while I wish you good luck implementing this, I'd first consdider that you appear to be the first person on Earth wanting this sort of thing. I mean, there's a bunch of productive hackers around Git and no one wanted to implement such a feature yet. To me, this means it might be better to just adopt the extsting approaches to the problem, even if they currently feel to be inferior to what you've learned with Mecrurial. – kostix Mar 24 '14 at 06:57
  • @kostix: Replace "git" with "subversion" and "revsets" with "distributed version control", and your sentence would have rung true in 2003 `;)`. The Mercurial community has found the feature useful. `git rev-list` seems to solves a subset of the problems, which suggests that _some_ of the problems revsets attempts to solve have been hit by git developers and tackled by git developers in an ad-hoc manner. Anyway, I am going very off-topic from the original question, which was not about the benefits of revsets, but whether there exists an equivalent (either core or third-party) for git. – davidg Mar 24 '14 at 07:32
  • @davidg, a minor correction: `git rev-list` is a plumbing level command used by `git log` and friends, it's not intended to be used by users but rather by scripts so I'd not say it tries to solve any problems beyond making `git log` to its job ;-) – kostix Mar 24 '14 at 07:37
  • Try `git log` with [commit ranges](http://git-scm.com/book/en/v2/Git-Tools-Revision-Selection/#_commit_ranges) such as `..`, `...`, and `--not`. Then add on top the `git log` with `grep`, and this probably provides the equivalent functionality. Time permitting, I will type up an answer with examples that match your question. – Shaun Luttin Dec 05 '14 at 17:54
  • re git/revset::svn/dvcs analogy, (a) rev-list and/or log already do all the basics but svn can't dvcs at all, and (b) sort/join/sed can do arbitrary set operations as oneliners or nearly so. So what, specifically, are you having trouble discovering about your histories, please? – jthill Dec 25 '14 at 22:45
  • This is a great question and confining revsets to just a log-search may be misleading individuals who have not used complex revsets. The full power of a reveset is simply not realized in such a context - for example, take `hg diff -r 'my-feature + tip~3':tip` which has no git equivalent, much less anything that can be written in a generalized manner. Now, is it "required"? Well, no as the lack-of-caring-of-git-users shows .. but there are a few things hg does do better, and this is one. – user2864740 Dec 06 '15 at 09:13

3 Answers3

3

The git-branchless suite of tools now includes a revset-like language under the command git branchless query.

Once installed and initialised on the current repository, the examples in the previous question (from eight years ago!) could be queried as follows:

# List patches not yet been merged into the branch default:
git branchless query "all() - ancestors('default')"
# List patches between the revision tagged 1.3 and the revision tagged
# 1.5 which which mention "bug" and affect a file in the directory hgext
git branchless query "1.3::1.5 and message('bug') and paths.changed('glob:hgext/*')"

These are remarkably similar to their HG equivalents.

davidg
  • 5,868
  • 2
  • 33
  • 51
2

To list all commits except from the default master branch, like I assume the first example does:

git log --all --not master

To get a result somewhat equal to the second example:

git log 1.3...1.5 --grep="bug" -- hgext
Faheem Mitha
  • 6,096
  • 7
  • 48
  • 83
peroyhav
  • 161
  • 1
  • 6
  • 4
    Thanks for the thought. Your answer indeed solves the particular examples I gave, but was not the general solution I was hoping for. I was really hoping for a plugin/extension that provides a DSL for specifying revisions similar to that of Mercurial's revsets DSL. Figuratively, you have solved my examples using `grep`, while what I really want is SQL. Such a DSL doesn't seem to exist for git at this time, but I will leave this question open in case that changes in the future. (I should give more interesting examples; when `or` and `and` predicates are nested, `grep` starts to break down). – davidg Jan 20 '15 at 11:52
  • I understand the issue, However, it is possible to add multiple grep arguments to git log, each grep argument is like an or clause let's say you want to match a string "Create" or the string "Add" you can run `git log --grep "Create" --grep "Add"` For affected files or folders, just add the files / folders you want to include after the -- argument. – peroyhav Jan 21 '15 at 15:41
2

Does git have an equivalent mechanism for querying changesets, either in the core program or available as an extension?

The closest equivalent in git is gitrevisions(7), but it's completely ad-hoc, and significantly less regular, and less composable. And not all commands use it (famously git diff has identical constructs which behave completely differently, because gitrevisions works on ranges but git diff works on pairs of commits).

Masklinn
  • 34,759
  • 3
  • 38
  • 57