Re: [PATCH] push: point to 'git pull' and 'git push --force' in case of non-fast forward

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Matthieu Moy <Matthieu.Moy@xxxxxxx> writes:

> 'git push' failing because of non-fast forward is a very common situation,
> and a beginner does not necessarily understand "fast forward" immediately.
>
> Signed-off-by: Matthieu Moy <Matthieu.Moy@xxxxxxx>
> ---
> That may be a bit verbose, but I think it's worth it.
> ...
> +		if (nonfastforward) {
> +			printf("Some branch push were rejected due to non-fast forward:\n");
> +			printf("Merge the remote changes (git pull) before pushing your's\n");
> +			printf("or use git push --force to discard the remote changes.\n");
> +		}

Although I think the patch identified the right place to make changes, I
am not sure about what the help message should say.

If the user lacks understanding of what a fast-forward is, I do not think
giving two choices that would produce vastly different results (because
they are applicable in vastly different situations) would help such a user
very much, as the understanding of the concept of fast-forward is a must
to correctly decide which one to use.

Unfortunately, I do not think we have a good description of fast-forward
in our documentation set.  The glossary defines what it is, git-push
manual page says by default only fast-forwards are accepted, and
user-manual says that we do not create a merge commit in a fast-forward
situation.  But nobody talks about _why_ a non-fast-forward update (either
push or fetch) is a bad idea clearly.

I wrote that in my upcoming book so we could refer to it in this error
message, but I suspect it may not help most people since it is in Japanese
;-)

Jokes aside, perhaps we could add "see git-push documentation for details"
to the above message of yours, and add something like this to the
documentation.

 Documentation/git-push.txt |   75 ++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 75 insertions(+), 0 deletions(-)

diff --git a/Documentation/git-push.txt b/Documentation/git-push.txt
index 2653388..c1ae82d 100644
--- a/Documentation/git-push.txt
+++ b/Documentation/git-push.txt
@@ -195,6 +195,81 @@ reason::
 	refs, no explanation is needed. For a failed ref, the reason for
 	failure is described.
 
+Note about fast-forwards
+------------------------
+
+When an update changes a branch (or more in general, a ref) that used to
+point at commit A to point at another commit B, it is called a
+fast-forward update if and only if B is a descendant of A.
+
+In a fast-forward update from A to B, the set of commits that the original
+commit A built on top of is a subset of the commits the new commit B
+builds on top of.  Hence, it does not lose any history.
+
+In contrast, a non-fast-forward update will lose history.  For example,
+suppose you and somebody else started at the same commit X, and you built
+a history leading to commit B while the other person built a history
+leading to commit A.  The history looks like this:
+
+----------------
+
+      B
+     /
+ ---X---A
+
+----------------
+
+Further suppose that the other person already pushed changes leading to A
+back to the original repository you two obtained the original commit X.
+
+The push done by the other person updated the branch that used to point at
+commit X to point at commit A.  It is a fast-forward.
+
+But if you try to push, you will attempt to update the branch (that
+now points at A) with commit B.  This does _not_ fast-forward.  If you did
+so, the changes introduced by commit A will be lost, because everybody
+will now start building on top of B.
+
+The command by default does not allow an update that is not a fast-forward
+to prevent such loss of history.
+
+If you do not want to lose your work (history from X to B) nor the work by
+the other person (history from X to A), you would need to first fetch the
+history from the repository, create a history that contains changes done
+by both parties, and push the result back.
+
+You can perform "git pull", resolve potential conflicts, and "git push"
+the result.  A "git pull" will create a merge commit C between commits A
+and B.
+
+----------------
+
+      B---C
+     /   /
+ ---X---A
+
+----------------
+
+Updating A with the resulting merge commit will fast-forward and your
+push will be accepted.
+
+Alternatively, you can rebase your change between X and B on top of A,
+with "git pull --rebase", and push the result back.  The rebase will
+create a new commit D that builds the change between X and B on top of
+A.
+
+----------------
+
+      B   D
+     /   /
+ ---X---A
+
+----------------
+
+Again, updating A with this commit will fast-forward and your push will be
+accepted.
+
+
 Examples
 --------
 
--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [Linux Kernel Development]     [Gcc Help]     [IETF Annouce]     [DCCP]     [Netdev]     [Networking]     [Security]     [V4L]     [Bugtraq]     [Yosemite]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux SCSI]     [Fedora Users]