Skip to content

Conversation

@soraxas
Copy link
Contributor

@soraxas soraxas commented Oct 26, 2025

This closes #193, and potentially adresses #323

Since the clone / pull / ... command in git subrepo are operating on a different repo, it often doesn't make much sense to trigger the hook, e.g., pre-commit hooks in the main repo.

This PR defaults to use --no-verify flag on these related operation, and the behaviour can also be configured via

The .gitrepo file:

[subrepo]
    ...
    verify = true  # Enable hooks for this subrepo

Copy link
Collaborator

@admorgan admorgan left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The idea is sounds, but as stated in the inline comments I would much rather have the default be that hooks run and subrepos must be configured to disable hooks. I would also prefer that there is only a setting the .gitrepo file if hooks are disabled.

I am ok with allowing a git config to set a default value for running to hooks. I think it would only apply to git subrepo clone and not override the behavior for existing subrepos.

I did not review the tests yet since I am asking for significant changes to how this would work.

local fetch_wanted=false # Fetch requested before a command
local squash_wanted=false # Squash commits on push
local update_wanted=false # Update .gitrepo with --branch and/or --remote
local verify_wanted=false # Run pre-commit and commit-msg hooks (default: skip)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have a lot of subrepos that use pre-commit (the tool) and work fine. I feel that it would be better to default to verifying and only disable verifying if explicitly configured. I would even be ok with adding a git config to globally set you want verify disabled.

local no_verify_flag=' --no-verify'
$verify_wanted && no_verify_flag=''
# shellcheck disable=2086
RUN git commit$no_verify_flag -m "$(get-commit-message)"
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if [[ $commit_msg_file ]]; then
RUN git command --file "$commit_msg_file"
# shellcheck disable=2086
RUN git commit$no_verify_flag --file "$commit_msg_file"
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

else
RUN git commit -m "$commit_message"
# shellcheck disable=2086
RUN git commit$no_verify_flag -m "$commit_message"
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if [[ $commit_msg_file ]]; then
RUN git commit $edit_flag --file "$commit_msg_file"
# shellcheck disable=2086
RUN git commit$no_verify_flag $edit_flag --file "$commit_msg_file"
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

else
RUN git commit $edit_flag -m "$commit_message"
# shellcheck disable=2086
RUN git commit$no_verify_flag $edit_flag -m "$commit_message"
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@soraxas
Copy link
Contributor Author

soraxas commented Oct 30, 2025

The issue was not on the pre-commit hook inside the subrepo, but the one in the main repo.

E.g., say there's a per-commit hook in the main repo, and say perhaps there's a python code formatter there

.
├── app
│   ├── .pre-commit-config.yaml
│   ├── subrepo1
│   ├── docs
│   ├── subrepo2
...

If I were to now clone a subrepo

git subrepo clone SOME_REPO_WITH_PYTHON_CODE new_subrepo

Then if the python code formatter did changed the newly cloned subrepo, the whole repo is now at a dirty state.
e.g.

git-subrepo: Command failed: 'git commit -m git subrepo clone ../py

subrepo:
  subdir:   "py"
  merged:   "12641cf"
upstream:
  origin:   "../py"
  branch:   "master"
  commit:   "12641cf"
git-subrepo:
  version:  "0.4.9"
  origin:   "???"
  commit:   "???"'.
ruff format..............................................................Failed
- hook id: ruff-format
- files were modified by this hook

1 file reformatted

Its at a non-recoverable state. If you want a clean history (of git subrepo clone), then you will need to (i) revert the change, (ii) manually disable your pre-commit hook, then (iii) perform the above clone, (iv) enable your pre-commit hook again, and then (v) perhaps peforms the code formatting in your subrepo to ensure consistency.

In my opinion, it is non-consistent, it leaves things in a dirty state, and intuitively, the hook that people expect to run (if at all) should be

  • the ones inside the subrepo when you perform the clone/commit action
     ├── app
     │   ├── .pre-commit-config.yaml
     │   ├── subrepo1                            # <------ this was the git subrepo ops
     │   │  ├── .pre-commit-config.yaml
    
  • and not the ones at the main repo
     ├── app                                      # <------ but this got executed
     │   ├── .pre-commit-config.yaml
     │   ├── subrepo1                            
     │   │  ├── .pre-commit-config.yaml
    

See #193 (comment) for the prior discussion. Since the hooks inside subrepo cannot be the ones that actually get executed, I don't see why the default behaviour should be to verify

@admorgan
Copy link
Collaborator

I understand that this is the repo containing the subrepo, and that is a feature. The git hooks are doing their job and should not allow you to accept code that doesn't pass their muster. As I said I have many repos that contain subrepos and both the subrepo and the containing repo have very aggressive hooks. I am happy to see that you are using
https://pre-commit.com. See the bottom for how I handle this in pre-commit in a large organization.

