* cherry-pick and 'log --no-walk' and ordering @ 2012-08-10 20:41 Martin von Zweigbergk 2012-08-10 21:38 ` Junio C Hamano 0 siblings, 1 reply; 37+ messages in thread From: Martin von Zweigbergk @ 2012-08-10 20:41 UTC (permalink / raw) To: Git; +Cc: Christian Couder A while ago when I was looking at revision.c, I was surprised to see that commits are sorted even when --no-walk is passed, but as 8e64006 (Teach revision machinery about --no-walk, 2007-07-24) points out, this can be useful for doing $ git log --abbrev-commit --pretty=oneline --decorate --all --no-walk and get the result sorted by date. However, it can also be useful _not_ to get a result sorted by date, e.g. when doing something like "<generate an ordered list of revisions> | git rev-list --oneline --no-walk --stdin". Would a --no-sort option to rev-list be appreciated or are there better solutions? There is also cherry-pick/revert, which I _think_ does not really want the revisions sorted. cherry-pick implicitly reverses the order of the walk, so 'git cherry-pick branch~2..branch' applies them in the right order (at least in the absence of clock skew). The documentation for cherry-pick suggests "git rev-list --reverse master -- README | git cherry-pick -n --stdin", which I think makes no sense -- this would reverse the output from rev-list only to have it reversed again in cherry-pick, if it wasn't for the sorting by date. I think the --reverse passed to rev-list might even break the cherry-pick if there are commits in non-increasing date order. This is also supported by the fact that test still pass after applying the patch below. I think the test cases make more sense after the patch. Do others agree with the analysis? I suppose it's too late to change cherry-pick to start differentiating between "git cherry-pick commit1 commit2" and "git cherry-pick commit2 commit1", but I think we should at least update the documentation as in the patch below (or maybe even with a --topo-order passed to cherry-pick?). We could possibly change cherry-pick's ordering from the default ordering to topological ordering. Martin Sorry about the mangled whitespace below; just for reference, not intended to be applied. diff --git a/Documentation/git-cherry-pick.txt b/Documentation/git-cherry-pick.txt index 0e170a5..454e205 100644 --- a/Documentation/git-cherry-pick.txt +++ b/Documentation/git-cherry-pick.txt @@ -181,7 +181,7 @@ EXAMPLES are in next but not HEAD to the current branch, creating a new commit for each new change. -`git rev-list --reverse master -- README | git cherry-pick -n --stdin`:: +`git rev-list master -- README | git cherry-pick -n --stdin`:: Apply the changes introduced by all commits on the master branch that touched README to the working tree and index, diff --git a/t/t3508-cherry-pick-many-commits.sh b/t/t3508-cherry-pick-many-commits.sh index 75f7ff4..020baaf 100755 --- a/t/t3508-cherry-pick-many-commits.sh +++ b/t/t3508-cherry-pick-many-commits.sh @@ -164,7 +164,7 @@ test_expect_success 'cherry-pick --stdin works' ' git checkout -f master && git reset --hard first && test_tick && - git rev-list --reverse first..fourth | git cherry-pick --stdin && + git rev-list first..fourth | git cherry-pick --stdin && git diff --quiet other && git diff --quiet HEAD other && check_head_differs_from fourth diff --git a/t/t3510-cherry-pick-sequence.sh b/t/t3510-cherry-pick-sequence.sh index f4e6450..9e28910 100755 --- a/t/t3510-cherry-pick-sequence.sh +++ b/t/t3510-cherry-pick-sequence.sh @@ -400,7 +400,7 @@ test_expect_success '--continue of single-pick respects -x' ' test_expect_success '--continue respects -x in first commit in multi-pick' ' pristine_detach initial && - test_must_fail git cherry-pick -x picked anotherpick && + test_must_fail git cherry-pick -x anotherpick picked && echo c >foo && git add foo && git cherry-pick --continue && @@ -430,7 +430,7 @@ test_expect_success '--signoff is not automatically propagated to resolved confl test_expect_success '--signoff dropped for implicit commit of resolution, multi-pick case' ' pristine_detach initial && - test_must_fail git cherry-pick -s picked anotherpick && + test_must_fail git cherry-pick -s anotherpick picked && echo c >foo && git add foo && git cherry-pick --continue && ^ permalink raw reply related [flat|nested] 37+ messages in thread
* Re: cherry-pick and 'log --no-walk' and ordering 2012-08-10 20:41 cherry-pick and 'log --no-walk' and ordering Martin von Zweigbergk @ 2012-08-10 21:38 ` Junio C Hamano 2012-08-11 5:34 ` Martin von Zweigbergk 0 siblings, 1 reply; 37+ messages in thread From: Junio C Hamano @ 2012-08-10 21:38 UTC (permalink / raw) To: Martin von Zweigbergk; +Cc: Git, Christian Couder Martin von Zweigbergk <martin.von.zweigbergk@gmail.com> writes: > There is also cherry-pick/revert, which I _think_ does not really want > the revisions sorted. Yes, I think sequencer.c::prepare_revs() is wrong to unconditoinally call prepare_revision_walk(). It instead should first check the revs->pending.objects list to see if what was given by the caller is a mere collection of individual objects or a range expression (i.e. check if any of them is marked with UNINTERESTING), and refrain from going into the body of the preparation steps, which has to involve sorting. I think we had to fix a bug in "git show" coming from a similar root cause, but the bug manifested in the opposite direction. ^ permalink raw reply [flat|nested] 37+ messages in thread
* Re: cherry-pick and 'log --no-walk' and ordering 2012-08-10 21:38 ` Junio C Hamano @ 2012-08-11 5:34 ` Martin von Zweigbergk 2012-08-11 6:28 ` Junio C Hamano 0 siblings, 1 reply; 37+ messages in thread From: Martin von Zweigbergk @ 2012-08-11 5:34 UTC (permalink / raw) To: Junio C Hamano; +Cc: Git, Christian Couder On Fri, Aug 10, 2012 at 2:38 PM, Junio C Hamano <gitster@pobox.com> wrote: > Martin von Zweigbergk <martin.von.zweigbergk@gmail.com> writes: > >> There is also cherry-pick/revert, which I _think_ does not really want >> the revisions sorted. > > Yes, I think sequencer.c::prepare_revs() is wrong to unconditoinally > call prepare_revision_walk(). > > It instead should first check the revs->pending.objects list to see > if what was given by the caller is a mere collection of individual > objects or a range expression (i.e. check if any of them is marked > with UNINTERESTING), and refrain from going into the body of the > preparation steps, which has to involve sorting. Do you mean "has to involve sorting" as in "has to involve sorting in order not to break current users of e.g. 'git log --no-walk --branches'" or "revision walking inherently involves sorting"? My current working assumption is that it is the former. I will make rev_info.no_walk a tri-state {walk, no-walk-sorted, no-walk-unsorted}. The third state would be used from cherry-pick/revert (and maybe git-show, although it should make no difference). I would also expose the third state to rev-list's command line, maybe as --no-walk=unsorted. Actually, all but command-line parsing is done now and test seem fine, with quite a small patch: $ git diff --stat builtin/log.c | 2 +- builtin/revert.c | 2 +- revision.c | 5 +++-- revision.h | 6 +++++- 4 files changed, 10 insertions(+), 5 deletions(-) Did you see a problem with this approach, since you said that sequencer shouldn't unconditionally call prepare_revision_walk()? I can see that git-show needs to go through revs->pending.objects because it handles tags and stuff, but cherry-pick/revert only seem to need the revisions. Martin ^ permalink raw reply [flat|nested] 37+ messages in thread
* Re: cherry-pick and 'log --no-walk' and ordering 2012-08-11 5:34 ` Martin von Zweigbergk @ 2012-08-11 6:28 ` Junio C Hamano 2012-08-13 6:27 ` [PATCH 0/4] " y [not found] ` <1344839240-17402-1-git-send-email-y> 0 siblings, 2 replies; 37+ messages in thread From: Junio C Hamano @ 2012-08-11 6:28 UTC (permalink / raw) To: Martin von Zweigbergk; +Cc: Git, Christian Couder Martin von Zweigbergk <martin.von.zweigbergk@gmail.com> writes: > On Fri, Aug 10, 2012 at 2:38 PM, Junio C Hamano <gitster@pobox.com> wrote: >> Martin von Zweigbergk <martin.von.zweigbergk@gmail.com> writes: >> >>> There is also cherry-pick/revert, which I _think_ does not really want >>> the revisions sorted. >> >> Yes, I think sequencer.c::prepare_revs() is wrong to unconditoinally >> call prepare_revision_walk(). >> >> It instead should first check the revs->pending.objects list to see >> if what was given by the caller is a mere collection of individual >> objects or a range expression (i.e. check if any of them is marked >> with UNINTERESTING), and refrain from going into the body of the >> preparation steps, which has to involve sorting. > > Do you mean "has to involve sorting" as in "has to involve sorting in > order not to break current users of e.g. 'git log --no-walk > --branches'" or "revision walking inherently involves sorting"? Range limited revision walking, e.g. "git cherry-pick A..B D~4..D", fundamentally implies sorting and you cannot assume B would appear before D only because B comes before D on the command line (B may even be inside D~4..D range in which case it would not even appear in the final output). Any caller that wants to retrieve the objects given from the command line in the order the user gave it, e.g. "git cherry-pick A B C", using setup_revisions() and without walking the history, must look at revs->pending.objects without calling prepare_revision_walk(). ^ permalink raw reply [flat|nested] 37+ messages in thread
* [PATCH 0/4] Re: cherry-pick and 'log --no-walk' and ordering 2012-08-11 6:28 ` Junio C Hamano @ 2012-08-13 6:27 ` y 2012-08-13 7:17 ` Junio C Hamano 2012-08-29 6:15 ` [PATCH v2 0/3] revision (no-)walking in order Martin von Zweigbergk [not found] ` <1344839240-17402-1-git-send-email-y> 1 sibling, 2 replies; 37+ messages in thread From: y @ 2012-08-13 6:27 UTC (permalink / raw) To: Junio C Hamano; +Cc: git, Christian Couder, Martin von Zweigbergk From: Martin von Zweigbergk <martin.von.zweigbergk@gmail.com> This series adds supports for 'git log --no-walk=unsorted', which should be useful for the re-roll of my mz/rebase-range series. It also addresses the bug in cherry-pick/revert, which makes it sort revisions by date. On Fri, Aug 10, 2012 at 11:28 PM, Junio C Hamano <gitster@pobox.com> wrote: > Range limited revision walking, e.g. "git cherry-pick A..B D~4..D", > fundamentally implies sorting and you cannot assume B would appear > before D only because B comes before D on the command line (B may > even be inside D~4..D range in which case it would not even appear > in the final output). Sorry, I probably wasn't clear; I mentioned "revision walking", but I only meant the no-walk case. I hope the patches make sense. Martin von Zweigbergk (4): teach log --no-walk=unsorted, which avoids sorting revisions passed to cherry-pick should be in "default" order cherry-pick/revert: respect order of revisions to pick cherry-pick/revert: default to topological sorting Documentation/git-cherry-pick.txt | 2 +- builtin/log.c | 2 +- builtin/revert.c | 3 ++- revision.c | 18 +++++++++++++++--- revision.h | 6 +++++- t/t3508-cherry-pick-many-commits.sh | 2 +- t/t3510-cherry-pick-sequence.sh | 4 ++-- t/t4202-log.sh | 10 ++++++++++ 8 files changed, 37 insertions(+), 10 deletions(-) -- 1.7.11.1.104.ge7b44f1 ^ permalink raw reply [flat|nested] 37+ messages in thread
* Re: [PATCH 0/4] Re: cherry-pick and 'log --no-walk' and ordering 2012-08-13 6:27 ` [PATCH 0/4] " y @ 2012-08-13 7:17 ` Junio C Hamano 2012-08-13 7:26 ` Junio C Hamano 2012-08-13 16:09 ` Martin von Zweigbergk 2012-08-29 6:15 ` [PATCH v2 0/3] revision (no-)walking in order Martin von Zweigbergk 1 sibling, 2 replies; 37+ messages in thread From: Junio C Hamano @ 2012-08-13 7:17 UTC (permalink / raw) To: Martin von Zweigbergk; +Cc: git, Christian Couder, Martin von Zweigbergk y@google.com writes: [Administrivia: I somehow doubt y@google.com would reach you, and futzed with the To: line above] > From: Martin von Zweigbergk <martin.von.zweigbergk@gmail.com> > > This series adds supports for 'git log --no-walk=unsorted', which > should be useful for the re-roll of my mz/rebase-range series. It also > addresses the bug in cherry-pick/revert, which makes it sort revisions > by date. > > On Fri, Aug 10, 2012 at 11:28 PM, Junio C Hamano <gitster@pobox.com> wrote: >> Range limited revision walking, e.g. "git cherry-pick A..B D~4..D", >> fundamentally implies sorting and you cannot assume B would appear >> before D only because B comes before D on the command line (B may >> even be inside D~4..D range in which case it would not even appear >> in the final output). > > Sorry, I probably wasn't clear; I mentioned "revision walking", but I > only meant the no-walk case. I hope the patches make sense. I actually think --no-walk, especially when given any negative revision, that sorts is fundamentally a flawed concept (it led to the inconsistency that made "git show A..B C" vs "git show C A..B" behave differently, which we had to fix recently). Would anything break if we take your patch, but without two possibilities to revs->no_walk option (i.e. we never sort under no_walk)? That is, the core of your change would become something like this: revision.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/revision.c b/revision.c index 9e8f47a..589d17f 100644 --- a/revision.c +++ b/revision.c @@ -2116,12 +2116,12 @@ int prepare_revision_walk(struct rev_info *revs) } e++; } - commit_list_sort_by_date(&revs->commits); if (!revs->leak_pending) free(list); if (revs->no_walk) return 0; + commit_list_sort_by_date(&revs->commits); if (revs->limited) if (limit_list(revs) < 0) return -1; ^ permalink raw reply related [flat|nested] 37+ messages in thread
* Re: [PATCH 0/4] Re: cherry-pick and 'log --no-walk' and ordering 2012-08-13 7:17 ` Junio C Hamano @ 2012-08-13 7:26 ` Junio C Hamano 2012-08-13 16:09 ` Martin von Zweigbergk 1 sibling, 0 replies; 37+ messages in thread From: Junio C Hamano @ 2012-08-13 7:26 UTC (permalink / raw) To: Martin von Zweigbergk; +Cc: git, Christian Couder Junio C Hamano <gitster@pobox.com> writes: > Would anything break if we take your patch, but without two > possibilities to revs->no_walk option (i.e. we never sort under > no_walk)? By the way, by "would anything break", I do not just mean if our existing tests trigger failures from "test_expect_success"; I suspect some do assume the sorting behaviour. I am wondering if the sorting makes sense in the real users; in other words, if the failing tests, if any, are expecting sensible and useful behaviour. After all, the sorting by the commit timestamp is made solely to optimize the limit_list() which wants to traverse commits ancestry near the tip of the history, and sorting by the commit timestamp is done because it is usually a good and quick approximation for topological sorting. ^ permalink raw reply [flat|nested] 37+ messages in thread
* Re: [PATCH 0/4] Re: cherry-pick and 'log --no-walk' and ordering 2012-08-13 7:17 ` Junio C Hamano 2012-08-13 7:26 ` Junio C Hamano @ 2012-08-13 16:09 ` Martin von Zweigbergk 2012-08-13 17:05 ` Junio C Hamano 1 sibling, 1 reply; 37+ messages in thread From: Martin von Zweigbergk @ 2012-08-13 16:09 UTC (permalink / raw) To: Junio C Hamano; +Cc: git, Christian Couder, Johannes Schindelin On Mon, Aug 13, 2012 at 12:17 AM, Junio C Hamano <gitster@pobox.com> wrote: > y@google.com writes: > > [Administrivia: I somehow doubt y@google.com would reach you, and > futzed with the To: line above] :-( Sorry, sendemail.from now set. (I apparently answered "y" instead of just <enter> to accept the default.) > I actually think --no-walk, especially when given any negative > revision, that sorts is fundamentally a flawed concept (it led to > the inconsistency that made "git show A..B C" vs "git show C A..B" > behave differently, which we had to fix recently). I completely agree. > Would anything break if we take your patch, but without two > possibilities to revs->no_walk option (i.e. we never sort under > no_walk)? That is, the core of your change would become something > like this: I also thought the sorting was just a bug. From what I understand by looking how the code has evolved, the sorting in the no-walk case was not intentional, but more of a consequence of the implementation. That patch you suggested was my first attempt and led me to find the broken cherry-pick test cases that I then fixed in patch 2/4. But, it clearly would break the test case in t4202 called 'git log --no-walk <commits> sorts by commit time'. So I started digging from there and found e.g. http://thread.gmane.org/gmane.comp.version-control.git/123205/focus=123216 For convenience, I have pasted the commit message of the commit mentioned in that thread at the end of this email. So we would be breaking at least Johannes's use case if we changed it. I would think almost everyone who doesn't already know would expect "git rev-list A B" to list them in that order, so is a migration desired? Or just change the default for --no-walk from "sorted" to "unsorted" in git 2.0? By the way, git-log's documentation says "By default, the commits are shown in reverse chronological order.", which to some degree is in support of the current behavior. commit 8e64006eee9c82eba513b98306c179c9e2385e4e Author: Johannes Schindelin <Johannes.Schindelin@gmx.de> Date: Tue Jul 24 00:38:40 2007 +0100 Teach revision machinery about --no-walk The flag "no_walk" is present in struct rev_info since a long time, but so far has been in use exclusively by "git show". With this flag, you can see all your refs, ordered by date of the last commit: $ git log --abbrev-commit --pretty=oneline --decorate --all --no-walk which is extremely helpful if you have to juggle with a lot topic branches, and do not remember in which one you introduced that uber debug option, or simply want to get an overview what is cooking. (Note that the "git log" invocation above does not output the same as $ git show --abbrev-commit --pretty=oneline --decorate --all --quiet since "git show" keeps the alphabetic order that "--all" returns the refs in, even if the option "--date-order" was passed.) For good measure, this also adds the "--do-walk" option which overrides "--no-walk". Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de> Signed-off-by: Junio C Hamano <gitster@pobox.com> ^ permalink raw reply [flat|nested] 37+ messages in thread
* Re: [PATCH 0/4] Re: cherry-pick and 'log --no-walk' and ordering 2012-08-13 16:09 ` Martin von Zweigbergk @ 2012-08-13 17:05 ` Junio C Hamano 2012-08-13 18:28 ` Martin von Zweigbergk 0 siblings, 1 reply; 37+ messages in thread From: Junio C Hamano @ 2012-08-13 17:05 UTC (permalink / raw) To: Martin von Zweigbergk; +Cc: git, Christian Couder, Johannes Schindelin Martin von Zweigbergk <martin.von.zweigbergk@gmail.com> writes: > I also thought the sorting was just a bug. From what I understand by > looking how the code has evolved, the sorting in the no-walk case was > not intentional, but more of a consequence of the implementation. That > patch you suggested was my first attempt and led me to find the broken > cherry-pick test cases that I then fixed in patch 2/4. But, it clearly > would break the test case in t4202 called 'git log --no-walk <commits> > sorts by commit time'. So I started digging from there and found e.g. > > http://thread.gmane.org/gmane.comp.version-control.git/123205/focus=123216 > > For convenience, I have pasted the commit message of the commit > mentioned in that thread at the end of this email. So we would be > breaking at least Johannes's use case if we changed it. Ok. Having a way to conveniently sort based on committer date is indeed handy, and losing it would be a regression. Not that the accident that supports only on committer date is a nicely designed feature. The user may want to sort on author date instead, but there is no way to do so with --no-walk. So in that sense, Johannes's use case happens to work by accident. > ... so is a migration desired? Or just > change the default for --no-walk from "sorted" to "unsorted" in git > 2.0? I think the proper support for Johannes's case should give users more control on what to sort on, and that switch should not be tied to "--no-walk". After all, being able to sort commits in the result of limit_list() with various criteria would equally useful as being able to sort commits listed on the command line with --no-walk. Think about what "git shortlog A..B" does, for example. It is like first enumerating commits within the given range, and sorting the result using author as the primary and then timestamp as the secondary sort column. So let's not even think about migration, and go in the direction of giving "--no-walk" two flavours, for now. Either it keeps the order commits were given from the command line, or it does the default sort using the timestamp. We can later add the --sort-on option that would work with or without --no-walk for people who want output that is differently sorted, but that is outside the scope of your series. > By the way, git-log's documentation says "By default, the commits are > shown in reverse chronological order.", which to some degree is in > support of the current behavior. That is talking about the presentation order of the result of limit_list(), predates --no-walk, and was not adjusted to the new world order when --no-walk was introduced, so I would not take it as a supporting argument. But not regressing the current "you can see them sorted on the commit timestamp (this is merely an accident and not a designed feature, so you cannot choose to sort on other things)" behaviour is a reason enough not to disable sorting for the plain "--no-walk" option. Thanks. ^ permalink raw reply [flat|nested] 37+ messages in thread
* Re: [PATCH 0/4] Re: cherry-pick and 'log --no-walk' and ordering 2012-08-13 17:05 ` Junio C Hamano @ 2012-08-13 18:28 ` Martin von Zweigbergk 2012-08-13 21:31 ` Junio C Hamano 0 siblings, 1 reply; 37+ messages in thread From: Martin von Zweigbergk @ 2012-08-13 18:28 UTC (permalink / raw) To: Junio C Hamano; +Cc: git, Christian Couder, Johannes Schindelin On Mon, Aug 13, 2012 at 10:05 AM, Junio C Hamano <gitster@pobox.com> wrote: > Martin von Zweigbergk <martin.von.zweigbergk@gmail.com> writes: >> >> ... so is a migration desired? Or just >> change the default for --no-walk from "sorted" to "unsorted" in git >> 2.0? > > I think the proper support for Johannes's case should give users > more control on what to sort on, and that switch should not be tied > to "--no-walk". After all, being able to sort commits in the result > of limit_list() with various criteria would equally useful as being > able to sort commits listed on the command line with --no-walk. > Think about what "git shortlog A..B" does, for example. It is like > first enumerating commits within the given range, and sorting the > result using author as the primary and then timestamp as the > secondary sort column. > > So let's not even think about migration, and go in the direction of > giving "--no-walk" two flavours, for now. Either it keeps the order > commits were given from the command line, or it does the default > sort using the timestamp. We can later add the --sort-on option that > would work with or without --no-walk for people who want output that > is differently sorted, but that is outside the scope of your series. Makes sense. The shortlog example is a good example of sorting that completely reorders the commit graph sometimes even making sense for ranges. Thanks! ^ permalink raw reply [flat|nested] 37+ messages in thread
* Re: [PATCH 0/4] Re: cherry-pick and 'log --no-walk' and ordering 2012-08-13 18:28 ` Martin von Zweigbergk @ 2012-08-13 21:31 ` Junio C Hamano 2012-08-13 22:01 ` Martin von Zweigbergk 0 siblings, 1 reply; 37+ messages in thread From: Junio C Hamano @ 2012-08-13 21:31 UTC (permalink / raw) To: Martin von Zweigbergk; +Cc: git, Christian Couder, Johannes Schindelin Martin von Zweigbergk <martin.von.zweigbergk@gmail.com> writes: > Makes sense. The shortlog example is a good example of sorting that > completely reorders the commit graph sometimes even making sense for > ranges. Thanks! By the way, does this topic relate to the long stalled "rebase" topic from you, and if so how? ^ permalink raw reply [flat|nested] 37+ messages in thread
* Re: [PATCH 0/4] Re: cherry-pick and 'log --no-walk' and ordering 2012-08-13 21:31 ` Junio C Hamano @ 2012-08-13 22:01 ` Martin von Zweigbergk 0 siblings, 0 replies; 37+ messages in thread From: Martin von Zweigbergk @ 2012-08-13 22:01 UTC (permalink / raw) To: Junio C Hamano; +Cc: git, Christian Couder, Johannes Schindelin On Mon, Aug 13, 2012 at 2:31 PM, Junio C Hamano <gitster@pobox.com> wrote: > Martin von Zweigbergk <martin.von.zweigbergk@gmail.com> writes: > >> Makes sense. The shortlog example is a good example of sorting that >> completely reorders the commit graph sometimes even making sense for >> ranges. Thanks! > > By the way, does this topic relate to the long stalled "rebase" > topic from you, and if so how? Yes, but only through the first patch in the series. Unless I'm mistaken, I would can get a list of revisions to rebase using git-patch-id, but to convert that into a instruction list with running git-log on each commit, I planned to use 'git rev-list --format=... --no-walk=unsorted --stdin', which of course doesn't exist before patch 1/4. The rest of the current series is a little fuzzy to me, especially the confusion about reversing or not. Feel free to split out patch 1 into a separate topic if you like, or however you would handle that. ^ permalink raw reply [flat|nested] 37+ messages in thread
* [PATCH v2 0/3] revision (no-)walking in order 2012-08-13 6:27 ` [PATCH 0/4] " y 2012-08-13 7:17 ` Junio C Hamano @ 2012-08-29 6:15 ` Martin von Zweigbergk 2012-08-29 6:15 ` [PATCH v2 1/3] teach log --no-walk=unsorted, which avoids sorting Martin von Zweigbergk ` (3 more replies) 1 sibling, 4 replies; 37+ messages in thread From: Martin von Zweigbergk @ 2012-08-29 6:15 UTC (permalink / raw) To: git Cc: Junio C Hamano, Christian Couder, Johannes Schindelin, Martin von Zweigbergk I'm still working on a re-roll of my rebase-range series, but I think these three are quite unrelated and shouldn't be held up by that other series. Junio, thanks for all the help with explaining revision walking. It was a little blurry for a long time, but at least I feel more comfortable with these few patches now. Btw, the rebase-range series seems to need (or be greatly simplified), although I'm not 100% sure yet, by teaching patch-id --keep-empty, which would be its first command line option. Let me know if you (plural) sees a problem with that. Btw2, I'm migrating my email to martinvonz@gmail.com (not y@google.com ;-) which saves a few keystrokes and matches some of my other accounts, so these patches will be the first ones from the new address. Martin von Zweigbergk (3): teach log --no-walk=unsorted, which avoids sorting demonstrate broken 'git cherry-pick three one two' cherry-pick/revert: respect order of revisions to pick Documentation/rev-list-options.txt | 12 ++++++++---- builtin/log.c | 2 +- builtin/revert.c | 2 +- revision.c | 18 +++++++++++++++--- revision.h | 6 +++++- sequencer.c | 4 +++- t/t3508-cherry-pick-many-commits.sh | 15 +++++++++++++++ t/t4202-log.sh | 10 ++++++++++ 8 files changed, 58 insertions(+), 11 deletions(-) -- 1.7.11.1.104.ge7b44f1 ^ permalink raw reply [flat|nested] 37+ messages in thread
* [PATCH v2 1/3] teach log --no-walk=unsorted, which avoids sorting 2012-08-29 6:15 ` [PATCH v2 0/3] revision (no-)walking in order Martin von Zweigbergk @ 2012-08-29 6:15 ` Martin von Zweigbergk 2012-08-29 17:34 ` Dan Johnson 2012-08-29 6:15 ` [PATCH v2 2/3] demonstrate broken 'git cherry-pick three one two' Martin von Zweigbergk ` (2 subsequent siblings) 3 siblings, 1 reply; 37+ messages in thread From: Martin von Zweigbergk @ 2012-08-29 6:15 UTC (permalink / raw) To: git Cc: Junio C Hamano, Christian Couder, Johannes Schindelin, Martin von Zweigbergk When 'git log' is passed the --no-walk option, no revision walk takes place, naturally. Perhaps somewhat surprisingly, however, the provided revisions still get sorted by commit date. So e.g 'git log --no-walk HEAD HEAD~1' and 'git log --no-walk HEAD~1 HEAD' give the same result (unless the two revisions share the commit date, in which case they will retain the order given on the command line). As the commit that introduced --no-walk (8e64006 (Teach revision machinery about --no-walk, 2007-07-24)) points out, the sorting is intentional, to allow things like git log --abbrev-commit --pretty=oneline --decorate --all --no-walk to show all refs in order by commit date. But there are also other cases where the sorting is not wanted, such as <command producing revisions in order> | git log --oneline --no-walk --stdin To accomodate both cases, leave the decision of whether or not to sort up to the caller, by allowing --no-walk={sorted,unsorted}, defaulting to 'sorted' for backward-compatibility reasons. Signed-off-by: Martin von Zweigbergk <martinvonz@gmail.com> --- Documentation/rev-list-options.txt | 12 ++++++++---- builtin/log.c | 2 +- builtin/revert.c | 2 +- revision.c | 18 +++++++++++++++--- revision.h | 6 +++++- t/t4202-log.sh | 10 ++++++++++ 6 files changed, 40 insertions(+), 10 deletions(-) diff --git a/Documentation/rev-list-options.txt b/Documentation/rev-list-options.txt index def1340..5436eba 100644 --- a/Documentation/rev-list-options.txt +++ b/Documentation/rev-list-options.txt @@ -636,10 +636,14 @@ These options are mostly targeted for packing of git repositories. Only useful with '--objects'; print the object IDs that are not in packs. ---no-walk:: - - Only show the given revs, but do not traverse their ancestors. - This has no effect if a range is specified. +--no-walk[=(sorted|unsorted)]:: + + Only show the given commits, but do not traverse their ancestors. + This has no effect if a range is specified. If the argument + "unsorted" is given, the commits are show in the order they were + given on the command line. Otherwise (if "sorted" or no argument + was given), the commits are show in reverse chronological order + by commit time. --do-walk:: diff --git a/builtin/log.c b/builtin/log.c index ecc2793..20838b1 100644 --- a/builtin/log.c +++ b/builtin/log.c @@ -456,7 +456,7 @@ int cmd_show(int argc, const char **argv, const char *prefix) init_revisions(&rev, prefix); rev.diff = 1; rev.always_show_header = 1; - rev.no_walk = 1; + rev.no_walk = REVISION_WALK_NO_WALK_SORTED; rev.diffopt.stat_width = -1; /* Scale to real terminal size */ memset(&opt, 0, sizeof(opt)); diff --git a/builtin/revert.c b/builtin/revert.c index 82d1bf8..42ce399 100644 --- a/builtin/revert.c +++ b/builtin/revert.c @@ -193,7 +193,7 @@ static void parse_args(int argc, const char **argv, struct replay_opts *opts) struct setup_revision_opt s_r_opt; opts->revs = xmalloc(sizeof(*opts->revs)); init_revisions(opts->revs, NULL); - opts->revs->no_walk = 1; + opts->revs->no_walk = REVISION_WALK_NO_WALK_SORTED; if (argc < 2) usage_with_options(usage_str, options); memset(&s_r_opt, 0, sizeof(s_r_opt)); diff --git a/revision.c b/revision.c index 442a945..66ba2e6 100644 --- a/revision.c +++ b/revision.c @@ -1300,7 +1300,7 @@ static int handle_revision_opt(struct rev_info *revs, int argc, const char **arg !strcmp(arg, "--no-walk") || !strcmp(arg, "--do-walk") || !strcmp(arg, "--bisect") || !prefixcmp(arg, "--glob=") || !prefixcmp(arg, "--branches=") || !prefixcmp(arg, "--tags=") || - !prefixcmp(arg, "--remotes=")) + !prefixcmp(arg, "--remotes=") || !prefixcmp(arg, "--no-walk=")) { unkv[(*unkc)++] = arg; return 1; @@ -1695,7 +1695,18 @@ static int handle_revision_pseudo_opt(const char *submodule, } else if (!strcmp(arg, "--not")) { *flags ^= UNINTERESTING; } else if (!strcmp(arg, "--no-walk")) { - revs->no_walk = 1; + revs->no_walk = REVISION_WALK_NO_WALK_SORTED; + } else if (!prefixcmp(arg, "--no-walk=")) { + /* + * Detached form ("--no-walk X" as opposed to "--no-walk=X") + * not allowed, since the argument is optional. + */ + if (!strcmp(arg + 10, "sorted")) + revs->no_walk = REVISION_WALK_NO_WALK_SORTED; + else if (!strcmp(arg + 10, "unsorted")) + revs->no_walk = REVISION_WALK_NO_WALK_UNSORTED; + else + return error("invalid argument to --no-walk"); } else if (!strcmp(arg, "--do-walk")) { revs->no_walk = 0; } else { @@ -2117,10 +2128,11 @@ int prepare_revision_walk(struct rev_info *revs) } e++; } - commit_list_sort_by_date(&revs->commits); if (!revs->leak_pending) free(list); + if (revs->no_walk != REVISION_WALK_NO_WALK_UNSORTED) + commit_list_sort_by_date(&revs->commits); if (revs->no_walk) return 0; if (revs->limited) diff --git a/revision.h b/revision.h index cb5ab35..a95bd0b 100644 --- a/revision.h +++ b/revision.h @@ -41,6 +41,10 @@ struct rev_cmdline_info { } *rev; }; +#define REVISION_WALK_WALK 0 +#define REVISION_WALK_NO_WALK_SORTED 1 +#define REVISION_WALK_NO_WALK_UNSORTED 2 + struct rev_info { /* Starting list */ struct commit_list *commits; @@ -62,7 +66,7 @@ struct rev_info { /* Traversal flags */ unsigned int dense:1, prune:1, - no_walk:1, + no_walk:2, show_all:1, remove_empty_trees:1, simplify_history:1, diff --git a/t/t4202-log.sh b/t/t4202-log.sh index 71be59d..bd83355 100755 --- a/t/t4202-log.sh +++ b/t/t4202-log.sh @@ -178,11 +178,21 @@ test_expect_success 'git log --no-walk <commits> sorts by commit time' ' test_cmp expect actual ' +test_expect_success 'git log --no-walk=sorted <commits> sorts by commit time' ' + git log --no-walk=sorted --oneline 5d31159 804a787 394ef78 > actual && + test_cmp expect actual +' + cat > expect << EOF 5d31159 fourth 804a787 sixth 394ef78 fifth EOF +test_expect_success 'git log --no-walk=unsorted <commits> leaves list of commits as given' ' + git log --no-walk=unsorted --oneline 5d31159 804a787 394ef78 > actual && + test_cmp expect actual +' + test_expect_success 'git show <commits> leaves list of commits as given' ' git show --oneline -s 5d31159 804a787 394ef78 > actual && test_cmp expect actual -- 1.7.11.1.104.ge7b44f1 ^ permalink raw reply related [flat|nested] 37+ messages in thread
* Re: [PATCH v2 1/3] teach log --no-walk=unsorted, which avoids sorting 2012-08-29 6:15 ` [PATCH v2 1/3] teach log --no-walk=unsorted, which avoids sorting Martin von Zweigbergk @ 2012-08-29 17:34 ` Dan Johnson 2012-08-29 17:42 ` Junio C Hamano 0 siblings, 1 reply; 37+ messages in thread From: Dan Johnson @ 2012-08-29 17:34 UTC (permalink / raw) To: Martin von Zweigbergk Cc: git, Junio C Hamano, Christian Couder, Johannes Schindelin On Wed, Aug 29, 2012 at 2:15 AM, Martin von Zweigbergk <martinvonz@gmail.com> wrote: > When 'git log' is passed the --no-walk option, no revision walk takes > place, naturally. Perhaps somewhat surprisingly, however, the provided > revisions still get sorted by commit date. So e.g 'git log --no-walk > HEAD HEAD~1' and 'git log --no-walk HEAD~1 HEAD' give the same result > (unless the two revisions share the commit date, in which case they > will retain the order given on the command line). As the commit that > introduced --no-walk (8e64006 (Teach revision machinery about > --no-walk, 2007-07-24)) points out, the sorting is intentional, to > allow things like > > git log --abbrev-commit --pretty=oneline --decorate --all --no-walk > > to show all refs in order by commit date. > > But there are also other cases where the sorting is not wanted, such > as > > <command producing revisions in order> | > git log --oneline --no-walk --stdin > > To accomodate both cases, leave the decision of whether or not to sort > up to the caller, by allowing --no-walk={sorted,unsorted}, defaulting > to 'sorted' for backward-compatibility reasons. > > Signed-off-by: Martin von Zweigbergk <martinvonz@gmail.com> > --- Perhaps I am missing something from an earlier discussion, but it is not obvious to me why this is an option to the no-walk behavior and not something like --sorted/--unsorted as a separate option. In other words, I don't understand why you always want to sort if you are doing revision walking. Thanks for any explanation, -Dan ^ permalink raw reply [flat|nested] 37+ messages in thread
* Re: [PATCH v2 1/3] teach log --no-walk=unsorted, which avoids sorting 2012-08-29 17:34 ` Dan Johnson @ 2012-08-29 17:42 ` Junio C Hamano 0 siblings, 0 replies; 37+ messages in thread From: Junio C Hamano @ 2012-08-29 17:42 UTC (permalink / raw) To: Dan Johnson Cc: Martin von Zweigbergk, git, Christian Couder, Johannes Schindelin Dan Johnson <computerdruid@gmail.com> writes: > Perhaps I am missing something from an earlier discussion, but it is http://thread.gmane.org/gmane.comp.version-control.git/203259/focus=203344 > not obvious to me why this is an option to the no-walk behavior and > not something like --sorted/--unsorted as a separate option. > > In other words, I don't understand why you always want to sort if you > are doing revision walking. When you have more than one starting points to dig the history from (e.g. "git log foo bar baz"), you would want to start digging from the newer ones, as that would help you find the fork points of the branches involved more efficiently. But you need to follow the previous discussion if you want to understand implications around sorting. ^ permalink raw reply [flat|nested] 37+ messages in thread
* [PATCH v2 2/3] demonstrate broken 'git cherry-pick three one two' 2012-08-29 6:15 ` [PATCH v2 0/3] revision (no-)walking in order Martin von Zweigbergk 2012-08-29 6:15 ` [PATCH v2 1/3] teach log --no-walk=unsorted, which avoids sorting Martin von Zweigbergk @ 2012-08-29 6:15 ` Martin von Zweigbergk 2012-08-30 21:02 ` Junio C Hamano 2012-08-29 6:15 ` [PATCH v2 3/3] cherry-pick/revert: respect order of revisions to pick Martin von Zweigbergk 2012-08-29 6:46 ` [PATCH v2 0/3] revision (no-)walking in order Junio C Hamano 3 siblings, 1 reply; 37+ messages in thread From: Martin von Zweigbergk @ 2012-08-29 6:15 UTC (permalink / raw) To: git Cc: Junio C Hamano, Christian Couder, Johannes Schindelin, Martin von Zweigbergk Cherry-picking commits out of order (w.r.t. commit time stamp) doesn't currently work. Add a test case to demonstrate it. Signed-off-by: Martin von Zweigbergk <martinvonz@gmail.com> --- t/t3508-cherry-pick-many-commits.sh | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/t/t3508-cherry-pick-many-commits.sh b/t/t3508-cherry-pick-many-commits.sh index 75f7ff4..fff20c3 100755 --- a/t/t3508-cherry-pick-many-commits.sh +++ b/t/t3508-cherry-pick-many-commits.sh @@ -44,6 +44,21 @@ test_expect_success 'cherry-pick first..fourth works' ' check_head_differs_from fourth ' +test_expect_failure 'cherry-pick three one two works' ' + git checkout -f first && + test_commit one && + test_commit two && + test_commit three && + git checkout -f master && + git reset --hard first && + git cherry-pick three one two && + git diff --quiet three && + git diff --quiet HEAD three && + test "$(git log --reverse --format=%s first..)" == "three +one +two" +' + test_expect_success 'output to keep user entertained during multi-pick' ' cat <<-\EOF >expected && [master OBJID] second -- 1.7.11.1.104.ge7b44f1 ^ permalink raw reply related [flat|nested] 37+ messages in thread
* Re: [PATCH v2 2/3] demonstrate broken 'git cherry-pick three one two' 2012-08-29 6:15 ` [PATCH v2 2/3] demonstrate broken 'git cherry-pick three one two' Martin von Zweigbergk @ 2012-08-30 21:02 ` Junio C Hamano 0 siblings, 0 replies; 37+ messages in thread From: Junio C Hamano @ 2012-08-30 21:02 UTC (permalink / raw) To: Martin von Zweigbergk; +Cc: git, Christian Couder, Johannes Schindelin Martin von Zweigbergk <martinvonz@gmail.com> writes: > Cherry-picking commits out of order (w.r.t. commit time stamp) doesn't > currently work. Add a test case to demonstrate it. > > Signed-off-by: Martin von Zweigbergk <martinvonz@gmail.com> > --- > t/t3508-cherry-pick-many-commits.sh | 15 +++++++++++++++ > 1 file changed, 15 insertions(+) > > diff --git a/t/t3508-cherry-pick-many-commits.sh b/t/t3508-cherry-pick-many-commits.sh > index 75f7ff4..fff20c3 100755 > --- a/t/t3508-cherry-pick-many-commits.sh > +++ b/t/t3508-cherry-pick-many-commits.sh > @@ -44,6 +44,21 @@ test_expect_success 'cherry-pick first..fourth works' ' > check_head_differs_from fourth > ' > > +test_expect_failure 'cherry-pick three one two works' ' > + git checkout -f first && > + test_commit one && > + test_commit two && > + test_commit three && > + git checkout -f master && > + git reset --hard first && > + git cherry-pick three one two && > + git diff --quiet three && > + git diff --quiet HEAD three && > + test "$(git log --reverse --format=%s first..)" == "three > +one > +two" > +' "test $A == $B" is not POSIX. I'll drop '=' when queuing, so no need to resend. Thanks. > + > test_expect_success 'output to keep user entertained during multi-pick' ' > cat <<-\EOF >expected && > [master OBJID] second ^ permalink raw reply [flat|nested] 37+ messages in thread
* [PATCH v2 3/3] cherry-pick/revert: respect order of revisions to pick 2012-08-29 6:15 ` [PATCH v2 0/3] revision (no-)walking in order Martin von Zweigbergk 2012-08-29 6:15 ` [PATCH v2 1/3] teach log --no-walk=unsorted, which avoids sorting Martin von Zweigbergk 2012-08-29 6:15 ` [PATCH v2 2/3] demonstrate broken 'git cherry-pick three one two' Martin von Zweigbergk @ 2012-08-29 6:15 ` Martin von Zweigbergk 2012-08-29 6:46 ` [PATCH v2 0/3] revision (no-)walking in order Junio C Hamano 3 siblings, 0 replies; 37+ messages in thread From: Martin von Zweigbergk @ 2012-08-29 6:15 UTC (permalink / raw) To: git Cc: Junio C Hamano, Christian Couder, Johannes Schindelin, Martin von Zweigbergk When giving multiple individual revisions to cherry-pick or revert, as in 'git cherry-pick A B' or 'git revert B A', one would expect them to be picked/reverted in the order given on the command line. They are instead ordered by their commit timestamp -- in chronological order for "cherry-pick" and in reverse chronological order for "revert". This matches the order in which one would usually give them on the command line, making this bug somewhat hard to notice. Still, it has been reported at least once before [1]. It seems like the chronological sorting happened by accident because the revision walker has traditionally always sorted commits in reverse chronological order when rev_info.no_walk was enabled. In the case of 'git revert B A' where B is newer than A, this sorting is a no-op. For 'git cherry-pick A B', the sorting would reverse the arguments, but because the sequencer also flips the rev_info.reverse flag when picking (as opposed to reverting), the end result is a chronological order. The rev_info.reverse flag was probably flipped so that the revision walker emits B before C in 'git cherry-pick A..C'; that it happened to effectively undo the unexpected sorting done when not walking, was probably a coincidence that allowed this bug to happen at all. Fix the bug by telling the revision walker not to sort the commits when not walking. The only case we want to reverse the order is now when cherry-picking and walking revisions (rev_info.no_walk = 0). [1] http://thread.gmane.org/gmane.comp.version-control.git/164794 Signed-off-by: Martin von Zweigbergk <martinvonz@gmail.com> --- builtin/revert.c | 2 +- sequencer.c | 4 +++- t/t3508-cherry-pick-many-commits.sh | 2 +- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/builtin/revert.c b/builtin/revert.c index 42ce399..98ad641 100644 --- a/builtin/revert.c +++ b/builtin/revert.c @@ -193,7 +193,7 @@ static void parse_args(int argc, const char **argv, struct replay_opts *opts) struct setup_revision_opt s_r_opt; opts->revs = xmalloc(sizeof(*opts->revs)); init_revisions(opts->revs, NULL); - opts->revs->no_walk = REVISION_WALK_NO_WALK_SORTED; + opts->revs->no_walk = REVISION_WALK_NO_WALK_UNSORTED; if (argc < 2) usage_with_options(usage_str, options); memset(&s_r_opt, 0, sizeof(s_r_opt)); diff --git a/sequencer.c b/sequencer.c index bf078f2..9f32104 100644 --- a/sequencer.c +++ b/sequencer.c @@ -543,7 +543,9 @@ static int do_pick_commit(struct commit *commit, struct replay_opts *opts) static void prepare_revs(struct replay_opts *opts) { - if (opts->action != REPLAY_REVERT) + // picking (but not reverting) ranges (but not individual revisions) + // should be done in reverse + if (opts->action == REPLAY_PICK && !opts->revs->no_walk) opts->revs->reverse ^= 1; if (prepare_revision_walk(opts->revs)) diff --git a/t/t3508-cherry-pick-many-commits.sh b/t/t3508-cherry-pick-many-commits.sh index fff20c3..04b5ad4 100755 --- a/t/t3508-cherry-pick-many-commits.sh +++ b/t/t3508-cherry-pick-many-commits.sh @@ -44,7 +44,7 @@ test_expect_success 'cherry-pick first..fourth works' ' check_head_differs_from fourth ' -test_expect_failure 'cherry-pick three one two works' ' +test_expect_success 'cherry-pick three one two works' ' git checkout -f first && test_commit one && test_commit two && -- 1.7.11.1.104.ge7b44f1 ^ permalink raw reply related [flat|nested] 37+ messages in thread
* Re: [PATCH v2 0/3] revision (no-)walking in order 2012-08-29 6:15 ` [PATCH v2 0/3] revision (no-)walking in order Martin von Zweigbergk ` (2 preceding siblings ...) 2012-08-29 6:15 ` [PATCH v2 3/3] cherry-pick/revert: respect order of revisions to pick Martin von Zweigbergk @ 2012-08-29 6:46 ` Junio C Hamano 2012-08-29 16:20 ` [PATCH] Martin von Zweigbergk has a new e-mail address Martin von Zweigbergk 3 siblings, 1 reply; 37+ messages in thread From: Junio C Hamano @ 2012-08-29 6:46 UTC (permalink / raw) To: Martin von Zweigbergk; +Cc: git, Christian Couder, Johannes Schindelin Martin von Zweigbergk <martinvonz@gmail.com> writes: > Btw2, I'm migrating my email to martinvonz@gmail.com (not y@google.com > ;-) which saves a few keystrokes and matches some of my other > accounts, so these patches will be the first ones from the new > address. Please send in something like this, then. .mailmap | 1 + 1 file changed, 1 insertion(+) diff --git i/.mailmap w/.mailmap index 6303782..2650f9e 100644 --- i/.mailmap +++ w/.mailmap @@ -43,6 +43,7 @@ Lars Doelle <lars.doelle@on-line.de> Li Hong <leehong@pku.edu.cn> Lukas Sandström <lukass@etek.chalmers.se> Martin Langhoff <martin@laptop.org> +Martin von Zweigbergk <martinvonz@gmail.com> <martin.von.zweigbergk@gmail.com> Michael Coleman <tutufan@gmail.com> Michael J Gruber <git@drmicha.warpmail.net> <michaeljgruber+gmane@fastmail.fm> Michael W. Olson <mwolson@gnu.org> ^ permalink raw reply related [flat|nested] 37+ messages in thread
* [PATCH] Martin von Zweigbergk has a new e-mail address 2012-08-29 6:46 ` [PATCH v2 0/3] revision (no-)walking in order Junio C Hamano @ 2012-08-29 16:20 ` Martin von Zweigbergk 0 siblings, 0 replies; 37+ messages in thread From: Martin von Zweigbergk @ 2012-08-29 16:20 UTC (permalink / raw) To: Junio C Hamano; +Cc: git, Martin von Zweigbergk Signed-off-by: Martin von Zweigbergk <martinvonz@gmail.com> --- .mailmap | 1 + 1 file changed, 1 insertion(+) diff --git a/.mailmap b/.mailmap index 6303782..2650f9e 100644 --- a/.mailmap +++ b/.mailmap @@ -43,6 +43,7 @@ Lars Doelle <lars.doelle@on-line.de> Li Hong <leehong@pku.edu.cn> Lukas Sandström <lukass@etek.chalmers.se> Martin Langhoff <martin@laptop.org> +Martin von Zweigbergk <martinvonz@gmail.com> <martin.von.zweigbergk@gmail.com> Michael Coleman <tutufan@gmail.com> Michael J Gruber <git@drmicha.warpmail.net> <michaeljgruber+gmane@fastmail.fm> Michael W. Olson <mwolson@gnu.org> -- 1.7.11.1.104.ge7b44f1 ^ permalink raw reply related [flat|nested] 37+ messages in thread
[parent not found: <1344839240-17402-1-git-send-email-y>]
* [PATCH 1/4] teach log --no-walk=unsorted, which avoids sorting [not found] ` <1344839240-17402-1-git-send-email-y> @ 2012-08-13 6:27 ` y 2012-08-13 6:27 ` [PATCH 2/4] revisions passed to cherry-pick should be in "default" order y ` (2 subsequent siblings) 3 siblings, 0 replies; 37+ messages in thread From: y @ 2012-08-13 6:27 UTC (permalink / raw) To: Junio C Hamano; +Cc: git, Christian Couder, Martin von Zweigbergk From: Martin von Zweigbergk <martin.von.zweigbergk@gmail.com> When 'git log' is passed the --no-walk option, no revision walk takes place, naturally. Perhaps somewhat surprisingly, however, the provided revisions still get sorted by commit date. So e.g 'git log --no-walk HEAD HEAD~1' and 'git log --no-walk HEAD~1 HEAD' give the same result (unless the two revisions share the commit date, in which case they will retain the order given on the command line). As the commit that introduced --no-walk (8e64006 (Teach revision machinery about --no-walk, 2007-07-24)) points out, the sorting is intentional, to allow things like git log --abbrev-commit --pretty=oneline --decorate --all --no-walk to show all refs in order by commit date. But there are also other cases where the sorting is not wanted, such as <command producing revisions in order> | git log --oneline --no-walk --stdin To accomodate both cases, leave the decision of whether or not to sort up to the caller, by allowing --no-walk={sorted,unsorted}, defaulting to 'sorted'. Signed-off-by: Martin von Zweigbergk <martin.von.zweigbergk@gmail.com> --- builtin/log.c | 2 +- builtin/revert.c | 2 +- revision.c | 18 +++++++++++++++--- revision.h | 6 +++++- t/t4202-log.sh | 10 ++++++++++ 5 files changed, 32 insertions(+), 6 deletions(-) diff --git a/builtin/log.c b/builtin/log.c index ecc2793..20838b1 100644 --- a/builtin/log.c +++ b/builtin/log.c @@ -456,7 +456,7 @@ int cmd_show(int argc, const char **argv, const char *prefix) init_revisions(&rev, prefix); rev.diff = 1; rev.always_show_header = 1; - rev.no_walk = 1; + rev.no_walk = REVISION_WALK_NO_WALK_SORTED; rev.diffopt.stat_width = -1; /* Scale to real terminal size */ memset(&opt, 0, sizeof(opt)); diff --git a/builtin/revert.c b/builtin/revert.c index 82d1bf8..42ce399 100644 --- a/builtin/revert.c +++ b/builtin/revert.c @@ -193,7 +193,7 @@ static void parse_args(int argc, const char **argv, struct replay_opts *opts) struct setup_revision_opt s_r_opt; opts->revs = xmalloc(sizeof(*opts->revs)); init_revisions(opts->revs, NULL); - opts->revs->no_walk = 1; + opts->revs->no_walk = REVISION_WALK_NO_WALK_SORTED; if (argc < 2) usage_with_options(usage_str, options); memset(&s_r_opt, 0, sizeof(s_r_opt)); diff --git a/revision.c b/revision.c index 9e8f47a..2faf675 100644 --- a/revision.c +++ b/revision.c @@ -1298,7 +1298,7 @@ static int handle_revision_opt(struct rev_info *revs, int argc, const char **arg !strcmp(arg, "--no-walk") || !strcmp(arg, "--do-walk") || !strcmp(arg, "--bisect") || !prefixcmp(arg, "--glob=") || !prefixcmp(arg, "--branches=") || !prefixcmp(arg, "--tags=") || - !prefixcmp(arg, "--remotes=")) + !prefixcmp(arg, "--remotes=") || !prefixcmp(arg, "--no-walk=")) { unkv[(*unkc)++] = arg; return 1; @@ -1693,7 +1693,18 @@ static int handle_revision_pseudo_opt(const char *submodule, } else if (!strcmp(arg, "--not")) { *flags ^= UNINTERESTING; } else if (!strcmp(arg, "--no-walk")) { - revs->no_walk = 1; + revs->no_walk = REVISION_WALK_NO_WALK_SORTED; + } else if (!prefixcmp(arg, "--no-walk=")) { + /* + * Detached form ("--no-walk X" as opposed to "--no-walk=X") + * not allowed, since the argument is optional. + */ + if (!strcmp(arg + 10, "sorted")) + revs->no_walk = REVISION_WALK_NO_WALK_SORTED; + else if (!strcmp(arg + 10, "unsorted")) + revs->no_walk = REVISION_WALK_NO_WALK_UNSORTED; + else + return error("invalid argument to --no-walk"); } else if (!strcmp(arg, "--do-walk")) { revs->no_walk = 0; } else { @@ -2116,10 +2127,11 @@ int prepare_revision_walk(struct rev_info *revs) } e++; } - commit_list_sort_by_date(&revs->commits); if (!revs->leak_pending) free(list); + if (revs->no_walk != REVISION_WALK_NO_WALK_UNSORTED) + commit_list_sort_by_date(&revs->commits); if (revs->no_walk) return 0; if (revs->limited) diff --git a/revision.h b/revision.h index cb5ab35..a95bd0b 100644 --- a/revision.h +++ b/revision.h @@ -41,6 +41,10 @@ struct rev_cmdline_info { } *rev; }; +#define REVISION_WALK_WALK 0 +#define REVISION_WALK_NO_WALK_SORTED 1 +#define REVISION_WALK_NO_WALK_UNSORTED 2 + struct rev_info { /* Starting list */ struct commit_list *commits; @@ -62,7 +66,7 @@ struct rev_info { /* Traversal flags */ unsigned int dense:1, prune:1, - no_walk:1, + no_walk:2, show_all:1, remove_empty_trees:1, simplify_history:1, diff --git a/t/t4202-log.sh b/t/t4202-log.sh index 71be59d..bd83355 100755 --- a/t/t4202-log.sh +++ b/t/t4202-log.sh @@ -178,11 +178,21 @@ test_expect_success 'git log --no-walk <commits> sorts by commit time' ' test_cmp expect actual ' +test_expect_success 'git log --no-walk=sorted <commits> sorts by commit time' ' + git log --no-walk=sorted --oneline 5d31159 804a787 394ef78 > actual && + test_cmp expect actual +' + cat > expect << EOF 5d31159 fourth 804a787 sixth 394ef78 fifth EOF +test_expect_success 'git log --no-walk=unsorted <commits> leaves list of commits as given' ' + git log --no-walk=unsorted --oneline 5d31159 804a787 394ef78 > actual && + test_cmp expect actual +' + test_expect_success 'git show <commits> leaves list of commits as given' ' git show --oneline -s 5d31159 804a787 394ef78 > actual && test_cmp expect actual -- 1.7.11.1.104.ge7b44f1 ^ permalink raw reply related [flat|nested] 37+ messages in thread
* [PATCH 2/4] revisions passed to cherry-pick should be in "default" order [not found] ` <1344839240-17402-1-git-send-email-y> 2012-08-13 6:27 ` [PATCH 1/4] teach log --no-walk=unsorted, which avoids sorting y @ 2012-08-13 6:27 ` y 2012-08-13 20:05 ` Junio C Hamano 2012-08-13 20:10 ` Martin von Zweigbergk 2012-08-13 6:27 ` [PATCH 3/4] cherry-pick/revert: respect order of revisions to pick y 2012-08-13 6:27 ` [PATCH 4/4] cherry-pick/revert: default to topological sorting y 3 siblings, 2 replies; 37+ messages in thread From: y @ 2012-08-13 6:27 UTC (permalink / raw) To: Junio C Hamano; +Cc: git, Christian Couder, Martin von Zweigbergk From: Martin von Zweigbergk <martin.von.zweigbergk@gmail.com> 'git cherry-pick' internally sets the --reverse option while walking revisions, so that 'git cherry-pick branch@{u}..branch' will apply the revisions starting at the oldest one. If no uninteresing revisions are given, --no-walk is implied. Still, the documentation for 'git cherry-pick --stdin' uses the following example: git rev-list --reverse master -- README | git cherry-pick -n --stdin The above would seem to reverse the revisions in the output (which it does), and then pipe them to 'git cherry-pick', which would reverse them again and apply them in the wrong order. The same problem occurs when supplying revisions explicitly on the command line instead of sending them to stdin. Because of the sorting-by-date that is done by the revision walker (even with the implied --no-walk), the ordering in the output from 'git rev-list' in the example above is effectively ignored, and the above actually works most of the time. However, if revisions share a commit date (as can easily happen as a result of rebasing), they do get applied out-of-order. Update the documentation not to suggest reversing the input to 'git cherry-pick'. Also update test cases where the inputs are reversed. Signed-off-by: Martin von Zweigbergk <martin.von.zweigbergk@gmail.com> --- Documentation/git-cherry-pick.txt | 2 +- t/t3508-cherry-pick-many-commits.sh | 2 +- t/t3510-cherry-pick-sequence.sh | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Documentation/git-cherry-pick.txt b/Documentation/git-cherry-pick.txt index 0e170a5..454e205 100644 --- a/Documentation/git-cherry-pick.txt +++ b/Documentation/git-cherry-pick.txt @@ -181,7 +181,7 @@ EXAMPLES are in next but not HEAD to the current branch, creating a new commit for each new change. -`git rev-list --reverse master -- README | git cherry-pick -n --stdin`:: +`git rev-list master -- README | git cherry-pick -n --stdin`:: Apply the changes introduced by all commits on the master branch that touched README to the working tree and index, diff --git a/t/t3508-cherry-pick-many-commits.sh b/t/t3508-cherry-pick-many-commits.sh index 75f7ff4..020baaf 100755 --- a/t/t3508-cherry-pick-many-commits.sh +++ b/t/t3508-cherry-pick-many-commits.sh @@ -164,7 +164,7 @@ test_expect_success 'cherry-pick --stdin works' ' git checkout -f master && git reset --hard first && test_tick && - git rev-list --reverse first..fourth | git cherry-pick --stdin && + git rev-list first..fourth | git cherry-pick --stdin && git diff --quiet other && git diff --quiet HEAD other && check_head_differs_from fourth diff --git a/t/t3510-cherry-pick-sequence.sh b/t/t3510-cherry-pick-sequence.sh index f4e6450..9e28910 100755 --- a/t/t3510-cherry-pick-sequence.sh +++ b/t/t3510-cherry-pick-sequence.sh @@ -400,7 +400,7 @@ test_expect_success '--continue of single-pick respects -x' ' test_expect_success '--continue respects -x in first commit in multi-pick' ' pristine_detach initial && - test_must_fail git cherry-pick -x picked anotherpick && + test_must_fail git cherry-pick -x anotherpick picked && echo c >foo && git add foo && git cherry-pick --continue && @@ -430,7 +430,7 @@ test_expect_success '--signoff is not automatically propagated to resolved confl test_expect_success '--signoff dropped for implicit commit of resolution, multi-pick case' ' pristine_detach initial && - test_must_fail git cherry-pick -s picked anotherpick && + test_must_fail git cherry-pick -s anotherpick picked && echo c >foo && git add foo && git cherry-pick --continue && -- 1.7.11.1.104.ge7b44f1 ^ permalink raw reply related [flat|nested] 37+ messages in thread
* Re: [PATCH 2/4] revisions passed to cherry-pick should be in "default" order 2012-08-13 6:27 ` [PATCH 2/4] revisions passed to cherry-pick should be in "default" order y @ 2012-08-13 20:05 ` Junio C Hamano 2012-08-13 20:50 ` Martin von Zweigbergk 2012-08-13 20:10 ` Martin von Zweigbergk 1 sibling, 1 reply; 37+ messages in thread From: Junio C Hamano @ 2012-08-13 20:05 UTC (permalink / raw) To: y; +Cc: git, Christian Couder, Martin von Zweigbergk y@google.com writes: > From: Martin von Zweigbergk <martin.von.zweigbergk@gmail.com> > > 'git cherry-pick' internally sets the --reverse option while walking > revisions, so that 'git cherry-pick branch@{u}..branch' will apply the > revisions starting at the oldest one. If no uninteresing revisions are > given, --no-walk is implied. Still, the documentation for 'git > cherry-pick --stdin' uses the following example: > > git rev-list --reverse master -- README | git cherry-pick -n --stdin > > The above would seem to reverse the revisions in the output (which it > does), and then pipe them to 'git cherry-pick', which would reverse > them again and apply them in the wrong order. I think we have cleared this confusion up in the previous discussion. It it sequencer's bug that reorders the commits when the caller ("rev-list --reverse" in this case) gives list of individual commits to replay. So I think we are all OK with chucking this patch. Am I mistaken? ^ permalink raw reply [flat|nested] 37+ messages in thread
* Re: [PATCH 2/4] revisions passed to cherry-pick should be in "default" order 2012-08-13 20:05 ` Junio C Hamano @ 2012-08-13 20:50 ` Martin von Zweigbergk 2012-08-13 21:05 ` Junio C Hamano 0 siblings, 1 reply; 37+ messages in thread From: Martin von Zweigbergk @ 2012-08-13 20:50 UTC (permalink / raw) To: Junio C Hamano; +Cc: git, Christian Couder On Mon, Aug 13, 2012 at 1:05 PM, Junio C Hamano <gitster@pobox.com> wrote: > y@google.com writes: > >> From: Martin von Zweigbergk <martin.von.zweigbergk@gmail.com> >> >> 'git cherry-pick' internally sets the --reverse option while walking >> revisions, so that 'git cherry-pick branch@{u}..branch' will apply the >> revisions starting at the oldest one. If no uninteresing revisions are >> given, --no-walk is implied. Still, the documentation for 'git >> cherry-pick --stdin' uses the following example: >> >> git rev-list --reverse master -- README | git cherry-pick -n --stdin >> >> The above would seem to reverse the revisions in the output (which it >> does), and then pipe them to 'git cherry-pick', which would reverse >> them again and apply them in the wrong order. > > I think we have cleared this confusion up in the previous > discussion. It it sequencer's bug that reorders the commits when > the caller ("rev-list --reverse" in this case) gives list of > individual commits to replay. > > So I think we are all OK with chucking this patch. Am I mistaken? I can't really say. I suppose the current patch is smaller (it can't really get smaller than one line), but iterating over the arguments the sequencer level might be more correct. Would the result be different in some cases? I would be happy to add a test case at least, although I'm not sure when I would have time to implement it in sequencer. To connect to the other mail I sent on this thread (in parallel with yours), do you think "git cherrry-pick HEAD HEAD~1" should apply the commits in the same order as "git cherry-pick HEAD~2..HEAD" (which would give the same result if passed to 'rev-list --no-walk' for a linear history) or in the order specified on the command line? I couldn't find any conclusive evidence of what was intended in either log messages or test cases. ^ permalink raw reply [flat|nested] 37+ messages in thread
* Re: [PATCH 2/4] revisions passed to cherry-pick should be in "default" order 2012-08-13 20:50 ` Martin von Zweigbergk @ 2012-08-13 21:05 ` Junio C Hamano 2012-08-15 6:05 ` Martin von Zweigbergk 0 siblings, 1 reply; 37+ messages in thread From: Junio C Hamano @ 2012-08-13 21:05 UTC (permalink / raw) To: Martin von Zweigbergk; +Cc: git, Christian Couder Martin von Zweigbergk <martin.von.zweigbergk@gmail.com> writes: > To connect to the other mail I sent on this thread (in parallel with > yours), do you think "git cherrry-pick HEAD HEAD~1" should apply the > commits in the same order as "git cherry-pick HEAD~2..HEAD" (which > would give the same result if passed to 'rev-list --no-walk' for a > linear history) or in the order specified on the command line? Definitely the latter; I do not think of any semi-reasonable excuse to do otherwise. > I couldn't find any conclusive evidence of what was intended in > either log messages or test cases. Do not take the "multi-commit handling" that was bolted on to cherry-pick and revert long after these commands with a single commit form were polished and have become stable too seriously and its behaviour cast in stone. There is no reason to believe the bolted-on part was designed with sufficient thoughts behind it, nor was implemented with the same competency as the code before it was introduced. I recall myself applying these patches after only cursory review, saying "Meh, I wouldn't do multiple commits anyway, and bugs found by people can be fixed later" ;-). It is OK to consider its doneness as "the developers declared success based on their limited testing; it internally still sorts, but sorting a range by timestamp happens to yield the correct result most of the time, and this bug was not found until much later. There certainly are other bugs, at both implementation and design level, yet to be discovered." phase of its lifecycle. ^ permalink raw reply [flat|nested] 37+ messages in thread
* Re: [PATCH 2/4] revisions passed to cherry-pick should be in "default" order 2012-08-13 21:05 ` Junio C Hamano @ 2012-08-15 6:05 ` Martin von Zweigbergk 2012-08-15 17:16 ` Junio C Hamano 0 siblings, 1 reply; 37+ messages in thread From: Martin von Zweigbergk @ 2012-08-15 6:05 UTC (permalink / raw) To: Junio C Hamano; +Cc: git, Christian Couder On Mon, Aug 13, 2012 at 2:05 PM, Junio C Hamano <gitster@pobox.com> wrote: > Martin von Zweigbergk <martin.von.zweigbergk@gmail.com> writes: > >> To connect to the other mail I sent on this thread (in parallel with >> yours), do you think "git cherrry-pick HEAD HEAD~1" should apply the >> commits in the same order as "git cherry-pick HEAD~2..HEAD" (which >> would give the same result if passed to 'rev-list --no-walk' for a >> linear history) or in the order specified on the command line? > > Definitely the latter; I do not think of any semi-reasonable excuse > to do otherwise. Indeed. My patches tried to fix the wrong problem. Sorry I'm slow, but I think I'm finally starting to understand what you've been saying all along about the bug being in sequencer. I'll try to recapitulate a bit for my own and maybe others' understanding. For simplicity, let's assume a linear history with unique timestamps, but not necessarily increasing with each commit. Currently: 1) 'git cherry-pick A..C' picks the commits order in reverse "default" order 2) 'git cherry-pick B C' picks the commits in chronological order 3) 'git rev-list --reverse A..C | git cherry-pick --stdin' behaves just like 'git cherry-pick B C' and therefore picks the commits in chronological order In cases 2) and 3), even though cherry-pick tells the revision walker not to walk, it still sorts the commits in reverse chronological order. But cherry-pick also tells the revision walker explicitly to reverse the list, so in the end, the order is chronological. In case 2), however, the first ordering make no difference in this "limited" case (IIUC). So the "default" ordering (which would be C, then B in this case, regardless of timestamps), gets reversed and B gets applied first, followed by C. So all of the above case give the right result in the end as long as the timestamps are chronological, and case 1) gives the right result regardless. The other two cases only works in most cases because the unexpcted sorting when no-walk is in effect counteracts the final reversal. When I noticed that the order of inputs to cases 2) and 3) above was ignored, and thinking that 'git rev-list A..C | git cherry-pick --stdin' should mimic 'git cherry-pick A..C', I incorrectly thought that the error was the use of --reverse to 'git rev-list' as well as the sorting done in the no-walk case. I think completely ignored case 2) at this point. I now think I understand that the sorting done in the no-walk case is indeed incorrect, but that the --reverse passed to rev-list is correct. Instead, the final reversal, which is currently unconditional, should not be done in the no-walk case. IIUC, this could be implemented by making cherry-pick iterate over rev_info.pending.objects just like 'git show' does when not walking. Junio, I think it makes sense to just drop this whole series for now. I'll probably include patch 1/4 in my stalled rebase-range series instead. If I understood you correctly, you didn't have any objections to that patch. ^ permalink raw reply [flat|nested] 37+ messages in thread
* Re: [PATCH 2/4] revisions passed to cherry-pick should be in "default" order 2012-08-15 6:05 ` Martin von Zweigbergk @ 2012-08-15 17:16 ` Junio C Hamano 2012-08-15 18:22 ` Martin von Zweigbergk 0 siblings, 1 reply; 37+ messages in thread From: Junio C Hamano @ 2012-08-15 17:16 UTC (permalink / raw) To: Martin von Zweigbergk; +Cc: git, Christian Couder Martin von Zweigbergk <martin.von.zweigbergk@gmail.com> writes: > So all of the above case give the right result in the end as long > as the timestamps are chronological, and case 1) gives the right > result regardless. The other two cases only works in most cases > because the unexpcted sorting when no-walk is in effect > counteracts the final reversal. In short, if you have three commits in a row, A--B--C, with timestamps that are not skewed, and want to replay changes of B and then C in that order, all three you listed ends up doing the right thing. But if you want to apply the change C and then B: - "git cherry-pick A..C" is obviously not a way to do so, so we won't discuss it further. - "git cherry-pick C B" is the most natural way the user would want to express this request, but because of the sorting (i.e. commit_list_sort_by_date() in prepare_revision_walk(), combined with ->reverse in sequencer.c::prepare_revs()), it applies B and then C. That is the real bug. Feeding the revs to "git cherry-pick --stdin" in the order the user wishes them to be applied has the same issue. > IIUC, this could be implemented by making cherry-pick iterate > over rev_info.pending.objects just like 'git show' does when not > walking. Yes, that was exactly why I said sequencer.c::prepare_revs() is wrong to call prepare_revision_walk() unconditionally, even when there is no revision walking involved. I actually think your approach to place the "do not sort when we are not walking" logic in prepare_revision_walk() makes more sense. "show" has to look at pending.objects[] because it needs to show objects other than commits (e.g. "git show :foo"), so there won't be any change in its implementation with your change. It will have to look at pending.objects[] itself. But "cherry-pick" and sequencer-derived commands only deal with commits. It would be far less error prone to let them call get_revision() repeatedly like all other revision enumerating commands do, than to have them go over the pending.objects[] list, dereferencing tags and using only commits. The resulting callers would be more readable, too, I would think. ^ permalink raw reply [flat|nested] 37+ messages in thread
* Re: [PATCH 2/4] revisions passed to cherry-pick should be in "default" order 2012-08-15 17:16 ` Junio C Hamano @ 2012-08-15 18:22 ` Martin von Zweigbergk 2012-08-15 18:39 ` Junio C Hamano 0 siblings, 1 reply; 37+ messages in thread From: Martin von Zweigbergk @ 2012-08-15 18:22 UTC (permalink / raw) To: Junio C Hamano; +Cc: git, Christian Couder On Wed, Aug 15, 2012 at 10:16 AM, Junio C Hamano <gitster@pobox.com> wrote: > Martin von Zweigbergk <martin.von.zweigbergk@gmail.com> writes: > >> So all of the above case give the right result in the end as long >> as the timestamps are chronological, and case 1) gives the right >> result regardless. The other two cases only works in most cases >> because the unexpcted sorting when no-walk is in effect >> counteracts the final reversal. > > In short, if you have three commits in a row, A--B--C, with > timestamps that are not skewed, and want to replay changes of B and > then C in that order, all three you listed ends up doing the right > thing. But if you want to apply the change C and then B: > > - "git cherry-pick A..C" is obviously not a way to do so, so we > won't discuss it further. > > - "git cherry-pick C B" is the most natural way the user would > want to express this request, but because of the sorting > (i.e. commit_list_sort_by_date() in prepare_revision_walk(), > combined with ->reverse in sequencer.c::prepare_revs()), it > applies B and then C. That is the real bug. > > Feeding the revs to "git cherry-pick --stdin" in the order the > user wishes them to be applied has the same issue. Exactly. > I actually think your approach to place the "do not sort when we are > not walking" logic in prepare_revision_walk() makes more sense. > "show" has to look at pending.objects[] because it needs to show > objects other than commits (e.g. "git show :foo"), so there won't be > any change in its implementation with your change. It will have to > look at pending.objects[] itself. Yes, I noticed that's why "show" has to do it that way. > But "cherry-pick" and sequencer-derived commands only deal with > commits. It would be far less error prone to let them call > get_revision() repeatedly like all other revision enumerating > commands do, than to have them go over the pending.objects[] list, > dereferencing tags and using only commits. The resulting callers > would be more readable, too, I would think. Makes sense, I'll try to implement it that way. I was afraid that we would need to call prepare_revision_walk() once first and then if we afterwards find out that we should not walk, we would need to call it again without the reverse option. But after looking at how rev_info.reverse is used, it seem like it's only used in get_revision(), so we can leave it either on or off during the prepare_revision_walk() and the and set appropriately before calling get_revision(), like so: init_revisions(&revs); revs.no_walk = REVISION_WALK_NO_WALK_UNSORTED; setup_revisions(...); prepare_revision_walk(&revs); revs.reverse = !revs.no_walk; // iterate over revisions ^ permalink raw reply [flat|nested] 37+ messages in thread
* Re: [PATCH 2/4] revisions passed to cherry-pick should be in "default" order 2012-08-15 18:22 ` Martin von Zweigbergk @ 2012-08-15 18:39 ` Junio C Hamano 2012-08-15 20:50 ` Martin von Zweigbergk 0 siblings, 1 reply; 37+ messages in thread From: Junio C Hamano @ 2012-08-15 18:39 UTC (permalink / raw) To: Martin von Zweigbergk; +Cc: git, Christian Couder Martin von Zweigbergk <martin.von.zweigbergk@gmail.com> writes: > Makes sense, I'll try to implement it that way. I was afraid that > we would need to call prepare_revision_walk() once first and then > if we afterwards find out that we should not walk, we would need > to call it again without the reverse option. > But after looking at > how rev_info.reverse is used, it seem like it's only used in > get_revision(), so we can leave it either on or off during the > prepare_revision_walk() and the and set appropriately before > calling get_revision(), like so: > > init_revisions(&revs); > revs.no_walk = REVISION_WALK_NO_WALK_UNSORTED; > setup_revisions(...); > prepare_revision_walk(&revs); > revs.reverse = !revs.no_walk; Sorry, but I do not understand why you frutz with "reverse" after prepare, and not before. I think you can just set no_walk and let setup_revisions() turn it off upon seeing a range (this happens in add_pending_object()). After setup_revisions() returns, if no_walk is still set, you only got individual refs without ranges, so no reversing required. You also need to be careful about "revert" that shares the code; when reverting range A..C in your example, you want to undo C and then B, and you do not want to reverse them. ^ permalink raw reply [flat|nested] 37+ messages in thread
* Re: [PATCH 2/4] revisions passed to cherry-pick should be in "default" order 2012-08-15 18:39 ` Junio C Hamano @ 2012-08-15 20:50 ` Martin von Zweigbergk 0 siblings, 0 replies; 37+ messages in thread From: Martin von Zweigbergk @ 2012-08-15 20:50 UTC (permalink / raw) To: Junio C Hamano; +Cc: git, Christian Couder On Wed, Aug 15, 2012 at 11:39 AM, Junio C Hamano <gitster@pobox.com> wrote: > Martin von Zweigbergk <martin.von.zweigbergk@gmail.com> writes: > >> Makes sense, I'll try to implement it that way. I was afraid that >> we would need to call prepare_revision_walk() once first and then >> if we afterwards find out that we should not walk, we would need >> to call it again without the reverse option. > >> But after looking at >> how rev_info.reverse is used, it seem like it's only used in >> get_revision(), so we can leave it either on or off during the >> prepare_revision_walk() and the and set appropriately before >> calling get_revision(), like so: >> >> init_revisions(&revs); >> revs.no_walk = REVISION_WALK_NO_WALK_UNSORTED; >> setup_revisions(...); >> prepare_revision_walk(&revs); >> revs.reverse = !revs.no_walk; > > Sorry, but I do not understand why you frutz with "reverse" after > prepare, and not before. > > I think you can just set no_walk and let setup_revisions() turn it > off upon seeing a range (this happens in add_pending_object()). Ah, of course. For some reason I thought that was called from prepare_revision_walk() > After setup_revisions() returns, if no_walk is still set, you only > got individual refs without ranges, so no reversing required. Yes, it's in the other case (e.g. 'git cherry-pick A..C', when no_walk is not set), that we need to set reverse before walking. > You also need to be careful about "revert" that shares the code; > when reverting range A..C in your example, you want to undo C and > then B, and you do not want to reverse them. Yep. It looks like this, so should be safe. But thanks for the reminder. if (opts->action != REPLAY_REVERT) opts->revs->reverse ^= 1; ^ permalink raw reply [flat|nested] 37+ messages in thread
* Re: [PATCH 2/4] revisions passed to cherry-pick should be in "default" order 2012-08-13 6:27 ` [PATCH 2/4] revisions passed to cherry-pick should be in "default" order y 2012-08-13 20:05 ` Junio C Hamano @ 2012-08-13 20:10 ` Martin von Zweigbergk 2012-08-13 20:52 ` Junio C Hamano 1 sibling, 1 reply; 37+ messages in thread From: Martin von Zweigbergk @ 2012-08-13 20:10 UTC (permalink / raw) To: git; +Cc: Junio C Hamano, Christian Couder On Sun, Aug 12, 2012 at 11:27 PM, <y@google.com> wrote: > From: Martin von Zweigbergk <martin.von.zweigbergk@gmail.com> > > 'git cherry-pick' internally sets the --reverse option while walking > revisions, so that 'git cherry-pick branch@{u}..branch' will apply the > revisions starting at the oldest one. By the way, I can see the usefulness of --reverse when giving a range, but I think it's a little confusing when not giving a range. So "git cherry-pick A B" will apply B first, then A. I thought I'd mention that explicitly in case it wasn't clear. ^ permalink raw reply [flat|nested] 37+ messages in thread
* Re: [PATCH 2/4] revisions passed to cherry-pick should be in "default" order 2012-08-13 20:10 ` Martin von Zweigbergk @ 2012-08-13 20:52 ` Junio C Hamano 0 siblings, 0 replies; 37+ messages in thread From: Junio C Hamano @ 2012-08-13 20:52 UTC (permalink / raw) To: Martin von Zweigbergk; +Cc: git, Christian Couder Martin von Zweigbergk <martin.von.zweigbergk@gmail.com> writes: > By the way, I can see the usefulness of --reverse when giving a range, > but I think it's a little confusing when not giving a range. "git rev-list --reverse --root v1.0.0" is a way to say "give me a list of commits to be replayed in sequence" without having a bottom, no? Ah, you mean when we do _not_ walk. Yeah, that is why I said that when we do not walk, we should not even call into prepare_revision_walk() in the first place in my earlier message. We should take the commits as given from the revs->pending.objects list instead. With your "no_walk = NO_WALK_UNSORTED", calling prepare_revision_walk() would amont to the same thing, as you would not sort the commits and use them as given by the user. > So "git cherry-pick A B" will apply B first, then A. I am confused a bit. Are you describing a buggy behaviour in the current codebase, or are you saying we should fix it to behave that way? ^ permalink raw reply [flat|nested] 37+ messages in thread
* [PATCH 3/4] cherry-pick/revert: respect order of revisions to pick [not found] ` <1344839240-17402-1-git-send-email-y> 2012-08-13 6:27 ` [PATCH 1/4] teach log --no-walk=unsorted, which avoids sorting y 2012-08-13 6:27 ` [PATCH 2/4] revisions passed to cherry-pick should be in "default" order y @ 2012-08-13 6:27 ` y 2012-08-13 6:27 ` [PATCH 4/4] cherry-pick/revert: default to topological sorting y 3 siblings, 0 replies; 37+ messages in thread From: y @ 2012-08-13 6:27 UTC (permalink / raw) To: Junio C Hamano Cc: git, Christian Couder, Martin von Zweigbergk, Kevin Ballard From: Martin von Zweigbergk <martin.von.zweigbergk@gmail.com> 'git cherry-pick A B' implicitly sends --no-walk=sorted to the revision walker, which means that the older of A and B will be applied first, which is most likely surprising to most. Fix this by instead sending --no-walk=unsorted to the revision walker. Signed-off-by: Martin von Zweigbergk <martin.von.zweigbergk@gmail.com> --- This has actually been reported before, in http://thread.gmane.org/gmane.comp.version-control.git/164794/focus=164807, where I apparently replied myself. Incidentally, it seems like the unrelated bug in 'git show' I reported in that thread is the one that Junio mentioned got fixed recently. builtin/revert.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/builtin/revert.c b/builtin/revert.c index 42ce399..98ad641 100644 --- a/builtin/revert.c +++ b/builtin/revert.c @@ -193,7 +193,7 @@ static void parse_args(int argc, const char **argv, struct replay_opts *opts) struct setup_revision_opt s_r_opt; opts->revs = xmalloc(sizeof(*opts->revs)); init_revisions(opts->revs, NULL); - opts->revs->no_walk = REVISION_WALK_NO_WALK_SORTED; + opts->revs->no_walk = REVISION_WALK_NO_WALK_UNSORTED; if (argc < 2) usage_with_options(usage_str, options); memset(&s_r_opt, 0, sizeof(s_r_opt)); -- 1.7.11.1.104.ge7b44f1 ^ permalink raw reply related [flat|nested] 37+ messages in thread
* [PATCH 4/4] cherry-pick/revert: default to topological sorting [not found] ` <1344839240-17402-1-git-send-email-y> ` (2 preceding siblings ...) 2012-08-13 6:27 ` [PATCH 3/4] cherry-pick/revert: respect order of revisions to pick y @ 2012-08-13 6:27 ` y 2012-08-13 20:23 ` Junio C Hamano 3 siblings, 1 reply; 37+ messages in thread From: y @ 2012-08-13 6:27 UTC (permalink / raw) To: Junio C Hamano; +Cc: git, Christian Couder, Martin von Zweigbergk From: Martin von Zweigbergk <martin.von.zweigbergk@gmail.com> When 'git cherry-pick' and 'git revert' are used with ranges such as 'git cherry-pick A..B', the order of the commits to pick are determined by the default date-based sorting. If a commit has a commit date before the commit date of its parent, it will therfore be applied before its parent. In the context of cherry-pick/revert, this is most likely not what the user expected, so let's enable topological sorting by default. Signed-off-by: Martin von Zweigbergk <martin.von.zweigbergk@gmail.com> --- builtin/revert.c | 1 + 1 file changed, 1 insertion(+) diff --git a/builtin/revert.c b/builtin/revert.c index 98ad641..6880ce5 100644 --- a/builtin/revert.c +++ b/builtin/revert.c @@ -194,6 +194,7 @@ static void parse_args(int argc, const char **argv, struct replay_opts *opts) opts->revs = xmalloc(sizeof(*opts->revs)); init_revisions(opts->revs, NULL); opts->revs->no_walk = REVISION_WALK_NO_WALK_UNSORTED; + opts->revs->topo_order = 1; if (argc < 2) usage_with_options(usage_str, options); memset(&s_r_opt, 0, sizeof(s_r_opt)); -- 1.7.11.1.104.ge7b44f1 ^ permalink raw reply related [flat|nested] 37+ messages in thread
* Re: [PATCH 4/4] cherry-pick/revert: default to topological sorting 2012-08-13 6:27 ` [PATCH 4/4] cherry-pick/revert: default to topological sorting y @ 2012-08-13 20:23 ` Junio C Hamano 2012-08-13 21:50 ` Junio C Hamano 0 siblings, 1 reply; 37+ messages in thread From: Junio C Hamano @ 2012-08-13 20:23 UTC (permalink / raw) To: y; +Cc: git, Christian Couder, Martin von Zweigbergk y@google.com writes: > From: Martin von Zweigbergk <martin.von.zweigbergk@gmail.com> > > When 'git cherry-pick' and 'git revert' are used with ranges such as > 'git cherry-pick A..B', the order of the commits to pick are > determined by the default date-based sorting. If a commit has a commit > date before the commit date of its parent, it will therfore be applied > before its parent. Is that what --topo-order really means? I just tried this: $ git checkout v1.7.12-rc2 $ GIT_COMMITTER_DATE='@0 +0000' git commit --allow-empty -m old $ git log --pretty=fuller -2 and (obviously) the result shows the "old" one and then the v1.7.12-rc2. The point of --topo-order is to deal with merges more sensibly, I think, e.g. with a history with this shape with timestamps, ---1----2----4----7 \ \ 3----5----6----8--- "git log" may show "8 7 6 5 4 3 2 1", while "git log --topo-order" would give you "8 6 5 3 7 4 2 1". And indeed in the context of cherry-pick and revert, topo-order is a more sensible option. So there is nothing wrong in the patch, but the above explanation of yours is flawed. > In the context of cherry-pick/revert, this is most > likely not what the user expected, so let's enable topological sorting > by default. > > Signed-off-by: Martin von Zweigbergk <martin.von.zweigbergk@gmail.com> > --- > builtin/revert.c | 1 + > 1 file changed, 1 insertion(+) > > diff --git a/builtin/revert.c b/builtin/revert.c > index 98ad641..6880ce5 100644 > --- a/builtin/revert.c > +++ b/builtin/revert.c > @@ -194,6 +194,7 @@ static void parse_args(int argc, const char **argv, struct replay_opts *opts) > opts->revs = xmalloc(sizeof(*opts->revs)); > init_revisions(opts->revs, NULL); > opts->revs->no_walk = REVISION_WALK_NO_WALK_UNSORTED; > + opts->revs->topo_order = 1; > if (argc < 2) > usage_with_options(usage_str, options); > memset(&s_r_opt, 0, sizeof(s_r_opt)); ^ permalink raw reply [flat|nested] 37+ messages in thread
* Re: [PATCH 4/4] cherry-pick/revert: default to topological sorting 2012-08-13 20:23 ` Junio C Hamano @ 2012-08-13 21:50 ` Junio C Hamano 0 siblings, 0 replies; 37+ messages in thread From: Junio C Hamano @ 2012-08-13 21:50 UTC (permalink / raw) To: Martin von Zweigbergk; +Cc: git, Christian Couder Junio C Hamano <gitster@pobox.com> writes: > y@google.com writes: > >> From: Martin von Zweigbergk <martin.von.zweigbergk@gmail.com> >> >> When 'git cherry-pick' and 'git revert' are used with ranges such as >> 'git cherry-pick A..B', the order of the commits to pick are >> determined by the default date-based sorting. If a commit has a commit >> date before the commit date of its parent, it will therfore be applied >> before its parent. > > Is that what --topo-order really means? And it turns out that the documentation is crappy. Perhaps something like this, but an illustration may not hurt. Documentation/rev-list-options.txt | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/Documentation/rev-list-options.txt b/Documentation/rev-list-options.txt index d9b2b5b..c147117 100644 --- a/Documentation/rev-list-options.txt +++ b/Documentation/rev-list-options.txt @@ -579,9 +579,10 @@ Commit Ordering By default, the commits are shown in reverse chronological order. --topo-order:: - - This option makes them appear in topological order (i.e. - descendant commits are shown before their parents). + This option makes them appear in topological order. Even + without this option, descendant commits are shown before + their parents, but this tries to avoid showing commits on + multiple lines of history intermixed. --date-order:: ^ permalink raw reply related [flat|nested] 37+ messages in thread
end of thread, other threads:[~2012-08-30 21:02 UTC | newest] Thread overview: 37+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2012-08-10 20:41 cherry-pick and 'log --no-walk' and ordering Martin von Zweigbergk 2012-08-10 21:38 ` Junio C Hamano 2012-08-11 5:34 ` Martin von Zweigbergk 2012-08-11 6:28 ` Junio C Hamano 2012-08-13 6:27 ` [PATCH 0/4] " y 2012-08-13 7:17 ` Junio C Hamano 2012-08-13 7:26 ` Junio C Hamano 2012-08-13 16:09 ` Martin von Zweigbergk 2012-08-13 17:05 ` Junio C Hamano 2012-08-13 18:28 ` Martin von Zweigbergk 2012-08-13 21:31 ` Junio C Hamano 2012-08-13 22:01 ` Martin von Zweigbergk 2012-08-29 6:15 ` [PATCH v2 0/3] revision (no-)walking in order Martin von Zweigbergk 2012-08-29 6:15 ` [PATCH v2 1/3] teach log --no-walk=unsorted, which avoids sorting Martin von Zweigbergk 2012-08-29 17:34 ` Dan Johnson 2012-08-29 17:42 ` Junio C Hamano 2012-08-29 6:15 ` [PATCH v2 2/3] demonstrate broken 'git cherry-pick three one two' Martin von Zweigbergk 2012-08-30 21:02 ` Junio C Hamano 2012-08-29 6:15 ` [PATCH v2 3/3] cherry-pick/revert: respect order of revisions to pick Martin von Zweigbergk 2012-08-29 6:46 ` [PATCH v2 0/3] revision (no-)walking in order Junio C Hamano 2012-08-29 16:20 ` [PATCH] Martin von Zweigbergk has a new e-mail address Martin von Zweigbergk [not found] ` <1344839240-17402-1-git-send-email-y> 2012-08-13 6:27 ` [PATCH 1/4] teach log --no-walk=unsorted, which avoids sorting y 2012-08-13 6:27 ` [PATCH 2/4] revisions passed to cherry-pick should be in "default" order y 2012-08-13 20:05 ` Junio C Hamano 2012-08-13 20:50 ` Martin von Zweigbergk 2012-08-13 21:05 ` Junio C Hamano 2012-08-15 6:05 ` Martin von Zweigbergk 2012-08-15 17:16 ` Junio C Hamano 2012-08-15 18:22 ` Martin von Zweigbergk 2012-08-15 18:39 ` Junio C Hamano 2012-08-15 20:50 ` Martin von Zweigbergk 2012-08-13 20:10 ` Martin von Zweigbergk 2012-08-13 20:52 ` Junio C Hamano 2012-08-13 6:27 ` [PATCH 3/4] cherry-pick/revert: respect order of revisions to pick y 2012-08-13 6:27 ` [PATCH 4/4] cherry-pick/revert: default to topological sorting y 2012-08-13 20:23 ` Junio C Hamano 2012-08-13 21:50 ` Junio C Hamano
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for NNTP newsgroup(s).