git: avoid "bad object" messages when force-pushing
If a user attempts to force-push over a ref and we don't currently have the object that the reference currently points to, our pre-push hook will fail with a message like the following: ref foo:: Error in git rev-list --stdin --objects --not --remotes=origin --: exit status 128 fatal: bad object 1aabb695d63c4d4afe731ab69573893390526896 This occurs because we pass the existing object name to git rev-list as something to exclude. Normally, this is a good idea, since it means we can short-circuit the traversal since we already know what the other side has. However, in this case, it causes unwanted problems. What we really want is for Git to just ignore an object if it's bad, and fortunately the rev-list --ignore-missing object does exactly this, so let's use it. Note that we must pass it before the --stdin option since otherwise it has no effect, so move the --stdin option to the end of the command.
This commit is contained in:
parent
d38724823c
commit
aab142ddb9
@ -225,7 +225,7 @@ func NewRevListScanner(include, excluded []string, opt *ScanRefsOptions) (*RevLi
|
||||
// occurred.
|
||||
func revListArgs(include, exclude []string, opt *ScanRefsOptions) (io.Reader, []string, error) {
|
||||
var stdin io.Reader
|
||||
args := []string{"rev-list", "--stdin"}
|
||||
args := []string{"rev-list"}
|
||||
if !opt.CommitsOnly {
|
||||
args = append(args, "--objects")
|
||||
}
|
||||
@ -251,6 +251,7 @@ func revListArgs(include, exclude []string, opt *ScanRefsOptions) (io.Reader, []
|
||||
case ScanAllMode:
|
||||
args = append(args, "--all")
|
||||
case ScanRangeToRemoteMode:
|
||||
args = append(args, "--ignore-missing")
|
||||
if len(opt.SkippedRefs) == 0 {
|
||||
args = append(args, "--not", "--remotes="+opt.Remote)
|
||||
stdin = strings.NewReader(strings.Join(
|
||||
@ -263,7 +264,7 @@ func revListArgs(include, exclude []string, opt *ScanRefsOptions) (io.Reader, []
|
||||
default:
|
||||
return nil, nil, errors.Errorf("unknown scan type: %d", opt.Mode)
|
||||
}
|
||||
return stdin, append(args, "--"), nil
|
||||
return stdin, append(args, "--stdin", "--"), nil
|
||||
}
|
||||
|
||||
func includeExcludeShas(include, exclude []string) []string {
|
||||
|
@ -57,7 +57,7 @@ func TestRevListArgs(t *testing.T) {
|
||||
SkipDeletedBlobs: false,
|
||||
},
|
||||
ExpectedStdin: fmt.Sprintf("%s\n^%s", s1, s2),
|
||||
ExpectedArgs: []string{"rev-list", "--stdin", "--objects", "--do-walk", "--"},
|
||||
ExpectedArgs: []string{"rev-list", "--objects", "--do-walk", "--stdin", "--"},
|
||||
},
|
||||
"scan refs not deleted, left and right": {
|
||||
Include: []string{s1}, Exclude: []string{s2}, Opt: &ScanRefsOptions{
|
||||
@ -65,7 +65,7 @@ func TestRevListArgs(t *testing.T) {
|
||||
SkipDeletedBlobs: true,
|
||||
},
|
||||
ExpectedStdin: fmt.Sprintf("%s\n^%s", s1, s2),
|
||||
ExpectedArgs: []string{"rev-list", "--stdin", "--objects", "--no-walk", "--"},
|
||||
ExpectedArgs: []string{"rev-list", "--objects", "--no-walk", "--stdin", "--"},
|
||||
},
|
||||
"scan refs deleted, left only": {
|
||||
Include: []string{s1}, Opt: &ScanRefsOptions{
|
||||
@ -73,7 +73,7 @@ func TestRevListArgs(t *testing.T) {
|
||||
SkipDeletedBlobs: false,
|
||||
},
|
||||
ExpectedStdin: s1,
|
||||
ExpectedArgs: []string{"rev-list", "--stdin", "--objects", "--do-walk", "--"},
|
||||
ExpectedArgs: []string{"rev-list", "--objects", "--do-walk", "--stdin", "--"},
|
||||
},
|
||||
"scan refs not deleted, left only": {
|
||||
Include: []string{s1}, Opt: &ScanRefsOptions{
|
||||
@ -81,13 +81,13 @@ func TestRevListArgs(t *testing.T) {
|
||||
SkipDeletedBlobs: true,
|
||||
},
|
||||
ExpectedStdin: s1,
|
||||
ExpectedArgs: []string{"rev-list", "--stdin", "--objects", "--no-walk", "--"},
|
||||
ExpectedArgs: []string{"rev-list", "--objects", "--no-walk", "--stdin", "--"},
|
||||
},
|
||||
"scan all": {
|
||||
Include: []string{s1}, Exclude: []string{s2}, Opt: &ScanRefsOptions{
|
||||
Mode: ScanAllMode,
|
||||
},
|
||||
ExpectedArgs: []string{"rev-list", "--stdin", "--objects", "--all", "--"},
|
||||
ExpectedArgs: []string{"rev-list", "--objects", "--all", "--stdin", "--"},
|
||||
},
|
||||
"scan left to remote, no skipped refs": {
|
||||
Include: []string{s1}, Opt: &ScanRefsOptions{
|
||||
@ -96,7 +96,7 @@ func TestRevListArgs(t *testing.T) {
|
||||
SkippedRefs: []string{},
|
||||
},
|
||||
ExpectedStdin: s1,
|
||||
ExpectedArgs: []string{"rev-list", "--stdin", "--objects", "--not", "--remotes=origin", "--"},
|
||||
ExpectedArgs: []string{"rev-list", "--objects", "--ignore-missing", "--not", "--remotes=origin", "--stdin", "--"},
|
||||
},
|
||||
"scan left to remote, skipped refs": {
|
||||
Include: []string{s1}, Exclude: []string{s2}, Opt: &ScanRefsOptions{
|
||||
@ -104,7 +104,7 @@ func TestRevListArgs(t *testing.T) {
|
||||
Remote: "origin",
|
||||
SkippedRefs: []string{"a", "b", "c"},
|
||||
},
|
||||
ExpectedArgs: []string{"rev-list", "--stdin", "--objects", "--"},
|
||||
ExpectedArgs: []string{"rev-list", "--objects", "--ignore-missing", "--stdin", "--"},
|
||||
ExpectedStdin: s1 + "\n^" + s2 + "\na\nb\nc",
|
||||
},
|
||||
"scan unknown type": {
|
||||
@ -119,7 +119,7 @@ func TestRevListArgs(t *testing.T) {
|
||||
Order: DateRevListOrder,
|
||||
},
|
||||
ExpectedStdin: fmt.Sprintf("%s\n^%s", s1, s2),
|
||||
ExpectedArgs: []string{"rev-list", "--stdin", "--objects", "--date-order", "--do-walk", "--"},
|
||||
ExpectedArgs: []string{"rev-list", "--objects", "--date-order", "--do-walk", "--stdin", "--"},
|
||||
},
|
||||
"scan author date order": {
|
||||
Include: []string{s1}, Exclude: []string{s2}, Opt: &ScanRefsOptions{
|
||||
@ -127,7 +127,7 @@ func TestRevListArgs(t *testing.T) {
|
||||
Order: AuthorDateRevListOrder,
|
||||
},
|
||||
ExpectedStdin: fmt.Sprintf("%s\n^%s", s1, s2),
|
||||
ExpectedArgs: []string{"rev-list", "--stdin", "--objects", "--author-date-order", "--do-walk", "--"},
|
||||
ExpectedArgs: []string{"rev-list", "--objects", "--author-date-order", "--do-walk", "--stdin", "--"},
|
||||
},
|
||||
"scan topo order": {
|
||||
Include: []string{s1}, Exclude: []string{s2}, Opt: &ScanRefsOptions{
|
||||
@ -135,7 +135,7 @@ func TestRevListArgs(t *testing.T) {
|
||||
Order: TopoRevListOrder,
|
||||
},
|
||||
ExpectedStdin: fmt.Sprintf("%s\n^%s", s1, s2),
|
||||
ExpectedArgs: []string{"rev-list", "--stdin", "--objects", "--topo-order", "--do-walk", "--"},
|
||||
ExpectedArgs: []string{"rev-list", "--objects", "--topo-order", "--do-walk", "--stdin", "--"},
|
||||
},
|
||||
"scan commits only": {
|
||||
Include: []string{s1}, Exclude: []string{s2}, Opt: &ScanRefsOptions{
|
||||
@ -143,7 +143,7 @@ func TestRevListArgs(t *testing.T) {
|
||||
CommitsOnly: true,
|
||||
},
|
||||
ExpectedStdin: fmt.Sprintf("%s\n^%s", s1, s2),
|
||||
ExpectedArgs: []string{"rev-list", "--stdin", "--do-walk", "--"},
|
||||
ExpectedArgs: []string{"rev-list", "--do-walk", "--stdin", "--"},
|
||||
},
|
||||
"scan reverse": {
|
||||
Include: []string{s1}, Exclude: []string{s2}, Opt: &ScanRefsOptions{
|
||||
@ -151,7 +151,7 @@ func TestRevListArgs(t *testing.T) {
|
||||
Reverse: true,
|
||||
},
|
||||
ExpectedStdin: fmt.Sprintf("%s\n^%s", s1, s2),
|
||||
ExpectedArgs: []string{"rev-list", "--stdin", "--objects", "--reverse", "--do-walk", "--"},
|
||||
ExpectedArgs: []string{"rev-list", "--objects", "--reverse", "--do-walk", "--stdin", "--"},
|
||||
},
|
||||
} {
|
||||
t.Run(desc, c.Assert)
|
||||
|
@ -1222,3 +1222,34 @@ begin_test "pre-push does not traverse Git objects server has"
|
||||
! grep $contents_oid push.log
|
||||
)
|
||||
end_test
|
||||
|
||||
begin_test "pre-push with force-pushed ref"
|
||||
(
|
||||
set -e
|
||||
reponame="pre-push-force-pushed-ref"
|
||||
setup_remote_repo "$reponame"
|
||||
clone_repo "$reponame" "$reponame"
|
||||
|
||||
git config "lfs.$(repo_endpoint "$GITSERVER" "$reponame").locksverify" false
|
||||
git lfs track "*.dat"
|
||||
echo "hi" > a.dat
|
||||
git add .gitattributes a.dat
|
||||
git commit -m "add a.dat"
|
||||
git tag -a -m tagname tagname
|
||||
|
||||
refute_server_object "$reponame" 98ea6e4f216f2fb4b69fff9b3a44842c38686ca685f3f55dc48c5d3fb1107be4 "refs/heads/master"
|
||||
|
||||
git push origin master tagname
|
||||
|
||||
assert_server_object "$reponame" 98ea6e4f216f2fb4b69fff9b3a44842c38686ca685f3f55dc48c5d3fb1107be4 "refs/heads/master"
|
||||
|
||||
# We pick a different message so that we get different object IDs even if both
|
||||
# commands run in the same second.
|
||||
git tag -f -a -m tagname2 tagname
|
||||
# Prune the old tag object.
|
||||
git reflog expire --all --expire=now
|
||||
git gc --prune=now
|
||||
# Make sure we deal with us missing the object for the old value of the tag ref.
|
||||
git push origin +tagname
|
||||
)
|
||||
end_test
|
||||
|
Loading…
Reference in New Issue
Block a user