Skip to content

Commit 07436e4

Browse files
moygitster
authored andcommitted
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 <[email protected]> Signed-off-by: Junio C Hamano <[email protected]> Signed-off-by: Nanako Shiraishi <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent e89df7d commit 07436e4

File tree

4 files changed

+103
-5
lines changed

4 files changed

+103
-5
lines changed

Documentation/git-push.txt

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,92 @@ reason::
195195
refs, no explanation is needed. For a failed ref, the reason for
196196
failure is described.
197197

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+
198284
Examples
199285
--------
200286

builtin-push.c

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,7 @@ static int do_push(const char *repo, int flags)
140140
struct transport *transport =
141141
transport_get(remote, url[i]);
142142
int err;
143+
int nonfastforward;
143144
if (receivepack)
144145
transport_set_option(transport,
145146
TRANS_OPT_RECEIVEPACK, receivepack);
@@ -148,13 +149,19 @@ static int do_push(const char *repo, int flags)
148149

149150
if (flags & TRANSPORT_PUSH_VERBOSE)
150151
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);
152154
err |= transport_disconnect(transport);
153155

154156
if (!err)
155157
continue;
156158

157159
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+
}
158165
errs++;
159166
}
160167
return !!errs;

transport.c

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -820,7 +820,7 @@ static int print_one_push_status(struct ref *ref, const char *dest, int count, i
820820
}
821821

822822
static void print_push_status(const char *dest, struct ref *refs,
823-
int verbose, int porcelain)
823+
int verbose, int porcelain, int * nonfastforward)
824824
{
825825
struct ref *ref;
826826
int n = 0;
@@ -835,11 +835,14 @@ static void print_push_status(const char *dest, struct ref *refs,
835835
if (ref->status == REF_STATUS_OK)
836836
n += print_one_push_status(ref, dest, n, porcelain);
837837

838+
*nonfastforward = 0;
838839
for (ref = refs; ref; ref = ref->next) {
839840
if (ref->status != REF_STATUS_NONE &&
840841
ref->status != REF_STATUS_UPTODATE &&
841842
ref->status != REF_STATUS_OK)
842843
n += print_one_push_status(ref, dest, n, porcelain);
844+
if (ref->status == REF_STATUS_REJECT_NONFASTFORWARD)
845+
*nonfastforward = 1;
843846
}
844847
}
845848

@@ -997,7 +1000,8 @@ int transport_set_option(struct transport *transport,
9971000
}
9981001

9991002
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)
10011005
{
10021006
verify_remote_names(refspec_nr, refspec);
10031007

@@ -1024,7 +1028,7 @@ int transport_push(struct transport *transport,
10241028

10251029
ret = transport->push_refs(transport, remote_refs, flags);
10261030

1027-
print_push_status(transport->url, remote_refs, verbose | porcelain, porcelain);
1031+
print_push_status(transport->url, remote_refs, verbose | porcelain, porcelain, nonfastforward);
10281032

10291033
if (!(flags & TRANSPORT_PUSH_DRY_RUN)) {
10301034
struct ref *ref;

transport.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,8 @@ int transport_set_option(struct transport *transport, const char *name,
6868
const char *value);
6969

7070
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);
7273

7374
const struct ref *transport_get_remote_refs(struct transport *transport);
7475

0 commit comments

Comments
 (0)