v0.12.1 7328df5

changed.go RawHistoryFolder

1// SPDX-License-Identifier: AGPL-3.0-or-later
2
3package gitcli
4
5import (
6	"bufio"
7	"context"
8	"fmt"
9
10	"bnema.dev/ermite/internal/domain"
11	"bnema.dev/ermite/internal/ports"
12)
13
14var _ ports.CIGit = (*Git)(nil)
15
16// emptyTree is the id of the empty tree of a SHA-1 repository, what a diff
17// from "nothing" starts at.
18const emptyTree = "4b825dc642cb6eb9a060e54bf8d69288fbee4904"
19
20// ChangedPaths runs `git diff-tree -r --name-only -z` from base to head, with
21// renames not detected (a rename lists both paths, as GitHub's push filters
22// see it), and stops reading after max paths: truncated tells there were more.
23// A zero base diffs against the empty tree.
24//
25//hexcheck:ignore suspicious-business-logic-in-adapter reads the path list git prints; the bound comes from the port
26func (g *Git) ChangedPaths(ctx context.Context, repo domain.RepoName, base, head domain.ObjectID, limit int) ([]string, bool, error) {
27	if limit < 1 || head.IsZero() {
28		return nil, false, fmt.Errorf("changed paths: %w: limit %d", domain.ErrInvalid, limit)
29	}
30	dir, err := g.repoDir(repo)
31	if err != nil {
32		return nil, false, err
33	}
34	from := emptyTree
35	if !base.IsZero() {
36		from = base.String()
37	}
38	args := readArgs(dir, "diff-tree", "-r", "--name-only", "-z", "--no-renames", "--no-commit-id", "--end-of-options", from, head.String())
39	var (
40		paths     []string
41		truncated bool
42	)
43	err = g.pipe(ctx, args, func(r *bufio.Reader) error {
44		for {
45			name, err := r.ReadString(0)
46			if err != nil {
47				return nil // the end of the output; a failing exit status is reported by pipe
48			}
49			if len(paths) == limit {
50				truncated = true
51				return errStop
52			}
53			paths = append(paths, name[:len(name)-1])
54		}
55	})
56	if err != nil {
57		return nil, false, fmt.Errorf("changed paths %s..%s in %q: %w", from, head, repo, err)
58	}
59	return paths, truncated, nil
60}
61
62// CommitsOffBranches lists the commits reachable from head and from no branch
63// (refs/heads/*), newest first, at most limit. It runs
64// `git log --not --branches --not <head>`: tags do not count, so the commit of
65// another tag that no branch has is listed.
66//
67//hexcheck:ignore suspicious-business-logic-in-adapter parses git output into domain values; the limit comes from the port
68func (g *Git) CommitsOffBranches(ctx context.Context, repo domain.RepoName, head domain.ObjectID, limit int) ([]domain.Commit, bool, error) {
69	if head.IsZero() {
70		return nil, false, fmt.Errorf("commits off branches: %w: no head", domain.ErrInvalid)
71	}
72	// "--not --branches" excludes every branch, the second "--not" turns the
73	// negation off again for the head that follows.
74	return g.logCommits(ctx, repo, head, limit, []string{"--not", "--branches", "--not"}, nil)
75}

Keyboard shortcuts

Single-key shortcuts are on. ctrl k and esc work whatever this says.

ctrl k :
go to a section, branch, tag, file or repository
?
this list
j k
move the row cursor down / up
enter
open the row under the cursor; on Files, a directory opens or closes in place
↑ ↓ ← → home end
in the file tree (focus on a row): previous / next row, close / open a directory or go to its parent / first entry, first / last row. They never open a file
l h
on Files: open a directory or a file / close a directory or go up to its parent, then to the parent page. Elsewhere: into the side panel (on a merge request, its files) / back to the content; there j k move between its controls
g g G
first / last row
/
filter the list; on Files, find a file anywhere in the repository (esc clears, enter opens the best match)
b
switch branch or tag
g s g f g c g b g m g i g r g a
tabs: summary, files, commits, branches & tags, merge requests, issues, releases, actions (when available)
g h
home
w
wide mode: use the whole width of the screen, or not (remembered)
y
copy a permalink pinned to the commit
d u x
diff: split / unified / collapse or expand all
e E
diff: the whole file in view / every file, with the lines the hunks hide
n
merge request: next note in the diff
esc
close a dialog, leave a field

Branches 2

Tags 45

↑↓ moveenter openesc close