Jeff King c9e3a4e76d patch-ids: handle duplicate hashmap entries
This fixes a bug introduced in dfb7a1b4d0 (patch-ids: stop using a
hand-rolled hashmap implementation, 2016-07-29) in which

  git rev-list --cherry-pick A...B

will fail to suppress commits reachable from A even if a commit with
matching patch-id appears in B.

Around the time of that commit, the algorithm for "--cherry-pick" looked
something like this:

  0. Traverse all of the commits, marking them as being on the left or
     right side of the symmetric difference.

  1. Iterate over the left-hand commits, inserting a patch-id struct for
     each into a hashmap, and pointing commit->util to the patch-id
     struct.

  2. Iterate over the right-hand commits, checking which are present in
     the hashmap. If so, we exclude the commit from the output _and_ we
     mark the patch-id as "seen".

  3. Iterate again over the left-hand commits, checking whether
     commit->util->seen is set; if so, exclude them from the output.

At the end, we'll have eliminated commits from both sides that have a
matching patch-id on the other side. But there's a subtle assumption
here: for any given patch-id, we must have exactly one struct
representing it. If two commits from A both have the same patch-id and
we allow duplicates in the hashmap, then we run into a problem:

  a. In step 1, we insert two patch-id structs into the hashmap.

  b. In step 2, our lookups will find only one of these structs, so only
     one "seen" flag is marked.

  c. In step 3, one of the commits in A will have its commit->util->seen
     set, but the other will not. We'll erroneously output the latter.

Prior to dfb7a1b4d0, our hashmap did not allow duplicates. Afterwards,
it used hashmap_add(), which explicitly does allow duplicates.

At that point, the solution would have been easy: when we are about to
add a duplicate, skip doing so and return the existing entry which
matches. But it gets more complicated.

In 683f17ec44 (patch-ids: replace the seen indicator with a commit
pointer, 2016-07-29), our step 3 goes away entirely. Instead, in step 2,
when the right-hand side finds a matching patch_id from the left-hand
side, we can directly mark the left-hand patch_id->commit to be omitted.
Solving that would be easy, too; there's a one-to-many relationship of
patch-ids to commits, so we just need to keep a list.

But there's more. Commit b3dfeebb92 (rebase: avoid computing unnecessary
patch IDs, 2016-07-29) built on that by lazily computing the full
patch-ids. So we don't even know when adding to the hashmap whether two
commits truly have the same id. We'd have to tentatively assign them a
list, and then possibly split them apart (possibly into N new structs)
at the moment we compute the real patch-ids. This could work, but it's
complicated and error-prone.

Instead, let's accept that we may store duplicates, and teach the lookup
side to be more clever. Rather than asking for a single matching
patch-id, it will need to iterate over all matching patch-ids. This does
mean examining every entry in a single hash bucket, but the worst-case
for a hash lookup was already doing that.

We'll keep the hashmap details out of the caller by providing a simple
iteration interface. We can retain the simple has_commit_patch_id()
interface for the other callers, but we'll simplify its return value
into an integer, rather than returning the patch_id struct. That way
they won't be tempted to look at the "commit" field of the return value
without iterating.