Your (and the other issues) argument as I read it is that hooks should be disabled because it is inconvenient when they fail on "3rd party code". I counter argue that your hooks are not properly configured. Your hooks should understand they shouldn't run in git subrepos (there is porcelain commands to get a list of subrepos).

After sleeping on it, I have completely changed my mind on this patch. I now believe (but obviously my mind can be changed) that the follow things are true.

  1. --no-verify is a valid use case for git subrepo
  2. To behave similar to git --no-verify should only be a command line option that must be used for each command it would apply to (It should not be store in a git config or .gitrepo file were it would effect users of the repo
  • Git has declared hooks are a personal tool, and not controlled by the repo. I personally disagree with this, but I will not attempt to override it.
  • It is possible to write hooks that behave the way you desire today without any infrastructure changes in git subrepo
  • Git does not have a mechanism to configure to turn off hooks for a specific repo, they rely on you doing that via the hooks.
  • --no-verify only suppresses 3 of the 29 hooks provided by git, therefore hook users should still be warned about potential stumbling blocks.
  1. Both the parent repository (the subrepo) and the containing repository hooks should be run.

In summary I would accept a patch that adds a --no-verify flag that behaves like git's, but not what was proposed here.

Bonus material:

To disable containing repo hooks for subrepo in pre-commit add to the top of the file:

# Exclude code that is maintained outside this repo
exclude: >
    (?x)^(
          3rdparty/zlib/.*|
          3rdpart/sqlite3.*
    )$
repos:
  - repo <path to clang-format>
    rev:: latest
    hooks:
     - id: clang-format
       exclude: ^$

If you use something like clang-format you can also configure the tool to do the right thing, so either disable it for those directories in the tool configuration or better, submit a .clang-format configuration to the upstream project and leave it enabled and doing the right thing.

Do remember that that repositories hooks won't run when you make changes to the containing repo in that directory, so when you git subrepo push you may have to fix up your patches to follow the rules of that repo.

@soraxas
Copy link
Contributor Author

soraxas commented Nov 1, 2025

Hi thank you for the very detail write out (and including your reflection as well).

I don't agree partially with some of your view points. Points not explicitly mentioned below could be view as agreement with you:

The git hooks are doing their job and should not allow you to accept code that doesn't pass their muster

This part is true

As I said I have many repos that contain subrepos and both the subrepo and the containing repo have very aggressive hooks

The part about the containing repo has aggressive hooks has no bearing on the whole issue at all, as the inner hooks were never respected (I presume this part is clear to you, but mentioning them might muddle the focus on hooks that actually matters here (parent/root), especially to others stumble to this issue)

[we think] ... hooks should be disabled because it is inconvenient when they fail on "3rd party code".

They are more than just inconvenient, they actually are confusing and for someone who don't fully understand the inner working of gir-subrepo (like me initially) they would have no idea what's wrong and dunno how to fix them. The contrived procedure that I mentioned is just me, somehow stumble my way, through me trial n error.

... It should not be store in a git config or .gitrepo file were it would effect users of the repo

Don't agree with it, with details below. But other methods like .gitattributes had always affect the user of the repo.
The current proposed method actually doesn't affect day-to-day committing of modfiled files in the subrepo. (i believe) it only affects the auto committing during initial clone, or pull from remote, which IMO, should never be verified as they represent the commit from remote. Modifying them with hook (without the initial commit) is already make the subrepo diverge from remote

It is possible to write hooks that behave the way you desire today without any infrastructure changes in git subrepo

It requires the changing of hooks, which could also be part of other well established infrastructure.

Git does not have a mechanism to configure to turn off hooks for a specific repo, they rely on you doing that via the hooks.

This point is misleading, because hooks actually requires you to manually installed. Hence there's no "disabling" as enabling is not automatic. Not saying that I agree nor disagree whether hooks should be automatically enabled or not. But the argument that "official git has no way to declare disabling hooks, so git-subrepo should too" is invalid.

Both the parent repository (the subrepo) and the containing repository hooks should be run.

I reckon this first depends on the philosophy of

  1. Viewing subrepo as just like a submodule where it should be treated as a separate module / 3rd part code (but without the submodule issue as elaborated in Q&A). And hence, all parent repo operation should skip the subrepo. And subrepo hook operation should operate in that subrepo.
    i. Eg in normal git submodule, using lfs or other hooks has no bearing in the submodules.
    ii. This is the viewpoint that brings the idea that hooks should be skipped

  2. Subrepo is nothing special. It is just some subdirectory where we happen to be able to push or pull from other remote.
    i. (perhaps this can be a valid viewpoint too, and I believe this is closer to your viewpoint)


Thanks for the pointers on the exclude on solving pre-commit.config. It is indeed a solution, tho only for that kind of hooks

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Make bypassing the pre-commit and commit-msg hooks optional

2 participants