@matheusbsbs / matheus-bagliano / commits / 07436e43da
Fork 0

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

'git push' failing because of non-fast forward is a very common situation, and a beginner does not necessarily understand "fast forward" immediately. Add a new section to the git-push documentation and refer them to it. Signed-off-by: Matthieu Moy <Matthieu.Moy@imag.fr> Signed-off-by: Junio C Hamano <gitster@pobox.com> Signed-off-by: Nanako Shiraishi <nanako3@lavabit.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Matthieu Moy committed Aug 8, 2009 at 09:51 UTC 07436e43daf1a97d3d702090d6289f745bd5ad90
4 files changed +103 -5
Documentation/git-push.txt
+86
@@ -195,6 +195,92 @@ reason::
195 refs, no explanation is needed. For a failed ref, the reason for
196 failure is described.
197
198 +Note about fast-forwards
199 +------------------------
200 +
201 +When an update changes a branch (or more in general, a ref) that used to
202 +point at commit A to point at another commit B, it is called a
203 +fast-forward update if and only if B is a descendant of A.
204 +
205 +In a fast-forward update from A to B, the set of commits that the original
206 +commit A built on top of is a subset of the commits the new commit B
207 +builds on top of. Hence, it does not lose any history.
208 +
209 +In contrast, a non-fast-forward update will lose history. For example,
210 +suppose you and somebody else started at the same commit X, and you built
211 +a history leading to commit B while the other person built a history
212 +leading to commit A. The history looks like this:
213 +
214 +----------------
215 +
216 + B
217 + /
218 + ---X---A
219 +
220 +----------------
221 +
222 +Further suppose that the other person already pushed changes leading to A
223 +back to the original repository you two obtained the original commit X.
224 +
225 +The push done by the other person updated the branch that used to point at
226 +commit X to point at commit A. It is a fast-forward.
227 +
228 +But if you try to push, you will attempt to update the branch (that
229 +now points at A) with commit B. This does _not_ fast-forward. If you did
230 +so, the changes introduced by commit A will be lost, because everybody
231 +will now start building on top of B.
232 +
233 +The command by default does not allow an update that is not a fast-forward
234 +to prevent such loss of history.
235 +
236 +If you do not want to lose your work (history from X to B) nor the work by
237 +the other person (history from X to A), you would need to first fetch the
238 +history from the repository, create a history that contains changes done
239 +by both parties, and push the result back.
240 +
241 +You can perform "git pull", resolve potential conflicts, and "git push"
242 +the result. A "git pull" will create a merge commit C between commits A
243 +and B.
244 +
245 +----------------
246 +
247 + B---C
248 + / /
249 + ---X---A
250 +
251 +----------------
252 +
253 +Updating A with the resulting merge commit will fast-forward and your
254 +push will be accepted.
255 +
256 +Alternatively, you can rebase your change between X and B on top of A,
257 +with "git pull --rebase", and push the result back. The rebase will
258 +create a new commit D that builds the change between X and B on top of
259 +A.
260 +
261 +----------------
262 +
263 + B D
264 + / /
265 + ---X---A
266 +
267 +----------------
268 +
269 +Again, updating A with this commit will fast-forward and your push will be
270 +accepted.
271 +
272 +There is another common situation where you may encounter non-fast-forward
273 +rejection when you try to push, and it is possible even when you are
274 +pushing into a repository nobody else pushes into. After you push commit
275 +A yourself (in the first picture in this section), replace it with "git
276 +commit --amend" to produce commit B, and you try to push it out, because
277 +forgot that you have pushed A out already. In such a case, and only if
278 +you are certain that nobody in the meantime fetched your earlier commit A
279 +(and started building on top of it), you can run "git push --force" to
280 +overwrite it. In other words, "git push --force" is a method reserved for
281 +a case where you do mean to lose history.
282 +
283 +
284 Examples
285 --------
286
builtin-push.c
+8 -1
@@ -140,6 +140,7 @@ static int do_push(const char *repo, int flags)
140 struct transport *transport =
141 transport_get(remote, url[i]);
142 int err;
143 + int nonfastforward;
144 if (receivepack)
145 transport_set_option(transport,
146 TRANS_OPT_RECEIVEPACK, receivepack);
@@ -148,13 +149,19 @@ static int do_push(const char *repo, int flags)
149
150 if (flags & TRANSPORT_PUSH_VERBOSE)
151 fprintf(stderr, "Pushing to %s\n", url[i]);
151 - err = transport_push(transport, refspec_nr, refspec, flags);
152 + err = transport_push(transport, refspec_nr, refspec, flags,
153 + &nonfastforward);
154 err |= transport_disconnect(transport);
155
156 if (!err)
157 continue;
158
159 error("failed to push some refs to '%s'", url[i]);
160 + if (nonfastforward) {
161 + printf("To prevent you from losing history, non-fast-forward updates were rejected.\n"
162 + "Merge the remote changes before pushing again.\n"
163 + "See 'non-fast forward' section of 'git push --help' for details.\n");
164 + }
165 errs++;
166 }
167 return !!errs;
transport.c
+7 -3
@@ -820,7 +820,7 @@ static int print_one_push_status(struct ref *ref, const char *dest, int count, i
820 }
821
822 static void print_push_status(const char *dest, struct ref *refs,
823 - int verbose, int porcelain)
823 + int verbose, int porcelain, int * nonfastforward)
824 {
825 struct ref *ref;
826 int n = 0;
@@ -835,11 +835,14 @@ static void print_push_status(const char *dest, struct ref *refs,
835 if (ref->status == REF_STATUS_OK)
836 n += print_one_push_status(ref, dest, n, porcelain);
837
838 + *nonfastforward = 0;
839 for (ref = refs; ref; ref = ref->next) {
840 if (ref->status != REF_STATUS_NONE &&
841 ref->status != REF_STATUS_UPTODATE &&
842 ref->status != REF_STATUS_OK)
843 n += print_one_push_status(ref, dest, n, porcelain);
844 + if (ref->status == REF_STATUS_REJECT_NONFASTFORWARD)
845 + *nonfastforward = 1;
846 }
847 }
848
@@ -997,7 +1000,8 @@ int transport_set_option(struct transport *transport,
1000 }
1001
1002 int transport_push(struct transport *transport,
1000 - int refspec_nr, const char **refspec, int flags)
1003 + int refspec_nr, const char **refspec, int flags,
1004 + int * nonfastforward)
1005 {
1006 verify_remote_names(refspec_nr, refspec);
1007
@@ -1024,7 +1028,7 @@ int transport_push(struct transport *transport,
1028
1029 ret = transport->push_refs(transport, remote_refs, flags);
1030
1027 - print_push_status(transport->url, remote_refs, verbose | porcelain, porcelain);
1031 + print_push_status(transport->url, remote_refs, verbose | porcelain, porcelain, nonfastforward);
1032
1033 if (!(flags & TRANSPORT_PUSH_DRY_RUN)) {
1034 struct ref *ref;
transport.h
+2 -1
@@ -68,7 +68,8 @@ int transport_set_option(struct transport *transport, const char *name,
68 const char *value);
69
70 int transport_push(struct transport *connection,
71 - int refspec_nr, const char **refspec, int flags);
71 + int refspec_nr, const char **refspec, int flags,
72 + int * nonfastforward);
73
74 const struct ref *transport_get_remote_refs(struct transport *transport);
75