arxanas / git-branchless

High-velocity, monorepo-scale workflow for Git
Apache License 2.0
3.47k stars 89 forks source link

`sync` subcommand with `--pull` does not support negative refspecs #1444

Open ryan-ph opened 1 week ago

ryan-ph commented 1 week ago

Description of the bug

Git v2.29.0 supports negative refspecs to allow filtering which refspecs to ignore.

It seems like git branchless sync --pull does not currently respect this and will cause panics if a negative refspec is specified in the git config.

Example git config specifying a negative refspec for any branches with an underscore prefix

[remote "origin"]
    fetch = ^refs/heads/_*

Expected behavior

When running git branchless sync --pull, I expect all refs to be fetched from the remote following all git refspec rules (i.e. all refs which match postive refspecs and do not match any negative refspecs), and all local refs to be updated.

Actual behavior

A panic:

$ git sync --pull
branchless: running command: git fetch --all
branchless: processing 1 update: remote branch origin/master
From github.com:**********
   1cbda20c5530..7aebefa5462d  master        -> origin/master
branchless: processing 1 update: remote branch origin/fix-inventory
 * [new branch]                fix-inventory -> origin/fix-inventory
The application panicked (crashed).
Message:  A fatal error occurred:
   0: could not find upstream branch for branch with name 'master': '^refs/heads/_*' is not a valid refspec.; class=Invalid (3)
   1: '^refs/heads/_*' is not a valid refspec.; class=Invalid (3)

Version of rustc

No response

Automated bug report

No response

Version of git-branchless

git-branchless-opts 0.10.0

Version of git

git version 2.44.0

ryan-ph commented 1 week ago

Seems like this is an upstream issue: https://github.com/libgit2/libgit2/issues/6741

arxanas commented 4 days ago

Thanks for reporting. It's unfortunate because, as far as I know, we don't actually need or care about the fetch refspec for the main branch. I think it's hitting this code path and asking for the upstream branch:

https://github.com/arxanas/git-branchless/blob/2be0fd031979e37dfdf8870a3058f1802af4f7b1/git-branchless-lib/src/git/reference.rs#L277-L296

And then I guess we're making a Branch object, which probably involves parsing all the information, not just the upstream branch name.


I only glanced through it, but it's possible that we only need the OID of upstream branch, and not the full branch information. Namely, we might be able to call this function instead:

https://github.com/arxanas/git-branchless/blob/2be0fd031979e37dfdf8870a3058f1802af4f7b1/git-branchless-lib/src/git/reference.rs#L298-L308

where we're doing this in sync:

https://github.com/arxanas/git-branchless/blob/2be0fd031979e37dfdf8870a3058f1802af4f7b1/git-branchless/src/commands/sync.rs#L170-L183

and then maybe we would avoid hitting the unimplemented libgit2 code path? If you're interested, you could try it to see if it fixes your error.

ryan-ph commented 3 days ago

Thanks for all the code pointers! Will give it a shot when I get some free time (hopefully in the next week)