#!/bin/sh global test_description := ''compare & swap push force/delete safety'' source ./test-lib.sh proc setup_srcdst_basic { rm -fr src dst && git clone --no-local . src && git clone --no-local src dst && shell { cd src && git checkout HEAD^0 } } test_expect_success setup ' # create template repository test_commit A && test_commit B && test_commit C ' test_expect_success 'push to update (protected)' ' setup_srcdst_basic && ( cd dst && test_commit D && test_must_fail git push --force-with-lease=master:master origin master 2>err && grep "stale info" err ) && git ls-remote . refs/heads/master >expect && git ls-remote src refs/heads/master >actual && test_cmp expect actual ' test_expect_success 'push to update (protected, forced)' ' setup_srcdst_basic && ( cd dst && test_commit D && git push --force --force-with-lease=master:master origin master 2>err && grep "forced update" err ) && git ls-remote dst refs/heads/master >expect && git ls-remote src refs/heads/master >actual && test_cmp expect actual ' test_expect_success 'push to update (protected, tracking)' ' setup_srcdst_basic && ( cd src && git checkout master && test_commit D && git checkout HEAD^0 ) && git ls-remote src refs/heads/master >expect && ( cd dst && test_commit E && git ls-remote . refs/remotes/origin/master >expect && test_must_fail git push --force-with-lease=master origin master && git ls-remote . refs/remotes/origin/master >actual && test_cmp expect actual ) && git ls-remote src refs/heads/master >actual && test_cmp expect actual ' test_expect_success 'push to update (protected, tracking, forced)' ' setup_srcdst_basic && ( cd src && git checkout master && test_commit D && git checkout HEAD^0 ) && ( cd dst && test_commit E && git ls-remote . refs/remotes/origin/master >expect && git push --force --force-with-lease=master origin master ) && git ls-remote dst refs/heads/master >expect && git ls-remote src refs/heads/master >actual && test_cmp expect actual ' test_expect_success 'push to update (allowed)' ' setup_srcdst_basic && ( cd dst && test_commit D && git push --force-with-lease=master:master^ origin master ) && git ls-remote dst refs/heads/master >expect && git ls-remote src refs/heads/master >actual && test_cmp expect actual ' test_expect_success 'push to update (allowed, tracking)' ' setup_srcdst_basic && ( cd dst && test_commit D && git push --force-with-lease=master origin master 2>err && ! grep "forced update" err ) && git ls-remote dst refs/heads/master >expect && git ls-remote src refs/heads/master >actual && test_cmp expect actual ' test_expect_success 'push to update (allowed even though no-ff)' ' setup_srcdst_basic && ( cd dst && git reset --hard HEAD^ && test_commit D && git push --force-with-lease=master origin master 2>err && grep "forced update" err ) && git ls-remote dst refs/heads/master >expect && git ls-remote src refs/heads/master >actual && test_cmp expect actual ' test_expect_success 'push to delete (protected)' ' setup_srcdst_basic && git ls-remote src refs/heads/master >expect && ( cd dst && test_must_fail git push --force-with-lease=master:master^ origin :master ) && git ls-remote src refs/heads/master >actual && test_cmp expect actual ' test_expect_success 'push to delete (protected, forced)' ' setup_srcdst_basic && ( cd dst && git push --force --force-with-lease=master:master^ origin :master ) && >expect && git ls-remote src refs/heads/master >actual && test_cmp expect actual ' test_expect_success 'push to delete (allowed)' ' setup_srcdst_basic && ( cd dst && git push --force-with-lease=master origin :master 2>err && grep deleted err ) && >expect && git ls-remote src refs/heads/master >actual && test_cmp expect actual ' test_expect_success 'cover everything with default force-with-lease (protected)' ' setup_srcdst_basic && ( cd src && git branch naster master^ ) && git ls-remote src refs/heads/\* >expect && ( cd dst && test_must_fail git push --force-with-lease origin master master:naster ) && git ls-remote src refs/heads/\* >actual && test_cmp expect actual ' test_expect_success 'cover everything with default force-with-lease (allowed)' ' setup_srcdst_basic && ( cd src && git branch naster master^ ) && ( cd dst && git fetch && git push --force-with-lease origin master master:naster ) && git ls-remote dst refs/heads/master | sed -e "s/master/naster/" >expect && git ls-remote src refs/heads/naster >actual && test_cmp expect actual ' test_expect_success 'new branch covered by force-with-lease' ' setup_srcdst_basic && ( cd dst && git branch branch master && git push --force-with-lease=branch origin branch ) && git ls-remote dst refs/heads/branch >expect && git ls-remote src refs/heads/branch >actual && test_cmp expect actual ' test_expect_success 'new branch covered by force-with-lease (explicit)' ' setup_srcdst_basic && ( cd dst && git branch branch master && git push --force-with-lease=branch: origin branch ) && git ls-remote dst refs/heads/branch >expect && git ls-remote src refs/heads/branch >actual && test_cmp expect actual ' test_expect_success 'new branch already exists' ' setup_srcdst_basic && ( cd src && git checkout -b branch master && test_commit F ) && ( cd dst && git branch branch master && test_must_fail git push --force-with-lease=branch: origin branch ) ' test_done (CommandList children: [ (Assignment keyword: Assign_None pairs: [ (assign_pair lhs: (LhsName name:test_description) op: Equal rhs: {(SQ <"compare & swap push force/delete safety">)} spids: [4] ) ] spids: [4] ) (C {(.)} {(./test-lib.sh)}) (FuncDef name: setup_srcdst_basic body: (BraceGroup children: [ (AndOr children: [ (C {(rm)} {(-fr)} {(src)} {(dst)}) (AndOr children: [ (C {(git)} {(clone)} {(--no-local)} {(.)} {(src)}) (AndOr children: [ (C {(git)} {(clone)} {(--no-local)} {(src)} {(dst)}) (Subshell child: (AndOr children: [ (C {(cd)} {(src)}) (C {(git)} {(checkout)} {(HEAD) (Lit_Other "^") (0)}) ] op_id: Op_DAmp ) spids: [60 78] ) ] op_id: Op_DAmp ) ] op_id: Op_DAmp ) ] op_id: Op_DAmp ) ] spids: [20] ) spids: [15 19] ) (C {(test_expect_success)} {(setup)} { (SQ <"\n"> <"\t# create template repository\n"> <"\ttest_commit A &&\n"> <"\ttest_commit B &&\n"> <"\ttest_commit C\n"> ) } ) (C {(test_expect_success)} {(SQ <"push to update (protected)">)} { (SQ <"\n"> <"\tsetup_srcdst_basic &&\n"> <"\t(\n"> <"\t\tcd dst &&\n"> <"\t\ttest_commit D &&\n"> <"\t\ttest_must_fail git push --force-with-lease=master:master origin master 2>err &&\n"> <"\t\tgrep \"stale info\" err\n"> <"\t) &&\n"> <"\tgit ls-remote . refs/heads/master >expect &&\n"> <"\tgit ls-remote src refs/heads/master >actual &&\n"> <"\ttest_cmp expect actual\n"> ) } ) (C {(test_expect_success)} {(SQ <"push to update (protected, forced)">)} { (SQ <"\n"> <"\tsetup_srcdst_basic &&\n"> <"\t(\n"> <"\t\tcd dst &&\n"> <"\t\ttest_commit D &&\n"> <"\t\tgit push --force --force-with-lease=master:master origin master 2>err &&\n"> <"\t\tgrep \"forced update\" err\n"> <"\t) &&\n"> <"\tgit ls-remote dst refs/heads/master >expect &&\n"> <"\tgit ls-remote src refs/heads/master >actual &&\n"> <"\ttest_cmp expect actual\n"> ) } ) (C {(test_expect_success)} {(SQ <"push to update (protected, tracking)">)} { (SQ <"\n"> <"\tsetup_srcdst_basic &&\n"> <"\t(\n"> <"\t\tcd src &&\n"> <"\t\tgit checkout master &&\n"> <"\t\ttest_commit D &&\n"> <"\t\tgit checkout HEAD^0\n"> <"\t) &&\n"> <"\tgit ls-remote src refs/heads/master >expect &&\n"> <"\t(\n"> <"\t\tcd dst &&\n"> <"\t\ttest_commit E &&\n"> <"\t\tgit ls-remote . refs/remotes/origin/master >expect &&\n"> <"\t\ttest_must_fail git push --force-with-lease=master origin master &&\n"> <"\t\tgit ls-remote . refs/remotes/origin/master >actual &&\n"> <"\t\ttest_cmp expect actual\n"> <"\t) &&\n"> <"\tgit ls-remote src refs/heads/master >actual &&\n"> <"\ttest_cmp expect actual\n"> ) } ) (C {(test_expect_success)} {(SQ <"push to update (protected, tracking, forced)">)} { (SQ <"\n"> <"\tsetup_srcdst_basic &&\n"> <"\t(\n"> <"\t\tcd src &&\n"> <"\t\tgit checkout master &&\n"> <"\t\ttest_commit D &&\n"> <"\t\tgit checkout HEAD^0\n"> <"\t) &&\n"> <"\t(\n"> <"\t\tcd dst &&\n"> <"\t\ttest_commit E &&\n"> <"\t\tgit ls-remote . refs/remotes/origin/master >expect &&\n"> <"\t\tgit push --force --force-with-lease=master origin master\n"> <"\t) &&\n"> <"\tgit ls-remote dst refs/heads/master >expect &&\n"> <"\tgit ls-remote src refs/heads/master >actual &&\n"> <"\ttest_cmp expect actual\n"> ) } ) (C {(test_expect_success)} {(SQ <"push to update (allowed)">)} { (SQ <"\n"> <"\tsetup_srcdst_basic &&\n"> <"\t(\n"> <"\t\tcd dst &&\n"> <"\t\ttest_commit D &&\n"> <"\t\tgit push --force-with-lease=master:master^ origin master\n"> <"\t) &&\n"> <"\tgit ls-remote dst refs/heads/master >expect &&\n"> <"\tgit ls-remote src refs/heads/master >actual &&\n"> <"\ttest_cmp expect actual\n"> ) } ) (C {(test_expect_success)} {(SQ <"push to update (allowed, tracking)">)} { (SQ <"\n"> <"\tsetup_srcdst_basic &&\n"> <"\t(\n"> <"\t\tcd dst &&\n"> <"\t\ttest_commit D &&\n"> <"\t\tgit push --force-with-lease=master origin master 2>err &&\n"> <"\t\t! grep \"forced update\" err\n"> <"\t) &&\n"> <"\tgit ls-remote dst refs/heads/master >expect &&\n"> <"\tgit ls-remote src refs/heads/master >actual &&\n"> <"\ttest_cmp expect actual\n"> ) } ) (C {(test_expect_success)} {(SQ <"push to update (allowed even though no-ff)">)} { (SQ <"\n"> <"\tsetup_srcdst_basic &&\n"> <"\t(\n"> <"\t\tcd dst &&\n"> <"\t\tgit reset --hard HEAD^ &&\n"> <"\t\ttest_commit D &&\n"> <"\t\tgit push --force-with-lease=master origin master 2>err &&\n"> <"\t\tgrep \"forced update\" err\n"> <"\t) &&\n"> <"\tgit ls-remote dst refs/heads/master >expect &&\n"> <"\tgit ls-remote src refs/heads/master >actual &&\n"> <"\ttest_cmp expect actual\n"> ) } ) (C {(test_expect_success)} {(SQ <"push to delete (protected)">)} { (SQ <"\n"> <"\tsetup_srcdst_basic &&\n"> <"\tgit ls-remote src refs/heads/master >expect &&\n"> <"\t(\n"> <"\t\tcd dst &&\n"> <"\t\ttest_must_fail git push --force-with-lease=master:master^ origin :master\n"> <"\t) &&\n"> <"\tgit ls-remote src refs/heads/master >actual &&\n"> <"\ttest_cmp expect actual\n"> ) } ) (C {(test_expect_success)} {(SQ <"push to delete (protected, forced)">)} { (SQ <"\n"> <"\tsetup_srcdst_basic &&\n"> <"\t(\n"> <"\t\tcd dst &&\n"> <"\t\tgit push --force --force-with-lease=master:master^ origin :master\n"> <"\t) &&\n"> <"\t>expect &&\n"> <"\tgit ls-remote src refs/heads/master >actual &&\n"> <"\ttest_cmp expect actual\n"> ) } ) (C {(test_expect_success)} {(SQ <"push to delete (allowed)">)} { (SQ <"\n"> <"\tsetup_srcdst_basic &&\n"> <"\t(\n"> <"\t\tcd dst &&\n"> <"\t\tgit push --force-with-lease=master origin :master 2>err &&\n"> <"\t\tgrep deleted err\n"> <"\t) &&\n"> <"\t>expect &&\n"> <"\tgit ls-remote src refs/heads/master >actual &&\n"> <"\ttest_cmp expect actual\n"> ) } ) (C {(test_expect_success)} {(SQ <"cover everything with default force-with-lease (protected)">)} { (SQ <"\n"> <"\tsetup_srcdst_basic &&\n"> <"\t(\n"> <"\t\tcd src &&\n"> <"\t\tgit branch naster master^\n"> <"\t) &&\n"> <"\tgit ls-remote src refs/heads/\\* >expect &&\n"> <"\t(\n"> <"\t\tcd dst &&\n"> <"\t\ttest_must_fail git push --force-with-lease origin master master:naster\n"> <"\t) &&\n"> <"\tgit ls-remote src refs/heads/\\* >actual &&\n"> <"\ttest_cmp expect actual\n"> ) } ) (C {(test_expect_success)} {(SQ <"cover everything with default force-with-lease (allowed)">)} { (SQ <"\n"> <"\tsetup_srcdst_basic &&\n"> <"\t(\n"> <"\t\tcd src &&\n"> <"\t\tgit branch naster master^\n"> <"\t) &&\n"> <"\t(\n"> <"\t\tcd dst &&\n"> <"\t\tgit fetch &&\n"> <"\t\tgit push --force-with-lease origin master master:naster\n"> <"\t) &&\n"> <"\tgit ls-remote dst refs/heads/master |\n"> <"\tsed -e \"s/master/naster/\" >expect &&\n"> <"\tgit ls-remote src refs/heads/naster >actual &&\n"> <"\ttest_cmp expect actual\n"> ) } ) (C {(test_expect_success)} {(SQ <"new branch covered by force-with-lease">)} { (SQ <"\n"> <"\tsetup_srcdst_basic &&\n"> <"\t(\n"> <"\t\tcd dst &&\n"> <"\t\tgit branch branch master &&\n"> <"\t\tgit push --force-with-lease=branch origin branch\n"> <"\t) &&\n"> <"\tgit ls-remote dst refs/heads/branch >expect &&\n"> <"\tgit ls-remote src refs/heads/branch >actual &&\n"> <"\ttest_cmp expect actual\n"> ) } ) (C {(test_expect_success)} {(SQ <"new branch covered by force-with-lease (explicit)">)} { (SQ <"\n"> <"\tsetup_srcdst_basic &&\n"> <"\t(\n"> <"\t\tcd dst &&\n"> <"\t\tgit branch branch master &&\n"> <"\t\tgit push --force-with-lease=branch: origin branch\n"> <"\t) &&\n"> <"\tgit ls-remote dst refs/heads/branch >expect &&\n"> <"\tgit ls-remote src refs/heads/branch >actual &&\n"> <"\ttest_cmp expect actual\n"> ) } ) (C {(test_expect_success)} {(SQ <"new branch already exists">)} { (SQ <"\n"> <"\tsetup_srcdst_basic &&\n"> <"\t(\n"> <"\t\tcd src &&\n"> <"\t\tgit checkout -b branch master &&\n"> <"\t\ttest_commit F\n"> <"\t) &&\n"> <"\t(\n"> <"\t\tcd dst &&\n"> <"\t\tgit branch branch master &&\n"> <"\t\ttest_must_fail git push --force-with-lease=branch: origin branch\n"> <"\t)\n"> ) } ) (C {(test_done)}) ] )