Welcome to the 66th edition of Git Rev News, a digest of all things Git. For our goals, the archives, the way we work, and how to contribute or to subscribe, see the Git Rev News page on git.github.io.
This edition covers what happened during the month of July 2020.
git-mv: improve error message for conflicted file
Chris Torek sent a patch to change the error message from git mv
when it’s used on a file that has unresolved conflicts. Previously,
in this special case git mv
would error out with the same error
message as if the file was not managed by Git, that is:
“fatal: not under version control, src=…”
This was of course misleading, so Chris’ patch implemented detecting this case and then using the new “must resolve merge conflict first” error message if applicable.
Eric Sunshine first reviewed the patch suggesting a small code improvement in the detection of this case, and a more succinct new error message, “conflicted”. Eric also commented on the test case that Chris’ patch added, suggesting a number of small changes that would make the test look more modern.
Junio Hamano, the Git maintainer, commented on the code detecting this case. He suggested a less wasteful way to do that.
Chris then replied to Eric’s review saying he will use Junio’s suggestion for the detection code and Eric’s suggestions for the error message and the test.
Chris also asked if he should clean up and modernize other tests in the test script that could benefit from Eric’s suggestions, but Eric replied that the test script, “t7001-mv.sh”, had so many old style issues that such improvements should happen in a dedicated patch series.
Interestingly Eric listed 17 different old style issues, and for each one he described what should be done to fix them, so that his email can be read as a guide to modernizing test scripts.
Elijah Newren replied to Junio’s suggestion, pointing to
an email from two years ago,
where the same issue was already discussed and where Junio suggested
that git mv
on a conflicting file could just move the file and
remove its conflicting status, in the same way as git rm
and
git add
already work on such a file.
Elijah said that he was still planning to implement what Junio had suggested in that email, but that in the meantime fixing the error message was perfectly fine.
Junio replied to Elijah saying that he was not convinced any more that what he had suggested two years ago was actually the right thing to do, and then describing in details some issues with his old suggestion. Junio agreed though that fixing the error message as in Chris’ patch was a “strict improvement”.
Elijah and Junio then discussed a bit more technical issues related to Junio’s old proposal.
Chris sent a version 2 of his patch implementing Junio’s and Eric’s suggestions, including the shortened “conflicted” error message that Eric had suggested.
Junio replied to Chris and discussed a bit the “conflicted” error message, but Chris’ version 2 patch got merged to the master branch as is.
How can I search git log with certain keyword but without the other keyword?
孙世龙 sunshilong asked how to search for commits in git log
that include
certain keyword A, but at the same time do not have another keyword B in them.
The example provided was a branch with three commits:
b90b03f b12
27f7577 b1
7268b40 t123
The original poster wanted to use git log --grep
to find commits that match
“12” but not “t123”. In this example it should return only “b90b03f b12” as
search result.
Carlo Arenas proposed using features of PCRE syntax (Perl Compatible Regular Expressions) with a negative lookahead assertion and word boundary to generate expression that matches one but not the other:
git log -P --all-match --grep '12' --grep '\b(?!t123\b)\w+'
The syntax was explained by Jeff King, alias Peff, who also said that the
short option -P
had to be spelled --perl-regexp
before Git version
v2.14.0. He also reminded that for this to work one also needs a version of Git
built with libpcre support.
It turned out however that it didn’t resolve the [more] real issue that sunshilong had:
I wonder why this command doesn’t work well.
I intend to find the comment with the keyword “12” but without “comments” whereas the output is something like this:
git log --perl-regexp --all-match --grep=12 --grep '\b(?!comments\b)\w+' commit f5b6c3e33bd2559d6976b1d589071a5928992601 Author: sunshilong <sunshilong369@gmail.com> Date: 2020-04-12 23:00:29 +0800 comments 2020.04.12 ng
Peff responded that he can’t think of a way to achieve that just using a regex,
and that currently Git supports similar feature only in git grep
:
The natural thing to me would be the equivalent of:
git grep -e 12 --and --not -e comments
The underlying grep machinery in Git understands how to compose multiple patterns like this, and the command above really does work (though of course it is searching for lines in a file and not commit messages).
But none of that is exposed via the command-line of “git log”. I think it would be possible to do so, but I’m not sure how tricky it would be (certainly one complication is that “--not” already means something else there, but presumably we could have “--grep-and”, “--grep-not”, etc).
The idea of introducing --grep-and
and --grep-not
to disambiguate from --not
(which
means something completely different for the log family) is
as old as 2012,
as Junio C Hamano reminded. He then went to explain the problem
with properly implementing such feature:
Having said that, I do not think our underlying grep machinery is equipped to answer “find every commit whose log message has X but not Y”, even if we exposed the interface that is equivalent to that of “git grep” to “git log”.
There are two levels of boolean combination involved in running our “grep” machinery. The lower level is used to determine if each line matches the criteria. The main consumer of the “grep” machinery is of course “git grep” and because it is line oriented, we have quite a rich set of operations and combinations to say things like “if a line has X and Y on it in any order, but not Z on it, then the line is a match.” That is what “--not”, “--and”, “--or” (not exposed to the “git log” interface) express and we even take “(“ and “)” for grouping, e.g. “( X --or Y ) --and --not Z”.
Another level of combination is to determine if the entire document matches. It often happens that you want to find a document with both X and Y in it, and “grep -e X --and -e Y” is *NOT* a way to do so — the “--and” is a line-level combinator and tells the machinery to find lines that have both X and Y on them.
We have a fairly ad-hoc single mechanism for boolean combination at this level and that is the “--all-match” option, which says “Look at the boolean expression you used to find each matching line, and separate them at the OR operator at the top level. Now, apply the matching logic to all lines in a document and see if all the clauses joined by the top-level OR operators matched at least once. If yes, then the document matches.”
That is how “git grep --all-match -e X -e Y” finds documents that refer to both X and Y but not necessarily on the same line.
There is not much room for the line-level “--not” operator to participate in this picture. “git grep -e X --not -e Y” would mean “find lines that has X, or that does not have Y”, so as long as a document has one line with X on it and one line (which can be but does not have to be the same line) that does not have Y on it, the variant of that search with “--all-match” in it would say “yup the doc matches”. But that is definitely not what the user who wants to say “if a doc has X in it, I want to see it, but I do not want to see it if it also has Y” wants to see.
Then the discussion petered out, without much further help. It remains to be seen if somebody would take up the challenge of improving Git search capabilities by adding support for boolean combinations of line-level and document-level match operations.
Various
Light reading
Git tools and sites
grr
and Windows Explorer enhancements.This edition of Git Rev News was curated by Christian Couder <christian.couder@gmail.com>, Jakub Narębski <jnareb@gmail.com>, Markus Jansen <mja@jansen-preisler.de> and Kaartic Sivaraam <kaartic.sivaraam@gmail.com>.