git@vger.kernel.org mailing list mirror (one of many)
 help / color / mirror / code / Atom feed
From: "Ævar Arnfjörð Bjarmason" <avarab@gmail.com>
To: git@vger.kernel.org
Cc: "Junio C Hamano" <gitster@pobox.com>, "Jeff King" <peff@peff.net>,
	"Jakub Narębski" <jnareb@gmail.com>,
	"Jacob Keller" <jacob.keller@gmail.com>,
	"Matt McCutchen" <matt@mattmccutchen.net>,
	"Simon Ruderich" <simon@ruderich.org>,
	"Ævar Arnfjörð Bjarmason" <avarab@gmail.com>
Subject: [PATCH v2] push: document & test --force-with-lease with multiple remotes
Date: Wed, 19 Apr 2017 09:22:03 +0000	[thread overview]
Message-ID: <20170419092203.5269-1-avarab@gmail.com> (raw)
In-Reply-To: <xmqqinm3k7qa.fsf@gitster.mtv.corp.google.com>

Document & test for cases where there are two remotes pointing to the
same URL, and a background fetch & subsequent `git push
--force-with-lease` shouldn't clobber un-updated references we haven't
fetched.

Some editors like Microsoft's VSC have a feature to auto-fetch in the
background, this bypasses the protections offered by
--force-with-lease & --force-with-lease=<refname>, as noted in the
documentation being added here.

See the 'Tools that do an automatic fetch defeat "git push
--force-with-lease"' (<1491617750.2149.10.camel@mattmccutchen.net>)
git mailing list thread for more details. Jakub Narębski suggested
this method of adding another remote to bypass this edge case,
document that & add a test for it.

Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---

On Mon, Apr 17, 2017 at 5:56 AM, Junio C Hamano <gitster@pobox.com> wrote:
> Ævar Arnfjörð Bjarmason  <avarab@gmail.com> writes:
>
>> Document & test for cases where there are two remotes pointing to the
>> same URL, and a background fetch & subsequent `git push
>> --force-with-lease` shouldn't clobber un-updated references we haven't
>> fetched.
>>
>> Some editors like Microsoft's VSC have a feature to auto-fetch in the
>> background, this bypasses the protections offered by
>> --force-with-lease as noted in the documentation being added here.
>
> That sounds like an unfortunate mix of two "feature"s that are
> mutually incompatible.  Perhaps those who thought auto-fetch was a
> good idea didn't think through the implications, 

Well, to be fair to those people there's been no negative interaction
with the everyday commands people use by aggressively fetching in the
background until this feature came along, at least not that I can
think of.

There's a lot of advice online and in our own docs to the effect of
"pull is fetch + merge|rebase, if you just want to inspect the remote
just safely fetch".

Now advice to that effect needs needs to be amended to say "...unless
you were thinking of using the shorthand of --force-with-lease, then
it'll subtly do the wrong thing".

To argue against the point I was making in
<CACBZZX48RanjHsv1UsnxkbxRtqKRGgMcgmtVqQmR84H5j8awqQ@mail.gmail.com>
saying basically "at least it sucks less than --force", I'm not so
sure anymore. I think that this feature's bit too obscure to break the
general "fetch is safe" advice in such a way, and we should probably
change how it works by default to make that true again.

> and also it is understandable that those who never thought
> auto-fetch was a good idea would want --force-with-lease to default
> to the remote-tracking branch.
>
>> diff --git a/Documentation/git-push.txt b/Documentation/git-push.txt
>> index 1624a35888..2f2e9c078b 100644
>> --- a/Documentation/git-push.txt
>> +++ b/Documentation/git-push.txt
>> @@ -210,6 +210,43 @@ or we do not even have to have such a remote-tracking branch when
>>  this form is used).  If `<expect>` is the empty string, then the named ref
>>  must not already exist.
>>  +
>> +This option interacts very badly with anything that implicitly runs
>> +`git fetch` on the remote to be pushed to in the background. The
>
> This description is not accurate.  Only those who do not to specify
> what is expected and instead use the remote-tracking branch are
> affected (but these random "git fetch" clobbering the
> remote-tracking branch is sort of known and expected).
>
> I do not think I would mind if these two new lines were added one
> paragraph above, i.e. where "--force-with-lease=<refname>" form is
> described.  It clearly says "... as the remote-tracking branch we
> have for them." and that is the best place to say "This option
> interacts badly".

I think this addresses your concerns in a better way. I didn't want to
add this huge multi-paragraph digression in the middle of where we're
briefly explaining the various forms of --force-with-lease above, but
I've reworded this so that it's clear that we're only talking about
the shorthard forms now, not --force-with-lease=<ref>:<expect>.

