summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Documentation/config.txt4
-rw-r--r--Documentation/fetch-options.txt2
-rw-r--r--Documentation/git-add.txt2
-rw-r--r--Documentation/git-merge.txt2
-rw-r--r--Documentation/git-push.txt86
-rw-r--r--Documentation/git-rev-list.txt2
-rw-r--r--Documentation/git.txt2
-rw-r--r--Documentation/gitattributes.txt2
-rw-r--r--Documentation/gitcore-tutorial.txt4
-rw-r--r--Documentation/user-manual.txt2
-rw-r--r--builtin-push.c9
-rw-r--r--help.c4
-rw-r--r--transport.c11
-rw-r--r--transport.h3
14 files changed, 117 insertions, 18 deletions
diff --git a/Documentation/config.txt b/Documentation/config.txt
index 7791c32bc3..2632c5149e 100644
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
@@ -605,7 +605,7 @@ color.interactive.<slot>::
Use customized color for 'git-add --interactive'
output. `<slot>` may be `prompt`, `header`, `help` or `error`, for
four distinct types of normal output from interactive
- programs. The values of these variables may be specified as
+ commands. The values of these variables may be specified as
in color.branch.<slot>.
color.pager::
@@ -1113,7 +1113,7 @@ instaweb.port::
linkgit:git-instaweb[1].
interactive.singlekey::
- In interactive programs, allow the user to provide one-letter
+ In interactive commands, allow the user to provide one-letter
input with a single key (i.e., without hitting enter).
Currently this is used only by the `\--patch` mode of
linkgit:git-add[1]. Note that this setting is silently
diff --git a/Documentation/fetch-options.txt b/Documentation/fetch-options.txt
index d313795fdb..ea3b1bc19f 100644
--- a/Documentation/fetch-options.txt
+++ b/Documentation/fetch-options.txt
@@ -1,7 +1,7 @@
-q::
--quiet::
Pass --quiet to git-fetch-pack and silence any other internally
- used programs.
+ used git commands.
-v::
--verbose::
diff --git a/Documentation/git-add.txt b/Documentation/git-add.txt
index ab1943c712..e67b7e875e 100644
--- a/Documentation/git-add.txt
+++ b/Documentation/git-add.txt
@@ -10,7 +10,7 @@ SYNOPSIS
[verse]
'git add' [-n] [-v] [--force | -f] [--interactive | -i] [--patch | -p]
[--edit | -e] [--all | [--update | -u]] [--intent-to-add | -N]
- [--refresh] [--ignore-errors] [--] <filepattern>...
+ [--refresh] [--ignore-errors] [--] [<filepattern>...]
DESCRIPTION
-----------
diff --git a/Documentation/git-merge.txt b/Documentation/git-merge.txt
index c04ae739ed..af68d694a0 100644
--- a/Documentation/git-merge.txt
+++ b/Documentation/git-merge.txt
@@ -10,7 +10,7 @@ SYNOPSIS
--------
[verse]
'git merge' [-n] [--stat] [--no-commit] [--squash] [-s <strategy>]...
- [-m <msg>] <remote> <remote>...
+ [-m <msg>] <remote>...
'git merge' <msg> HEAD <remote>...
DESCRIPTION
diff --git a/Documentation/git-push.txt b/Documentation/git-push.txt
index 2653388fd8..58d2bd5d4a 100644
--- a/Documentation/git-push.txt
+++ b/Documentation/git-push.txt
@@ -195,6 +195,92 @@ 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.
+
+There is another common situation where you may encounter non-fast-forward
+rejection when you try to push, and it is possible even when you are
+pushing into a repository nobody else pushes into. After you push commit
+A yourself (in the first picture in this section), replace it with "git
+commit --amend" to produce commit B, and you try to push it out, because
+forgot that you have pushed A out already. In such a case, and only if
+you are certain that nobody in the meantime fetched your earlier commit A
+(and started building on top of it), you can run "git push --force" to
+overwrite it. In other words, "git push --force" is a method reserved for
+a case where you do mean to lose history.
+
+
Examples
--------
diff --git a/Documentation/git-rev-list.txt b/Documentation/git-rev-list.txt
index bf98c8449c..3341d1b62f 100644
--- a/Documentation/git-rev-list.txt
+++ b/Documentation/git-rev-list.txt
@@ -90,7 +90,7 @@ between the two operands. The following two commands are equivalent:
$ git rev-list A...B
-----------------------------------------------------------------------
-'git-rev-list' is a very essential git program, since it
+'rev-list' is a very essential git command, since it
provides the ability to build and traverse commit ancestry graphs. For
this reason, it has a lot of different options that enables it to be
used by commands as different as 'git-bisect' and
diff --git a/Documentation/git.txt b/Documentation/git.txt
index 5fd5953e29..5832c752e1 100644
--- a/Documentation/git.txt
+++ b/Documentation/git.txt
@@ -327,7 +327,7 @@ Synching repositories
include::cmds-synchingrepositories.txt[]
-The following are helper programs used by the above; end users
+The following are helper commands used by the above; end users
typically do not use them directly.
include::cmds-synchelpers.txt[]
diff --git a/Documentation/gitattributes.txt b/Documentation/gitattributes.txt
index aaa073efc8..1195e83b6e 100644
--- a/Documentation/gitattributes.txt
+++ b/Documentation/gitattributes.txt
@@ -404,7 +404,7 @@ Performing a three-way merge
The attribute `merge` affects how three versions of a file is
merged when a file-level merge is necessary during `git merge`,
-and other programs such as `git revert` and `git cherry-pick`.
+and other commands such as `git revert` and `git cherry-pick`.
Set::
diff --git a/Documentation/gitcore-tutorial.txt b/Documentation/gitcore-tutorial.txt
index 7ba5e589d7..b3640c4e64 100644
--- a/Documentation/gitcore-tutorial.txt
+++ b/Documentation/gitcore-tutorial.txt
@@ -12,7 +12,7 @@ git *
DESCRIPTION
-----------
-This tutorial explains how to use the "core" git programs to set up and
+This tutorial explains how to use the "core" git commands to set up and
work with a git repository.
If you just need to use git as a revision control system you may prefer
@@ -1328,7 +1328,7 @@ into it later. Obviously, this repository creation needs to be
done only once.
[NOTE]
-'git-push' uses a pair of programs,
+'git-push' uses a pair of commands,
'git-send-pack' on your local machine, and 'git-receive-pack'
on the remote machine. The communication between the two over
the network internally uses an SSH connection.
diff --git a/Documentation/user-manual.txt b/Documentation/user-manual.txt
index 0b88a51d0b..67ebffa568 100644
--- a/Documentation/user-manual.txt
+++ b/Documentation/user-manual.txt
@@ -4131,7 +4131,7 @@ What does this mean?
`git rev-list` is the original version of the revision walker, which
_always_ printed a list of revisions to stdout. It is still functional,
-and needs to, since most new Git programs start out as scripts using
+and needs to, since most new Git commands start out as scripts using
`git rev-list`.
`git rev-parse` is not as important any more; it was only used to filter out
diff --git a/builtin-push.c b/builtin-push.c
index bc0c91aa4e..67f6d96fbe 100644
--- a/builtin-push.c
+++ b/builtin-push.c
@@ -140,6 +140,7 @@ static int do_push(const char *repo, int flags)
struct transport *transport =
transport_get(remote, url[i]);
int err;
+ int nonfastforward;
if (receivepack)
transport_set_option(transport,
TRANS_OPT_RECEIVEPACK, receivepack);
@@ -148,13 +149,19 @@ static int do_push(const char *repo, int flags)
if (flags & TRANSPORT_PUSH_VERBOSE)
fprintf(stderr, "Pushing to %s\n", url[i]);
- err = transport_push(transport, refspec_nr, refspec, flags);
+ err = transport_push(transport, refspec_nr, refspec, flags,
+ &nonfastforward);
err |= transport_disconnect(transport);
if (!err)
continue;
error("failed to push some refs to '%s'", url[i]);
+ if (nonfastforward) {
+ printf("To prevent you from losing history, non-fast-forward updates were rejected.\n"
+ "Merge the remote changes before pushing again.\n"
+ "See 'non-fast forward' section of 'git push --help' for details.\n");
+ }
errs++;
}
return !!errs;
diff --git a/help.c b/help.c
index 6c46d8b494..294337e71c 100644
--- a/help.c
+++ b/help.c
@@ -302,7 +302,7 @@ const char *help_unknown_cmd(const char *cmd)
struct cmdnames main_cmds, other_cmds;
memset(&main_cmds, 0, sizeof(main_cmds));
- memset(&other_cmds, 0, sizeof(main_cmds));
+ memset(&other_cmds, 0, sizeof(other_cmds));
memset(&aliases, 0, sizeof(aliases));
git_config(git_unknown_cmd_config, NULL);
@@ -334,7 +334,7 @@ const char *help_unknown_cmd(const char *cmd)
const char *assumed = main_cmds.names[0]->name;
main_cmds.names[0] = NULL;
clean_cmdnames(&main_cmds);
- fprintf(stderr, "WARNING: You called a Git program named '%s', "
+ fprintf(stderr, "WARNING: You called a Git command named '%s', "
"which does not exist.\n"
"Continuing under the assumption that you meant '%s'\n",
cmd, assumed);
diff --git a/transport.c b/transport.c
index afec5b731a..faee154c38 100644
--- a/transport.c
+++ b/transport.c
@@ -821,7 +821,7 @@ static int print_one_push_status(struct ref *ref, const char *dest, int count, i
}
static void print_push_status(const char *dest, struct ref *refs,
- int verbose, int porcelain)
+ int verbose, int porcelain, int * nonfastforward)
{
struct ref *ref;
int n = 0;
@@ -836,11 +836,14 @@ static void print_push_status(const char *dest, struct ref *refs,
if (ref->status == REF_STATUS_OK)
n += print_one_push_status(ref, dest, n, porcelain);
+ *nonfastforward = 0;
for (ref = refs; ref; ref = ref->next) {
if (ref->status != REF_STATUS_NONE &&
ref->status != REF_STATUS_UPTODATE &&
ref->status != REF_STATUS_OK)
n += print_one_push_status(ref, dest, n, porcelain);
+ if (ref->status == REF_STATUS_REJECT_NONFASTFORWARD)
+ *nonfastforward = 1;
}
}
@@ -999,7 +1002,8 @@ int transport_set_option(struct transport *transport,
}
int transport_push(struct transport *transport,
- int refspec_nr, const char **refspec, int flags)
+ int refspec_nr, const char **refspec, int flags,
+ int * nonfastforward)
{
verify_remote_names(refspec_nr, refspec);
@@ -1029,7 +1033,8 @@ int transport_push(struct transport *transport,
if (!quiet || push_had_errors(remote_refs))
print_push_status(transport->url, remote_refs,
- verbose | porcelain, porcelain);
+ verbose | porcelain, porcelain,
+ nonfastforward);
if (!(flags & TRANSPORT_PUSH_DRY_RUN)) {
struct ref *ref;
diff --git a/transport.h b/transport.h
index f1d3ebf674..171a01c7a3 100644
--- a/transport.h
+++ b/transport.h
@@ -69,7 +69,8 @@ int transport_set_option(struct transport *transport, const char *name,
const char *value);
int transport_push(struct transport *connection,
- int refspec_nr, const char **refspec, int flags);
+ int refspec_nr, const char **refspec, int flags,
+ int * nonfastforward);
const struct ref *transport_get_remote_refs(struct transport *transport);