Reported-by: Arnaud Morin <arnaud.morin@gmail.com>
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2021-01-12 11:13:32 -08:00
2020-10-05 14:01:52 -07:00
2020-10-29 14:24:09 -07:00
2020-09-22 12:36:28 -07:00
2020-08-13 11:02:15 -07:00
2020-10-05 14:01:52 -07:00
2020-07-30 19:18:06 -07:00
2020-08-27 14:04:49 -07:00
2020-09-19 15:56:06 -07:00
2020-09-19 15:56:06 -07:00
2020-09-29 14:01:20 -07:00
2020-09-02 14:39:25 -07:00
2020-09-25 15:25:38 -07:00
2020-08-11 18:04:11 -07:00
2020-08-10 10:23:57 -07:00
2020-09-30 12:53:47 -07:00
2020-08-27 14:04:49 -07:00
2020-08-27 14:04:49 -07:00
2020-08-24 14:54:31 -07:00
2020-07-30 19:18:06 -07:00
2020-10-05 14:01:51 -07:00
2020-08-27 14:04:49 -07:00
2020-07-30 19:18:06 -07:00
2020-07-28 15:02:17 -07:00
2020-09-03 12:37:04 -07:00
2020-09-03 12:37:04 -07:00
2020-08-10 10:23:57 -07:00
2020-10-04 12:49:08 -07:00
2020-10-29 14:24:09 -07:00
2020-07-30 19:18:06 -07:00
2020-07-30 19:18:06 -07:00
2020-07-30 19:18:06 -07:00
2020-07-28 15:02:17 -07:00
2020-09-18 17:58:00 -07:00
2020-08-28 14:07:09 -07:00
2020-07-30 19:18:06 -07:00
2020-07-30 19:18:06 -07:00
2020-09-22 12:36:28 -07:00
2020-10-05 14:01:54 -07:00
2020-10-05 14:01:54 -07:00
2020-10-29 14:24:09 -07:00
2020-09-03 12:37:04 -07:00
2020-10-05 14:01:54 -07:00
2020-10-05 14:01:54 -07:00
2020-07-30 19:18:06 -07:00
2020-07-28 15:02:17 -07:00
2020-08-11 18:04:11 -07:00
2020-08-13 14:13:39 -07:00
2020-09-02 14:39:25 -07:00
2020-07-30 19:18:06 -07:00
2020-07-30 19:18:06 -07:00
2020-07-30 19:18:06 -07:00
2020-09-03 12:37:04 -07:00
2020-07-28 15:02:17 -07:00
2020-10-05 14:01:52 -07:00
2020-10-05 14:01:52 -07:00

Build status

Git - fast, scalable, distributed revision control system

Git is a fast, scalable, distributed revision control system with an unusually rich command set that provides both high-level operations and full access to internals.

Git is an Open Source project covered by the GNU General Public License version 2 (some parts of it are under different licenses, compatible with the GPLv2). It was originally written by Linus Torvalds with help of a group of hackers around the net.

Please read the file INSTALL for installation instructions.

Many Git online resources are accessible from https://git-scm.com/ including full documentation and Git related tools.

See Documentation/gittutorial.txt to get started, then see Documentation/giteveryday.txt for a useful minimum set of commands, and Documentation/git-<commandname>.txt for documentation of each command. If git has been correctly installed, then the tutorial can also be read with man gittutorial or git help tutorial, and the documentation of each command with man git-<commandname> or git help <commandname>.

CVS users may also want to read Documentation/gitcvs-migration.txt (man gitcvs-migration or git help cvs-migration if git is installed).

The user discussion and development of Git take place on the Git mailing list -- everyone is welcome to post bug reports, feature requests, comments and patches to git@vger.kernel.org (read Documentation/SubmittingPatches for instructions on patch submission). To subscribe to the list, send an email with just "subscribe git" in the body to majordomo@vger.kernel.org. The mailing list archives are available at https://lore.kernel.org/git/, http://marc.info/?l=git and other archival sites.

Issues which are security relevant should be disclosed privately to the Git Security mailing list git-security@googlegroups.com.

The maintainer frequently sends the "What's cooking" reports that list the current status of various development topics to the mailing list. The discussion following them give a good reference for project status, development direction and remaining tasks.

The name "git" was given by Linus Torvalds when he wrote the very first version. He described the tool as "the stupid content tracker" and the name as (depending on your mood):

  • random three-letter combination that is pronounceable, and not actually used by any common UNIX command. The fact that it is a mispronunciation of "get" may or may not be relevant.
  • stupid. contemptible and despicable. simple. Take your pick from the dictionary of slang.
  • "global information tracker": you're in a good mood, and it actually works for you. Angels sing, and a light suddenly fills the room.
  • "goddamn idiotic truckload of sh*t": when it breaks
Description
No description provided
Readme 635 MiB
Languages
C 50.5%
Shell 38.7%
Perl 4.5%
Tcl 3.2%
Python 0.8%
Other 2.1%