Skip to content

Commit 22012f9

Browse files
authored
Merge pull request #11 from raszi/feat/default-origin-main
feat: compare with origin/main by default
2 parents 6ed4722 + 5cd04b4 commit 22012f9

8 files changed

Lines changed: 128 additions & 23 deletions

File tree

‎README.org‎

Lines changed: 70 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,30 @@
55

66
This is a small tool that helps to list the files you have changed (added/modified/removed) in your git branch.
77

8-
This can be useful when working with large repositories, as you can run tools on a specific subset of files instead of the entire repository.
9-
It can be easily integrated into your workflow to streamline your development process.
8+
** Motivation
9+
10+
The author wrote this tool for a project with very slow tests and tools. A full run took too long for each small change. The author wanted to run the tests and tools only on the files of the current branch.
11+
12+
The tool lists these files:
13+
14+
- the files from the commits since the branch left ~origin/main~
15+
- the files with uncommitted changes
16+
- the untracked files
17+
18+
The tool only prints the list. Send the list to another tool:
19+
20+
#+begin_src bash
21+
$ git-changed -e '**/*.rs' | xargs rustfmt
22+
#+end_src
23+
24+
** Alternatives
25+
26+
- ~git diff --name-only $(git merge-base origin/main HEAD)~ lists the committed and the uncommitted changes. It does not list the untracked files. Add ~git ls-files --others --exclude-standard~ for those.
27+
- lint-staged (https://github.com/lint-staged/lint-staged) runs commands on the staged files before a commit. It needs Node.js.
28+
- lefthook (https://github.com/evilmartians/lefthook) is a git hook manager. It gives ~{staged_files}~ and ~{push_files}~ to the commands. A ~lefthook~ command can also call ~git-changed~.
29+
- tj-actions/changed-files (https://github.com/tj-actions/changed-files) lists the changed files in GitHub Actions.
30+
31+
~git-changed~ does not run commands and does not manage hooks. It only lists the files, so you can use it in a terminal, in a hook, or in CI.
1032

1133
** Install with Nix
1234

@@ -55,7 +77,9 @@ $ git-changed '*.rs' | xargs rustfmt
5577

5678
*** Default branch
5779

58-
Per default the script uses the ~init.defaultBranch~ if that is configured, and falls back to ~main~, you can override this setting by a command line parameter:
80+
The tool compares your branch with ~origin/main~. It does not use your local ~main~ branch, because that branch can be old.
81+
82+
To use a different base, give the ~--base~ option:
5983

6084
#+begin_src bash
6185
$ git-changed --base development
@@ -73,11 +97,7 @@ Or only for the current repository:
7397
$ git config changed.defaultBranch development
7498
#+end_src
7599

76-
The value can be any revision. If your local ~main~ is older than the remote one, the tool also lists the files that changed on ~main~ after your local copy. To compare with the remote branch, set:
77-
78-
#+begin_src bash
79-
$ git config changed.defaultBranch origin/main
80-
#+end_src
100+
The value can be any revision, for example a branch, a tag, or ~upstream/main~.
81101

82102
*** Filtering files with glob pattern
83103

@@ -101,7 +121,48 @@ Some tools may not handle files that no longer exist. With this option, you can
101121
$ git-changed -e
102122
#+end_src
103123

104-
*** A more complex example
124+
*** Examples
125+
126+
Run only the specs of the branch. A new spec file is in the list before you run ~git add~:
127+
128+
#+begin_src bash
129+
$ git-changed -e 'spec/**/*_spec.rb' | xargs bundle exec rspec
130+
#+end_src
131+
132+
Lint the changed files. The ~-e~ option removes the deleted files, so the linter does not fail on a missing file:
133+
134+
#+begin_src bash
135+
$ git-changed -e -0 '**/*.py' | xargs -0 ruff check
136+
#+end_src
137+
138+
Run the tests again each time that you save a changed file. entr (https://github.com/eradman/entr) reads the list of files to watch from standard input:
139+
140+
#+begin_src bash
141+
$ git-changed -e '**/*.rs' | entr -c cargo test
142+
#+end_src
143+
144+
Open all changed files in the editor:
145+
146+
#+begin_src bash
147+
$ vim $(git-changed -e)
148+
#+end_src
149+
150+
Select one changed file with fzf (https://github.com/junegunn/fzf) and open it:
151+
152+
#+begin_src bash
153+
$ vim "$(git-changed -e | fzf)"
154+
#+end_src
155+
156+
Run a linter before each push with lefthook. The list contains all the work on the branch, also the work that you did not commit:
157+
158+
#+begin_src yaml
159+
pre-push:
160+
commands:
161+
rubocop:
162+
run: git-changed -e -0 '**/*.rb' | xargs -0 bundle exec rubocop
163+
#+end_src
164+
165+
Compare with the ~development~ branch and compile each changed file:
105166

106167
#+begin_src bash
107168
$ git-changed -0 -b development '**/*.rs' | xargs -0 -n 1 rustc

‎src/git.rs‎

Lines changed: 7 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,8 @@ use std::collections::BTreeSet;
1111
use std::path::Path;
1212
use std::path::PathBuf;
1313

14-
const CONFIG_PATHS: [&str; 2] = ["changed.defaultBranch", "init.defaultBranch"];
15-
const DEFAULT_BRANCH: &str = "main";
14+
const CONFIG_PATH: &str = "changed.defaultBranch";
15+
const DEFAULT_BRANCH: &str = "origin/main";
1616

1717
pub fn open_repository(directory: &Path) -> Result<Repository> {
1818
Repository::discover(directory)
@@ -56,18 +56,13 @@ fn canonical(path: &Path) -> Result<PathBuf> {
5656
fn default_branch(repo: &Repository) -> Result<String> {
5757
let config = repo.config().context("Cannot read the git config")?;
5858

59-
for path in CONFIG_PATHS {
60-
match config.get_string(path) {
61-
Ok(branch) => return Ok(branch),
62-
Err(error) if error.code() == ErrorCode::NotFound => continue,
63-
Err(error) => {
64-
return Err(error)
65-
.with_context(|| format!("Cannot read {path} from the git config"))
66-
}
59+
match config.get_string(CONFIG_PATH) {
60+
Ok(branch) => Ok(branch),
61+
Err(error) if error.code() == ErrorCode::NotFound => Ok(DEFAULT_BRANCH.to_string()),
62+
Err(error) => {
63+
Err(error).with_context(|| format!("Cannot read {CONFIG_PATH} from the git config"))
6764
}
6865
}
69-
70-
Ok(DEFAULT_BRANCH.to_string())
7166
}
7267

7368
fn committed_changes(repo: &Repository, base: &str) -> Result<Vec<String>> {

‎tests/features/default.feature‎

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
Feature: Compare with origin/main by default
2+
3+
Background: A git repository with a remote branch
4+
Given an empty directory
5+
When the user executes the command: "git init --initial-branch=main"
6+
And the user executes the command: "git config user.name 'John Doe'"
7+
And the user executes the command: "git config user.email 'jdoe@example.com'"
8+
And the user executes the command: "git commit --allow-empty --message 'Initial commit'"
9+
And the user executes the command: "git update-ref refs/remotes/origin/main main"
10+
11+
Scenario: It displays the commits that are not pushed to origin/main
12+
When the user executes the command: "touch README.md"
13+
And the user executes the command: "git add README.md"
14+
And the user executes the command: "git commit --message 'Adding README'"
15+
And the user executes the tool like: "git-changed"
16+
Then it succeeds with the following output
17+
"""
18+
README.md
19+
"""
20+
21+
Scenario: It ignores an old local main branch
22+
When the user executes the command: "git switch --create upstream"
23+
And the user executes the command: "touch LICENSE"
24+
And the user executes the command: "git add LICENSE"
25+
And the user executes the command: "git commit --message 'Adding LICENSE'"
26+
And the user executes the command: "git update-ref refs/remotes/origin/main upstream"
27+
And the user executes the command: "git switch --create feature"
28+
And the user executes the command: "touch README.md"
29+
And the user executes the command: "git add README.md"
30+
And the user executes the command: "git commit --message 'Adding README'"
31+
And the user executes the tool like: "git-changed"
32+
Then it succeeds with the following output
33+
"""
34+
README.md
35+
"""
36+
37+
Scenario: It fails if origin/main does not exist
38+
When the user executes the command: "git update-ref -d refs/remotes/origin/main"
39+
And the user executes the tool like: "git-changed"
40+
Then it fails with the following error
41+
"""
42+
Cannot find the commit of origin/main: revspec 'origin/main' not found; class=Reference (4); code=NotFound (-3)
43+
"""

‎tests/features/empty.feature‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ Feature: Empty git repository
66
And the user executes the command: "git config user.name 'John Doe'"
77
And the user executes the command: "git config user.email 'jdoe@example.com'"
88
And the user executes the command: "git commit --allow-empty --message 'Initial commit'"
9+
And the user executes the command: "git update-ref refs/remotes/origin/main main"
910

1011
Scenario: It displays nothing
1112
When the user executes the tool like: "git-changed"

‎tests/features/non-empty.feature‎

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ Feature: Non-empty git repository
66
And the user executes the command: "git config user.name 'John Doe'"
77
And the user executes the command: "git config user.email 'jdoe@example.com'"
88
And the user executes the command: "git commit --allow-empty --message 'Initial commit'"
9+
And the user executes the command: "git update-ref refs/remotes/origin/main main"
910
And the user executes the command: "touch README.md"
1011
And the user executes the command: "git add README.md"
1112

@@ -31,10 +32,11 @@ Feature: Non-empty git repository
3132
README.md
3233
"""
3334

34-
Rule: With changes committed on the base branch
35+
Rule: With changes pushed to the base branch
3536

36-
Background: With committed changes
37+
Background: With pushed changes
3738
When the user executes the command: "git commit --message 'Adding README'"
39+
And the user executes the command: "git update-ref refs/remotes/origin/main main"
3840

3941
Scenario: It displays nothing if there are no changes
4042
When the user executes the tool like: "git-changed"

‎tests/features/output.feature‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ Feature: Output
66
And the user executes the command: "git config user.name 'John Doe'"
77
And the user executes the command: "git config user.email 'jdoe@example.com'"
88
And the user executes the command: "git commit --allow-empty --message 'Initial commit'"
9+
And the user executes the command: "git update-ref refs/remotes/origin/main main"
910
And the user executes the command: "touch c.md a.md e.md b.md d.md"
1011

1112
Scenario: It displays the files in sorted order

‎tests/features/subdirectory.feature‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ Feature: Run the tool in a subdirectory
66
And the user executes the command: "git config user.name 'John Doe'"
77
And the user executes the command: "git config user.email 'jdoe@example.com'"
88
And the user executes the command: "git commit --allow-empty --message 'Initial commit'"
9+
And the user executes the command: "git update-ref refs/remotes/origin/main main"
910
And the user executes the command: "mkdir src"
1011
And the user executes the command: "touch README.md src/main.rs"
1112
And the user executes the command: "git add README.md src/main.rs"

‎tests/features/untracked.feature‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ Feature: Untracked files
66
And the user executes the command: "git config user.name 'John Doe'"
77
And the user executes the command: "git config user.email 'jdoe@example.com'"
88
And the user executes the command: "git commit --allow-empty --message 'Initial commit'"
9+
And the user executes the command: "git update-ref refs/remotes/origin/main main"
910
And the user executes the command: "mkdir docs"
1011
And the user executes the command: "touch docs/guide.md"
1112

0 commit comments

Comments
 (0)