Skip to content

git fetch messes up shallow clones #573

@howtonotwin

Description

@howtonotwin

I've got a shallow clone of nixpkgs together with a script to let me "git fetch" to it properly. Long story short, its master tracks NixOS/nixpkgs's master, its depth is neither an integer nor fixed, and when I make a branch to do something master will usually end up advancing by the time I'm ready to run nixpkgs-review

      o <---- master (advances with a cronjob)
     /|\
    / | \          o <- my-topic-branch
   / /|  \/-------/
  / | |\  \
 /  | | |  \
~~~~~~~~~~~~~ <- commits listed in .git/shallow (widened over time by cronjob)

nixpkgs-review puts my workflow in peril in a couple of ways:

  • It does git fetch --depth=<n> if it sees the repository is shallow. While it does take care to use its own namespace of refs, .git/shallow is not namespaced. The --depth=<n> beheads my history, disconnecting master from my-topic-branch. This causes the dreaded "refusing to merge unrelated histories" error, even if my master was already up to date (that is, if a fetch was not necessary) and even if my repository otherwise contained enough history to merge master and my-topic-branch.

    That is, nixpkgs-review turns my repository into the following and then dies about it

          o <---- master (advances with a cronjob)
          ~ <- new shallow boundary due to --depth=<n>
                       
              o <- my-topic-branch
             / \
            /   \
           ~~~~~~~ <- partial old contents of .git/shallow
    

    Not only does nixpkgs-review fail, but a large chunk of the repository has become unreachable. I can manually fix it by deleting the offending new commits from .git/shallow, but in the mean time a git gc could theoretically remove some of the unreachable commits and prune the now-extraneous entries from .git/shallow and make the situation permanent.

    TL;DR: git fetch --depth=<n> is logically a destructive operation. nixpkgs-review shouldn't be doing it.

  • It does git fetch at all. git fetch (at least, as of git-2.50.1) simply doesn't handle shallow repositories very well. Even if nixpkgs-review were patched not to pass --depth=<n> to git fetch, if NixOS/nixpkgs has advanced beyond my master and nixpkgs-review does a git fetch of the new tip commit, then that git fetch may pull in a line of commits that goes around my shallow boundary and thus start pulling down the whole history of nixpkgs.

          o <---- NixOS/nixpkgs's master
         /|\
        / | \
       /  o <----- my master
      /  /|\  \
     /  / | \  \
    |  ~~~~~~ <- my .git/shallow
    |
    v to rest of nixpkgs history (huge)
      (to add insult to injury git fetch is incredibly slow at negotiating which commits it wants in this case)
    

    This is much less of a problem; were this to happen I could just interrupt the fetch and run my own script to update my repository properly before rerunning nixpkgs-review.

All that said, I think nixpkgs-review should consider doing some or all of the following:

  • Provide an option to override the shallow repository detection and make sure --depth is never passed to git fetch.
    • Actually, I can't think of a situation where anyone would benefit from nixpkgs-review passing --depth to git fetch. Maybe this code should be off by default or even removed?
  • Provide an option to make sure git fetch never happens at all. If no new commits need to be fetched anyway, then nixpkgs-review should simply create a ref without using git fetch. If new commits do need to be fetched, nixpkgs-review could either let the user specify a custom command or simply error out.
  • Change the comment in the README about shallow clones. The problem with shallow clones is not so much insufficient history being available to merge topic branches into master, but rather the standard git tools simply don't know how to bring a shallow repository up to date without either breaking the history or breaking the shallowness (and current nixpkgs-review chooses to break the history).

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions