Hey Junio. On Tue, 2020-04-21 at 12:14 -0700, Junio C Hamano wrote: > You can compute the commits that are not reachable from any of the > signed tags. > > git rev-list --all --not $list_tags_and_commits_you_trust_here > > will enumerate all the commits that are not reachable from those > tags. And with reachable you mean: "commits which were not before the commits I trust" ("before obviously again not in terms of their date, but their position in the tree"). > But your "have everything dropped" is a fuzzy notion and you must be > more precise to define what you want. Imagine this history: > > > ----o-----o-----L-----x----x-----x-----x-----x----x HEAD (master) > / > / > / > ... ------o----o----G > > where you have two people you trust (Linus and Greg), HEAD is the > tip of your 'master' branch, probably you fetched from Linus, L and > G are the two recent tags Linus and Greg signed. > > If you enumerate commits that are not reachable from L or G, you'll > get all commits that are marked with 'x'. Commits marked with 'o' > are reachable from either 'L' or 'G', and you would want to keep > them. That seems to be more or less what I'd want. > Now, you need to define what you mean by "have everything dropped". > You can remove commits 'x' but then after that where would your > 'master' branch point at? There is no good answer to that question. Hmm well naively I'd have said master should point to L, assuming Greg's branch was merged into it and assuming git knows which branch was the one merged into. Of course that would leave Greg's branch possibly dangling at G. Maybe one could handle such cases like this: ----o-----o-----L-----x----x-----x-----x-----x----x HEAD (master) / / / ... -----t----o----G If the former branch name can be determined (from the commit message?), recreate it. If not, the commits from Greg's branch could be either left unreachable or maybe, with some special option, could be pointed at by some newly created branch-name foo-1 or whatever. If Greg's branch contains a commit pointed to by tag (here named t), at least this would be reachable anyway. But I guess for the use case I'm thinking about, unreachable commits wouldn't be that much of a problem. > What you could do is remove all branches and tags except for the > signed tags you trust from your repository and then use "git repack" > the repository. Then there will be tags that point at L and G but > you'd be discarding 'master' (which is not signed) and repack will > discard all 'x' in the sample history illustrated above. Well one could probably just manually set master to some reasonable commit, i.e. the one which was likely anyway master at some point in time, until Linus added further commits. Is there an easy (like for people who don't dream in git ;-) ) and ideally fast way to do all this. I would have guessed that a command which does this more or less out of the box, might be quite helpful for security conscious people. The scenario shouldn't be so rare: - one clones a repo, where commits are usually not signed, but tags are - one has a number of trusted people and can even securely retrieve their keys (in my case, Debian ships Linus' and Greg's key in the source package of the kernel) - one needs to work with the repo, including any older states in the history (in my case it's trying to bisect the - for me - showstopper bug: https://bugzilla.kernel.org/show_bug.cgi?id=207245 ) - one doesn't want to use anything which is not signed by trusted people, so basically one wants a repo, as if it would have just been cloned when all branches/etc. were at the state of a signed tag (or commit). So I have something like the (stable)kernel repo which looks a bit like (with (L) and (G) indicating who signed): x---x---x--- foo / ----o-----v.5.5(L)----o----o-----v.5.6(L)----x-----x----x master \ \ \ o----v.5.6.1(G)---o----v.5.6.1(G) \ o----o----v.5.5.1(G)---o---o---v.5.5.1(G)---x---x A command like: git drop-unsigned-stuff --trusted-key 00411886 --trusted-key 6092693E would end up in this (and even garbage-collect all unreachable stuff already, unless one uses some special option): ----o-----v.5.5(L)----o----o-----v.5.6(L) master \ \ \ o----v.5.6.1(G)---o----v.5.6.1(G) \ o----o----v.5.5.1(G)---o---o---v.5.5.1(G) So with that repo, unless I fetch something new, I could be sure, everything I have or I could potentially checkout was at some time trusted by someone I trust. In the example above, a branch (foo) which is completely unsigned would consequentially be dropped completely. In earlier days, most projects released their (signed) sources as some tarball,...many nowadays just set (and sometimes even sign) some git tag (which is great)... but with the old tarball one could have been sure that everything in it is trusted (if one trusts the signer), which git this is of course less simple. So such cases I would have liked a simple way to get rid of everything untrusted. But probably my use case is just too exotic, otherwise git would already have a helper command for it ^^ Cheers, Chris.