Re: [PATCH v2 1/2] pkt-line: add packet_writel() and packet_read_line_gently()
On 2017-03-24 16:27, Ben Peart wrote: > Add packet_writel() which writes multiple lines in a single call and > then calls packet_flush_gently(). Add packet_read_line_gently() to > enable reading a line without dying on EOF. > > Signed-off-by: Ben Peart> --- > pkt-line.c | 31 +++ > pkt-line.h | 11 +++ > 2 files changed, 42 insertions(+) > > diff --git a/pkt-line.c b/pkt-line.c > index d4b6bfe076..2788aa1af6 100644 > --- a/pkt-line.c > +++ b/pkt-line.c > @@ -171,6 +171,25 @@ int packet_write_fmt_gently(int fd, const char *fmt, ...) > return status; > } > > +int packet_writel(int fd, const char *line, ...) The name packet_writel is hard to distinguish from packet_write. Would packet_write_lines make more sense ? > +{ > + va_list args; > + int err; > + va_start(args, line); > + for (;;) { > + if (!line) > + break; > + if (strlen(line) > LARGE_PACKET_DATA_MAX) > + return -1; > + err = packet_write_fmt_gently(fd, "%s\n", line); > + if (err) > + return err; > + line = va_arg(args, const char*); > + } > + va_end(args); > + return packet_flush_gently(fd); > +} > + I don't think that this va_start() is needed, even if it works. int packet_write_line(int fd, const char *lines[]) | const char *line = *lines; int err; while (line) { if (strlen(line) > LARGE_PACKET_DATA_MAX) return -1; err = packet_write_fmt_gently(fd, "%s\n", line); if (err) return err; lines++; line = *lines; } return packet_flush_gently(fd); ]
Re: Re: Re: GSoC Project | Convert interactive rebase to C
Johannes Schindelinwrote: > On Tue, 21 Mar 2017, Ivan Tham wrote: > > Stefan Beller wrote: > > > On Mon, Mar 20, 2017 at 9:41 AM, Ivan Tham wrote: > > > > I am Ivan Tham. Currently studying in Computer Science in APIIT > > > > Malaysia. I am interested particapate in Google Summer of Code 2017 > > > > under git organization. I would like to attempt "Add more builtin > > > > patterns for userdiff" particularly for shell for my microproject. > > > > > > I'd love to see proper shell support! Although there is already some > > > support for shell (by looking at diffs on our test suite) ? So I am > > > not sure what there is left to do? Can you clarify what you're trying > > > there? > > > > Are you sure about that? From what I had looked into userdiff.c, there > > is no support for shell. There just a recent patch for [go patterns][0]. > > Or perhaps I should have rename it as "userdiff.c: patterns for "shell" > > language"? > > I also could not find any shell patterns in the userdiff code... Thanks a lot for replying me, I thought no one was intereted. :D > > > > I am interested to work on "Convert interactive rebase to C" > > > > > > +cc Johannes, who recently worked on rebase and the sequencer. > > Glad you are interested! Please note that large parts of the interactive > rebase are already in C now, but there is enough work left in that corner. Glad to hear that, I would really like to see interactive rebase in C. > > > > aiming to port most builtins stuff to C in which we can reduce the > > > > size of git. Additionally, I would also like to convert scripts to > > > > builtins as an additional milestone. > > Careful. It is a ton of work to get the rebase -i conversion done, and > then a ton of work to get it integrated. That will fill 3 months, very > easily. My main aim is to reduce the extra dependency of perl, but planning to start with rebase, can I make that an optional task where I can help out after I had completed my main task during gsoc? > > > > What do you think of these projects? Would it collide with Valery > > > > Tolstov's Shell to Builtins proposal? > > I missed that proposal, and could only find submodule-related mails on the > public-inbox server. Care to provide a pointer? > > > > Curious why all people ask about colliding with Valerys proposal here? > > > I do not think it would collide, as submodules and rebase are very > > > different areas of the code base. > > Indeed ;-) Cheers, Ivan Tham
Re: [PATCH v7 0/7] short status: improve reporting for submodule changes
Stefan Beller wrote: > v7: > * taken all of Jonathan minor nits, so patch 1..6 should be good to go > * patch 7 lacks tests and documentation (according to Jonathan...) > but as it is the last patch, just fixing a minor detail we can leave it off. > > Junio, please take patch 1-6 as usual, I will be out until next Wednesday. [...] > Stefan Beller (8): > submodule.c: port is_submodule_modified to use porcelain 2 > submodule.c: use argv_array in is_submodule_modified > submodule.c: convert is_submodule_modified to use > strbuf_getwholeline_fd > submodule.c: port is_submodule_modified to use porcelain 2 > submodule.c: factor out early loop termination in > is_submodule_modified > submodule.c: stricter checking for submodules in is_submodule_modified > short status: improve reporting for submodule changes > submodule.c: correctly handle nested submodules in > is_submodule_modified > > Documentation/git-status.txt | 9 +++ > submodule.c | 56 --- > t/t3600-rm.sh| 18 ++ > t/t7506-status-submodule.sh | 57 > > wt-status.c | 13 -- > 5 files changed, 116 insertions(+), 37 deletions(-) Patches 1-6 are Reviewed-by: Jonathan NiederThe effect of patch 7 on --porcelain=2 output is subtle enough that I don't feel I understand it. I think it heads in a good direction but indeed, some tests could help to illustrate the desired behavior. Thanks for your patient work. Jonathan
Re: [PATCH] [GSoC] remove_subtree(): reimplement using iterators
> On Fri, Mar 24, 2017 at 2:02 PM, Stefan Bellerwrote: > Welcome to the Git community! Thank you! > Please use a more imperative style. (e.g. s/Uses/Use/ ... > s/and simplfying/which simplifies/) Thank you. Will do in a second version of this patch. > Thanks for this link. It gives good context for reviewing the change, > but it will not be good context to record as a commit message. > (When someone looks at a commit message later on, they are usually trying > to figure out what the author was thinking; if there were any special cases to > be thought about. Was performance on the authors mind? etc) > So I propose to put the link into the more informal section if a > reroll is needed. Perfect. I will remove it from the message. > Instead of constructing the path again here based on relative path > and the path parameter, I wonder if we could use > > if (unlink(diter->path)) > .. > > here? Then we would not need the strbuf at all? Yes, we can! Thank you for the pointer. Will be in the next version of the patch. > Also we'd need to handle (empty) directories differently for removal? >From what I've tested, we do not need to do it. > Do we need to check the return code of dir_iterator_advance > for ITER_ERROR as well? I believe not – it only tries to perform an operation if we have ITER_OK. Since ITER_ERROR would end up in a no-op anyway I don't see how a check for it would be useful. > > > > } > > - closedir(dir); > > + > > if (rmdir(path->buf)) > > die_errno("cannot rmdir '%s'", path->buf); > > This would remove the "top level" directory as given by path. > When reading the dir-iterator code, I am not sure if this is > also part of the yield in dir_iterator_advance. I've tested it, and it does not yield in there. Thank you for the advice, and as stated, will submit a v2 of the patch in short notice. Thank you, Daniel.
[PATCH 7/7] submodule.c: correctly handle nested submodules in is_submodule_modified
When a nested submodule has untracked files, it would be reported as "modified submodule" in the superproject, because submodules are not parsed correctly in is_submodule_modified as they are bucketed into the modified pile as "they are not an untracked file". Signed-off-by: Stefan Beller--- submodule.c | 23 +-- t/t3600-rm.sh | 2 +- t/t7506-status-submodule.sh | 2 +- 3 files changed, 23 insertions(+), 4 deletions(-) diff --git a/submodule.c b/submodule.c index fa21c7bb72..730cc9513a 100644 --- a/submodule.c +++ b/submodule.c @@ -1078,8 +1078,27 @@ unsigned is_submodule_modified(const char *path, int ignore_untracked) /* regular untracked files */ if (buf.buf[0] == '?') dirty_submodule |= DIRTY_SUBMODULE_UNTRACKED; - else - dirty_submodule |= DIRTY_SUBMODULE_MODIFIED; + + if (buf.buf[0] == 'u' || + buf.buf[0] == '1' || + buf.buf[0] == '2') { + /* +* T XY : +* T = line type, XY = status, = submodule state +*/ + if (buf.len < 1 + 1 + 2 + 1 + 4) + die("BUG: invalid status --porcelain=2 line %s", + buf.buf); + + /* regular unmerged and renamed files */ + if (buf.buf[5] == 'S' && buf.buf[8] == 'U') + /* nested untracked file */ + dirty_submodule |= DIRTY_SUBMODULE_UNTRACKED; + + if (memcmp(buf.buf + 5, "S..U", 4)) + /* other change */ + dirty_submodule |= DIRTY_SUBMODULE_MODIFIED; + } if ((dirty_submodule & DIRTY_SUBMODULE_MODIFIED) && ((dirty_submodule & DIRTY_SUBMODULE_UNTRACKED) || diff --git a/t/t3600-rm.sh b/t/t3600-rm.sh index a6e5c5bd56..b58793448b 100755 --- a/t/t3600-rm.sh +++ b/t/t3600-rm.sh @@ -659,7 +659,7 @@ test_expect_success 'rm of a populated nested submodule with nested untracked fi test -d submod && test -f submod/.git && git status -s -uno --ignore-submodules=none >actual && - test_cmp expect.modified_inside actual && + test_cmp expect.modified_untracked actual && git rm -f submod && test ! -d submod && git status -s -uno --ignore-submodules=none >actual && diff --git a/t/t7506-status-submodule.sh b/t/t7506-status-submodule.sh index 6d3acb4a5a..ab822c79e6 100755 --- a/t/t7506-status-submodule.sh +++ b/t/t7506-status-submodule.sh @@ -340,7 +340,7 @@ test_expect_success 'status with untracked file in nested submodule (porcelain)' test_expect_success 'status with untracked file in nested submodule (short)' ' git -C super status --short >output && diff output - <<-\EOF -m sub1 +? sub1 EOF ' -- 2.12.0.rc1.49.gdeb397943c.dirty
[PATCH v7 0/7] short status: improve reporting for submodule changes
v7: * taken all of Jonathan minor nits, so patch 1..6 should be good to go * patch 7 lacks tests and documentation (according to Jonathan...) but as it is the last patch, just fixing a minor detail we can leave it off. Junio, please take patch 1-6 as usual, I will be out until next Wednesday. Thanks, Stefan v6: * kill the child once we know all information that we ask for, as an optimization * reordered the patches for that * strbuf_getwholeline instead of its _fd version. v5: * fixed rebase error in the first 2 patches * the last 3 patches introduce behavior change outside the scope of is_modified_submodule whereas the first 4 ought to just be local changes. Thanks, Stefan v4: * broken down in a lot of tiny patches. Jonathan wrote: > Patch 1/3 is the one that gives me pause, since I hadn't been able to > chase down all callers. Would it be feasible to split that into two: > one patch to switch to --porcelain=2 but not change behavior, and a > separate patch to improve what is stored in the dirty_submodule flags? This part is in the latest patch now. Thanks, Stefan v3: This comes as a series; first I'd like to refactor is_submodule_modified to take advantage of the new porcelain=2 plumbing switch to check for changes in the submodule. On top of the refactoring comes the actual change, which moved the rewriting of the submodule change indicator letter to the collection part. Thanks, Stefan Stefan Beller (8): submodule.c: port is_submodule_modified to use porcelain 2 submodule.c: use argv_array in is_submodule_modified submodule.c: convert is_submodule_modified to use strbuf_getwholeline_fd submodule.c: port is_submodule_modified to use porcelain 2 submodule.c: factor out early loop termination in is_submodule_modified submodule.c: stricter checking for submodules in is_submodule_modified short status: improve reporting for submodule changes submodule.c: correctly handle nested submodules in is_submodule_modified Documentation/git-status.txt | 9 +++ submodule.c | 56 --- t/t3600-rm.sh| 18 ++ t/t7506-status-submodule.sh | 57 wt-status.c | 13 -- 5 files changed, 116 insertions(+), 37 deletions(-) -- 2.12.1.438.gb674c4c09c
[PATCH 4/7] submodule.c: port is_submodule_modified to use porcelain 2
Migrate 'is_submodule_modified' to the new porcelain format of git-status. This conversion attempts to convert faithfully, i.e. the behavior ought to be exactly the same. As the output in the parsing only distinguishes between untracked files and the rest, this is easy to port to the new format, as we only need to identify untracked files and the rest is handled in the "else" case. untracked files are indicated by only a single question mark instead of two question marks, so the conversion is easy. Signed-off-by: Stefan BellerReviewed-by: Jonathan Nieder --- submodule.c | 9 + 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/submodule.c b/submodule.c index e72781d9f2..5865795b9f 100644 --- a/submodule.c +++ b/submodule.c @@ -1060,7 +1060,7 @@ unsigned is_submodule_modified(const char *path, int ignore_untracked) } strbuf_reset(); - argv_array_pushl(, "status", "--porcelain", NULL); + argv_array_pushl(, "status", "--porcelain=2", NULL); if (ignore_untracked) argv_array_push(, "-uno"); @@ -1070,11 +1070,12 @@ unsigned is_submodule_modified(const char *path, int ignore_untracked) cp.out = -1; cp.dir = path; if (start_command()) - die("Could not run 'git status --porcelain' in submodule %s", path); + die("Could not run 'git status --porcelain=2' in submodule %s", path); fp = xfdopen(cp.out, "r"); while (strbuf_getwholeline(, fp, '\n') != EOF) { - if ((buf.buf[0] == '?') && (buf.buf[1] == '?')) + /* regular untracked files */ + if (buf.buf[0] == '?') dirty_submodule |= DIRTY_SUBMODULE_UNTRACKED; else dirty_submodule |= DIRTY_SUBMODULE_MODIFIED; @@ -1093,7 +1094,7 @@ unsigned is_submodule_modified(const char *path, int ignore_untracked) fclose(fp); if (finish_command() && !ignore_cp_exit_code) - die("'git status --porcelain' failed in submodule %s", path); + die("'git status --porcelain=2' failed in submodule %s", path); strbuf_release(); return dirty_submodule; -- 2.12.0.rc1.49.gdeb397943c.dirty
[PATCH 2/7] submodule.c: factor out early loop termination in is_submodule_modified
This makes it easier for a follow up patch. Signed-off-by: Stefan BellerReviewed-by: Jonathan Nieder --- submodule.c | 16 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/submodule.c b/submodule.c index 2c667ac95a..93e3fefd39 100644 --- a/submodule.c +++ b/submodule.c @@ -1075,16 +1075,16 @@ unsigned is_submodule_modified(const char *path, int ignore_untracked) len = strbuf_read(, cp.out, 1024); line = buf.buf; while (len > 2) { - if ((line[0] == '?') && (line[1] == '?')) { + if ((line[0] == '?') && (line[1] == '?')) dirty_submodule |= DIRTY_SUBMODULE_UNTRACKED; - if (dirty_submodule & DIRTY_SUBMODULE_MODIFIED) - break; - } else { + else dirty_submodule |= DIRTY_SUBMODULE_MODIFIED; - if (ignore_untracked || - (dirty_submodule & DIRTY_SUBMODULE_UNTRACKED)) - break; - } + + if ((dirty_submodule & DIRTY_SUBMODULE_MODIFIED) && + ((dirty_submodule & DIRTY_SUBMODULE_UNTRACKED) || +ignore_untracked)) + break; + next_line = strchr(line, '\n'); if (!next_line) break; -- 2.12.0.rc1.49.gdeb397943c.dirty
[PATCH 3/7] submodule.c: convert is_submodule_modified to use strbuf_getwholeline
Instead of implementing line reading yet again, make use of our beautiful library function to read one line. By using strbuf_getwholeline instead of strbuf_read, we avoid having to allocate memory for the entire child process output at once. That is, we limit maximum memory usage. Also we can start processing the output as it comes in, no need to wait for all of it. Once we know all information that we care about, we can terminate the child early. In that case we do not care about its exit code as well. By just closing our side of the pipe the child process will get a SIGPIPE signal, which it will not report nor do we report it in finish_command, ac78663b0d (run-command: don't warn on SIGPIPE deaths, 2015-12-29). Helped-by: Jonathan NiederSigned-off-by: Stefan Beller --- submodule.c | 30 ++ t/t7506-status-submodule.sh | 18 +- 2 files changed, 31 insertions(+), 17 deletions(-) diff --git a/submodule.c b/submodule.c index 93e3fefd39..e72781d9f2 100644 --- a/submodule.c +++ b/submodule.c @@ -1041,12 +1041,12 @@ int fetch_populated_submodules(const struct argv_array *options, unsigned is_submodule_modified(const char *path, int ignore_untracked) { - ssize_t len; struct child_process cp = CHILD_PROCESS_INIT; struct strbuf buf = STRBUF_INIT; + FILE *fp; unsigned dirty_submodule = 0; - const char *line, *next_line; const char *git_dir; + int ignore_cp_exit_code = 0; strbuf_addf(, "%s/.git", path); git_dir = read_gitfile(buf.buf); @@ -1072,29 +1072,27 @@ unsigned is_submodule_modified(const char *path, int ignore_untracked) if (start_command()) die("Could not run 'git status --porcelain' in submodule %s", path); - len = strbuf_read(, cp.out, 1024); - line = buf.buf; - while (len > 2) { - if ((line[0] == '?') && (line[1] == '?')) + fp = xfdopen(cp.out, "r"); + while (strbuf_getwholeline(, fp, '\n') != EOF) { + if ((buf.buf[0] == '?') && (buf.buf[1] == '?')) dirty_submodule |= DIRTY_SUBMODULE_UNTRACKED; else dirty_submodule |= DIRTY_SUBMODULE_MODIFIED; if ((dirty_submodule & DIRTY_SUBMODULE_MODIFIED) && ((dirty_submodule & DIRTY_SUBMODULE_UNTRACKED) || -ignore_untracked)) - break; - - next_line = strchr(line, '\n'); - if (!next_line) +ignore_untracked)) { + /* +* We're not interested in any further information from +* the child any more, neither output nor its exit code. +*/ + ignore_cp_exit_code = 1; break; - next_line++; - len -= (next_line - line); - line = next_line; + } } - close(cp.out); + fclose(fp); - if (finish_command()) + if (finish_command() && !ignore_cp_exit_code) die("'git status --porcelain' failed in submodule %s", path); strbuf_release(); diff --git a/t/t7506-status-submodule.sh b/t/t7506-status-submodule.sh index d31b34da83..51f8d0d034 100755 --- a/t/t7506-status-submodule.sh +++ b/t/t7506-status-submodule.sh @@ -177,8 +177,24 @@ test_expect_success 'status with added file in modified submodule with .git file test_i18ngrep "modified: sub (new commits, modified content)" output ' +test_expect_success 'status with a lot of untracked files in the submodule' ' + ( + cd sub + i=0 && + while test $i -lt 1024 + do + >some-file-$i + i=$(( $i + 1 )) + done + ) && + git status --porcelain sub 2>err.actual && + test_must_be_empty err.actual && + rm err.actual +' + test_expect_success 'rm submodule contents' ' - rm -rf sub/* sub/.git + rm -rf sub && + mkdir sub ' test_expect_success 'status clean (empty submodule dir)' ' -- 2.12.0.rc1.49.gdeb397943c.dirty
[PATCH 1/7] submodule.c: use argv_array in is_submodule_modified
struct argv_array is easier to use and maintain. Signed-off-by: Stefan BellerReviewed-by: Jonathan Nieder --- submodule.c | 10 ++ 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/submodule.c b/submodule.c index 3200b7bb2b..2c667ac95a 100644 --- a/submodule.c +++ b/submodule.c @@ -1043,12 +1043,6 @@ unsigned is_submodule_modified(const char *path, int ignore_untracked) { ssize_t len; struct child_process cp = CHILD_PROCESS_INIT; - const char *argv[] = { - "status", - "--porcelain", - NULL, - NULL, - }; struct strbuf buf = STRBUF_INIT; unsigned dirty_submodule = 0; const char *line, *next_line; @@ -1066,10 +1060,10 @@ unsigned is_submodule_modified(const char *path, int ignore_untracked) } strbuf_reset(); + argv_array_pushl(, "status", "--porcelain", NULL); if (ignore_untracked) - argv[2] = "-uno"; + argv_array_push(, "-uno"); - cp.argv = argv; prepare_submodule_repo_env(_array); cp.git_cmd = 1; cp.no_stdin = 1; -- 2.12.0.rc1.49.gdeb397943c.dirty
[PATCH 6/7] short status: improve reporting for submodule changes
If I add an untracked file to a submodule or modify a tracked file, currently "git status --short" treats the change in the same way as changes to the current HEAD of the submodule: $ git clone --quiet --recurse-submodules https://gerrit.googlesource.com/gerrit $ echo hello >gerrit/plugins/replication/stray-file $ sed -i -e 's/.*//' gerrit/plugins/replication/.mailmap $ git -C gerrit status --short M plugins/replication This is by analogy with ordinary files, where "M" represents a change that has not been added yet to the index. But this change cannot be added to the index without entering the submodule, "git add"-ing it, and running "git commit", so the analogy is counterproductive. Introduce new status letters " ?" and " m" for this. These are similar to the existing "??" and " M" but mean that the submodule (not the parent project) has new untracked files and modified files, respectively. The user can use "git add" and "git commit" from within the submodule to add them. Changes to the submodule's HEAD commit can be recorded in the index with a plain "git add -u" and are shown with " M", like today. To avoid excessive clutter, show at most one of " ?", " m", and " M" for the submodule. They represent increasing levels of change --- the last one that applies is shown (e.g., " m" if there are both modified files and untracked files in the submodule, or " M" if the submodule's HEAD has been modified and it has untracked files). While making these changes, we need to make sure to not break porcelain level 1, which shares code with "status --short". We only change "git status --short". Non-short "git status" and "git status --porcelain=2" already handle these cases by showing more detail: $ git -C gerrit status --porcelain=2 1 .M S.MU 16 16 16 305c864db28eb0c77c8499bc04c87de3f849cf3c 305c864db28eb0c77c8499bc04c87de3f849cf3c plugins/replication $ git -C gerrit status [...] modified: plugins/replication (modified content, untracked content) Scripts caring about these distinctions should use --porcelain=2. Helped-by: Jonathan NiederSigned-off-by: Stefan Beller Reviewed-by: Jonathan Nieder --- Documentation/git-status.txt | 9 +++ t/t3600-rm.sh| 18 ++ t/t7506-status-submodule.sh | 57 wt-status.c | 17 +++-- 4 files changed, 94 insertions(+), 7 deletions(-) diff --git a/Documentation/git-status.txt b/Documentation/git-status.txt index ba873657cf..01b457c322 100644 --- a/Documentation/git-status.txt +++ b/Documentation/git-status.txt @@ -181,6 +181,13 @@ in which case `XY` are `!!`. ! !ignored - +Submodules have more state and instead report + Mthe submodule has a different HEAD than +recorded in the index + mthe submodule has modified content + ?the submodule has untracked files + + If -b is used the short-format status is preceded by a line ## branchname tracking info @@ -210,6 +217,8 @@ field from the first filename). Third, filenames containing special characters are not specially formatted; no quoting or backslash-escaping is performed. +Any submodule changes are reported as modified `M` instead of `m` or single `?`. + Porcelain Format Version 2 ~~ diff --git a/t/t3600-rm.sh b/t/t3600-rm.sh index 5aa6db584c..a6e5c5bd56 100755 --- a/t/t3600-rm.sh +++ b/t/t3600-rm.sh @@ -268,6 +268,14 @@ cat >expect.modified actual && @@ -436,7 +444,7 @@ test_expect_success 'rm of a populated submodule with untracked files fails unle test -d submod && test -f submod/.git && git status -s -uno --ignore-submodules=none >actual && - test_cmp expect.modified actual && + test_cmp expect.modified_untracked actual && git rm -f submod && test ! -d submod && git status -s -uno --ignore-submodules=none >actual && @@ -621,7 +629,7 @@ test_expect_success 'rm of a populated nested submodule with different nested HE test -d submod && test -f submod/.git && git status -s -uno --ignore-submodules=none >actual && - test_cmp expect.modified actual && + test_cmp expect.modified_inside actual && git rm -f submod && test ! -d submod && git status -s -uno --ignore-submodules=none >actual && @@ -636,7 +644,7 @@ test_expect_success 'rm of a populated nested submodule with nested modification
[PATCH 5/7] submodule.c: stricter checking for submodules in is_submodule_modified
By having a stricter check in the superproject we catch errors earlier, instead of spawning a child process to tell us. Reviewed-by: Jonathan NiederSigned-off-by: Stefan Beller --- submodule.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/submodule.c b/submodule.c index 5865795b9f..fa21c7bb72 100644 --- a/submodule.c +++ b/submodule.c @@ -1052,11 +1052,12 @@ unsigned is_submodule_modified(const char *path, int ignore_untracked) git_dir = read_gitfile(buf.buf); if (!git_dir) git_dir = buf.buf; - if (!is_directory(git_dir)) { + if (!is_git_directory(git_dir)) { + if (is_directory(git_dir)) + die(_("'%s' not recognized as a git repository"), git_dir); strbuf_release(); /* The submodule is not checked out, so it is not modified */ return 0; - } strbuf_reset(); -- 2.12.0.rc1.49.gdeb397943c.dirty
Re: [PATCH 7/7] submodule.c: correctly handle nested submodules in is_submodule_modified
On Fri, Mar 24, 2017 at 4:31 PM, Jonathan Niederwrote: > > Can this overflow the buffer? Submodule state is supposed to be 4 > characters, so could do > > /* > * T XY : > * T = line type, XY = status, = submodule state > */ > if (buf.len < 1 + 1 + 2 + 1 + 4) > die("BUG: invalid status --porcelain=2 line > %s", > buf.buf); > > if (buf.buf[5] == 'S' && buf.buf[8] == 'U') > /* untracked file */ > dirty_submodule |= DIRTY_SUBMODULE_UNTRACKED; > > if (memcmp(buf.buf + 5, "S..U", 4)) > /* other change */ > dirty_submodule |= DIRTY_SUBMODULE_MODIFIED; good idea, will use. > } > >> + /* nested submodule handling */ >> + if (buf.buf[6] == 'C' || buf.buf[7] == 'M') >> + dirty_submodule |= >> DIRTY_SUBMODULE_MODIFIED; >> + if (buf.buf[8] == 'U') >> + dirty_submodule |= >> DIRTY_SUBMODULE_UNTRACKED; >> + } else >> + dirty_submodule |= DIRTY_SUBMODULE_MODIFIED; >> + } > > I get lost in these cases. What does it mean if we see S..., for > example? That means there is a submodule with no new commits, no modified files and no untracked files. ("Why did we even output this?", oh because of it is in either 2 (moved) or because the hashes are different, i.e. we already added the new HEAD of the submodule) > > Some tests covering these cases with --porcelain=2 and a brief mention > in documentation may help. ok, will do.
Re: [PATCH 3/7] submodule.c: convert is_submodule_modified to use strbuf_getwholeline
On Fri, Mar 24, 2017 at 3:38 PM, Jonathan Niederwrote: > It also overlaps work a little better. mentioned >> Once we know all information that we care about, we can terminate >> the child early. In that case we do not care about its exit code as well. > > Should this say something about SIGPIPE? done > language nit: s/, no output/: neither output/ done > wait_or_whine(cp->pid, cp->argv[0], 1) doesn't do that but is meant for > signal handling. Maybe we should rely on SIGPIPE instead (which > wait_or_whine always silences) and avoid the kill() call. done > Can there be a test for this case (i.e. having lots of untracked files > in the submodule so the child process fills its pipe buffer and has to > exit early)? done
Re: [PATCH v2 2/3] sequencer: make commit options more extensible
Hi Junio, On Thu, 23 Mar 2017, Junio C Hamano wrote: > Johannes Schindelinwrites: > > > @@ -926,14 +930,14 @@ static void record_in_rewritten(struct object_id *oid, > > static int do_pick_commit(enum todo_command command, struct commit *commit, > > struct replay_opts *opts, int final_fixup) > > { > > - int edit = opts->edit, cleanup_commit_message = 0; > > - const char *msg_file = edit ? NULL : git_path_merge_msg(); > > + unsigned int flags = opts->edit ? EDIT_MSG : 0, allow = 0; > > + const char *msg_file = opts->edit ? NULL : git_path_merge_msg(); > > unsigned char head[20]; > > struct commit *base, *next, *parent; > > const char *base_label, *next_label; > > struct commit_message msg = { NULL, NULL, NULL, NULL }; > > struct strbuf msgbuf = STRBUF_INIT; > > - int res, unborn = 0, amend = 0, allow = 0; > > + int res, unborn = 0; > > ... > > @@ -1123,11 +1127,11 @@ static int do_pick_commit(enum todo_command > > command, struct commit *commit, > > if (allow < 0) { > > res = allow; > > goto leave; > > - } > > + } else if (allow) > > + flags |= ALLOW_EMPTY; > > Making "flags" unsigned was a correct change, but this is now wrong, > as "allow" is made unsigned by accident. Right. Bummer. > Perhaps something like this needs to be squashed in? > > sequencer.c | 4 ++-- > 1 file changed, 2 insertions(+), 2 deletions(-) > > diff --git a/sequencer.c b/sequencer.c > index bc2fe48e65..6c423566e6 100644 > --- a/sequencer.c > +++ b/sequencer.c > @@ -932,14 +932,14 @@ static void record_in_rewritten(struct object_id *oid, > static int do_pick_commit(enum todo_command command, struct commit *commit, > struct replay_opts *opts, int final_fixup) > { > - unsigned int flags = opts->edit ? EDIT_MSG : 0, allow = 0; > + unsigned int flags = opts->edit ? EDIT_MSG : 0; > const char *msg_file = opts->edit ? NULL : git_path_merge_msg(); > unsigned char head[20]; > struct commit *base, *next, *parent; > const char *base_label, *next_label; > struct commit_message msg = { NULL, NULL, NULL, NULL }; > struct strbuf msgbuf = STRBUF_INIT; > - int res, unborn = 0; > + int allow, res, unborn = 0; I had originally moved it from there, to stay with the related flags, but I should just have left it there. Your patch looks good, you could do even better by reverting that move (IIRC it was at the end of the line, and it was set to 0 by default). Ciao, Dscho
Re: What's cooking in git.git (Mar 2017, #10; Fri, 24)
On 03/24, Junio C Hamano wrote: > * bw/recurse-submodules-relative-fix (2017-03-17) 5 commits > - ls-files: fix bug when recursing with relative pathspec > - ls-files: fix typo in variable name > - grep: fix bug when recursing with relative pathspec > - setup: allow for prefix to be passed to git commands > - grep: fix help text typo > > A few commands that recently learned the "--recurse-submodule" > option misbehaved when started from a subdirectory of the > superproject. Anything more you think needs to be done about this? I noticed that Dscho's config series hit master so I could rebase against that (as there is a small conflict). Aside from that it didn't seem like there were many complaints with the proposed fix. -- Brandon Williams
Will OpenSSL's license change impact us?
They're changing their license[1] to Apache 2 which unlike the current fuzzy compatibility with the current license[2] is explicitly incompatible with GPLv2[3]. We use OpenSSL for SHA1 by default unless NO_OPENSSL=YesPlease. This still hasn't happened, but given the lifetime of git versions packaged up by distros knowing sooner than later if this is going to be a practical problem would be good. If so perhaps we could copy the relevant subset of the code int our tree, or libressl's, or improve block-sha1. We also use OpenSSL for git-imap-send, AFAICT with no fallback other than "don't use ssl" or "use stunnel". 1. https://www.openssl.org/blog/blog/2017/03/20/license/ 2. https://www.openssl.org/docs/faq.html#LEGAL2 3. https://www.apache.org/licenses/GPL-compatibility.html
Re: [PATCH v1] travis-ci: build and test Git on Windows
Hi Peff, On Thu, 23 Mar 2017, Jeff King wrote: > My pattern is particularly spiky from Travis's perspective, because once > a day I rebase everything on top of master and push them the whole thing > in a bunch. So they 75 branches, all at once. That seems like it would > be ripe for throttling (though I would much rather they just queue the > builds and do them one at a time). Travis is optimized for Continuous Integration, i.e. one or maybe two integration branches that merge PRs every once in a while. What we would need is Continuous Testing, really, because we do not do Continuous Integration at all. On the point of the sekrit variable: all I tried to do is to avoid overwhelming the (currently) single VM with plenty of jobs. If the build & test would not take so darned long on Windows due to going in and out of the POSIX emulation layer a gazillion times (caused by intense shell scripting), the tests could be faster. But that would require a massive amount of work, and I simply have too much on my plate to take that task on in addition. If you have an idea how to prevent the overloading of the VM by any means that does not involve that token, please tell me. Ciao, Dscho
Re: [PATCH 7/7] submodule.c: correctly handle nested submodules in is_submodule_modified
Stefan Beller wrote: > When a nested submodule has untracked files, it would be reported as > "modified submodule" in the superproject, because submodules are not > parsed correctly in is_submodule_modified as they are bucketed into > the modified pile as "they are not an untracked file". > > Signed-off-by: Stefan Beller> --- > submodule.c | 16 ++-- > t/t3600-rm.sh | 2 +- > t/t7506-status-submodule.sh | 2 +- > 3 files changed, 16 insertions(+), 4 deletions(-) > > diff --git a/submodule.c b/submodule.c > index 467f1de763..ec7e9b1b06 100644 > --- a/submodule.c > +++ b/submodule.c > @@ -1078,8 +1078,20 @@ unsigned is_submodule_modified(const char *path, int > ignore_untracked) > /* regular untracked files */ > if (buf.buf[0] == '?') > dirty_submodule |= DIRTY_SUBMODULE_UNTRACKED; > - else > - dirty_submodule |= DIRTY_SUBMODULE_MODIFIED; > + > + /* regular unmerged and renamed files */ > + if (buf.buf[0] == 'u' || > + buf.buf[0] == '1' || > + buf.buf[0] == '2') { > + if (buf.buf[5] == 'S') { Can this overflow the buffer? Submodule state is supposed to be 4 characters, so could do /* * T XY : * T = line type, XY = status, = submodule state */ if (buf.len < 1 + 1 + 2 + 1 + 4) die("BUG: invalid status --porcelain=2 line %s", buf.buf); if (buf.buf[5] == 'S' && buf.buf[8] == 'U') /* untracked file */ dirty_submodule |= DIRTY_SUBMODULE_UNTRACKED; if (memcmp(buf.buf + 5, "S..U", 4)) /* other change */ dirty_submodule |= DIRTY_SUBMODULE_MODIFIED; } > + /* nested submodule handling */ > + if (buf.buf[6] == 'C' || buf.buf[7] == 'M') > + dirty_submodule |= > DIRTY_SUBMODULE_MODIFIED; > + if (buf.buf[8] == 'U') > + dirty_submodule |= > DIRTY_SUBMODULE_UNTRACKED; > + } else > + dirty_submodule |= DIRTY_SUBMODULE_MODIFIED; > + } I get lost in these cases. What does it mean if we see S..., for example? As an example, if I am understanding correctly, before this patch, if I have a submodule-in-submodule: $ find . -name .git .git sub/.git sub/subsub/.git and I put a stray file in the sub-sub module: $ echo stray-file >sub/subsub/x.o then status --porcelain=2 tells me that sub is modified: $ git status --porcelain=2 1 .M S.M. [...] sub What should it say after the patch? Is the XY field ".." or ".M"? Some tests covering these cases with --porcelain=2 and a brief mention in documentation may help. Thanks, Jonathan diff --git i/submodule.c w/submodule.c index ec7e9b1b06..aec1b2cdca 100644 --- i/submodule.c +++ w/submodule.c @@ -1083,13 +1083,18 @@ unsigned is_submodule_modified(const char *path, int ignore_untracked) if (buf.buf[0] == 'u' || buf.buf[0] == '1' || buf.buf[0] == '2') { - if (buf.buf[5] == 'S') { - /* nested submodule handling */ - if (buf.buf[6] == 'C' || buf.buf[7] == 'M') - dirty_submodule |= DIRTY_SUBMODULE_MODIFIED; - if (buf.buf[8] == 'U') - dirty_submodule |= DIRTY_SUBMODULE_UNTRACKED; - } else + /* +* T XY : +* T = line type, XY = status, = submodule state +*/ + if (buf.len < 1 + 1 + 2 + 1 + 4) + die("BUG: invalid status --porcelain=2 line %s", + buf.buf); + if (buf.buf[5] == 'S' && buf.buf[8] == 'U') + /* untracked file */ + dirty_submodule |= DIRTY_SUBMODULE_UNTRACKED; + if (memcmp(buf.buf + 5, "S..U", 4)) + /* other change */ dirty_submodule |= DIRTY_SUBMODULE_MODIFIED; }
[PATCH 6/7] mingw: enable DC_AND_OPENSSL_SHA1 by default
Signed-off-by: Johannes Schindelin--- config.mak.uname | 1 + 1 file changed, 1 insertion(+) diff --git a/config.mak.uname b/config.mak.uname index 399fe192719..a16e9ef0551 100644 --- a/config.mak.uname +++ b/config.mak.uname @@ -552,6 +552,7 @@ else USE_LIBPCRE= YesPlease NO_CURL = USE_NED_ALLOCATOR = YesPlease + DC_AND_OPENSSL_SHA1 = YesPlease else COMPAT_CFLAGS += -D__USE_MINGW_ANSI_STDIO NO_CURL = YesPlease -- 2.12.1.windows.1
[PATCH 7/7] p0013: new test to compare SHA1DC vs OpenSSL
To demonstrate the need for the core.enableSHA1DC knob, this test compares the performance of the SHA-1 algorithms with collision detection vs OpenSSL's (that does not detect attempted collision attacks). The payload size of 300MB was actually not concocted from thin air, but is based on the massive Windows monorepo, whose index file weighs in with roughly that size (and which is SHA-1'ed upon every single read and write). On this developer's machine, this comparison shows a hefty difference: 0013.1: calculate SHA-1 for 300MB (SHA1DC)3.03(0.03+0.17) 0013.2: calculate SHA-1 for 300MB (OpenSSL) 0.58(0.06+0.16) It is not only that ~6x slower performance is a pretty tall order, the absolute numbers themselves speak a very clear language: having to wait one second every time a file is `git add`ed is noticeable, but one can handwave it away. Having to wait six seconds (3 to read the index, a fraction of a millisecond to hash the new contents and update the in-memory index, then 3 seconds to write out the index) is outright annoying. And unnecessary, too: the content of the index is never crafted to cause SHA-1 collisions. Obviously, this test requires that Git was built with the new DC_AND_OPENSSL_SHA1 make flag; it is skipped otherwise. Signed-off-by: Johannes Schindelin--- t/perf/p0013-sha1dc.sh | 23 +++ 1 file changed, 23 insertions(+) create mode 100644 t/perf/p0013-sha1dc.sh diff --git a/t/perf/p0013-sha1dc.sh b/t/perf/p0013-sha1dc.sh new file mode 100644 index 000..e08473ac969 --- /dev/null +++ b/t/perf/p0013-sha1dc.sh @@ -0,0 +1,23 @@ +#!/bin/sh + +test_description="Tests performance of SHA1DC vs OpenSSL" + +. ./perf-lib.sh + +test -n "$DC_AND_OPENSSL_SHA1" || { + skip_all='DC_AND_OPENSSL_SHA1 required for this test' + test_done +} + +test_perf 'calculate SHA-1 for 300MB (SHA1DC)' ' + dd if=/dev/zero bs=1M count=300 | + test-sha1 +' + +test_perf 'calculate SHA-1 for 300MB (OpenSSL)' ' + dd if=/dev/zero bs=1M count=300 | + test-sha1 --disable-sha1dc +' + +test_done + -- 2.12.1.windows.1
Re: What's cooking in git.git (Mar 2017, #10; Fri, 24)
On Fri, Mar 24, 2017 at 10:21 PM, Junio C Hamanowrote: > * ab/test-readme-updates (2017-03-23) 4 commits > - SQUASH??? > - t/README: clarify the test_have_prereq documentation > - t/README: change "Inside part" to "Inside the part" > - t/README: link to metacpan.org, not search.cpan.org > > Doc updates. > > Waiting for a reaction to SQUASH??? Sorry about the late reply. That squash looks good to me, please squash it in. > * ab/doc-submitting (2017-03-21) 3 commits > - SQUASH??? remove "alias" thing > - doc/SubmittingPatches: show how to get a CLI commit summary > - doc/SubmittingPatches: clarify the casing convention for "area: change..." > > Doc update. > > Any further comments? Squashing that in looks good. > * ab/ref-filter-no-contains (2017-03-24) 16 commits > - tag: add tests for --with and --without > - ref-filter: reflow recently changed branch/tag/for-each-ref docs > - ref-filter: add --no-contains option to tag/branch/for-each-ref > - tag: change --point-at to default to HEAD > - tag: implicitly supply --list given another list-like option > - tag: change misleading --list documentation > - parse-options: add OPT_NONEG to the "contains" option > - tag: add more incompatibles mode tests > - for-each-ref: partly change to in help > - tag tests: fix a typo in a test description > - tag: remove a TODO item from the test suite > - ref-filter: add test for --contains on a non-commit > - ref-filter: make combining --merged & --no-merged an error > - tag doc: reword --[no-]merged to talk about commits, not tips > - tag doc: split up the --[no-]merged documentation > - tag doc: move the description of --[no-]merged earlier > > "git tag/branch/for-each-ref" family of commands long allowed to > filter the refs by "--contains X" (show only the refs that are > descendants of X), "--merged X" (show only the refs that are > ancestors of X), "--no-merged X" (show only the refs that are not > ancestors of X). One curious omission, "--no-contains X" (show > only the refs that are not descendants of X) has been added to > them. > > This looks ready for 'next'. Any comments? Looks good to me, although I would say that wouldn't I? :)
[PATCH 2/7] Makefile: optionally compile with both SHA1DC and SHA1_OPENSSL
Nowadays, there are practical collision attacks on the SHA-1 algorithm. For that reason, Git integrated code that detects attempts to sneak in objects using those known attack vectors and enabled it by default. The collision detection is not for free, though: when using the SHA1DC code, calculating the SHA-1 takes substantially longer than using OpenSSL's (in some case hardware-accelerated) SHA1-routines, and this happens even when switching off the collision detection in SHA1DC's code. Therefore, it makes sense to limit the use of the collision-detecting SHA1DC to the cases where objects are introduced from any outside source, and use the fast OpenSSL code instead when working on implicitly trusted data (such as when the user calls `git add`). This patch introduces the DC_AND_OPENSSL_SHA1 Makefile knob to compile with both SHA1DC and OpenSSL's SHA-1 routines, defaulting to SHA1DC. A later patch will add the ability to switch between them. Signed-off-by: Johannes Schindelin--- Makefile | 12 hash.h| 2 +- sha1dc/sha1.c | 21 + sha1dc/sha1.h | 16 4 files changed, 50 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 9f8b35ad41f..3e181d2f0e2 100644 --- a/Makefile +++ b/Makefile @@ -147,6 +147,11 @@ all:: # Define OPENSSL_SHA1 environment variable when running make to link # with the SHA1 routine from openssl library. # +# Define DC_AND_OPENSSL_SHA1 environment variable when running make to use +# the collision-detecting sha1 algorithm by default, configurable via the +# core.enableSHA1DC setting, falling back to OpenSSL's faster algorithm when +# the collision detection is disabled. +# # Define SHA1_MAX_BLOCK_SIZE to limit the amount of data that will be hashed # in one call to the platform's SHA1_Update(). e.g. APPLE_COMMON_CRYPTO # wants 'SHA1_MAX_BLOCK_SIZE=1024L*1024L*1024L' defined. @@ -1391,6 +1396,12 @@ ifdef APPLE_COMMON_CRYPTO SHA1_MAX_BLOCK_SIZE = 1024L*1024L*1024L endif +ifdef DC_AND_OPENSSL_SHA1 + EXTLIBS += $(LIB_4_CRYPTO) + LIB_OBJS += sha1dc/sha1.o + LIB_OBJS += sha1dc/ubc_check.o + BASIC_CFLAGS += -DSHA1_DC_AND_OPENSSL +else ifdef OPENSSL_SHA1 EXTLIBS += $(LIB_4_CRYPTO) BASIC_CFLAGS += -DSHA1_OPENSSL @@ -1415,6 +1426,7 @@ endif endif endif endif +endif ifdef SHA1_MAX_BLOCK_SIZE LIB_OBJS += compat/sha1-chunked.o diff --git a/hash.h b/hash.h index a11fc9233fc..3a09343270d 100644 --- a/hash.h +++ b/hash.h @@ -7,7 +7,7 @@ #include #elif defined(SHA1_OPENSSL) #include -#elif defined(SHA1_DC) +#elif defined(SHA1_DC) || defined(SHA1_DC_AND_OPENSSL) #include "sha1dc/sha1.h" #else /* SHA1_BLK */ #include "block-sha1/sha1.h" diff --git a/sha1dc/sha1.c b/sha1dc/sha1.c index d99db4f2e1b..e6bcf0ffa86 100644 --- a/sha1dc/sha1.c +++ b/sha1dc/sha1.c @@ -1806,3 +1806,24 @@ void git_SHA1DCUpdate(SHA1_CTX *ctx, const void *vdata, unsigned long len) } SHA1DCUpdate(ctx, data, len); } + +#ifdef SHA1_DC_AND_OPENSSL +void (*SHA1_Init_func)(SHA_CTX_union *ctx) = (void *)SHA1DCInit; +void (*SHA1_Update_func)(SHA_CTX_union *ctx, const void *pointer, size_t size) = + (void *)git_SHA1DCUpdate; +int (*SHA1_Final_func)(unsigned char sha1[20], SHA_CTX_union *ctx) = + (void *)git_SHA1DCFinal; + +void toggle_sha1dc(int enable) +{ + if (enable) { + SHA1_Init_func = (void *)SHA1DCInit; + SHA1_Update_func = (void *)git_SHA1DCUpdate; + SHA1_Final_func = (void *)git_SHA1DCFinal; + } else { + SHA1_Init_func = (void *)SHA1_Init; + SHA1_Update_func = (void *)SHA1_Update; + SHA1_Final_func = (void *)SHA1_Final; + } +} +#endif diff --git a/sha1dc/sha1.h b/sha1dc/sha1.h index bd8bd928fb3..243c2fe0b6b 100644 --- a/sha1dc/sha1.h +++ b/sha1dc/sha1.h @@ -110,10 +110,26 @@ void git_SHA1DCFinal(unsigned char [20], SHA1_CTX *); */ void git_SHA1DCUpdate(SHA1_CTX *ctx, const void *data, unsigned long len); +#ifdef SHA1_DC_AND_OPENSSL +extern void toggle_sha1dc(int enable); + +typedef union { + SHA1_CTX dc; + SHA_CTX openssl; +} SHA_CTX_union; +extern void (*SHA1_Init_func)(SHA_CTX_union *ctx); +extern void (*SHA1_Update_func)(SHA_CTX_union *ctx, const void *data, size_t len); +extern int (*SHA1_Final_func)(unsigned char sha1[20], SHA_CTX_union *ctx); +#define platform_SHA_CTX SHA_CTX_union +#define platform_SHA1_Init SHA1_Init_func +#define platform_SHA1_Update SHA1_Update_func +#define platform_SHA1_Final SHA1_Final_func +#else #define platform_SHA_CTX SHA1_CTX #define platform_SHA1_Init SHA1DCInit #define platform_SHA1_Update git_SHA1DCUpdate #define platform_SHA1_Final git_SHA1DCFinal +#endif #if defined(__cplusplus) } -- 2.12.1.windows.1
[PATCH 1/7] sha1dc: safeguard against outside definitions of BIGENDIAN
In sha1dc/sha1.c, we #define BIGENDIAN under certain circumstances, and obviously leave the door open for scenarios where our conditions do not catch and that constant is #defined elsewhere. However, we did not expect that anybody would possibly #define BIGENDIAN to 0, indicating that the current platform is *not* big endian. This is not just a theoretical consideration: On Windows, the winsock2.h header file (which is used to allow Git to communicate via network) does indeed do this. Let's test for that circumstance, too, and byte-swap as intended in that case. This fixes a massive breakage on Windows where current `pu` (having switched on DC_SHA1 by default) breaks pretty much every single test case. Signed-off-by: Johannes Schindelin--- sha1dc/sha1.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sha1dc/sha1.c b/sha1dc/sha1.c index 6dd0da36084..d99db4f2e1b 100644 --- a/sha1dc/sha1.c +++ b/sha1dc/sha1.c @@ -35,7 +35,7 @@ #define sha1_mix(W, t) (rotate_left(W[t - 3] ^ W[t - 8] ^ W[t - 14] ^ W[t - 16], 1)) -#if defined(BIGENDIAN) +#if defined(BIGENDIAN) && BIGENDIAN != 0 #define sha1_load(m, t, temp) { temp = m[t]; } #else #define sha1_load(m, t, temp) { temp = m[t]; sha1_bswap32(temp); } -- 2.12.1.windows.1
[PATCH 5/7] t0013: test DC_AND_OPENSSL_SHA1, too
Signed-off-by: Johannes Schindelin--- Makefile | 1 + t/helper/test-sha1.c | 10 ++ t/t0013-sha1dc.sh| 10 ++ 3 files changed, 21 insertions(+) diff --git a/Makefile b/Makefile index 3e181d2f0e2..0b581357625 100644 --- a/Makefile +++ b/Makefile @@ -2251,6 +2251,7 @@ GIT-BUILD-OPTIONS: FORCE @echo NO_UNIX_SOCKETS=\''$(subst ','\'',$(subst ','\'',$(NO_UNIX_SOCKETS)))'\' >>$@+ @echo PAGER_ENV=\''$(subst ','\'',$(subst ','\'',$(PAGER_ENV)))'\' >>$@+ @echo DC_SHA1=\''$(subst ','\'',$(subst ','\'',$(DC_SHA1)))'\' >>$@+ + @echo DC_AND_OPENSSL_SHA1=\''$(subst ','\'',$(subst ','\'',$(DC_AND_OPENSSL_SHA1)))'\' >>$@+ ifdef TEST_OUTPUT_DIRECTORY @echo TEST_OUTPUT_DIRECTORY=\''$(subst ','\'',$(subst ','\'',$(TEST_OUTPUT_DIRECTORY)))'\' >>$@+ endif diff --git a/t/helper/test-sha1.c b/t/helper/test-sha1.c index a1c13f54eca..27ce8869e51 100644 --- a/t/helper/test-sha1.c +++ b/t/helper/test-sha1.c @@ -8,6 +8,16 @@ int cmd_main(int ac, const char **av) int binary = 0; char *buffer; + if (ac > 1 && !strcmp(av[1], "--disable-sha1dc")) { +#ifdef SHA1_DC_AND_OPENSSL + toggle_sha1dc(0); +#else + die("Not compiled with DC_AND_OPENSSL_SHA1"); +#endif + ac--; + av++; + } + if (ac == 2) { if (!strcmp(av[1], "-b")) binary = 1; diff --git a/t/t0013-sha1dc.sh b/t/t0013-sha1dc.sh index 435a96d6108..2b529b31b4e 100755 --- a/t/t0013-sha1dc.sh +++ b/t/t0013-sha1dc.sh @@ -5,6 +5,10 @@ test_description='test sha1 collision detection' TEST_DATA="$TEST_DIRECTORY/t0013" test -z "$DC_SHA1" || test_set_prereq DC_SHA1 +test -z "$DC_AND_OPENSSL_SHA1" || { + test_set_prereq DC_AND_OPENSSL_SHA1 + test_set_prereq DC_SHA1 +} test_expect_success DC_SHA1 'test-sha1 detects shattered pdf' ' test_must_fail test-sha1 <"$TEST_DATA/shattered-1.pdf" 2>err && @@ -12,4 +16,10 @@ test_expect_success DC_SHA1 'test-sha1 detects shattered pdf' ' grep 38762cf7f55934b34d179ae6a4c80cadccbb7f0a err ' +test_expect_success DC_AND_OPENSSL_SHA1 'sha1dc can be turned off' ' + test-sha1 --disable-sha1dc <"$TEST_DATA/shattered-1.pdf" 2>err && + ! test_i18ngrep collision err && + ! grep 38762cf7f55934b34d179ae6a4c80cadccbb7f0a err +' + test_done -- 2.12.1.windows.1
[PATCH 3/7] config: add the core.enablesha1dc setting
When compiled with DC_AND_OPENSSL_SHA1, this new config setting allows to switch from the collision-detecting SHA-1 routines (SHA1DC) to the noticeably faster OpenSSL ones. The default is still to detect collisions. Signed-off-by: Johannes Schindelin--- config.c | 8 1 file changed, 8 insertions(+) diff --git a/config.c b/config.c index 1a4d85537b3..f94e2963e57 100644 --- a/config.c +++ b/config.c @@ -1205,6 +1205,14 @@ static int git_default_core_config(const char *var, const char *value) return 0; } + if (!strcmp(var, "core.enablesha1dc")) { +#ifdef DC_AND_OPENSSL_SHA1 + toggle_sha1dc(git_config_bool(var, value)); +#else + warning("Ignoring core.enablesha1dc='%s'", value); +#endif + } + /* Add other config variables here and to Documentation/config.txt. */ return 0; } -- 2.12.1.windows.1
[PATCH 4/7] t0013: do not skip the entire file wholesale without DC_SHA1
So far, there is only one test case in that script, and that case indeed requires that the code was compiled with with the DC_SHA1 flag. However, we are about to add another test case to verify that the DC_AND_OPENSSL_SHA1 flag works correctly, too. So let's refactor the code a little. Signed-off-by: Johannes Schindelin--- t/t0013-sha1dc.sh | 8 ++-- 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/t/t0013-sha1dc.sh b/t/t0013-sha1dc.sh index 6d655cb161b..435a96d6108 100755 --- a/t/t0013-sha1dc.sh +++ b/t/t0013-sha1dc.sh @@ -4,13 +4,9 @@ test_description='test sha1 collision detection' . ./test-lib.sh TEST_DATA="$TEST_DIRECTORY/t0013" -if test -z "$DC_SHA1" -then - skip_all='skipping sha1 collision tests, DC_SHA1 not set' - test_done -fi +test -z "$DC_SHA1" || test_set_prereq DC_SHA1 -test_expect_success 'test-sha1 detects shattered pdf' ' +test_expect_success DC_SHA1 'test-sha1 detects shattered pdf' ' test_must_fail test-sha1 <"$TEST_DATA/shattered-1.pdf" 2>err && test_i18ngrep collision err && grep 38762cf7f55934b34d179ae6a4c80cadccbb7f0a err -- 2.12.1.windows.1
[PATCH 0/7] PREVIEW: Introduce DC_AND_OPENSSL_SHA1 make flag
As I pointed out several times in the past, the performance hit of enabling SHA1DC globally is not acceptable. This patch series not only demonstrates that clearly in the perf test it adds (it is the last patch in the current series, and its commit message has some numbers), it also shows an early glimpse of what I will be proposing to fix the situation. Obviously, this patch series is not complete yet: - the first patch is an obvious bug fix that I sent out separately, but it is needed to unbreak almost all tests on Windows. - the most important part will be the patch turning core.enableSHA1DC into a tristate: "externalOnly" or "smart" or "auto" or something indicating that it switches on collision detection only for commands that accept objects from an outside source into the local repository, such as fetch, fast-import, etc Johannes Schindelin (7): sha1dc: safeguard against outside definitions of BIGENDIAN Makefile: optionally compile with both SHA1DC and SHA1_OPENSSL config: add the core.enablesha1dc setting t0013: do not skip the entire file wholesale without DC_SHA1 t0013: test DC_AND_OPENSSL_SHA1, too mingw: enable DC_AND_OPENSSL_SHA1 by default p0013: new test to compare SHA1DC vs OpenSSL Makefile | 13 + config.c | 8 config.mak.uname | 1 + hash.h | 2 +- sha1dc/sha1.c | 23 ++- sha1dc/sha1.h | 16 t/helper/test-sha1.c | 10 ++ t/perf/p0013-sha1dc.sh | 23 +++ t/t0013-sha1dc.sh | 18 -- 9 files changed, 106 insertions(+), 8 deletions(-) create mode 100644 t/perf/p0013-sha1dc.sh base-commit: 063fe858b89ef8ee27965115fd6b1ed12e42e793 Published-As: https://github.com/dscho/git/releases/tag/sha1dc-knob-v1 Fetch-It-Via: git fetch https://github.com/dscho/git sha1dc-knob-v1 -- 2.12.1.windows.1
[PATCH/RFC] parse-options: add facility to make options configurable
Add a nascent WIP facility to specify via the options parsing that we'd e.g. like to grab the --status option for commit.status from the commit.status config key. This is all very proof-of-concept, and uses the ugly hack of s/const // for the options struct because I'm now keeping state in it, as noted in one of the TODO comments that should be moved. But even so this works, passes all tests, gets rid of 3 lines in commit.c, and has the promise of getting rid of a *lot* more manual option parsing in favor of declaring config keys via OPT_* everywhere. See myfor more details. Signed-off-by: Ævar Arnfjörð Bjarmason --- On Sun, Mar 19, 2017 at 2:43 PM, Ævar Arnfjörð Bjarmason wrote: > I don't know if this is what Duy has in mind, but the facility I've > described is purely an internal code reorganization issue. I.e. us > not having to write custom code for each bultin every time we want to > take an option from the command line || config. Here's an implementation of this I hacked up this evening. This is very WIP as noted in the commit message / TODO comments, but it works! I thought I'd send it to the list for comments on the general approach before taking it much further. builtin/commit.c | 7 ++- parse-options-cb.c | 21 + parse-options.c| 40 parse-options.h| 16 +--- 4 files changed, 72 insertions(+), 12 deletions(-) diff --git a/builtin/commit.c b/builtin/commit.c index 4e288bc513..a7c9e4128f 100644 --- a/builtin/commit.c +++ b/builtin/commit.c @@ -1500,10 +1500,6 @@ static int git_commit_config(const char *k, const char *v, void *cb) if (!strcmp(k, "commit.template")) return git_config_pathname(_file, k, v); - if (!strcmp(k, "commit.status")) { - include_status = git_config_bool(k, v); - return 0; - } if (!strcmp(k, "commit.cleanup")) return git_config_string(_arg, k, v); if (!strcmp(k, "commit.gpgsign")) { @@ -1596,7 +1592,8 @@ int cmd_commit(int argc, const char **argv, const char *prefix) OPT_FILENAME('t', "template", _file, N_("use specified template file")), OPT_BOOL('e', "edit", _flag, N_("force edit of commit")), OPT_STRING(0, "cleanup", _arg, N_("default"), N_("how to strip spaces and #comments from message")), - OPT_BOOL(0, "status", _status, N_("include status in commit message template")), + OPT_BOOL_C(0, "status", _status, N_("include status in commit message template"), + "commit.status", parse_opt_confkey_bool), { OPTION_STRING, 'S', "gpg-sign", _commit, N_("key-id"), N_("GPG sign commit"), PARSE_OPT_OPTARG, NULL, (intptr_t) "" }, /* end commit message options */ diff --git a/parse-options-cb.c b/parse-options-cb.c index b7d8f7dcb2..2383d9bbe0 100644 --- a/parse-options-cb.c +++ b/parse-options-cb.c @@ -236,3 +236,24 @@ int parse_opt_passthru_argv(const struct option *opt, const char *arg, int unset return 0; } + +/* Does it suck that I have to use the cache interface to the config + * here? Should we somehow unroll this whole thing so + * parse_options_step loops over the config values, and maybe + * populates opt->conf_key (which we'd need to add) for all the + * options that need it? + * + * I.e. should we make this more complex because this one-shot + * interface is expensive, or is it just fine? +*/ + +int parse_opt_confkey_bool(const struct option *opt, const char *arg, int unset) { + const char *value; + + if (git_config_get_value(opt->conf_key, )) + return 0; + + *(int *)opt->value = git_config_bool(opt->conf_key, value); + + return 0; +} diff --git a/parse-options.c b/parse-options.c index 4fbe924a5d..f9aba088d8 100644 --- a/parse-options.c +++ b/parse-options.c @@ -235,12 +235,13 @@ static int parse_short_opt(struct parse_opt_ctx_t *p, const struct option *optio } static int parse_long_opt(struct parse_opt_ctx_t *p, const char *arg, - const struct option *options) + struct option *options) { const struct option *all_opts = options; const char *arg_end = strchrnul(arg, '='); const struct option *abbrev_option = NULL, *ambiguous_option = NULL; int abbrev_flags = 0, ambiguous_flags = 0; + int ret; for (; options->type != OPTION_END; options++) { const char *rest, *long_name = options->long_name; @@ -313,7 +314,17 @@ static int parse_long_opt(struct parse_opt_ctx_t *p, const char *arg, continue; p->opt = rest + 1; } - return get_value(p, options, all_opts, flags ^
Re: [PATCH 6/7] short status: improve reporting for submodule changes
Stefan Beller wrote: > +++ b/wt-status.c > @@ -431,10 +431,19 @@ static void wt_status_collect_changed_cb(struct > diff_queue_struct *q, > } > if (!d->worktree_status) > d->worktree_status = p->status; > - d->dirty_submodule = p->two->dirty_submodule; > - if (S_ISGITLINK(p->two->mode)) > + if (S_ISGITLINK(p->two->mode)) { > + d->dirty_submodule = p->two->dirty_submodule; This is to simplify because dirty_submodule is just going to stay as 0 in the !S_ISGITLINK(p->two->mode) case, right? > d->new_submodule_commits = !!oidcmp(>one->oid, > >two->oid); > + if (s->status_format == STATUS_FORMAT_SHORT) { > + if (d->new_submodule_commits) > + d->worktree_status = 'M'; > + else if (d->dirty_submodule & > DIRTY_SUBMODULE_MODIFIED) > + d->worktree_status = 'm'; > + else if (d->dirty_submodule & > DIRTY_SUBMODULE_UNTRACKED) > + d->worktree_status = '?'; > + } > + } Makes sense. This patch also goes past the right margin. Maybe this code to compute d->worktree_status could be its own function? With or without such a change, Reviewed-by: Jonathan Niederdiff --git i/wt-status.c w/wt-status.c index 9909fd0e57..0375484962 100644 --- i/wt-status.c +++ w/wt-status.c @@ -407,6 +407,16 @@ static void wt_longstatus_print_change_data(struct wt_status *s, strbuf_release(); } +static char short_submodule_status(struct wt_status_change_data *d) { + if (d->new_submodule_commits) + return 'M'; + if (d->dirty_submodule & DIRTY_SUBMODULE_MODIFIED) + return 'm'; + if (d->dirty_submodule & DIRTY_SUBMODULE_UNTRACKED) + return '?'; + return d->worktree_status; +} + static void wt_status_collect_changed_cb(struct diff_queue_struct *q, struct diff_options *options, void *data) @@ -435,14 +445,8 @@ static void wt_status_collect_changed_cb(struct diff_queue_struct *q, d->dirty_submodule = p->two->dirty_submodule; d->new_submodule_commits = !!oidcmp(>one->oid, >two->oid); - if (s->status_format == STATUS_FORMAT_SHORT) { - if (d->new_submodule_commits) - d->worktree_status = 'M'; - else if (d->dirty_submodule & DIRTY_SUBMODULE_MODIFIED) - d->worktree_status = 'm'; - else if (d->dirty_submodule & DIRTY_SUBMODULE_UNTRACKED) - d->worktree_status = '?'; - } + if (s->status_format == STATUS_FORMAT_SHORT) + d->worktree_status = short_submodule_status(d); } switch (p->status) {
Re: [PATCH v4 1/2] diff --no-index: optionally follow symlinks
Dennis Kaarsemakerwrites: > @@ -52,7 +52,7 @@ static int get_mode(const char *path, int *mode) > #endif > else if (path == file_from_standard_input) > *mode = create_ce_mode(0666); > - else if (lstat(path, )) > + else if (dereference ? stat(path, ) : lstat(path, )) > return error("Could not access '%s'", path); > else > *mode = st.st_mode; This part makes sense---when the caller tells us to stat() we stat(), otherwise, we lstat(). > diff --git a/diff.c b/diff.c > index be11e4ef2b..2afecfb939 100644 > --- a/diff.c > +++ b/diff.c > @@ -2815,7 +2815,7 @@ int diff_populate_filespec(struct diff_filespec *s, > unsigned int flags) > s->size = xsize_t(st.st_size); > if (!s->size) > goto empty; > - if (S_ISLNK(st.st_mode)) { > + if (S_ISLNK(s->mode)) { This change is conceptually wrong. s->mode (often) comes from the index but in this codepath, after finding that s->oid is not valid or we want to read from the working tree instead (several lines before this part), we are committed to read from the working tree and check things with st.st_* fields, not s->mode, when we decide what to do with the thing we find on the filesystem, no? > @@ -2825,6 +2825,10 @@ int diff_populate_filespec(struct diff_filespec *s, > unsigned int flags) > s->should_free = 1; > return 0; > } > + if (S_ISLNK(st.st_mode)) { > + stat(s->path, ); > + s->size = xsize_t(st.st_size); > + } > if (size_only) > return 0; > if ((flags & CHECK_BINARY) && I suspect that this would conflict with a recent topic. But more importantly, this inserted code feels doubly wrong. - what allows us to unconditionally do "ah, symbolic link on the disk--find the target of the link, not the symbolic link itself"? We do not seem to be checking '--dereference' around here. - does this code do a reasonable thing when the path is a symbolic link that points at a directory? what does it mean to grab st.st_size for such a thing (and then go on to open() and xmmap() it)? Puzzled. Thanks.
[PATCH] sha1dc: safeguard against outside definitions of BIGENDIAN
In sha1dc/sha1.c, we #define BIGENDIAN under certain circumstances, and obviously leave the door open for scenarios where our conditions do not catch and that constant is #defined elsewhere. However, we did not expect that anybody would possibly #define BIGENDIAN to 0, indicating that the current platform is *not* big endian. This is not just a theoretical consideration: On Windows, the winsock2.h header file (which is used to allow Git to communicate via network) does indeed do this. Let's test for that circumstance, too, and byte-swap as intended in that case. This fixes a massive breakage on Windows where current `pu` (having switched on DC_SHA1 by default) breaks pretty much every single test case. Signed-off-by: Johannes Schindelin--- Published-As: https://github.com/dscho/git/releases/tag/sha1dc-bigendian=0-v1 Fetch-It-Via: git fetch https://github.com/dscho/git sha1dc-bigendian=0-v1 Obviously, this patch is based on `next`. sha1dc/sha1.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sha1dc/sha1.c b/sha1dc/sha1.c index 6dd0da36084..d99db4f2e1b 100644 --- a/sha1dc/sha1.c +++ b/sha1dc/sha1.c @@ -35,7 +35,7 @@ #define sha1_mix(W, t) (rotate_left(W[t - 3] ^ W[t - 8] ^ W[t - 14] ^ W[t - 16], 1)) -#if defined(BIGENDIAN) +#if defined(BIGENDIAN) && BIGENDIAN != 0 #define sha1_load(m, t, temp) { temp = m[t]; } #else #define sha1_load(m, t, temp) { temp = m[t]; sha1_bswap32(temp); } base-commit: c21884356fab0bc6bc5fa6abcadbda27a112a76c -- 2.12.1.windows.1
Re: [PATCH 5/7] submodule.c: stricter checking for submodules in is_submodule_modified
Stefan Beller wrote: > By having a stricter check in the superproject we catch errors earlier, > instead of spawning a child process to tell us. > > Signed-off-by: Stefan Beller> Reviewed-by: Jonathan Nieder Yep. :)
Re: [PATCH 4/7] submodule.c: port is_submodule_modified to use porcelain 2
Stefan Beller wrote: [...] > --- a/submodule.c > +++ b/submodule.c [...] > @@ -1070,11 +1070,12 @@ unsigned is_submodule_modified(const char *path, int > ignore_untracked) [...] > while (strbuf_getwholeline(, fp, '\n') != EOF) { > - if ((buf.buf[0] == '?') && (buf.buf[1] == '?')) > + /* regular untracked files */ > + if (buf.buf[0] == '?') > dirty_submodule |= DIRTY_SUBMODULE_UNTRACKED; > else > dirty_submodule |= DIRTY_SUBMODULE_MODIFIED; At first I didn't believe it could be so simple. :) Unlike ordinary files that use 1, 2, or u, ignored files use '!'. You're not passing --ignored so you don't have to worry about them. Reviewed-by: Jonathan NiederVery nice.
Re: [PATCH 3/7] submodule.c: convert is_submodule_modified to use strbuf_getwholeline
Stefan Beller wrote: > Instead of implementing line reading yet again, make use of our beautiful > library function to read one line. By using strbuf_getwholeline instead > of strbuf_read, we avoid having to allocate memory for the entire child > process output at once. That is, we limit maximum memory usage. It also overlaps work a little better. > Once we know all information that we care about, we can terminate > the child early. In that case we do not care about its exit code as well. Should this say something about SIGPIPE? [...] > +++ b/submodule.c [...] > @@ -1072,28 +1072,27 @@ unsigned is_submodule_modified(const char *path, int > ignore_untracked) [...] > + /* > + * We're not interested in any further information from > + * the child any more, no output nor its exit code. > + */ language nit: s/, no output/: neither output/ [...] > - if (finish_command()) > + if (finish_command() && !ignore_cp_exit_code) finish_command complains if the child dies of SIGTERM: error: status died of signal 15 wait_or_whine(cp->pid, cp->argv[0], 1) doesn't do that but is meant for signal handling. Maybe we should rely on SIGPIPE instead (which wait_or_whine always silences) and avoid the kill() call. Can there be a test for this case (i.e. having lots of untracked files in the submodule so the child process fills its pipe buffer and has to exit early)? Thanks, Jonathan
Re: [PATCH 2/7] submodule.c: factor out early loop termination in is_submodule_modified
Stefan Beller wrote: > --- a/submodule.c > +++ b/submodule.c > @@ -1075,16 +1075,15 @@ unsigned is_submodule_modified(const char *path, int > ignore_untracked) > len = strbuf_read(, cp.out, 1024); > line = buf.buf; > while (len > 2) { > - if ((line[0] == '?') && (line[1] == '?')) { > + if ((line[0] == '?') && (line[1] == '?')) > dirty_submodule |= DIRTY_SUBMODULE_UNTRACKED; > - if (dirty_submodule & DIRTY_SUBMODULE_MODIFIED) > - break; > - } else { > + else > dirty_submodule |= DIRTY_SUBMODULE_MODIFIED; > - if (ignore_untracked || > - (dirty_submodule & DIRTY_SUBMODULE_UNTRACKED)) > - break; > - } > + > + if ((dirty_submodule & DIRTY_SUBMODULE_MODIFIED) && > + ((dirty_submodule & DIRTY_SUBMODULE_UNTRACKED) || > ignore_untracked)) nit: long line Reviewed-by: Jonathan Niederdiff --git i/submodule.c w/submodule.c index aba89661a7..8934d97359 100644 --- i/submodule.c +++ w/submodule.c @@ -1087,8 +1087,10 @@ unsigned is_submodule_modified(const char *path, int ignore_untracked) dirty_submodule |= DIRTY_SUBMODULE_MODIFIED; if ((dirty_submodule & DIRTY_SUBMODULE_MODIFIED) && - ((dirty_submodule & DIRTY_SUBMODULE_UNTRACKED) || ignore_untracked)) + (ignore_untracked +|| (dirty_submodule & DIRTY_SUBMODULE_UNTRACKED))) { break; + } next_line = strchr(line, '\n'); if (!next_line)
Re: [PATCH 1/7] submodule.c: use argv_array in is_submodule_modified
Stefan Beller wrote: > struct argv_array is easier to use and maintain Missing '.' at end of sentence. > Signed-off-by: Stefan Beller> --- > submodule.c | 10 ++ > 1 file changed, 2 insertions(+), 8 deletions(-) With or without that tweak, I still like this as much as last time. :) Reviewed-by: Jonathan Nieder Thanks.
[PATCH v2] send-email: Net::SMTP::SSL is obsolete, use only when necessary
Net::SMTP itself can do the necessary SSL and STARTTLS bits just fine since version 1.28, and Net::SMTP::SSL is now deprecated. Since 1.28 isn't that old yet, keep the old code in place and use it when necessary. While we're in the area, mark some messages for translation that were not yet marked as such. Signed-off-by: Dennis Kaarsemaker--- git-send-email.perl | 54 ++--- 1 file changed, 35 insertions(+), 19 deletions(-) diff --git a/git-send-email.perl b/git-send-email.perl index eea0a517f7..0d90439d9a 100755 --- a/git-send-email.perl +++ b/git-send-email.perl @@ -1353,10 +1353,12 @@ EOF die __("The required SMTP server is not properly defined.") } + require Net::SMTP; + my $use_net_smtp_ssl = version->parse($Net::SMTP::VERSION) < version->parse("1.28"); + $smtp_domain ||= maildomain(); + if ($smtp_encryption eq 'ssl') { $smtp_server_port ||= 465; # ssmtp - require Net::SMTP::SSL; - $smtp_domain ||= maildomain(); require IO::Socket::SSL; # Suppress "variable accessed once" warning. @@ -1368,34 +1370,48 @@ EOF # Net::SMTP::SSL->new() does not forward any SSL options IO::Socket::SSL::set_client_defaults( ssl_verify_params()); - $smtp ||= Net::SMTP::SSL->new($smtp_server, - Hello => $smtp_domain, - Port => $smtp_server_port, - Debug => $debug_net_smtp); + + if ($use_net_smtp_ssl) { + require Net::SMTP::SSL; + $smtp ||= Net::SMTP::SSL->new($smtp_server, + Hello => $smtp_domain, + Port => $smtp_server_port, + Debug => $debug_net_smtp); + } + else { + $smtp ||= Net::SMTP->new($smtp_server, +Hello => $smtp_domain, +Port => $smtp_server_port, +Debug => $debug_net_smtp, +SSL => 1); + } } else { - require Net::SMTP; - $smtp_domain ||= maildomain(); $smtp_server_port ||= 25; $smtp ||= Net::SMTP->new($smtp_server, Hello => $smtp_domain, Debug => $debug_net_smtp, Port => $smtp_server_port); if ($smtp_encryption eq 'tls' && $smtp) { - require Net::SMTP::SSL; - $smtp->command('STARTTLS'); - $smtp->response(); - if ($smtp->code == 220) { + if ($use_net_smtp_ssl) { + $smtp->command('STARTTLS'); + $smtp->response(); + if ($smtp->code != 220) { + die sprintf(__("Server does not support STARTTLS! %s"), $smtp->message); + } + require Net::SMTP::SSL; $smtp = Net::SMTP::SSL->start_SSL($smtp, ssl_verify_params()) - or die "STARTTLS failed! ".IO::Socket::SSL::errstr(); - $smtp_encryption = ''; - # Send EHLO again to receive fresh - # supported commands - $smtp->hello($smtp_domain); - } else { - die sprintf(__("Server does not support STARTTLS! %s"), $smtp->message); + or die sprintf(__("STARTTLS failed! %s"), IO::Socket::SSL::errstr()); + } + else { + $smtp->starttls(ssl_verify_params()) +
[PATCH v4 0/2] diff --no-index: support symlinks and pipes
git diff <(command1) <(command2) is less useful than it could be, all it outputs is: diff --git a/dev/fd/63 b/dev/fd/62 index 9e6542b297..9f7b2c291b 12 --- a/dev/fd/63 +++ b/dev/fd/62 @@ -1 +1 @@ -pipe:[464811685] \ No newline at end of file +pipe:[464811687] \ No newline at end of file Normal diff provides arguably better output: the diff of the output of the commands. This series makes it possible for git diff --no-index to follow symlinks and read from pipes, mimicking the behaviour of normal diff. v1: http://public-inbox.org/git/2016201958.2175-1-den...@kaarsemaker.net/ v2: http://public-inbox.org/git/20170113102021.6054-1-den...@kaarsemaker.net/ v3: http://public-inbox.org/git/20170318210038.22638-1-den...@kaarsemaker.net/ Changes since v3: Using the --dereference option without being in explicit or implicit no-index mode is no longer silently ignored, but an error. A test has been added for this behaviour. Dennis Kaarsemaker (2): diff --no-index: optionally follow symlinks diff --no-index: support reading from pipes Documentation/diff-options.txt | 9 +++ builtin/diff.c | 2 ++ diff-no-index.c| 16 ++--- diff.c | 30 +++ diff.h | 2 +- t/t4011-diff-symlink.sh| 6 + t/t4053-diff-no-index.sh | 54 ++ t/test-lib.sh | 4 8 files changed, 115 insertions(+), 8 deletions(-) -- 2.12.0-488-gd3584ba
[PATCH v4 1/2] diff --no-index: optionally follow symlinks
Git's diff machinery does not follow symlinks, which makes sense as git itself also does not, but stores the symlink destination. In --no-index mode however, it is useful for diff to be able to follow symlinks, matching the behaviour of ordinary diff. A new --dereference (name copied from diff) option has been added to enable this behaviour. --no-dereference can be used to disable it again. Signed-off-by: Dennis Kaarsemaker--- Documentation/diff-options.txt | 9 + builtin/diff.c | 2 ++ diff-no-index.c| 7 --- diff.c | 12 ++-- diff.h | 2 +- t/t4011-diff-symlink.sh| 6 ++ t/t4053-diff-no-index.sh | 44 ++ 7 files changed, 76 insertions(+), 6 deletions(-) diff --git a/Documentation/diff-options.txt b/Documentation/diff-options.txt index 2d77a19626..5a9d58b701 100644 --- a/Documentation/diff-options.txt +++ b/Documentation/diff-options.txt @@ -216,6 +216,15 @@ any of those replacements occurred. commit range. Defaults to `diff.submodule` or the 'short' format if the config option is unset. +ifdef::git-diff[] +--dereference:: +--no-dereference:: + Normally, "git diff --no-index" will compare symlinks by comparing what + they point to. The `--dereference` option will make it compare the content + of the linked files. The `--no-dereference` option disables an earlier + `--dereference`. +endif::git-diff[] + --color[=]:: Show colored diff. `--color` (i.e. without '=') is the same as `--color=always`. diff --git a/builtin/diff.c b/builtin/diff.c index 7f91f6d226..09e646060e 100644 --- a/builtin/diff.c +++ b/builtin/diff.c @@ -360,6 +360,8 @@ int cmd_diff(int argc, const char **argv, const char *prefix) if (nongit) die(_("Not a git repository")); argc = setup_revisions(argc, argv, , NULL); + if (DIFF_OPT_TST(, DEREFERENCE)) + die(_("--dereference can only be used together with --no-index")); if (!rev.diffopt.output_format) { rev.diffopt.output_format = DIFF_FORMAT_PATCH; diff_setup_done(); diff --git a/diff-no-index.c b/diff-no-index.c index f420786039..fe48f32ddd 100644 --- a/diff-no-index.c +++ b/diff-no-index.c @@ -40,7 +40,7 @@ static int read_directory_contents(const char *path, struct string_list *list) */ static const char file_from_standard_input[] = "-"; -static int get_mode(const char *path, int *mode) +static int get_mode(const char *path, int *mode, int dereference) { struct stat st; @@ -52,7 +52,7 @@ static int get_mode(const char *path, int *mode) #endif else if (path == file_from_standard_input) *mode = create_ce_mode(0666); - else if (lstat(path, )) + else if (dereference ? stat(path, ) : lstat(path, )) return error("Could not access '%s'", path); else *mode = st.st_mode; @@ -93,7 +93,8 @@ static int queue_diff(struct diff_options *o, { int mode1 = 0, mode2 = 0; - if (get_mode(name1, ) || get_mode(name2, )) + if (get_mode(name1, , DIFF_OPT_TST(o, DEREFERENCE)) || + get_mode(name2, , DIFF_OPT_TST(o, DEREFERENCE))) return -1; if (mode1 && mode2 && S_ISDIR(mode1) != S_ISDIR(mode2)) { diff --git a/diff.c b/diff.c index be11e4ef2b..2afecfb939 100644 --- a/diff.c +++ b/diff.c @@ -2815,7 +2815,7 @@ int diff_populate_filespec(struct diff_filespec *s, unsigned int flags) s->size = xsize_t(st.st_size); if (!s->size) goto empty; - if (S_ISLNK(st.st_mode)) { + if (S_ISLNK(s->mode)) { struct strbuf sb = STRBUF_INIT; if (strbuf_readlink(, s->path, s->size)) @@ -2825,6 +2825,10 @@ int diff_populate_filespec(struct diff_filespec *s, unsigned int flags) s->should_free = 1; return 0; } + if (S_ISLNK(st.st_mode)) { + stat(s->path, ); + s->size = xsize_t(st.st_size); + } if (size_only) return 0; if ((flags & CHECK_BINARY) && @@ -3884,7 +3888,11 @@ int diff_opt_parse(struct diff_options *options, else if (!strcmp(arg, "--no-follow")) { DIFF_OPT_CLR(options, FOLLOW_RENAMES); DIFF_OPT_CLR(options, DEFAULT_FOLLOW_RENAMES); - } else if (!strcmp(arg, "--color")) + } else if (!strcmp(arg, "--dereference")) + DIFF_OPT_SET(options, DEREFERENCE); + else if (!strcmp(arg, "--no-dereference")) + DIFF_OPT_CLR(options, DEREFERENCE); + else if (!strcmp(arg, "--color")) options->use_color = 1; else if
[PATCH v4 2/2] diff --no-index: support reading from pipes
diff <(command1) <(command2) provides useful output, let's make it possible for git to do the same. Signed-off-by: Dennis Kaarsemaker--- diff-no-index.c | 9 + diff.c | 18 -- t/t4053-diff-no-index.sh | 10 ++ t/test-lib.sh| 4 4 files changed, 39 insertions(+), 2 deletions(-) diff --git a/diff-no-index.c b/diff-no-index.c index fe48f32ddd..1262a587e5 100644 --- a/diff-no-index.c +++ b/diff-no-index.c @@ -83,6 +83,15 @@ static struct diff_filespec *noindex_filespec(const char *name, int mode) name = "/dev/null"; s = alloc_filespec(name); fill_filespec(s, null_sha1, 0, mode); + /* +* In --no-index mode, we support reading from pipes. canon_mode, called by +* fill_filespec, gets confused by this and thinks we now have subprojects. +* To help the rest of the diff machinery along, we now override what +* canon_mode says. This is done here instead of in canon_mode, because the +* rest of git does not (and should not) support pipes. +*/ + if (S_ISFIFO(mode)) + s->mode = S_IFREG | ce_permissions(mode); if (name == file_from_standard_input) populate_from_stdin(s); return s; diff --git a/diff.c b/diff.c index 2afecfb939..4f74a54d74 100644 --- a/diff.c +++ b/diff.c @@ -2765,6 +2765,11 @@ static int diff_populate_gitlink(struct diff_filespec *s, int size_only) return 0; } +static int should_mmap_file_contents(struct stat *st) +{ + return S_ISREG(st->st_mode); +} + /* * While doing rename detection and pickaxe operation, we may need to * grab the data for the blob (or file) for our own in-core comparison. @@ -2839,9 +2844,18 @@ int diff_populate_filespec(struct diff_filespec *s, unsigned int flags) fd = open(s->path, O_RDONLY); if (fd < 0) goto err_empty; - s->data = xmmap(NULL, s->size, PROT_READ, MAP_PRIVATE, fd, 0); + if (!should_mmap_file_contents()) { + struct strbuf sb = STRBUF_INIT; + strbuf_read(, fd, 0); + s->size = sb.len; + s->data = strbuf_detach(, NULL); + s->should_free = 1; + } + else { + s->data = xmmap(NULL, s->size, PROT_READ, MAP_PRIVATE, fd, 0); + s->should_munmap = 1; + } close(fd); - s->should_munmap = 1; /* * Convert from working tree format to canonical git format diff --git a/t/t4053-diff-no-index.sh b/t/t4053-diff-no-index.sh index 8c87bffb34..2d9b322315 100755 --- a/t/t4053-diff-no-index.sh +++ b/t/t4053-diff-no-index.sh @@ -171,4 +171,14 @@ test_expect_success SYMLINKS 'diff --no-index --no-dereference does not follow s test_cmp expect actual ' +test_expect_success PROCESS_SUBSTITUTION 'diff --no-index works on fifos' ' + cat >expect <<-EOF && + @@ -1 +1 @@ + -1 + +2 + EOF + test_expect_code 1 git diff --no-index --dereference <(echo 1) <(echo 2) | tail -n +5 > actual && + test_cmp expect actual +' + test_done diff --git a/t/test-lib.sh b/t/test-lib.sh index 11562bde10..78f3d24651 100644 --- a/t/test-lib.sh +++ b/t/test-lib.sh @@ -1128,3 +1128,7 @@ build_option () { test_lazy_prereq LONG_IS_64BIT ' test 8 -le "$(build_option sizeof-long)" ' + +test_lazy_prereq PROCESS_SUBSTITUTION ' + eval "foo=<(echo test)" 2>/dev/null +' -- 2.12.0-488-gd3584ba
What's cooking in git.git (Mar 2017, #10; Fri, 24)
Here are the topics that have been cooking. Commits prefixed with '-' are only in 'pu' (proposed updates) while commits prefixed with '+' are in 'next'. The ones marked with '.' do not appear in any of the integration branches, but I am still holding onto them. The second maintenance release for v2.12.x series has just been tagged. You can find the changes described here in the integration branches of the repositories listed at http://git-blame.blogspot.com/p/git-public-repositories.html -- [Graduated to "master"] * dl/credential-cache-socket-in-xdg-cache (2017-03-17) 3 commits (merged to 'next' on 2017-03-20 at 9de71bcce8) + credential-cache: add tests for XDG functionality + credential-cache: use XDG_CACHE_HOME for socket + path.c: add xdg_cache_home The default location "~/.git-credential-cache/socket" for the socket used to communicate with the credential-cache daemon has been moved to "~/.cache/git/credential/socket". * jk/execv-dashed-external (2017-03-18) 1 commit (merged to 'next' on 2017-03-20 at 62119fa314) + run-command: fix segfault when cleaning forked async process Fix for NO_PTHREADS build. * jk/sha1dc (2017-03-17) 6 commits (merged to 'next' on 2017-03-20 at 3455b6c19f) + Makefile: make DC_SHA1 the default + t0013: add a basic sha1 collision detection test + Makefile: add DC_SHA1 knob + sha1dc: disable safe_hash feature + sha1dc: adjust header includes for git + sha1dc: add collision-detecting sha1 implementation The "detect attempt to create collisions" variant of SHA-1 implementation by Marc Stevens (CWI) and Dan Shumow (Microsoft) has been integrated and made the default. * js/regexec-buf (2017-03-18) 1 commit (merged to 'next' on 2017-03-20 at 7381595eb7) + pickaxe: fix segfault with '-S<...> --pickaxe-regex' Fix for potential segv introduced in v2.11.0 and later (also v2.10.2). * rs/http-push-cleanup (2017-03-18) 1 commit (merged to 'next' on 2017-03-20 at fcf8d30bc0) + http-push: don't check return value of lookup_unknown_object() Code clean-up. * rs/path-name-safety-cleanup (2017-03-18) 1 commit (merged to 'next' on 2017-03-20 at 78ea574469) + revision: remove declaration of path_name() Code clean-up. * rs/shortlog-cleanup (2017-03-18) 1 commit (merged to 'next' on 2017-03-20 at a826dff5cf) + shortlog: don't set after_subject to an empty string Code clean-up. * rs/update-hook-optim (2017-03-18) 1 commit (merged to 'next' on 2017-03-20 at f36ede55be) + receive-pack: simplify run_update_post_hook() Code clean-up. * sg/test-with-stdin (2017-03-18) 2 commits (merged to 'next' on 2017-03-20 at a66fec5692) + tests: make the 'test_pause' helper work in non-verbose mode + tests: create an interactive gdb session with the 'debug' helper Teach the "debug" helper used in the test framework that allows a command to run under "gdb" to make the session interactive. -- [New Topics] * ab/test-readme-updates (2017-03-23) 4 commits - SQUASH??? - t/README: clarify the test_have_prereq documentation - t/README: change "Inside part" to "Inside the part" - t/README: link to metacpan.org, not search.cpan.org Doc updates. Waiting for a reaction to SQUASH??? * jk/quote-env-path-list-component (2017-03-22) 1 commit (merged to 'next' on 2017-03-24 at 78843c4f9d) + t5615: fix a here-doc syntax error A test fix. Will merge to 'master'. * js/rebase-i-reword-to-run-hooks (2017-03-23) 4 commits - SQUASH??? - sequencer: allow the commit-msg hooks to run during a `reword` - sequencer: make commit options more extensible - t7504: document regression: reword no longer calls commit-msg A recent update to "rebase -i" stopped running hooks for the "git commit" command during "reword" action, which has been fixed. Waiting for a reaction to SQUASH??? * sb/push-options-via-transport (2017-03-22) 2 commits (merged to 'next' on 2017-03-24 at c5535bec3b) + remote-curl: allow push options + send-pack: send push options correctly in stateless-rpc case Recently we started passing the "--push-options" through the external remote helper interface; now the "smart HTTP" remote helper understands what to do with the passed information. Will merge to 'master'. * sb/submodule-update-initial-runs-custom-script (2017-03-22) 1 commit (merged to 'next' on 2017-03-24 at 628200c3b1) + t7406: correct test case for submodule-update initial population A test fix. Will merge to 'master'. * ab/branch-list-doc (2017-03-24) 2 commits - branch doc: update description for `--list` - branch doc: change `git branch ` to use `` Doc update. Will merge to 'next'. * km/config-grammofix (2017-03-23) 1 commit (merged to 'next' on 2017-03-24 at 75ddbbc6f9) + doc/config: grammar fixes for core.{editor,commentChar} Doc update. Will merge to 'master'. * sg/completion-ctags (2017-03-23) 3 commits - completion:
A note from the maintainer
Welcome to the Git development community. This message is written by the maintainer and talks about how Git project is managed, and how you can work with it. * Mailing list and the community The development is primarily done on the Git mailing list. Help requests, feature proposals, bug reports and patches should be sent to the list address. You don't have to be subscribed to send messages. The convention on the list is to keep everybody involved on Cc:, so it is unnecessary to say "Please Cc: me, I am not subscribed". Before sending patches, please read Documentation/SubmittingPatches and Documentation/CodingGuidelines to familiarize yourself with the project convention. If you sent a patch and you did not hear any response from anybody for several days, it could be that your patch was totally uninteresting, but it also is possible that it was simply lost in the noise. Please do not hesitate to send a reminder message in such a case. Messages getting lost in the noise may be a sign that those who can evaluate your patch don't have enough mental/time bandwidth to process them right at the moment, and it often helps to wait until the list traffic becomes calmer before sending such a reminder. The list archive is available at a few public sites: http://public-inbox.org/git/ http://marc.info/?l=git http://www.spinics.net/lists/git/ For those who prefer to read it over NNTP: nntp://news.public-inbox.org/inbox.comp.version-control.git nntp://news.gmane.org/gmane.comp.version-control.git are available. When you point at a message in a mailing list archive, using its message ID is often the most robust (if not very friendly) way to do so, like this: http://public-inbox.org/git/pine.lnx.4.58.0504150753440.7...@ppc970.osdl.org Often these web interfaces accept the message ID with enclosing <> stripped (like the above example to point at one of the most important message in the Git list). Some members of the development community can sometimes be found on the #git and #git-devel IRC channels on Freenode. Their logs are available at: http://colabti.org/irclogger/irclogger_log/git http://colabti.org/irclogger/irclogger_log/git-devel There is a volunteer-run newsletter to serve our community ("Git Rev News" http://git.github.io/rev_news/rev_news.html). Git is a member project of software freedom conservancy, a non-profit organization (https://sfconservancy.org/). To reach a committee of liaisons to the conservancy, contact them at . * Reporting bugs When you think git does not behave as you expect, please do not stop your bug report with just "git does not work". "I used git in this way, but it did not work" is not much better, neither is "I used git in this way, and X happend, which is broken". It often is that git is correct to cause X happen in such a case, and it is your expectation that is broken. People would not know what other result Y you expected to see instead of X, if you left it unsaid. Please remember to always state - what you wanted to achieve; - what you did (the version of git and the command sequence to reproduce the behavior); - what you saw happen (X above); - what you expected to see (Y above); and - how the last two are different. See http://www.chiark.greenend.org.uk/~sgtatham/bugs.html for further hints. If you think you found a security-sensitive issue and want to disclose it to us without announcing it to wider public, please contact us at our security mailing list . This is a closed list that is limited to people who need to know early about vulnerabilities, including: - people triaging and fixing reported vulnerabilities - people operating major git hosting sites with many users - people packaging and distributing git to large numbers of people where these issues are discussed without risk of the information leaking out before we're ready to make public announcements. * Repositories and documentation. My public git.git repositories are at: git://git.kernel.org/pub/scm/git/git.git/ https://kernel.googlesource.com/pub/scm/git/git git://repo.or.cz/alt-git.git/ https://github.com/git/git/ git://git.sourceforge.jp/gitroot/git-core/git.git/ git://git-core.git.sourceforge.net/gitroot/git-core/git-core/ This one shows not just the main integration branches, but also individual topics broken out: git://github.com/gitster/git/ A few web interfaces are found at: http://git.kernel.org/cgit/git/git.git https://kernel.googlesource.com/pub/scm/git/git http://repo.or.cz/w/alt-git.git Preformatted documentation from the tip of the "master" branch can be found in: git://git.kernel.org/pub/scm/git/git-{htmldocs,manpages}.git/ git://repo.or.cz/git-{htmldocs,manpages}.git/ https://github.com/gitster/git-{htmldocs,manpages}.git/ The manual pages formatted in HTML for the tip of
[ANNOUNCE] Git v2.12.2
The latest maintenance release Git v2.12.2 is now available at the usual places. These fixes have all been in the 'master' branch to be included in the next feature release. The tarballs are found at: https://www.kernel.org/pub/software/scm/git/ The following public repositories all have a copy of the 'v2.12.2' tag and the 'maint' branch that the tag points at: url = https://kernel.googlesource.com/pub/scm/git/git url = git://repo.or.cz/alt-git.git url = git://git.sourceforge.jp/gitroot/git-core/git.git url = git://git-core.git.sourceforge.net/gitroot/git-core/git-core url = https://github.com/gitster/git Git v2.12.2 Release Notes = Fixes since v2.12.1 --- * "git status --porcelain" is supposed to give a stable output, but a few strings were left as translatable by mistake. * "Dumb http" transport used to misparse a nonsense http-alternates response, which has been fixed. * "git diff --quiet" relies on the size field in diff_filespec to be correctly populated, but diff_populate_filespec() helper function made an incorrect short-cut when asked only to populate the size field for paths that need to go through convert_to_git() (e.g. CRLF conversion). * There is no need for Python only to give a few messages to the standard error stream, but we somehow did. * A leak in a codepath to read from a packed object in (rare) cases has been plugged. * "git upload-pack", which is a counter-part of "git fetch", did not report a request for a ref that was not advertised as invalid. This is generally not a problem (because "git fetch" will stop before making such a request), but is the right thing to do. * A "gc.log" file left by a backgrounded "gc --auto" disables further automatic gc; it has been taught to run at least once a day (by default) by ignoring a stale "gc.log" file that is too old. * "git remote rm X", when a branch has remote X configured as the value of its branch.*.remote, tried to remove branch.*.remote and branch.*.merge and failed if either is unset. * A caller of tempfile API that uses stdio interface to write to files may ignore errors while writing, which is detected when tempfile is closed (with a call to ferror()). By that time, the original errno that may have told us what went wrong is likely to be long gone and was overwritten by an irrelevant value. close_tempfile() now resets errno to EIO to make errno at least predictable. * "git show-branch" expected there were only very short branch names in the repository and used a fixed-length buffer to hold them without checking for overflow. * The code that parses header fields in the commit object has been updated for (micro)performance and code hygiene. * A test that creates a confusing branch whose name is HEAD has been corrected not to do so. * "Cc:" on the trailer part does not have to conform to RFC strictly, unlike in the e-mail header. "git send-email" has been updated to ignore anything after '>' when picking addresses, to allow non-address cruft like " # stable 4.4" after the address. * "git push" had a handful of codepaths that could lead to a deadlock when unexpected error happened, which has been fixed. * Code to read submodule..ignore config did not state the variable name correctly when giving an error message diagnosing misconfiguration. * "git ls-remote" and "git archive --remote" are designed to work without being in a directory under Git's control. However, recent updates revealed that we randomly look into a directory called .git/ without actually doing necessary set-up when working in a repository. Stop doing so. * The code to parse the command line "git grep ... [[--] ...]" has been cleaned up, and a handful of bugs have been fixed (e.g. we used to check "--" if it is a rev). * The code to parse "git -c VAR=VAL cmd" and set configuration variable for the duration of cmd had two small bugs, which have been fixed. This supersedes jc/config-case-cmdline topic that has been discarded. Also contains various documentation updates and code clean-ups. Changes since v2.12.1 are as follows: David Turner (1): gc: ignore old gc.log files Eric Wong (1): README: create HTTP/HTTPS links from URLs in Markdown Jeff King (20): grep: move thread initialization a little lower grep: re-order rev-parsing loop grep: fix "--" rev/pathspec disambiguation grep: avoid resolving revision names in --no-index case grep: do not diagnose misspelt revs with --no-index show-branch: drop head_len variable show-branch: store resolved head in heap buffer remote: avoid reading $GIT_DIR config in non-repo grep: treat revs the same for --untracked as
Re: How do I copy a branch & its config to a new name?
On Fri, Mar 24, 2017 at 12:10:49PM +0100, Ævar Arnfjörð Bjarmason wrote: > Actually this is a bit confusing, but I think reversing the arguments > makes sense, i.e.: > > git branch -c dest [src] > > And similarly: > > git checkout -c dest [] > > This is confusing in that it reverses the arguments, but more useful > in that it allows you to omit src like the other invocations of these > commands, and you can e.g. do: > > git branch -c avar/topic-2 > > While on avar/topic to start working on avar/topic-2, which would copy > avar/topic's state & config. > > I'll put this on my TODO list, but unless someone comes up with a > compelling argument against the above I plan to make the interface > look like that. I think it probably should match "git branch -m", which uses: git branch -c [] That's the closest operation we currently have, and it still allows omitting the src. It _is_ different than: git branch [] I wondered if you could advertise "-c" not as a new "copy mode", but rather as an option for normal branch creation. Sort of a "by the way, copy the config". But I don't think that's a great mental model. doesn't have to be a branch at all. -Peff
Re: [PATCHv2 00/14] completion: speed up refs completion
On Thu, Mar 23, 2017 at 11:28:52AM -0700, Junio C Hamano wrote: > SZEDER Gáborwrites: > > > This series is the updated version of 'sg/completion-refs-speedup'. > > It speeds up refs completion for large number of refs, partly by > > giving up disambiguating ambiguous refs and partly by eliminating most > > of the shell processing between 'git for-each-ref' and 'ls-remote' and > > Bash's completion facility. The rest is a bit of preparatory > > reorganization, cleanup and bugfixes. > > > > Changes since v1: > > ... > > [1] - > > http://public-inbox.org/git/20170206181545.12869-1-szeder@gmail.com/ > > It seems Jacob Keller was the only person who was excited about > these changes when v1 was posted? It would be nice to see a bit > more enthusiasm from other folks who are invested in the completion > script, but you are the de-facto go-to person on the completion > already, so ... ;-) > > Will replace. Let's advance this to 'next' soonish (say, by early > next week). I'm far from an expert in the completion scripts, but I read over the whole thing and it looked good to me. As usual with bash, the optimizations can make the code a bit non-intuitive, but I think the changes are clearly explained and the performance results speak for themselves. -Peff
Re: [PATCHv2 11/14] completion: let 'for-each-ref' sort remote branches for 'checkout' DWIMery
On Thu, Mar 23, 2017 at 04:29:21PM +0100, SZEDER Gábor wrote: > diff --git a/contrib/completion/git-completion.bash > b/contrib/completion/git-completion.bash > index 394dcece6..d26312899 100644 > --- a/contrib/completion/git-completion.bash > +++ b/contrib/completion/git-completion.bash > @@ -423,8 +423,9 @@ __git_refs () > # Try to find a remote branch that matches the > completion word > # but only output if the branch name is unique > __git for-each-ref --format="%(refname:strip=3)" \ > + --sort="refname:strip=3" \ > "refs/remotes/*/$match*" > "refs/remotes/*/$match*/**" | \ > - sort | uniq -u > + uniq -u I wonder if it would be worth adding a "--unique" option to for-each-ref. I guess the definition of "unique" may change though (here you'd want to do it on the sort key, but other cases may want unique branch names sorted by time, which is less trivial). -Peff
Re: [PATCHv2 08/14] completion: let 'for-each-ref' and 'ls-remote' filter matching refs
On Thu, Mar 23, 2017 at 04:29:18PM +0100, SZEDER Gábor wrote: > When completing refs, several __git_refs() code paths list all the > refs from the refs/{heads,tags,remotes}/ hierarchy and then > __gitcomp_nl() iterates over those refs in a shell loop to filter out > refs not matching the current ref to be completed. This comes with a > considerable performance penalty when a repository contains a lot of > refs but the current ref can be uniquely completed or when only a > handful of refs match the current ref. Part of this is due to outputting too many refs from for-each-ref, but part of it is that for-each-ref is not good at limiting the refs it looks at internally. I have a patch for that, but it's not all that helpful without Michael Haggerty's mmap-packed-refs work, so I'll get it included there. So that makes this change doubly important. You get the immediate speedups, and then you'll get another one when that work is merged later. > case "$cur_" in > refs|refs/*) > format="refname" > - refs="${cur_%/*}" > + refs=("$match*" "$match*/**") > track="" Working on the aforementioned patch, I noticed that for-each-ref's matching is a little tricky due to its path semantics. So I wanted to double-check your patterns. :) I think these should do the right thing. -Peff
Re: [PATCHv2 07/14] completion: don't disambiguate short refs
On Thu, Mar 23, 2017 at 04:29:17PM +0100, SZEDER Gábor wrote: > However, it's questionable whether ambiguous refs are really that bad > to justify that much extra cost: It's not clear to me that the existing completion actually does a good job with disambiguation anyway. If I have a tag and a branch named "foo", then in theory doing: git log fo should present me with "heads/foo" and "tags/foo" as options. But it doesn't seem to; it just completes "foo". But even if it did, those don't _start_ with foo, I have to go to some work to back up anyway. I think we are better off just completing "foo" and letting the command complain that it's ambiguous. So even leaving aside the performance tradeoff, that seems like a more sensible behavior anyway. And AFAICT, that's the behavior you'd get with your patch (we'd get two "foo"s, but the completion is presumably smart enough to handle that. > This speeds up refs completion considerably. Uniquely completing a > branch in a repository with 100k local branches, all packed, best of > five: > > On Linux, before: > > $ time __git_complete_refs --cur=maste > > real0m1.662s > user0m1.368s > sys 0m0.296s > > After: > > real0m0.831s > user0m0.808s > sys 0m0.028s This is nice, though I think faster ref storage is another way to attack the problem. This is much simpler, though. :) -Peff
Re: [PATCH] push: allow atomic flag via configuration
Jeff Kingwrites: > My one question would be whether people would want this to actually be > specific to a particular remote, and not just on for a given repository > (your "site-specific" in the description made me think of that). In that > case it would be better as part of the remote.* config. Yeah, I had the same reaction. Conceptually, this sits next to remote.*.push that defines which set of refs are sent by default, and remote..pushAtomic does make sense. If (and only if) it turns out to be cumbersome for somebody to set the configuration for each and every remote, it is OK to also add push.atomic to serve as a fallback for remote.*.pushAtomic, I would think, but adding only push.atomic feels somewhat backwards.
Re: [PATCH] log: if --decorate is not given, default to --decorate=auto
Jeff Kingwrites: > I see you ended up with a test that uses test_terminal, which is much > better (and your patch looks good to me). > > But I was concerned that there might be a bug in pager_in_use(), so I > dug into it a little. I think the code there is correct; it's just > relaying the environment variable's value. Likewise, on the setting > side, I think the code is correct. We set the environment variable > whenever we start the pager in setup_pager(). > > I think what is confusing is that "git -p" does _not_ mean > "unconditionally use a pager". It means "start a pager if stdout is a > terminal, even if this command is not usually paged". So something like > "git -p log >actual" is correct not to trigger pager_in_use(). > > I also double-checked the documentation, which covers this case > accurately. So I think all is well, and there's nothing to fix. You > might want an option for "even though stdout is not a tty pretend like a > pager is in use", but that is exactly what GIT_PAGER_IN_USE=1 is for. Thanks ;-).
Re: [PATCH] push: allow atomic flag via configuration
On Fri, Mar 24, 2017 at 11:53:54AM -0700, Jonathan Nieder wrote: > I didn't receive the original patch (maybe mailing delay?) so > commenting here. Vger seems a bit slow lately. The list copy did eventually get delivered to me and public-inbox: http://public-inbox.org/git/1490375874.745.227.ca...@locke.gandi.net/ I don't think it answers any of your questions, though. ;) -Peff
[PATCH] pager_in_use: use git_env_bool()
On Fri, Mar 24, 2017 at 02:55:43PM -0400, Jeff King wrote: > But I was concerned that there might be a bug in pager_in_use(), so I > dug into it a little. I think the code there is correct; [...] I did see this small cleanup opportunity, though. -- >8 -- Subject: [PATCH] pager_in_use: use git_env_bool() The pager_in_use() function predates git_env_bool(), but ends up doing the same thing. Let's make use of the latter, which is shorter and less repetitive. Signed-off-by: Jeff King--- pager.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/pager.c b/pager.c index 73ca8bc3b..c113d898a 100644 --- a/pager.c +++ b/pager.c @@ -135,9 +135,7 @@ void setup_pager(void) int pager_in_use(void) { - const char *env; - env = getenv("GIT_PAGER_IN_USE"); - return env ? git_config_bool("GIT_PAGER_IN_USE", env) : 0; + return git_env_bool("GIT_PAGER_IN_USE", 0); } /* -- 2.12.1.843.g1937c56c2
Re: [PATCH] log: if --decorate is not given, default to --decorate=auto
On Thu, Mar 23, 2017 at 10:52:34AM -0600, Alex Henrie wrote: > Unfortunately, I think I found a bug. Even when using `git -p`, the > function pager_in_use() always returns false if the output is not a > TTY. So, `isatty(1) || pager_in_use()` and `color_stdout_is_tty || > (pager_in_use() && pager_use_color)` are redundant. > > If we want to use `git -p log` in a test, we'll have to change the > behavior of pager_in_use(). Alternatively, we could use > `GIT_PAGER_IN_USE=1 git log` instead. I see you ended up with a test that uses test_terminal, which is much better (and your patch looks good to me). But I was concerned that there might be a bug in pager_in_use(), so I dug into it a little. I think the code there is correct; it's just relaying the environment variable's value. Likewise, on the setting side, I think the code is correct. We set the environment variable whenever we start the pager in setup_pager(). I think what is confusing is that "git -p" does _not_ mean "unconditionally use a pager". It means "start a pager if stdout is a terminal, even if this command is not usually paged". So something like "git -p log >actual" is correct not to trigger pager_in_use(). I also double-checked the documentation, which covers this case accurately. So I think all is well, and there's nothing to fix. You might want an option for "even though stdout is not a tty pretend like a pager is in use", but that is exactly what GIT_PAGER_IN_USE=1 is for. -Peff
Re: [PATCH] push: allow atomic flag via configuration
Hi, Jeff King wrote: > On Fri, Mar 24, 2017 at 06:17:54PM +0100, Romuald Brunet wrote: >> Added a "push.atomic" option to git-config to allow site-specific >> configuration of the atomic flag of git push > > I don't really use --atomic myself, but this seems like a reasonable > thing to want, and the implementation looks cleanly done. > > My one question would be whether people would want this to actually be > specific to a particular remote, and not just on for a given repository > (your "site-specific" in the description made me think of that). In that > case it would be better as part of the remote.* config. I didn't receive the original patch (maybe mailing delay?) so commenting here. I use --atomic sometimes, but it's tied to the specific context of what I'm trying to push. I'd be interested to hear more about the use case. Do you want pushes to be atomic opportunistically when the server supports that (analogous to push.gpgSign=if-asked)? This also seems likely to break scripts that rely on the current non-atomic behavior, so without knowing more about the use case it's hard to see how to proceed. Thanks and hope that helps, Jonathan
LETS WORK TOGETHER AND ACHIEVED THIS FUND.
Dear Friend, I need your help transferring (US$4.5M DOLLARS) to your bank account.I have every enquiries’details to make the bank believed you and release the fund in within 5 banking working days with your full co-operation with me for success. Send the below requirement to enable me advice you on how to apply to the Bank for the claim. 1)Full names. 2)country of origin. 3)Your Mobile No. 4)Your Age. 5)occupation. Thanks. Mr Joshua Blaise
Re: [PATCH] push: allow atomic flag via configuration
On Fri, Mar 24, 2017 at 06:17:54PM +0100, Romuald Brunet wrote: > Added a "push.atomic" option to git-config to allow site-specific > configuration of the atomic flag of git push I don't really use --atomic myself, but this seems like a reasonable thing to want, and the implementation looks cleanly done. My one question would be whether people would want this to actually be specific to a particular remote, and not just on for a given repository (your "site-specific" in the description made me think of that). In that case it would be better as part of the remote.* config. -Peff
[PATCH v4 13/16] tag: change --point-at to default to HEAD
Change the --points-at option to default to HEAD for consistency with its siblings --contains, --merged etc. which default to HEAD. Previously we'd get: $ git tag --points-at 2>&1 | head -n 1 error: option `points-at' requires a value This changes behavior added in commit ae7706b9ac (tag: add --points-at list option, 2012-02-08). Signed-off-by: Ævar Arnfjörð Bjarmason--- Documentation/git-tag.txt | 3 ++- builtin/tag.c | 3 ++- t/t7004-tag.sh| 9 - 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/Documentation/git-tag.txt b/Documentation/git-tag.txt index 4d289f5dd5..d5cdb18d96 100644 --- a/Documentation/git-tag.txt +++ b/Documentation/git-tag.txt @@ -139,7 +139,8 @@ This option is only applicable when listing tags without annotation lines. commit (`HEAD` if not specified), incompatible with `--merged`. --points-at :: - Only list tags of the given object. Implies `--list`. + Only list tags of the given object (HEAD if not + specified). Implies `--list`. -m :: --message=:: diff --git a/builtin/tag.c b/builtin/tag.c index 3c686961db..8bf6d85176 100644 --- a/builtin/tag.c +++ b/builtin/tag.c @@ -431,7 +431,8 @@ int cmd_tag(int argc, const char **argv, const char *prefix) N_("field name to sort on"), _opt_ref_sorting), { OPTION_CALLBACK, 0, "points-at", _at, N_("object"), - N_("print only tags of the object"), 0, parse_opt_object_name + N_("print only tags of the object"), PARSE_OPT_LASTARG_DEFAULT, + parse_opt_object_name, (intptr_t) "HEAD" }, OPT_STRING( 0 , "format", , N_("format"), N_("format to use for the output")), OPT_BOOL('i', "ignore-case", , N_("sorting and filtering are case insensitive")), diff --git a/t/t7004-tag.sh b/t/t7004-tag.sh index 5823de16aa..3529c3009c 100755 --- a/t/t7004-tag.sh +++ b/t/t7004-tag.sh @@ -1534,7 +1534,8 @@ do " test_expect_success "Doing 'git tag --list-like $option is permitted" " git tag -n $option HEAD HEAD && - git tag $option HEAD HEAD + git tag $option HEAD HEAD && + git tag $option " done @@ -1546,6 +1547,12 @@ test_expect_success '--points-at can be used in non-list mode' ' test_cmp expect actual ' +test_expect_success '--points-at is a synonym for --points-at HEAD' ' + echo v4.0 >expect && + git tag --points-at >actual && + test_cmp expect actual +' + test_expect_success '--points-at finds lightweight tags' ' echo v4.0 >expect && git tag --points-at v4.0 >actual && -- 2.11.0
[PATCH v4 15/16] ref-filter: reflow recently changed branch/tag/for-each-ref docs
Reflow the recently changed branch/tag-for-each-ref documentation. This change shows no changes under --word-diff, except the innocuous change of moving git-tag.txt's "[--sort=]" around slightly. Signed-off-by: Ævar Arnfjörð Bjarmason--- Documentation/git-branch.txt | 15 --- Documentation/git-tag.txt| 7 --- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/Documentation/git-branch.txt b/Documentation/git-branch.txt index e4b5d5c3e1..5e175ec339 100644 --- a/Documentation/git-branch.txt +++ b/Documentation/git-branch.txt @@ -10,9 +10,9 @@ SYNOPSIS [verse] 'git branch' [--color[=] | --no-color] [-r | -a] [--list] [-v [--abbrev= | --no-abbrev]] - [--column[=] | --no-column] + [--column[=] | --no-column] [--sort=] [(--merged | --no-merged) []] - [--contains [
[PATCH v4 16/16] tag: add tests for --with and --without
Change the test suite to test for these synonyms for --contains and --no-contains, respectively. Before this change there were no tests for them at all. This doesn't exhaustively test for them as well as their --contains and --no-contains synonyms, but at least it's something. Signed-off-by: Ævar Arnfjörð Bjarmason--- t/t7004-tag.sh | 6 -- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/t/t7004-tag.sh b/t/t7004-tag.sh index 8a6e8032da..6143113dbb 100755 --- a/t/t7004-tag.sh +++ b/t/t7004-tag.sh @@ -1599,10 +1599,12 @@ test_expect_success 'mixing incompatibles modes and options is forbidden' ' test_must_fail git tag --contains tag-blob && test_must_fail git tag --no-contains tag-tree && test_must_fail git tag --no-contains tag-blob && - test_must_fail git tag --contains --no-contains + test_must_fail git tag --contains --no-contains && + test_must_fail git tag --no-with HEAD && + test_must_fail git tag --no-without HEAD ' -for option in --contains --no-contains --merged --no-merged --points-at +for option in --contains --with --no-contains --without --merged --no-merged --points-at do test_expect_success "mixing incompatible modes with $option is forbidden" " test_must_fail git tag -d $option HEAD && -- 2.11.0
[PATCH v4 07/16] tag tests: fix a typo in a test description
Change "suceed" to "succeed" in a test description. The typo has been here since the code was originally added in commit ef5a6fb597 ("Add test-script for git-tag", 2007-06-28). Signed-off-by: Ævar Arnfjörð Bjarmason--- t/t7004-tag.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/t/t7004-tag.sh b/t/t7004-tag.sh index 830eff948e..63ee2cf727 100755 --- a/t/t7004-tag.sh +++ b/t/t7004-tag.sh @@ -136,7 +136,7 @@ test_expect_success \ 'test $(git tag -l mytag) = mytag' test_expect_success \ - 'listing tags using a non-matching pattern should suceed' \ + 'listing tags using a non-matching pattern should succeed' \ 'git tag -l xxx' test_expect_success \ -- 2.11.0
[PATCH v4 14/16] ref-filter: add --no-contains option to tag/branch/for-each-ref
Change the tag, branch & for-each-ref commands to have a --no-contains option in addition to their longstanding --contains options. This allows for finding the last-good rollout tag given a known-bad . Given a hypothetically bad commit cf5c7253e0, the git version to revert to can be found with this hacky two-liner: (git tag -l 'v[0-9]*'; git tag -l --contains cf5c7253e0 'v[0-9]*') | sort | uniq -c | grep -E '^ *1 ' | awk '{print $2}' | tail -n 10 With this new --no-contains option the same can be achieved with: git tag -l --no-contains cf5c7253e0 'v[0-9]*' | sort | tail -n 10 As the filtering machinery is shared between the tag, branch & for-each-ref commands, implement this for those commands too. A practical use for this with "branch" is e.g. finding branches which were branched off between v2.8.0 and v2.10.0: git branch --contains v2.8.0 --no-contains v2.10.0 The "describe" command also has a --contains option, but its semantics are unrelated to what tag/branch/for-each-ref use --contains for. A --no-contains option for "describe" wouldn't make any sense, other than being exactly equivalent to not supplying --contains at all, which would be confusing at best. Add a --without option to "tag" as an alias for --no-contains, for consistency with --with and --contains. The --with option is undocumented, and possibly the only user of it is Junio (). But it's trivial to support, so let's do that. The additions to the the test suite are inverse copies of the corresponding --contains tests. With this change --no-contains for tag, branch & for-each-ref is just as well tested as the existing --contains option. In addition to those tests, add a test for "tag" which asserts that --no-contains won't find tree/blob tags, which is slightly unintuitive, but consistent with how --contains works & is documented. Signed-off-by: Ævar Arnfjörð Bjarmason --- Documentation/git-branch.txt | 16 +++- Documentation/git-for-each-ref.txt | 6 +- Documentation/git-tag.txt | 6 +- builtin/branch.c | 5 +- builtin/for-each-ref.c | 3 +- builtin/tag.c | 8 +- contrib/completion/git-completion.bash | 4 +- parse-options.h| 2 + ref-filter.c | 19 +++-- ref-filter.h | 1 + t/t3201-branch-contains.sh | 54 +- t/t6302-for-each-ref-filter.sh | 16 t/t7004-tag.sh | 130 - 13 files changed, 245 insertions(+), 25 deletions(-) diff --git a/Documentation/git-branch.txt b/Documentation/git-branch.txt index e465298571..e4b5d5c3e1 100644 --- a/Documentation/git-branch.txt +++ b/Documentation/git-branch.txt @@ -11,7 +11,8 @@ SYNOPSIS 'git branch' [--color[=] | --no-color] [-r | -a] [--list] [-v [--abbrev= | --no-abbrev]] [--column[=] | --no-column] - [(--merged | --no-merged | --contains) []] [--sort=] + [(--merged | --no-merged) []] + [--contains [
[PATCH v4 12/16] tag: implicitly supply --list given another list-like option
Change the "tag" command to implicitly turn on its --list mode when provided with a list-like option such as --contains, --points-at etc. This is for consistency with how "branch" works. When "branch" is given a list-like option, such as --contains, it implicitly provides --list. Before this change "tag" would error out on those sorts of invocations. I.e. while both of these worked for "branch": git branch --contains v2.8.0 git branch --list --contains v2.8.0 Only the latter form worked for "tag": git tag --contains v2.8.0 '*rc*' git tag --list --contains v2.8.0 '*rc*' Now "tag", like "branch", will implicitly supply --list when a list-like option is provided, and no other conflicting non-list options (such as -d) are present on the command-line. Spelunking through the history via: git log --reverse -p -G'only allowed with' -- '*builtin*tag*c' Reveals that there was no good reason for not allowing this in the first place. The --contains option added in 32c35cfb1e ("git-tag: Add --contains option", 2009-01-26) made this an error. All the other subsequent list-like options that were added copied its pattern of making this usage an error. The only tests that break as a result of this change are tests that were explicitly checking that this "branch-like" usage wasn't permitted. Change those failing tests to check that this invocation mode is permitted, add extra tests for the list-like options we weren't testing, and tests to ensure that e.g. we don't toggle the list mode in the presence of other conflicting non-list options. With this change errors messages such as "--contains option is only allowed with -l" don't make sense anymore, since options like --contain turn on -l. Instead we error out when list-like options such as --contain are used in conjunction with conflicting options such as -d or -v. Signed-off-by: Ævar Arnfjörð Bjarmason--- Documentation/git-tag.txt | 17 +-- builtin/tag.c | 18 ++-- t/t7004-tag.sh| 55 ++- 3 files changed, 73 insertions(+), 17 deletions(-) diff --git a/Documentation/git-tag.txt b/Documentation/git-tag.txt index 47d8733523..4d289f5dd5 100644 --- a/Documentation/git-tag.txt +++ b/Documentation/git-tag.txt @@ -82,10 +82,11 @@ OPTIONS -n:: specifies how many lines from the annotation, if any, - are printed when using -l. - The default is not to print any annotation lines. - If no number is given to `-n`, only the first line is printed. - If the tag is not annotated, the commit message is displayed instead. + are printed when using -l. Implies `--list`. ++ +The default is not to print any annotation lines. +If no number is given to `-n`, only the first line is printed. +If the tag is not annotated, the commit message is displayed instead. -l:: --list:: @@ -95,6 +96,10 @@ OPTIONS Running "git tag" without arguments also lists all tags. The pattern is a shell wildcard (i.e., matched using fnmatch(3)). Multiple patterns may be given; if any of them matches, the tag is shown. ++ +This option is implicitly supplied if any other list-like option such +as `--contains` is provided. See the documentation for each of those +options for details. --sort=:: Sort based on the key given. Prefix `-` to sort in @@ -123,7 +128,7 @@ This option is only applicable when listing tags without annotation lines. --contains []:: Only list tags which contain the specified commit (HEAD if not - specified). + specified). Implies `--list`. --merged []:: Only list tags whose commits are reachable from the specified @@ -134,7 +139,7 @@ This option is only applicable when listing tags without annotation lines. commit (`HEAD` if not specified), incompatible with `--merged`. --points-at :: - Only list tags of the given object. + Only list tags of the given object. Implies `--list`. -m :: --message=:: diff --git a/builtin/tag.c b/builtin/tag.c index ad29be6923..3c686961db 100644 --- a/builtin/tag.c +++ b/builtin/tag.c @@ -454,8 +454,14 @@ int cmd_tag(int argc, const char **argv, const char *prefix) } create_tag_object = (opt.sign || annotate || msg.given || msgfile); - if (argc == 0 && !cmdmode) - cmdmode = 'l'; + if (!cmdmode) { + if (argc == 0) + cmdmode = 'l'; + else if (filter.with_commit || +filter.points_at.nr || filter.merge_commit || +filter.lines != -1) + cmdmode = 'l'; + } if ((create_tag_object || force) && (cmdmode != 0)) usage_with_options(git_tag_usage, options); @@ -485,13 +491,13 @@ int cmd_tag(int argc, const char **argv, const char *prefix) return ret; } if (filter.lines != -1) - die(_("-n
[PATCH v4 11/16] tag: change misleading --list documentation
Change the documentation for --list so that it's described as a toggle, not as an option that takes a as an argument. Junio initially documented this in b867c7c23a ("git-tag: -l to list tags (usability).", 2006-02-17), but later Jeff King changed "tag" to accept multiple patterns in 588d0e834b ("tag: accept multiple patterns for --list", 2011-06-20). However, documenting this as "-l " was never correct, as these both worked before Jeff's change: git tag -l 'v*' git tag 'v*' -l One would expect an option that was documented like that to only accept: git tag --list git tag --list 'v*rc*' And after Jeff's change, one that took multiple patterns: git tag --list 'v*rc*' --list '*2.8*' But since it's actually a toggle all of these work as well, and produce identical output to the last example above: git tag --list 'v*rc*' '*2.8*' git tag --list 'v*rc*' '*2.8*' --list --list --list git tag --list 'v*rc*' '*2.8*' --list -l --list -l --list Now the documentation is more in tune with how the "branch" command describes its --list option since commit cddd127b9a ("branch: introduce --list option", 2011-08-28). Change the test suite to assert that these invocations work for the cases that weren't already being tested for. Signed-off-by: Ævar Arnfjörð Bjarmason--- Documentation/git-tag.txt | 15 --- t/t7004-tag.sh| 25 + 2 files changed, 33 insertions(+), 7 deletions(-) diff --git a/Documentation/git-tag.txt b/Documentation/git-tag.txt index 448fdf3743..47d8733523 100644 --- a/Documentation/git-tag.txt +++ b/Documentation/git-tag.txt @@ -87,13 +87,14 @@ OPTIONS If no number is given to `-n`, only the first line is printed. If the tag is not annotated, the commit message is displayed instead. --l :: ---list :: - List tags with names that match the given pattern (or all if no - pattern is given). Running "git tag" without arguments also - lists all tags. The pattern is a shell wildcard (i.e., matched - using fnmatch(3)). Multiple patterns may be given; if any of - them matches, the tag is shown. +-l:: +--list:: + List tags. With optional `...`, e.g. `git tag --list + 'v-*'`, list only the tags that match the pattern(s). ++ +Running "git tag" without arguments also lists all tags. The pattern +is a shell wildcard (i.e., matched using fnmatch(3)). Multiple +patterns may be given; if any of them matches, the tag is shown. --sort=:: Sort based on the key given. Prefix `-` to sort in diff --git a/t/t7004-tag.sh b/t/t7004-tag.sh index 92af8bb7e6..75681b2cad 100755 --- a/t/t7004-tag.sh +++ b/t/t7004-tag.sh @@ -118,6 +118,18 @@ test_expect_success 'listing all tags if one exists should succeed' ' git tag ' +cat >expect actual && + test_cmp expect actual && + git tag --list -l --list >actual && + test_cmp expect actual +' + test_expect_success 'listing all tags if one exists should output that tag' ' test $(git tag -l) = mytag && test $(git tag) = mytag @@ -336,6 +348,19 @@ test_expect_success 'tag -l can accept multiple patterns' ' test_cmp expect actual ' +# Between v1.7.7 & v2.13.0 a fair reading of the git-tag documentation +# could leave you with the impression that "-l -l " +# was how we wanted to accept multiple patterns. +# +# This test should not imply that this is a sane thing to support. but +# since the documentation was worded like it was let's at least find +# out if we're going to break this long-documented form of taking +# multiple patterns. +test_expect_success 'tag -l -l works, as our buggy documentation previously suggested' ' + git tag -l "v1*" -l "v0*" >actual && + test_cmp expect actual +' + test_expect_success 'listing tags in column' ' COLUMNS=40 git tag -l --column=row >actual && cat >expected <<\EOF && -- 2.11.0
[PATCH v4 05/16] ref-filter: add test for --contains on a non-commit
Change the tag test suite to test for --contains on a tree & blob. It only accepts commits and will spew out " is a tree, not a commit". It's sufficient to test this just for the "tag" and "branch" commands, because it covers all the machinery shared between "branch" and "for-each-ref". Signed-off-by: Ævar Arnfjörð Bjarmason--- t/t3201-branch-contains.sh | 9 + t/t7004-tag.sh | 4 +++- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/t/t3201-branch-contains.sh b/t/t3201-branch-contains.sh index 7f3ec47241..daa3ae82b7 100755 --- a/t/t3201-branch-contains.sh +++ b/t/t3201-branch-contains.sh @@ -130,6 +130,15 @@ test_expect_success 'implicit --list conflicts with modification options' ' ' +test_expect_success 'Assert that --contains only works on commits, not trees & blobs' ' + test_must_fail git branch --contains master^{tree} && + blob=$(git hash-object -w --stdin <<-\EOF + Some blob + EOF + ) && + test_must_fail git branch --contains $blob +' + # We want to set up a case where the walk for the tracking info # of one branch crosses the tip of another branch (and make sure # that the latter walk does not mess up our flag to see if it was diff --git a/t/t7004-tag.sh b/t/t7004-tag.sh index 45790664c1..3439913488 100755 --- a/t/t7004-tag.sh +++ b/t/t7004-tag.sh @@ -1461,7 +1461,9 @@ test_expect_success 'mixing incompatibles modes and options is forbidden' ' test_must_fail git tag -n 100 && test_must_fail git tag -l -m msg && test_must_fail git tag -l -F some file && - test_must_fail git tag -v -s + test_must_fail git tag -v -s && + test_must_fail git tag --contains tag-tree && + test_must_fail git tag --contains tag-blob ' # check points-at -- 2.11.0
[PATCH v4 04/16] ref-filter: make combining --merged & --no-merged an error
Change the behavior of specifying --merged & --no-merged to be an error, instead of silently picking the option that was provided last. Subsequent changes of mine add a --no-contains option in addition to the existing --contains. Providing both of those isn't an error, and has actual meaning. Making its cousins have different behavior in this regard would be confusing to the user, especially since we'd be silently disregarding some of their command-line input. Signed-off-by: Ævar Arnfjörð Bjarmason--- Documentation/git-branch.txt | 6 -- Documentation/git-for-each-ref.txt | 6 -- Documentation/git-tag.txt | 4 ++-- ref-filter.c | 11 ++- t/t3200-branch.sh | 4 t/t6302-for-each-ref-filter.sh | 4 t/t7004-tag.sh | 4 7 files changed, 32 insertions(+), 7 deletions(-) diff --git a/Documentation/git-branch.txt b/Documentation/git-branch.txt index 092f1bcf9f..e465298571 100644 --- a/Documentation/git-branch.txt +++ b/Documentation/git-branch.txt @@ -215,11 +215,13 @@ start-point is either a local or remote-tracking branch. --merged []:: Only list branches whose tips are reachable from the - specified commit (HEAD if not specified). Implies `--list`. + specified commit (HEAD if not specified). Implies `--list`, + incompatible with `--no-merged`. --no-merged []:: Only list branches whose tips are not reachable from the - specified commit (HEAD if not specified). Implies `--list`. + specified commit (HEAD if not specified). Implies `--list`, + incompatible with `--merged`. :: The name of the branch to create or delete. diff --git a/Documentation/git-for-each-ref.txt b/Documentation/git-for-each-ref.txt index 111e1be6f5..4d55893712 100644 --- a/Documentation/git-for-each-ref.txt +++ b/Documentation/git-for-each-ref.txt @@ -69,11 +69,13 @@ OPTIONS --merged []:: Only list refs whose tips are reachable from the - specified commit (HEAD if not specified). + specified commit (HEAD if not specified), + incompatible with `--no-merged`. --no-merged []:: Only list refs whose tips are not reachable from the - specified commit (HEAD if not specified). + specified commit (HEAD if not specified), + incompatible with `--merged`. --contains []:: Only list refs which contain the specified commit (HEAD if not diff --git a/Documentation/git-tag.txt b/Documentation/git-tag.txt index 3abf912782..448fdf3743 100644 --- a/Documentation/git-tag.txt +++ b/Documentation/git-tag.txt @@ -126,11 +126,11 @@ This option is only applicable when listing tags without annotation lines. --merged []:: Only list tags whose commits are reachable from the specified - commit (`HEAD` if not specified). + commit (`HEAD` if not specified), incompatible with `--no-merged`. --no-merged []:: Only list tags whose commits are not reachable from the specified - commit (`HEAD` if not specified). + commit (`HEAD` if not specified), incompatible with `--merged`. --points-at :: Only list tags of the given object. diff --git a/ref-filter.c b/ref-filter.c index 9c82b5b9d6..d7efae7b53 100644 --- a/ref-filter.c +++ b/ref-filter.c @@ -2084,8 +2084,17 @@ int parse_opt_merge_filter(const struct option *opt, const char *arg, int unset) { struct ref_filter *rf = opt->value; unsigned char sha1[20]; + int no_merged = starts_with(opt->long_name, "no"); - rf->merge = starts_with(opt->long_name, "no") + if (rf->merge) { + if (no_merged) { + return opterror(opt, "is incompatible with --merged", 0); + } else { + return opterror(opt, "is incompatible with --no-merged", 0); + } + } + + rf->merge = no_merged ? REF_FILTER_MERGED_OMIT : REF_FILTER_MERGED_INCLUDE; diff --git a/t/t3200-branch.sh b/t/t3200-branch.sh index 9f353c0efc..fe62e7c775 100755 --- a/t/t3200-branch.sh +++ b/t/t3200-branch.sh @@ -978,6 +978,10 @@ test_expect_success '--merged catches invalid object names' ' test_must_fail git branch --merged ' +test_expect_success '--merged is incompatible with --no-merged' ' + test_must_fail git branch --merged HEAD --no-merged HEAD +' + test_expect_success 'tracking with unexpected .fetch refspec' ' rm -rf a b c d && git init a && diff --git a/t/t6302-for-each-ref-filter.sh b/t/t6302-for-each-ref-filter.sh index a09a1a46ef..d36d5dc124 100755 --- a/t/t6302-for-each-ref-filter.sh +++ b/t/t6302-for-each-ref-filter.sh @@ -421,4 +421,8 @@ test_expect_success 'check %(if:notequals=)' ' test_cmp expect actual ' +test_expect_success '--merged is incompatible with --no-merged' ' + test_must_fail git
[PATCH v4 02/16] tag doc: split up the --[no-]merged documentation
Split up the --[no-]merged documentation into documentation that documents each option independently. This is in line with how "branch" and "for-each-ref" are documented, and makes subsequent changes to discuss the limits & caveats of each option easier to read. Signed-off-by: Ævar Arnfjörð Bjarmason--- Documentation/git-tag.txt | 11 +++ 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/Documentation/git-tag.txt b/Documentation/git-tag.txt index 33f18ea5fb..68b0ab2410 100644 --- a/Documentation/git-tag.txt +++ b/Documentation/git-tag.txt @@ -124,10 +124,13 @@ This option is only applicable when listing tags without annotation lines. Only list tags which contain the specified commit (HEAD if not specified). ---[no-]merged []:: - Only list tags whose tips are reachable, or not reachable - if `--no-merged` is used, from the specified commit (`HEAD` - if not specified). +--merged []:: + Only list tags whose tips are reachable from the specified commit + (`HEAD` if not specified). + +--no-merged []:: + Only list tags whose tips are not reachable from the specified + commit (`HEAD` if not specified). --points-at :: Only list tags of the given object. -- 2.11.0
[PATCH v4 03/16] tag doc: reword --[no-]merged to talk about commits, not tips
Change the wording for the --merged and --no-merged options to talk about "commits" instead of "tips". This phrasing was copied from the "branch" documentation in commit 5242860f54 ("tag.c: implement '--merged' and '--no-merged' options", 2015-09-10). Talking about the "tip" is branch nomenclature, not something usually associated with tags. This phrasing might lead the reader to believe that these options might find tags pointing to trees or blobs, let's instead be explicit and only talk about commits. Signed-off-by: Ævar Arnfjörð Bjarmason--- Documentation/git-tag.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Documentation/git-tag.txt b/Documentation/git-tag.txt index 68b0ab2410..3abf912782 100644 --- a/Documentation/git-tag.txt +++ b/Documentation/git-tag.txt @@ -125,11 +125,11 @@ This option is only applicable when listing tags without annotation lines. specified). --merged []:: - Only list tags whose tips are reachable from the specified commit - (`HEAD` if not specified). + Only list tags whose commits are reachable from the specified + commit (`HEAD` if not specified). --no-merged []:: - Only list tags whose tips are not reachable from the specified + Only list tags whose commits are not reachable from the specified commit (`HEAD` if not specified). --points-at :: -- 2.11.0
[PATCH v4 01/16] tag doc: move the description of --[no-]merged earlier
Move the documentation for the --merged & --no-merged options earlier in the documentation, to sit along the other switches, and right next to the similar --contains and --points-at switches. It makes more sense to group the options together, not have some options after the like of , , etc. This was originally put there when the --merged & --no-merged options were introduced in 5242860f54 ("tag.c: implement '--merged' and '--no-merged' options", 2015-09-10). It's not apparent from that commit that the documentation is being placed apart from other options, rather than along with them, so this was likely missed in the initial review. Signed-off-by: Ævar Arnfjörð Bjarmason--- Documentation/git-tag.txt | 10 +- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Documentation/git-tag.txt b/Documentation/git-tag.txt index 525737a5d8..33f18ea5fb 100644 --- a/Documentation/git-tag.txt +++ b/Documentation/git-tag.txt @@ -124,6 +124,11 @@ This option is only applicable when listing tags without annotation lines. Only list tags which contain the specified commit (HEAD if not specified). +--[no-]merged []:: + Only list tags whose tips are reachable, or not reachable + if `--no-merged` is used, from the specified commit (`HEAD` + if not specified). + --points-at :: Only list tags of the given object. @@ -173,11 +178,6 @@ This option is only applicable when listing tags without annotation lines. that of linkgit:git-for-each-ref[1]. When unspecified, defaults to `%(refname:strip=2)`. ---[no-]merged []:: - Only list tags whose tips are reachable, or not reachable - if `--no-merged` is used, from the specified commit (`HEAD` - if not specified). - CONFIGURATION - By default, 'git tag' in sign-with-default mode (-s) will use your -- 2.11.0
[PATCH v4 09/16] tag: add more incompatibles mode tests
Amend the test suite to test for more invalid uses like "-l -a" etc. This change tests the code path in builtin/tag.c between lines: if (argc == 0 && !cmdmode) And: if ((create_tag_object || force) && (cmdmode != 0)) Signed-off-by: Ævar Arnfjörð Bjarmason--- t/t7004-tag.sh | 16 1 file changed, 16 insertions(+) diff --git a/t/t7004-tag.sh b/t/t7004-tag.sh index 63ee2cf727..92af8bb7e6 100755 --- a/t/t7004-tag.sh +++ b/t/t7004-tag.sh @@ -1455,8 +1455,24 @@ test_expect_success 'checking that initial commit is in all tags' " test_expect_success 'mixing incompatibles modes and options is forbidden' ' test_must_fail git tag -a && + test_must_fail git tag -a -l && + test_must_fail git tag -s && + test_must_fail git tag -s -l && + test_must_fail git tag -m && + test_must_fail git tag -m -l && + test_must_fail git tag -m "hlagh" && + test_must_fail git tag -m "hlagh" -l && + test_must_fail git tag -F && + test_must_fail git tag -F -l && + test_must_fail git tag -f && + test_must_fail git tag -f -l && + test_must_fail git tag -a -s -m -F && + test_must_fail git tag -a -s -m -F -l && test_must_fail git tag -l -v && + test_must_fail git tag -l -d && + test_must_fail git tag -l -v -d && test_must_fail git tag -n 100 && + test_must_fail git tag -n 100 -v && test_must_fail git tag -l -m msg && test_must_fail git tag -l -F some file && test_must_fail git tag -v -s && -- 2.11.0
[PATCH v4 08/16] for-each-ref: partly change to in help
Change mentions of to in the help output of for-each-ref as appropriate. Both --[no-]merged and --contains only take commits, but --points-at can take any object, such as a tag pointing to a tree or blob. Signed-off-by: Ævar Arnfjörð Bjarmason--- builtin/for-each-ref.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/builtin/for-each-ref.c b/builtin/for-each-ref.c index df41fa0350..1a5ed20f59 100644 --- a/builtin/for-each-ref.c +++ b/builtin/for-each-ref.c @@ -8,8 +8,8 @@ static char const * const for_each_ref_usage[] = { N_("git for-each-ref [] []"), N_("git for-each-ref [--points-at ]"), - N_("git for-each-ref [(--merged | --no-merged) []]"), - N_("git for-each-ref [--contains []]"), + N_("git for-each-ref [(--merged | --no-merged) []]"), + N_("git for-each-ref [--contains []]"), NULL }; -- 2.11.0
[PATCH v4 06/16] tag: remove a TODO item from the test suite
Change the test for "git tag -l" to not have an associated TODO comment saying that it should return non-zero if there's no tags. This was added in commit ef5a6fb597 ("Add test-script for git-tag", 2007-06-28) when the tests for "tag" were initially added, but at this point changing this would be inconsistent with how "git tag" is a synonym for "git tag -l", and would needlessly break external code that relies on this porcelain command. Signed-off-by: Ævar Arnfjörð Bjarmason--- t/t7004-tag.sh | 2 -- 1 file changed, 2 deletions(-) diff --git a/t/t7004-tag.sh b/t/t7004-tag.sh index 3439913488..830eff948e 100755 --- a/t/t7004-tag.sh +++ b/t/t7004-tag.sh @@ -16,7 +16,6 @@ tag_exists () { git show-ref --quiet --verify refs/tags/"$1" } -# todo: git tag -l now returns always zero, when fixed, change this test test_expect_success 'listing all tags in an empty tree should succeed' ' git tag -l && git tag @@ -136,7 +135,6 @@ test_expect_success \ 'listing a tag using a matching pattern should output that tag' \ 'test $(git tag -l mytag) = mytag' -# todo: git tag -l now returns always zero, when fixed, change this test test_expect_success \ 'listing tags using a non-matching pattern should suceed' \ 'git tag -l xxx' -- 2.11.0
[PATCH v4 10/16] parse-options: add OPT_NONEG to the "contains" option
Add the OPT_NONEG flag to the "contains" option and its hidden synonym "with". Since this was added in commit 694a577519 ("git-branch --contains=commit", 2007-11-07) giving --no-{contains,with} hasn't been an error, but has emitted the help output since filter.with_commit wouldn't get set. Now git will emit "error: unknown option `no-{contains,with}'" at the top of the help output. Signed-off-by: Ævar Arnfjörð Bjarmason--- parse-options.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/parse-options.h b/parse-options.h index dcd8a0926c..9f48f554ba 100644 --- a/parse-options.h +++ b/parse-options.h @@ -258,7 +258,7 @@ extern int parse_opt_passthru_argv(const struct option *, const char *, int); PARSE_OPT_LASTARG_DEFAULT | flag, \ parse_opt_commits, (intptr_t) "HEAD" \ } -#define OPT_CONTAINS(v, h) _OPT_CONTAINS_OR_WITH("contains", v, h, 0) -#define OPT_WITH(v, h) _OPT_CONTAINS_OR_WITH("with", v, h, PARSE_OPT_HIDDEN) +#define OPT_CONTAINS(v, h) _OPT_CONTAINS_OR_WITH("contains", v, h, PARSE_OPT_NONEG) +#define OPT_WITH(v, h) _OPT_CONTAINS_OR_WITH("with", v, h, PARSE_OPT_HIDDEN | PARSE_OPT_NONEG) #endif -- 2.11.0
[PATCH v4 00/16] Various changes to the "tag" command & related
Hopefully the final version. This is exactly like v3 except for a couple of minor changes (and rebased on the latest upstream master): Ævar Arnfjörð Bjarmason (16): tag doc: move the description of --[no-]merged earlier tag doc: split up the --[no-]merged documentation tag doc: reword --[no-]merged to talk about commits, not tips ref-filter: make combining --merged & --no-merged an error ref-filter: add test for --contains on a non-commit tag: remove a TODO item from the test suite tag tests: fix a typo in a test description for-each-ref: partly change to in help tag: add more incompatibles mode tests Clarified in the commit message what code in builtin/tag.c we're trying to test here. parse-options: add OPT_NONEG to the "contains" option tag: change misleading --list documentation Use the same phrasing as Junio's "branch doc: update description for `--list`" does when describing "git tag --list". tag: implicitly supply --list given another list-like option tag: change --point-at to default to HEAD ref-filter: add --no-contains option to tag/branch/for-each-ref ref-filter: reflow recently changed branch/tag/for-each-ref docs tag: add tests for --with and --without Documentation/git-branch.txt | 33 +++-- Documentation/git-for-each-ref.txt | 12 +- Documentation/git-tag.txt | 59 +--- builtin/branch.c | 5 +- builtin/for-each-ref.c | 5 +- builtin/tag.c | 27 ++-- contrib/completion/git-completion.bash | 4 +- parse-options.h| 6 +- ref-filter.c | 30 +++- ref-filter.h | 1 + t/t3200-branch.sh | 4 + t/t3201-branch-contains.sh | 61 +++- t/t6302-for-each-ref-filter.sh | 20 +++ t/t7004-tag.sh | 245 +++-- 14 files changed, 440 insertions(+), 72 deletions(-) -- 2.11.0
Re: [PATCH v2] log: if --decorate is not given, default to --decorate=auto
Alex Henrie wrote: > Signed-off-by: Alex Henrie> --- > builtin/log.c | 9 - > t/t4202-log.sh | 10 +- > 2 files changed, 17 insertions(+), 2 deletions(-) Nice. Reviewed-by: Jonathan Nieder
[PATCH 5/7] submodule.c: stricter checking for submodules in is_submodule_modified
By having a stricter check in the superproject we catch errors earlier, instead of spawning a child process to tell us. Reviewed-by: Jonathan NiederSigned-off-by: Stefan Beller --- submodule.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/submodule.c b/submodule.c index 256f15fde1..467f1de763 100644 --- a/submodule.c +++ b/submodule.c @@ -1052,11 +1052,12 @@ unsigned is_submodule_modified(const char *path, int ignore_untracked) git_dir = read_gitfile(buf.buf); if (!git_dir) git_dir = buf.buf; - if (!is_directory(git_dir)) { + if (!is_git_directory(git_dir)) { + if (is_directory(git_dir)) + die(_("'%s' not recognized as a git repository"), git_dir); strbuf_release(); /* The submodule is not checked out, so it is not modified */ return 0; - } strbuf_reset(); -- 2.12.1.437.g2b7623d507
[PATCH 7/7] submodule.c: correctly handle nested submodules in is_submodule_modified
When a nested submodule has untracked files, it would be reported as "modified submodule" in the superproject, because submodules are not parsed correctly in is_submodule_modified as they are bucketed into the modified pile as "they are not an untracked file". Signed-off-by: Stefan Beller--- submodule.c | 16 ++-- t/t3600-rm.sh | 2 +- t/t7506-status-submodule.sh | 2 +- 3 files changed, 16 insertions(+), 4 deletions(-) diff --git a/submodule.c b/submodule.c index 467f1de763..ec7e9b1b06 100644 --- a/submodule.c +++ b/submodule.c @@ -1078,8 +1078,20 @@ unsigned is_submodule_modified(const char *path, int ignore_untracked) /* regular untracked files */ if (buf.buf[0] == '?') dirty_submodule |= DIRTY_SUBMODULE_UNTRACKED; - else - dirty_submodule |= DIRTY_SUBMODULE_MODIFIED; + + /* regular unmerged and renamed files */ + if (buf.buf[0] == 'u' || + buf.buf[0] == '1' || + buf.buf[0] == '2') { + if (buf.buf[5] == 'S') { + /* nested submodule handling */ + if (buf.buf[6] == 'C' || buf.buf[7] == 'M') + dirty_submodule |= DIRTY_SUBMODULE_MODIFIED; + if (buf.buf[8] == 'U') + dirty_submodule |= DIRTY_SUBMODULE_UNTRACKED; + } else + dirty_submodule |= DIRTY_SUBMODULE_MODIFIED; + } if ((dirty_submodule & DIRTY_SUBMODULE_MODIFIED) && ((dirty_submodule & DIRTY_SUBMODULE_UNTRACKED) || ignore_untracked)) { diff --git a/t/t3600-rm.sh b/t/t3600-rm.sh index a6e5c5bd56..b58793448b 100755 --- a/t/t3600-rm.sh +++ b/t/t3600-rm.sh @@ -659,7 +659,7 @@ test_expect_success 'rm of a populated nested submodule with nested untracked fi test -d submod && test -f submod/.git && git status -s -uno --ignore-submodules=none >actual && - test_cmp expect.modified_inside actual && + test_cmp expect.modified_untracked actual && git rm -f submod && test ! -d submod && git status -s -uno --ignore-submodules=none >actual && diff --git a/t/t7506-status-submodule.sh b/t/t7506-status-submodule.sh index ad46384064..e3cdcede72 100755 --- a/t/t7506-status-submodule.sh +++ b/t/t7506-status-submodule.sh @@ -324,7 +324,7 @@ test_expect_success 'status with untracked file in nested submodule (porcelain)' test_expect_success 'status with untracked file in nested submodule (short)' ' git -C super status --short >output && diff output - <<-\EOF -m sub1 +? sub1 EOF ' -- 2.12.1.437.g2b7623d507
[PATCH 3/7] submodule.c: convert is_submodule_modified to use strbuf_getwholeline
Instead of implementing line reading yet again, make use of our beautiful library function to read one line. By using strbuf_getwholeline instead of strbuf_read, we avoid having to allocate memory for the entire child process output at once. That is, we limit maximum memory usage. Once we know all information that we care about, we can terminate the child early. In that case we do not care about its exit code as well. Helped-by: Jonathan NiederSigned-off-by: Stefan Beller --- submodule.c | 31 +++ 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/submodule.c b/submodule.c index e52cb8a958..0c43f9f2b1 100644 --- a/submodule.c +++ b/submodule.c @@ -1041,12 +1041,12 @@ int fetch_populated_submodules(const struct argv_array *options, unsigned is_submodule_modified(const char *path, int ignore_untracked) { - ssize_t len; struct child_process cp = CHILD_PROCESS_INIT; struct strbuf buf = STRBUF_INIT; + FILE *fp; unsigned dirty_submodule = 0; - const char *line, *next_line; const char *git_dir; + int ignore_cp_exit_code = 0; strbuf_addf(, "%s/.git", path); git_dir = read_gitfile(buf.buf); @@ -1072,28 +1072,27 @@ unsigned is_submodule_modified(const char *path, int ignore_untracked) if (start_command()) die("Could not run 'git status --porcelain' in submodule %s", path); - len = strbuf_read(, cp.out, 1024); - line = buf.buf; - while (len > 2) { - if ((line[0] == '?') && (line[1] == '?')) + fp = xfdopen(cp.out, "r"); + while (strbuf_getwholeline(, fp, '\n') != EOF) { + if ((buf.buf[0] == '?') && (buf.buf[1] == '?')) dirty_submodule |= DIRTY_SUBMODULE_UNTRACKED; else dirty_submodule |= DIRTY_SUBMODULE_MODIFIED; if ((dirty_submodule & DIRTY_SUBMODULE_MODIFIED) && - ((dirty_submodule & DIRTY_SUBMODULE_UNTRACKED) || ignore_untracked)) - break; - - next_line = strchr(line, '\n'); - if (!next_line) + ((dirty_submodule & DIRTY_SUBMODULE_UNTRACKED) || ignore_untracked)) { + /* +* We're not interested in any further information from +* the child any more, no output nor its exit code. +*/ + kill(cp.pid, SIGTERM); + ignore_cp_exit_code = 1; break; - next_line++; - len -= (next_line - line); - line = next_line; + } } - close(cp.out); + fclose(fp); - if (finish_command()) + if (finish_command() && !ignore_cp_exit_code) die("'git status --porcelain' failed in submodule %s", path); strbuf_release(); -- 2.12.1.437.g2b7623d507
[PATCH 4/7] submodule.c: port is_submodule_modified to use porcelain 2
Migrate 'is_submodule_modified' to the new porcelain format of git-status. This conversion attempts to convert faithfully, i.e. the behavior ought to be exactly the same. As the output in the parsing only distinguishes between untracked files and the rest, this is easy to port to the new format, as we only need to identify untracked files and the rest is handled in the "else" case. untracked files are indicated by only a single question mark instead of two question marks, so the conversion is easy. Signed-off-by: Stefan Beller--- submodule.c | 9 + 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/submodule.c b/submodule.c index 0c43f9f2b1..256f15fde1 100644 --- a/submodule.c +++ b/submodule.c @@ -1060,7 +1060,7 @@ unsigned is_submodule_modified(const char *path, int ignore_untracked) } strbuf_reset(); - argv_array_pushl(, "status", "--porcelain", NULL); + argv_array_pushl(, "status", "--porcelain=2", NULL); if (ignore_untracked) argv_array_push(, "-uno"); @@ -1070,11 +1070,12 @@ unsigned is_submodule_modified(const char *path, int ignore_untracked) cp.out = -1; cp.dir = path; if (start_command()) - die("Could not run 'git status --porcelain' in submodule %s", path); + die("Could not run 'git status --porcelain=2' in submodule %s", path); fp = xfdopen(cp.out, "r"); while (strbuf_getwholeline(, fp, '\n') != EOF) { - if ((buf.buf[0] == '?') && (buf.buf[1] == '?')) + /* regular untracked files */ + if (buf.buf[0] == '?') dirty_submodule |= DIRTY_SUBMODULE_UNTRACKED; else dirty_submodule |= DIRTY_SUBMODULE_MODIFIED; @@ -1093,7 +1094,7 @@ unsigned is_submodule_modified(const char *path, int ignore_untracked) fclose(fp); if (finish_command() && !ignore_cp_exit_code) - die("'git status --porcelain' failed in submodule %s", path); + die("'git status --porcelain=2' failed in submodule %s", path); strbuf_release(); return dirty_submodule; -- 2.12.1.437.g2b7623d507
[PATCH 6/7] short status: improve reporting for submodule changes
If I add an untracked file to a submodule or modify a tracked file, currently "git status --short" treats the change in the same way as changes to the current HEAD of the submodule: $ git clone --quiet --recurse-submodules https://gerrit.googlesource.com/gerrit $ echo hello >gerrit/plugins/replication/stray-file $ sed -i -e 's/.*//' gerrit/plugins/replication/.mailmap $ git -C gerrit status --short M plugins/replication This is by analogy with ordinary files, where "M" represents a change that has not been added yet to the index. But this change cannot be added to the index without entering the submodule, "git add"-ing it, and running "git commit", so the analogy is counterproductive. Introduce new status letters " ?" and " m" for this. These are similar to the existing "??" and " M" but mean that the submodule (not the parent project) has new untracked files and modified files, respectively. The user can use "git add" and "git commit" from within the submodule to add them. Changes to the submodule's HEAD commit can be recorded in the index with a plain "git add -u" and are shown with " M", like today. To avoid excessive clutter, show at most one of " ?", " m", and " M" for the submodule. They represent increasing levels of change --- the last one that applies is shown (e.g., " m" if there are both modified files and untracked files in the submodule, or " M" if the submodule's HEAD has been modified and it has untracked files). While making these changes, we need to make sure to not break porcelain level 1, which shares code with "status --short". We only change "git status --short". Non-short "git status" and "git status --porcelain=2" already handle these cases by showing more detail: $ git -C gerrit status --porcelain=2 1 .M S.MU 16 16 16 305c864db28eb0c77c8499bc04c87de3f849cf3c 305c864db28eb0c77c8499bc04c87de3f849cf3c plugins/replication $ git -C gerrit status [...] modified: plugins/replication (modified content, untracked content) Scripts caring about these distinctions should use --porcelain=2. Helped-by: Jonathan NiederSigned-off-by: Stefan Beller --- Documentation/git-status.txt | 9 +++ t/t3600-rm.sh| 18 ++ t/t7506-status-submodule.sh | 57 wt-status.c | 13 -- 4 files changed, 90 insertions(+), 7 deletions(-) diff --git a/Documentation/git-status.txt b/Documentation/git-status.txt index ba873657cf..01b457c322 100644 --- a/Documentation/git-status.txt +++ b/Documentation/git-status.txt @@ -181,6 +181,13 @@ in which case `XY` are `!!`. ! !ignored - +Submodules have more state and instead report + Mthe submodule has a different HEAD than +recorded in the index + mthe submodule has modified content + ?the submodule has untracked files + + If -b is used the short-format status is preceded by a line ## branchname tracking info @@ -210,6 +217,8 @@ field from the first filename). Third, filenames containing special characters are not specially formatted; no quoting or backslash-escaping is performed. +Any submodule changes are reported as modified `M` instead of `m` or single `?`. + Porcelain Format Version 2 ~~ diff --git a/t/t3600-rm.sh b/t/t3600-rm.sh index 5aa6db584c..a6e5c5bd56 100755 --- a/t/t3600-rm.sh +++ b/t/t3600-rm.sh @@ -268,6 +268,14 @@ cat >expect.modified actual && @@ -436,7 +444,7 @@ test_expect_success 'rm of a populated submodule with untracked files fails unle test -d submod && test -f submod/.git && git status -s -uno --ignore-submodules=none >actual && - test_cmp expect.modified actual && + test_cmp expect.modified_untracked actual && git rm -f submod && test ! -d submod && git status -s -uno --ignore-submodules=none >actual && @@ -621,7 +629,7 @@ test_expect_success 'rm of a populated nested submodule with different nested HE test -d submod && test -f submod/.git && git status -s -uno --ignore-submodules=none >actual && - test_cmp expect.modified actual && + test_cmp expect.modified_inside actual && git rm -f submod && test ! -d submod && git status -s -uno --ignore-submodules=none >actual && @@ -636,7 +644,7 @@ test_expect_success 'rm of a populated nested submodule with nested modification test -d submod && test -f submod/.git &&
[PATCH 2/7] submodule.c: factor out early loop termination in is_submodule_modified
This makes it easier for a follow up patch. Signed-off-by: Stefan Beller--- submodule.c | 15 +++ 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/submodule.c b/submodule.c index 2c667ac95a..e52cb8a958 100644 --- a/submodule.c +++ b/submodule.c @@ -1075,16 +1075,15 @@ unsigned is_submodule_modified(const char *path, int ignore_untracked) len = strbuf_read(, cp.out, 1024); line = buf.buf; while (len > 2) { - if ((line[0] == '?') && (line[1] == '?')) { + if ((line[0] == '?') && (line[1] == '?')) dirty_submodule |= DIRTY_SUBMODULE_UNTRACKED; - if (dirty_submodule & DIRTY_SUBMODULE_MODIFIED) - break; - } else { + else dirty_submodule |= DIRTY_SUBMODULE_MODIFIED; - if (ignore_untracked || - (dirty_submodule & DIRTY_SUBMODULE_UNTRACKED)) - break; - } + + if ((dirty_submodule & DIRTY_SUBMODULE_MODIFIED) && + ((dirty_submodule & DIRTY_SUBMODULE_UNTRACKED) || ignore_untracked)) + break; + next_line = strchr(line, '\n'); if (!next_line) break; -- 2.12.1.437.g2b7623d507
[PATCH v6 0/7] short status: improve reporting for submodule changes
v6: * kill the child once we know all information that we ask for, as an optimization * reordered the patches for that * strbuf_getwholeline instead of its _fd version. v5: * fixed rebase error in the first 2 patches * the last 3 patches introduce behavior change outside the scope of is_modified_submodule whereas the first 4 ought to just be local changes. Thanks, Stefan v4: * broken down in a lot of tiny patches. Jonathan wrote: > Patch 1/3 is the one that gives me pause, since I hadn't been able to > chase down all callers. Would it be feasible to split that into two: > one patch to switch to --porcelain=2 but not change behavior, and a > separate patch to improve what is stored in the dirty_submodule flags? This part is in the latest patch now. Thanks, Stefan v3: This comes as a series; first I'd like to refactor is_submodule_modified to take advantage of the new porcelain=2 plumbing switch to check for changes in the submodule. On top of the refactoring comes the actual change, which moved the rewriting of the submodule change indicator letter to the collection part. Thanks, Stefan Stefan Beller (8): submodule.c: port is_submodule_modified to use porcelain 2 submodule.c: use argv_array in is_submodule_modified submodule.c: convert is_submodule_modified to use strbuf_getwholeline_fd submodule.c: port is_submodule_modified to use porcelain 2 submodule.c: factor out early loop termination in is_submodule_modified submodule.c: stricter checking for submodules in is_submodule_modified short status: improve reporting for submodule changes submodule.c: correctly handle nested submodules in is_submodule_modified Documentation/git-status.txt | 9 +++ submodule.c | 56 --- t/t3600-rm.sh| 18 ++ t/t7506-status-submodule.sh | 57 wt-status.c | 13 -- 5 files changed, 116 insertions(+), 37 deletions(-) -- 2.12.1.438.gb674c4c09c
[PATCH 1/7] submodule.c: use argv_array in is_submodule_modified
struct argv_array is easier to use and maintain Signed-off-by: Stefan Beller--- submodule.c | 10 ++ 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/submodule.c b/submodule.c index 3200b7bb2b..2c667ac95a 100644 --- a/submodule.c +++ b/submodule.c @@ -1043,12 +1043,6 @@ unsigned is_submodule_modified(const char *path, int ignore_untracked) { ssize_t len; struct child_process cp = CHILD_PROCESS_INIT; - const char *argv[] = { - "status", - "--porcelain", - NULL, - NULL, - }; struct strbuf buf = STRBUF_INIT; unsigned dirty_submodule = 0; const char *line, *next_line; @@ -1066,10 +1060,10 @@ unsigned is_submodule_modified(const char *path, int ignore_untracked) } strbuf_reset(); + argv_array_pushl(, "status", "--porcelain", NULL); if (ignore_untracked) - argv[2] = "-uno"; + argv_array_push(, "-uno"); - cp.argv = argv; prepare_submodule_repo_env(_array); cp.git_cmd = 1; cp.no_stdin = 1; -- 2.12.1.437.g2b7623d507
Re: [PATCH 3/3] t7004, t7030: fix here-doc syntax errors
On Fri, Mar 24, 2017 at 11:04:27AM -0700, Junio C Hamano wrote: > Jeff Kingwrites: > > > It seems like t7030 should just skip_all when the GPG prereq is not > > met (it's not wrong to mark each test that's added, but it would have > > made this particular mistake harder). > > I'd leave that to be done by others after the dust settles ;-). > > Here is what I have right now (proposed log message has updates to > match rather obvious changes to the tests). Thanks, this looks good to me. -Peff
Re: [PATCH 3/3] t7004, t7030: fix here-doc syntax errors
On Fri, Mar 24, 2017 at 12:49:43PM -0400, Jeff King wrote: > On Fri, Mar 24, 2017 at 09:45:30AM -0700, Junio C Hamano wrote: > > > I actually think this uncovers another class of breakage. t7030 > > tests should be protected with GPG prereq and 'fourth-signed' that > > is made only with the prereq in the first test will not be found. > > It seems like t7030 should just skip_all when the GPG prereq is not > met (it's not wrong to mark each test that's added, but it would have > made this particular mistake harder). > > > t7004 probably has the same issue. > > These ones should be marked individually, though. I started to prepare a patch for t7030, but given that we want to do this all in one patch anyway (for bisectability), I think it probably makes sense to just add the missing GPG prereqs as part of the patch you posted. If somebody wants to convert t7030 to skip_all on top that's fine, but it's not that big a deal. -Peff
Re: [PATCH 3/3] t7004, t7030: fix here-doc syntax errors
Jeff Kingwrites: > It seems like t7030 should just skip_all when the GPG prereq is not > met (it's not wrong to mark each test that's added, but it would have > made this particular mistake harder). I'd leave that to be done by others after the dust settles ;-). Here is what I have right now (proposed log message has updates to match rather obvious changes to the tests). -- >8 -- From: Santiago Torres Date: Thu, 23 Mar 2017 18:28:47 -0400 Subject: [PATCH] t7004, t7030: fix here-doc syntax errors Jan Palus noticed that some here-doc are spelled incorrectly, resulting the entire remainder of the test snippet being slurped into the "expect" file as if it were data, e.g. in this sequence cat >expect Helped-by: Jeff King Signed-off-by: Santiago Torres Signed-off-by: Junio C Hamano --- t/t7004-tag.sh| 12 +--- t/t7030-verify-tag.sh | 12 +--- 2 files changed, 10 insertions(+), 14 deletions(-) diff --git a/t/t7004-tag.sh b/t/t7004-tag.sh index b53a2e5e41..f67bbb8abc 100755 --- a/t/t7004-tag.sh +++ b/t/t7004-tag.sh @@ -847,18 +847,16 @@ test_expect_success GPG 'verifying a forged tag should fail' ' test_must_fail git tag -v forged-tag ' -test_expect_success 'verifying a proper tag with --format pass and format accordingly' ' - cat >expect <<-\EOF +test_expect_success GPG 'verifying a proper tag with --format pass and format accordingly' ' + cat >expect <<-\EOF && tagname : signed-tag - EOF && + EOF git tag -v --format="tagname : %(tag)" "signed-tag" >actual && test_cmp expect actual ' -test_expect_success 'verifying a forged tag with --format fail and format accordingly' ' - cat >expect <<-\EOF - tagname : forged-tag - EOF && +test_expect_success GPG 'verifying a forged tag with --format should fail silently' ' + >expect && test_must_fail git tag -v --format="tagname : %(tag)" "forged-tag" >actual && test_cmp expect actual ' diff --git a/t/t7030-verify-tag.sh b/t/t7030-verify-tag.sh index d62ccbb98e..b4b49eeb08 100755 --- a/t/t7030-verify-tag.sh +++ b/t/t7030-verify-tag.sh @@ -125,18 +125,16 @@ test_expect_success GPG 'verify multiple tags' ' test_cmp expect.stderr actual.stderr ' -test_expect_success 'verifying tag with --format' ' - cat >expect <<-\EOF +test_expect_success GPG 'verifying tag with --format' ' + cat >expect <<-\EOF && tagname : fourth-signed - EOF && + EOF git verify-tag --format="tagname : %(tag)" "fourth-signed" >actual && test_cmp expect actual ' -test_expect_success 'verifying a forged tag with --format fail and format accordingly' ' - cat >expect <<-\EOF - tagname : 7th forged-signed - EOF && +test_expect_success GPG 'verifying a forged tag with --format should fail silently' ' + >expect && test_must_fail git verify-tag --format="tagname : %(tag)" $(cat forged1.tag) >actual-forged && test_cmp expect actual-forged ' -- 2.12.1-432-gf364f02724
Re: [PATCH v3 2/2] l10n: Add git-add.txt to localized man pages
Ævar Arnfjörð Bjarmasonwrites: > On Mon, Mar 20, 2017 at 11:05 PM, Junio C Hamano wrote: >> But more importantly, aren't we essentially adding an equivalent of >> >> cd Documentation && cat git-*.txt >> >> to our codebase? >> >> Surely we cannot avoid having a copy of all messages that are to be >> translated using msgid/msgstr based approach, and we already do so >> for end-user-facing in-program strings, but it just feels a bit too >> much having to carry a duplicate (and slightly a stale) copy of the >> entire documentation set around. For N languages, we'll have an >> equivalent for N copies of the English text, in addition to the >> translated documentation. > > As someone reading this thread from the sidelines you never elaborate > on why this is a problem worth solving (other than "a bit too much") > before everyone downthread jumped on trying to figure out how to solve > this out-of tree somehow. I do not particularly see the size as an issue that must be solved; to me, it is "nice to solve". But going back and finding this from Jean-Noel in an earlier message: ... This is one of the points raised in the first RFC mail. Splitting this part would help a lot manage the translations with their own workflow, would not clutter the main repo with files not really needed for packaging and would simplify dealing with the interaction with crowd translation websites which can directly push translation content to a git repo. there may be other benefits we may be able to reap from such a split.
Re: [PATCH] read-cache: call verify_hdr() in a background thread
Jeff Hostetler wrote: > On 3/24/2017 12:35 PM, Jonathan Nieder wrote: >> What happens if there is an error before the code reaches the end of >> the function? I think there needs to be a verify_hdr_finish call in >> the 'unmap:' cleanup section. > > But the "unmap" section calls die(). Do need to join first ?? > (It's OK if we do, just asking.) Good point. Now I wonder why the 'unmap:' section exists at all. $ git log -Sunmap: read-cache.c commit e83c5163316f89bfbde7d9ab23ca2e25604af290 Author: Linus TorvaldsDate: Thu Apr 7 15:13:13 2005 -0700 Initial revision of "git", the information manager from hell So the unmap: section has been there since day one. At that point it used 'return error(...)', so it made more sense. Where did the die() come from, then? commit 5d1a5c02e8ac1c16688ea4a44512245f25a49f8a Author: Linus Torvalds Date: Sat Oct 1 13:24:27 2005 -0700 [PATCH] Better error reporting for "git status" I think it should be safe to eliminate the 'unmap' section altogether and that that change just forgot to, but in any case it's orthogonal to your patch. Thanks and sorry for the confusion, Jonathan
Re: [PATCH v2 0/7] thread lazy_init_name_hash
Jeff Hostetlerwrites: > WRT the assert() in name-hash.c, Stefan suggested converting it > to an if-!-die form in an earlier message in this thread. I'm OK > with that or with removing the assert completely. I actually am OK with leaving things as they are ;-)
Re: [PATCH] name-hash: add test-lazy-init-name-hash to .gitignore
On 24/03/17 17:26, Ramsay Jones wrote: > > Signed-off-by: Ramsay Jones> --- > > Hi Jeff, > > If you need to re-roll your 'jh/memihash-opt' branch, could you please > squash this into the relevant patch (commit f25dde4fbf, "name-hash: add > test-lazy-init-name-hash", 23-03-2017). > > Thanks! > > ATB, > Ramsay Jones > > t/helper/.gitignore | 1 + > 1 file changed, 1 insertion(+) > > diff --git a/t/helper/.gitignore b/t/helper/.gitignore > index 5f68aa8f8..57bdd4b8e 100644 > --- a/t/helper/.gitignore > +++ b/t/helper/.gitignore > @@ -12,6 +12,7 @@ > /test-hashmap > /test-index-version > /test-line-buffer > +/test-lazy-init-name-hash Heh, you could even put it before the '/test-line-buffer' entry! ;-) Ahem. ATB, Ramsay Jones > /test-match-trees > /test-mergesort > /test-mktemp >
Re: [PATCH v2] log: if --decorate is not given, default to --decorate=auto
Alex Henriewrites: > +test_expect_success TTY 'log output on a TTY' ' > + git log --oneline --decorate >expect.short && > + > + test_terminal git log --oneline >actual && > + test_cmp expect.short actual > +' > + Nice. I didn't know test_terminal was so easy to use ;-) Looks good. Will queue. Thanks.
Re: [PATCH] read-cache: call verify_hdr() in a background thread
On 3/24/2017 12:35 PM, Jonathan Nieder wrote: g...@jeffhostetler.com wrote: From: Jeff HostetlerTeash do_read_index() in read-cache.c to call verify_hdr() ... Nice. Do you have example commands I can run to reproduce that benchmark? (Even better if you can phrase that as a patch against t/perf/.) I debated doing a t/perf and/or t/helper to demonstrate this like I did for the lazy-init-name-hash changes the other day, but decided against it. I'll put together something and include it in the next version. [...] --- a/read-cache.c +++ b/read-cache.c @@ -1564,6 +1564,83 @@ static void post_read_index_from(struct index_state *istate) tweak_untracked_cache(istate); } +#ifdef NO_PTHREADS + +struct verify_hdr_thread_data { + struct cache_header *hdr; + size_t size; 'size' appears to always be cast to an unsigned long when it's used. Why not use unsigned long consistently? +}; + +/* + * Non-threaded version does all the work immediately. + * Returns < 0 on error or bad signature. + */ +static int verify_hdr_start(struct verify_hdr_thread_data *d) +{ + return verify_hdr(d->hdr, (unsigned long)d->size); +} + +static int verify_hdr_finish(struct verify_hdr_thread_data *d) +{ + return 0; +} + +#else + +#include Please put this at the top of the file with other #includes. One simple way to do that is to #include "thread-utils.h" at the top of the file unconditionally. + +/* + * Require index file to be larger than this threshold before + * we bother using a background thread to verify the SHA. + */ +#define VERIFY_HDR_THRESHOLD(1024) nits: (1) no need for parens for a numerical macro like this (2) comment can be made briefer and more explicit: /* * Index size threshold in bytes before it's worth bothering to * use a background thread to verify the index file. */ How was this value chosen? This was somewhat at random. I'll update with the t/perf stuff. + +struct verify_hdr_thread_data { + pthread_t thread_id; + struct cache_header *hdr; + size_t size; + int result; +}; All structs are data. Other parts of git seem to name this kind of callback cookie *_cb_data, so perhaps verify_hdr_cb_data? On the other hand this seems to also be used by the caller as a handle to the async verify_hdr process. Maybe verify_hdr_state? This seems to be doing something similar to the existing 'struct async' interface. Could it use that instead, or does it incur too much overhead? An advantage would be avoiding having to handle the NO_PTHREADS ifdef-ery. + +/* + * Thread proc to run verify_hdr() computation in a background thread. + */ +static void *verify_hdr_thread_proc(void *_data) Please don't name identifiers with a leading underscore --- those are reserved names. +{ + struct verify_hdr_thread_data *d = _data; + d->result = verify_hdr(d->hdr, (unsigned long)d->size); + return NULL; +} I was just modeling the code on what I saw in preload-index.c. There the #ifdef side defines the trivial functions. Then the #else and the #include, the struct thread_data, and then the preload_thread(void *_data) function declaration. But blame reports that code dating back to 2008. Is there an example of a newer preferred style somewhere ? + +/* + * Threaded version starts background thread and returns zero + * to indicate that we don't know the hash is bad yet. If the + * index is too small, we just do the work imediately. + */ +static int verify_hdr_start(struct verify_hdr_thread_data *d) This comment restates what the code says. Is there background or something about the intent behind the code that could be said instead to help the reader? Otherwise I'd suggest removing the comment. [...] What happens if there is an error before the code reaches the end of the function? I think there needs to be a verify_hdr_finish call in the 'unmap:' cleanup section. But the "unmap" section calls die(). Do need to join first ?? (It's OK if we do, just asking.) The rest looks reasonable. Thanks and hope that helps, Jonathan Thanks, Jeff
[PATCH 2/4] fast-import: use xsnprintf for formatting headers
The stream_blob() function checks the return value of snprintf and dies. This is more simply done with xsnprintf (and matches the similar call in store_object). The message the user would get is less specific, but since the point is that this _shouldn't_ ever happen, that's OK. Signed-off-by: Jeff King--- fast-import.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/fast-import.c b/fast-import.c index 4e0f3f5dd..4a057e81f 100644 --- a/fast-import.c +++ b/fast-import.c @@ -1237,9 +1237,7 @@ static void stream_blob(uintmax_t len, unsigned char *sha1out, uintmax_t mark) sha1file_checkpoint(pack_file, ); offset = checkpoint.offset; - hdrlen = snprintf((char *)out_buf, out_sz, "blob %" PRIuMAX, len) + 1; - if (out_sz <= hdrlen) - die("impossibly large object header"); + hdrlen = xsnprintf((char *)out_buf, out_sz, "blob %" PRIuMAX, len) + 1; git_SHA1_Init(); git_SHA1_Update(, out_buf, hdrlen); -- 2.12.1.843.g1937c56c2
[PATCH 4/4] pack.h: define largest possible encoded object size
Several callers use fixed buffers for storing the pack object header, and they've picked 10 as a magic number. This is reasonable, since it handles objects up to 2^67. But let's give them a constant so it's clear that the number isn't pulled out of thin air. Signed-off-by: Jeff King--- builtin/pack-objects.c | 6 -- pack.h | 6 ++ 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/builtin/pack-objects.c b/builtin/pack-objects.c index cf3fc50a2..84af7c232 100644 --- a/builtin/pack-objects.c +++ b/builtin/pack-objects.c @@ -239,7 +239,8 @@ static unsigned long write_no_reuse_object(struct sha1file *f, struct object_ent unsigned long limit, int usable_delta) { unsigned long size, datalen; - unsigned char header[10], dheader[10]; + unsigned char header[MAX_PACK_OBJECT_HEADER], + dheader[MAX_PACK_OBJECT_HEADER]; unsigned hdrlen; enum object_type type; void *buf; @@ -353,7 +354,8 @@ static off_t write_reuse_object(struct sha1file *f, struct object_entry *entry, off_t offset; enum object_type type = entry->type; off_t datalen; - unsigned char header[10], dheader[10]; + unsigned char header[MAX_PACK_OBJECT_HEADER], + dheader[MAX_PACK_OBJECT_HEADER]; unsigned hdrlen; if (entry->delta) diff --git a/pack.h b/pack.h index 87e456d5e..5c2158746 100644 --- a/pack.h +++ b/pack.h @@ -84,6 +84,12 @@ extern int verify_pack(struct packed_git *, verify_fn fn, struct progress *, uin extern off_t write_pack_header(struct sha1file *f, uint32_t); extern void fixup_pack_header_footer(int, unsigned char *, const char *, uint32_t, unsigned char *, off_t); extern char *index_pack_lockfile(int fd); + +/* + * The "hdr" output buffer should be at least this big, which will handle sizes + * up to 2^67. + */ +#define MAX_PACK_OBJECT_HEADER 10 extern int encode_in_pack_object_header(unsigned char *hdr, int hdr_len, enum object_type, uintmax_t); -- 2.12.1.843.g1937c56c2
[PATCH] name-hash: add test-lazy-init-name-hash to .gitignore
Signed-off-by: Ramsay Jones--- Hi Jeff, If you need to re-roll your 'jh/memihash-opt' branch, could you please squash this into the relevant patch (commit f25dde4fbf, "name-hash: add test-lazy-init-name-hash", 23-03-2017). Thanks! ATB, Ramsay Jones t/helper/.gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/t/helper/.gitignore b/t/helper/.gitignore index 5f68aa8f8..57bdd4b8e 100644 --- a/t/helper/.gitignore +++ b/t/helper/.gitignore @@ -12,6 +12,7 @@ /test-hashmap /test-index-version /test-line-buffer +/test-lazy-init-name-hash /test-match-trees /test-mergesort /test-mktemp -- 2.12.0
[PATCH 3/4] encode_in_pack_object_header: respect output buffer length
The encode_in_pack_object_header() writes a variable-length header to an output buffer, but it doesn't actually know long the buffer is. At first glance, this looks like it might be possible to overflow. In practice, this is probably impossible. The smallest buffer we use is 10 bytes, which would hold the header for an object up to 2^67 bytes. Obviously we're not likely to see such an object, but we might worry that an object could lie about its size (causing us to overflow before we realize it does not actually have that many bytes). But the argument is passed as a uintmax_t. Even on systems that have __int128 available, uintmax_t is typically restricted to 64-bit by the ABI. So it's unlikely that a system exists where this could be exploited. Still, it's easy enough to use a normal out/len pair and make sure we don't write too far. That protects the hypothetical 128-bit system, makes it harder for callers to accidentally specify a too-small buffer, and makes the resulting code easier to audit. Note that the one caller in fast-import tried to catch such a case, but did so _after_ the call (at which point we'd have already overflowed!). This check can now go away. Signed-off-by: Jeff King--- builtin/pack-objects.c | 6 -- bulk-checkin.c | 2 +- fast-import.c | 10 +- pack-write.c | 5 - pack.h | 3 ++- 5 files changed, 16 insertions(+), 10 deletions(-) diff --git a/builtin/pack-objects.c b/builtin/pack-objects.c index 16517f263..cf3fc50a2 100644 --- a/builtin/pack-objects.c +++ b/builtin/pack-objects.c @@ -286,7 +286,8 @@ static unsigned long write_no_reuse_object(struct sha1file *f, struct object_ent * The object header is a byte of 'type' followed by zero or * more bytes of length. */ - hdrlen = encode_in_pack_object_header(type, size, header); + hdrlen = encode_in_pack_object_header(header, sizeof(header), + type, size); if (type == OBJ_OFS_DELTA) { /* @@ -358,7 +359,8 @@ static off_t write_reuse_object(struct sha1file *f, struct object_entry *entry, if (entry->delta) type = (allow_ofs_delta && entry->delta->idx.offset) ? OBJ_OFS_DELTA : OBJ_REF_DELTA; - hdrlen = encode_in_pack_object_header(type, entry->size, header); + hdrlen = encode_in_pack_object_header(header, sizeof(header), + type, entry->size); offset = entry->in_pack_offset; revidx = find_pack_revindex(p, offset); diff --git a/bulk-checkin.c b/bulk-checkin.c index 991b4a13e..ddb6070c4 100644 --- a/bulk-checkin.c +++ b/bulk-checkin.c @@ -105,7 +105,7 @@ static int stream_to_pack(struct bulk_checkin_state *state, git_deflate_init(, pack_compression_level); - hdrlen = encode_in_pack_object_header(type, size, obuf); + hdrlen = encode_in_pack_object_header(obuf, sizeof(obuf), type, size); s.next_out = obuf + hdrlen; s.avail_out = sizeof(obuf) - hdrlen; diff --git a/fast-import.c b/fast-import.c index 4a057e81f..f6f416f20 100644 --- a/fast-import.c +++ b/fast-import.c @@ -1173,7 +1173,8 @@ static int store_object( delta_count_by_type[type]++; e->depth = last->depth + 1; - hdrlen = encode_in_pack_object_header(OBJ_OFS_DELTA, deltalen, hdr); + hdrlen = encode_in_pack_object_header(hdr, sizeof(hdr), + OBJ_OFS_DELTA, deltalen); sha1write(pack_file, hdr, hdrlen); pack_size += hdrlen; @@ -1184,7 +1185,8 @@ static int store_object( pack_size += sizeof(hdr) - pos; } else { e->depth = 0; - hdrlen = encode_in_pack_object_header(type, dat->len, hdr); + hdrlen = encode_in_pack_object_header(hdr, sizeof(hdr), + type, dat->len); sha1write(pack_file, hdr, hdrlen); pack_size += hdrlen; } @@ -1246,9 +1248,7 @@ static void stream_blob(uintmax_t len, unsigned char *sha1out, uintmax_t mark) git_deflate_init(, pack_compression_level); - hdrlen = encode_in_pack_object_header(OBJ_BLOB, len, out_buf); - if (out_sz <= hdrlen) - die("impossibly large object header"); + hdrlen = encode_in_pack_object_header(out_buf, out_sz, OBJ_BLOB, len); s.next_out = out_buf + hdrlen; s.avail_out = out_sz - hdrlen; diff --git a/pack-write.c b/pack-write.c index 88bc7f9f7..c057513f1 100644 --- a/pack-write.c +++ b/pack-write.c @@ -304,7 +304,8 @@ char *index_pack_lockfile(int ip_out) * - each byte afterwards: low seven bits are size continuation, *with the high bit being "size continues" */ -int encode_in_pack_object_header(enum object_type type, uintmax_t
[PATCH 1/4] fast-import: use xsnprintf for writing sha1s
When we have to write a sha1 with a newline, we do so by copying both into a single buffer, so that we can issue a single write() call. We use snprintf but don't bother to check the output, since we know it will fit. However, we should use xsnprintf() in such a case so that we're notified if our assumption turns out to be wrong (and to make it easier to audit for unchecked snprintf calls). Signed-off-by: Jeff King--- This is ready for conversion to oid_to_hex, too, but I avoided that here. The buffer would need to be allocated with the new GIT_MAX_HEXSZ, which is not yet available. So I figured it was better to leave it than half-convert it and leave brian wondering whether it's really supposed to be GIT_MAX_HEXSZ or GIT_SHA1_HEXSZ. fast-import.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fast-import.c b/fast-import.c index 41a539f97..4e0f3f5dd 100644 --- a/fast-import.c +++ b/fast-import.c @@ -3003,7 +3003,7 @@ static void parse_get_mark(const char *p) if (!oe) die("Unknown mark: %s", command_buf.buf); - snprintf(output, sizeof(output), "%s\n", sha1_to_hex(oe->idx.sha1)); + xsnprintf(output, sizeof(output), "%s\n", sha1_to_hex(oe->idx.sha1)); cat_blob_write(output, 41); } -- 2.12.1.843.g1937c56c2
[PATCH 0/4] a few minor buffer cleanups in fast-import
I don't think any of these is a triggerable bug. They're just cleanups to make it more obvious that the code is doing the right thing (and making it harder to do the wrong thing). [1/4]: fast-import: use xsnprintf for writing sha1s [2/4]: fast-import: use xsnprintf for formatting headers [3/4]: encode_in_pack_object_header: respect output buffer length [4/4]: pack.h: define largest possible encoded object size builtin/pack-objects.c | 12 bulk-checkin.c | 2 +- fast-import.c | 16 +++- pack-write.c | 5 - pack.h | 9 - 5 files changed, 28 insertions(+), 16 deletions(-) -Peff
[PATCH] push: allow atomic flag via configuration
Added a "push.atomic" option to git-config to allow site-specific configuration of the atomic flag of git push Signed-off-by: Romuald Brunet--- Documentation/config.txt | 5 + builtin/push.c | 6 ++ contrib/completion/git-completion.bash | 1 + t/t5543-atomic-push.sh | 31 +++ 4 files changed, 43 insertions(+) diff --git a/Documentation/config.txt b/Documentation/config.txt index 0d8df5a9f..c826c86ae 100644 --- a/Documentation/config.txt +++ b/Documentation/config.txt @@ -2555,6 +2555,11 @@ new default). -- +push.atomic:: + If set to true enable `--atomic` option by default. You + may override this configuration at time of push by specifying + `--no-atomic`. + push.followTags:: If set to true enable `--follow-tags` option by default. You may override this configuration at time of push by specifying diff --git a/builtin/push.c b/builtin/push.c index 5c22e9f2e..03066f3f7 100644 --- a/builtin/push.c +++ b/builtin/push.c @@ -498,6 +498,12 @@ static int git_push_config(const char *k, const char *v, void *cb) const char *value; if (!git_config_get_value("push.recursesubmodules", )) recurse_submodules = parse_push_recurse_submodules_arg(k, value); + } else if (!strcmp(k, "push.atomic")) { + if (git_config_bool(k, v)) + *flags |= TRANSPORT_PUSH_ATOMIC; + else + *flags &= ~TRANSPORT_PUSH_ATOMIC; + return 0; } return git_default_config(k, v, NULL); diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash index fc32286a4..8d38f5f8f 100644 --- a/contrib/completion/git-completion.bash +++ b/contrib/completion/git-completion.bash @@ -2396,6 +2396,7 @@ _git_config () pull.octopus pull.twohead push.default + push.atomic push.followTags rebase.autosquash rebase.stat diff --git a/t/t5543-atomic-push.sh b/t/t5543-atomic-push.sh index 3480b3300..7c573b85b 100755 --- a/t/t5543-atomic-push.sh +++ b/t/t5543-atomic-push.sh @@ -191,4 +191,35 @@ test_expect_success 'atomic push is not advertised if configured' ' test_refs master HEAD@{1} ' +test_expect_success 'atomic option possible via git-config' ' + # prepare the repo + mk_repo_pair && + ( + cd workbench && + test_commit one && + git checkout -b second master && + test_commit two && + git push --mirror up + ) && + # a third party modifies the server side: + ( + cd upstream && + git checkout second && + git tag test_tag second + ) && + # see if we can now push both branches. + ( + cd workbench && + git config push.atomic true && + git checkout master && + test_commit three && + git checkout second && + test_commit four && + git tag test_tag && + test_must_fail git push --tags up master second + ) && + test_refs master HEAD@{3} && + test_refs second HEAD@{1} +' + test_done -- 2.12.0.dirty
Re: [PATCH v1 2/3] sub-process: refactor the filter process code into a reusable module
Junio C Hamanowrites: > ... > And for something of sub-process.[ch]'s size, I suspect that it > would have more than 1 such logical unit to be independently > refactored, so in total, I would suspect the series would become > > 1 (boring mechanical part) + > 2 or more (refactoring) + > 1 (final movement) > > i.e. 4 or more patches? To avoid confusion (although readers may not require), even though I explained "boring mechanical part" first and "refactoring", that was purely for explanation. In practice, I would expect that it would be easier to both do and review if refactoring is done with the original name. A function that will keep its name in the final result (e.g. start_multi_file_filter()) will call a new and more generic helper function. The new helper may start using the new name from the get-go (e.g. subprocess_start()), but the data types it shares with the original part of the code (e.g. 'struct cmd2process') may still be using the original name. And after completing "2 or more" refactoring would be a good place to do the remaining "boring mechanical rename". IOW, the count above could be 2 or more (refactoring) + 1 (boring mechanical part) + 1 (final movement) and I didn't mean to say that you need to rename first. What we want is "if you need to have a single large patch that cannot be split, see if you can make it purely mechanical.", as a single large patch that is _not_ mechanical conversion is the worst kind of patch for reviewers.