A word-diff with version 1:
    
    diff --git a/Documentation/git-push.txt b/Documentation/git-push.txt
    index 2f2e9c078b..0a639664fd 100644
    --- a/Documentation/git-push.txt
    +++ b/Documentation/git-push.txt
    @@ -212,5 +212,17 @@ must not already exist.
    +
    [-This-]{+Note that all forms other than `--force-with-lease=<refname>:<expect>`+}
    {+that specifies the expected current value of the ref explicitly are+}
    {+still experimental and their semantics may change as we gain experience+}
    {+with this feature.+}
    {+++}
    {+"--no-force-with-lease" will cancel all the previous --force-with-lease on the+}
    {+command line.+}
    {+++}
    {+A general note on safety: supplying this+} option {+without an expected+}
    {+value, i.e. as `--force-with-lease` or `--force-with-lease=<refname>`+}
    interacts very badly with anything that implicitly runs `git fetch` on
    the remote to be pushed to in the [-background.-]{+background, e.g. `git fetch origin`+}
    {+on your repository in a cronjob.+}
    {+++}
    The protection it offers over `--force` is ensuring that subsequent
    changes your work wasn't based on aren't clobbered, but this is
    @@ -231,3 +243,3 @@ on `origin-push` won't be updated, and thus commands like:
    +
    	git push --force-with-lease [-origin-]{+origin-push+}
    +
    @@ -238,5 +250,5 @@ more tedious like:
    +
    	git fetch              [-;#-]{+#+} update 'master' from remote
    	git tag base master    [-;#-]{+#+} mark our base point
    	git rebase -i master   [-;#-]{+#+} rewrite some commits
    	git push --force-with-lease=master:base master:master
    @@ -248,10 +260,2 @@ force push changes to `master` if the remote version is still at
    updated to in the background.
    [-+-]
    [-Note that all forms other than `--force-with-lease=<refname>:<expect>`-]
    [-that specifies the expected current value of the ref explicitly are-]
    [-still experimental and their semantics may change as we gain experience-]
    [-with this feature.-]
    [-+-]
    [-"--no-force-with-lease" will cancel all the previous --force-with-lease on the-]
    [-command line.-]

 Documentation/git-push.txt | 41 +++++++++++++++++++++++++++++++++++++++++
 t/t5533-push-cas.sh        | 29 +++++++++++++++++++++++++++++
 2 files changed, 70 insertions(+)

diff --git a/Documentation/git-push.txt b/Documentation/git-push.txt
index 1624a35888..0a639664fd 100644
--- a/Documentation/git-push.txt
+++ b/Documentation/git-push.txt
@@ -217,6 +217,47 @@ with this feature.
 +
 "--no-force-with-lease" will cancel all the previous --force-with-lease on the
 command line.
++
+A general note on safety: supplying this option without an expected
+value, i.e. as `--force-with-lease` or `--force-with-lease=<refname>`
+interacts very badly with anything that implicitly runs `git fetch` on
+the remote to be pushed to in the background, e.g. `git fetch origin`
+on your repository in a cronjob.
++
+The protection it offers over `--force` is ensuring that subsequent
+changes your work wasn't based on aren't clobbered, but this is
+trivially defeated if some background process is updating refs in the
+background. We don't have anything except the remote tracking info to
+go by as a heuristic for refs you're expected to have seen & are
+willing to clobber.
++
+If your editor or some other system is running `git fetch` in the
+background for you a way to mitigate this is to simply set up another
+remote:
++
+	git remote add origin-push $(git config remote.origin.url)
+	git fetch origin-push
++
+Now when the background process runs `git fetch origin` the references
+on `origin-push` won't be updated, and thus commands like:
++
+	git push --force-with-lease origin-push
++
+Will fail unless you manually run `git fetch origin-push`. This method
+is of course entirely defeated by something that runs `git fetch
+--all`, in that case you'd need to either disable it or do something
+more tedious like:
++
+	git fetch              # update 'master' from remote
+	git tag base master    # mark our base point
+	git rebase -i master   # rewrite some commits
+	git push --force-with-lease=master:base master:master
++
+I.e. create a `base` tag for versions of the upstream code that you've
+seen and are willing to overwrite, then rewrite history, and finally
+force push changes to `master` if the remote version is still at
+`base`, regardless of what your local `remotes/origin/master` has been
+updated to in the background.
 
 -f::
 --force::
diff --git a/t/t5533-push-cas.sh b/t/t5533-push-cas.sh
index a2c9e7439f..d38ecee217 100755
--- a/t/t5533-push-cas.sh
+++ b/t/t5533-push-cas.sh
@@ -229,4 +229,33 @@ test_expect_success 'new branch already exists' '
 	)
 '
 
+test_expect_success 'background updates of REMOTE can be mitigated with a non-updated REMOTE-push' '
+	rm -rf src dst &&
+	git init --bare src.bare &&
+	test_when_finished "rm -rf src.bare" &&
+	git clone --no-local src.bare dst &&
+	test_when_finished "rm -rf dst" &&
+	(
+		cd dst &&
+		test_commit G &&
+		git remote add origin-push ../src.bare &&
+		git push origin-push master:master
+	) &&
+	git clone --no-local src.bare dst2 &&
+	test_when_finished "rm -rf dst2" &&
+	(
+		cd dst2 &&
+		test_commit H &&
+		git push
+	) &&
+	(
+		cd dst &&
+		test_commit I &&
+		git fetch origin &&
+		test_must_fail git push --force-with-lease origin-push &&
+		git fetch origin-push &&
+		git push --force-with-lease origin-push
+	)
+'
+
 test_done
-- 
2.11.0


  reply	other threads:[~2017-04-19  9:22 UTC|newest]

Thread overview: 49+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2017-04-08  2:15 Tools that do an automatic fetch defeat "git push --force-with-lease" Matt McCutchen
2017-04-08  7:24 ` Stefan Haller
2017-04-08  7:35 ` Ævar Arnfjörð Bjarmason
2017-04-08  9:29   ` Jeff King
2017-04-08 10:10     ` Jakub Narębski
2017-04-08 11:41       ` [PATCH] push: document & test --force-with-lease with multiple remotes Ævar Arnfjörð Bjarmason
2017-04-09  9:55         ` Simon Ruderich
2017-04-09 11:40           ` Ævar Arnfjörð Bjarmason
2017-04-17  3:56         ` Junio C Hamano
2017-04-19  9:22           ` Ævar Arnfjörð Bjarmason [this message]
2017-04-08 21:54     ` Tools that do an automatic fetch defeat "git push --force-with-lease" Jacob Keller
2017-04-08 22:13       ` Jeff King
2017-04-08 22:21         ` Jacob Keller
2017-04-09  8:38         ` Stefan Haller
2017-04-09  8:49           ` Jacob Keller
2017-04-09 11:00             ` Stefan Haller
2017-04-10  8:08               ` Jacob Keller
2017-04-10  9:58                 ` Ævar Arnfjörð Bjarmason
2017-04-10 23:33                   ` Jacob Keller
2017-04-11  8:51                     ` Junio C Hamano
2017-04-12  9:11                       ` Stefan Haller
2017-07-06 18:56                       ` [PATCH] push: disable lazy --force-with-lease by default Junio C Hamano
2017-07-06 19:38                         ` Stefan Beller
2017-07-06 22:39                           ` Junio C Hamano
2017-07-06 22:42                             ` Stefan Beller
2017-07-10 22:32                             ` Stefan Beller
2017-07-07  9:24                         ` Stefan Haller
2017-07-07  9:42                           ` Jeff King
2017-07-07  9:54                           ` Ævar Arnfjörð Bjarmason
2017-07-07 15:15                             ` Junio C Hamano
2017-07-15 10:45                               ` Ævar Arnfjörð Bjarmason
2017-07-17 17:28                                 ` Junio C Hamano
2017-07-07  9:39                         ` Ævar Arnfjörð Bjarmason
2017-04-11 12:37                   ` Tools that do an automatic fetch defeat "git push --force-with-lease" Stefan Haller
2017-04-11 12:37                 ` Stefan Haller
2017-04-10 18:31           ` Jeff King
2017-04-11 12:37             ` Stefan Haller
2017-04-11 12:50               ` Jeff King
2017-04-12  9:11                 ` Stefan Haller
2017-04-09  8:38       ` Stefan Haller
2017-04-09  8:46         ` Jacob Keller
2017-04-08  8:25 ` Jacob Keller
2017-04-08  9:31   ` Jeff King
2017-04-08 15:03     ` Stefan Haller
2017-04-08 22:03       ` Jeff King
2017-04-08 15:03 ` Stefan Haller
2017-04-08 16:04   ` Ævar Arnfjörð Bjarmason
2017-04-08 17:28     ` Stefan Haller
2017-04-12  9:11   ` Stefan Haller

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

  List information: http://vger.kernel.org/majordomo-info.html

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20170419092203.5269-1-avarab@gmail.com \
    --to=avarab@gmail.com \
    --cc=git@vger.kernel.org \
    --cc=gitster@pobox.com \
    --cc=jacob.keller@gmail.com \
    --cc=jnareb@gmail.com \
    --cc=matt@mattmccutchen.net \
    --cc=peff@peff.net \
    --cc=simon@ruderich.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
Code repositories for project(s) associated with this public inbox

	https://80x24.org/mirrors/git.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).