Skip to content

Commit 18e23f6

Browse files
clickyotomygitster
authored andcommitted
t, doc: update tests, reference for "--force-if-includes"
Update test cases for the new option, and document its usage and update related references. Update test cases for the new option, and document its usage and update related references. - t/t5533-push-cas.sh: Update test cases for "compare-and-swap" when used along with "--force-if-includes" helps mitigate overwrites when remote refs are updated in the background; allows forced updates when changes from remote are integrated locally. - Documentation: Add reference for the new option, configuration setting ("push.useForceIfIncludes") and advise messages. Signed-off-by: Srinidhi Kaushik <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 4a928e6 commit 18e23f6

File tree

4 files changed

+174
-4
lines changed

4 files changed

+174
-4
lines changed

Documentation/config/advice.txt

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,8 @@ advice.*::
1010
that the check is disabled.
1111
pushUpdateRejected::
1212
Set this variable to 'false' if you want to disable
13-
'pushNonFFCurrent',
14-
'pushNonFFMatching', 'pushAlreadyExists',
15-
'pushFetchFirst', and 'pushNeedsForce'
13+
'pushNonFFCurrent', 'pushNonFFMatching', 'pushAlreadyExists',
14+
'pushFetchFirst', 'pushNeedsForce', and 'pushRefNeedsUpdate'
1615
simultaneously.
1716
pushNonFFCurrent::
1817
Advice shown when linkgit:git-push[1] fails due to a
@@ -41,6 +40,10 @@ advice.*::
4140
we can still suggest that the user push to either
4241
refs/heads/* or refs/tags/* based on the type of the
4342
source object.
43+
pushRefNeedsUpdate::
44+
Shown when linkgit:git-push[1] rejects a forced update of
45+
a branch when its remote-tracking ref has updates that we
46+
do not have locally.
4447
statusAheadBehind::
4548
Shown when linkgit:git-status[1] computes the ahead/behind
4649
counts for a local ref compared to its remote tracking ref,

Documentation/config/push.txt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,3 +114,9 @@ push.recurseSubmodules::
114114
specifying '--recurse-submodules=check|on-demand|no'.
115115
If not set, 'no' is used by default, unless 'submodule.recurse' is
116116
set (in which case a 'true' value means 'on-demand').
117+
118+
push.useForceIfIncludes::
119+
If set to "true", it is equivalent to specifying
120+
`--force-if-includes` as an option to linkgit:git-push[1]
121+
in the command line. Adding `--no-force-if-includes` at the
122+
time of push overrides this configuration setting.

Documentation/git-push.txt

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ SYNOPSIS
1313
[--repo=<repository>] [-f | --force] [-d | --delete] [--prune] [-v | --verbose]
1414
[-u | --set-upstream] [-o <string> | --push-option=<string>]
1515
[--[no-]signed|--signed=(true|false|if-asked)]
16-
[--force-with-lease[=<refname>[:<expect>]]]
16+
[--force-with-lease[=<refname>[:<expect>]] [--force-if-includes]]
1717
[--no-verify] [<repository> [<refspec>...]]
1818

1919
DESCRIPTION
@@ -320,6 +320,14 @@ seen and are willing to overwrite, then rewrite history, and finally
320320
force push changes to `master` if the remote version is still at
321321
`base`, regardless of what your local `remotes/origin/master` has been
322322
updated to in the background.
323+
+
324+
Alternatively, specifying `--force-if-includes` as an ancillary option
325+
along with `--force-with-lease[=<refname>]` (i.e., without saying what
326+
exact commit the ref on the remote side must be pointing at, or which
327+
refs on the remote side are being protected) at the time of "push" will
328+
verify if updates from the remote-tracking refs that may have been
329+
implicitly updated in the background are integrated locally before
330+
allowing a forced update.
323331

324332
-f::
325333
--force::
@@ -341,6 +349,22 @@ one branch, use a `+` in front of the refspec to push (e.g `git push
341349
origin +master` to force a push to the `master` branch). See the
342350
`<refspec>...` section above for details.
343351

352+
--[no-]force-if-includes::
353+
Force an update only if the tip of the remote-tracking ref
354+
has been integrated locally.
355+
+
356+
This option enables a check that verifies if the tip of the
357+
remote-tracking ref is reachable from one of the "reflog" entries of
358+
the local branch based in it for a rewrite. The check ensures that any
359+
updates from the remote have been incorporated locally by rejecting the
360+
forced update if that is not the case.
361+
+
362+
If the option is passed without specifying `--force-with-lease`, or
363+
specified along with `--force-with-lease=<refname>:<expect>`, it is
364+
a "no-op".
365+
+
366+
Specifying `--no-force-if-includes` disables this behavior.
367+
344368
--repo=<repository>::
345369
This option is equivalent to the <repository> argument. If both
346370
are specified, the command-line argument takes precedence.

t/t5533-push-cas.sh

Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,46 @@ setup_srcdst_basic () {
1313
)
1414
}
1515

16+
# For tests with "--force-if-includes".
17+
setup_src_dup_dst () {
18+
rm -fr src dup dst &&
19+
git init --bare dst &&
20+
git clone --no-local dst src &&
21+
git clone --no-local dst dup
22+
(
23+
cd src &&
24+
test_commit A &&
25+
test_commit B &&
26+
test_commit C &&
27+
git push origin
28+
) &&
29+
(
30+
cd dup &&
31+
git fetch &&
32+
git merge origin/master &&
33+
git switch -c branch master~2 &&
34+
test_commit D &&
35+
test_commit E &&
36+
git push origin --all
37+
) &&
38+
(
39+
cd src &&
40+
git switch master &&
41+
git fetch --all &&
42+
git branch branch --track origin/branch &&
43+
git rebase origin/master
44+
) &&
45+
(
46+
cd dup &&
47+
git switch master &&
48+
test_commit F &&
49+
test_commit G &&
50+
git switch branch &&
51+
test_commit H &&
52+
git push origin --all
53+
)
54+
}
55+
1656
test_expect_success setup '
1757
# create template repository
1858
test_commit A &&
@@ -256,4 +296,101 @@ test_expect_success 'background updates of REMOTE can be mitigated with a non-up
256296
)
257297
'
258298

299+
test_expect_success 'background updates to remote can be mitigated with "--force-if-includes"' '
300+
setup_src_dup_dst &&
301+
test_when_finished "rm -fr dst src dup" &&
302+
git ls-remote dst refs/heads/master >expect.master &&
303+
git ls-remote dst refs/heads/branch >expect.branch &&
304+
(
305+
cd src &&
306+
git switch branch &&
307+
test_commit I &&
308+
git switch master &&
309+
test_commit J &&
310+
git fetch --all &&
311+
test_must_fail git push --force-with-lease --force-if-includes --all
312+
) &&
313+
git ls-remote dst refs/heads/master >actual.master &&
314+
git ls-remote dst refs/heads/branch >actual.branch &&
315+
test_cmp expect.master actual.master &&
316+
test_cmp expect.branch actual.branch
317+
'
318+
319+
test_expect_success 'background updates to remote can be mitigated with "push.useForceIfIncludes"' '
320+
setup_src_dup_dst &&
321+
test_when_finished "rm -fr dst src dup" &&
322+
git ls-remote dst refs/heads/master >expect.master &&
323+
(
324+
cd src &&
325+
git switch branch &&
326+
test_commit I &&
327+
git switch master &&
328+
test_commit J &&
329+
git fetch --all &&
330+
git config --local push.useForceIfIncludes true &&
331+
test_must_fail git push --force-with-lease=master origin master
332+
) &&
333+
git ls-remote dst refs/heads/master >actual.master &&
334+
test_cmp expect.master actual.master
335+
'
336+
337+
test_expect_success '"--force-if-includes" should be disabled for --force-with-lease="<refname>:<expect>"' '
338+
setup_src_dup_dst &&
339+
test_when_finished "rm -fr dst src dup" &&
340+
git ls-remote dst refs/heads/master >expect.master &&
341+
(
342+
cd src &&
343+
git switch branch &&
344+
test_commit I &&
345+
git switch master &&
346+
test_commit J &&
347+
remote_head="$(git rev-parse refs/remotes/origin/master)" &&
348+
git fetch --all &&
349+
test_must_fail git push --force-if-includes --force-with-lease="master:$remote_head" 2>err &&
350+
grep "stale info" err
351+
) &&
352+
git ls-remote dst refs/heads/master >actual.master &&
353+
test_cmp expect.master actual.master
354+
'
355+
356+
test_expect_success '"--force-if-includes" should allow forced update after a rebase ("pull --rebase")' '
357+
setup_src_dup_dst &&
358+
test_when_finished "rm -fr dst src dup" &&
359+
(
360+
cd src &&
361+
git switch branch &&
362+
test_commit I &&
363+
git switch master &&
364+
test_commit J &&
365+
git pull --rebase origin master &&
366+
git push --force-if-includes --force-with-lease="master"
367+
)
368+
'
369+
370+
test_expect_success '"--force-if-includes" should allow forced update after a rebase ("pull --rebase", local rebase)' '
371+
setup_src_dup_dst &&
372+
test_when_finished "rm -fr dst src dup" &&
373+
(
374+
cd src &&
375+
git switch branch &&
376+
test_commit I &&
377+
git switch master &&
378+
test_commit J &&
379+
git pull --rebase origin master &&
380+
git rebase --onto HEAD~4 HEAD~1 &&
381+
git push --force-if-includes --force-with-lease="master"
382+
)
383+
'
384+
385+
test_expect_success '"--force-if-includes" should allow deletes' '
386+
setup_src_dup_dst &&
387+
test_when_finished "rm -fr dst src dup" &&
388+
(
389+
cd src &&
390+
git switch branch &&
391+
git pull --rebase origin branch &&
392+
git push --force-if-includes --force-with-lease="branch" origin :branch
393+
)
394+
'
395+
259396
test_done

0 commit comments

Comments
 (0)