@@ -546,51 +546,56 @@ vcsGit =
546
546
(\ e -> if isPermissionError e then removePathForcibly dotGitModulesPath else throw e)
547
547
else removeDirectoryRecursive dotGitModulesPath
548
548
549
- -- If we want a particular branch or tag, fetch it.
550
- ref <- case srpBranch `mplus` srpTag of
551
- Nothing -> pure " HEAD"
552
- Just ref -> do
553
- -- /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\
554
- -- /!\ MULTIPLE HOURS HAVE BEEN LOST HERE!! /!\
555
- -- /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\
556
- --
557
- -- If you run `git fetch origin MY_TAG`, then the tag _will_ be
558
- -- fetched, but no local ref (e.g. `refs/tags/MY_TAG`) will be
559
- -- created.
560
- --
561
- -- This means that doing `git fetch origin MY_TAG && git reset --hard
562
- -- MY_TAG` will fail with a message like `unknown revision MY_TAG`.
563
- --
564
- -- There are two ways around this:
565
- --
566
- -- 1. Provide a refmap explicitly:
567
- --
568
- -- git fetch --refmap="+refs/tags/*:refs/tags/*" origin MYTAG
569
- --
570
- -- This tells Git to create local tags matching remote tags. It's
571
- -- not in the default refmap so you need to set it explicitly.
572
- -- (You can also set it with `git config set --local
573
- -- remote.origin.fetch ...`.)
574
- --
575
- -- 2. Use `FETCH_HEAD` directly: Git writes a `FETCH_HEAD` ref
576
- -- containing the commit that was just fetched. This feels a bit
577
- -- nasty but seems to work reliably, even if nothing was fetched.
578
- -- (That is, deleting `FETCH_HEAD` and re-running a `git fetch`
579
- -- command will succesfully recreate the `FETCH_HEAD` ref.)
580
- --
581
- -- Option 2 is what Cabal has done historically, and we're keeping it
582
- -- for now. Option 1 is possible but seems to have little benefit.
583
- git localDir (" fetch" : verboseArg ++ [" origin" , ref])
584
- pure " FETCH_HEAD"
585
-
586
- -- Then, reset to the appropriate ref.
587
- git localDir $
588
- " reset"
589
- : verboseArg
590
- ++ [ " --hard"
591
- , ref
592
- , " --"
593
- ]
549
+ -- `doShallow` controls whether we use a shallow clone.
550
+ -- If the clone is shallow, make sure to fetch specified revisions before
551
+ -- using them.
552
+ when doShallow $ do
553
+
554
+ -- If we want a particular branch or tag, fetch it.
555
+ ref <- case srpBranch `mplus` srpTag of
556
+ Nothing -> pure " HEAD"
557
+ Just ref -> do
558
+ -- /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\
559
+ -- /!\ MULTIPLE HOURS HAVE BEEN LOST HERE!! /!\
560
+ -- /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\
561
+ --
562
+ -- If you run `git fetch origin MY_TAG`, then the tag _will_ be
563
+ -- fetched, but no local ref (e.g. `refs/tags/MY_TAG`) will be
564
+ -- created.
565
+ --
566
+ -- This means that doing `git fetch origin MY_TAG && git reset --hard
567
+ -- MY_TAG` will fail with a message like `unknown revision MY_TAG`.
568
+ --
569
+ -- There are two ways around this:
570
+ --
571
+ -- 1. Provide a refmap explicitly:
572
+ --
573
+ -- git fetch --refmap="+refs/tags/*:refs/tags/*" origin MYTAG
574
+ --
575
+ -- This tells Git to create local tags matching remote tags. It's
576
+ -- not in the default refmap so you need to set it explicitly.
577
+ -- (You can also set it with `git config set --local
578
+ -- remote.origin.fetch ...`.)
579
+ --
580
+ -- 2. Use `FETCH_HEAD` directly: Git writes a `FETCH_HEAD` ref
581
+ -- containing the commit that was just fetched. This feels a bit
582
+ -- nasty but seems to work reliably, even if nothing was fetched.
583
+ -- (That is, deleting `FETCH_HEAD` and re-running a `git fetch`
584
+ -- command will succesfully recreate the `FETCH_HEAD` ref.)
585
+ --
586
+ -- Option 2 is what Cabal has done historically, and we're keeping it
587
+ -- for now. Option 1 is possible but seems to have little benefit.
588
+ git localDir (" fetch" : verboseArg ++ [" origin" , ref])
589
+ pure " FETCH_HEAD"
590
+
591
+ -- Then, reset to the appropriate ref.
592
+ git localDir $
593
+ " reset"
594
+ : verboseArg
595
+ ++ [ " --hard"
596
+ , ref
597
+ , " --"
598
+ ]
594
599
595
600
-- We need to check if `.gitmodules` exists _after_ the `git reset` call.
596
601
gitModulesExists <- doesFileExist gitModulesPath
@@ -608,8 +613,31 @@ vcsGit =
608
613
{ progInvokeCwd = Just cwd
609
614
}
610
615
616
+ -- Beware: if the user supplied revision for the source repository
617
+ -- package is /not/ a full hash, then we cannot fetch it, which means
618
+ -- we cannot do a shallow clone (--depth=1).
619
+ -- See #10605.
620
+ doShallow
621
+ | Nothing <- srpTag
622
+ -- No tag, OK for shallow
623
+ = True
624
+
625
+ -- full hashes are 40 characters
626
+ | Just tg <- srpTag
627
+ , length tg >= 40
628
+ = True
629
+
630
+ | otherwise
631
+ = False
632
+
633
+ depthIs1
634
+ | doShallow = [" --depth=1" ]
635
+ | otherwise = []
636
+
611
637
cloneArgs =
612
- [" clone" , " --depth=1" , " --no-checkout" , loc, localDir]
638
+ [" clone" ]
639
+ ++ depthIs1
640
+ ++ [ " --no-checkout" , loc, localDir]
613
641
++ case peer of
614
642
Nothing -> []
615
643
Just peerLocalDir -> [" --reference" , peerLocalDir]
0 commit comments